bustapi 0.1.0__cp311-cp311-win_amd64.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.

Potentially problematic release.


This version of bustapi might be problematic. Click here for more details.

bustapi/helpers.py ADDED
@@ -0,0 +1,370 @@
1
+ """
2
+ Helper functions for BustAPI - Flask-compatible utilities
3
+ """
4
+
5
+ import os
6
+ from typing import Any, Optional
7
+
8
+ from .exceptions import HTTPException
9
+ from .response import Response
10
+ from .response import redirect as _redirect
11
+
12
+
13
+ def abort(code: int, description: Optional[str] = None, **kwargs) -> None:
14
+ """
15
+ Abort request with HTTP error code (Flask-compatible).
16
+
17
+ Args:
18
+ code: HTTP status code
19
+ description: Error description
20
+ **kwargs: Additional arguments
21
+
22
+ Raises:
23
+ HTTPException: HTTP exception with specified code
24
+ """
25
+ raise HTTPException(code, description=description)
26
+
27
+
28
+ def redirect(location: str, code: int = 302) -> Response:
29
+ """
30
+ Create a redirect response (Flask-compatible).
31
+
32
+ Args:
33
+ location: Redirect URL
34
+ code: HTTP status code (301, 302, etc.)
35
+
36
+ Returns:
37
+ Redirect response
38
+ """
39
+ return _redirect(location, code)
40
+
41
+
42
+ def url_for(endpoint: str, **values) -> str:
43
+ """
44
+ Generate URL for endpoint (Flask-compatible placeholder).
45
+
46
+ Args:
47
+ endpoint: Endpoint name
48
+ **values: URL parameters
49
+
50
+ Returns:
51
+ Generated URL
52
+
53
+ Note:
54
+ This is a simplified implementation. Full URL generation
55
+ requires route reversal which should be implemented in
56
+ the Rust backend for performance.
57
+ """
58
+ # Placeholder implementation
59
+ # TODO: Implement proper URL reversal with route mapping
60
+
61
+ # For now, just return the endpoint as-is
62
+ # In a full implementation, this would:
63
+ # 1. Look up the route pattern for the endpoint
64
+ # 2. Substitute parameters into the pattern
65
+ # 3. Generate the full URL
66
+
67
+ if values:
68
+ # Simple parameter substitution for basic cases
69
+ url = endpoint
70
+ for key, value in values.items():
71
+ url = url.replace(f"<{key}>", str(value))
72
+ url = url.replace(f"<int:{key}>", str(value))
73
+ url = url.replace(f"<string:{key}>", str(value))
74
+ return url
75
+
76
+ return endpoint
77
+
78
+
79
+ def flash(message: str, category: str = "message") -> None:
80
+ """
81
+ Flash a message to the user (Flask-compatible placeholder).
82
+
83
+ Args:
84
+ message: Message to flash
85
+ category: Message category
86
+
87
+ Note:
88
+ This is a placeholder implementation. Flash messaging
89
+ requires session support which should be implemented.
90
+ """
91
+ # TODO: Implement flash messaging with session support
92
+ pass
93
+
94
+
95
+ def get_flashed_messages(
96
+ with_categories: bool = False, category_filter: Optional[list] = None
97
+ ) -> list:
98
+ """
99
+ Get flashed messages (Flask-compatible placeholder).
100
+
101
+ Args:
102
+ with_categories: Include categories in result
103
+ category_filter: Filter by categories
104
+
105
+ Returns:
106
+ List of flashed messages
107
+
108
+ Note:
109
+ This is a placeholder implementation.
110
+ """
111
+ # TODO: Implement flash message retrieval
112
+ return []
113
+
114
+
115
+ def send_file(
116
+ path_or_file,
117
+ mimetype: Optional[str] = None,
118
+ as_attachment: bool = False,
119
+ attachment_filename: Optional[str] = None,
120
+ add_etags: bool = True,
121
+ cache_timeout: Optional[int] = None,
122
+ conditional: bool = False,
123
+ last_modified: Optional[Any] = None,
124
+ ) -> Response:
125
+ """
126
+ Send a file to the user (Flask-compatible).
127
+
128
+ Args:
129
+ path_or_file: File path or file-like object
130
+ mimetype: MIME type
131
+ as_attachment: Send as attachment
132
+ attachment_filename: Attachment filename
133
+ add_etags: Add ETag header
134
+ cache_timeout: Cache timeout
135
+ conditional: Enable conditional responses
136
+ last_modified: Last modified time
137
+
138
+ Returns:
139
+ Response object with file content
140
+ """
141
+ from .response import send_file as _send_file
142
+
143
+ return _send_file(path_or_file, mimetype, as_attachment, attachment_filename)
144
+
145
+
146
+ def send_from_directory(directory: str, path: str, **kwargs) -> Response:
147
+ """
148
+ Send a file from a directory (Flask-compatible).
149
+
150
+ Args:
151
+ directory: Directory path
152
+ path: File path within directory
153
+ **kwargs: Additional arguments for send_file
154
+
155
+ Returns:
156
+ Response object with file content
157
+ """
158
+ # Security: ensure path doesn't escape directory
159
+ safe_path = os.path.normpath(path).lstrip("/")
160
+ full_path = os.path.join(directory, safe_path)
161
+
162
+ # Check if path tries to escape directory
163
+ if not os.path.abspath(full_path).startswith(os.path.abspath(directory)):
164
+ abort(404, description="File not found")
165
+
166
+ return send_file(full_path, **kwargs)
167
+
168
+
169
+ def safe_join(directory: str, *pathnames: str) -> Optional[str]:
170
+ """
171
+ Safely join directory and path components.
172
+
173
+ Args:
174
+ directory: Base directory
175
+ *pathnames: Path components to join
176
+
177
+ Returns:
178
+ Joined path or None if unsafe
179
+ """
180
+ if not pathnames:
181
+ return directory
182
+
183
+ path = os.path.join(directory, *pathnames)
184
+ path = os.path.normpath(path)
185
+
186
+ # Check if path tries to escape directory
187
+ if not path.startswith(directory + os.sep) and path != directory:
188
+ return None
189
+
190
+ return path
191
+
192
+
193
+ def escape(text: str) -> str:
194
+ """
195
+ Escape HTML special characters.
196
+
197
+ Args:
198
+ text: Text to escape
199
+
200
+ Returns:
201
+ Escaped text
202
+ """
203
+ return (
204
+ text.replace("&", "&amp;")
205
+ .replace("<", "&lt;")
206
+ .replace(">", "&gt;")
207
+ .replace('"', "&quot;")
208
+ .replace("'", "&#x27;")
209
+ )
210
+
211
+
212
+ def get_debug_flag() -> bool:
213
+ """
214
+ Get debug flag from environment or current app.
215
+
216
+ Returns:
217
+ Debug flag value
218
+ """
219
+ # Check environment variable first
220
+ debug_env = os.environ.get("FLASK_DEBUG", "").lower()
221
+ if debug_env in ("1", "true", "yes", "on"):
222
+ return True
223
+ elif debug_env in ("0", "false", "no", "off"):
224
+ return False
225
+
226
+ # Try to get from current app
227
+ try:
228
+ current_app = _get_current_object()
229
+ return current_app.config.get("DEBUG", False)
230
+ except RuntimeError:
231
+ return False
232
+
233
+
234
+ def _get_current_object():
235
+ """
236
+ Get current application object (placeholder).
237
+
238
+ Returns:
239
+ Current application
240
+
241
+ Raises:
242
+ RuntimeError: If no application context
243
+ """
244
+ # TODO: Implement application context
245
+ raise RuntimeError("Working outside of application context")
246
+
247
+
248
+ # Template helpers (placeholders)
249
+ def render_template(template_name: str, **context) -> str:
250
+ """
251
+ Render template (Flask-compatible placeholder).
252
+
253
+ Args:
254
+ template_name: Template filename
255
+ **context: Template context variables
256
+
257
+ Returns:
258
+ Rendered template string
259
+
260
+ Note:
261
+ This is a placeholder. Template rendering should be
262
+ implemented with a proper template engine like Jinja2.
263
+ """
264
+ # TODO: Implement template rendering
265
+ return f"<!-- Template: {template_name} -->"
266
+
267
+
268
+ def render_template_string(source: str, **context) -> str:
269
+ """
270
+ Render template from string (Flask-compatible placeholder).
271
+
272
+ Args:
273
+ source: Template source string
274
+ **context: Template context variables
275
+
276
+ Returns:
277
+ Rendered template string
278
+ """
279
+ # TODO: Implement template rendering from string
280
+ return source
281
+
282
+
283
+ # JSON helpers
284
+ def jsonify(*args, **kwargs) -> Response:
285
+ """
286
+ Create JSON response (re-export from response module).
287
+
288
+ Args:
289
+ *args: Positional arguments for JSON data
290
+ **kwargs: Keyword arguments for JSON data
291
+
292
+ Returns:
293
+ JSON response
294
+ """
295
+ from .response import jsonify as _jsonify
296
+
297
+ return _jsonify(*args, **kwargs)
298
+
299
+
300
+ # Request helpers
301
+ def get_json() -> Any:
302
+ """
303
+ Get JSON data from current request.
304
+
305
+ Returns:
306
+ JSON data from request
307
+ """
308
+ from .request import request
309
+
310
+ return request.get_json()
311
+
312
+
313
+ # URL helpers
314
+ def url_quote(string: str, charset: str = "utf-8", safe: str = "/:") -> str:
315
+ """
316
+ URL quote a string.
317
+
318
+ Args:
319
+ string: String to quote
320
+ charset: Character encoding
321
+ safe: Characters to not quote
322
+
323
+ Returns:
324
+ URL quoted string
325
+ """
326
+ from urllib.parse import quote
327
+
328
+ if isinstance(string, str):
329
+ string = string.encode(charset)
330
+ return quote(string, safe=safe)
331
+
332
+
333
+ def url_unquote(string: str, charset: str = "utf-8") -> str:
334
+ """
335
+ URL unquote a string.
336
+
337
+ Args:
338
+ string: String to unquote
339
+ charset: Character encoding
340
+
341
+ Returns:
342
+ URL unquoted string
343
+ """
344
+ from urllib.parse import unquote
345
+
346
+ return unquote(string, encoding=charset)
347
+
348
+
349
+ # Configuration helpers
350
+ def get_env() -> str:
351
+ """
352
+ Get environment name.
353
+
354
+ Returns:
355
+ Environment name (development, production, etc.)
356
+ """
357
+ return os.environ.get("FLASK_ENV", "development")
358
+
359
+
360
+ def get_load_dotenv(default: bool = True) -> bool:
361
+ """
362
+ Check if .env files should be loaded.
363
+
364
+ Args:
365
+ default: Default value
366
+
367
+ Returns:
368
+ Whether to load .env files
369
+ """
370
+ return os.environ.get("FLASK_SKIP_DOTENV", "").lower() not in ("1", "true", "yes")
bustapi/py.typed ADDED
File without changes