arraykit 1.0.9__tar.gz → 1.2.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-1.0.9 → arraykit-1.2.0}/MANIFEST.in +1 -0
- {arraykit-1.0.9/arraykit.egg-info → arraykit-1.2.0}/PKG-INFO +40 -15
- {arraykit-1.0.9 → arraykit-1.2.0}/README.rst +16 -0
- arraykit-1.2.0/VERSION +2 -0
- {arraykit-1.0.9 → arraykit-1.2.0/arraykit.egg-info}/PKG-INFO +40 -15
- {arraykit-1.0.9 → arraykit-1.2.0}/arraykit.egg-info/SOURCES.txt +4 -0
- arraykit-1.2.0/pyproject.toml +56 -0
- arraykit-1.2.0/setup.py +38 -0
- {arraykit-1.0.9 → arraykit-1.2.0}/src/__init__.py +4 -1
- {arraykit-1.0.9 → arraykit-1.2.0}/src/__init__.pyi +3 -0
- {arraykit-1.0.9 → arraykit-1.2.0}/src/_arraykit.c +24 -3
- {arraykit-1.0.9 → arraykit-1.2.0}/src/auto_map.c +14 -4
- {arraykit-1.0.9 → arraykit-1.2.0}/src/methods.c +133 -0
- {arraykit-1.0.9 → arraykit-1.2.0}/src/methods.h +9 -0
- {arraykit-1.0.9 → arraykit-1.2.0}/src/utilities.h +63 -9
- arraykit-1.2.0/test/test_astype_array.py +123 -0
- arraykit-1.2.0/test/test_objectable.py +68 -0
- {arraykit-1.0.9 → arraykit-1.2.0}/test/test_pyi.py +2 -0
- {arraykit-1.0.9 → arraykit-1.2.0}/test/test_util.py +1 -2
- arraykit-1.0.9/setup.py +0 -94
- {arraykit-1.0.9 → arraykit-1.2.0}/LICENSE.txt +0 -0
- {arraykit-1.0.9 → arraykit-1.2.0}/arraykit.egg-info/dependency_links.txt +0 -0
- {arraykit-1.0.9 → arraykit-1.2.0}/arraykit.egg-info/requires.txt +0 -0
- {arraykit-1.0.9 → arraykit-1.2.0}/arraykit.egg-info/top_level.txt +0 -0
- {arraykit-1.0.9 → arraykit-1.2.0}/setup.cfg +0 -0
- {arraykit-1.0.9 → arraykit-1.2.0}/src/array_go.c +0 -0
- {arraykit-1.0.9 → arraykit-1.2.0}/src/array_go.h +0 -0
- {arraykit-1.0.9 → arraykit-1.2.0}/src/array_to_tuple.c +0 -0
- {arraykit-1.0.9 → arraykit-1.2.0}/src/array_to_tuple.h +0 -0
- {arraykit-1.0.9 → arraykit-1.2.0}/src/auto_map.h +0 -0
- {arraykit-1.0.9 → arraykit-1.2.0}/src/block_index.c +0 -0
- {arraykit-1.0.9 → arraykit-1.2.0}/src/block_index.h +0 -0
- {arraykit-1.0.9 → arraykit-1.2.0}/src/delimited_to_arrays.c +0 -0
- {arraykit-1.0.9 → arraykit-1.2.0}/src/delimited_to_arrays.h +0 -0
- {arraykit-1.0.9 → arraykit-1.2.0}/src/py.typed +0 -0
- {arraykit-1.0.9 → arraykit-1.2.0}/src/tri_map.c +0 -0
- {arraykit-1.0.9 → arraykit-1.2.0}/src/tri_map.h +0 -0
- {arraykit-1.0.9 → arraykit-1.2.0}/test/test_array_go.py +0 -0
- {arraykit-1.0.9 → arraykit-1.2.0}/test/test_auto_map.py +0 -0
- {arraykit-1.0.9 → arraykit-1.2.0}/test/test_auto_map_property.py +0 -0
- {arraykit-1.0.9 → arraykit-1.2.0}/test/test_block_index.py +0 -0
- {arraykit-1.0.9 → arraykit-1.2.0}/test/test_delimited_to_arrays.py +0 -0
- {arraykit-1.0.9 → arraykit-1.2.0}/test/test_delimited_to_arrays_integration.py +0 -0
- {arraykit-1.0.9 → arraykit-1.2.0}/test/test_delimited_to_arrays_property.py +0 -0
- {arraykit-1.0.9 → arraykit-1.2.0}/test/test_nonzero_1d.py +0 -0
- {arraykit-1.0.9 → arraykit-1.2.0}/test/test_nonzero_1d_property.py +0 -0
- {arraykit-1.0.9 → arraykit-1.2.0}/test/test_split_after_count.py +0 -0
- {arraykit-1.0.9 → arraykit-1.2.0}/test/test_tri_map.py +0 -0
- {arraykit-1.0.9 → arraykit-1.2.0}/test/test_type_discovery.py +0 -0
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: arraykit
|
|
3
|
-
Version: 1.0
|
|
3
|
+
Version: 1.2.0
|
|
4
4
|
Summary: Array utilities for StaticFrame
|
|
5
|
-
Home-page: https://github.com/static-frame/arraykit
|
|
6
5
|
Author: Christopher Ariza, Brandt Bucher, Charles Burkland
|
|
7
|
-
License: MIT
|
|
8
|
-
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/static-frame/arraykit
|
|
8
|
+
Keywords: numpy,array
|
|
9
9
|
Classifier: Development Status :: 5 - Production/Stable
|
|
10
10
|
Classifier: Intended Audience :: Developers
|
|
11
11
|
Classifier: Topic :: Software Development
|
|
12
12
|
Classifier: Programming Language :: C
|
|
13
13
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
14
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
15
14
|
Classifier: Operating System :: MacOS :: MacOS X
|
|
16
15
|
Classifier: Operating System :: Microsoft :: Windows
|
|
17
16
|
Classifier: Operating System :: POSIX
|
|
@@ -19,22 +18,32 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
19
18
|
Classifier: Programming Language :: Python :: 3.11
|
|
20
19
|
Classifier: Programming Language :: Python :: 3.12
|
|
21
20
|
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
22
|
+
Classifier: Programming Language :: Python :: Free Threading
|
|
22
23
|
Classifier: Typing :: Typed
|
|
23
24
|
Requires-Python: >=3.10
|
|
24
25
|
Description-Content-Type: text/x-rst
|
|
25
26
|
License-File: LICENSE.txt
|
|
26
27
|
Requires-Dist: numpy>=1.24.3
|
|
27
|
-
Dynamic: author
|
|
28
|
-
Dynamic: classifier
|
|
29
|
-
Dynamic: description
|
|
30
|
-
Dynamic: description-content-type
|
|
31
|
-
Dynamic: home-page
|
|
32
|
-
Dynamic: keywords
|
|
33
|
-
Dynamic: license
|
|
34
28
|
Dynamic: license-file
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
.. image:: https://img.shields.io/pypi/pyversions/arraykit.svg
|
|
33
|
+
:target: https://pypi.org/project/arraykit
|
|
34
|
+
|
|
35
|
+
.. image:: https://img.shields.io/pypi/v/arraykit.svg
|
|
36
|
+
:target: https://pypi.org/project/arraykit
|
|
37
|
+
|
|
38
|
+
.. image:: https://img.shields.io/conda/vn/conda-forge/arraykit.svg
|
|
39
|
+
:target: https://anaconda.org/conda-forge/arraykit
|
|
40
|
+
|
|
41
|
+
.. image:: https://img.shields.io/github/actions/workflow/status/static-frame/arraykit/ci.yml?branch=master&label=build&logo=Github
|
|
42
|
+
:target: https://github.com/static-frame/arraykit/actions/workflows/ci.yml
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
arraykit
|
|
46
|
+
=============
|
|
38
47
|
|
|
39
48
|
The ArrayKit library provides utilities for creating and transforming NumPy arrays, implementing performance-critical StaticFrame operations as Python C extensions.
|
|
40
49
|
|
|
@@ -55,6 +64,22 @@ ArrayKit requires the following:
|
|
|
55
64
|
What is New in ArrayKit
|
|
56
65
|
-------------------------
|
|
57
66
|
|
|
67
|
+
1.2.0
|
|
68
|
+
............
|
|
69
|
+
|
|
70
|
+
Now building wheels for Python 3.14 and 3.14t.
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
1.1.0
|
|
74
|
+
............
|
|
75
|
+
|
|
76
|
+
Now building free-threaded compatible wheels for Python 3.13.
|
|
77
|
+
|
|
78
|
+
Added ``is_objectable()`` and ``is_objectable_dt64()``.
|
|
79
|
+
|
|
80
|
+
Added ``astype_array()``.
|
|
81
|
+
|
|
82
|
+
|
|
58
83
|
1.0.9
|
|
59
84
|
............
|
|
60
85
|
|
|
@@ -35,6 +35,22 @@ ArrayKit requires the following:
|
|
|
35
35
|
What is New in ArrayKit
|
|
36
36
|
-------------------------
|
|
37
37
|
|
|
38
|
+
1.2.0
|
|
39
|
+
............
|
|
40
|
+
|
|
41
|
+
Now building wheels for Python 3.14 and 3.14t.
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
1.1.0
|
|
45
|
+
............
|
|
46
|
+
|
|
47
|
+
Now building free-threaded compatible wheels for Python 3.13.
|
|
48
|
+
|
|
49
|
+
Added ``is_objectable()`` and ``is_objectable_dt64()``.
|
|
50
|
+
|
|
51
|
+
Added ``astype_array()``.
|
|
52
|
+
|
|
53
|
+
|
|
38
54
|
1.0.9
|
|
39
55
|
............
|
|
40
56
|
|
arraykit-1.2.0/VERSION
ADDED
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: arraykit
|
|
3
|
-
Version: 1.0
|
|
3
|
+
Version: 1.2.0
|
|
4
4
|
Summary: Array utilities for StaticFrame
|
|
5
|
-
Home-page: https://github.com/static-frame/arraykit
|
|
6
5
|
Author: Christopher Ariza, Brandt Bucher, Charles Burkland
|
|
7
|
-
License: MIT
|
|
8
|
-
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/static-frame/arraykit
|
|
8
|
+
Keywords: numpy,array
|
|
9
9
|
Classifier: Development Status :: 5 - Production/Stable
|
|
10
10
|
Classifier: Intended Audience :: Developers
|
|
11
11
|
Classifier: Topic :: Software Development
|
|
12
12
|
Classifier: Programming Language :: C
|
|
13
13
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
14
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
15
14
|
Classifier: Operating System :: MacOS :: MacOS X
|
|
16
15
|
Classifier: Operating System :: Microsoft :: Windows
|
|
17
16
|
Classifier: Operating System :: POSIX
|
|
@@ -19,22 +18,32 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
19
18
|
Classifier: Programming Language :: Python :: 3.11
|
|
20
19
|
Classifier: Programming Language :: Python :: 3.12
|
|
21
20
|
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
22
|
+
Classifier: Programming Language :: Python :: Free Threading
|
|
22
23
|
Classifier: Typing :: Typed
|
|
23
24
|
Requires-Python: >=3.10
|
|
24
25
|
Description-Content-Type: text/x-rst
|
|
25
26
|
License-File: LICENSE.txt
|
|
26
27
|
Requires-Dist: numpy>=1.24.3
|
|
27
|
-
Dynamic: author
|
|
28
|
-
Dynamic: classifier
|
|
29
|
-
Dynamic: description
|
|
30
|
-
Dynamic: description-content-type
|
|
31
|
-
Dynamic: home-page
|
|
32
|
-
Dynamic: keywords
|
|
33
|
-
Dynamic: license
|
|
34
28
|
Dynamic: license-file
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
.. image:: https://img.shields.io/pypi/pyversions/arraykit.svg
|
|
33
|
+
:target: https://pypi.org/project/arraykit
|
|
34
|
+
|
|
35
|
+
.. image:: https://img.shields.io/pypi/v/arraykit.svg
|
|
36
|
+
:target: https://pypi.org/project/arraykit
|
|
37
|
+
|
|
38
|
+
.. image:: https://img.shields.io/conda/vn/conda-forge/arraykit.svg
|
|
39
|
+
:target: https://anaconda.org/conda-forge/arraykit
|
|
40
|
+
|
|
41
|
+
.. image:: https://img.shields.io/github/actions/workflow/status/static-frame/arraykit/ci.yml?branch=master&label=build&logo=Github
|
|
42
|
+
:target: https://github.com/static-frame/arraykit/actions/workflows/ci.yml
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
arraykit
|
|
46
|
+
=============
|
|
38
47
|
|
|
39
48
|
The ArrayKit library provides utilities for creating and transforming NumPy arrays, implementing performance-critical StaticFrame operations as Python C extensions.
|
|
40
49
|
|
|
@@ -55,6 +64,22 @@ ArrayKit requires the following:
|
|
|
55
64
|
What is New in ArrayKit
|
|
56
65
|
-------------------------
|
|
57
66
|
|
|
67
|
+
1.2.0
|
|
68
|
+
............
|
|
69
|
+
|
|
70
|
+
Now building wheels for Python 3.14 and 3.14t.
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
1.1.0
|
|
74
|
+
............
|
|
75
|
+
|
|
76
|
+
Now building free-threaded compatible wheels for Python 3.13.
|
|
77
|
+
|
|
78
|
+
Added ``is_objectable()`` and ``is_objectable_dt64()``.
|
|
79
|
+
|
|
80
|
+
Added ``astype_array()``.
|
|
81
|
+
|
|
82
|
+
|
|
58
83
|
1.0.9
|
|
59
84
|
............
|
|
60
85
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
LICENSE.txt
|
|
2
2
|
MANIFEST.in
|
|
3
3
|
README.rst
|
|
4
|
+
VERSION
|
|
5
|
+
pyproject.toml
|
|
4
6
|
setup.py
|
|
5
7
|
arraykit.egg-info/PKG-INFO
|
|
6
8
|
arraykit.egg-info/SOURCES.txt
|
|
@@ -27,6 +29,7 @@ src/tri_map.c
|
|
|
27
29
|
src/tri_map.h
|
|
28
30
|
src/utilities.h
|
|
29
31
|
test/test_array_go.py
|
|
32
|
+
test/test_astype_array.py
|
|
30
33
|
test/test_auto_map.py
|
|
31
34
|
test/test_auto_map_property.py
|
|
32
35
|
test/test_block_index.py
|
|
@@ -35,6 +38,7 @@ test/test_delimited_to_arrays_integration.py
|
|
|
35
38
|
test/test_delimited_to_arrays_property.py
|
|
36
39
|
test/test_nonzero_1d.py
|
|
37
40
|
test/test_nonzero_1d_property.py
|
|
41
|
+
test/test_objectable.py
|
|
38
42
|
test/test_pyi.py
|
|
39
43
|
test/test_split_after_count.py
|
|
40
44
|
test/test_tri_map.py
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = [
|
|
3
|
+
"setuptools>=64",
|
|
4
|
+
"wheel",
|
|
5
|
+
"numpy>=2.2"
|
|
6
|
+
]
|
|
7
|
+
build-backend = "setuptools.build_meta"
|
|
8
|
+
|
|
9
|
+
[project]
|
|
10
|
+
name = "arraykit"
|
|
11
|
+
description = "Array utilities for StaticFrame"
|
|
12
|
+
readme = { file = "README.rst", content-type = "text/x-rst" }
|
|
13
|
+
requires-python = ">=3.10"
|
|
14
|
+
|
|
15
|
+
dynamic = ["version"]
|
|
16
|
+
|
|
17
|
+
authors = [
|
|
18
|
+
{ name = "Christopher Ariza" },
|
|
19
|
+
{ name = "Brandt Bucher" },
|
|
20
|
+
{ name = "Charles Burkland" },
|
|
21
|
+
]
|
|
22
|
+
license = "MIT"
|
|
23
|
+
keywords = ["numpy", "array"]
|
|
24
|
+
dependencies = [
|
|
25
|
+
"numpy>=1.24.3",
|
|
26
|
+
]
|
|
27
|
+
classifiers = [
|
|
28
|
+
"Development Status :: 5 - Production/Stable",
|
|
29
|
+
"Intended Audience :: Developers",
|
|
30
|
+
"Topic :: Software Development",
|
|
31
|
+
"Programming Language :: C",
|
|
32
|
+
"Programming Language :: Python :: Implementation :: CPython",
|
|
33
|
+
"Operating System :: MacOS :: MacOS X",
|
|
34
|
+
"Operating System :: Microsoft :: Windows",
|
|
35
|
+
"Operating System :: POSIX",
|
|
36
|
+
"Programming Language :: Python :: 3.10",
|
|
37
|
+
"Programming Language :: Python :: 3.11",
|
|
38
|
+
"Programming Language :: Python :: 3.12",
|
|
39
|
+
"Programming Language :: Python :: 3.13",
|
|
40
|
+
"Programming Language :: Python :: 3.14",
|
|
41
|
+
"Programming Language :: Python :: Free Threading",
|
|
42
|
+
"Typing :: Typed",
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
[project.urls]
|
|
46
|
+
Homepage = "https://github.com/static-frame/arraykit"
|
|
47
|
+
|
|
48
|
+
[tool.setuptools]
|
|
49
|
+
package-dir = { "arraykit" = "src" }
|
|
50
|
+
|
|
51
|
+
[tool.setuptools.package-data]
|
|
52
|
+
arraykit = ["__init__.pyi", "py.typed"]
|
|
53
|
+
|
|
54
|
+
[tool.setuptools.dynamic]
|
|
55
|
+
version = { file = "VERSION" }
|
|
56
|
+
|
arraykit-1.2.0/setup.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from setuptools import setup, Extension
|
|
2
|
+
from setuptools.command.build_ext import build_ext
|
|
3
|
+
import site, os
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
AK_VERSION = Path("VERSION").read_text(encoding="utf-8").strip()
|
|
7
|
+
|
|
8
|
+
def get_ext_dir(*components: tp.Iterable[str]) -> tp.Sequence[str]:
|
|
9
|
+
dirs = []
|
|
10
|
+
for sp in site.getsitepackages():
|
|
11
|
+
fp = os.path.join(sp, *components)
|
|
12
|
+
if os.path.exists(fp):
|
|
13
|
+
dirs.append(fp)
|
|
14
|
+
return dirs
|
|
15
|
+
|
|
16
|
+
ext_modules = [
|
|
17
|
+
Extension(
|
|
18
|
+
name="arraykit._arraykit",
|
|
19
|
+
sources=[
|
|
20
|
+
"src/_arraykit.c",
|
|
21
|
+
"src/array_go.c",
|
|
22
|
+
"src/array_to_tuple.c",
|
|
23
|
+
"src/block_index.c",
|
|
24
|
+
"src/delimited_to_arrays.c",
|
|
25
|
+
"src/methods.c",
|
|
26
|
+
"src/tri_map.c",
|
|
27
|
+
"src/auto_map.c",
|
|
28
|
+
],
|
|
29
|
+
|
|
30
|
+
include_dirs=get_ext_dir('numpy', '_core', 'include') + ['src'],
|
|
31
|
+
library_dirs=get_ext_dir('numpy', '_core', 'lib'),
|
|
32
|
+
define_macros=[("AK_VERSION", AK_VERSION)],
|
|
33
|
+
libraries=["npymath"],
|
|
34
|
+
)
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
setup(ext_modules=ext_modules)
|
|
38
|
+
|
|
@@ -31,7 +31,10 @@ from ._arraykit import slice_to_ascending_slice as slice_to_ascending_slice
|
|
|
31
31
|
from ._arraykit import array_to_tuple_array as array_to_tuple_array
|
|
32
32
|
from ._arraykit import array_to_tuple_iter as array_to_tuple_iter
|
|
33
33
|
from ._arraykit import nonzero_1d as nonzero_1d
|
|
34
|
-
|
|
34
|
+
from ._arraykit import is_objectable_dt64 as is_objectable_dt64
|
|
35
|
+
from ._arraykit import is_objectable as is_objectable
|
|
36
|
+
from ._arraykit import astype_array as astype_array
|
|
35
37
|
from ._arraykit import AutoMap as AutoMap
|
|
36
38
|
from ._arraykit import FrozenAutoMap as FrozenAutoMap
|
|
37
39
|
from ._arraykit import NonUniqueError as NonUniqueError
|
|
40
|
+
|
|
@@ -203,6 +203,9 @@ def get_new_indexers_and_screen(indexers: np.ndarray, positions: np.ndarray) ->
|
|
|
203
203
|
def first_true_1d(__array: np.ndarray, *, forward: bool) -> int: ...
|
|
204
204
|
def first_true_2d(__array: np.ndarray, *, forward: bool, axis: int) -> np.ndarray: ...
|
|
205
205
|
def nonzero_1d(__array: np.ndarray, /) -> np.ndarray: ...
|
|
206
|
+
def is_objectable_dt64(__array: np.ndarray, /) -> bool: ...
|
|
207
|
+
def is_objectable(__array: np.ndarray, /) -> bool: ...
|
|
208
|
+
def astype_array(__array: np.ndarray, __dtype: np.dtype | None, /) -> np.ndarray: ...
|
|
206
209
|
def slice_to_ascending_slice(__slice: slice, __size: int) -> slice: ...
|
|
207
210
|
def array_to_tuple_array(__array: np.ndarray) -> np.ndarray: ...
|
|
208
211
|
def array_to_tuple_iter(__array: np.ndarray) -> tp.Iterator[tp.Tuple[tp.Any, ...]]: ...
|
|
@@ -52,6 +52,9 @@ static PyMethodDef arraykit_methods[] = {
|
|
|
52
52
|
NULL},
|
|
53
53
|
{"count_iteration", count_iteration, METH_O, NULL},
|
|
54
54
|
{"nonzero_1d", nonzero_1d, METH_O, NULL},
|
|
55
|
+
{"is_objectable_dt64", is_objectable_dt64, METH_O, NULL},
|
|
56
|
+
{"is_objectable", is_objectable, METH_O, NULL},
|
|
57
|
+
{"astype_array", astype_array, METH_VARARGS, NULL},
|
|
55
58
|
{"isna_element",
|
|
56
59
|
(PyCFunction)isna_element,
|
|
57
60
|
METH_VARARGS | METH_KEYWORDS,
|
|
@@ -72,7 +75,7 @@ static struct PyModuleDef arraykit_module = {
|
|
|
72
75
|
.m_methods = arraykit_methods,
|
|
73
76
|
};
|
|
74
77
|
|
|
75
|
-
PyObject
|
|
78
|
+
PyObject*
|
|
76
79
|
PyInit__arraykit(void)
|
|
77
80
|
{
|
|
78
81
|
import_array();
|
|
@@ -95,6 +98,7 @@ PyInit__arraykit(void)
|
|
|
95
98
|
return NULL;
|
|
96
99
|
}
|
|
97
100
|
|
|
101
|
+
// store a reference to the deepcopy function
|
|
98
102
|
PyObject *copy = PyImport_ImportModule("copy");
|
|
99
103
|
if (copy == NULL) {
|
|
100
104
|
return NULL;
|
|
@@ -105,6 +109,18 @@ PyInit__arraykit(void)
|
|
|
105
109
|
return NULL;
|
|
106
110
|
}
|
|
107
111
|
|
|
112
|
+
// store a year dtype object
|
|
113
|
+
PyObject* dt_year_str = PyUnicode_FromString("datetime64[Y]");
|
|
114
|
+
if (!dt_year_str) return NULL;
|
|
115
|
+
|
|
116
|
+
PyArray_Descr* dt_year = NULL;
|
|
117
|
+
if (!PyArray_DescrConverter2(dt_year_str, &dt_year)) {
|
|
118
|
+
Py_DECREF(dt_year_str);
|
|
119
|
+
return NULL;
|
|
120
|
+
}
|
|
121
|
+
Py_DECREF(dt_year_str);
|
|
122
|
+
|
|
123
|
+
|
|
108
124
|
PyObject *m = PyModule_Create(&arraykit_module);
|
|
109
125
|
if (!m ||
|
|
110
126
|
PyModule_AddStringConstant(m, "__version__", Py_STRINGIFY(AK_VERSION)) ||
|
|
@@ -128,12 +144,17 @@ PyInit__arraykit(void)
|
|
|
128
144
|
PyModule_AddObject(m, "ErrorInitTypeBlocks", ErrorInitTypeBlocks) ||
|
|
129
145
|
PyModule_AddObject(m, "AutoMap", (PyObject *)&AMType) ||
|
|
130
146
|
PyModule_AddObject(m, "FrozenAutoMap", (PyObject *)&FAMType) ||
|
|
131
|
-
PyModule_AddObject(m, "NonUniqueError", NonUniqueError)
|
|
147
|
+
PyModule_AddObject(m, "NonUniqueError", NonUniqueError) ||
|
|
148
|
+
PyModule_AddObject(m, "dt_year", (PyObject *)dt_year)
|
|
132
149
|
){
|
|
133
|
-
|
|
150
|
+
Py_XDECREF(deepcopy);
|
|
151
|
+
Py_XDECREF(dt_year);
|
|
134
152
|
Py_XDECREF(m);
|
|
135
153
|
return NULL;
|
|
136
154
|
}
|
|
155
|
+
#ifdef Py_GIL_DISABLED
|
|
156
|
+
PyUnstable_Module_SetGIL(m, Py_MOD_GIL_NOT_USED);
|
|
157
|
+
#endif
|
|
137
158
|
return m;
|
|
138
159
|
}
|
|
139
160
|
|
|
@@ -426,8 +426,13 @@ fami_iternext(FAMIObject *self)
|
|
|
426
426
|
else {
|
|
427
427
|
PyObject* t = PyTuple_New(2);
|
|
428
428
|
if (!t) { return NULL; }
|
|
429
|
+
#if PY_VERSION_HEX >= 0x030D0000 // Python 3.13+
|
|
430
|
+
PyObject* k = PyList_GetItemRef(self->fam->keys, index);
|
|
431
|
+
#else
|
|
429
432
|
PyObject* k = PyList_GET_ITEM(self->fam->keys, index);
|
|
430
|
-
|
|
433
|
+
Py_XINCREF(k);
|
|
434
|
+
#endif
|
|
435
|
+
if (!k) { return NULL; }
|
|
431
436
|
PyTuple_SET_ITEM(t, 0, k);
|
|
432
437
|
PyTuple_SET_ITEM(t, 1, PyLong_FromSsize_t(index));
|
|
433
438
|
return t;
|
|
@@ -438,8 +443,13 @@ fami_iternext(FAMIObject *self)
|
|
|
438
443
|
return PyArray_ToScalar(PyArray_GETPTR1(self->keys_array, index), self->keys_array);
|
|
439
444
|
}
|
|
440
445
|
else {
|
|
446
|
+
#if PY_VERSION_HEX >= 0x030D0000 // Python 3.13+
|
|
447
|
+
PyObject* yield = PyList_GetItemRef(self->fam->keys, index);
|
|
448
|
+
#else
|
|
441
449
|
PyObject* yield = PyList_GET_ITEM(self->fam->keys, index);
|
|
442
|
-
|
|
450
|
+
Py_XINCREF(yield);
|
|
451
|
+
#endif
|
|
452
|
+
if (!yield) { return NULL; }
|
|
443
453
|
return yield;
|
|
444
454
|
}
|
|
445
455
|
}
|
|
@@ -1302,11 +1312,11 @@ lookup(FAMObject *self, PyObject *key) {
|
|
|
1302
1312
|
return self->table[table_pos].keys_pos;
|
|
1303
1313
|
}
|
|
1304
1314
|
|
|
1305
|
-
// Insert a key_pos, hash pair into the table. Assumes table already has appropriate size. When inserting a new
|
|
1315
|
+
// Insert a key_pos, hash pair into the table. Assumes table already has appropriate size. When inserting a new item, `hash` is -1, forcing a fresh hash to be computed here. Return 0 on success, -1 on error.
|
|
1306
1316
|
static int
|
|
1307
1317
|
insert_obj(
|
|
1308
1318
|
FAMObject *self,
|
|
1309
|
-
PyObject *key,
|
|
1319
|
+
PyObject *key, // NOTE: a borrowed reference
|
|
1310
1320
|
Py_ssize_t keys_pos,
|
|
1311
1321
|
Py_hash_t hash)
|
|
1312
1322
|
{
|
|
@@ -201,6 +201,139 @@ nonzero_1d(PyObject *Py_UNUSED(m), PyObject *a) {
|
|
|
201
201
|
return AK_nonzero_1d(array);
|
|
202
202
|
}
|
|
203
203
|
|
|
204
|
+
PyObject*
|
|
205
|
+
is_objectable_dt64(PyObject *m, PyObject *a) {
|
|
206
|
+
AK_CHECK_NUMPY_ARRAY(a);
|
|
207
|
+
PyArrayObject* array = (PyArrayObject*)a;
|
|
208
|
+
|
|
209
|
+
// this returns a new reference
|
|
210
|
+
PyObject* dt_year = PyObject_GetAttrString(m, "dt_year");
|
|
211
|
+
int is_objectable = AK_is_objectable_dt64(array, dt_year);
|
|
212
|
+
Py_DECREF(dt_year);
|
|
213
|
+
|
|
214
|
+
switch (is_objectable) {
|
|
215
|
+
case -1:
|
|
216
|
+
return NULL;
|
|
217
|
+
case 0:
|
|
218
|
+
Py_RETURN_FALSE;
|
|
219
|
+
case 1:
|
|
220
|
+
Py_RETURN_TRUE;
|
|
221
|
+
}
|
|
222
|
+
return NULL;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
PyObject*
|
|
227
|
+
is_objectable(PyObject *m, PyObject *a) {
|
|
228
|
+
AK_CHECK_NUMPY_ARRAY(a);
|
|
229
|
+
PyArrayObject* array = (PyArrayObject*)a;
|
|
230
|
+
|
|
231
|
+
char kind = PyArray_DESCR(array)->kind;
|
|
232
|
+
if ((kind == 'M' || kind == 'm')) {
|
|
233
|
+
// this returns a new reference
|
|
234
|
+
PyObject* dt_year = PyObject_GetAttrString(m, "dt_year");
|
|
235
|
+
int is_objectable = AK_is_objectable_dt64(array, dt_year);
|
|
236
|
+
Py_DECREF(dt_year);
|
|
237
|
+
|
|
238
|
+
switch (is_objectable) {
|
|
239
|
+
case -1:
|
|
240
|
+
return NULL;
|
|
241
|
+
case 0:
|
|
242
|
+
Py_RETURN_FALSE;
|
|
243
|
+
case 1:
|
|
244
|
+
Py_RETURN_TRUE;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
Py_RETURN_TRUE;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// Convert array to the dtype provided. NOTE: mutable arrays will be returned unless the input array is immutable and no dtype change is needed
|
|
251
|
+
PyObject*
|
|
252
|
+
astype_array(PyObject* m, PyObject* args) {
|
|
253
|
+
|
|
254
|
+
PyObject* a = NULL;
|
|
255
|
+
PyObject* dtype_spec = Py_None;
|
|
256
|
+
|
|
257
|
+
if (!PyArg_ParseTuple(args, "O!|O:astype_array",
|
|
258
|
+
&PyArray_Type, &a,
|
|
259
|
+
&dtype_spec)) {
|
|
260
|
+
return NULL;
|
|
261
|
+
}
|
|
262
|
+
PyArrayObject* array = (PyArrayObject*)a;
|
|
263
|
+
|
|
264
|
+
PyArray_Descr* dtype = NULL;
|
|
265
|
+
if (dtype_spec == Py_None) {
|
|
266
|
+
dtype = PyArray_DescrFromType(NPY_DEFAULT_TYPE);
|
|
267
|
+
} else {
|
|
268
|
+
if (!PyArray_DescrConverter(dtype_spec, &dtype)) {
|
|
269
|
+
return NULL;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if (PyArray_EquivTypes(PyArray_DESCR(array), dtype)) {
|
|
274
|
+
Py_DECREF(dtype);
|
|
275
|
+
|
|
276
|
+
if (PyArray_ISWRITEABLE(array)) {
|
|
277
|
+
PyObject* result = PyArray_NewCopy(array, NPY_ANYORDER);
|
|
278
|
+
if (!result) {
|
|
279
|
+
return NULL;
|
|
280
|
+
}
|
|
281
|
+
return result;
|
|
282
|
+
}
|
|
283
|
+
else { // already immutable
|
|
284
|
+
Py_INCREF(a);
|
|
285
|
+
return a;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
// if converting to an object
|
|
289
|
+
if (dtype->type_num == NPY_OBJECT) {
|
|
290
|
+
char kind = PyArray_DESCR(array)->kind;
|
|
291
|
+
if ((kind == 'M' || kind == 'm')) {
|
|
292
|
+
PyObject* dt_year = PyObject_GetAttrString(m, "dt_year");
|
|
293
|
+
int is_objectable = AK_is_objectable_dt64(array, dt_year);
|
|
294
|
+
Py_DECREF(dt_year);
|
|
295
|
+
|
|
296
|
+
if (!is_objectable) {
|
|
297
|
+
PyObject* result = PyArray_NewLikeArray(array, NPY_ANYORDER, dtype, 0);
|
|
298
|
+
if (!result) {
|
|
299
|
+
Py_DECREF(dtype);
|
|
300
|
+
return NULL;
|
|
301
|
+
}
|
|
302
|
+
PyObject** data = (PyObject**)PyArray_DATA((PyArrayObject*)result);
|
|
303
|
+
|
|
304
|
+
PyArrayIterObject* it = (PyArrayIterObject*)PyArray_IterNew(a);
|
|
305
|
+
if (!it) {
|
|
306
|
+
Py_DECREF(result);
|
|
307
|
+
return NULL;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
npy_intp i = 0;
|
|
311
|
+
while (it->index < it->size) {
|
|
312
|
+
PyObject* item = PyArray_ToScalar(it->dataptr, array);
|
|
313
|
+
if (!item) {
|
|
314
|
+
Py_DECREF(result);
|
|
315
|
+
Py_DECREF(it);
|
|
316
|
+
return NULL;
|
|
317
|
+
}
|
|
318
|
+
data[i++] = item;
|
|
319
|
+
PyArray_ITER_NEXT(it);
|
|
320
|
+
}
|
|
321
|
+
Py_DECREF(it);
|
|
322
|
+
return result;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
// all other cases: do a standard cast conversion
|
|
327
|
+
PyObject* result = PyArray_CastToType(array, dtype, 0);
|
|
328
|
+
if (!result) {
|
|
329
|
+
Py_DECREF(dtype);
|
|
330
|
+
return NULL;
|
|
331
|
+
}
|
|
332
|
+
return result;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
|
|
204
337
|
static char *first_true_1d_kwarg_names[] = {
|
|
205
338
|
"array",
|
|
206
339
|
"forward",
|
|
@@ -47,6 +47,15 @@ resolve_dtype_iter(PyObject *Py_UNUSED(m), PyObject *arg);
|
|
|
47
47
|
PyObject *
|
|
48
48
|
nonzero_1d(PyObject *Py_UNUSED(m), PyObject *a);
|
|
49
49
|
|
|
50
|
+
PyObject *
|
|
51
|
+
is_objectable_dt64(PyObject *m, PyObject *a);
|
|
52
|
+
|
|
53
|
+
PyObject *
|
|
54
|
+
is_objectable(PyObject *m, PyObject *a);
|
|
55
|
+
|
|
56
|
+
PyObject *
|
|
57
|
+
astype_array(PyObject *m, PyObject *args);
|
|
58
|
+
|
|
50
59
|
PyObject *
|
|
51
60
|
first_true_1d(PyObject *Py_UNUSED(m), PyObject *args, PyObject *kwargs);
|
|
52
61
|
|
|
@@ -223,6 +223,69 @@ AK_slice_to_ascending_slice(PyObject* slice, Py_ssize_t size)
|
|
|
223
223
|
-step);
|
|
224
224
|
}
|
|
225
225
|
|
|
226
|
+
|
|
227
|
+
static inline NPY_DATETIMEUNIT
|
|
228
|
+
AK_dt_unit_from_array(PyArrayObject* a) {
|
|
229
|
+
// This is based on get_datetime_metadata_from_dtype in the NumPy source, but that function is private. This does not check that the dtype is of the appropriate type.
|
|
230
|
+
PyArray_Descr* dt = PyArray_DESCR(a); // borrowed ref
|
|
231
|
+
PyArray_DatetimeMetaData* dma = &(((PyArray_DatetimeDTypeMetaData *)PyDataType_C_METADATA(dt))->meta);
|
|
232
|
+
return dma->base;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Given a dt64 array, determine if it can be cast to a object without data loss. Returns -1 on error. NOTE: if we use dt_year, must incref first
|
|
236
|
+
static inline int
|
|
237
|
+
AK_is_objectable_dt64(PyArrayObject* a, PyObject* dt_year)
|
|
238
|
+
{
|
|
239
|
+
NPY_DATETIMEUNIT unit = AK_dt_unit_from_array(a);
|
|
240
|
+
switch (unit) {
|
|
241
|
+
case NPY_FR_ERROR:
|
|
242
|
+
case NPY_FR_Y:
|
|
243
|
+
case NPY_FR_M:
|
|
244
|
+
case NPY_FR_W:
|
|
245
|
+
return false;
|
|
246
|
+
case NPY_FR_D:
|
|
247
|
+
case NPY_FR_h:
|
|
248
|
+
case NPY_FR_m:
|
|
249
|
+
case NPY_FR_s:
|
|
250
|
+
case NPY_FR_ms:
|
|
251
|
+
case NPY_FR_us:
|
|
252
|
+
break;
|
|
253
|
+
case NPY_FR_ns:
|
|
254
|
+
case NPY_FR_ps:
|
|
255
|
+
case NPY_FR_fs:
|
|
256
|
+
case NPY_FR_as:
|
|
257
|
+
case NPY_FR_GENERIC:
|
|
258
|
+
return false;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
Py_INCREF(dt_year);
|
|
262
|
+
PyObject* a_year = PyArray_CastToType(a, (PyArray_Descr*)dt_year, 0);
|
|
263
|
+
if (!a_year) {
|
|
264
|
+
Py_DECREF(dt_year);
|
|
265
|
+
return -1;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
npy_int64* data = (npy_int64*)PyArray_DATA((PyArrayObject*)a_year);
|
|
269
|
+
npy_intp size = PyArray_SIZE((PyArrayObject*)a_year);
|
|
270
|
+
|
|
271
|
+
for (npy_intp i = 0; i < size; ++i) {
|
|
272
|
+
npy_int64 v = data[i];
|
|
273
|
+
if (v == NPY_DATETIME_NAT) {
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
// offset: 1-1970, 9999-1970
|
|
277
|
+
if (v < -1969 || v > 8029) {
|
|
278
|
+
Py_DECREF(a_year);
|
|
279
|
+
return 0;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
Py_DECREF(a_year);
|
|
283
|
+
return 1;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
|
|
226
289
|
// Given a Boolean, contiguous 1D array, return the index positions in an int64 array. Through experimentation it has been verified that doing full-size allocation of memory provides the best performance at all scales. Using NpyIter, or using, bit masks does not improve performance over pointer arithmetic. Prescanning for all empty is very effective. Note that NumPy benefits from first counting the nonzeros, then allocating only enough data for the expexted number of indices.
|
|
227
290
|
static inline PyObject *
|
|
228
291
|
AK_nonzero_1d(PyArrayObject* array) {
|
|
@@ -319,15 +382,6 @@ AK_nonzero_1d(PyArrayObject* array) {
|
|
|
319
382
|
return final;
|
|
320
383
|
}
|
|
321
384
|
|
|
322
|
-
static inline NPY_DATETIMEUNIT
|
|
323
|
-
AK_dt_unit_from_array(PyArrayObject* a) {
|
|
324
|
-
// This is based on get_datetime_metadata_from_dtype in the NumPy source, but that function is private. This does not check that the dtype is of the appropriate type.
|
|
325
|
-
PyArray_Descr* dt = PyArray_DESCR(a); // borrowed ref
|
|
326
|
-
PyArray_DatetimeMetaData* dma = &(((PyArray_DatetimeDTypeMetaData *)PyDataType_C_METADATA(dt))->meta);
|
|
327
|
-
// PyArray_DatetimeMetaData* dma = &(((PyArray_DatetimeDTypeMetaData *)PyArray_DESCR(a)->c_metadata)->meta);
|
|
328
|
-
return dma->base;
|
|
329
|
-
}
|
|
330
|
-
|
|
331
385
|
static inline NPY_DATETIMEUNIT
|
|
332
386
|
AK_dt_unit_from_scalar(PyDatetimeScalarObject* dts) {
|
|
333
387
|
// Based on convert_pyobject_to_datetime and related usage in datetime.c
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
from arraykit import astype_array
|
|
6
|
+
|
|
7
|
+
class TestUnit(unittest.TestCase):
|
|
8
|
+
|
|
9
|
+
def test_astype_array_a1(self) -> None:
|
|
10
|
+
a1 = np.array([10, 20, 30], dtype=np.int64)
|
|
11
|
+
a1.flags.writeable = False
|
|
12
|
+
|
|
13
|
+
a2 = astype_array(a1, np.int64)
|
|
14
|
+
self.assertEqual(id(a1), id(a2))
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def test_astype_array_a2(self) -> None:
|
|
18
|
+
a1 = np.array([10, 20, 30], dtype=np.int64)
|
|
19
|
+
a1.flags.writeable = False
|
|
20
|
+
|
|
21
|
+
a2 = astype_array(a1, np.float64)
|
|
22
|
+
self.assertNotEqual(id(a1), id(a2))
|
|
23
|
+
self.assertEqual(a2.dtype, np.dtype(np.float64))
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def test_astype_array_a3(self) -> None:
|
|
27
|
+
a1 = np.array([False, True, False])
|
|
28
|
+
|
|
29
|
+
a2 = astype_array(a1, np.int8)
|
|
30
|
+
self.assertEqual(a2.dtype, np.dtype(np.int8))
|
|
31
|
+
self.assertTrue(a2.flags.writeable)
|
|
32
|
+
|
|
33
|
+
def test_astype_array_b1(self) -> None:
|
|
34
|
+
a1 = np.array(['2021', '2024'], dtype=np.datetime64)
|
|
35
|
+
|
|
36
|
+
a2 = astype_array(a1, np.object_)
|
|
37
|
+
self.assertEqual(a2.dtype, np.dtype(np.object_))
|
|
38
|
+
self.assertTrue(a2.flags.writeable)
|
|
39
|
+
self.assertEqual(list(a2), [np.datetime64('2021'), np.datetime64('2024')])
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def test_astype_array_b2(self) -> None:
|
|
43
|
+
a1 = np.array(['2021', '1642'], dtype=np.datetime64)
|
|
44
|
+
|
|
45
|
+
a2 = astype_array(a1, np.object_)
|
|
46
|
+
self.assertEqual(a2.dtype, np.dtype(np.object_))
|
|
47
|
+
self.assertTrue(a2.flags.writeable)
|
|
48
|
+
self.assertEqual(list(a2), [np.datetime64('2021'), np.datetime64('1642')])
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def test_astype_array_b3(self) -> None:
|
|
52
|
+
a1 = np.array(['2021', '2024', '1984', '1642'], dtype=np.datetime64).reshape((2, 2))
|
|
53
|
+
|
|
54
|
+
a2 = astype_array(a1, np.object_)
|
|
55
|
+
self.assertEqual(a2.dtype, np.dtype(np.object_))
|
|
56
|
+
self.assertTrue(a2.flags.writeable)
|
|
57
|
+
self.assertEqual(
|
|
58
|
+
list(list(a) for a in a2),
|
|
59
|
+
[[np.datetime64('2021'), np.datetime64('2024')], [np.datetime64('1984'), np.datetime64('1642')]])
|
|
60
|
+
|
|
61
|
+
def test_astype_array_b4(self) -> None:
|
|
62
|
+
a1 = np.array(['2021', '2024', '1532', '1984', '1642', '899'], dtype=np.datetime64).reshape((2, 3))
|
|
63
|
+
|
|
64
|
+
a2 = astype_array(a1, np.object_)
|
|
65
|
+
self.assertEqual(a2.dtype, np.dtype(np.object_))
|
|
66
|
+
self.assertEqual(a2.shape, (2, 3))
|
|
67
|
+
self.assertTrue(a2.flags.writeable)
|
|
68
|
+
self.assertEqual(
|
|
69
|
+
list(list(a) for a in a2),
|
|
70
|
+
[[np.datetime64('2021'), np.datetime64('2024'), np.datetime64('1532')],
|
|
71
|
+
[np.datetime64('1984'), np.datetime64('1642'), np.datetime64('899')]])
|
|
72
|
+
|
|
73
|
+
def test_astype_array_c(self) -> None:
|
|
74
|
+
with self.assertRaises(TypeError):
|
|
75
|
+
_ = astype_array([3, 4, 5], np.int64)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def test_astype_array_d1(self) -> None:
|
|
79
|
+
a1 = np.array([10, 20, 30], dtype=np.int64)
|
|
80
|
+
a2 = astype_array(a1)
|
|
81
|
+
|
|
82
|
+
self.assertEqual(a2.dtype, np.dtype(np.float64))
|
|
83
|
+
self.assertEqual(a2.shape, (3,))
|
|
84
|
+
self.assertTrue(a2.flags.writeable)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def test_astype_array_d2(self) -> None:
|
|
88
|
+
a1 = np.array([10, 20, 30], dtype=np.int64)
|
|
89
|
+
a2 = astype_array(a1, None)
|
|
90
|
+
|
|
91
|
+
self.assertEqual(a2.dtype, np.dtype(np.float64))
|
|
92
|
+
self.assertEqual(a2.shape, (3,))
|
|
93
|
+
self.assertTrue(a2.flags.writeable)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def test_astype_array_d3(self) -> None:
|
|
98
|
+
a1 = np.array([10, 20, 30], dtype=np.int64)
|
|
99
|
+
a2 = astype_array(a1, np.int64)
|
|
100
|
+
|
|
101
|
+
self.assertEqual(a2.dtype, np.dtype(np.int64))
|
|
102
|
+
self.assertEqual(a2.shape, (3,))
|
|
103
|
+
self.assertTrue(a2.flags.writeable)
|
|
104
|
+
|
|
105
|
+
self.assertNotEqual(id(a1), id(a2))
|
|
106
|
+
|
|
107
|
+
def test_astype_array_e(self) -> None:
|
|
108
|
+
a1 = np.array(['2021', '2024', '1997', '1984', '2000', '1999'], dtype='datetime64[ns]').reshape((2, 3))
|
|
109
|
+
|
|
110
|
+
a2 = astype_array(a1, np.object_)
|
|
111
|
+
self.assertEqual(a2.dtype, np.dtype(np.object_))
|
|
112
|
+
self.assertEqual(a2.shape, (2, 3))
|
|
113
|
+
self.assertTrue(a2.flags.writeable)
|
|
114
|
+
self.assertEqual(
|
|
115
|
+
list(list(a) for a in a2),
|
|
116
|
+
[[np.datetime64('2021-01-01T00:00:00.000000000'),
|
|
117
|
+
np.datetime64('2024-01-01T00:00:00.000000000'),
|
|
118
|
+
np.datetime64('1997-01-01T00:00:00.000000000')],
|
|
119
|
+
[np.datetime64('1984-01-01T00:00:00.000000000'),
|
|
120
|
+
np.datetime64('2000-01-01T00:00:00.000000000'),
|
|
121
|
+
np.datetime64('1999-01-01T00:00:00.000000000')]]
|
|
122
|
+
)
|
|
123
|
+
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
from arraykit import is_objectable_dt64
|
|
6
|
+
from arraykit import is_objectable
|
|
7
|
+
|
|
8
|
+
class TestUnit(unittest.TestCase):
|
|
9
|
+
|
|
10
|
+
def test_is_objectable_a1(self) -> None:
|
|
11
|
+
a1 = np.array(['2022-01-04', '1954-04-12'], dtype=np.datetime64)
|
|
12
|
+
self.assertTrue(is_objectable(a1))
|
|
13
|
+
|
|
14
|
+
def test_is_objectable_a2(self) -> None:
|
|
15
|
+
a1 = np.array(['10000-01-04', '1954-04-12'], dtype=np.datetime64)
|
|
16
|
+
self.assertFalse(is_objectable(a1))
|
|
17
|
+
|
|
18
|
+
def test_is_objectable_b(self) -> None:
|
|
19
|
+
a1 = np.array([10, 20])
|
|
20
|
+
self.assertTrue(is_objectable(a1))
|
|
21
|
+
|
|
22
|
+
def test_is_objectable_c(self) -> None:
|
|
23
|
+
a1 = np.array([True, False])
|
|
24
|
+
self.assertTrue(is_objectable(a1))
|
|
25
|
+
|
|
26
|
+
def test_is_objectable_d(self) -> None:
|
|
27
|
+
a1 = np.array(['b', 'ccc'])
|
|
28
|
+
self.assertTrue(is_objectable(a1))
|
|
29
|
+
|
|
30
|
+
def test_is_objectable_e(self) -> None:
|
|
31
|
+
a1 = np.array(['b', None, False], dtype=object)
|
|
32
|
+
self.assertTrue(is_objectable(a1))
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
#---------------------------------------------------------------------------
|
|
36
|
+
|
|
37
|
+
def test_is_objectable_dt64_a1(self) -> None:
|
|
38
|
+
a1 = np.array(['2022-01-04', '1954-04-12'], dtype=np.datetime64)
|
|
39
|
+
self.assertTrue(is_objectable_dt64(a1))
|
|
40
|
+
|
|
41
|
+
def test_is_objectable_dt64_a2(self) -> None:
|
|
42
|
+
a1 = np.array(['2022-01-04', '', '1954-04-12'], dtype=np.datetime64)
|
|
43
|
+
self.assertTrue(is_objectable_dt64(a1))
|
|
44
|
+
|
|
45
|
+
def test_is_objectable_dt64_a3(self) -> None:
|
|
46
|
+
a1 = np.array(['2022-01-04', '1954-04-12', '', ''], dtype=np.datetime64)
|
|
47
|
+
self.assertTrue(is_objectable_dt64(a1))
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def test_is_objectable_dt64_b(self) -> None:
|
|
51
|
+
# years are nevery objectable
|
|
52
|
+
a1 = np.array(['2022', '2023'], dtype=np.datetime64)
|
|
53
|
+
self.assertFalse(is_objectable_dt64(a1))
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def test_is_objectable_dt64_c(self) -> None:
|
|
57
|
+
a1 = np.array(['-120-01-01', '2023-04-05'], dtype='datetime64[m]')
|
|
58
|
+
self.assertFalse(is_objectable_dt64(a1))
|
|
59
|
+
|
|
60
|
+
def test_is_objectable_dt64_d(self) -> None:
|
|
61
|
+
a1 = np.array(['2024-01-01', '2023-04-05', '10000-01-01'], dtype='datetime64[s]')
|
|
62
|
+
self.assertFalse(is_objectable_dt64(a1))
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def test_is_objectable_dt64_e(self) -> None:
|
|
66
|
+
a1 = np.array(['2024-01-01', '2023-04-05'], dtype='datetime64[ns]')
|
|
67
|
+
self.assertFalse(is_objectable_dt64(a1))
|
|
68
|
+
|
|
@@ -17,6 +17,7 @@ from arraykit import mloc
|
|
|
17
17
|
from arraykit import immutable_filter
|
|
18
18
|
from arraykit import array_deepcopy
|
|
19
19
|
from arraykit import isna_element
|
|
20
|
+
from arraykit import is_objectable_dt64
|
|
20
21
|
from arraykit import dtype_from_element
|
|
21
22
|
from arraykit import count_iteration
|
|
22
23
|
from arraykit import first_true_1d
|
|
@@ -953,7 +954,5 @@ class TestUnit(unittest.TestCase):
|
|
|
953
954
|
)
|
|
954
955
|
|
|
955
956
|
|
|
956
|
-
|
|
957
|
-
|
|
958
957
|
if __name__ == '__main__':
|
|
959
958
|
unittest.main()
|
arraykit-1.0.9/setup.py
DELETED
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
import site
|
|
2
|
-
import os
|
|
3
|
-
from os import path
|
|
4
|
-
import typing as tp
|
|
5
|
-
from setuptools import Extension # type: ignore
|
|
6
|
-
from setuptools import setup
|
|
7
|
-
|
|
8
|
-
AK_VERSION = '1.0.9'
|
|
9
|
-
|
|
10
|
-
ROOT_DIR_FP = path.abspath(path.dirname(__file__))
|
|
11
|
-
|
|
12
|
-
def get_long_description() -> str:
|
|
13
|
-
with open(path.join(ROOT_DIR_FP, 'README.rst'), encoding='utf-8') as f:
|
|
14
|
-
msg = []
|
|
15
|
-
collect = False
|
|
16
|
-
start = -1
|
|
17
|
-
for i, line in enumerate(f):
|
|
18
|
-
if line.startswith('arraykit'):
|
|
19
|
-
start = i + 2 # skip this line and the next
|
|
20
|
-
if i == start:
|
|
21
|
-
collect = True
|
|
22
|
-
if collect:
|
|
23
|
-
msg.append(line)
|
|
24
|
-
return ''.join(msg).strip()
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
# NOTE: we do this to avoid importing numpy: https://stackoverflow.com/questions/54117786/add-numpy-get-include-argument-to-setuptools-without-preinstalled-numpy
|
|
28
|
-
# we used to import the following to get directories:
|
|
29
|
-
# from numpy.distutils.misc_util import get_info
|
|
30
|
-
# import numpy as np # type: ignore
|
|
31
|
-
# get_info('npymath')['library_dirs']
|
|
32
|
-
# get_info('npymath')['libraries']
|
|
33
|
-
|
|
34
|
-
def get_ext_dir(*components: tp.Iterable[str]) -> tp.Sequence[str]:
|
|
35
|
-
dirs = []
|
|
36
|
-
for sp in site.getsitepackages():
|
|
37
|
-
fp = os.path.join(sp, *components)
|
|
38
|
-
if os.path.exists(fp):
|
|
39
|
-
dirs.append(fp)
|
|
40
|
-
return dirs
|
|
41
|
-
|
|
42
|
-
ak_extension = Extension(
|
|
43
|
-
name='arraykit._arraykit', # build into module
|
|
44
|
-
sources=[
|
|
45
|
-
'src/_arraykit.c',
|
|
46
|
-
'src/array_go.c',
|
|
47
|
-
'src/array_to_tuple.c',
|
|
48
|
-
'src/block_index.c',
|
|
49
|
-
'src/delimited_to_arrays.c',
|
|
50
|
-
'src/methods.c',
|
|
51
|
-
'src/tri_map.c',
|
|
52
|
-
'src/auto_map.c',
|
|
53
|
-
],
|
|
54
|
-
include_dirs=get_ext_dir('numpy', '_core', 'include') + ['src'],
|
|
55
|
-
library_dirs=get_ext_dir('numpy', '_core', 'lib'),
|
|
56
|
-
define_macros=[("AK_VERSION", AK_VERSION)],
|
|
57
|
-
libraries=['npymath'], # not including mlib at this time
|
|
58
|
-
)
|
|
59
|
-
|
|
60
|
-
setup(
|
|
61
|
-
name='arraykit',
|
|
62
|
-
version=AK_VERSION,
|
|
63
|
-
description='Array utilities for StaticFrame',
|
|
64
|
-
long_description=get_long_description(),
|
|
65
|
-
long_description_content_type='text/x-rst', # use text/x-rst
|
|
66
|
-
python_requires='>=3.10',
|
|
67
|
-
install_requires=['numpy>=1.24.3'],
|
|
68
|
-
url='https://github.com/static-frame/arraykit',
|
|
69
|
-
author='Christopher Ariza, Brandt Bucher, Charles Burkland',
|
|
70
|
-
license='MIT',
|
|
71
|
-
# See https://pypi.python.org/pypi?%3Aaction=list_classifiers
|
|
72
|
-
classifiers=[
|
|
73
|
-
'Development Status :: 5 - Production/Stable',
|
|
74
|
-
'Intended Audience :: Developers',
|
|
75
|
-
'Topic :: Software Development',
|
|
76
|
-
"Programming Language :: C",
|
|
77
|
-
"Programming Language :: Python :: Implementation :: CPython",
|
|
78
|
-
'License :: OSI Approved :: MIT License',
|
|
79
|
-
'Operating System :: MacOS :: MacOS X',
|
|
80
|
-
'Operating System :: Microsoft :: Windows',
|
|
81
|
-
'Operating System :: POSIX',
|
|
82
|
-
'Programming Language :: Python :: 3.10',
|
|
83
|
-
'Programming Language :: Python :: 3.11',
|
|
84
|
-
'Programming Language :: Python :: 3.12',
|
|
85
|
-
'Programming Language :: Python :: 3.13',
|
|
86
|
-
'Typing :: Typed',
|
|
87
|
-
],
|
|
88
|
-
keywords='numpy array',
|
|
89
|
-
packages=['arraykit'],
|
|
90
|
-
package_dir={'arraykit': 'src'},
|
|
91
|
-
package_data={'arraykit': ['__init__.pyi', 'py.typed']},
|
|
92
|
-
include_package_data=True,
|
|
93
|
-
ext_modules=[ak_extension],
|
|
94
|
-
)
|
|
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
|
|
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
|