Cat Feeder  1.0.0
The Cat feeder project
Loading...
Searching...
No Matches
parameters.py
Go to the documentation of this file.
1r"""
2# +==== BEGIN CatFeeder =================+
3# LOGO:
4# ..............(..../\
5# ...............)..(.')
6# ..............(../..)
7# ...............\‍(__)|
8# Inspired by Joan Stark
9# source https://www.asciiart.eu/
10# animals/cats
11# /STOP
12# PROJECT: CatFeeder
13# FILE: parameters.py
14# CREATION DATE: 23-01-2026
15# LAST Modified: 1:12:8 24-01-2026
16# DESCRIPTION:
17# This is the project in charge of making the connected cat feeder project work.
18# /STOP
19# COPYRIGHT: (c) Cat Feeder
20# PURPOSE: Parameter decorators for API endpoint metadata management.
21#
22# Provides decorators for documenting request parameters, headers, and body content.
23# /STOP
24# // AR
25# +==== END CatFeeder =================+
26"""
27from typing import Callable, Optional, Dict, Any, Union
28from functools import wraps
29
30
31def _preserve_metadata(func: Callable, wrapper: Callable) -> None:
32 """Helper function to preserve existing metadata attributes."""
33 metadata_attrs = [
34 '_requires_auth', '_requires_admin', '_public', '_testing_only',
35 '_security_level', '_environment', '_description', '_summary',
36 '_response_model', '_tags', '_requires_body', '_body_model',
37 '_requires_headers', '_header_names', '_requires_auth_header',
38 '_auth_header_name', '_requires_bearer_auth', '_requires_basic_auth',
39 '_requires_api_key', '_auth_scheme', '_requires_query_params',
40 '_query_params', '_requires_path_params', '_path_params',
41 '_accepts_json_body', '_accepts_form_data', '_accepts_file_upload',
42 '_json_body_description', '_json_body_example'
43 ]
44
45 for attr in metadata_attrs:
46 if hasattr(func, attr):
47 setattr(wrapper, attr, getattr(func, attr))
48
49
50# Existing functions - preserve original API
51def inject_query_params(description: str = "Query parameters") -> Callable:
52 """Mark endpoint as requiring query parameters (legacy API).
53
54 Args:
55 description: Description of the query parameters.
56
57 Returns:
58 Decorator function.
59 """
60 def decorator(func: Callable) -> Callable:
61 @wraps(func)
62 def wrapper(*args, **kwargs):
63 return func(*args, **kwargs)
64
65 setattr(wrapper, "_requires_query_params", True)
66 setattr(wrapper, "_query_params_description", description)
67
68 _preserve_metadata(func, wrapper)
69 return wrapper
70 return decorator
71
72
73def inject_json_body(description: str = "JSON request body", example: Union[str, Dict[str, Any], None] = None) -> Callable:
74 """Mark endpoint as accepting JSON body content (legacy API).
75
76 Args:
77 description: Description of the JSON body content.
78 example: Example JSON content (as dict or JSON string).
79
80 Returns:
81 Decorator function.
82 """
83 def decorator(func: Callable) -> Callable:
84 @wraps(func)
85 def wrapper(*args, **kwargs):
86 return func(*args, **kwargs)
87
88 setattr(wrapper, "_accepts_json_body", True)
89 setattr(wrapper, "_json_body_description", description)
90 if example is not None:
91 setattr(wrapper, "_json_body_example", example)
92
93 _preserve_metadata(func, wrapper)
94 return wrapper
95 return decorator
96
97
98def inject_request(description: str = "HTTP request") -> Callable:
99 """Mark endpoint as receiving HTTP request (legacy API).
100
101 Args:
102 description: Description of the request.
103
104 Returns:
105 Decorator function.
106 """
107 def decorator(func: Callable) -> Callable:
108 @wraps(func)
109 def wrapper(*args, **kwargs):
110 return func(*args, **kwargs)
111
112 setattr(wrapper, "_accepts_request", True)
113 setattr(wrapper, "_request_description", description)
114
115 _preserve_metadata(func, wrapper)
116 return wrapper
117 return decorator
118
119
120def requires_body(model_class: Any = None, description: str = "Request body") -> Callable:
121 """Mark endpoint as requiring a request body with optional Pydantic model.
122
123 Args:
124 model_class: Optional Pydantic model class for validation.
125 description: Description of the request body.
126
127 Returns:
128 Decorator function.
129 """
130 def decorator(func: Callable) -> Callable:
131 @wraps(func)
132 def wrapper(*args, **kwargs):
133 return func(*args, **kwargs)
134
135 setattr(wrapper, "_requires_body", True)
136 setattr(wrapper, "_body_model", model_class)
137 setattr(wrapper, "_body_description", description)
138
139 _preserve_metadata(func, wrapper)
140 return wrapper
141 return decorator
142
143
144def requires_headers(*header_names: str, description: str = "Required headers") -> Callable:
145 """Mark endpoint as requiring specific headers.
146
147 Args:
148 header_names: Names of required headers.
149 description: Description of the headers.
150
151 Returns:
152 Decorator function.
153 """
154 def decorator(func: Callable) -> Callable:
155 @wraps(func)
156 def wrapper(*args, **kwargs):
157 return func(*args, **kwargs)
158
159 setattr(wrapper, "_requires_headers", True)
160 setattr(wrapper, "_header_names", list(header_names))
161 setattr(wrapper, "_headers_description", description)
162
163 _preserve_metadata(func, wrapper)
164 return wrapper
165 return decorator
166
167
168# New authentication decorators
169def requires_auth_header(header_name: str = "Authorization", scheme: Optional[str] = None) -> Callable:
170 """Mark endpoint as requiring authentication header.
171
172 Args:
173 header_name: Name of the auth header (default: Authorization).
174 scheme: Optional auth scheme (e.g., "Bearer", "Basic").
175
176 Returns:
177 Decorator function.
178 """
179 def decorator(func: Callable) -> Callable:
180 @wraps(func)
181 def wrapper(*args, **kwargs):
182 return func(*args, **kwargs)
183
184 setattr(wrapper, "_requires_auth_header", True)
185 setattr(wrapper, "_auth_header_name", header_name)
186 if scheme:
187 setattr(wrapper, "_auth_scheme", scheme)
188
189 _preserve_metadata(func, wrapper)
190 return wrapper
191 return decorator
192
193
194def requires_bearer_auth() -> Callable:
195 """Mark endpoint as requiring Bearer token authentication.
196
197 Specifically expects: Authorization: Bearer <token>
198
199 Returns:
200 Decorator function.
201 """
202 def decorator(func: Callable) -> Callable:
203 @wraps(func)
204 def wrapper(*args, **kwargs):
205 return func(*args, **kwargs)
206
207 setattr(wrapper, "_requires_bearer_auth", True)
208 setattr(wrapper, "_auth_scheme", "Bearer")
209 setattr(wrapper, "_auth_header_name", "Authorization")
210
211 _preserve_metadata(func, wrapper)
212 return wrapper
213 return decorator
214
215
216def requires_basic_auth() -> Callable:
217 """Mark endpoint as requiring Basic authentication.
218
219 Specifically expects: Authorization: Basic <credentials>
220
221 Returns:
222 Decorator function.
223 """
224 def decorator(func: Callable) -> Callable:
225 @wraps(func)
226 def wrapper(*args, **kwargs):
227 return func(*args, **kwargs)
228
229 setattr(wrapper, "_requires_basic_auth", True)
230 setattr(wrapper, "_auth_scheme", "Basic")
231 setattr(wrapper, "_auth_header_name", "Authorization")
232
233 _preserve_metadata(func, wrapper)
234 return wrapper
235 return decorator
236
237
238def requires_api_key(header_name: str = "X-API-Key") -> Callable:
239 """Mark endpoint as requiring API key authentication.
240
241 Args:
242 header_name: Name of the API key header (default: X-API-Key).
243
244 Returns:
245 Decorator function.
246 """
247 def decorator(func: Callable) -> Callable:
248 @wraps(func)
249 def wrapper(*args, **kwargs):
250 return func(*args, **kwargs)
251
252 setattr(wrapper, "_requires_api_key", True)
253 setattr(wrapper, "_auth_scheme", "API-Key")
254 setattr(wrapper, "_auth_header_name", header_name)
255
256 _preserve_metadata(func, wrapper)
257 return wrapper
258 return decorator
259
260
261def requires_query_params(**params: str) -> Callable:
262 """Mark endpoint as requiring specific query parameters.
263
264 Args:
265 params: Query parameter names and their descriptions.
266
267 Returns:
268 Decorator function.
269 """
270 def decorator(func: Callable) -> Callable:
271 @wraps(func)
272 def wrapper(*args, **kwargs):
273 return func(*args, **kwargs)
274
275 setattr(wrapper, "_requires_query_params", True)
276 setattr(wrapper, "_query_params", dict(params))
277
278 _preserve_metadata(func, wrapper)
279 return wrapper
280 return decorator
281
282
283def requires_path_params(**params: str) -> Callable:
284 """Mark endpoint as requiring specific path parameters.
285
286 Args:
287 params: Path parameter names and their descriptions.
288
289 Returns:
290 Decorator function.
291 """
292 def decorator(func: Callable) -> Callable:
293 @wraps(func)
294 def wrapper(*args, **kwargs):
295 return func(*args, **kwargs)
296
297 setattr(wrapper, "_requires_path_params", True)
298 setattr(wrapper, "_path_params", dict(params))
299
300 _preserve_metadata(func, wrapper)
301 return wrapper
302 return decorator
303
304
305# Aliased functions for new naming convention
306def json_body(description: str = "JSON request body", example: Union[str, Dict[str, Any], None] = None) -> Callable:
307 """Mark endpoint as accepting JSON body content (alias for inject_json_body).
308
309 Args:
310 description: Description of the JSON body content.
311 example: Example JSON content (as dict or JSON string).
312
313 Returns:
314 Decorator function.
315 """
316 return inject_json_body(description, example)
317
318
319def form_data(description: str = "Form data") -> Callable:
320 """Mark endpoint as accepting form data.
321
322 Args:
323 description: Description of the form data.
324
325 Returns:
326 Decorator function.
327 """
328 def decorator(func: Callable) -> Callable:
329 @wraps(func)
330 def wrapper(*args, **kwargs):
331 return func(*args, **kwargs)
332
333 setattr(wrapper, "_accepts_form_data", True)
334 setattr(wrapper, "_form_data_description", description)
335
336 _preserve_metadata(func, wrapper)
337 return wrapper
338 return decorator
339
340
341def file_upload(description: str = "File upload") -> Callable:
342 """Mark endpoint as accepting file uploads.
343
344 Args:
345 description: Description of the file upload.
346
347 Returns:
348 Decorator function.
349 """
350 def decorator(func: Callable) -> Callable:
351 @wraps(func)
352 def wrapper(*args, **kwargs):
353 return func(*args, **kwargs)
354
355 setattr(wrapper, "_accepts_file_upload", True)
356 setattr(wrapper, "_file_upload_description", description)
357
358 _preserve_metadata(func, wrapper)
359 return wrapper
360 return decorator
Callable json_body(str description="JSON request body", Union[str, Dict[str, Any], None] example=None)
Callable file_upload(str description="File upload")
Callable requires_auth_header(str header_name="Authorization", Optional[str] scheme=None)
Callable requires_api_key(str header_name="X-API-Key")
Callable requires_headers(*str header_names, str description="Required headers")
Callable inject_json_body(str description="JSON request body", Union[str, Dict[str, Any], None] example=None)
Definition parameters.py:73
Callable form_data(str description="Form data")
None _preserve_metadata(Callable func, Callable wrapper)
Definition parameters.py:31
Callable inject_request(str description="HTTP request")
Definition parameters.py:98
Callable requires_body(Any model_class=None, str description="Request body")
Callable inject_query_params(str description="Query parameters")
Definition parameters.py:51