arraykit 0.7.0__tar.gz → 0.7.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 (27) hide show
  1. {arraykit-0.7.0/arraykit.egg-info → arraykit-0.7.2}/PKG-INFO +1 -1
  2. {arraykit-0.7.0 → arraykit-0.7.2}/README.rst +15 -2
  3. {arraykit-0.7.0 → arraykit-0.7.2/arraykit.egg-info}/PKG-INFO +1 -1
  4. {arraykit-0.7.0 → arraykit-0.7.2}/setup.py +1 -1
  5. {arraykit-0.7.0 → arraykit-0.7.2}/src/__init__.py +2 -2
  6. {arraykit-0.7.0 → arraykit-0.7.2}/src/__init__.pyi +2 -2
  7. {arraykit-0.7.0 → arraykit-0.7.2}/src/_arraykit.c +135 -54
  8. {arraykit-0.7.0 → arraykit-0.7.2}/test/test_util.py +92 -30
  9. {arraykit-0.7.0 → arraykit-0.7.2}/LICENSE.txt +0 -0
  10. {arraykit-0.7.0 → arraykit-0.7.2}/MANIFEST.in +0 -0
  11. {arraykit-0.7.0 → arraykit-0.7.2}/arraykit.egg-info/SOURCES.txt +0 -0
  12. {arraykit-0.7.0 → arraykit-0.7.2}/arraykit.egg-info/dependency_links.txt +0 -0
  13. {arraykit-0.7.0 → arraykit-0.7.2}/arraykit.egg-info/requires.txt +0 -0
  14. {arraykit-0.7.0 → arraykit-0.7.2}/arraykit.egg-info/top_level.txt +0 -0
  15. {arraykit-0.7.0 → arraykit-0.7.2}/setup.cfg +0 -0
  16. {arraykit-0.7.0 → arraykit-0.7.2}/src/py.typed +0 -0
  17. {arraykit-0.7.0 → arraykit-0.7.2}/test/test_array_go.py +0 -0
  18. {arraykit-0.7.0 → arraykit-0.7.2}/test/test_block_index.py +0 -0
  19. {arraykit-0.7.0 → arraykit-0.7.2}/test/test_delimited_to_arrays.py +0 -0
  20. {arraykit-0.7.0 → arraykit-0.7.2}/test/test_delimited_to_arrays_integration.py +0 -0
  21. {arraykit-0.7.0 → arraykit-0.7.2}/test/test_delimited_to_arrays_property.py +0 -0
  22. {arraykit-0.7.0 → arraykit-0.7.2}/test/test_nonzero_1d.py +0 -0
  23. {arraykit-0.7.0 → arraykit-0.7.2}/test/test_nonzero_1d_property.py +0 -0
  24. {arraykit-0.7.0 → arraykit-0.7.2}/test/test_pyi.py +0 -0
  25. {arraykit-0.7.0 → arraykit-0.7.2}/test/test_split_after_count.py +0 -0
  26. {arraykit-0.7.0 → arraykit-0.7.2}/test/test_tri_map.py +0 -0
  27. {arraykit-0.7.0 → arraykit-0.7.2}/test/test_type_discovery.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: arraykit
3
- Version: 0.7.0
3
+ Version: 0.7.2
4
4
  Summary: Array utilities for StaticFrame
5
5
  Home-page: https://github.com/static-frame/arraykit
6
6
  Author: Christopher Ariza, Brandt Bucher, Charles Burkland
@@ -37,12 +37,25 @@ ArrayKit requires the following:
37
37
  What is New in ArrayKit
38
38
  -------------------------
39
39
 
40
+
41
+ 0.7.2
42
+ ............
43
+
44
+ Improved ``array_to_tuple_array()`` and ``array_to_tuple_iter()`` to preserve ``tuple`` in 1D arrays.
45
+
46
+
47
+ 0.7.1
48
+ ............
49
+
50
+ Extended ``array_to_tuple_array()`` and ``array_to_tuple_iter()`` to support 1D arrays.
51
+
52
+
40
53
  0.7.0
41
54
  ............
42
55
 
43
- Added ``array2d_to_array1d()``.
56
+ Added ``array_to_tuple_array()``.
44
57
 
45
- Added ``array2d_tuple_iter()``.
58
+ Added ``array_to_tuple_iter()``.
46
59
 
47
60
 
48
61
  0.6.3
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: arraykit
3
- Version: 0.7.0
3
+ Version: 0.7.2
4
4
  Summary: Array utilities for StaticFrame
5
5
  Home-page: https://github.com/static-frame/arraykit
6
6
  Author: Christopher Ariza, Brandt Bucher, Charles Burkland
@@ -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.7.0'
8
+ AK_VERSION = '0.7.2'
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,6 +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
+ from ._arraykit import array_to_tuple_array as array_to_tuple_array
32
+ from ._arraykit import array_to_tuple_iter as array_to_tuple_iter
33
33
  from ._arraykit import nonzero_1d as nonzero_1d
@@ -161,5 +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, ...]]: ...
164
+ def array_to_tuple_array(__array: np.ndarray) -> np.ndarray: ...
165
+ def array_to_tuple_iter(__array: np.ndarray) -> tp.Iterator[tp.Tuple[tp.Any, ...]]: ...
@@ -3524,16 +3524,20 @@ array_deepcopy(PyObject *m, PyObject *args, PyObject *kwargs)
3524
3524
  }
3525
3525
 
3526
3526
  //------------------------------------------------------------------------------
3527
- // Given a 2D array, return a 1D object array of tuples.
3527
+ // Given a 1D or 2D array, return a 1D object array of tuples.
3528
3528
  static PyObject *
3529
- array2d_to_array1d(PyObject *Py_UNUSED(m), PyObject *a)
3529
+ array_to_tuple_array(PyObject *Py_UNUSED(m), PyObject *a)
3530
3530
  {
3531
- AK_CHECK_NUMPY_ARRAY_2D(a);
3531
+ AK_CHECK_NUMPY_ARRAY(a);
3532
3532
  PyArrayObject *input_array = (PyArrayObject *)a;
3533
+ int ndim = PyArray_NDIM(input_array);
3534
+ if (ndim != 1 && ndim != 2) {
3535
+ return PyErr_Format(PyExc_NotImplementedError,
3536
+ "Expected 1D or 2D array, not %i.",
3537
+ ndim);
3538
+ }
3533
3539
 
3534
3540
  npy_intp num_rows = PyArray_DIM(input_array, 0);
3535
- npy_intp num_cols = PyArray_DIM(input_array, 1);
3536
-
3537
3541
  npy_intp dims[] = {num_rows};
3538
3542
  // NOTE: this initializes values to NULL, not None
3539
3543
  PyObject* output = PyArray_SimpleNew(1, dims, NPY_OBJECT);
@@ -3545,26 +3549,64 @@ array2d_to_array1d(PyObject *Py_UNUSED(m), PyObject *a)
3545
3549
  PyObject** p = output_data;
3546
3550
  PyObject** p_end = p + num_rows;
3547
3551
  npy_intp i = 0;
3548
- npy_intp j;
3549
3552
  PyObject* tuple;
3550
3553
  PyObject* item;
3551
3554
 
3552
- while (p < p_end) {
3553
- tuple = PyTuple_New(num_cols);
3554
- if (tuple == NULL) {
3555
- goto error;
3555
+ if (ndim == 2) {
3556
+ npy_intp num_cols = PyArray_DIM(input_array, 1);
3557
+ npy_intp j;
3558
+ while (p < p_end) {
3559
+ tuple = PyTuple_New(num_cols);
3560
+ if (tuple == NULL) {
3561
+ goto error;
3562
+ }
3563
+ for (j = 0; j < num_cols; ++j) {
3564
+ // cannot assume input_array is contiguous
3565
+ item = PyArray_ToScalar(PyArray_GETPTR2(input_array, i, j), input_array);
3566
+ if (item == NULL) {
3567
+ Py_DECREF(tuple);
3568
+ goto error;
3569
+ }
3570
+ PyTuple_SET_ITEM(tuple, j, item); // steals reference to item
3571
+ }
3572
+ *p++ = tuple; // assign with new ref, no incr needed
3573
+ i++;
3556
3574
  }
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);
3575
+ }
3576
+ else if (PyArray_TYPE(input_array) != NPY_OBJECT) { // ndim == 1, not object
3577
+ while (p < p_end) {
3578
+ tuple = PyTuple_New(1);
3579
+ if (tuple == NULL) {
3580
+ goto error;
3581
+ }
3582
+ // scalar returned in is native PyObject from object arrays
3583
+ item = PyArray_ToScalar(PyArray_GETPTR1(input_array, i), input_array);
3560
3584
  if (item == NULL) {
3561
3585
  Py_DECREF(tuple);
3562
3586
  goto error;
3563
3587
  }
3564
- PyTuple_SET_ITEM(tuple, j, item); // steals reference to item
3588
+ PyTuple_SET_ITEM(tuple, 0, item); // steals reference to item
3589
+ *p++ = tuple; // assign with new ref, no incr needed
3590
+ i++;
3591
+ }
3592
+ }
3593
+ else { // ndim == 1, object
3594
+ while (p < p_end) {
3595
+ item = *(PyObject**)PyArray_GETPTR1(input_array, i);
3596
+ Py_INCREF(item); // always incref
3597
+ if (PyTuple_Check(item)) {
3598
+ tuple = item; // do not double pack
3599
+ }
3600
+ else {
3601
+ tuple = PyTuple_New(1);
3602
+ if (tuple == NULL) {
3603
+ goto error;
3604
+ }
3605
+ PyTuple_SET_ITEM(tuple, 0, item); // steals reference to item
3606
+ }
3607
+ *p++ = tuple; // assign with new ref, no incr needed
3608
+ i++;
3565
3609
  }
3566
- *p++ = tuple; // assign with new ref, no incr needed
3567
- i++;
3568
3610
  }
3569
3611
  PyArray_CLEARFLAGS((PyArrayObject *)output, NPY_ARRAY_WRITEABLE);
3570
3612
  return output;
@@ -3579,65 +3621,96 @@ error:
3579
3621
  }
3580
3622
 
3581
3623
  //------------------------------------------------------------------------------
3582
- // Array2DTuple Iterator
3624
+ // ArrayToTupleIterator
3583
3625
 
3584
- static PyTypeObject A2DTupleType;
3626
+ static PyTypeObject ATTType;
3585
3627
 
3586
- typedef struct A2DTupleObject {
3628
+ typedef struct ATTObject {
3587
3629
  PyObject_HEAD
3588
3630
  PyArrayObject* array;
3589
3631
  npy_intp num_rows;
3590
3632
  npy_intp num_cols;
3591
3633
  Py_ssize_t pos; // current index state, mutated in-place
3592
- } A2DTupleObject;
3634
+ } ATTObject;
3593
3635
 
3594
3636
  static PyObject *
3595
- A2DTuple_new(PyArrayObject* array,
3637
+ ATT_new(PyArrayObject* array,
3596
3638
  npy_intp num_rows,
3597
3639
  npy_intp num_cols) {
3598
- A2DTupleObject* a2dt = PyObject_New(A2DTupleObject, &A2DTupleType);
3640
+ ATTObject* a2dt = PyObject_New(ATTObject, &ATTType);
3599
3641
  if (!a2dt) {
3600
3642
  return NULL;
3601
3643
  }
3602
3644
  Py_INCREF((PyObject*)array);
3603
3645
  a2dt->array = array;
3604
3646
  a2dt->num_rows = num_rows;
3605
- a2dt->num_cols = num_cols;
3647
+ a2dt->num_cols = num_cols; // -1 for 1D array
3606
3648
  a2dt->pos = 0;
3607
3649
  return (PyObject *)a2dt;
3608
3650
  }
3609
3651
 
3610
3652
  static void
3611
- A2DTuple_dealloc(A2DTupleObject *self) {
3653
+ ATT_dealloc(ATTObject *self) {
3612
3654
  Py_DECREF((PyObject*)self->array);
3613
3655
  PyObject_Del((PyObject*)self);
3614
3656
  }
3615
3657
 
3616
3658
  static PyObject*
3617
- A2DTuple_iter(A2DTupleObject *self) {
3659
+ ATT_iter(ATTObject *self) {
3618
3660
  Py_INCREF(self);
3619
3661
  return (PyObject*)self;
3620
3662
  }
3621
3663
 
3622
3664
  static PyObject *
3623
- A2DTuple_iternext(A2DTupleObject *self) {
3665
+ ATT_iternext(ATTObject *self) {
3624
3666
  Py_ssize_t i = self->pos;
3625
3667
  if (i < self->num_rows) {
3626
3668
  npy_intp num_cols = self->num_cols;
3627
3669
  PyArrayObject* array = self->array;
3628
- PyObject* tuple = PyTuple_New(num_cols);
3629
3670
  PyObject* item;
3630
- if (tuple == NULL) {
3631
- return NULL;
3671
+ PyObject* tuple;
3672
+
3673
+ if (num_cols > -1) { // ndim == 2
3674
+ tuple = PyTuple_New(num_cols);
3675
+ if (tuple == NULL) {
3676
+ return NULL;
3677
+ }
3678
+ for (npy_intp j = 0; j < num_cols; ++j) {
3679
+ // cannot assume array is contiguous
3680
+ item = PyArray_ToScalar(PyArray_GETPTR2(array, i, j), array);
3681
+ if (item == NULL) {
3682
+ Py_DECREF(tuple);
3683
+ return NULL;
3684
+ }
3685
+ PyTuple_SET_ITEM(tuple, j, item); // steals ref
3686
+ }
3632
3687
  }
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);
3688
+ else if (PyArray_TYPE(array) != NPY_OBJECT) { // ndim == 1, not object
3689
+ tuple = PyTuple_New(1);
3690
+ if (tuple == NULL) {
3691
+ return NULL;
3692
+ }
3693
+ item = PyArray_ToScalar(PyArray_GETPTR1(array, i), array);
3636
3694
  if (item == NULL) {
3637
3695
  Py_DECREF(tuple);
3638
3696
  return NULL;
3639
3697
  }
3640
- PyTuple_SET_ITEM(tuple, j, item); // steals reference to item
3698
+ PyTuple_SET_ITEM(tuple, 0, item); // steals ref
3699
+ }
3700
+ else { // ndim == 1, object
3701
+ item = *(PyObject**)PyArray_GETPTR1(array, i);
3702
+ Py_INCREF(item); // always incref
3703
+ if (PyTuple_Check(item)) {
3704
+ tuple = item; // do not double pack
3705
+ }
3706
+ else {
3707
+ tuple = PyTuple_New(1);
3708
+ if (tuple == NULL) {
3709
+ Py_DECREF(item);
3710
+ return NULL;
3711
+ }
3712
+ PyTuple_SET_ITEM(tuple, 0, item); // steals ref
3713
+ }
3641
3714
  }
3642
3715
  self->pos++;
3643
3716
  return tuple;
@@ -3646,44 +3719,52 @@ A2DTuple_iternext(A2DTupleObject *self) {
3646
3719
  }
3647
3720
 
3648
3721
  // static PyObject *
3649
- // A2DTuple_reversed(A2DTupleObject *self) {
3650
- // return A2DTuple_new(self->bi, !self->reversed);
3722
+ // ATT_reversed(ATTObject *self) {
3723
+ // return ATT_new(self->bi, !self->reversed);
3651
3724
  // }
3652
3725
 
3653
3726
  static PyObject *
3654
- A2DTuple_length_hint(A2DTupleObject *self) {
3727
+ ATT_length_hint(ATTObject *self) {
3655
3728
  Py_ssize_t len = Py_MAX(0, self->num_rows - self->pos);
3656
3729
  return PyLong_FromSsize_t(len);
3657
3730
  }
3658
3731
 
3659
- static PyMethodDef A2DTuple_methods[] = {
3660
- {"__length_hint__", (PyCFunction)A2DTuple_length_hint, METH_NOARGS, NULL},
3661
- // {"__reversed__", (PyCFunction)A2DTuple_reversed, METH_NOARGS, NULL},
3732
+ static PyMethodDef ATT_methods[] = {
3733
+ {"__length_hint__", (PyCFunction)ATT_length_hint, METH_NOARGS, NULL},
3734
+ // {"__reversed__", (PyCFunction)ATT_reversed, METH_NOARGS, NULL},
3662
3735
  {NULL},
3663
3736
  };
3664
3737
 
3665
- static PyTypeObject A2DTupleType = {
3738
+ static PyTypeObject ATTType = {
3666
3739
  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",
3740
+ .tp_basicsize = sizeof(ATTObject),
3741
+ .tp_dealloc = (destructor) ATT_dealloc,
3742
+ .tp_iter = (getiterfunc) ATT_iter,
3743
+ .tp_iternext = (iternextfunc) ATT_iternext,
3744
+ .tp_methods = ATT_methods,
3745
+ .tp_name = "arraykit.ATTIterator",
3673
3746
  };
3674
3747
 
3675
3748
  // Given a 2D array, return an iterator of row tuples.
3676
3749
  static PyObject *
3677
- array2d_tuple_iter(PyObject *Py_UNUSED(m), PyObject *a)
3750
+ array_to_tuple_iter(PyObject *Py_UNUSED(m), PyObject *a)
3678
3751
  {
3679
- AK_CHECK_NUMPY_ARRAY_2D(a);
3680
- PyArrayObject* array = (PyArrayObject *)a;
3752
+ AK_CHECK_NUMPY_ARRAY(a);
3753
+ PyArrayObject *array = (PyArrayObject *)a;
3754
+ int ndim = PyArray_NDIM(array);
3755
+ if (ndim != 1 && ndim != 2) {
3756
+ return PyErr_Format(PyExc_NotImplementedError,
3757
+ "Expected 1D or 2D array, not %i.",
3758
+ ndim);
3759
+ }
3681
3760
  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);
3761
+ npy_intp num_cols = -1; // indicate 1d
3762
+ if (ndim == 2) {
3763
+ num_cols = PyArray_DIM(array, 1);
3764
+ }
3765
+ return ATT_new(array, num_rows, num_cols);
3684
3766
  }
3685
3767
 
3686
-
3687
3768
  //------------------------------------------------------------------------------
3688
3769
  // type resolution
3689
3770
 
@@ -7431,8 +7512,8 @@ static PyMethodDef arraykit_methods[] = {
7431
7512
  (PyCFunction)array_deepcopy,
7432
7513
  METH_VARARGS | METH_KEYWORDS,
7433
7514
  NULL},
7434
- {"array2d_to_array1d", array2d_to_array1d, METH_O, NULL},
7435
- {"array2d_tuple_iter", array2d_tuple_iter, METH_O, NULL},
7515
+ {"array_to_tuple_array", array_to_tuple_array, METH_O, NULL},
7516
+ {"array_to_tuple_iter", array_to_tuple_iter, METH_O, NULL},
7436
7517
  {"resolve_dtype", resolve_dtype, METH_VARARGS, NULL},
7437
7518
  {"resolve_dtype_iter", resolve_dtype_iter, METH_O, NULL},
7438
7519
  {"first_true_1d",
@@ -22,8 +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
+ from arraykit import array_to_tuple_array
26
+ from arraykit import array_to_tuple_iter
27
27
 
28
28
  from performance.reference.util import get_new_indexers_and_screen_ak as get_new_indexers_and_screen_full
29
29
  from arraykit import get_new_indexers_and_screen
@@ -286,15 +286,49 @@ class TestUnit(unittest.TestCase):
286
286
  a2 = array_deepcopy(a1, ())
287
287
 
288
288
  #---------------------------------------------------------------------------
289
- def test_array2d_to_array1d_dummy(self) -> None:
289
+ def test_array_to_tuple_array_1d_a(self) -> None:
290
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:
291
+ a2 = array_to_tuple_array(a1)
292
+ self.assertEqual(a2.tolist(), [(0,), (1,), (2,), (3,), (4,), (5,), (6,), (7,), (8,), (9,)])
293
+
294
+ def test_array_to_tuple_array_1d_b(self) -> None:
295
+ a1 = np.array(['aaa', 'b', 'ccc'])
296
+ a2 = array_to_tuple_array(a1)
297
+ self.assertEqual(a2.tolist(), [('aaa',), ('b',), ('ccc',)])
298
+
299
+ def test_array_to_tuple_array_1d_c(self) -> None:
300
+ a1 = np.array([None, 'b', 30])
301
+ a2 = array_to_tuple_array(a1)
302
+ self.assertEqual(a2.tolist(), [(None,), ('b',), (30,)])
303
+
304
+ def test_array_to_tuple_array_1d_d(self) -> None:
305
+ a1 = np.array([('a', 10), ('b', 30), ('c', 5)], dtype=object)
306
+ a2 = array_to_tuple_array(a1) # from 2d
307
+ self.assertEqual(a2.tolist(), [('a', 10), ('b', 30), ('c', 5)])
308
+ a3 = array_to_tuple_array(a2) # from 1d
309
+ self.assertEqual(a3.tolist(), [('a', 10), ('b', 30), ('c', 5)])
310
+
311
+ def test_array_to_tuple_array_1d_e(self) -> None:
312
+ a1 = np.array([True, False, True], dtype=object)
313
+ a2 = array_to_tuple_array(a1)
314
+ self.assertIs(a2[0][0].__class__, bool)
315
+ self.assertEqual(a2.tolist(), [(True,), (False,), (True,)])
316
+
317
+ def test_array_to_tuple_array_1d_f(self) -> None:
318
+ a1 = np.array([None, None, None], dtype=object)
319
+ a1[0] = 3
320
+ a1[1] = ('a', 30)
321
+ a1[2] = (None, True, 90000000)
322
+
323
+ a2 = array_to_tuple_array(a1)
324
+ self.assertEqual(a2.tolist(), [(3,), ('a', 30), (None, True, 90000000)])
325
+
326
+ a3 = array_to_tuple_array(a2)
327
+ self.assertEqual(a3.tolist(), [(3,), ('a', 30), (None, True, 90000000)])
328
+
329
+ def test_array_to_tuple_array_b(self) -> None:
296
330
  a1 = np.arange(10, dtype=np.int64).reshape(5, 2)
297
- result = array2d_to_array1d(a1)
331
+ result = array_to_tuple_array(a1)
298
332
  assert isinstance(result[0], tuple)
299
333
  assert result[0] == (0, 1)
300
334
  self.assertIs(type(result[0][0]), np.int64)
@@ -302,37 +336,37 @@ class TestUnit(unittest.TestCase):
302
336
  self.assertEqual(tuple(result), ((0, 1), (2, 3), (4, 5), (6, 7), (8, 9)))
303
337
 
304
338
 
305
- def test_array2d_to_array1d_c(self) -> None:
339
+ def test_array_to_tuple_array_c(self) -> None:
306
340
  a1 = np.array([["a", "b"], ["ccc", "ddd"], ["ee", "ff"]])
307
- a2 = array2d_to_array1d(a1)
341
+ a2 = array_to_tuple_array(a1)
308
342
  self.assertEqual(a2.tolist(), [('a', 'b'), ('ccc', 'ddd'), ('ee', 'ff')])
309
343
 
310
- def test_array2d_to_array1d_d(self) -> None:
344
+ def test_array_to_tuple_array_d(self) -> None:
311
345
  a1 = np.array([[3, 5], [10, 20], [7, 2]], dtype=np.uint8)
312
- a2 = array2d_to_array1d(a1)
346
+ a2 = array_to_tuple_array(a1)
313
347
  self.assertEqual(a2.tolist(), [(3, 5), (10, 20), (7, 2)])
314
348
  self.assertIs(type(a2[0][0]), np.uint8)
315
349
 
316
- def test_array2d_to_array1d_e(self) -> None:
350
+ def test_array_to_tuple_array_e(self) -> None:
317
351
  a1 = np.arange(20, dtype=np.int64).reshape(4, 5)
318
- result = array2d_to_array1d(a1)
352
+ result = array_to_tuple_array(a1)
319
353
  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
354
 
321
355
  #---------------------------------------------------------------------------
322
- def test_array2d_tuple_iter_a(self) -> None:
356
+ def test_array_to_tuple_iter_a(self) -> None:
323
357
  a1 = np.arange(20, dtype=np.int64).reshape(4, 5)
324
- result = list(array2d_tuple_iter(a1))
358
+ result = list(array_to_tuple_iter(a1))
325
359
  self.assertEqual(len(result), 4)
326
360
  self.assertEqual(result, [(0, 1, 2, 3, 4), (5, 6, 7, 8, 9), (10, 11, 12, 13, 14), (15, 16, 17, 18, 19)])
327
361
 
328
- def test_array2d_tuple_iter_b(self) -> None:
362
+ def test_array_to_tuple_iter_b(self) -> None:
329
363
  a1 = np.arange(20, dtype=np.int64).reshape(10, 2)
330
- result = list(array2d_tuple_iter(a1))
364
+ result = list(array_to_tuple_iter(a1))
331
365
  self.assertEqual(result, [(0, 1), (2, 3), (4, 5), (6, 7), (8, 9), (10, 11), (12, 13), (14, 15), (16, 17), (18, 19)])
332
366
 
333
- def test_array2d_tuple_iter_c(self) -> None:
367
+ def test_array_to_tuple_iter_c(self) -> None:
334
368
  a1 = np.array([['aaa', 'bb'], ['c', 'dd'], ['ee', 'fffff']])
335
- it = array2d_tuple_iter(a1)
369
+ it = array_to_tuple_iter(a1)
336
370
  self.assertEqual(it.__length_hint__(), 3)
337
371
  self.assertEqual(next(it), ('aaa', 'bb'))
338
372
  self.assertEqual(it.__length_hint__(), 2)
@@ -343,35 +377,63 @@ class TestUnit(unittest.TestCase):
343
377
  with self.assertRaises(StopIteration):
344
378
  next(it)
345
379
 
346
- def test_array2d_tuple_iter_d(self) -> None:
380
+ def test_array_to_tuple_iter_d(self) -> None:
347
381
  a1 = np.array([['aaa', 'bb'], ['c', 'dd'], ['ee', 'fffff']])
348
- it = array2d_tuple_iter(a1)
382
+ it = array_to_tuple_iter(a1)
349
383
  # __reversed__ not implemented
350
384
  with self.assertRaises(TypeError):
351
385
  reversed(it)
352
386
 
353
- def test_array2d_tuple_iter_e(self) -> None:
387
+ def test_array_to_tuple_iter_e(self) -> None:
354
388
  a1 = np.array([[None, 'bb'], [None, 'dd'], [3, None]])
355
- it = array2d_tuple_iter(a1)
389
+ it = array_to_tuple_iter(a1)
356
390
  del a1
357
391
  self.assertEqual(list(it), [(None, 'bb'), (None, 'dd'), (3, None)])
358
392
 
359
- def test_array2d_tuple_iter_f(self) -> None:
393
+ def test_array_to_tuple_iter_f(self) -> None:
360
394
  a1 = np.array([[None, 'bb'], [None, 'dd'], [3, None]])
361
- it1 = array2d_tuple_iter(a1)
395
+ it1 = array_to_tuple_iter(a1)
362
396
  del a1
363
397
  it2 = iter(it1)
364
398
  self.assertEqual(list(it1), [(None, 'bb'), (None, 'dd'), (3, None)])
365
399
  self.assertEqual(list(it2), []) # expected behavior
366
400
 
367
- def test_array2d_tuple_iter_g(self) -> None:
401
+ def test_array_to_tuple_iter_g(self) -> None:
368
402
  a1 = np.array([[None, 'bb'], [None, 'dd'], [3, None]])
369
- it1 = array2d_tuple_iter(a1)
370
- it2 = array2d_tuple_iter(a1)
403
+ it1 = array_to_tuple_iter(a1)
404
+ it2 = array_to_tuple_iter(a1)
371
405
  del a1
372
406
  self.assertEqual(list(it1), [(None, 'bb'), (None, 'dd'), (3, None)])
373
407
  self.assertEqual(list(it2), [(None, 'bb'), (None, 'dd'), (3, None)])
374
408
 
409
+ def test_array_to_tuple_iter_1d_a(self) -> None:
410
+ a1 = np.array(['bb', 'c', 'aaa'])
411
+ result = list(array_to_tuple_iter(a1))
412
+ self.assertEqual(len(result), 3)
413
+ self.assertEqual(result, [('bb',), ('c',), ('aaa',)])
414
+
415
+ def test_array_to_tuple_iter_1d_b(self) -> None:
416
+ a1 = np.array([20, -1, 8])
417
+ result = list(array_to_tuple_iter(a1))
418
+ self.assertEqual(len(result), 3)
419
+ self.assertEqual(result, [(20,), (-1,), (8,)])
420
+
421
+ def test_array_to_tuple_iter_1d_c(self) -> None:
422
+ a1 = np.array([('a', 4), ('c', -1), ('d', 8)], dtype=object)
423
+ a2 = list(array_to_tuple_iter(a1))
424
+ self.assertEqual(len(a2), 3)
425
+ self.assertEqual(a2, [('a', 4), ('c', -1), ('d', 8)])
426
+
427
+ def test_array_to_tuple_iter_1d_d(self) -> None:
428
+ a1 = np.array([None, None, None], dtype=object)
429
+ a1[0] = 3
430
+ a1[1] = ('a', 30)
431
+ a1[2] = (None, True, 90000000)
432
+
433
+ a2 = list(array_to_tuple_iter(a1))
434
+ self.assertEqual(a2, [(3,), ('a', 30), (None, True, 90000000)])
435
+
436
+
375
437
  #---------------------------------------------------------------------------
376
438
 
377
439
  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