MouseTools 2.1.2.dev2__py3-none-any.whl → 3.0.0.dev1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2021 Scott Caratozzolo
3
+ Copyright (c) 2024 Scott Caratozzolo
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -0,0 +1,39 @@
1
+ Metadata-Version: 2.1
2
+ Name: MouseTools
3
+ Version: 3.0.0.dev1
4
+ Summary: An unofficial Python wrapper for Disney's API
5
+ Author: Scott Caratozzolo
6
+ Project-URL: repository, https://gitlab.com/caratozzoloxyz/public/MouseTools
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Classifier: Operating System :: OS Independent
10
+ Description-Content-Type: text/markdown
11
+ License-File: LICENSE
12
+ Requires-Dist: requests
13
+
14
+ # MouseTools
15
+ [![PyPI version](https://badge.fury.io/py/MouseTools.svg)](https://badge.fury.io/py/MouseTools) [![Downloads](https://pepy.tech/badge/mousetools)](https://pepy.tech/project/mousetools)
16
+
17
+
18
+ An unofficial Python wrapper for the Disney API. Data is pulled directly from Disney. This package supports Walt Disney World and Disneyland.
19
+
20
+ Read the [documentation](https://caratozzoloxyz.gitlab.io/public/MouseTools/)/
21
+
22
+
23
+ ### Installation
24
+ You can install using pip:
25
+ ```bash
26
+ pip install MouseTools
27
+ ```
28
+ You can also install directly from this repo in case of any changes not uploaded to Pypi.
29
+ ```bash
30
+ pip install git+https://gitlab.com/caratozzoloxyz/public/MouseTools
31
+ ```
32
+
33
+ ### License
34
+ This project is distributed under the MIT license. For more information see [LICENSE](https://gitlab.com/caratozzoloxyz/public/MouseTools/-/blob/master/LICENSE?ref_type=heads)
35
+
36
+ ### Disclaimer
37
+ This project is in no way affiliated with The Walt Disney Company and all use of Disney Services is subject to the [Disney Terms of Use](https://disneytermsofuse.com/).
38
+
39
+ This package uses the [ThemeParks.wiki API](https://themeparks.wiki/).
@@ -0,0 +1,25 @@
1
+ mousetools/__init__.py,sha256=83vn73ueEi1KaPISFpdHB5AmMwieJJmVEpV4ko9SZBE,581
2
+ mousetools/auth.py,sha256=XBCeD_hQaFPcSgKWWxYXpxwx2QxUk72adU4H8O5G-YY,2177
3
+ mousetools/exceptions.py,sha256=F94ohI_xDi0dLtTFInGhJL4u9TLY259OLmiiV6gcE_Q,538
4
+ mousetools/ids.py,sha256=k7pl9zeWSNUobr6RAJlQpEiwtH37RS4r6jZwvn0D0wI,3743
5
+ mousetools/urls.py,sha256=9GX9WYqfbg6Mv70Sz7WkqifFKUCvdYM3R7yZuQddvp4,302
6
+ mousetools/entities/__init__.py,sha256=g_USz0PsavrhDpUAuSz9eMBvxS1upJRgFoz9xLQl1kQ,742
7
+ mousetools/entities/attraction.py,sha256=R3Ju7hzdIu4kxzoSQRrSprOWoREu89AUN0Wc26R7iEQ,190
8
+ mousetools/entities/base.py,sha256=IVAAwszx-MgmwP5TIo-7aN_i2AysRXONS5UTDFOx-1g,13223
9
+ mousetools/entities/destination.py,sha256=_UUATQz_sdlWEYg1aAZeespPNkS7thzURbzZb5dvFWE,193
10
+ mousetools/entities/dining_event.py,sha256=OCHKiqmdzoraYxKxZs1EtfZRkqKCJdtMZNY3GOlbN-E,340
11
+ mousetools/entities/entertainment.py,sha256=CmgiJMShsph0gFbvMQzrmD5PaRp5mxeO9lUBY59cQBU,199
12
+ mousetools/entities/entertainment_venue.py,sha256=8xeYnjgrgK2kiXHDx_Qw-Q_u9DdKZFGuuXmS5cQ0-0g,214
13
+ mousetools/entities/event.py,sha256=R-6osBRaCj5AYLbmSOcd5JLcQBN_X-suP3bbEcTCWI0,175
14
+ mousetools/entities/merchandise_facility.py,sha256=YRcAJlcmKf7s-Khy2V42a4v1n4q_LXRE1h5JhSe3fqA,217
15
+ mousetools/entities/park.py,sha256=Tr_0HGwePXCV8rMiBrjyqdbCun40pDWSnf3mhLEyx9w,172
16
+ mousetools/entities/resort.py,sha256=6NS1UIxzL_t7reoPQ5Da-T070MuJ4tp9pIxiREECX6s,178
17
+ mousetools/entities/restaurant.py,sha256=TWbgp5e-Sw_EV9WrzyEebqbBeVtU7Jp_hb36i7hD-aE,190
18
+ mousetools/mixins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
+ mousetools/mixins/disney.py,sha256=PnEpaR1s-yMV2YLJO_pF440p_qOBWu1V9fF5UEMECLY,2045
20
+ mousetools/mixins/themeparksapi.py,sha256=6Zeo0QDnfT4ovHrlycA-SDQiES6vXOivLWFUAn8AG0g,4123
21
+ MouseTools-3.0.0.dev1.dist-info/LICENSE,sha256=xX4HoDU-zdafl3yEfIaspkvqHPaaXhuDwkJ6qhDMUIo,1074
22
+ MouseTools-3.0.0.dev1.dist-info/METADATA,sha256=VUCidYBzR9DG3tyRq7pXjjJKGx9Q9B1hbAPvrSOQtWs,1570
23
+ MouseTools-3.0.0.dev1.dist-info/WHEEL,sha256=Mdi9PDNwEZptOjTlUcAth7XJDFtKrHYaQMPulZeBCiQ,91
24
+ MouseTools-3.0.0.dev1.dist-info/top_level.txt,sha256=7nanLN103J_xJn6HK6yuyqqlDgltCsQY2-ArRXx1Ukk,11
25
+ MouseTools-3.0.0.dev1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (72.1.0)
2
+ Generator: setuptools (73.0.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
mousetools/__init__.py CHANGED
@@ -1,27 +1,13 @@
1
- """
2
- init
3
- expose classes and modules
4
- """
5
- from mousetools.parks import Park
6
- from mousetools.entertainmentvenues import EntertainmentVenue
7
- from mousetools.attractions import Attraction
8
- from mousetools.entertainments import Entertainment
9
- from mousetools.characters import Character
10
- from mousetools.facilities import Facility
11
- from mousetools.pointsofinterest import PointOfInterest
12
- from mousetools.destinations import Destination
13
- import mousetools.ids as ids
1
+ import logging
2
+ from mousetools.ids import ancestor_entities, DestinationIds
14
3
 
15
- __version__ = "2.1.2-dev.2" # will be set at runtime
4
+ logger = logging.getLogger(__name__)
5
+ logger.addHandler(logging.NullHandler())
16
6
 
7
+ __version__ = "3.0.0-dev.1" # will be set at runtime
8
+ logger.info(f"MouseTools version: {__version__}")
17
9
 
18
- __all__ = [
19
- "Destination",
20
- "Park",
21
- "EntertainmentVenue",
22
- "Attraction",
23
- "Entertainment",
24
- "Facility",
25
- "Character",
26
- "PointOfInterest",
27
- ]
10
+ WALT_DISNEY_WORLD_ENTITIES = ancestor_entities(DestinationIds.WALT_DISNEY_WORLD)
11
+ logger.debug("%s Walt Disney World Entities", len(WALT_DISNEY_WORLD_ENTITIES))
12
+ DISNEYLAND_RESORT_ENTITIES = ancestor_entities(DestinationIds.DISNEYLAND_RESORT)
13
+ logger.debug("%s Disneyland Resort Entities", len(DISNEYLAND_RESORT_ENTITIES))
mousetools/auth.py CHANGED
@@ -1,42 +1,60 @@
1
- import requests
2
- import json
3
- from datetime import datetime, timedelta
4
-
5
-
6
- def disney_authentication():
7
- """Gets an authentication (access) token from Disney and returns it"""
8
-
9
- headers = {
10
- 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36',
11
- 'Accept-Language' : 'en_US',
12
- 'Cache-Control' : '0',
13
- 'Accept' : 'application/json',
14
- 'Content-Type' : 'application/x-www-form-urlencoded',
15
- 'Connection' : 'keep-alive',
16
- 'Proxy-Connection' : 'keep-alive',
17
- 'Accept-Encoding' : 'gzip, deflate'
18
- }
19
- auth = requests.get("https://disneyworld.disney.go.com/authentication/get-client-token", headers=headers, timeout=10).json()
20
- return auth['access_token'], auth['expires_in']
21
-
22
-
23
- time_of_expire = None
24
- access_token = None
25
-
26
- def get_headers():
27
- """Creates the headers to send during the request and returns it"""
28
-
29
- global time_of_expire
30
- global access_token
31
-
32
- if time_of_expire == None or (datetime.now() > time_of_expire):
33
- access_token, expires_in = disney_authentication()
34
- time_of_expire = datetime.now() + timedelta(seconds=(expires_in-10))
35
-
36
- headers = {"Authorization":"BEARER {}".format(access_token), "User-Agent":'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36', "Content-Type":"application/json;charset=UTF-8","Accept":"*/*"}
37
-
38
- return headers
39
-
40
- if __name__ == '__main__':
41
-
42
- print(get_headers())
1
+ import typing
2
+ import requests
3
+ from datetime import datetime, timedelta
4
+
5
+
6
+ class Authentication:
7
+ def __init__(self):
8
+ self.time_of_expire: typing.Optional[datetime] = None
9
+ self.access_token: typing.Optional[str] = None
10
+
11
+ @staticmethod
12
+ def authenticate() -> typing.Tuple[str, int]:
13
+ """Gets an access token from Disney and the token's expiration time
14
+
15
+ Returns:
16
+ (typing.Tuple[str, int]): Access token to the api and how long until it expires
17
+ """
18
+
19
+ headers = {
20
+ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36",
21
+ "Accept-Language": "en-US,en;q=0.9",
22
+ "Cache-Control": "max-age=0",
23
+ "Accept": "application/json",
24
+ "Content-Type": "application/x-www-form-urlencoded",
25
+ "Connection": "keep-alive",
26
+ "Proxy-Connection": "keep-alive",
27
+ "Accept-Encoding": "gzip, deflate",
28
+ }
29
+ response = requests.get(
30
+ "https://disneyworld.disney.go.com/authentication/get-client-token",
31
+ headers=headers,
32
+ timeout=10,
33
+ )
34
+ auth = response.json()
35
+
36
+ return auth["access_token"], int(auth["expires_in"])
37
+
38
+ def get_headers(self) -> typing.Dict[str, str]:
39
+ """Creates the headers to send during the request
40
+
41
+ Returns:
42
+ (typing.Dict[str, str]): Headers for the request
43
+ """
44
+
45
+ if self.time_of_expire is None or (datetime.now() > self.time_of_expire):
46
+ access_token, expires_in = self.authenticate()
47
+ self.time_of_expire = datetime.now() + timedelta(seconds=(expires_in - 10))
48
+ self.access_token = access_token
49
+
50
+ headers = {
51
+ "Authorization": f"BEARER {self.access_token}",
52
+ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36",
53
+ "Content-Type": "application/json",
54
+ "Accept": "*/*",
55
+ }
56
+
57
+ return headers
58
+
59
+
60
+ auth_obj = Authentication()
@@ -0,0 +1,13 @@
1
+ from mousetools.entities.attraction import Attraction
2
+ from mousetools.entities.entertainment import Entertainment
3
+ from mousetools.entities.destination import Destination
4
+ from mousetools.entities.park import Park
5
+ from mousetools.entities.entertainment_venue import EntertainmentVenue
6
+ from mousetools.entities.merchandise_facility import MerchandiseFacility
7
+ from mousetools.entities.restaurant import Restaurant
8
+ from mousetools.entities.resort import Resort
9
+ from mousetools.entities.dining_event import DiningEvent, DinnerShow
10
+ from mousetools.entities.event import Event
11
+
12
+
13
+ __all__ = ["Attraction", "Entertainment", "Destination", "Park", "EntertainmentVenue" ,"MerchandiseFacility", "Restaurant", "Resort", "DiningEvent", "DinnerShow", "Event"]
@@ -0,0 +1,8 @@
1
+ from mousetools.entities.base import Entity
2
+
3
+
4
+ class Attraction(Entity):
5
+ """Class for Attraction Entities."""
6
+
7
+ def __repr__(self) -> str:
8
+ return f"Attraction(id='{self.id}')"
@@ -0,0 +1,381 @@
1
+ import logging
2
+ import typing
3
+ from datetime import datetime
4
+ from zoneinfo import ZoneInfo
5
+ from mousetools.mixins.disney import DisneyAPIMixin
6
+ from mousetools.mixins.themeparksapi import ThemeParkAPIMixin
7
+ from mousetools.ids import DestinationIds
8
+ from mousetools.urls import ENTITY_DETAILS_SIMPLE_BASE_URL
9
+ from mousetools.exceptions import AncestorDestinationMissing
10
+
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ class Entity(DisneyAPIMixin, ThemeParkAPIMixin):
16
+ def __init__(self, id: str):
17
+ self.id: str = id
18
+ self.disney_data: typing.Optional[dict] = None
19
+
20
+ @property
21
+ def name(self) -> typing.Optional[str]:
22
+ """
23
+ The name of the entity.
24
+
25
+ Returns:
26
+ (typing.Optional[str]): The name of the entity, or None if it was not found.
27
+ """
28
+
29
+ if self.disney_data is None:
30
+ self.disney_data = self.get_disney_data()
31
+ try:
32
+ return self.disney_data["name"]
33
+ except KeyError:
34
+ logger.debug("No name found for %s", self.id)
35
+ return None
36
+
37
+ @property
38
+ def entity_type(self) -> typing.Optional[str]:
39
+ """
40
+ The type of entity this is.
41
+
42
+ Returns:
43
+ (typing.Optional[str]): The type of entity this is, or None if it was not found.
44
+ """
45
+
46
+ if self.disney_data is None:
47
+ self.disney_data = self.get_disney_data()
48
+ try:
49
+ return self.disney_data["entityType"]
50
+ except KeyError:
51
+ logger.debug("No entity type found for %s", self.id)
52
+ return None
53
+
54
+ @property
55
+ def entity_type_name(self) -> typing.Optional[str]:
56
+ """
57
+ The name of the type of entity.
58
+
59
+ Returns:
60
+ (typing.Optional[str]): The name of the type of entity, or None if it was not found.
61
+ """
62
+ if self.disney_data is None:
63
+ self.disney_data = self.get_disney_data()
64
+ try:
65
+ return self.disney_data["entityTypeName"]
66
+ except KeyError:
67
+ logger.debug("No entity type name found for %s", self.id)
68
+ return None
69
+
70
+ @property
71
+ def url_friendly_id(self) -> typing.Optional[str]:
72
+ """
73
+ The url friendly id of the entity.
74
+
75
+ Returns:
76
+ (typing.Optional[str]): The url friendly id of the entity, or None if not found.
77
+ """
78
+ if self.disney_data is None:
79
+ self.disney_data = self.get_disney_data()
80
+ try:
81
+ id = self.disney_data["urlFriendlyId"]
82
+ # for some reason pirates in wdw has a -wdw and its wrong
83
+ id = id.replace("-wdw", "").replace("-dlr", "")
84
+ return id
85
+ except KeyError:
86
+ logger.debug("No url friendly id found for %s", self.id)
87
+ return None
88
+
89
+ @property
90
+ def coordinates(self) -> typing.Optional[dict[str, float]]:
91
+ """
92
+ The coordinates of this entity
93
+
94
+ Returns:
95
+ (typing.Optional[dict[str, float]]): A dict with "lat" and "lng" keys containing the coordinates of this entity as floats, or None if no coordinates are found
96
+ """
97
+ if self.disney_data is None:
98
+ self.disney_data = self.get_disney_data()
99
+ try:
100
+ return {
101
+ "lat": float(self.disney_data["marker"]["lat"]),
102
+ "lng": float(self.disney_data["marker"]["lng"]),
103
+ }
104
+ except KeyError:
105
+ logger.debug("No coordinates found for %s", self.id)
106
+ return None
107
+
108
+ @property
109
+ def ancestor_destination_id(self) -> typing.Optional[str]:
110
+ """
111
+ The id of the ancestor destination of this entity.
112
+
113
+ Returns:
114
+ (typing.Optional[str]): The id of the ancestor destination of this entity, or None if it was not found.
115
+ """
116
+
117
+ if self.disney_data is None:
118
+ self.disney_data = self.get_disney_data()
119
+ try:
120
+ return self._ancestor_destination_id
121
+ except KeyError:
122
+ logger.debug("No ancestor destination id found for %s", self.id)
123
+ return None
124
+
125
+ @ancestor_destination_id.setter
126
+ def ancestor_destination_id(self, value: typing.Optional[str]):
127
+ """
128
+ Set the ancestor destination id
129
+
130
+ Required for ThemeParkAPIMixin
131
+
132
+ Args:
133
+ value (typing.Optional[str]): Str to set ancestor_destination_id to
134
+ """
135
+ self.ancestor_destination_id = value
136
+
137
+ @property
138
+ def ancestor_park_ids(self) -> typing.Optional[list[str]]:
139
+ """
140
+ The ids of parks that are ancestors of this entity.
141
+
142
+ Returns:
143
+ (typing.Optional[list[str]]): A list of park ids that are ancestors of this entity, or None if no such ids are found.
144
+ """
145
+ if self.disney_data is None:
146
+ self.disney_data = self.get_disney_data()
147
+ try:
148
+ return [
149
+ i
150
+ for i in self.disney_data["parkIds"]
151
+ if any(j in i for j in ["theme-park", "water-park"])
152
+ ]
153
+ except KeyError:
154
+ logger.debug("No ancestor park ids found for %s", self.id)
155
+ return None
156
+
157
+ @property
158
+ def ancestor_resort_ids(self) -> typing.Optional[list[str]]:
159
+ """
160
+ The ids of resorts that are ancestors of this entity.
161
+
162
+ Returns:
163
+ (typing.Optional[list[str]]): A list of resort ids that are ancestors of this entity, or None if no such ids are found.
164
+ """
165
+
166
+ if self.disney_data is None:
167
+ self.disney_data = self.get_disney_data()
168
+ try:
169
+ return [i for i in self.disney_data["parkIds"] if "resort" in i]
170
+ except KeyError:
171
+ logger.debug("No ancestor resort ids found for %s", self.id)
172
+ return None
173
+
174
+ @property
175
+ def ancestor_land_id(self) -> typing.Optional[str]:
176
+ """
177
+ The id of the land that is an ancestor of this entity.
178
+
179
+ Returns:
180
+ (typing.Optional[str]): The id of the land that is an ancestor of this entity, or None if no such id is found.
181
+ """
182
+ if self.disney_data is None:
183
+ self.disney_data = self.get_disney_data()
184
+ try:
185
+ return self.disney_data["landId"]
186
+ except KeyError:
187
+ logger.debug("No ancestor land id found for %s", self.id)
188
+ return None
189
+
190
+ @property
191
+ def ancestor_resort_area_ids(self) -> typing.Optional[list[str]]:
192
+ """
193
+ The ids of resort areas that are ancestors of this entity.
194
+
195
+ Returns:
196
+ (typing.Optional[list[str]]): A list of resort area ids that are ancestors of this entity, or None if no such ids are found.
197
+ """
198
+ if self.disney_data is None:
199
+ self.disney_data = self.get_disney_data()
200
+ try:
201
+ return [i for i in self.disney_data["parkIds"] if "resort-area" in i]
202
+ except KeyError:
203
+ logger.debug("No ancestor resort area ids found for %s", self.id)
204
+ return None
205
+
206
+ @property
207
+ def ancestor_entertainment_venue_ids(self) -> typing.Optional[list[str]]:
208
+ """
209
+ The ids of entertainment venues that are ancestors of this entity.
210
+
211
+ Returns:
212
+ (typing.Optional[list[str]]): A list of entertainment venue ids that are ancestors of this entity, or None if no such ids are found.
213
+ """
214
+ if self.disney_data is None:
215
+ self.disney_data = self.get_disney_data()
216
+ try:
217
+ return [
218
+ i for i in self.disney_data["parkIds"] if "Entertainment-Venue" in i
219
+ ]
220
+ except KeyError:
221
+ logger.debug("No ancestor entertainment venue ids found for %s", self.id)
222
+ return None
223
+
224
+ @property
225
+ def ancestor_restaurant_ids(self) -> typing.Optional[list[str]]:
226
+ """
227
+ The ids of restaurants that are ancestors of this entity.
228
+
229
+ Returns:
230
+ (typing.Optional[list[str]]): A list of restaurant ids that are ancestors of this entity, or None if no such ids are found.
231
+ """
232
+ if self.disney_data is None:
233
+ self.disney_data = self.get_disney_data()
234
+ try:
235
+ return [i["id"] for i in self.disney_data["restaurants"]]
236
+ except KeyError:
237
+ logger.debug("No ancestor restaurant ids found for %s", self.id)
238
+ return None
239
+
240
+ @property
241
+ def time_zone(self) -> ZoneInfo:
242
+ """
243
+ The time zone of the entity.
244
+
245
+ Returns:
246
+ (ZoneInfo): The time zone of the entity.
247
+ """
248
+
249
+ if self.ancestor_destination_id == DestinationIds.WALT_DISNEY_WORLD:
250
+ return ZoneInfo("America/New_York")
251
+ elif self.ancestor_destination_id == DestinationIds.DISNEYLAND_RESORT:
252
+ return ZoneInfo("America/Los_Angeles")
253
+ else:
254
+ return ZoneInfo("UTC")
255
+
256
+ def details_simple_url(self) -> str:
257
+ """
258
+ Gets the simple details url for this entity
259
+
260
+ Returns:
261
+ (str): The simple details url
262
+
263
+ Raises:
264
+ AncestorDestinationMissing: If the ancestor destination id is not
265
+ either Walt Disney World or Disneyland Resort
266
+ """
267
+ if self.ancestor_destination_id == DestinationIds.WALT_DISNEY_WORLD:
268
+ dest_url_friendly_id = "wdw"
269
+ elif self.ancestor_destination_id == DestinationIds.DISNEYLAND_RESORT:
270
+ dest_url_friendly_id = "dlr"
271
+ else:
272
+ raise AncestorDestinationMissing
273
+ return f"{ENTITY_DETAILS_SIMPLE_BASE_URL}/{dest_url_friendly_id}/{self.url_friendly_id}/{datetime.now().strftime('%Y-%m-%d')}"
274
+
275
+ def status(self) -> typing.Optional[str]:
276
+ """
277
+ The current status of the entity.
278
+
279
+ Returns:
280
+ (typing.Optional[str]): The current status of the entity, or None if no such data exists.
281
+ """
282
+
283
+ live_data = self.get_entity_live_tp()
284
+ try:
285
+ return live_data["liveData"][0]["status"]
286
+ except (KeyError, IndexError):
287
+ logger.debug("No status found for %s", self.id)
288
+ return None
289
+
290
+ def wait_time(self) -> typing.Optional[int]:
291
+ """
292
+ The current wait time for the entity.
293
+
294
+ Returns:
295
+ (typing.Optional[int]): The current wait time for the entity, or None if no such data exists.
296
+ """
297
+ live_data = self.get_entity_live_tp()
298
+ try:
299
+ return live_data["liveData"][0]["queue"]["STANDBY"]["waitTime"]
300
+ except (KeyError, IndexError):
301
+ logger.debug("No wait time found for %s", self.id)
302
+ return None
303
+
304
+ def last_updated(self) -> typing.Optional[datetime]:
305
+ """
306
+ The last time the entity's data was updated.
307
+
308
+ Returns:
309
+ (typing.Optional[datetime]): The last time the entity's data was updated, or None if no such data exists.
310
+ """
311
+ live_data = self.get_entity_live_tp()
312
+ try:
313
+ return datetime.strptime(
314
+ live_data["liveData"][0]["lastUpdated"], "%Y-%m-%dT%H:%M:%SZ"
315
+ ).replace(tzinfo=ZoneInfo("UTC"))
316
+ except (KeyError, IndexError):
317
+ logger.debug("No last updated found for %s", self.id)
318
+ return None
319
+
320
+ def today_operating_hours(self) -> typing.Optional[dict[str, dict[str, datetime]]]:
321
+ """
322
+ The operating hours for today for the entity.
323
+
324
+ Returns:
325
+ (typing.Optional[dict[str, dict[str, datetime]]]): A dictionary of the operating hours for today, or None if no such data exists.
326
+ """
327
+
328
+ live_data = self.get_entity_live_tp()
329
+ temp = {}
330
+
331
+ try:
332
+ for i in live_data["liveData"][0]["operatingHours"]:
333
+ temp[i["type"]] = {
334
+ "start_time": datetime.strptime(
335
+ i["startTime"], "%Y-%m-%dT%H:%M:%S%z"
336
+ ).replace(tzinfo=self.time_zone),
337
+ "end_time": datetime.strptime(
338
+ i["endTime"], "%Y-%m-%dT%H:%M:%S%z"
339
+ ).replace(tzinfo=self.time_zone),
340
+ }
341
+ except (KeyError, IndexError):
342
+ logger.debug("No operating hours found for %s", self.id)
343
+ return None
344
+
345
+ return temp
346
+
347
+ def today_showtimes(self) -> typing.Optional[list[datetime]]:
348
+ """
349
+ The showtimes for today for the entity.
350
+
351
+ Returns:
352
+ (typing.Optional[list[datetime]]): A list of the showtimes for today, or None if no such data exists.
353
+ """
354
+ live_data = self.get_entity_live_tp()
355
+ temp = []
356
+
357
+ try:
358
+ for i in live_data["liveData"][0]["showtimes"]:
359
+ temp.append(
360
+ datetime.strptime(i["startTime"], "%Y-%m-%dT%H:%M:%S%z").replace(
361
+ tzinfo=self.time_zone
362
+ )
363
+ )
364
+ except (KeyError, IndexError):
365
+ logger.debug("No showtimes found for %s", self.id)
366
+ return None
367
+
368
+ return temp
369
+
370
+ def __str__(self) -> str:
371
+ return f"{self.entity_type}: {self.name} ({self.id})"
372
+
373
+ def __repr__(self) -> str:
374
+ return f"Entity(id='{self.id}')"
375
+
376
+ def __eq__(self, other) -> bool:
377
+ if isinstance(other, Entity):
378
+ return self.id == other.id
379
+ return False
380
+
381
+ # TODO virtual queue
@@ -0,0 +1,8 @@
1
+ from mousetools.entities.base import Entity
2
+
3
+
4
+ class Destination(Entity):
5
+ """Class for Destination Entities."""
6
+
7
+ def __repr__(self) -> str:
8
+ return f"Destination(id='{self.id}')"
@@ -0,0 +1,15 @@
1
+ from mousetools.entities.base import Entity
2
+
3
+
4
+ class DiningEvent(Entity):
5
+ """Class for DiningEvent Entities."""
6
+
7
+ def __repr__(self) -> str:
8
+ return f"DiningEvent(id='{self.id}')"
9
+
10
+
11
+ class DinnerShow(Entity):
12
+ """Class for DiningEvent Entities."""
13
+
14
+ def __repr__(self) -> str:
15
+ return f"DinnerShow(id='{self.id}')"
@@ -0,0 +1,8 @@
1
+ from mousetools.entities.base import Entity
2
+
3
+
4
+ class Entertainment(Entity):
5
+ """Class for Entertainment Entities."""
6
+
7
+ def __repr__(self) -> str:
8
+ return f"Entertainment(id='{self.id}')"
@@ -0,0 +1,8 @@
1
+ from mousetools.entities.base import Entity
2
+
3
+
4
+ class EntertainmentVenue(Entity):
5
+ """Class for EntertainmentVenue Entities."""
6
+
7
+ def __repr__(self) -> str:
8
+ return f"EntertainmentVenue(id='{self.id}')"