datagsm-openapi-sdk 1.0.0b1__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.
- datagsm_openapi/__init__.py +61 -0
- datagsm_openapi/_http.py +291 -0
- datagsm_openapi/_json.py +53 -0
- datagsm_openapi/api/__init__.py +18 -0
- datagsm_openapi/api/_base.py +73 -0
- datagsm_openapi/api/club.py +106 -0
- datagsm_openapi/api/neis.py +141 -0
- datagsm_openapi/api/project.py +103 -0
- datagsm_openapi/api/student.py +128 -0
- datagsm_openapi/client.py +118 -0
- datagsm_openapi/exceptions.py +213 -0
- datagsm_openapi/models/__init__.py +41 -0
- datagsm_openapi/models/_common.py +37 -0
- datagsm_openapi/models/club.py +76 -0
- datagsm_openapi/models/enums.py +82 -0
- datagsm_openapi/models/neis.py +102 -0
- datagsm_openapi/models/project.py +76 -0
- datagsm_openapi/models/student.py +79 -0
- datagsm_openapi/py.typed +1 -0
- datagsm_openapi_sdk-1.0.0b1.dist-info/METADATA +55 -0
- datagsm_openapi_sdk-1.0.0b1.dist-info/RECORD +24 -0
- datagsm_openapi_sdk-1.0.0b1.dist-info/WHEEL +5 -0
- datagsm_openapi_sdk-1.0.0b1.dist-info/licenses/LICENSE +21 -0
- datagsm_openapi_sdk-1.0.0b1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"""NEIS API module for DataGSM OpenAPI SDK."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from datetime import date as Date
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
from ..models import Meal, Schedule
|
|
8
|
+
from ._base import BaseApi
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass
|
|
12
|
+
class MealRequest:
|
|
13
|
+
"""급식 조회 요청 파라미터 (Meal Query Parameters).
|
|
14
|
+
|
|
15
|
+
Use either 'date' for a single day or 'from_date' and 'to_date' for a date range.
|
|
16
|
+
|
|
17
|
+
Attributes:
|
|
18
|
+
date: Single date to query
|
|
19
|
+
from_date: Start date for range query
|
|
20
|
+
to_date: End date for range query
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
date: Optional[Date] = None
|
|
24
|
+
from_date: Optional[Date] = None
|
|
25
|
+
to_date: Optional[Date] = None
|
|
26
|
+
|
|
27
|
+
def to_params(self) -> dict[str, Optional[object]]:
|
|
28
|
+
"""Convert to query parameters dictionary.
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
Dictionary of query parameters
|
|
32
|
+
"""
|
|
33
|
+
params: dict[str, Optional[object]] = {
|
|
34
|
+
"date": self.date,
|
|
35
|
+
"fromDate": self.from_date,
|
|
36
|
+
"toDate": self.to_date,
|
|
37
|
+
}
|
|
38
|
+
return params
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@dataclass
|
|
42
|
+
class ScheduleRequest:
|
|
43
|
+
"""학사일정 조회 요청 파라미터 (Schedule Query Parameters).
|
|
44
|
+
|
|
45
|
+
Use either 'date' for a single day or 'from_date' and 'to_date' for a date range.
|
|
46
|
+
|
|
47
|
+
Attributes:
|
|
48
|
+
date: Single date to query
|
|
49
|
+
from_date: Start date for range query
|
|
50
|
+
to_date: End date for range query
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
date: Optional[Date] = None
|
|
54
|
+
from_date: Optional[Date] = None
|
|
55
|
+
to_date: Optional[Date] = None
|
|
56
|
+
|
|
57
|
+
def to_params(self) -> dict[str, Optional[object]]:
|
|
58
|
+
"""Convert to query parameters dictionary.
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
Dictionary of query parameters
|
|
62
|
+
"""
|
|
63
|
+
params: dict[str, Optional[object]] = {
|
|
64
|
+
"date": self.date,
|
|
65
|
+
"fromDate": self.from_date,
|
|
66
|
+
"toDate": self.to_date,
|
|
67
|
+
}
|
|
68
|
+
return params
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class NeisApi(BaseApi):
|
|
72
|
+
"""NEIS 데이터 API (NEIS Data API).
|
|
73
|
+
|
|
74
|
+
Provides methods for querying school meal and schedule information from NEIS.
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
def get_meals(self, request: Optional[MealRequest] = None) -> list[Meal]:
|
|
78
|
+
"""급식 정보 조회 (Get Meal Information).
|
|
79
|
+
|
|
80
|
+
Query school meal information for a specific date or date range.
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
request: Query parameters (optional, defaults to today)
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
List of meals
|
|
87
|
+
|
|
88
|
+
Example:
|
|
89
|
+
>>> from datetime import date
|
|
90
|
+
>>> api = NeisApi(http_client)
|
|
91
|
+
>>>
|
|
92
|
+
>>> # Get today's meals
|
|
93
|
+
>>> today_meals = api.get_meals()
|
|
94
|
+
>>>
|
|
95
|
+
>>> # Get meals for a specific date
|
|
96
|
+
>>> request = MealRequest(date=date(2026, 2, 3))
|
|
97
|
+
>>> meals = api.get_meals(request)
|
|
98
|
+
>>>
|
|
99
|
+
>>> # Get meals for a date range
|
|
100
|
+
>>> request = MealRequest(
|
|
101
|
+
... from_date=date(2026, 2, 1),
|
|
102
|
+
... to_date=date(2026, 2, 7)
|
|
103
|
+
... )
|
|
104
|
+
>>> week_meals = api.get_meals(request)
|
|
105
|
+
"""
|
|
106
|
+
req = request or MealRequest(date=Date.today())
|
|
107
|
+
return self._get("/v1/neis/meals", params=req.to_params(), response_type=list[Meal])
|
|
108
|
+
|
|
109
|
+
def get_schedules(self, request: Optional[ScheduleRequest] = None) -> list[Schedule]:
|
|
110
|
+
"""학사일정 정보 조회 (Get Schedule Information).
|
|
111
|
+
|
|
112
|
+
Query school schedule/event information for a specific date or date range.
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
request: Query parameters (optional, defaults to today)
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
List of schedules
|
|
119
|
+
|
|
120
|
+
Example:
|
|
121
|
+
>>> from datetime import date
|
|
122
|
+
>>> api = NeisApi(http_client)
|
|
123
|
+
>>>
|
|
124
|
+
>>> # Get today's schedules
|
|
125
|
+
>>> today_events = api.get_schedules()
|
|
126
|
+
>>>
|
|
127
|
+
>>> # Get schedules for a specific date
|
|
128
|
+
>>> request = ScheduleRequest(date=date(2026, 3, 1))
|
|
129
|
+
>>> schedules = api.get_schedules(request)
|
|
130
|
+
>>>
|
|
131
|
+
>>> # Get schedules for a date range
|
|
132
|
+
>>> request = ScheduleRequest(
|
|
133
|
+
... from_date=date(2026, 3, 1),
|
|
134
|
+
... to_date=date(2026, 3, 31)
|
|
135
|
+
... )
|
|
136
|
+
>>> month_schedules = api.get_schedules(request)
|
|
137
|
+
"""
|
|
138
|
+
req = request or ScheduleRequest(date=Date.today())
|
|
139
|
+
return self._get(
|
|
140
|
+
"/v1/neis/schedules", params=req.to_params(), response_type=list[Schedule]
|
|
141
|
+
)
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"""Project API module for DataGSM OpenAPI SDK."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
from ..models import Project, ProjectResponse, ProjectSortBy, SortDirection
|
|
7
|
+
from ._base import BaseApi
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass
|
|
11
|
+
class ProjectRequest:
|
|
12
|
+
"""프로젝트 조회 요청 파라미터 (Project Query Parameters).
|
|
13
|
+
|
|
14
|
+
Attributes:
|
|
15
|
+
project_id: Project ID for exact match
|
|
16
|
+
project_name: Project name for filtering
|
|
17
|
+
club_id: Club ID filter
|
|
18
|
+
page: Page number (default: 0)
|
|
19
|
+
size: Page size (default: 100)
|
|
20
|
+
sort_by: Sort field
|
|
21
|
+
sort_direction: Sort direction (default: ASC)
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
project_id: Optional[int] = None
|
|
25
|
+
project_name: Optional[str] = None
|
|
26
|
+
club_id: Optional[int] = None
|
|
27
|
+
page: int = 0
|
|
28
|
+
size: int = 100
|
|
29
|
+
sort_by: Optional[ProjectSortBy] = None
|
|
30
|
+
sort_direction: SortDirection = SortDirection.ASC
|
|
31
|
+
|
|
32
|
+
def to_params(self) -> dict[str, Optional[object]]:
|
|
33
|
+
"""Convert to query parameters dictionary.
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
Dictionary of query parameters
|
|
37
|
+
"""
|
|
38
|
+
params: dict[str, Optional[object]] = {
|
|
39
|
+
"projectId": self.project_id,
|
|
40
|
+
"projectName": self.project_name,
|
|
41
|
+
"clubId": self.club_id,
|
|
42
|
+
"page": self.page,
|
|
43
|
+
"size": self.size,
|
|
44
|
+
"sortBy": self.sort_by.value if self.sort_by else None,
|
|
45
|
+
"sortDirection": self.sort_direction.value,
|
|
46
|
+
}
|
|
47
|
+
return params
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class ProjectApi(BaseApi):
|
|
51
|
+
"""프로젝트 데이터 API (Project Data API).
|
|
52
|
+
|
|
53
|
+
Provides methods for querying project information.
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
def get_projects(self, request: Optional[ProjectRequest] = None) -> ProjectResponse:
|
|
57
|
+
"""프로젝트 목록 조회 (Get Project List).
|
|
58
|
+
|
|
59
|
+
Query projects with optional filtering, sorting, and pagination.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
request: Query parameters (optional)
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
Paginated project response
|
|
66
|
+
|
|
67
|
+
Example:
|
|
68
|
+
>>> api = ProjectApi(http_client)
|
|
69
|
+
>>> # Get all projects
|
|
70
|
+
>>> response = api.get_projects()
|
|
71
|
+
>>> print(f"Total: {response.total_elements}")
|
|
72
|
+
>>>
|
|
73
|
+
>>> # Filter by club
|
|
74
|
+
>>> request = ProjectRequest(club_id=1)
|
|
75
|
+
>>> club_projects = api.get_projects(request)
|
|
76
|
+
"""
|
|
77
|
+
req = request or ProjectRequest()
|
|
78
|
+
return self._get("/v1/projects", params=req.to_params(), response_type=ProjectResponse)
|
|
79
|
+
|
|
80
|
+
def get_project(self, project_id: int) -> Optional[Project]:
|
|
81
|
+
"""특정 프로젝트 조회 (Get Specific Project).
|
|
82
|
+
|
|
83
|
+
Retrieve a single project by ID.
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
project_id: Project ID
|
|
87
|
+
|
|
88
|
+
Returns:
|
|
89
|
+
Project information if found, None otherwise
|
|
90
|
+
|
|
91
|
+
Example:
|
|
92
|
+
>>> api = ProjectApi(http_client)
|
|
93
|
+
>>> project = api.get_project(1)
|
|
94
|
+
>>> if project:
|
|
95
|
+
... print(f"Project: {project.name}")
|
|
96
|
+
... print(f"Description: {project.description}")
|
|
97
|
+
"""
|
|
98
|
+
request = ProjectRequest(project_id=project_id)
|
|
99
|
+
response = self.get_projects(request)
|
|
100
|
+
|
|
101
|
+
if response.projects:
|
|
102
|
+
return response.projects[0]
|
|
103
|
+
return None
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"""Student API module for DataGSM OpenAPI SDK."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
from ..models import Sex, SortDirection, Student, StudentResponse, StudentRole, StudentSortBy
|
|
7
|
+
from ._base import BaseApi
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass
|
|
11
|
+
class StudentRequest:
|
|
12
|
+
"""학생 조회 요청 파라미터 (Student Query Parameters).
|
|
13
|
+
|
|
14
|
+
Attributes:
|
|
15
|
+
student_id: Student ID for exact match
|
|
16
|
+
name: Student name for filtering
|
|
17
|
+
email: Email address for filtering
|
|
18
|
+
grade: Grade (1-3)
|
|
19
|
+
class_num: Class number
|
|
20
|
+
number: Student number within class
|
|
21
|
+
sex: Gender filter
|
|
22
|
+
role: Student role filter
|
|
23
|
+
dormitory_room: Dormitory room number
|
|
24
|
+
is_leave_school: Filter by leave school status
|
|
25
|
+
is_graduate: Filter by graduate status
|
|
26
|
+
page: Page number (default: 0)
|
|
27
|
+
size: Page size (default: 300)
|
|
28
|
+
sort_by: Sort field
|
|
29
|
+
sort_direction: Sort direction (default: ASC)
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
student_id: Optional[int] = None
|
|
33
|
+
name: Optional[str] = None
|
|
34
|
+
email: Optional[str] = None
|
|
35
|
+
grade: Optional[int] = None
|
|
36
|
+
class_num: Optional[int] = None
|
|
37
|
+
number: Optional[int] = None
|
|
38
|
+
sex: Optional[Sex] = None
|
|
39
|
+
role: Optional[StudentRole] = None
|
|
40
|
+
dormitory_room: Optional[int] = None
|
|
41
|
+
is_leave_school: Optional[bool] = None
|
|
42
|
+
is_graduate: Optional[bool] = None
|
|
43
|
+
page: int = 0
|
|
44
|
+
size: int = 300
|
|
45
|
+
sort_by: Optional[StudentSortBy] = None
|
|
46
|
+
sort_direction: SortDirection = SortDirection.ASC
|
|
47
|
+
|
|
48
|
+
def to_params(self) -> dict[str, Optional[object]]:
|
|
49
|
+
"""Convert to query parameters dictionary.
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
Dictionary of query parameters
|
|
53
|
+
"""
|
|
54
|
+
params: dict[str, Optional[object]] = {
|
|
55
|
+
"studentId": self.student_id,
|
|
56
|
+
"name": self.name,
|
|
57
|
+
"email": self.email,
|
|
58
|
+
"grade": self.grade,
|
|
59
|
+
"classNum": self.class_num,
|
|
60
|
+
"number": self.number,
|
|
61
|
+
"sex": self.sex.value if self.sex else None,
|
|
62
|
+
"role": self.role.value if self.role else None,
|
|
63
|
+
"dormitoryRoom": self.dormitory_room,
|
|
64
|
+
"isLeaveSchool": self.is_leave_school,
|
|
65
|
+
"isGraduated": self.is_graduate,
|
|
66
|
+
"page": self.page,
|
|
67
|
+
"size": self.size,
|
|
68
|
+
"sortBy": self.sort_by.value if self.sort_by else None,
|
|
69
|
+
"sortDirection": self.sort_direction.value,
|
|
70
|
+
}
|
|
71
|
+
return params
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class StudentApi(BaseApi):
|
|
75
|
+
"""학생 데이터 API (Student Data API).
|
|
76
|
+
|
|
77
|
+
Provides methods for querying student information.
|
|
78
|
+
"""
|
|
79
|
+
|
|
80
|
+
def get_students(
|
|
81
|
+
self, request: Optional[StudentRequest] = None
|
|
82
|
+
) -> StudentResponse:
|
|
83
|
+
"""학생 목록 조회 (Get Student List).
|
|
84
|
+
|
|
85
|
+
Query students with optional filtering, sorting, and pagination.
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
request: Query parameters (optional)
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
Paginated student response
|
|
92
|
+
|
|
93
|
+
Example:
|
|
94
|
+
>>> api = StudentApi(http_client)
|
|
95
|
+
>>> # Get all students
|
|
96
|
+
>>> response = api.get_students()
|
|
97
|
+
>>> print(f"Total: {response.total_elements}")
|
|
98
|
+
>>>
|
|
99
|
+
>>> # Filter by grade
|
|
100
|
+
>>> request = StudentRequest(grade=1)
|
|
101
|
+
>>> first_graders = api.get_students(request)
|
|
102
|
+
"""
|
|
103
|
+
req = request or StudentRequest()
|
|
104
|
+
return self._get("/v1/students", params=req.to_params(), response_type=StudentResponse)
|
|
105
|
+
|
|
106
|
+
def get_student(self, student_id: int) -> Optional[Student]:
|
|
107
|
+
"""특정 학생 조회 (Get Specific Student).
|
|
108
|
+
|
|
109
|
+
Retrieve a single student by ID.
|
|
110
|
+
|
|
111
|
+
Args:
|
|
112
|
+
student_id: Student ID
|
|
113
|
+
|
|
114
|
+
Returns:
|
|
115
|
+
Student information if found, None otherwise
|
|
116
|
+
|
|
117
|
+
Example:
|
|
118
|
+
>>> api = StudentApi(http_client)
|
|
119
|
+
>>> student = api.get_student(123)
|
|
120
|
+
>>> if student:
|
|
121
|
+
... print(f"Name: {student.name}")
|
|
122
|
+
"""
|
|
123
|
+
request = StudentRequest(student_id=student_id)
|
|
124
|
+
response = self.get_students(request)
|
|
125
|
+
|
|
126
|
+
if response.students:
|
|
127
|
+
return response.students[0]
|
|
128
|
+
return None
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"""Main client class for DataGSM OpenAPI SDK."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Optional
|
|
4
|
+
|
|
5
|
+
from ._http import HttpClient
|
|
6
|
+
from .api import ClubApi, NeisApi, ProjectApi, StudentApi
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class DataGsmClient:
|
|
10
|
+
"""Main client for interacting with the DataGSM OpenAPI.
|
|
11
|
+
|
|
12
|
+
This is the main entry point for the SDK. Create an instance with your API key
|
|
13
|
+
and use it to access various API endpoints.
|
|
14
|
+
|
|
15
|
+
Example:
|
|
16
|
+
Basic usage::
|
|
17
|
+
|
|
18
|
+
with DataGsmClient(api_key="your-api-key") as client:
|
|
19
|
+
students = client.students.get_students()
|
|
20
|
+
|
|
21
|
+
Attributes:
|
|
22
|
+
base_url: Base URL for the API
|
|
23
|
+
timeout: Request timeout in seconds
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
DEFAULT_BASE_URL = "https://openapi.data.hellogsm.kr"
|
|
27
|
+
|
|
28
|
+
def __init__(
|
|
29
|
+
self,
|
|
30
|
+
api_key: str,
|
|
31
|
+
base_url: Optional[str] = None,
|
|
32
|
+
timeout: float = 30.0,
|
|
33
|
+
) -> None:
|
|
34
|
+
"""Initialize the DataGSM client.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
api_key: Your DataGSM API key
|
|
38
|
+
base_url: Base URL for the API (default: https://openapi.data.hellogsm.kr)
|
|
39
|
+
timeout: Request timeout in seconds (default: 30.0)
|
|
40
|
+
"""
|
|
41
|
+
self.base_url = base_url or self.DEFAULT_BASE_URL
|
|
42
|
+
self.timeout = timeout
|
|
43
|
+
self._http_client = HttpClient(
|
|
44
|
+
base_url=self.base_url,
|
|
45
|
+
api_key=api_key,
|
|
46
|
+
timeout=timeout,
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
# Initialize API modules
|
|
50
|
+
self._student_api = StudentApi(self._http_client)
|
|
51
|
+
self._club_api = ClubApi(self._http_client)
|
|
52
|
+
self._project_api = ProjectApi(self._http_client)
|
|
53
|
+
self._neis_api = NeisApi(self._http_client)
|
|
54
|
+
|
|
55
|
+
@property
|
|
56
|
+
def students(self) -> StudentApi:
|
|
57
|
+
"""Access the Student API.
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
StudentApi instance
|
|
61
|
+
|
|
62
|
+
Example:
|
|
63
|
+
>>> with DataGsmClient(api_key="key") as client:
|
|
64
|
+
... students = client.students.get_students()
|
|
65
|
+
"""
|
|
66
|
+
return self._student_api
|
|
67
|
+
|
|
68
|
+
@property
|
|
69
|
+
def clubs(self) -> ClubApi:
|
|
70
|
+
"""Access the Club API.
|
|
71
|
+
|
|
72
|
+
Returns:
|
|
73
|
+
ClubApi instance
|
|
74
|
+
|
|
75
|
+
Example:
|
|
76
|
+
>>> with DataGsmClient(api_key="key") as client:
|
|
77
|
+
... clubs = client.clubs.get_clubs()
|
|
78
|
+
"""
|
|
79
|
+
return self._club_api
|
|
80
|
+
|
|
81
|
+
@property
|
|
82
|
+
def projects(self) -> ProjectApi:
|
|
83
|
+
"""Access the Project API.
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
ProjectApi instance
|
|
87
|
+
|
|
88
|
+
Example:
|
|
89
|
+
>>> with DataGsmClient(api_key="key") as client:
|
|
90
|
+
... projects = client.projects.get_projects()
|
|
91
|
+
"""
|
|
92
|
+
return self._project_api
|
|
93
|
+
|
|
94
|
+
@property
|
|
95
|
+
def neis(self) -> NeisApi:
|
|
96
|
+
"""Access the NEIS API.
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
NeisApi instance
|
|
100
|
+
|
|
101
|
+
Example:
|
|
102
|
+
>>> with DataGsmClient(api_key="key") as client:
|
|
103
|
+
... meals = client.neis.get_meals()
|
|
104
|
+
"""
|
|
105
|
+
return self._neis_api
|
|
106
|
+
|
|
107
|
+
def __enter__(self) -> "DataGsmClient":
|
|
108
|
+
"""Enter context manager."""
|
|
109
|
+
self._http_client.__enter__()
|
|
110
|
+
return self
|
|
111
|
+
|
|
112
|
+
def __exit__(self, *args: Any) -> None:
|
|
113
|
+
"""Exit context manager and close resources."""
|
|
114
|
+
self._http_client.__exit__(*args)
|
|
115
|
+
|
|
116
|
+
def close(self) -> None:
|
|
117
|
+
"""Close the client and release resources."""
|
|
118
|
+
self._http_client.close()
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
"""Exception classes for DataGSM OpenAPI SDK."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Optional
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class DataGsmException(Exception):
|
|
7
|
+
"""Base exception for all DataGSM API errors.
|
|
8
|
+
|
|
9
|
+
Attributes:
|
|
10
|
+
message: Human-readable error message
|
|
11
|
+
status_code: HTTP status code if available
|
|
12
|
+
response_body: Raw response body if available
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def __init__(
|
|
16
|
+
self,
|
|
17
|
+
message: str,
|
|
18
|
+
status_code: Optional[int] = None,
|
|
19
|
+
response_body: Optional[dict[str, Any]] = None,
|
|
20
|
+
) -> None:
|
|
21
|
+
"""Initialize the exception.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
message: Error message
|
|
25
|
+
status_code: HTTP status code
|
|
26
|
+
response_body: Raw response body
|
|
27
|
+
"""
|
|
28
|
+
super().__init__(message)
|
|
29
|
+
self.message = message
|
|
30
|
+
self.status_code = status_code
|
|
31
|
+
self.response_body = response_body
|
|
32
|
+
|
|
33
|
+
def __str__(self) -> str:
|
|
34
|
+
"""Return string representation of the exception."""
|
|
35
|
+
if self.status_code:
|
|
36
|
+
return f"[{self.status_code}] {self.message}"
|
|
37
|
+
return self.message
|
|
38
|
+
|
|
39
|
+
def __repr__(self) -> str:
|
|
40
|
+
"""Return detailed representation of the exception."""
|
|
41
|
+
return (
|
|
42
|
+
f"{self.__class__.__name__}("
|
|
43
|
+
f"message={self.message!r}, "
|
|
44
|
+
f"status_code={self.status_code!r})"
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class BadRequestException(DataGsmException):
|
|
49
|
+
"""Exception raised for 400 Bad Request errors.
|
|
50
|
+
|
|
51
|
+
Indicates that the request was malformed or contained invalid parameters.
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
def __init__(
|
|
55
|
+
self,
|
|
56
|
+
message: str = "Bad request",
|
|
57
|
+
response_body: Optional[dict[str, Any]] = None,
|
|
58
|
+
) -> None:
|
|
59
|
+
"""Initialize the exception.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
message: Error message
|
|
63
|
+
response_body: Raw response body
|
|
64
|
+
"""
|
|
65
|
+
super().__init__(message=message, status_code=400, response_body=response_body)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class UnauthorizedException(DataGsmException):
|
|
69
|
+
"""Exception raised for 401 Unauthorized errors.
|
|
70
|
+
|
|
71
|
+
Indicates that the API key is missing or invalid.
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
def __init__(
|
|
75
|
+
self,
|
|
76
|
+
message: str = "Unauthorized: Invalid or missing API key",
|
|
77
|
+
response_body: Optional[dict[str, Any]] = None,
|
|
78
|
+
) -> None:
|
|
79
|
+
"""Initialize the exception.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
message: Error message
|
|
83
|
+
response_body: Raw response body
|
|
84
|
+
"""
|
|
85
|
+
super().__init__(message=message, status_code=401, response_body=response_body)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class ForbiddenException(DataGsmException):
|
|
89
|
+
"""Exception raised for 403 Forbidden errors.
|
|
90
|
+
|
|
91
|
+
Indicates that the API key doesn't have permission for the requested resource.
|
|
92
|
+
"""
|
|
93
|
+
|
|
94
|
+
def __init__(
|
|
95
|
+
self,
|
|
96
|
+
message: str = "Forbidden: Insufficient permissions",
|
|
97
|
+
response_body: Optional[dict[str, Any]] = None,
|
|
98
|
+
) -> None:
|
|
99
|
+
"""Initialize the exception.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
message: Error message
|
|
103
|
+
response_body: Raw response body
|
|
104
|
+
"""
|
|
105
|
+
super().__init__(message=message, status_code=403, response_body=response_body)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class NotFoundException(DataGsmException):
|
|
109
|
+
"""Exception raised for 404 Not Found errors.
|
|
110
|
+
|
|
111
|
+
Indicates that the requested resource was not found.
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
def __init__(
|
|
115
|
+
self,
|
|
116
|
+
message: str = "Not found",
|
|
117
|
+
response_body: Optional[dict[str, Any]] = None,
|
|
118
|
+
) -> None:
|
|
119
|
+
"""Initialize the exception.
|
|
120
|
+
|
|
121
|
+
Args:
|
|
122
|
+
message: Error message
|
|
123
|
+
response_body: Raw response body
|
|
124
|
+
"""
|
|
125
|
+
super().__init__(message=message, status_code=404, response_body=response_body)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
class RateLimitException(DataGsmException):
|
|
129
|
+
"""Exception raised for 429 Too Many Requests errors.
|
|
130
|
+
|
|
131
|
+
Indicates that the rate limit has been exceeded.
|
|
132
|
+
"""
|
|
133
|
+
|
|
134
|
+
def __init__(
|
|
135
|
+
self,
|
|
136
|
+
message: str = "Rate limit exceeded",
|
|
137
|
+
response_body: Optional[dict[str, Any]] = None,
|
|
138
|
+
) -> None:
|
|
139
|
+
"""Initialize the exception.
|
|
140
|
+
|
|
141
|
+
Args:
|
|
142
|
+
message: Error message
|
|
143
|
+
response_body: Raw response body
|
|
144
|
+
"""
|
|
145
|
+
super().__init__(message=message, status_code=429, response_body=response_body)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
class ServerErrorException(DataGsmException):
|
|
149
|
+
"""Exception raised for 5xx Server Error responses.
|
|
150
|
+
|
|
151
|
+
Indicates that the server encountered an error processing the request.
|
|
152
|
+
"""
|
|
153
|
+
|
|
154
|
+
def __init__(
|
|
155
|
+
self,
|
|
156
|
+
message: str = "Internal server error",
|
|
157
|
+
status_code: int = 500,
|
|
158
|
+
response_body: Optional[dict[str, Any]] = None,
|
|
159
|
+
) -> None:
|
|
160
|
+
"""Initialize the exception.
|
|
161
|
+
|
|
162
|
+
Args:
|
|
163
|
+
message: Error message
|
|
164
|
+
status_code: HTTP status code (5xx)
|
|
165
|
+
response_body: Raw response body
|
|
166
|
+
"""
|
|
167
|
+
super().__init__(
|
|
168
|
+
message=message,
|
|
169
|
+
status_code=status_code,
|
|
170
|
+
response_body=response_body,
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
class NetworkException(DataGsmException):
|
|
175
|
+
"""Exception raised for network-related errors.
|
|
176
|
+
|
|
177
|
+
Indicates connection failures, timeouts, or other network issues.
|
|
178
|
+
"""
|
|
179
|
+
|
|
180
|
+
def __init__(
|
|
181
|
+
self,
|
|
182
|
+
message: str,
|
|
183
|
+
original_exception: Optional[Exception] = None,
|
|
184
|
+
) -> None:
|
|
185
|
+
"""Initialize the exception.
|
|
186
|
+
|
|
187
|
+
Args:
|
|
188
|
+
message: Error message
|
|
189
|
+
original_exception: The underlying exception that caused this error
|
|
190
|
+
"""
|
|
191
|
+
super().__init__(message=message)
|
|
192
|
+
self.original_exception = original_exception
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
class ValidationException(DataGsmException):
|
|
196
|
+
"""Exception raised for data validation errors.
|
|
197
|
+
|
|
198
|
+
Indicates that response data failed validation against the expected schema.
|
|
199
|
+
"""
|
|
200
|
+
|
|
201
|
+
def __init__(
|
|
202
|
+
self,
|
|
203
|
+
message: str,
|
|
204
|
+
validation_errors: Optional[list[dict[str, Any]]] = None,
|
|
205
|
+
) -> None:
|
|
206
|
+
"""Initialize the exception.
|
|
207
|
+
|
|
208
|
+
Args:
|
|
209
|
+
message: Error message
|
|
210
|
+
validation_errors: List of validation errors from Pydantic
|
|
211
|
+
"""
|
|
212
|
+
super().__init__(message=message)
|
|
213
|
+
self.validation_errors = validation_errors or []
|