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 ADDED
@@ -0,0 +1,67 @@
1
+ """
2
+ numpy2 - Advanced NumPy for Web Applications
3
+ ============================================
4
+
5
+ A powerful library that bridges NumPy and web frameworks, solving critical pain points:
6
+ - JSON serialization of NumPy types (int64, float64, etc.)
7
+ - Automatic type conversion for web APIs
8
+ - FastAPI/Flask/Django integration
9
+ - Zero-configuration setup
10
+ - Production-ready performance
11
+
12
+ Build by: Mahesh Makvana
13
+ GitHub: https://github.com/maheshmakvana/numpy2
14
+
15
+ Example:
16
+ >>> import numpy2 as np2
17
+ >>> arr = np2.array([1, 2, 3])
18
+ >>> json_safe = np2.to_json(arr)
19
+ >>> fastapi_response = np2.serialize(arr) # Ready for FastAPI JSONResponse
20
+ """
21
+
22
+ __version__ = "1.0.0"
23
+ __author__ = "Mahesh Makvana"
24
+ __email__ = "mahesh@example.com"
25
+ __license__ = "MIT"
26
+
27
+ from .core import (
28
+ array,
29
+ ndarray,
30
+ to_json,
31
+ from_json,
32
+ serialize,
33
+ deserialize,
34
+ JSONEncoder,
35
+ JSONDecoder,
36
+ )
37
+
38
+ from .converters import (
39
+ numpy_to_python,
40
+ pandas_to_json,
41
+ python_to_numpy,
42
+ )
43
+
44
+ from .integrations import (
45
+ FastAPIResponse,
46
+ FlaskResponse,
47
+ DjangoResponse,
48
+ setup_json_encoder,
49
+ )
50
+
51
+ __all__ = [
52
+ "array",
53
+ "ndarray",
54
+ "to_json",
55
+ "from_json",
56
+ "serialize",
57
+ "deserialize",
58
+ "JSONEncoder",
59
+ "JSONDecoder",
60
+ "numpy_to_python",
61
+ "pandas_to_json",
62
+ "python_to_numpy",
63
+ "FastAPIResponse",
64
+ "FlaskResponse",
65
+ "DjangoResponse",
66
+ "setup_json_encoder",
67
+ ]
numpy2/converters.py ADDED
@@ -0,0 +1,265 @@
1
+ """
2
+ numpy2.converters - Data type conversion utilities
3
+
4
+ Handles conversions between NumPy, pandas, Python types, and JSON
5
+ with automatic type inference and data integrity preservation.
6
+ """
7
+
8
+ import numpy as np
9
+ import pandas as pd
10
+ from typing import Any, Dict, List, Union, Optional
11
+
12
+
13
+ def numpy_to_python(obj: Any) -> Any:
14
+ """
15
+ Convert NumPy types to native Python types.
16
+
17
+ SOLVES: Silent data loss from NumPy type conversions
18
+
19
+ Args:
20
+ obj: NumPy object to convert
21
+
22
+ Returns:
23
+ Native Python type
24
+
25
+ Example:
26
+ >>> import numpy as np
27
+ >>> import numpy2 as np2
28
+ >>> val = np.int64(42)
29
+ >>> result = np2.numpy_to_python(val)
30
+ >>> type(result)
31
+ <class 'int'>
32
+ """
33
+
34
+ if isinstance(obj, np.ndarray):
35
+ return obj.tolist()
36
+ elif isinstance(obj, np.integer):
37
+ return int(obj)
38
+ elif isinstance(obj, np.floating):
39
+ if np.isnan(obj) or np.isinf(obj):
40
+ return None
41
+ return float(obj)
42
+ elif isinstance(obj, np.bool_):
43
+ return bool(obj)
44
+ elif isinstance(obj, np.datetime64):
45
+ return str(obj)
46
+ elif isinstance(obj, np.generic):
47
+ return obj.item()
48
+ elif isinstance(obj, (list, tuple)):
49
+ return type(obj)(numpy_to_python(item) for item in obj)
50
+ elif isinstance(obj, dict):
51
+ return {k: numpy_to_python(v) for k, v in obj.items()}
52
+ else:
53
+ return obj
54
+
55
+
56
+ def pandas_to_json(
57
+ df: pd.DataFrame,
58
+ orient: str = 'records',
59
+ include_index: bool = False
60
+ ) -> Dict[str, Any]:
61
+ """
62
+ Convert pandas DataFrame to JSON-safe dictionary.
63
+
64
+ SOLVES: JSON serialization of DataFrames with NumPy columns
65
+
66
+ Args:
67
+ df: pandas DataFrame
68
+ orient: DataFrame orientation ('records', 'list', 'dict', 'split', 'tight', 'index', 'columns', 'values')
69
+ include_index: Include index in output
70
+
71
+ Returns:
72
+ JSON-safe dictionary
73
+
74
+ Example:
75
+ >>> import pandas as pd
76
+ >>> import numpy2 as np2
77
+ >>> df = pd.DataFrame({'A': [1, 2], 'B': [3.5, 4.5]})
78
+ >>> result = np2.pandas_to_json(df)
79
+ >>> type(result)
80
+ <class 'dict'>
81
+ """
82
+
83
+ if not isinstance(df, pd.DataFrame):
84
+ raise TypeError(f"Expected pandas DataFrame, got {type(df)}")
85
+
86
+ # Convert all NumPy types to Python types
87
+ df_converted = df.copy()
88
+
89
+ for col in df_converted.columns:
90
+ if df_converted[col].dtype == 'object':
91
+ continue
92
+ if hasattr(df_converted[col].dtype, 'name'):
93
+ if 'int' in str(df_converted[col].dtype) or 'float' in str(df_converted[col].dtype):
94
+ df_converted[col] = df_converted[col].astype(str).apply(
95
+ lambda x: int(x) if '.' not in x else float(x)
96
+ )
97
+
98
+ result = df_converted.to_dict(orient=orient)
99
+
100
+ if include_index and orient == 'records':
101
+ result = [
102
+ {**row, '__index__': idx}
103
+ for idx, row in enumerate(result)
104
+ ]
105
+
106
+ return result
107
+
108
+
109
+ def python_to_numpy(
110
+ data: Any,
111
+ dtype: Optional[str] = None
112
+ ) -> np.ndarray:
113
+ """
114
+ Convert Python types to NumPy array.
115
+
116
+ Args:
117
+ data: Python data (list, tuple, dict, etc.)
118
+ dtype: Target NumPy dtype
119
+
120
+ Returns:
121
+ NumPy ndarray
122
+
123
+ Example:
124
+ >>> import numpy2 as np2
125
+ >>> data = [1, 2, 3]
126
+ >>> arr = np2.python_to_numpy(data, dtype='float32')
127
+ >>> arr.dtype
128
+ dtype('float32')
129
+ """
130
+
131
+ return np.array(data, dtype=dtype)
132
+
133
+
134
+ def infer_dtype(data: Any) -> str:
135
+ """
136
+ Intelligently infer appropriate NumPy dtype from data.
137
+
138
+ SOLVES: Type inference problems in web APIs
139
+
140
+ Args:
141
+ data: Data to analyze
142
+
143
+ Returns:
144
+ Inferred NumPy dtype string
145
+
146
+ Example:
147
+ >>> import numpy2 as np2
148
+ >>> dtype = np2.infer_dtype([1, 2, 3])
149
+ >>> dtype
150
+ 'int64'
151
+ """
152
+
153
+ if isinstance(data, (list, tuple)):
154
+ if not data:
155
+ return 'float64'
156
+
157
+ # Check first element type
158
+ first = data[0]
159
+
160
+ if isinstance(first, bool):
161
+ return 'bool'
162
+ elif isinstance(first, int):
163
+ # Check range to choose appropriate int type
164
+ values = [x for x in data if isinstance(x, int)]
165
+ if all(-128 <= v < 128 for v in values):
166
+ return 'int8'
167
+ elif all(-32768 <= v < 32768 for v in values):
168
+ return 'int16'
169
+ elif all(-2147483648 <= v < 2147483648 for v in values):
170
+ return 'int32'
171
+ else:
172
+ return 'int64'
173
+ elif isinstance(first, float):
174
+ return 'float64'
175
+ elif isinstance(first, str):
176
+ return 'object'
177
+ elif isinstance(first, (list, tuple)):
178
+ return infer_dtype(first)
179
+
180
+ elif isinstance(data, dict):
181
+ return 'object'
182
+
183
+ elif isinstance(data, np.ndarray):
184
+ return str(data.dtype)
185
+
186
+ return 'object'
187
+
188
+
189
+ def safe_cast(
190
+ value: Any,
191
+ target_dtype: str,
192
+ raise_on_error: bool = False
193
+ ) -> Any:
194
+ """
195
+ Safely cast value to target dtype with error handling.
196
+
197
+ SOLVES: Type conversion errors breaking web APIs
198
+
199
+ Args:
200
+ value: Value to cast
201
+ target_dtype: Target NumPy dtype
202
+ raise_on_error: Raise exception on failure (default: return original)
203
+
204
+ Returns:
205
+ Casted value or original value on failure
206
+
207
+ Example:
208
+ >>> import numpy2 as np2
209
+ >>> result = np2.safe_cast("123", 'int32')
210
+ >>> result
211
+ 123
212
+ """
213
+
214
+ try:
215
+ if target_dtype in ['int8', 'int16', 'int32', 'int64']:
216
+ return int(value)
217
+ elif target_dtype in ['float16', 'float32', 'float64']:
218
+ return float(value)
219
+ elif target_dtype == 'bool':
220
+ return bool(value)
221
+ else:
222
+ return np.array([value], dtype=target_dtype)[0]
223
+ except (ValueError, TypeError) as e:
224
+ if raise_on_error:
225
+ raise
226
+ return value
227
+
228
+
229
+ def batch_convert(
230
+ data: List[Dict[str, Any]],
231
+ dtype_map: Optional[Dict[str, str]] = None
232
+ ) -> List[Dict[str, Any]]:
233
+ """
234
+ Convert batch of records with consistent type handling.
235
+
236
+ SOLVES: Bulk data conversion issues in APIs
237
+
238
+ Args:
239
+ data: List of dictionaries to convert
240
+ dtype_map: Mapping of field names to target dtypes
241
+
242
+ Returns:
243
+ Converted data
244
+
245
+ Example:
246
+ >>> import numpy2 as np2
247
+ >>> data = [{'id': 1, 'value': 3.14}]
248
+ >>> converted = np2.batch_convert(data, {'id': 'int32', 'value': 'float32'})
249
+ """
250
+
251
+ if dtype_map is None:
252
+ dtype_map = {}
253
+
254
+ converted = []
255
+ for record in data:
256
+ new_record = {}
257
+ for key, value in record.items():
258
+ target_dtype = dtype_map.get(key)
259
+ if target_dtype:
260
+ new_record[key] = safe_cast(value, target_dtype)
261
+ else:
262
+ new_record[key] = numpy_to_python(value)
263
+ converted.append(new_record)
264
+
265
+ return converted
numpy2/core.py ADDED
@@ -0,0 +1,360 @@
1
+ """
2
+ numpy2.core - Core serialization and type conversion utilities
3
+
4
+ Solves NumPy JSON serialization issues:
5
+ - TypeError: Object of type int64 is not JSON serializable
6
+ - Silent data loss from NumPy type conversions
7
+ - Performance degradation in web APIs
8
+ - Framework incompatibility with NumPy dtypes
9
+ """
10
+
11
+ import json
12
+ import numpy as np
13
+ import pandas as pd
14
+ from typing import Any, Dict, List, Union, Optional
15
+ from decimal import Decimal
16
+
17
+
18
+ class JSONEncoder(json.JSONEncoder):
19
+ """
20
+ Custom JSON encoder that handles NumPy and pandas data types.
21
+
22
+ SOLVES: TypeError: Object of type int64 is not JSON serializable
23
+
24
+ Features:
25
+ - Automatic NumPy dtype conversion
26
+ - pandas Series/DataFrame support
27
+ - Preserves data integrity
28
+ - Zero configuration
29
+
30
+ Example:
31
+ >>> import json
32
+ >>> import numpy as np
33
+ >>> arr = np.array([1, 2, 3], dtype=np.int64)
34
+ >>> json.dumps(arr, cls=JSONEncoder)
35
+ '[1, 2, 3]'
36
+ """
37
+
38
+ def default(self, obj: Any) -> Any:
39
+ """Convert non-standard types to JSON-serializable format."""
40
+
41
+ # NumPy integer types
42
+ if isinstance(obj, np.integer):
43
+ return int(obj)
44
+
45
+ # NumPy float types
46
+ elif isinstance(obj, np.floating):
47
+ # Handle special float values
48
+ if np.isnan(obj):
49
+ return None # or "NaN" if preferred
50
+ elif np.isinf(obj):
51
+ return None # or "Infinity" if preferred
52
+ return float(obj)
53
+
54
+ # NumPy arrays
55
+ elif isinstance(obj, np.ndarray):
56
+ return obj.tolist()
57
+
58
+ # NumPy scalar types
59
+ elif isinstance(obj, np.generic):
60
+ return obj.item()
61
+
62
+ # pandas Series
63
+ elif isinstance(obj, pd.Series):
64
+ return obj.to_dict()
65
+
66
+ # pandas DataFrame
67
+ elif isinstance(obj, pd.DataFrame):
68
+ return obj.to_dict(orient='records')
69
+
70
+ # pandas Index
71
+ elif isinstance(obj, pd.Index):
72
+ return obj.tolist()
73
+
74
+ # Decimal support
75
+ elif isinstance(obj, Decimal):
76
+ return float(obj)
77
+
78
+ # datetime64
79
+ elif isinstance(obj, np.datetime64):
80
+ return str(obj)
81
+
82
+ # timedelta64
83
+ elif isinstance(obj, np.timedelta64):
84
+ return str(obj)
85
+
86
+ # complex numbers
87
+ elif isinstance(obj, (complex, np.complexfloating)):
88
+ return {"real": obj.real, "imag": obj.imag}
89
+
90
+ # Default fallback
91
+ return super().default(obj)
92
+
93
+
94
+ class JSONDecoder(json.JSONDecoder):
95
+ """
96
+ Custom JSON decoder that reconstructs NumPy arrays from JSON.
97
+
98
+ SOLVES: Data type loss when converting JSON back to NumPy
99
+
100
+ Features:
101
+ - Intelligent type inference
102
+ - Preserves numeric precision
103
+ - Optional NumPy array reconstruction
104
+
105
+ Example:
106
+ >>> import json
107
+ >>> data = '[1, 2, 3]'
108
+ >>> decoder = JSONDecoder()
109
+ >>> decoder.decode(data)
110
+ [1, 2, 3]
111
+ """
112
+
113
+ def __init__(self, to_numpy: bool = False, dtype: Optional[str] = None, *args, **kwargs):
114
+ """
115
+ Initialize decoder.
116
+
117
+ Args:
118
+ to_numpy: If True, convert lists to numpy arrays
119
+ dtype: NumPy dtype to use for arrays (e.g., 'int64', 'float32')
120
+ """
121
+ self.to_numpy = to_numpy
122
+ self.dtype = dtype
123
+ super().__init__(object_hook=self.object_hook, *args, **kwargs)
124
+
125
+ def object_hook(self, obj: Dict) -> Any:
126
+ """Convert objects back to appropriate types."""
127
+ if self.to_numpy and isinstance(obj, dict) and "real" in obj and "imag" in obj:
128
+ return complex(obj["real"], obj["imag"])
129
+ return obj
130
+
131
+
132
+ def to_json(obj: Any, indent: Optional[int] = None, **kwargs) -> str:
133
+ """
134
+ Convert NumPy arrays and pandas objects to JSON string.
135
+
136
+ SOLVES: TypeError: Object of type int64 is not JSON serializable
137
+
138
+ Args:
139
+ obj: NumPy array, pandas object, or standard Python object
140
+ indent: JSON indentation level
141
+ **kwargs: Additional arguments for json.dumps
142
+
143
+ Returns:
144
+ JSON string representation
145
+
146
+ Example:
147
+ >>> import numpy as np
148
+ >>> import numpy2 as np2
149
+ >>> arr = np.array([1, 2, 3], dtype=np.int64)
150
+ >>> json_str = np2.to_json(arr)
151
+ >>> print(json_str)
152
+ [1, 2, 3]
153
+ """
154
+ return json.dumps(obj, cls=JSONEncoder, indent=indent, **kwargs)
155
+
156
+
157
+ def from_json(
158
+ json_str: str,
159
+ to_numpy: bool = False,
160
+ dtype: Optional[str] = None
161
+ ) -> Any:
162
+ """
163
+ Deserialize JSON string to Python objects (optionally NumPy arrays).
164
+
165
+ Args:
166
+ json_str: JSON string to deserialize
167
+ to_numpy: Convert to numpy arrays
168
+ dtype: Target numpy dtype
169
+
170
+ Returns:
171
+ Deserialized Python object or NumPy array
172
+
173
+ Example:
174
+ >>> import numpy2 as np2
175
+ >>> json_str = '[1, 2, 3]'
176
+ >>> arr = np2.from_json(json_str, to_numpy=True, dtype='int64')
177
+ >>> type(arr)
178
+ <class 'numpy.ndarray'>
179
+ """
180
+ decoder = JSONDecoder(to_numpy=to_numpy, dtype=dtype)
181
+ result = decoder.decode(json_str)
182
+
183
+ if to_numpy and isinstance(result, list):
184
+ result = np.array(result, dtype=dtype)
185
+
186
+ return result
187
+
188
+
189
+ def serialize(obj: Any, include_metadata: bool = False) -> Dict[str, Any]:
190
+ """
191
+ Serialize NumPy/pandas objects to JSON-safe dictionary.
192
+
193
+ SOLVES: Web framework incompatibility with NumPy dtypes
194
+
195
+ Perfect for FastAPI JSONResponse, Flask jsonify, Django JsonResponse
196
+
197
+ Args:
198
+ obj: Object to serialize
199
+ include_metadata: Include shape, dtype, and other metadata
200
+
201
+ Returns:
202
+ JSON-safe dictionary
203
+
204
+ Example:
205
+ >>> import numpy as np
206
+ >>> import numpy2 as np2
207
+ >>> arr = np.array([[1, 2], [3, 4]], dtype=np.int32)
208
+ >>> result = np2.serialize(arr, include_metadata=True)
209
+ >>> result
210
+ {
211
+ 'data': [[1, 2], [3, 4]],
212
+ 'shape': [2, 2],
213
+ 'dtype': 'int32',
214
+ 'size': 4
215
+ }
216
+ """
217
+
218
+ if isinstance(obj, np.ndarray):
219
+ result = {
220
+ 'data': obj.tolist(),
221
+ }
222
+ if include_metadata:
223
+ result.update({
224
+ 'shape': list(obj.shape),
225
+ 'dtype': str(obj.dtype),
226
+ 'size': int(obj.size),
227
+ 'ndim': int(obj.ndim),
228
+ })
229
+ return result
230
+
231
+ elif isinstance(obj, pd.DataFrame):
232
+ result = {
233
+ 'data': obj.to_dict(orient='records'),
234
+ }
235
+ if include_metadata:
236
+ result.update({
237
+ 'shape': list(obj.shape),
238
+ 'columns': list(obj.columns),
239
+ 'index': obj.index.tolist(),
240
+ })
241
+ return result
242
+
243
+ elif isinstance(obj, pd.Series):
244
+ result = {
245
+ 'data': obj.to_dict(),
246
+ }
247
+ if include_metadata:
248
+ result.update({
249
+ 'name': obj.name,
250
+ 'dtype': str(obj.dtype),
251
+ 'index': obj.index.tolist(),
252
+ })
253
+ return result
254
+
255
+ elif isinstance(obj, dict):
256
+ # Recursively serialize nested structures
257
+ return {k: serialize(v, include_metadata) if isinstance(v, (np.ndarray, pd.DataFrame, pd.Series)) else v
258
+ for k, v in obj.items()}
259
+
260
+ elif isinstance(obj, (list, tuple)):
261
+ return [serialize(item, include_metadata) if isinstance(item, (np.ndarray, pd.DataFrame, pd.Series)) else item
262
+ for item in obj]
263
+
264
+ else:
265
+ return json.loads(json.dumps(obj, cls=JSONEncoder))
266
+
267
+
268
+ def deserialize(
269
+ data: Dict[str, Any],
270
+ to_numpy: bool = True,
271
+ dtype: Optional[str] = None
272
+ ) -> Union[np.ndarray, pd.DataFrame, Any]:
273
+ """
274
+ Deserialize JSON-safe dictionary back to NumPy/pandas objects.
275
+
276
+ Args:
277
+ data: Dictionary with 'data' key and optional metadata
278
+ to_numpy: Convert to NumPy array (if False, returns list)
279
+ dtype: Target dtype for conversion
280
+
281
+ Returns:
282
+ NumPy array, pandas DataFrame, or raw data
283
+
284
+ Example:
285
+ >>> import numpy2 as np2
286
+ >>> serialized = {
287
+ ... 'data': [[1, 2], [3, 4]],
288
+ ... 'shape': [2, 2],
289
+ ... 'dtype': 'int32'
290
+ ... }
291
+ >>> arr = np2.deserialize(serialized)
292
+ >>> type(arr)
293
+ <class 'numpy.ndarray'>
294
+ """
295
+
296
+ if not isinstance(data, dict):
297
+ return data
298
+
299
+ if 'data' not in data:
300
+ return data
301
+
302
+ array_data = data['data']
303
+
304
+ if to_numpy:
305
+ target_dtype = dtype or data.get('dtype', None)
306
+ return np.array(array_data, dtype=target_dtype)
307
+
308
+ return array_data
309
+
310
+
311
+ def array(
312
+ data: Any,
313
+ dtype: Optional[str] = None,
314
+ **kwargs
315
+ ) -> np.ndarray:
316
+ """
317
+ Create NumPy array with automatic type handling.
318
+
319
+ Wrapper around numpy.array with better type inference for web data.
320
+
321
+ Args:
322
+ data: Array data
323
+ dtype: Data type
324
+ **kwargs: Additional arguments for numpy.array
325
+
326
+ Returns:
327
+ NumPy ndarray
328
+ """
329
+ return np.array(data, dtype=dtype, **kwargs)
330
+
331
+
332
+ class ndarray:
333
+ """
334
+ Enhanced NumPy ndarray wrapper with web-friendly methods.
335
+
336
+ Adds convenience methods for serialization without modifying
337
+ the original NumPy array.
338
+ """
339
+
340
+ def __init__(self, data: Any, dtype: Optional[str] = None):
341
+ self._array = np.array(data, dtype=dtype)
342
+
343
+ def to_json(self, indent: Optional[int] = None) -> str:
344
+ """Convert to JSON string."""
345
+ return to_json(self._array, indent=indent)
346
+
347
+ def to_dict(self, include_metadata: bool = False) -> Dict:
348
+ """Convert to JSON-safe dictionary."""
349
+ return serialize(self._array, include_metadata=include_metadata)
350
+
351
+ @property
352
+ def numpy(self) -> np.ndarray:
353
+ """Get underlying NumPy array."""
354
+ return self._array
355
+
356
+ def __repr__(self) -> str:
357
+ return f"numpy2.ndarray({self._array})"
358
+
359
+ def __str__(self) -> str:
360
+ return str(self._array)