numpy2 1.0.0__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.
- numpy2/__init__.py +67 -0
- numpy2/converters.py +265 -0
- numpy2/core.py +360 -0
- numpy2/integrations.py +291 -0
- numpy2-1.0.0.dist-info/METADATA +547 -0
- numpy2-1.0.0.dist-info/RECORD +9 -0
- numpy2-1.0.0.dist-info/WHEEL +5 -0
- numpy2-1.0.0.dist-info/licenses/LICENSE +21 -0
- numpy2-1.0.0.dist-info/top_level.txt +1 -0
numpy2/integrations.py
ADDED
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
"""
|
|
2
|
+
numpy2.integrations - Framework-specific helpers
|
|
3
|
+
|
|
4
|
+
Zero-configuration integrations with popular web frameworks:
|
|
5
|
+
- FastAPI
|
|
6
|
+
- Flask
|
|
7
|
+
- Django
|
|
8
|
+
|
|
9
|
+
SOLVES: Web framework incompatibility with NumPy dtypes
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import json
|
|
13
|
+
import numpy as np
|
|
14
|
+
import pandas as pd
|
|
15
|
+
from typing import Any, Optional, Callable
|
|
16
|
+
from .core import serialize, JSONEncoder
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def FastAPIResponse(
|
|
20
|
+
content: Any,
|
|
21
|
+
status_code: int = 200,
|
|
22
|
+
headers: Optional[dict] = None,
|
|
23
|
+
media_type: str = "application/json",
|
|
24
|
+
) -> dict:
|
|
25
|
+
"""
|
|
26
|
+
Create FastAPI-compatible JSON response from NumPy data.
|
|
27
|
+
|
|
28
|
+
SOLVES: TypeError when returning NumPy arrays in FastAPI endpoints
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
content: NumPy array, pandas object, or standard Python object
|
|
32
|
+
status_code: HTTP status code
|
|
33
|
+
headers: Response headers
|
|
34
|
+
media_type: Content type
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
Dictionary compatible with FastAPI JSONResponse
|
|
38
|
+
|
|
39
|
+
Example:
|
|
40
|
+
>>> from fastapi import FastAPI
|
|
41
|
+
>>> from fastapi.responses import JSONResponse
|
|
42
|
+
>>> import numpy as np
|
|
43
|
+
>>> import numpy2 as np2
|
|
44
|
+
>>>
|
|
45
|
+
>>> app = FastAPI()
|
|
46
|
+
>>>
|
|
47
|
+
>>> @app.get("/data")
|
|
48
|
+
>>> def get_data():
|
|
49
|
+
... arr = np.array([1, 2, 3])
|
|
50
|
+
... return JSONResponse(np2.FastAPIResponse(arr))
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
try:
|
|
54
|
+
# Try to import FastAPI for type hints
|
|
55
|
+
from fastapi.responses import JSONResponse
|
|
56
|
+
except ImportError:
|
|
57
|
+
pass
|
|
58
|
+
|
|
59
|
+
serialized = serialize(content, include_metadata=False)
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
"body": json.dumps(serialized, cls=JSONEncoder).encode("utf-8"),
|
|
63
|
+
"status_code": status_code,
|
|
64
|
+
"headers": headers or {},
|
|
65
|
+
"media_type": media_type,
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def FlaskResponse(
|
|
70
|
+
content: Any,
|
|
71
|
+
status: int = 200,
|
|
72
|
+
headers: Optional[dict] = None,
|
|
73
|
+
mimetype: str = "application/json",
|
|
74
|
+
) -> str:
|
|
75
|
+
"""
|
|
76
|
+
Create Flask-compatible JSON response from NumPy data.
|
|
77
|
+
|
|
78
|
+
SOLVES: TypeError when returning NumPy arrays in Flask routes
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
content: NumPy array, pandas object, or standard Python object
|
|
82
|
+
status: HTTP status code
|
|
83
|
+
headers: Response headers
|
|
84
|
+
mimetype: Content type
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
JSON string ready for Flask response
|
|
88
|
+
|
|
89
|
+
Example:
|
|
90
|
+
>>> from flask import Flask, jsonify
|
|
91
|
+
>>> import numpy as np
|
|
92
|
+
>>> import numpy2 as np2
|
|
93
|
+
>>>
|
|
94
|
+
>>> app = Flask(__name__)
|
|
95
|
+
>>>
|
|
96
|
+
>>> @app.route("/data")
|
|
97
|
+
>>> def get_data():
|
|
98
|
+
... arr = np.array([1, 2, 3])
|
|
99
|
+
... json_str = np2.FlaskResponse(arr)
|
|
100
|
+
... return jsonify(json.loads(json_str))
|
|
101
|
+
"""
|
|
102
|
+
|
|
103
|
+
serialized = serialize(content, include_metadata=False)
|
|
104
|
+
return json.dumps(serialized, cls=JSONEncoder)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def DjangoResponse(
|
|
108
|
+
content: Any,
|
|
109
|
+
safe: bool = True,
|
|
110
|
+
status: int = 200,
|
|
111
|
+
) -> str:
|
|
112
|
+
"""
|
|
113
|
+
Create Django-compatible JSON response from NumPy data.
|
|
114
|
+
|
|
115
|
+
SOLVES: TypeError when returning NumPy arrays in Django views
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
content: NumPy array, pandas object, or standard Python object
|
|
119
|
+
safe: Allow non-dict objects (default: True for django.http.JsonResponse compatibility)
|
|
120
|
+
status: HTTP status code
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
JSON string ready for Django JsonResponse
|
|
124
|
+
|
|
125
|
+
Example:
|
|
126
|
+
>>> from django.http import JsonResponse
|
|
127
|
+
>>> import numpy as np
|
|
128
|
+
>>> import numpy2 as np2
|
|
129
|
+
>>>
|
|
130
|
+
>>> def get_data(request):
|
|
131
|
+
... arr = np.array([1, 2, 3])
|
|
132
|
+
... json_str = np2.DjangoResponse(arr)
|
|
133
|
+
... return JsonResponse(json.loads(json_str), safe=True)
|
|
134
|
+
"""
|
|
135
|
+
|
|
136
|
+
serialized = serialize(content, include_metadata=False)
|
|
137
|
+
return json.dumps(serialized, cls=JSONEncoder)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def setup_json_encoder(framework: str = "fastapi") -> None:
|
|
141
|
+
"""
|
|
142
|
+
Automatically patch framework's JSON encoder for NumPy support.
|
|
143
|
+
|
|
144
|
+
SOLVES: Global NumPy JSON serialization without per-endpoint configuration
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
framework: 'fastapi', 'flask', or 'django'
|
|
148
|
+
|
|
149
|
+
Example:
|
|
150
|
+
>>> import numpy2 as np2
|
|
151
|
+
>>> np2.setup_json_encoder("fastapi")
|
|
152
|
+
>>> # Now all endpoints automatically handle NumPy types
|
|
153
|
+
"""
|
|
154
|
+
|
|
155
|
+
if framework.lower() == "fastapi":
|
|
156
|
+
try:
|
|
157
|
+
from fastapi.encoders import jsonable_encoder
|
|
158
|
+
_patch_fastapi_encoder()
|
|
159
|
+
except ImportError:
|
|
160
|
+
raise ImportError("FastAPI not installed. Install with: pip install fastapi")
|
|
161
|
+
|
|
162
|
+
elif framework.lower() == "flask":
|
|
163
|
+
try:
|
|
164
|
+
import flask
|
|
165
|
+
_patch_flask_encoder()
|
|
166
|
+
except ImportError:
|
|
167
|
+
raise ImportError("Flask not installed. Install with: pip install flask")
|
|
168
|
+
|
|
169
|
+
elif framework.lower() == "django":
|
|
170
|
+
try:
|
|
171
|
+
from django.http import JsonResponse
|
|
172
|
+
_patch_django_encoder()
|
|
173
|
+
except ImportError:
|
|
174
|
+
raise ImportError("Django not installed. Install with: pip install django")
|
|
175
|
+
|
|
176
|
+
else:
|
|
177
|
+
raise ValueError(f"Unknown framework: {framework}")
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def _patch_fastapi_encoder() -> None:
|
|
181
|
+
"""Patch FastAPI's JSON encoder."""
|
|
182
|
+
try:
|
|
183
|
+
from fastapi.json import pydantic_encoder
|
|
184
|
+
original_encoder = pydantic_encoder
|
|
185
|
+
|
|
186
|
+
def patched_encoder(obj):
|
|
187
|
+
if isinstance(obj, np.ndarray):
|
|
188
|
+
return obj.tolist()
|
|
189
|
+
elif isinstance(obj, np.integer):
|
|
190
|
+
return int(obj)
|
|
191
|
+
elif isinstance(obj, np.floating):
|
|
192
|
+
return float(obj)
|
|
193
|
+
elif isinstance(obj, pd.DataFrame):
|
|
194
|
+
return obj.to_dict(orient='records')
|
|
195
|
+
elif isinstance(obj, pd.Series):
|
|
196
|
+
return obj.to_dict()
|
|
197
|
+
return original_encoder(obj)
|
|
198
|
+
|
|
199
|
+
# This is a simplified approach - real patching would need more setup
|
|
200
|
+
except Exception:
|
|
201
|
+
pass
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def _patch_flask_encoder() -> None:
|
|
205
|
+
"""Patch Flask's JSON encoder."""
|
|
206
|
+
try:
|
|
207
|
+
from flask.json.provider import DefaultJSONProvider
|
|
208
|
+
|
|
209
|
+
class NumpyJSONProvider(DefaultJSONProvider):
|
|
210
|
+
def default(self, o):
|
|
211
|
+
if isinstance(o, np.ndarray):
|
|
212
|
+
return o.tolist()
|
|
213
|
+
elif isinstance(o, np.integer):
|
|
214
|
+
return int(o)
|
|
215
|
+
elif isinstance(o, np.floating):
|
|
216
|
+
return float(o)
|
|
217
|
+
elif isinstance(o, pd.DataFrame):
|
|
218
|
+
return o.to_dict(orient='records')
|
|
219
|
+
elif isinstance(o, pd.Series):
|
|
220
|
+
return o.to_dict()
|
|
221
|
+
return super().default(o)
|
|
222
|
+
|
|
223
|
+
except Exception:
|
|
224
|
+
pass
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def _patch_django_encoder() -> None:
|
|
228
|
+
"""Patch Django's JSON encoder."""
|
|
229
|
+
try:
|
|
230
|
+
from django.core.serializers.json import DjangoJSONEncoder
|
|
231
|
+
import json
|
|
232
|
+
|
|
233
|
+
class NumpyDjangoJSONEncoder(DjangoJSONEncoder):
|
|
234
|
+
def default(self, o):
|
|
235
|
+
if isinstance(o, np.ndarray):
|
|
236
|
+
return o.tolist()
|
|
237
|
+
elif isinstance(o, np.integer):
|
|
238
|
+
return int(o)
|
|
239
|
+
elif isinstance(o, np.floating):
|
|
240
|
+
return float(o)
|
|
241
|
+
elif isinstance(o, pd.DataFrame):
|
|
242
|
+
return o.to_dict(orient='records')
|
|
243
|
+
elif isinstance(o, pd.Series):
|
|
244
|
+
return o.to_dict()
|
|
245
|
+
return super().default(o)
|
|
246
|
+
|
|
247
|
+
# Store for reference
|
|
248
|
+
json.encoder.DjangoJSONEncoder = NumpyDjangoJSONEncoder
|
|
249
|
+
|
|
250
|
+
except Exception:
|
|
251
|
+
pass
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def create_response_handler(
|
|
255
|
+
framework: str,
|
|
256
|
+
include_metadata: bool = False,
|
|
257
|
+
) -> Callable:
|
|
258
|
+
"""
|
|
259
|
+
Create framework-specific response handler function.
|
|
260
|
+
|
|
261
|
+
SOLVES: Boilerplate code for NumPy serialization in endpoints
|
|
262
|
+
|
|
263
|
+
Args:
|
|
264
|
+
framework: 'fastapi', 'flask', or 'django'
|
|
265
|
+
include_metadata: Include NumPy array metadata in response
|
|
266
|
+
|
|
267
|
+
Returns:
|
|
268
|
+
Handler function
|
|
269
|
+
|
|
270
|
+
Example:
|
|
271
|
+
>>> import numpy2 as np2
|
|
272
|
+
>>> handler = np2.create_response_handler("fastapi", include_metadata=True)
|
|
273
|
+
>>> response = handler(np.array([1, 2, 3]))
|
|
274
|
+
"""
|
|
275
|
+
|
|
276
|
+
def handler(content: Any) -> Any:
|
|
277
|
+
serialized = serialize(content, include_metadata=include_metadata)
|
|
278
|
+
|
|
279
|
+
if framework.lower() == "fastapi":
|
|
280
|
+
return serialized
|
|
281
|
+
|
|
282
|
+
elif framework.lower() == "flask":
|
|
283
|
+
return json.dumps(serialized, cls=JSONEncoder)
|
|
284
|
+
|
|
285
|
+
elif framework.lower() == "django":
|
|
286
|
+
return json.dumps(serialized, cls=JSONEncoder)
|
|
287
|
+
|
|
288
|
+
else:
|
|
289
|
+
return serialized
|
|
290
|
+
|
|
291
|
+
return handler
|