arraykit 0.6.3__tar.gz → 0.7.0__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.
- {arraykit-0.6.3/arraykit.egg-info → arraykit-0.7.0}/PKG-INFO +1 -1
- {arraykit-0.6.3 → arraykit-0.7.0}/README.rst +8 -0
- {arraykit-0.6.3 → arraykit-0.7.0/arraykit.egg-info}/PKG-INFO +1 -1
- {arraykit-0.6.3 → arraykit-0.7.0}/setup.py +1 -1
- {arraykit-0.6.3 → arraykit-0.7.0}/src/__init__.py +2 -0
- {arraykit-0.6.3 → arraykit-0.7.0}/src/__init__.pyi +2 -0
- {arraykit-0.6.3 → arraykit-0.7.0}/src/_arraykit.c +175 -1
- {arraykit-0.6.3 → arraykit-0.7.0}/test/test_util.py +89 -0
- {arraykit-0.6.3 → arraykit-0.7.0}/LICENSE.txt +0 -0
- {arraykit-0.6.3 → arraykit-0.7.0}/MANIFEST.in +0 -0
- {arraykit-0.6.3 → arraykit-0.7.0}/arraykit.egg-info/SOURCES.txt +0 -0
- {arraykit-0.6.3 → arraykit-0.7.0}/arraykit.egg-info/dependency_links.txt +0 -0
- {arraykit-0.6.3 → arraykit-0.7.0}/arraykit.egg-info/requires.txt +0 -0
- {arraykit-0.6.3 → arraykit-0.7.0}/arraykit.egg-info/top_level.txt +0 -0
- {arraykit-0.6.3 → arraykit-0.7.0}/setup.cfg +0 -0
- {arraykit-0.6.3 → arraykit-0.7.0}/src/py.typed +0 -0
- {arraykit-0.6.3 → arraykit-0.7.0}/test/test_array_go.py +0 -0
- {arraykit-0.6.3 → arraykit-0.7.0}/test/test_block_index.py +0 -0
- {arraykit-0.6.3 → arraykit-0.7.0}/test/test_delimited_to_arrays.py +0 -0
- {arraykit-0.6.3 → arraykit-0.7.0}/test/test_delimited_to_arrays_integration.py +0 -0
- {arraykit-0.6.3 → arraykit-0.7.0}/test/test_delimited_to_arrays_property.py +0 -0
- {arraykit-0.6.3 → arraykit-0.7.0}/test/test_nonzero_1d.py +0 -0
- {arraykit-0.6.3 → arraykit-0.7.0}/test/test_nonzero_1d_property.py +0 -0
- {arraykit-0.6.3 → arraykit-0.7.0}/test/test_pyi.py +0 -0
- {arraykit-0.6.3 → arraykit-0.7.0}/test/test_split_after_count.py +0 -0
- {arraykit-0.6.3 → arraykit-0.7.0}/test/test_tri_map.py +0 -0
- {arraykit-0.6.3 → arraykit-0.7.0}/test/test_type_discovery.py +0 -0
|
@@ -5,7 +5,7 @@ from setuptools import Extension # type: ignore
|
|
|
5
5
|
from setuptools import setup
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
|
|
8
|
-
AK_VERSION = '0.
|
|
8
|
+
AK_VERSION = '0.7.0'
|
|
9
9
|
|
|
10
10
|
def get_long_description() -> str:
|
|
11
11
|
return '''The ArrayKit library provides utilities for creating and transforming NumPy arrays, implementing performance-critical StaticFrame operations as Python C extensions.
|
|
@@ -28,4 +28,6 @@ from ._arraykit import count_iteration as count_iteration
|
|
|
28
28
|
from ._arraykit import first_true_1d as first_true_1d
|
|
29
29
|
from ._arraykit import first_true_2d as first_true_2d
|
|
30
30
|
from ._arraykit import slice_to_ascending_slice as slice_to_ascending_slice
|
|
31
|
+
from ._arraykit import array2d_to_array1d as array2d_to_array1d
|
|
32
|
+
from ._arraykit import array2d_tuple_iter as array2d_tuple_iter
|
|
31
33
|
from ._arraykit import nonzero_1d as nonzero_1d
|
|
@@ -161,3 +161,5 @@ def first_true_1d(__array: np.ndarray, *, forward: bool) -> int: ...
|
|
|
161
161
|
def first_true_2d(__array: np.ndarray, *, forward: bool, axis: int) -> np.ndarray: ...
|
|
162
162
|
def nonzero_1d(__array: np.ndarray, /) -> np.ndarray: ...
|
|
163
163
|
def slice_to_ascending_slice(__slice: slice, __size: int) -> slice: ...
|
|
164
|
+
def array2d_to_array1d(__array: np.ndarray) -> np.ndarray: ...
|
|
165
|
+
def array2d_tuple_iter(__array: np.ndarray) -> tp.Iterator[tp.Tuple[tp.Any, ...]]: ...
|
|
@@ -37,6 +37,18 @@ const static size_t UCS4_SIZE = sizeof(Py_UCS4);
|
|
|
37
37
|
} \
|
|
38
38
|
} while (0)
|
|
39
39
|
|
|
40
|
+
// Given a PyObject, raise if not an array or is not two dimensional.
|
|
41
|
+
# define AK_CHECK_NUMPY_ARRAY_2D(O) \
|
|
42
|
+
do { \
|
|
43
|
+
AK_CHECK_NUMPY_ARRAY(O) \
|
|
44
|
+
int ndim = PyArray_NDIM((PyArrayObject *)O); \
|
|
45
|
+
if (ndim != 2) { \
|
|
46
|
+
return PyErr_Format(PyExc_NotImplementedError,\
|
|
47
|
+
"Expected a 2D array, not %i.", \
|
|
48
|
+
ndim); \
|
|
49
|
+
} \
|
|
50
|
+
} while (0)
|
|
51
|
+
|
|
40
52
|
// Placeholder of not implemented pathways / debugging.
|
|
41
53
|
# define AK_NOT_IMPLEMENTED(msg) \
|
|
42
54
|
do { \
|
|
@@ -3511,6 +3523,167 @@ array_deepcopy(PyObject *m, PyObject *args, PyObject *kwargs)
|
|
|
3511
3523
|
return AK_ArrayDeepCopy(m, (PyArrayObject*)array, memo);
|
|
3512
3524
|
}
|
|
3513
3525
|
|
|
3526
|
+
//------------------------------------------------------------------------------
|
|
3527
|
+
// Given a 2D array, return a 1D object array of tuples.
|
|
3528
|
+
static PyObject *
|
|
3529
|
+
array2d_to_array1d(PyObject *Py_UNUSED(m), PyObject *a)
|
|
3530
|
+
{
|
|
3531
|
+
AK_CHECK_NUMPY_ARRAY_2D(a);
|
|
3532
|
+
PyArrayObject *input_array = (PyArrayObject *)a;
|
|
3533
|
+
|
|
3534
|
+
npy_intp num_rows = PyArray_DIM(input_array, 0);
|
|
3535
|
+
npy_intp num_cols = PyArray_DIM(input_array, 1);
|
|
3536
|
+
|
|
3537
|
+
npy_intp dims[] = {num_rows};
|
|
3538
|
+
// NOTE: this initializes values to NULL, not None
|
|
3539
|
+
PyObject* output = PyArray_SimpleNew(1, dims, NPY_OBJECT);
|
|
3540
|
+
if (output == NULL) {
|
|
3541
|
+
return NULL;
|
|
3542
|
+
}
|
|
3543
|
+
|
|
3544
|
+
PyObject** output_data = (PyObject**)PyArray_DATA((PyArrayObject*)output);
|
|
3545
|
+
PyObject** p = output_data;
|
|
3546
|
+
PyObject** p_end = p + num_rows;
|
|
3547
|
+
npy_intp i = 0;
|
|
3548
|
+
npy_intp j;
|
|
3549
|
+
PyObject* tuple;
|
|
3550
|
+
PyObject* item;
|
|
3551
|
+
|
|
3552
|
+
while (p < p_end) {
|
|
3553
|
+
tuple = PyTuple_New(num_cols);
|
|
3554
|
+
if (tuple == NULL) {
|
|
3555
|
+
goto error;
|
|
3556
|
+
}
|
|
3557
|
+
for (j = 0; j < num_cols; ++j) {
|
|
3558
|
+
// cannot assume input_array is contiguous
|
|
3559
|
+
item = PyArray_ToScalar(PyArray_GETPTR2(input_array, i, j), input_array);
|
|
3560
|
+
if (item == NULL) {
|
|
3561
|
+
Py_DECREF(tuple);
|
|
3562
|
+
goto error;
|
|
3563
|
+
}
|
|
3564
|
+
PyTuple_SET_ITEM(tuple, j, item); // steals reference to item
|
|
3565
|
+
}
|
|
3566
|
+
*p++ = tuple; // assign with new ref, no incr needed
|
|
3567
|
+
i++;
|
|
3568
|
+
}
|
|
3569
|
+
PyArray_CLEARFLAGS((PyArrayObject *)output, NPY_ARRAY_WRITEABLE);
|
|
3570
|
+
return output;
|
|
3571
|
+
error:
|
|
3572
|
+
p = output_data;
|
|
3573
|
+
p_end = p + num_rows;
|
|
3574
|
+
while (p < p_end) { // decref all tuples within array
|
|
3575
|
+
Py_XDECREF(*p++); // xdec as might be NULL
|
|
3576
|
+
}
|
|
3577
|
+
Py_DECREF(output);
|
|
3578
|
+
return NULL;
|
|
3579
|
+
}
|
|
3580
|
+
|
|
3581
|
+
//------------------------------------------------------------------------------
|
|
3582
|
+
// Array2DTuple Iterator
|
|
3583
|
+
|
|
3584
|
+
static PyTypeObject A2DTupleType;
|
|
3585
|
+
|
|
3586
|
+
typedef struct A2DTupleObject {
|
|
3587
|
+
PyObject_HEAD
|
|
3588
|
+
PyArrayObject* array;
|
|
3589
|
+
npy_intp num_rows;
|
|
3590
|
+
npy_intp num_cols;
|
|
3591
|
+
Py_ssize_t pos; // current index state, mutated in-place
|
|
3592
|
+
} A2DTupleObject;
|
|
3593
|
+
|
|
3594
|
+
static PyObject *
|
|
3595
|
+
A2DTuple_new(PyArrayObject* array,
|
|
3596
|
+
npy_intp num_rows,
|
|
3597
|
+
npy_intp num_cols) {
|
|
3598
|
+
A2DTupleObject* a2dt = PyObject_New(A2DTupleObject, &A2DTupleType);
|
|
3599
|
+
if (!a2dt) {
|
|
3600
|
+
return NULL;
|
|
3601
|
+
}
|
|
3602
|
+
Py_INCREF((PyObject*)array);
|
|
3603
|
+
a2dt->array = array;
|
|
3604
|
+
a2dt->num_rows = num_rows;
|
|
3605
|
+
a2dt->num_cols = num_cols;
|
|
3606
|
+
a2dt->pos = 0;
|
|
3607
|
+
return (PyObject *)a2dt;
|
|
3608
|
+
}
|
|
3609
|
+
|
|
3610
|
+
static void
|
|
3611
|
+
A2DTuple_dealloc(A2DTupleObject *self) {
|
|
3612
|
+
Py_DECREF((PyObject*)self->array);
|
|
3613
|
+
PyObject_Del((PyObject*)self);
|
|
3614
|
+
}
|
|
3615
|
+
|
|
3616
|
+
static PyObject*
|
|
3617
|
+
A2DTuple_iter(A2DTupleObject *self) {
|
|
3618
|
+
Py_INCREF(self);
|
|
3619
|
+
return (PyObject*)self;
|
|
3620
|
+
}
|
|
3621
|
+
|
|
3622
|
+
static PyObject *
|
|
3623
|
+
A2DTuple_iternext(A2DTupleObject *self) {
|
|
3624
|
+
Py_ssize_t i = self->pos;
|
|
3625
|
+
if (i < self->num_rows) {
|
|
3626
|
+
npy_intp num_cols = self->num_cols;
|
|
3627
|
+
PyArrayObject* array = self->array;
|
|
3628
|
+
PyObject* tuple = PyTuple_New(num_cols);
|
|
3629
|
+
PyObject* item;
|
|
3630
|
+
if (tuple == NULL) {
|
|
3631
|
+
return NULL;
|
|
3632
|
+
}
|
|
3633
|
+
for (npy_intp j = 0; j < num_cols; ++j) {
|
|
3634
|
+
// cannot assume array is contiguous
|
|
3635
|
+
item = PyArray_ToScalar(PyArray_GETPTR2(array, i, j), array);
|
|
3636
|
+
if (item == NULL) {
|
|
3637
|
+
Py_DECREF(tuple);
|
|
3638
|
+
return NULL;
|
|
3639
|
+
}
|
|
3640
|
+
PyTuple_SET_ITEM(tuple, j, item); // steals reference to item
|
|
3641
|
+
}
|
|
3642
|
+
self->pos++;
|
|
3643
|
+
return tuple;
|
|
3644
|
+
}
|
|
3645
|
+
return NULL;
|
|
3646
|
+
}
|
|
3647
|
+
|
|
3648
|
+
// static PyObject *
|
|
3649
|
+
// A2DTuple_reversed(A2DTupleObject *self) {
|
|
3650
|
+
// return A2DTuple_new(self->bi, !self->reversed);
|
|
3651
|
+
// }
|
|
3652
|
+
|
|
3653
|
+
static PyObject *
|
|
3654
|
+
A2DTuple_length_hint(A2DTupleObject *self) {
|
|
3655
|
+
Py_ssize_t len = Py_MAX(0, self->num_rows - self->pos);
|
|
3656
|
+
return PyLong_FromSsize_t(len);
|
|
3657
|
+
}
|
|
3658
|
+
|
|
3659
|
+
static PyMethodDef A2DTuple_methods[] = {
|
|
3660
|
+
{"__length_hint__", (PyCFunction)A2DTuple_length_hint, METH_NOARGS, NULL},
|
|
3661
|
+
// {"__reversed__", (PyCFunction)A2DTuple_reversed, METH_NOARGS, NULL},
|
|
3662
|
+
{NULL},
|
|
3663
|
+
};
|
|
3664
|
+
|
|
3665
|
+
static PyTypeObject A2DTupleType = {
|
|
3666
|
+
PyVarObject_HEAD_INIT(NULL, 0)
|
|
3667
|
+
.tp_basicsize = sizeof(A2DTupleObject),
|
|
3668
|
+
.tp_dealloc = (destructor) A2DTuple_dealloc,
|
|
3669
|
+
.tp_iter = (getiterfunc) A2DTuple_iter,
|
|
3670
|
+
.tp_iternext = (iternextfunc) A2DTuple_iternext,
|
|
3671
|
+
.tp_methods = A2DTuple_methods,
|
|
3672
|
+
.tp_name = "arraykit.A2DTupleIterator",
|
|
3673
|
+
};
|
|
3674
|
+
|
|
3675
|
+
// Given a 2D array, return an iterator of row tuples.
|
|
3676
|
+
static PyObject *
|
|
3677
|
+
array2d_tuple_iter(PyObject *Py_UNUSED(m), PyObject *a)
|
|
3678
|
+
{
|
|
3679
|
+
AK_CHECK_NUMPY_ARRAY_2D(a);
|
|
3680
|
+
PyArrayObject* array = (PyArrayObject *)a;
|
|
3681
|
+
npy_intp num_rows = PyArray_DIM(array, 0);
|
|
3682
|
+
npy_intp num_cols = PyArray_DIM(array, 1);
|
|
3683
|
+
return A2DTuple_new(array, num_rows, num_cols);
|
|
3684
|
+
}
|
|
3685
|
+
|
|
3686
|
+
|
|
3514
3687
|
//------------------------------------------------------------------------------
|
|
3515
3688
|
// type resolution
|
|
3516
3689
|
|
|
@@ -5944,7 +6117,6 @@ TriMap_dealloc(TriMapObject *self) {
|
|
|
5944
6117
|
if (self->many_from != NULL) {
|
|
5945
6118
|
// decref all arrays before freeing
|
|
5946
6119
|
for (Py_ssize_t i = 0; i < self->many_count; i++) {
|
|
5947
|
-
// NOTE: using dot to get to pointer?
|
|
5948
6120
|
Py_DECREF((PyObject*)self->many_from[i].dst);
|
|
5949
6121
|
}
|
|
5950
6122
|
PyMem_Free(self->many_from);
|
|
@@ -7259,6 +7431,8 @@ static PyMethodDef arraykit_methods[] = {
|
|
|
7259
7431
|
(PyCFunction)array_deepcopy,
|
|
7260
7432
|
METH_VARARGS | METH_KEYWORDS,
|
|
7261
7433
|
NULL},
|
|
7434
|
+
{"array2d_to_array1d", array2d_to_array1d, METH_O, NULL},
|
|
7435
|
+
{"array2d_tuple_iter", array2d_tuple_iter, METH_O, NULL},
|
|
7262
7436
|
{"resolve_dtype", resolve_dtype, METH_VARARGS, NULL},
|
|
7263
7437
|
{"resolve_dtype_iter", resolve_dtype_iter, METH_O, NULL},
|
|
7264
7438
|
{"first_true_1d",
|
|
@@ -22,6 +22,8 @@ from arraykit import count_iteration
|
|
|
22
22
|
from arraykit import first_true_1d
|
|
23
23
|
from arraykit import first_true_2d
|
|
24
24
|
from arraykit import slice_to_ascending_slice
|
|
25
|
+
from arraykit import array2d_to_array1d
|
|
26
|
+
from arraykit import array2d_tuple_iter
|
|
25
27
|
|
|
26
28
|
from performance.reference.util import get_new_indexers_and_screen_ak as get_new_indexers_and_screen_full
|
|
27
29
|
from arraykit import get_new_indexers_and_screen
|
|
@@ -283,6 +285,93 @@ class TestUnit(unittest.TestCase):
|
|
|
283
285
|
with self.assertRaises(TypeError):
|
|
284
286
|
a2 = array_deepcopy(a1, ())
|
|
285
287
|
|
|
288
|
+
#---------------------------------------------------------------------------
|
|
289
|
+
def test_array2d_to_array1d_dummy(self) -> None:
|
|
290
|
+
a1 = np.arange(10)
|
|
291
|
+
with self.assertRaises(NotImplementedError):
|
|
292
|
+
# 1 dimensional
|
|
293
|
+
_ = array2d_to_array1d(a1)
|
|
294
|
+
|
|
295
|
+
def test_array2d_to_array1d_b(self) -> None:
|
|
296
|
+
a1 = np.arange(10, dtype=np.int64).reshape(5, 2)
|
|
297
|
+
result = array2d_to_array1d(a1)
|
|
298
|
+
assert isinstance(result[0], tuple)
|
|
299
|
+
assert result[0] == (0, 1)
|
|
300
|
+
self.assertIs(type(result[0][0]), np.int64)
|
|
301
|
+
self.assertFalse(result.flags.writeable)
|
|
302
|
+
self.assertEqual(tuple(result), ((0, 1), (2, 3), (4, 5), (6, 7), (8, 9)))
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
def test_array2d_to_array1d_c(self) -> None:
|
|
306
|
+
a1 = np.array([["a", "b"], ["ccc", "ddd"], ["ee", "ff"]])
|
|
307
|
+
a2 = array2d_to_array1d(a1)
|
|
308
|
+
self.assertEqual(a2.tolist(), [('a', 'b'), ('ccc', 'ddd'), ('ee', 'ff')])
|
|
309
|
+
|
|
310
|
+
def test_array2d_to_array1d_d(self) -> None:
|
|
311
|
+
a1 = np.array([[3, 5], [10, 20], [7, 2]], dtype=np.uint8)
|
|
312
|
+
a2 = array2d_to_array1d(a1)
|
|
313
|
+
self.assertEqual(a2.tolist(), [(3, 5), (10, 20), (7, 2)])
|
|
314
|
+
self.assertIs(type(a2[0][0]), np.uint8)
|
|
315
|
+
|
|
316
|
+
def test_array2d_to_array1d_e(self) -> None:
|
|
317
|
+
a1 = np.arange(20, dtype=np.int64).reshape(4, 5)
|
|
318
|
+
result = array2d_to_array1d(a1)
|
|
319
|
+
self.assertEqual(result.tolist(), [(0, 1, 2, 3, 4), (5, 6, 7, 8, 9), (10, 11, 12, 13, 14), (15, 16, 17, 18, 19)])
|
|
320
|
+
|
|
321
|
+
#---------------------------------------------------------------------------
|
|
322
|
+
def test_array2d_tuple_iter_a(self) -> None:
|
|
323
|
+
a1 = np.arange(20, dtype=np.int64).reshape(4, 5)
|
|
324
|
+
result = list(array2d_tuple_iter(a1))
|
|
325
|
+
self.assertEqual(len(result), 4)
|
|
326
|
+
self.assertEqual(result, [(0, 1, 2, 3, 4), (5, 6, 7, 8, 9), (10, 11, 12, 13, 14), (15, 16, 17, 18, 19)])
|
|
327
|
+
|
|
328
|
+
def test_array2d_tuple_iter_b(self) -> None:
|
|
329
|
+
a1 = np.arange(20, dtype=np.int64).reshape(10, 2)
|
|
330
|
+
result = list(array2d_tuple_iter(a1))
|
|
331
|
+
self.assertEqual(result, [(0, 1), (2, 3), (4, 5), (6, 7), (8, 9), (10, 11), (12, 13), (14, 15), (16, 17), (18, 19)])
|
|
332
|
+
|
|
333
|
+
def test_array2d_tuple_iter_c(self) -> None:
|
|
334
|
+
a1 = np.array([['aaa', 'bb'], ['c', 'dd'], ['ee', 'fffff']])
|
|
335
|
+
it = array2d_tuple_iter(a1)
|
|
336
|
+
self.assertEqual(it.__length_hint__(), 3)
|
|
337
|
+
self.assertEqual(next(it), ('aaa', 'bb'))
|
|
338
|
+
self.assertEqual(it.__length_hint__(), 2)
|
|
339
|
+
self.assertEqual(next(it), ('c', 'dd'))
|
|
340
|
+
self.assertEqual(it.__length_hint__(), 1)
|
|
341
|
+
self.assertEqual(next(it), ('ee', 'fffff'))
|
|
342
|
+
self.assertEqual(it.__length_hint__(), 0)
|
|
343
|
+
with self.assertRaises(StopIteration):
|
|
344
|
+
next(it)
|
|
345
|
+
|
|
346
|
+
def test_array2d_tuple_iter_d(self) -> None:
|
|
347
|
+
a1 = np.array([['aaa', 'bb'], ['c', 'dd'], ['ee', 'fffff']])
|
|
348
|
+
it = array2d_tuple_iter(a1)
|
|
349
|
+
# __reversed__ not implemented
|
|
350
|
+
with self.assertRaises(TypeError):
|
|
351
|
+
reversed(it)
|
|
352
|
+
|
|
353
|
+
def test_array2d_tuple_iter_e(self) -> None:
|
|
354
|
+
a1 = np.array([[None, 'bb'], [None, 'dd'], [3, None]])
|
|
355
|
+
it = array2d_tuple_iter(a1)
|
|
356
|
+
del a1
|
|
357
|
+
self.assertEqual(list(it), [(None, 'bb'), (None, 'dd'), (3, None)])
|
|
358
|
+
|
|
359
|
+
def test_array2d_tuple_iter_f(self) -> None:
|
|
360
|
+
a1 = np.array([[None, 'bb'], [None, 'dd'], [3, None]])
|
|
361
|
+
it1 = array2d_tuple_iter(a1)
|
|
362
|
+
del a1
|
|
363
|
+
it2 = iter(it1)
|
|
364
|
+
self.assertEqual(list(it1), [(None, 'bb'), (None, 'dd'), (3, None)])
|
|
365
|
+
self.assertEqual(list(it2), []) # expected behavior
|
|
366
|
+
|
|
367
|
+
def test_array2d_tuple_iter_g(self) -> None:
|
|
368
|
+
a1 = np.array([[None, 'bb'], [None, 'dd'], [3, None]])
|
|
369
|
+
it1 = array2d_tuple_iter(a1)
|
|
370
|
+
it2 = array2d_tuple_iter(a1)
|
|
371
|
+
del a1
|
|
372
|
+
self.assertEqual(list(it1), [(None, 'bb'), (None, 'dd'), (3, None)])
|
|
373
|
+
self.assertEqual(list(it2), [(None, 'bb'), (None, 'dd'), (3, None)])
|
|
374
|
+
|
|
286
375
|
#---------------------------------------------------------------------------
|
|
287
376
|
|
|
288
377
|
def test_isna_element_a(self) -> None:
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|