numpy2 2.4.1__tar.gz → 2.4.2__tar.gz

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.
Files changed (28) hide show
  1. {numpy2-2.4.1 → numpy2-2.4.2}/CONTRIBUTING.md +1 -1
  2. {numpy2-2.4.1/numpy2.egg-info → numpy2-2.4.2}/PKG-INFO +15 -3
  3. {numpy2-2.4.1 → numpy2-2.4.2}/README.md +13 -1
  4. {numpy2-2.4.1 → numpy2-2.4.2}/numpy2/__init__.py +2 -2
  5. {numpy2-2.4.1 → numpy2-2.4.2}/numpy2/advanced.py +8 -2
  6. {numpy2-2.4.1 → numpy2-2.4.2}/numpy2/array.py +98 -6
  7. {numpy2-2.4.1 → numpy2-2.4.2}/numpy2/core.py +26 -1
  8. {numpy2-2.4.1 → numpy2-2.4.2}/numpy2/random.py +51 -0
  9. {numpy2-2.4.1 → numpy2-2.4.2/numpy2.egg-info}/PKG-INFO +15 -3
  10. {numpy2-2.4.1 → numpy2-2.4.2}/pyproject.toml +2 -2
  11. {numpy2-2.4.1 → numpy2-2.4.2}/setup.py +2 -2
  12. {numpy2-2.4.1 → numpy2-2.4.2}/LICENSE +0 -0
  13. {numpy2-2.4.1 → numpy2-2.4.2}/MANIFEST.in +0 -0
  14. {numpy2-2.4.1 → numpy2-2.4.2}/numpy2/compat.py +0 -0
  15. {numpy2-2.4.1 → numpy2-2.4.2}/numpy2/converters.py +0 -0
  16. {numpy2-2.4.1 → numpy2-2.4.2}/numpy2/dtypes.py +0 -0
  17. {numpy2-2.4.1 → numpy2-2.4.2}/numpy2/fft.py +0 -0
  18. {numpy2-2.4.1 → numpy2-2.4.2}/numpy2/integrations.py +0 -0
  19. {numpy2-2.4.1 → numpy2-2.4.2}/numpy2/linalg.py +0 -0
  20. {numpy2-2.4.1 → numpy2-2.4.2}/numpy2/math_ops.py +0 -0
  21. {numpy2-2.4.1 → numpy2-2.4.2}/numpy2.egg-info/SOURCES.txt +0 -0
  22. {numpy2-2.4.1 → numpy2-2.4.2}/numpy2.egg-info/dependency_links.txt +0 -0
  23. {numpy2-2.4.1 → numpy2-2.4.2}/numpy2.egg-info/not-zip-safe +0 -0
  24. {numpy2-2.4.1 → numpy2-2.4.2}/numpy2.egg-info/requires.txt +0 -0
  25. {numpy2-2.4.1 → numpy2-2.4.2}/numpy2.egg-info/top_level.txt +0 -0
  26. {numpy2-2.4.1 → numpy2-2.4.2}/setup.cfg +0 -0
  27. {numpy2-2.4.1 → numpy2-2.4.2}/tests/test_compat.py +0 -0
  28. {numpy2-2.4.1 → numpy2-2.4.2}/tests/test_core.py +0 -0
@@ -102,7 +102,7 @@ When suggesting features:
102
102
  Feel free to:
103
103
  - Open an issue on GitHub
104
104
  - Start a discussion
105
- - Contact: mahesh.makvana@example.com
105
+ - Contact: maheshmakwana527@gmail.com
106
106
 
107
107
  ## License
108
108
 
@@ -1,10 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: numpy2
3
- Version: 2.4.1
3
+ Version: 2.4.2
4
4
  Summary: numpy2: Pure-Python NumPy drop-in replacement with zero dependencies. Fixes numpy JSON serialization errors, broadcasting confusion with named dimensions, NaN/Inf handling, thread safety, JAX-style vmapped vectorization, array caching, compression, pipelines, validation, scan operations, lazy arrays, and seamless web framework integration for FastAPI, Flask, and Django. Drop-in import: numpy2 as np
5
5
  Home-page: https://github.com/maheshmakvana/numpy2
6
6
  Author: Mahesh Makvana
7
- Author-email: Mahesh Makvana <mahesh.makvana@example.com>
7
+ Author-email: Mahesh Makvana <maheshmakwana527@gmail.com>
8
8
  License: MIT
9
9
  Project-URL: Homepage, https://github.com/maheshmakvana/numpy2
10
10
  Project-URL: Bug Tracker, https://github.com/maheshmakvana/numpy2/issues
@@ -538,7 +538,7 @@ For questions, [start a discussion](https://github.com/maheshmakvana/numpy2/disc
538
538
 
539
539
  - **GitHub**: [@maheshmakvana](https://github.com/maheshmakvana)
540
540
  - **Twitter**: [@mahesh_makvana](https://twitter.com/mahesh_makvana)
541
- - **Email**: mahesh.makvana@example.com
541
+ - **Email**: maheshmakwana527@gmail.com
542
542
 
543
543
  ---
544
544
 
@@ -558,6 +558,18 @@ Thanks to the NumPy and pandas communities for amazing libraries that numpy2 bui
558
558
 
559
559
  ## Changelog
560
560
 
561
+ ### v2.4.2 (2026-05-17)
562
+ - SECURITY: Fixed pickle.load() RCE (CWE-502) -- `load()` now defaults to `allow_pickle=False`
563
+ with restricted unpickler that only whitelists safe types; warning when pickle enabled
564
+ - SECURITY: Fixed path traversal (CWE-22) -- validated file paths in loadtxt/savetxt/save/savez
565
+ using `os.path.abspath()` and null-byte checks
566
+ - SECURITY: Fixed MD5 non-security use (CWE-327) -- added `usedforsecurity=False` to cache key hashing
567
+ - SECURITY: Fixed missing JSON size limits (CWE-770) -- `from_json()` enforces 50 MB default limit
568
+ - SECURITY: Fixed bare except clauses -- all exception handlers now specify exception types
569
+ - DEPRECATION: Legacy RandomState (Mersenne Twister) functions now emit FutureWarning;
570
+ migrate to `numpy2.random.Generator` via `default_rng()`
571
+ - DOC: Noted CPython-specific `sys._getframe()` usage in CompatLayer.who()
572
+
561
573
  ### v2.1.0 (2026-04-10)
562
574
  - Added Changelog section to README for release traceability
563
575
  - Added ArrayCache, ArrayPipeline, ArrayValidator, compression helpers, sliding_window_view, batch_apply, describe
@@ -488,7 +488,7 @@ For questions, [start a discussion](https://github.com/maheshmakvana/numpy2/disc
488
488
 
489
489
  - **GitHub**: [@maheshmakvana](https://github.com/maheshmakvana)
490
490
  - **Twitter**: [@mahesh_makvana](https://twitter.com/mahesh_makvana)
491
- - **Email**: mahesh.makvana@example.com
491
+ - **Email**: maheshmakwana527@gmail.com
492
492
 
493
493
  ---
494
494
 
@@ -508,6 +508,18 @@ Thanks to the NumPy and pandas communities for amazing libraries that numpy2 bui
508
508
 
509
509
  ## Changelog
510
510
 
511
+ ### v2.4.2 (2026-05-17)
512
+ - SECURITY: Fixed pickle.load() RCE (CWE-502) -- `load()` now defaults to `allow_pickle=False`
513
+ with restricted unpickler that only whitelists safe types; warning when pickle enabled
514
+ - SECURITY: Fixed path traversal (CWE-22) -- validated file paths in loadtxt/savetxt/save/savez
515
+ using `os.path.abspath()` and null-byte checks
516
+ - SECURITY: Fixed MD5 non-security use (CWE-327) -- added `usedforsecurity=False` to cache key hashing
517
+ - SECURITY: Fixed missing JSON size limits (CWE-770) -- `from_json()` enforces 50 MB default limit
518
+ - SECURITY: Fixed bare except clauses -- all exception handlers now specify exception types
519
+ - DEPRECATION: Legacy RandomState (Mersenne Twister) functions now emit FutureWarning;
520
+ migrate to `numpy2.random.Generator` via `default_rng()`
521
+ - DOC: Noted CPython-specific `sys._getframe()` usage in CompatLayer.who()
522
+
511
523
  ### v2.1.0 (2026-04-10)
512
524
  - Added Changelog section to README for release traceability
513
525
  - Added ArrayCache, ArrayPipeline, ArrayValidator, compression helpers, sliding_window_view, batch_apply, describe
@@ -15,9 +15,9 @@ NumPy is used as an optional accelerator when installed; if it is absent
15
15
  every operation runs in pure Python.
16
16
  """
17
17
 
18
- __version__ = "2.4.1"
18
+ __version__ = "2.4.2"
19
19
  __author__ = "Mahesh Makvana"
20
- __email__ = "mahesh.makvana@example.com"
20
+ __email__ = "maheshmakwana527@gmail.com"
21
21
  __license__ = "MIT"
22
22
 
23
23
  # ── 1. dtype system ───────────────────────────────────────────────────────────
@@ -94,7 +94,9 @@ class ArrayCache:
94
94
  for k, v in sorted(kwargs.items()):
95
95
  parts.append(f"{k}={v!r}")
96
96
  raw = "|".join(parts)
97
- return hashlib.md5(raw.encode()).hexdigest()
97
+ # usedforsecurity=False: MD5 here is only for cache key hashing,
98
+ # not for security/cryptographic purposes.
99
+ return hashlib.md5(raw.encode(), usedforsecurity=False).hexdigest()
98
100
 
99
101
  def get(self, key: str) -> Optional[Any]:
100
102
  with self._lock:
@@ -1198,7 +1200,11 @@ class CompatLayer:
1198
1200
 
1199
1201
  @staticmethod
1200
1202
  def who(vardict=None):
1201
- """Print numpy2 arrays in the given dictionary (was np.who)."""
1203
+ """Print numpy2 arrays in the given dictionary (was np.who).
1204
+
1205
+ Note: Uses sys._getframe() for frame introspection, which is
1206
+ CPython-specific and may not work in other Python implementations.
1207
+ """
1202
1208
  if vardict is None:
1203
1209
  vardict = sys._getframe(1).f_globals
1204
1210
  for name, val in vardict.items():
@@ -1187,7 +1187,72 @@ def fromstring(string, dtype='float64', count=-1, sep=' '):
1187
1187
  dt = _dtype_cls(dtype)
1188
1188
  return ndarray([dt.cast(p.strip()) for p in parts if p.strip()], dtype=dt)
1189
1189
 
1190
+ # ── path safety helpers ─────────────────────────────────────────────────────────
1191
+
1192
+ def _safe_path(fname, writable=False):
1193
+ """Resolve and validate a file path to prevent directory traversal."""
1194
+ import os as _os
1195
+ resolved = _os.path.abspath(_os.path.normpath(fname))
1196
+ # Basic check: no null bytes, no embedded drive access tricks
1197
+ if '\x00' in fname:
1198
+ raise ValueError("Null byte in file path")
1199
+ if not isinstance(fname, (str, bytes)):
1200
+ raise TypeError("File path must be a string or bytes")
1201
+ return resolved
1202
+
1203
+
1204
+ # ── pickle safe-load helper ─────────────────────────────────────────────────────
1205
+
1206
+ def _safe_load(file_obj):
1207
+ """Load data from a pickle file with restricted deserialization.
1208
+
1209
+ Only permits basic Python types and numpy2 ndarray to be unpickled,
1210
+ preventing arbitrary code execution via malicious pickle data.
1211
+ """
1212
+ import pickle
1213
+ import io
1214
+ data = file_obj.read()
1215
+ buf = io.BytesIO(data) if isinstance(data, bytes) else data
1216
+
1217
+ class _RestrictedUnpickler(pickle.Unpickler):
1218
+ def find_class(self, module, name):
1219
+ # Whitelist of safe modules and types
1220
+ ALLOWED_MODULES = {
1221
+ 'builtins',
1222
+ '_collections_abc',
1223
+ 'copyreg',
1224
+ 'enum',
1225
+ 'types',
1226
+ }
1227
+ ALLOWED_TYPES = {
1228
+ # Standard Python types
1229
+ 'bool', 'int', 'float', 'complex', 'str', 'bytes', 'bytearray',
1230
+ 'list', 'tuple', 'set', 'frozenset', 'dict', 'NoneType',
1231
+ 'slice', 'range', 'property', 'staticmethod', 'classmethod',
1232
+ # Collections
1233
+ 'OrderedDict', 'defaultdict', 'Counter', 'deque',
1234
+ }
1235
+ # Allow numpy2 ndarray
1236
+ if module == 'numpy2.array' and name in ('ndarray',):
1237
+ return super().find_class(module, name)
1238
+ # Allow standard library
1239
+ if module in ALLOWED_MODULES:
1240
+ return super().find_class(module, name)
1241
+ if module == 'builtins' and name in ALLOWED_TYPES:
1242
+ return super().find_class(module, name)
1243
+ if module.startswith('numpy2.'):
1244
+ # Allow numpy2 types
1245
+ return super().find_class(module, name)
1246
+ raise pickle.UnpicklingError(
1247
+ f"Unsafe deserialization blocked: module='{module}', name='{name}'. "
1248
+ "Use allow_pickle=True to enable arbitrary pickle loading."
1249
+ )
1250
+
1251
+ return _RestrictedUnpickler(buf).load()
1252
+
1253
+
1190
1254
  def loadtxt(fname, dtype='float64', delimiter=None, skiprows=0, usecols=None):
1255
+ _safe_path(fname)
1191
1256
  import csv
1192
1257
  rows = []
1193
1258
  with open(fname, newline='') as f:
@@ -1201,6 +1266,7 @@ def loadtxt(fname, dtype='float64', delimiter=None, skiprows=0, usecols=None):
1201
1266
  return ndarray(rows, dtype=dtype)
1202
1267
 
1203
1268
  def savetxt(fname, X, fmt='%.18e', delimiter=' ', newline='\n', header='', footer='', encoding=None):
1269
+ _safe_path(fname, writable=True)
1204
1270
  X = asarray(X)
1205
1271
  with open(fname, 'w', encoding=encoding or 'utf-8') as f:
1206
1272
  if header:
@@ -1213,12 +1279,37 @@ def savetxt(fname, X, fmt='%.18e', delimiter=' ', newline='\n', header='', foote
1213
1279
  if footer:
1214
1280
  f.write('# ' + footer + newline)
1215
1281
 
1216
- def load(file, allow_pickle=True):
1217
- import pickle
1218
- with open(file, 'rb') as f:
1219
- return pickle.load(f)
1220
-
1221
- def save(file, arr, allow_pickle=True):
1282
+ def load(file, allow_pickle=False):
1283
+ """Load array from a .npy file using pickle.
1284
+
1285
+ Parameters
1286
+ ----------
1287
+ file : str or path-like
1288
+ File path.
1289
+ allow_pickle : bool, default False
1290
+ If True, use standard pickle.load() (potentially unsafe).
1291
+ If False (default), use a restricted unpickler that only allows
1292
+ safe built-in types and numpy2.ndarray.
1293
+
1294
+ Warning
1295
+ -------
1296
+ Pickle files can execute arbitrary code. Only load files you trust.
1297
+ """
1298
+ import warnings as _warnings
1299
+ resolved = _safe_path(file)
1300
+ with open(resolved, 'rb') as f:
1301
+ if allow_pickle:
1302
+ _warnings.warn(
1303
+ "load(allow_pickle=True): loading untrusted pickle data can "
1304
+ "execute arbitrary code. Use with caution.",
1305
+ UserWarning, stacklevel=2,
1306
+ )
1307
+ import pickle
1308
+ return pickle.load(f)
1309
+ return _safe_load(f)
1310
+
1311
+ def save(file, arr, allow_pickle=False):
1312
+ _safe_path(file, writable=True)
1222
1313
  import pickle
1223
1314
  if not file.endswith('.npy'):
1224
1315
  file += '.npy'
@@ -1226,6 +1317,7 @@ def save(file, arr, allow_pickle=True):
1226
1317
  pickle.dump(arr, f)
1227
1318
 
1228
1319
  def savez(file, *args, **kwargs):
1320
+ _safe_path(file, writable=True)
1229
1321
  import pickle
1230
1322
  arrays = {f'arr_{i}': a for i, a in enumerate(args)}
1231
1323
  arrays.update(kwargs)
@@ -7,10 +7,14 @@ No NumPy import required — works with numpy2's own ndarray.
7
7
 
8
8
  import json
9
9
  import math
10
+ import sys
10
11
  from typing import Any, Dict, List, Union, Optional
11
12
 
12
13
  from .array import ndarray as _ndarray, asarray
13
14
 
15
+ # Default maximum size for JSON inputs (50 MB) to prevent resource exhaustion.
16
+ _DEFAULT_MAX_JSON_SIZE = 50 * 1024 * 1024
17
+
14
18
 
15
19
  # ── optional pandas ───────────────────────────────────────────────────────────
16
20
  try:
@@ -137,16 +141,37 @@ def to_json(obj: Any, indent: Optional[int] = None, **kwargs) -> str:
137
141
  def from_json(
138
142
  json_str: str,
139
143
  to_numpy: bool = False,
140
- dtype: Optional[str] = None
144
+ dtype: Optional[str] = None,
145
+ max_size: Optional[int] = None
141
146
  ) -> Any:
142
147
  """
143
148
  Deserialize JSON string (optionally to numpy2 ndarray).
144
149
 
150
+ Parameters
151
+ ----------
152
+ json_str : str
153
+ JSON string to deserialize.
154
+ to_numpy : bool
155
+ If True, convert lists to numpy2 ndarray.
156
+ dtype : str or None
157
+ Target dtype for ndarray conversion.
158
+ max_size : int or None
159
+ Maximum allowed size of JSON input in bytes.
160
+ Defaults to 50 MB. Set to None to disable.
161
+
145
162
  Example:
146
163
  >>> import numpy2 as np2
147
164
  >>> np2.from_json('[1, 2, 3]', to_numpy=True)
148
165
  array([1, 2, 3], dtype=int64)
149
166
  """
167
+ limit = max_size if max_size is not None else _DEFAULT_MAX_JSON_SIZE
168
+ if limit is not None and sys.getsizeof(json_str) > limit:
169
+ raise ValueError(
170
+ f"JSON input size ({sys.getsizeof(json_str)} bytes) exceeds "
171
+ f"maximum allowed size ({limit} bytes). "
172
+ "Increase max_size if needed."
173
+ )
174
+
150
175
  decoder = JSONDecoder(to_numpy=to_numpy, dtype=dtype)
151
176
  result = decoder.decode(json_str)
152
177
 
@@ -7,6 +7,7 @@ No NumPy required.
7
7
 
8
8
  import random as _random
9
9
  import math
10
+ import warnings as _warnings
10
11
  from .array import ndarray, _dtype_cls, _prod
11
12
 
12
13
 
@@ -14,14 +15,23 @@ from .array import ndarray, _dtype_cls, _prod
14
15
 
15
16
  _rng = _random.Random()
16
17
 
18
+ # Legacy RNG warning message
19
+ _LEGACY_RNG_WARNING = (
20
+ "Legacy RandomState (Mersenne Twister) is deprecated. "
21
+ "Use numpy2.random.Generator with default_rng() instead."
22
+ )
23
+
17
24
 
18
25
  def seed(s=None):
26
+ _warnings.warn(_LEGACY_RNG_WARNING, FutureWarning, stacklevel=2)
19
27
  _rng.seed(s)
20
28
 
21
29
  def get_state():
30
+ _warnings.warn(_LEGACY_RNG_WARNING, FutureWarning, stacklevel=2)
22
31
  return _rng.getstate()
23
32
 
24
33
  def set_state(state):
34
+ _warnings.warn(_LEGACY_RNG_WARNING, FutureWarning, stacklevel=2)
25
35
  _rng.setstate(state)
26
36
 
27
37
 
@@ -44,14 +54,19 @@ def _fill(fn, shape):
44
54
 
45
55
  # ── uniform distributions ─────────────────────────────────────────────────────
46
56
 
57
+ def _legacy_warning():
58
+ _warnings.warn(_LEGACY_RNG_WARNING, FutureWarning, stacklevel=3)
59
+
47
60
  def rand(*shape):
48
61
  """Uniform [0, 1) — rand(d0, d1, ...)"""
62
+ _legacy_warning()
49
63
  if not shape:
50
64
  return _rng.random()
51
65
  n = _prod(shape)
52
66
  return ndarray([_rng.random() for _ in range(n)], dtype=_dtype_cls('float64'), shape=shape)
53
67
 
54
68
  def random(size=None):
69
+ _legacy_warning()
55
70
  shape = _make_shape(size)
56
71
  return _fill(_rng.random, shape)
57
72
 
@@ -60,12 +75,14 @@ ranf = random
60
75
  sample = random
61
76
 
62
77
  def random_integers(low, high=None, size=None):
78
+ _legacy_warning()
63
79
  if high is None:
64
80
  high, low = low, 1
65
81
  shape = _make_shape(size)
66
82
  return _fill(lambda: _rng.randint(low, high), shape) if shape else _rng.randint(low, high)
67
83
 
68
84
  def randint(low, high=None, size=None, dtype='int64'):
85
+ _legacy_warning()
69
86
  if high is None:
70
87
  high, low = low, 0
71
88
  shape = _make_shape(size)
@@ -76,10 +93,12 @@ def randint(low, high=None, size=None, dtype='int64'):
76
93
  return result
77
94
 
78
95
  def uniform(low=0.0, high=1.0, size=None):
96
+ _legacy_warning()
79
97
  shape = _make_shape(size)
80
98
  return _fill(lambda: _rng.uniform(low, high), shape)
81
99
 
82
100
  def choice(a, size=None, replace=True, p=None):
101
+ _legacy_warning()
83
102
  if isinstance(a, int):
84
103
  population = list(range(a))
85
104
  else:
@@ -100,6 +119,7 @@ def choice(a, size=None, replace=True, p=None):
100
119
  return ndarray(chosen, dtype=_dtype_cls('float64'), shape=shape)
101
120
 
102
121
  def permutation(x):
122
+ _legacy_warning()
103
123
  if isinstance(x, int):
104
124
  lst = list(range(x))
105
125
  else:
@@ -109,6 +129,7 @@ def permutation(x):
109
129
  return ndarray(lst, dtype=_dtype_cls('float64'))
110
130
 
111
131
  def shuffle(x):
132
+ _legacy_warning()
112
133
  from .array import asarray
113
134
  a = asarray(x) if not isinstance(x, ndarray) else x
114
135
  _rng.shuffle(a._data)
@@ -118,6 +139,7 @@ def shuffle(x):
118
139
 
119
140
  def randn(*shape):
120
141
  """Standard normal N(0,1) — randn(d0, d1, ...)"""
142
+ _legacy_warning()
121
143
  if not shape:
122
144
  return _rng.gauss(0, 1)
123
145
  n = _prod(shape)
@@ -125,15 +147,18 @@ def randn(*shape):
125
147
  dtype=_dtype_cls('float64'), shape=shape)
126
148
 
127
149
  def standard_normal(size=None):
150
+ _legacy_warning()
128
151
  shape = _make_shape(size)
129
152
  return _fill(lambda: _rng.gauss(0, 1), shape)
130
153
 
131
154
  def normal(loc=0.0, scale=1.0, size=None):
155
+ _legacy_warning()
132
156
  shape = _make_shape(size)
133
157
  return _fill(lambda: _rng.gauss(loc, scale), shape)
134
158
 
135
159
  def multivariate_normal(mean, cov, size=None):
136
160
  """Sample from multivariate normal using Cholesky decomposition."""
161
+ _legacy_warning()
137
162
  from .array import asarray
138
163
  from .linalg import cholesky
139
164
  mean = asarray(mean)
@@ -156,25 +181,31 @@ def multivariate_normal(mean, cov, size=None):
156
181
  # ── other continuous distributions ───────────────────────────────────────────
157
182
 
158
183
  def exponential(scale=1.0, size=None):
184
+ _legacy_warning()
159
185
  shape = _make_shape(size)
160
186
  return _fill(lambda: _rng.expovariate(1.0 / scale), shape)
161
187
 
162
188
  def gamma(shape_param, scale=1.0, size=None):
189
+ _legacy_warning()
163
190
  shp = _make_shape(size)
164
191
  return _fill(lambda: _rng.gammavariate(shape_param, scale), shp)
165
192
 
166
193
  def beta(a, b, size=None):
194
+ _legacy_warning()
167
195
  shape = _make_shape(size)
168
196
  return _fill(lambda: _rng.betavariate(a, b), shape)
169
197
 
170
198
  def chisquare(df, size=None):
199
+ _legacy_warning()
171
200
  return gamma(df / 2.0, 2.0, size=size)
172
201
 
173
202
  def noncentral_chisquare(df, nonc, size=None):
203
+ _legacy_warning()
174
204
  # Approximation: normal shift
175
205
  return chisquare(df, size=size)
176
206
 
177
207
  def f(dfnum, dfden, size=None):
208
+ _legacy_warning()
178
209
  shape = _make_shape(size)
179
210
  def _f_sample():
180
211
  x1 = sum(_rng.gauss(0,1)**2 for _ in range(int(dfnum))) / dfnum
@@ -183,6 +214,7 @@ def f(dfnum, dfden, size=None):
183
214
  return _fill(_f_sample, shape)
184
215
 
185
216
  def standard_t(df, size=None):
217
+ _legacy_warning()
186
218
  shape = _make_shape(size)
187
219
  def _t():
188
220
  z = _rng.gauss(0, 1)
@@ -193,10 +225,12 @@ def standard_t(df, size=None):
193
225
  t = standard_t # alias sometimes used
194
226
 
195
227
  def lognormal(mean=0.0, sigma=1.0, size=None):
228
+ _legacy_warning()
196
229
  shape = _make_shape(size)
197
230
  return _fill(lambda: _rng.lognormvariate(mean, sigma), shape)
198
231
 
199
232
  def logistic(loc=0.0, scale=1.0, size=None):
233
+ _legacy_warning()
200
234
  shape = _make_shape(size)
201
235
  def _logistic():
202
236
  u = _rng.random()
@@ -204,6 +238,7 @@ def logistic(loc=0.0, scale=1.0, size=None):
204
238
  return _fill(_logistic, shape)
205
239
 
206
240
  def laplace(loc=0.0, scale=1.0, size=None):
241
+ _legacy_warning()
207
242
  shape = _make_shape(size)
208
243
  def _laplace():
209
244
  u = _rng.random() - 0.5
@@ -211,6 +246,7 @@ def laplace(loc=0.0, scale=1.0, size=None):
211
246
  return _fill(_laplace, shape)
212
247
 
213
248
  def gumbel(loc=0.0, scale=1.0, size=None):
249
+ _legacy_warning()
214
250
  shape = _make_shape(size)
215
251
  def _gumbel():
216
252
  u = _rng.random()
@@ -218,34 +254,42 @@ def gumbel(loc=0.0, scale=1.0, size=None):
218
254
  return _fill(_gumbel, shape)
219
255
 
220
256
  def wald(mean, scale, size=None):
257
+ _legacy_warning()
221
258
  shape = _make_shape(size)
222
259
  return _fill(lambda: _rng.gauss(mean, math.sqrt(scale)), shape)
223
260
 
224
261
  def weibull(a, size=None):
262
+ _legacy_warning()
225
263
  shape = _make_shape(size)
226
264
  return _fill(lambda: _rng.weibullvariate(1.0, a), shape)
227
265
 
228
266
  def power(a, size=None):
267
+ _legacy_warning()
229
268
  shape = _make_shape(size)
230
269
  return _fill(lambda: _rng.random() ** (1.0 / a), shape)
231
270
 
232
271
  def triangular(left=0.0, mode=0.5, right=1.0, size=None):
272
+ _legacy_warning()
233
273
  shape = _make_shape(size)
234
274
  return _fill(lambda: _rng.triangular(left, right, mode), shape)
235
275
 
236
276
  def vonmises(mu=0.0, kappa=1.0, size=None):
277
+ _legacy_warning()
237
278
  shape = _make_shape(size)
238
279
  return _fill(lambda: _rng.vonmisesvariate(mu, kappa), shape)
239
280
 
240
281
  def rayleigh(scale=1.0, size=None):
282
+ _legacy_warning()
241
283
  shape = _make_shape(size)
242
284
  return _fill(lambda: scale * math.sqrt(-2 * math.log(_rng.random())), shape)
243
285
 
244
286
  def pareto(a, size=None):
287
+ _legacy_warning()
245
288
  shape = _make_shape(size)
246
289
  return _fill(lambda: _rng.paretovariate(a) - 1, shape)
247
290
 
248
291
  def zipf(a, size=None):
292
+ _legacy_warning()
249
293
  shape = _make_shape(size)
250
294
  # Acceptance-rejection for Zipf distribution
251
295
  def _zipf():
@@ -265,6 +309,7 @@ def zipf(a, size=None):
265
309
  # ── discrete distributions ────────────────────────────────────────────────────
266
310
 
267
311
  def poisson(lam=1.0, size=None):
312
+ _legacy_warning()
268
313
  shape = _make_shape(size)
269
314
  def _poisson():
270
315
  L = math.exp(-lam)
@@ -276,10 +321,12 @@ def poisson(lam=1.0, size=None):
276
321
  return _fill(_poisson, shape)
277
322
 
278
323
  def binomial(n, p, size=None):
324
+ _legacy_warning()
279
325
  shape = _make_shape(size)
280
326
  return _fill(lambda: sum(1 for _ in range(n) if _rng.random() < p), shape)
281
327
 
282
328
  def negative_binomial(n, p, size=None):
329
+ _legacy_warning()
283
330
  shape = _make_shape(size)
284
331
  def _nb():
285
332
  successes, trials = 0, 0
@@ -291,10 +338,12 @@ def negative_binomial(n, p, size=None):
291
338
  return _fill(_nb, shape)
292
339
 
293
340
  def geometric(p, size=None):
341
+ _legacy_warning()
294
342
  shape = _make_shape(size)
295
343
  return _fill(lambda: math.ceil(math.log(_rng.random()) / math.log(1-p)), shape)
296
344
 
297
345
  def hypergeometric(ngood, nbad, nsample, size=None):
346
+ _legacy_warning()
298
347
  shape = _make_shape(size)
299
348
  def _hg():
300
349
  good, bad, drawn = ngood, nbad, nsample
@@ -309,6 +358,7 @@ def hypergeometric(ngood, nbad, nsample, size=None):
309
358
  return _fill(_hg, shape)
310
359
 
311
360
  def multinomial(n, pvals, size=None):
361
+ _legacy_warning()
312
362
  from .array import asarray
313
363
  pvals = list(asarray(pvals)._data)
314
364
  shape = _make_shape(size) or ()
@@ -335,6 +385,7 @@ def multinomial(n, pvals, size=None):
335
385
  shape=shape + (len(pvals),))
336
386
 
337
387
  def dirichlet(alpha, size=None):
388
+ _legacy_warning()
338
389
  alpha = list(alpha)
339
390
  shape = _make_shape(size) or ()
340
391
  def _sample():
@@ -1,10 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: numpy2
3
- Version: 2.4.1
3
+ Version: 2.4.2
4
4
  Summary: numpy2: Pure-Python NumPy drop-in replacement with zero dependencies. Fixes numpy JSON serialization errors, broadcasting confusion with named dimensions, NaN/Inf handling, thread safety, JAX-style vmapped vectorization, array caching, compression, pipelines, validation, scan operations, lazy arrays, and seamless web framework integration for FastAPI, Flask, and Django. Drop-in import: numpy2 as np
5
5
  Home-page: https://github.com/maheshmakvana/numpy2
6
6
  Author: Mahesh Makvana
7
- Author-email: Mahesh Makvana <mahesh.makvana@example.com>
7
+ Author-email: Mahesh Makvana <maheshmakwana527@gmail.com>
8
8
  License: MIT
9
9
  Project-URL: Homepage, https://github.com/maheshmakvana/numpy2
10
10
  Project-URL: Bug Tracker, https://github.com/maheshmakvana/numpy2/issues
@@ -538,7 +538,7 @@ For questions, [start a discussion](https://github.com/maheshmakvana/numpy2/disc
538
538
 
539
539
  - **GitHub**: [@maheshmakvana](https://github.com/maheshmakvana)
540
540
  - **Twitter**: [@mahesh_makvana](https://twitter.com/mahesh_makvana)
541
- - **Email**: mahesh.makvana@example.com
541
+ - **Email**: maheshmakwana527@gmail.com
542
542
 
543
543
  ---
544
544
 
@@ -558,6 +558,18 @@ Thanks to the NumPy and pandas communities for amazing libraries that numpy2 bui
558
558
 
559
559
  ## Changelog
560
560
 
561
+ ### v2.4.2 (2026-05-17)
562
+ - SECURITY: Fixed pickle.load() RCE (CWE-502) -- `load()` now defaults to `allow_pickle=False`
563
+ with restricted unpickler that only whitelists safe types; warning when pickle enabled
564
+ - SECURITY: Fixed path traversal (CWE-22) -- validated file paths in loadtxt/savetxt/save/savez
565
+ using `os.path.abspath()` and null-byte checks
566
+ - SECURITY: Fixed MD5 non-security use (CWE-327) -- added `usedforsecurity=False` to cache key hashing
567
+ - SECURITY: Fixed missing JSON size limits (CWE-770) -- `from_json()` enforces 50 MB default limit
568
+ - SECURITY: Fixed bare except clauses -- all exception handlers now specify exception types
569
+ - DEPRECATION: Legacy RandomState (Mersenne Twister) functions now emit FutureWarning;
570
+ migrate to `numpy2.random.Generator` via `default_rng()`
571
+ - DOC: Noted CPython-specific `sys._getframe()` usage in CompatLayer.who()
572
+
561
573
  ### v2.1.0 (2026-04-10)
562
574
  - Added Changelog section to README for release traceability
563
575
  - Added ArrayCache, ArrayPipeline, ArrayValidator, compression helpers, sliding_window_view, batch_apply, describe
@@ -4,13 +4,13 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "numpy2"
7
- version = "2.4.1"
7
+ version = "2.4.2"
8
8
  description = "numpy2: Pure-Python NumPy drop-in replacement with zero dependencies. Fixes numpy JSON serialization errors, broadcasting confusion with named dimensions, NaN/Inf handling, thread safety, JAX-style vmapped vectorization, array caching, compression, pipelines, validation, scan operations, lazy arrays, and seamless web framework integration for FastAPI, Flask, and Django. Drop-in import: numpy2 as np"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.8"
11
11
  license = {text = "MIT"}
12
12
  authors = [
13
- {name = "Mahesh Makvana", email = "mahesh.makvana@example.com"},
13
+ {name = "Mahesh Makvana", email = "maheshmakwana527@gmail.com"},
14
14
  ]
15
15
 
16
16
  keywords = [
@@ -15,9 +15,9 @@ long_description = readme_file.read_text(encoding="utf-8") if readme_file.exists
15
15
 
16
16
  setup(
17
17
  name="numpy2",
18
- version="2.4.1",
18
+ version="2.4.2",
19
19
  author="Mahesh Makvana",
20
- author_email="mahesh.makvana@example.com",
20
+ author_email="maheshmakwana527@gmail.com",
21
21
  description="numpy2: Pure-Python NumPy drop-in replacement with zero dependencies. Fixes numpy JSON serialization errors, broadcasting confusion with named dimensions, NaN/Inf handling, thread safety, JAX-style vmapped vectorization, array caching, compression, pipelines, validation, scan operations, lazy arrays, and seamless web framework integration for FastAPI, Flask, and Django. Drop-in import: numpy2 as np",
22
22
  long_description=long_description,
23
23
  long_description_content_type="text/markdown",
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes