themeparks 2.0.0a1__tar.gz → 3.0.0__tar.gz

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.
Files changed (22) hide show
  1. themeparks-3.0.0/CHANGELOG.md +126 -0
  2. {themeparks-2.0.0a1 → themeparks-3.0.0}/MIGRATION.md +1 -1
  3. {themeparks-2.0.0a1 → themeparks-3.0.0}/PKG-INFO +4 -4
  4. {themeparks-2.0.0a1 → themeparks-3.0.0}/pyproject.toml +13 -4
  5. {themeparks-2.0.0a1 → themeparks-3.0.0}/themeparks/_client.py +7 -1
  6. {themeparks-2.0.0a1 → themeparks-3.0.0}/themeparks/_generated/models.py +338 -107
  7. themeparks-2.0.0a1/CHANGELOG.md +0 -41
  8. {themeparks-2.0.0a1 → themeparks-3.0.0}/.gitignore +0 -0
  9. {themeparks-2.0.0a1 → themeparks-3.0.0}/LICENSE +0 -0
  10. {themeparks-2.0.0a1 → themeparks-3.0.0}/README.md +0 -0
  11. {themeparks-2.0.0a1 → themeparks-3.0.0}/themeparks/__init__.py +0 -0
  12. {themeparks-2.0.0a1 → themeparks-3.0.0}/themeparks/_cache.py +0 -0
  13. {themeparks-2.0.0a1 → themeparks-3.0.0}/themeparks/_ergonomic/__init__.py +0 -0
  14. {themeparks-2.0.0a1 → themeparks-3.0.0}/themeparks/_ergonomic/dates.py +0 -0
  15. {themeparks-2.0.0a1 → themeparks-3.0.0}/themeparks/_ergonomic/destinations.py +0 -0
  16. {themeparks-2.0.0a1 → themeparks-3.0.0}/themeparks/_ergonomic/entity.py +0 -0
  17. {themeparks-2.0.0a1 → themeparks-3.0.0}/themeparks/_ergonomic/live.py +0 -0
  18. {themeparks-2.0.0a1 → themeparks-3.0.0}/themeparks/_errors.py +0 -0
  19. {themeparks-2.0.0a1 → themeparks-3.0.0}/themeparks/_generated/__init__.py +0 -0
  20. {themeparks-2.0.0a1 → themeparks-3.0.0}/themeparks/_raw.py +0 -0
  21. {themeparks-2.0.0a1 → themeparks-3.0.0}/themeparks/_transport.py +0 -0
  22. {themeparks-2.0.0a1 → themeparks-3.0.0}/themeparks/py.typed +0 -0
@@ -0,0 +1,126 @@
1
+ # Changelog
2
+
3
+ ## [3.0.0] - 2026-09-08
4
+
5
+ ### Fixed
6
+
7
+ - **Schedule entries now carry `purchases`.** The upstream spec described a
8
+ park's schedule two different ways: precisely when nested under a
9
+ destination, loosely when fetched directly. This client uses the direct
10
+ path, so `purchases` was absent from the model entirely. Magic Kingdom
11
+ serves 26 entries carrying purchases.
12
+
13
+ ```python
14
+ sched = client.entity(park_id).schedule()
15
+ for day in sched.schedule or []:
16
+ for p in day.purchases or []:
17
+ print(p.name, p.price.amount, p.price.currency)
18
+ ```
19
+
20
+ - **A null price on a schedule purchase no longer rejects the response.**
21
+ 2.0.1 made `PriceData.amount` nullable, but the schedule path used a
22
+ second, inline price model that kept `amount` non-nullable. Both now use
23
+ `PriceData`. Tokyo Disneyland serves six Premier Access rows with a null
24
+ amount, and this client raised `ValidationError` on every one of them.
25
+
26
+ - Schedule entries gained the `description` field the API has always sent.
27
+
28
+ ### Changed
29
+
30
+ - **BREAKING — `ScheduleEntry.type` is an enum, not a `str`.** It was
31
+ `type: str`; it is now a `Type` enum. This breaks *silently*: the comparison
32
+ does not raise, it just stops being true.
33
+
34
+ ```python
35
+ # before: True. now: False, with no error.
36
+ if day.type == "OPERATING":
37
+ ...
38
+
39
+ # use one of these instead
40
+ if day.type.value == "OPERATING":
41
+ ...
42
+ from themeparks._generated.models import Type
43
+ if day.type is Type.OPERATING:
44
+ ...
45
+ ```
46
+
47
+ Audit any comparison of `.type` against a string literal before upgrading.
48
+ This is the one change here that will not announce itself.
49
+
50
+ - **BREAKING — the `PricedScheduleEntry` and `Price` models are gone.**
51
+ `PricedScheduleEntry` is now `ScheduleEntry`, and the inline `Price` model
52
+ is replaced by `PriceData`. Neither was exported from the package root, so
53
+ this only affects code importing from `themeparks._generated.models`
54
+ directly — a private module.
55
+
56
+ - The duplicate `EntityType1` and `EntityType2` enums collapse into
57
+ `EntityType`. Same members, same values.
58
+
59
+ ## [2.0.1] - 2026-09-01
60
+ ### Fixed
61
+ - `PriceData.amount` is now nullable. The API returns `null` when a paid queue
62
+ exists but the provider does not publish a price, and `0` only when the queue
63
+ is genuinely free. Both previously arrived as `0`, so an unknown price was
64
+ indistinguishable from a free one.
65
+
66
+ Before this, a single null amount on one attraction made pydantic reject the
67
+ **entire** live response for that park, not just the one field.
68
+
69
+ Code testing `if price.amount:` or `if not price.amount:` now conflates
70
+ "free" with "price unknown" — the exact confusion this change exists to
71
+ remove. Switch to an explicit check:
72
+
73
+ ```python
74
+ if price.amount is None:
75
+ label = "price not published"
76
+ else:
77
+ label = f"{price.currency} {price.amount / 100:.2f}"
78
+ ```
79
+
80
+ `price.formatted` is optional and may be absent when the amount is unknown,
81
+ so do not rely on it alone to detect the case.
82
+
83
+ ## [2.0.0] - 2026-04-15
84
+ First stable v2 release. Identical surface to `2.0.0a1` after a brief alpha
85
+ soak; no code changes since `2.0.0a1`. Bumped `Development Status` classifier
86
+ to `Production/Stable`.
87
+
88
+ ## [2.0.0a1] - 2026-04-15
89
+ ### Added
90
+ - MkDocs Material documentation site with full API reference and a cookbook
91
+ (recipes for sorted wait times, 7-day schedules, geo-locations grouped by
92
+ entity type, every queue variant, and HTTP debugging).
93
+ - Top-level exports for `current_wait_time`, `iter_queues`, `parse_api_datetime`.
94
+ - Class-level docstrings on every public surface for readable API reference rendering.
95
+ - README sections explaining every queue variant (STANDBY, PAID_RETURN_TIME,
96
+ BOARDING_GROUP, etc.) and how to enable the httpx logger for HTTP debugging.
97
+
98
+ ### Fixed
99
+ - `walk()` now makes a single API call instead of one per descendant — the
100
+ `/children` endpoint already returns the entire subtree recursively. Walking
101
+ Walt Disney World dropped from ~250 requests to 1.
102
+ - `get_entity_schedule_month` now zero-pads the month (`/schedule/2026/05`,
103
+ not `/schedule/2026/5`) per the API requirement.
104
+ - `RetryConfig` field renamed `max_attempts` → `max_retries` to match its
105
+ actual semantics (N retries beyond the first attempt = N+1 total calls).
106
+ - `APIError` now includes a server-body excerpt in the exception message;
107
+ `RateLimitError.__repr__` includes `retry_after`.
108
+ - `destinations.find()` now performs the loose, case-insensitive substring
109
+ match it had always promised in its docstring (was exact equality).
110
+ - Generated queue variant classes renamed (`STANDBY` → `StandbyQueue` etc.)
111
+ so users access `queue.STANDBY` instead of the awkward `queue.STANDBY_1`.
112
+ - `eval-type-backport` is now a conditional dep on Python 3.9 so pydantic
113
+ can evaluate PEP 604 union syntax in the generated models.
114
+
115
+ ## [2.0.0a0] - 2026-04-14
116
+ ### Added
117
+ - Full rewrite on pydantic v2 + httpx.
118
+ - Sync `ThemeParks` and `AsyncThemeParks` clients with shared core.
119
+ - Ergonomic `client.entity(id)` navigation, `walk()`, `schedule.range()`.
120
+ - Typed pydantic models, correctly handling nullable queue fields (fixes #1, #2).
121
+ - Default-on caching with per-endpoint TTLs and pluggable adapter.
122
+ - 429 `Retry-After` handling.
123
+
124
+ ### Removed
125
+ - Legacy `openapi_client` top-level import and generated surface. See MIGRATION.md.
126
+ - `urllib3`-based transport.
@@ -170,7 +170,7 @@ The async surface mirrors the sync surface method-for-method.
170
170
 
171
171
  ## New in v2 (not in v1)
172
172
 
173
- - `tp.entity(id).walk()` — breadth-first iterator over every descendant.
173
+ - `tp.entity(id).walk()` — iterator over every descendant in a single API call (the `/children` endpoint already returns the full subtree).
174
174
  - `tp.entity(id).schedule.range(start, end)` — stitches monthly schedule
175
175
  responses into a single sorted, filtered list.
176
176
  - `tp.destinations.find(query)` — case-insensitive lookup by slug or name.
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: themeparks
3
- Version: 2.0.0a1
3
+ Version: 3.0.0
4
4
  Summary: Official SDK for the ThemeParks.wiki API
5
5
  Project-URL: Homepage, https://api.themeparks.wiki
6
6
  Project-URL: Source, https://github.com/ThemeParks/ThemeParks_Python
@@ -9,7 +9,7 @@ Author: ThemeParks.wiki contributors
9
9
  License: MIT
10
10
  License-File: LICENSE
11
11
  Keywords: api,disney,themeparks,universal,wait-times
12
- Classifier: Development Status :: 4 - Beta
12
+ Classifier: Development Status :: 5 - Production/Stable
13
13
  Classifier: Intended Audience :: Developers
14
14
  Classifier: License :: OSI Approved :: MIT License
15
15
  Classifier: Programming Language :: Python :: 3
@@ -30,7 +30,7 @@ Requires-Dist: mypy>=1.10; extra == 'dev'
30
30
  Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
31
31
  Requires-Dist: pytest-recording>=0.13; extra == 'dev'
32
32
  Requires-Dist: pytest>=8; extra == 'dev'
33
- Requires-Dist: ruff>=0.4; extra == 'dev'
33
+ Requires-Dist: ruff<0.17,>=0.4; extra == 'dev'
34
34
  Provides-Extra: docs
35
35
  Requires-Dist: mkdocs-material>=9.5; extra == 'docs'
36
36
  Requires-Dist: mkdocs>=1.5; extra == 'docs'
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "themeparks"
7
- version = "2.0.0a1"
7
+ version = "3.0.0"
8
8
  description = "Official SDK for the ThemeParks.wiki API"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -12,7 +12,7 @@ license = { text = "MIT" }
12
12
  authors = [{ name = "ThemeParks.wiki contributors" }]
13
13
  keywords = ["themeparks", "disney", "universal", "wait-times", "api"]
14
14
  classifiers = [
15
- "Development Status :: 4 - Beta",
15
+ "Development Status :: 5 - Production/Stable",
16
16
  "Intended Audience :: Developers",
17
17
  "License :: OSI Approved :: MIT License",
18
18
  "Programming Language :: Python :: 3",
@@ -40,7 +40,9 @@ dev = [
40
40
  "pytest>=8",
41
41
  "pytest-asyncio>=0.23",
42
42
  "pytest-recording>=0.13",
43
- "ruff>=0.4",
43
+ # Upper-bounded: an unpinned minor bump is what started reformatting
44
+ # Markdown code blocks and turned CI red on unrelated PRs.
45
+ "ruff>=0.4,<0.17",
44
46
  "mypy>=1.10",
45
47
  "datamodel-code-generator[http]>=0.25",
46
48
  ]
@@ -63,6 +65,11 @@ asyncio_mode = "auto"
63
65
  [tool.ruff]
64
66
  line-length = 100
65
67
  target-version = "py39"
68
+ # Markdown is documentation, not source. Ruff 0.16 began formatting Python
69
+ # blocks inside it, which rewrites hand-written examples in README.md,
70
+ # MIGRATION.md and docs/ — CI has been failing `ruff format --check .` on
71
+ # those four files regardless of what any PR changes. Prose stays ours.
72
+ extend-exclude = ["*.md"]
66
73
 
67
74
  [tool.ruff.lint]
68
75
  select = ["E", "F", "W", "I", "N", "UP", "B", "A", "SIM", "PL"]
@@ -72,7 +79,9 @@ select = ["E", "F", "W", "I", "N", "UP", "B", "A", "SIM", "PL"]
72
79
  "themeparks/_errors.py" = ["A001", "UP045"]
73
80
  "themeparks/_transport.py" = ["A004"]
74
81
  "themeparks/__init__.py" = ["A004"]
75
- "themeparks/_generated/*.py" = ["N815", "F401"]
82
+ # E501: field descriptions come from the upstream spec, so line length is not
83
+ # this repo's to choose. The PriceData.amount description is already over.
84
+ "themeparks/_generated/*.py" = ["N815", "F401", "E501"]
76
85
 
77
86
  [tool.mypy]
78
87
  python_version = "3.9"
@@ -13,7 +13,7 @@ from themeparks._raw import AsyncRawClient, RawClient
13
13
  from themeparks._transport import AsyncTransport, RetryConfig, SyncTransport
14
14
 
15
15
  DEFAULT_BASE_URL = "https://api.themeparks.wiki/v1"
16
- PACKAGE_VERSION = "2.0.0a1"
16
+ PACKAGE_VERSION = "2.0.0"
17
17
 
18
18
 
19
19
  def _default_user_agent() -> str:
@@ -118,6 +118,9 @@ class ThemeParks:
118
118
  def __exit__(self, exc_type: Any, exc: Any, tb: Any) -> None:
119
119
  self.close()
120
120
 
121
+ def __repr__(self) -> str:
122
+ return f"ThemeParks(base_url={str(self._client.base_url).rstrip('/')!r})"
123
+
121
124
 
122
125
  class AsyncThemeParks:
123
126
  """Asynchronous mirror of :class:`ThemeParks`.
@@ -171,3 +174,6 @@ class AsyncThemeParks:
171
174
 
172
175
  async def __aexit__(self, exc_type: Any, exc: Any, tb: Any) -> None:
173
176
  await self.close()
177
+
178
+ def __repr__(self) -> str:
179
+ return f"AsyncThemeParks(base_url={str(self._client.base_url).rstrip('/')!r})"
@@ -9,139 +9,355 @@ from typing import Annotated, Any
9
9
  from pydantic import AwareDatetime, BaseModel, Field
10
10
 
11
11
 
12
- class EntityType(Enum):
13
- DESTINATION = "DESTINATION"
14
- PARK = "PARK"
15
- ATTRACTION = "ATTRACTION"
16
- RESTAURANT = "RESTAURANT"
17
- HOTEL = "HOTEL"
18
- SHOW = "SHOW"
19
-
12
+ class BoardingGroupState(Enum):
13
+ """
14
+ State of boarding group availability
15
+ """
20
16
 
21
- class LiveStatusType(Enum):
22
- OPERATING = "OPERATING"
23
- DOWN = "DOWN"
17
+ AVAILABLE = "AVAILABLE"
18
+ PAUSED = "PAUSED"
24
19
  CLOSED = "CLOSED"
25
- REFURBISHMENT = "REFURBISHMENT"
26
20
 
27
21
 
28
- class ReturnTimeState(Enum):
29
- AVAILABLE = "AVAILABLE"
30
- TEMP_FULL = "TEMP_FULL"
31
- FINISHED = "FINISHED"
22
+ class DiningAvailability(BaseModel):
23
+ partySize: float | None = None
24
+ """
25
+ Available party size
26
+ """
27
+ waitTime: float | None = None
28
+ """
29
+ Current wait time in minutes
30
+ """
32
31
 
33
32
 
34
- class BoardingGroupState(Enum):
35
- AVAILABLE = "AVAILABLE"
36
- PAUSED = "PAUSED"
37
- CLOSED = "CLOSED"
33
+ class EntityLocation(BaseModel):
34
+ latitude: float | None = None
35
+ """
36
+ Latitude coordinate of the entity location
37
+ """
38
+ longitude: float | None = None
39
+ """
40
+ Longitude coordinate of the entity location
41
+ """
38
42
 
39
43
 
40
- class PriceData(BaseModel):
41
- amount: float
42
- currency: str
43
- formatted: str | None = None
44
+ class EntityType(Enum):
45
+ """
46
+ Type of entity in the theme park system
47
+ """
48
+
49
+ DESTINATION = "DESTINATION"
50
+ PARK = "PARK"
51
+ ATTRACTION = "ATTRACTION"
52
+ RESTAURANT = "RESTAURANT"
53
+ HOTEL = "HOTEL"
54
+ SHOW = "SHOW"
44
55
 
45
56
 
46
57
  class StandbyQueue(BaseModel):
47
58
  waitTime: float | None = None
59
+ """
60
+ Current standby wait time in minutes
61
+ """
48
62
 
49
63
 
50
64
  class SingleRiderQueue(BaseModel):
51
65
  waitTime: float | None = None
52
-
53
-
54
- class ReturnTimeQueue(BaseModel):
55
- state: ReturnTimeState | None = None
56
- returnStart: AwareDatetime | None = None
57
- returnEnd: AwareDatetime | None = None
58
-
59
-
60
- class PaidReturnTimeQueue(BaseModel):
61
- state: ReturnTimeState | None = None
62
- returnStart: AwareDatetime | None = None
63
- returnEnd: AwareDatetime | None = None
64
- price: PriceData | None = None
66
+ """
67
+ Current single rider wait time in minutes
68
+ """
65
69
 
66
70
 
67
71
  class BoardingGroupQueue(BaseModel):
68
72
  allocationStatus: BoardingGroupState | None = None
69
73
  currentGroupStart: float | None = None
74
+ """
75
+ Current boarding group start number
76
+ """
70
77
  currentGroupEnd: float | None = None
78
+ """
79
+ Current boarding group end number
80
+ """
71
81
  nextAllocationTime: AwareDatetime | None = None
82
+ """
83
+ Next boarding group allocation time
84
+ """
72
85
  estimatedWait: float | None = None
86
+ """
87
+ Estimated wait time in minutes
88
+ """
73
89
 
74
90
 
75
91
  class PaidStandbyQueue(BaseModel):
76
92
  waitTime: float | None = None
77
-
78
-
79
- class LiveQueue(BaseModel):
80
- STANDBY: StandbyQueue | None = None
81
- SINGLE_RIDER: SingleRiderQueue | None = None
82
- RETURN_TIME: ReturnTimeQueue | None = None
83
- PAID_RETURN_TIME: PaidReturnTimeQueue | None = None
84
- BOARDING_GROUP: BoardingGroupQueue | None = None
85
- PAID_STANDBY: PaidStandbyQueue | None = None
93
+ """
94
+ Current paid standby wait time in minutes
95
+ """
86
96
 
87
97
 
88
98
  class LiveShowTime(BaseModel):
89
99
  type: str
100
+ """
101
+ Type of show time entry
102
+ """
90
103
  startTime: AwareDatetime | None = None
104
+ """
105
+ Start time of the show
106
+ """
91
107
  endTime: AwareDatetime | None = None
108
+ """
109
+ End time of the show
110
+ """
92
111
 
93
112
 
94
- class DiningAvailability(BaseModel):
95
- partySize: float | None = None
96
- waitTime: float | None = None
113
+ class LiveStatusType(Enum):
114
+ """
115
+ Current operating status of an entity
116
+ """
117
+
118
+ OPERATING = "OPERATING"
119
+ DOWN = "DOWN"
120
+ CLOSED = "CLOSED"
121
+ REFURBISHMENT = "REFURBISHMENT"
122
+
123
+
124
+ class Park(BaseModel):
125
+ id: str
126
+ """
127
+ Unique identifier of the park
128
+ """
129
+ name: str
130
+ """
131
+ Name of the park
132
+ """
133
+
134
+
135
+ class PriceData(BaseModel):
136
+ amount: float | None = None
137
+ """
138
+ Numerical price amount, in the currency's lowest denomination (e.g. cents). null when the item costs money but the provider does not publish an amount; 0 means genuinely free
139
+ """
140
+ currency: str
141
+ """
142
+ Currency code
143
+ """
144
+ formatted: str | None = None
145
+ """
146
+ Formatted price string
147
+ """
148
+
149
+
150
+ class ReturnTimeState(Enum):
151
+ """
152
+ State of return time availability
153
+ """
154
+
155
+ AVAILABLE = "AVAILABLE"
156
+ TEMP_FULL = "TEMP_FULL"
157
+ FINISHED = "FINISHED"
158
+
159
+
160
+ class Type(Enum):
161
+ """
162
+ Type of schedule entry
163
+ """
164
+
165
+ OPERATING = "OPERATING"
166
+ TICKETED_EVENT = "TICKETED_EVENT"
167
+ PRIVATE_EVENT = "PRIVATE_EVENT"
168
+ EXTRA_HOURS = "EXTRA_HOURS"
169
+ INFO = "INFO"
170
+
171
+
172
+ class SchedulePriceType(Enum):
173
+ """
174
+ Type of schedule price
175
+ """
176
+
177
+ ADMISSION = "ADMISSION"
178
+ PACKAGE = "PACKAGE"
179
+ ATTRACTION = "ATTRACTION"
97
180
 
98
181
 
99
182
  class TagData(BaseModel):
100
183
  tag: str
184
+ """
185
+ Tag identifier
186
+ """
101
187
  tagName: str
188
+ """
189
+ Human readable tag name
190
+ """
102
191
  id: str | None = None
103
- value: str | float | dict[str, Any] | None = None
104
-
105
-
106
- class Location(BaseModel):
107
- latitude: float | None = None
108
- longitude: float | None = None
192
+ """
193
+ Unique identifier
194
+ """
195
+ value: Any | None = None
196
+ """
197
+ Tag value - can be string, number or object
198
+ """
109
199
 
110
200
 
111
- class EntityData(BaseModel):
201
+ class DestinationEntry(BaseModel):
112
202
  id: str
203
+ """
204
+ Unique identifier of the destination
205
+ """
113
206
  name: str
114
- entityType: EntityType
115
- parentId: str | None = None
116
- destinationId: str | None = None
117
- timezone: str
118
- location: Location | None = None
119
- tags: list[TagData] | None = None
207
+ """
208
+ Name of the destination
209
+ """
210
+ slug: str | None = None
211
+ """
212
+ URL-friendly slug for the destination
213
+ """
214
+ externalId: str | None = None
215
+ """
216
+ External entity ID from the source data provider
217
+ """
218
+ parks: list[Park]
219
+ """
220
+ Array of parks within this destination
221
+ """
222
+
223
+
224
+ class DestinationsResponse(BaseModel):
225
+ destinations: list[DestinationEntry]
226
+ """
227
+ Array of all destinations
228
+ """
120
229
 
121
230
 
122
231
  class EntityChild(BaseModel):
123
232
  id: str
233
+ """
234
+ Unique entity identifier
235
+ """
124
236
  name: str
237
+ """
238
+ Entity name
239
+ """
125
240
  entityType: EntityType
126
241
  externalId: str | None = None
242
+ """
243
+ External identifier
244
+ """
127
245
  parentId: str | None = None
128
- location: Location | None = None
246
+ """
247
+ Parent entity identifier
248
+ """
249
+ location: EntityLocation | None = None
129
250
 
130
251
 
131
252
  class EntityChildrenResponse(BaseModel):
132
253
  id: str | None = None
254
+ """
255
+ Parent entity identifier
256
+ """
133
257
  name: str | None = None
258
+ """
259
+ Parent entity name
260
+ """
134
261
  entityType: EntityType | None = None
135
262
  timezone: str | None = None
263
+ """
264
+ Entity timezone
265
+ """
136
266
  children: list[EntityChild] | None = None
137
267
 
138
268
 
269
+ class EntityData(BaseModel):
270
+ id: str
271
+ """
272
+ Unique entity identifier
273
+ """
274
+ name: str
275
+ """
276
+ Entity name
277
+ """
278
+ entityType: EntityType
279
+ parentId: str | None = None
280
+ """
281
+ Parent entity identifier
282
+ """
283
+ destinationId: str | None = None
284
+ """
285
+ DestinationEntry identifier
286
+ """
287
+ timezone: str
288
+ """
289
+ Entity timezone
290
+ """
291
+ location: EntityLocation | None = None
292
+ tags: list[TagData] | None = None
293
+
294
+
295
+ class ReturnTimeQueue(BaseModel):
296
+ state: ReturnTimeState | None = None
297
+ returnStart: AwareDatetime | None = None
298
+ """
299
+ Start time of return window
300
+ """
301
+ returnEnd: AwareDatetime | None = None
302
+ """
303
+ End time of return window
304
+ """
305
+
306
+
307
+ class PaidReturnTimeQueue(BaseModel):
308
+ state: ReturnTimeState | None = None
309
+ returnStart: AwareDatetime | None = None
310
+ returnEnd: AwareDatetime | None = None
311
+ price: PriceData | None = None
312
+
313
+
314
+ class LiveQueue(BaseModel):
315
+ STANDBY: StandbyQueue | None = None
316
+ SINGLE_RIDER: SingleRiderQueue | None = None
317
+ RETURN_TIME: ReturnTimeQueue | None = None
318
+ PAID_RETURN_TIME: PaidReturnTimeQueue | None = None
319
+ BOARDING_GROUP: BoardingGroupQueue | None = None
320
+ PAID_STANDBY: PaidStandbyQueue | None = None
321
+
322
+
323
+ class SchedulePriceObject(BaseModel):
324
+ type: SchedulePriceType | None = None
325
+ """
326
+ Type of price object
327
+ """
328
+ id: str | None = None
329
+ """
330
+ Unique identifier
331
+ """
332
+ name: str | None = None
333
+ """
334
+ Name of the price object
335
+ """
336
+ price: PriceData | None = None
337
+ """
338
+ Price of this purchase option
339
+ """
340
+ available: bool | None = None
341
+ """
342
+ Whether this price option is available
343
+ """
344
+
345
+
139
346
  class EntityLiveData(BaseModel):
140
347
  id: str
348
+ """
349
+ Entity identifier
350
+ """
141
351
  name: str
352
+ """
353
+ Entity name
354
+ """
142
355
  entityType: EntityType
143
356
  status: LiveStatusType | None = None
144
357
  lastUpdated: AwareDatetime
358
+ """
359
+ Last update timestamp
360
+ """
145
361
  queue: LiveQueue | None = None
146
362
  showtimes: list[LiveShowTime] | None = None
147
363
  operatingHours: list[LiveShowTime] | None = None
@@ -150,72 +366,87 @@ class EntityLiveData(BaseModel):
150
366
 
151
367
  class EntityLiveDataResponse(BaseModel):
152
368
  id: str | None = None
369
+ """
370
+ Entity identifier
371
+ """
153
372
  name: str | None = None
373
+ """
374
+ Entity name
375
+ """
154
376
  entityType: EntityType | None = None
155
377
  timezone: str | None = None
378
+ """
379
+ Entity timezone
380
+ """
156
381
  liveData: list[EntityLiveData] | None = None
157
382
 
158
383
 
159
- class Type(Enum):
160
- ADMISSION = "ADMISSION"
161
- PACKAGE = "PACKAGE"
162
- ATTRACTION = "ATTRACTION"
163
-
164
-
165
- class SchedulePriceObject(BaseModel):
166
- type: Type | None = None
167
- id: str | None = None
168
- name: str | None = None
169
- price: PriceData | None = None
170
- available: bool | None = None
171
-
172
-
173
- class Type1(Enum):
174
- OPERATING = "OPERATING"
175
- TICKETED_EVENT = "TICKETED_EVENT"
176
- PRIVATE_EVENT = "PRIVATE_EVENT"
177
- EXTRA_HOURS = "EXTRA_HOURS"
178
- INFO = "INFO"
179
-
180
-
181
384
  class ScheduleEntry(BaseModel):
182
385
  date: str
386
+ """
387
+ Schedule date
388
+ """
183
389
  openingTime: AwareDatetime
390
+ """
391
+ Opening time
392
+ """
184
393
  closingTime: AwareDatetime
185
- type: Type1
394
+ """
395
+ Closing time
396
+ """
397
+ type: Type
398
+ """
399
+ Type of schedule entry
400
+ """
401
+ description: str | None = None
402
+ """
403
+ Optional description of the schedule entry
404
+ """
186
405
  purchases: list[SchedulePriceObject] | None = None
406
+ """
407
+ Available purchases for this schedule entry
408
+ """
187
409
 
188
410
 
189
- class EntityScheduleResponse(BaseModel):
411
+ class ParkSchedule(BaseModel):
190
412
  id: str | None = None
413
+ """
414
+ Entity identifier
415
+ """
191
416
  name: str | None = None
417
+ """
418
+ Entity name
419
+ """
192
420
  entityType: EntityType | None = None
421
+ """
422
+ Type of entity
423
+ """
193
424
  timezone: str | None = None
194
- schedule: list[ScheduleEntry] | None = None
195
- parks: list[EntityScheduleResponse] | None = None
196
425
  """
197
- Only included for destinations, this will list all parks within the destination
426
+ Entity timezone
198
427
  """
428
+ schedule: list[ScheduleEntry] | None = None
199
429
 
200
430
 
201
- class DestinationParkEntry(BaseModel):
202
- id: str | None = None
203
- name: str | None = None
204
-
205
-
206
- class DestinationEntry(BaseModel):
431
+ class EntityScheduleResponse(BaseModel):
207
432
  id: str | None = None
433
+ """
434
+ Entity identifier
435
+ """
208
436
  name: str | None = None
209
- slug: str | None = None
210
- externalId: str | None = None
211
437
  """
212
- External entity ID from the source data provider
438
+ Entity name
439
+ """
440
+ entityType: EntityType | None = None
441
+ """
442
+ Type of entity
443
+ """
444
+ timezone: str | None = None
445
+ """
446
+ Entity timezone
447
+ """
448
+ schedule: list[ScheduleEntry] | None = None
449
+ parks: list[ParkSchedule] | None = None
450
+ """
451
+ Only included for destinations, lists all parks within the destination
213
452
  """
214
- parks: list[DestinationParkEntry] | None = None
215
-
216
-
217
- class DestinationsResponse(BaseModel):
218
- destinations: list[DestinationEntry] | None = None
219
-
220
-
221
- EntityScheduleResponse.model_rebuild()
@@ -1,41 +0,0 @@
1
- # Changelog
2
-
3
- ## [2.0.0a1] - 2026-04-15
4
- ### Added
5
- - MkDocs Material documentation site with full API reference and a cookbook
6
- (recipes for sorted wait times, 7-day schedules, geo-locations grouped by
7
- entity type, every queue variant, and HTTP debugging).
8
- - Top-level exports for `current_wait_time`, `iter_queues`, `parse_api_datetime`.
9
- - Class-level docstrings on every public surface for readable API reference rendering.
10
- - README sections explaining every queue variant (STANDBY, PAID_RETURN_TIME,
11
- BOARDING_GROUP, etc.) and how to enable the httpx logger for HTTP debugging.
12
-
13
- ### Fixed
14
- - `walk()` now makes a single API call instead of one per descendant — the
15
- `/children` endpoint already returns the entire subtree recursively. Walking
16
- Walt Disney World dropped from ~250 requests to 1.
17
- - `get_entity_schedule_month` now zero-pads the month (`/schedule/2026/05`,
18
- not `/schedule/2026/5`) per the API requirement.
19
- - `RetryConfig` field renamed `max_attempts` → `max_retries` to match its
20
- actual semantics (N retries beyond the first attempt = N+1 total calls).
21
- - `APIError` now includes a server-body excerpt in the exception message;
22
- `RateLimitError.__repr__` includes `retry_after`.
23
- - `destinations.find()` now performs the loose, case-insensitive substring
24
- match it had always promised in its docstring (was exact equality).
25
- - Generated queue variant classes renamed (`STANDBY` → `StandbyQueue` etc.)
26
- so users access `queue.STANDBY` instead of the awkward `queue.STANDBY_1`.
27
- - `eval-type-backport` is now a conditional dep on Python 3.9 so pydantic
28
- can evaluate PEP 604 union syntax in the generated models.
29
-
30
- ## [2.0.0a0] - 2026-04-14
31
- ### Added
32
- - Full rewrite on pydantic v2 + httpx.
33
- - Sync `ThemeParks` and `AsyncThemeParks` clients with shared core.
34
- - Ergonomic `client.entity(id)` navigation, `walk()`, `schedule.range()`.
35
- - Typed pydantic models, correctly handling nullable queue fields (fixes #1, #2).
36
- - Default-on caching with per-endpoint TTLs and pluggable adapter.
37
- - 429 `Retry-After` handling.
38
-
39
- ### Removed
40
- - Legacy `openapi_client` top-level import and generated surface. See MIGRATION.md.
41
- - `urllib3`-based transport.
File without changes
File without changes
File without changes