Coverage for src/data_api/models/buses.py: 100%
35 statements
« prev ^ index » next coverage.py v7.16.2, created at 2026-11-13 19:28 +0000
« prev ^ index » next coverage.py v7.16.2, created at 2026-11-13 19:28 +0000
1"""
2Shared bus response models.
4Pydantic models for request/response validation.
5Enums are imported from domain layer to avoid duplication.
6"""
8from pydantic import BaseModel, Field, field_validator
10from data_api.domain.buses.enums import (
11 BusDay,
12 BusDayWithCurrent,
13 BusDirection,
14 BusRouteType,
15 BusStopsName,
16 BusType,
17)
19__all__ = [
20 "BusStopsName",
21 "BusRouteType",
22 "BusType",
23 "BusDirection",
24 "BusDay",
25 "BusDayWithCurrent",
26 "BusInfo",
27 "BusStopsInfo",
28 "BusSchedule",
29 "BusArriveTime",
30 "BusDetailedSchedule",
31 "BusCanonicalSchedule",
32 "BusCanonicalDetailedSchedule",
33]
36class BusInfo(BaseModel):
37 """Bus route information."""
39 direction: str = Field(..., description="方向")
40 duration: str = Field(..., description="時刻表有效期間")
41 route: str = Field(..., description="路線")
42 routeEN: str = Field(..., description="英文路線")
45class BusStopsInfo(BaseModel):
46 """Bus stop information."""
48 name: str = Field(..., description="站牌中文名稱")
49 name_en: str = Field(..., description="站牌英文名稱")
50 latitude: str = Field(..., description="站牌所在地緯度")
51 longitude: str = Field(..., description="站牌所在地經度")
54class BusSchedule(BaseModel):
55 """Unified bus schedule entry for both Main and Nanda campus."""
57 time: str = Field(..., description="發車時間")
58 description: str = Field(..., description="備註")
59 dep_stop: str = Field(..., description="發車地點")
60 line: str = Field("", description="路線 (主校區: red/green, 南大: route_1/route_2)")
61 bus_type: BusType = Field(..., description="營運車輛類型")
64class BusArriveTime(BaseModel):
65 """Bus arrival time at a stop."""
67 stop: str = Field(..., description="公車站牌名稱")
68 arrive_time: str = Field(..., description="預計到達時間")
71class BusDetailedSchedule(BaseModel):
72 """Unified detailed bus schedule for both Main and Nanda campus."""
74 dep_info: BusSchedule = Field(..., description="發車資訊")
75 stops_time: list[BusArriveTime] = Field(..., description="各站發車時間")
78class BusCanonicalSchedule(BusSchedule):
79 """Schedule with campus-qualified line identifiers for the current API."""
81 line: str = Field("", description="路線 (main_red/main_green/nanda_route_1/nanda_route_2)")
82 arrive_time: str | None = Field(
83 None, description="指定站牌的預計到達時間(僅在提供 stop 參數時回傳,未指定時省略)"
84 )
86 @field_validator("line")
87 @classmethod
88 def qualify_line(cls, line: str) -> str:
89 return {
90 "red": "main_red",
91 "green": "main_green",
92 "route_1": "nanda_route_1",
93 "route_2": "nanda_route_2",
94 }.get(line, line)
97class BusCanonicalDetailedSchedule(BusDetailedSchedule):
98 """Detailed schedule with campus-qualified departure line identifiers."""
100 dep_info: BusCanonicalSchedule = Field(..., description="發車資訊")
101 arrive_time: str | None = Field(
102 None, description="指定站牌的預計到達時間(僅在提供 stop 參數時回傳,未指定時省略)"
103 )