smartarr 0.1.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.
smartarr-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 OpenAI
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,149 @@
1
+ Metadata-Version: 2.4
2
+ Name: smartarr
3
+ Version: 0.1.0
4
+ Summary: Expressive array utilities with an optional C backend.
5
+ Author: OpenAI Codex
6
+ License-Expression: MIT
7
+ Keywords: array,utilities,c-extension,numpy
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3 :: Only
12
+ Classifier: Programming Language :: Python :: 3.9
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: C
17
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
18
+ Classifier: Topic :: Utilities
19
+ Requires-Python: >=3.9
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Provides-Extra: numpy
23
+ Requires-Dist: numpy>=1.24; extra == "numpy"
24
+ Dynamic: license-file
25
+
26
+ # smartarr
27
+
28
+ `smartarr` is an expressive array utility layer for Python with a clean `smart(arr)` API and an optional C backend for fast core operations.
29
+
30
+ ## Why it exists
31
+
32
+ The goal is simple:
33
+
34
+ - one readable interface for lists, tuples, and NumPy arrays
35
+ - fast common operations when the C extension is available
36
+ - chainable transformations that still feel like Python
37
+
38
+ ```python
39
+ from smartarr import smart
40
+
41
+ value = smart([1, 2, 3, 4, 5]).rotate(2).reverse().middle()
42
+ print(value) # 1
43
+ ```
44
+
45
+ ## Install
46
+
47
+ Local install from this project:
48
+
49
+ ```bash
50
+ python -m pip install .
51
+ ```
52
+
53
+ Editable install for development:
54
+
55
+ ```bash
56
+ python -m pip install -e .
57
+ ```
58
+
59
+ Optional NumPy support:
60
+
61
+ ```bash
62
+ python -m pip install ".[numpy]"
63
+ ```
64
+
65
+ If a compiler is available, `smartarr` builds its C extension automatically. If not, installation still succeeds and falls back to the pure Python backend.
66
+
67
+ ## Quick start
68
+
69
+ ```python
70
+ from smartarr import smart
71
+
72
+ arr = smart([1, 2, 3, 4])
73
+
74
+ print(arr.first()) # 1
75
+ print(arr.last()) # 4
76
+ print(arr.middle()) # 3
77
+ print(arr.middle(mode="left")) # 2
78
+ print(arr.middle(mode="avg")) # 2.5
79
+ print(arr.rotate(1).to_list()) # [4, 1, 2, 3]
80
+ print(arr.reverse().to_list()) # [4, 3, 2, 1]
81
+ print(arr.chunk(2).to_list()) # [[1, 2], [3, 4]]
82
+ print(arr.window(2).to_list()) # [[1, 2], [2, 3], [3, 4]]
83
+ ```
84
+
85
+ ## Design notes
86
+
87
+ - `middle()` defaults to the right-middle element for even-length arrays, matching `arr[len(arr) // 2]`.
88
+ - Structural methods return a new `SmartArray`, so chaining works naturally.
89
+ - Terminal methods return a final value, such as an element, a number, or a dictionary.
90
+ - Flat transformations preserve the original adapter where practical. Shape-changing operations return list-shaped data by default.
91
+
92
+ ## Supported input types
93
+
94
+ - `list`
95
+ - `tuple`
96
+ - NumPy `ndarray` when NumPy is installed
97
+ - general iterables such as `range`
98
+
99
+ ## Current feature coverage
100
+
101
+ ### V1
102
+
103
+ - `first`
104
+ - `last`
105
+ - `middle`
106
+ - `rotate`
107
+ - `reverse`
108
+ - `len`
109
+ - `is_empty`
110
+
111
+ ### V2
112
+
113
+ - `chunk`
114
+ - `window`
115
+ - `random`
116
+ - `find`
117
+ - `count`
118
+ - `contains`
119
+ - `is_sorted`
120
+ - `sorted`
121
+
122
+ ### V3
123
+
124
+ - `map`
125
+ - `filter`
126
+ - `reduce`
127
+ - `sum`
128
+ - `mean`
129
+ - `median`
130
+ - `min`
131
+ - `max`
132
+ - `peaks`
133
+ - `unique`
134
+ - `duplicates`
135
+ - `frequency`
136
+ - `flatten`
137
+ - `reshape`
138
+
139
+ ## Development
140
+
141
+ Run tests:
142
+
143
+ ```bash
144
+ python -m unittest discover -s tests -v
145
+ ```
146
+
147
+ ## License
148
+
149
+ MIT
@@ -0,0 +1,124 @@
1
+ # smartarr
2
+
3
+ `smartarr` is an expressive array utility layer for Python with a clean `smart(arr)` API and an optional C backend for fast core operations.
4
+
5
+ ## Why it exists
6
+
7
+ The goal is simple:
8
+
9
+ - one readable interface for lists, tuples, and NumPy arrays
10
+ - fast common operations when the C extension is available
11
+ - chainable transformations that still feel like Python
12
+
13
+ ```python
14
+ from smartarr import smart
15
+
16
+ value = smart([1, 2, 3, 4, 5]).rotate(2).reverse().middle()
17
+ print(value) # 1
18
+ ```
19
+
20
+ ## Install
21
+
22
+ Local install from this project:
23
+
24
+ ```bash
25
+ python -m pip install .
26
+ ```
27
+
28
+ Editable install for development:
29
+
30
+ ```bash
31
+ python -m pip install -e .
32
+ ```
33
+
34
+ Optional NumPy support:
35
+
36
+ ```bash
37
+ python -m pip install ".[numpy]"
38
+ ```
39
+
40
+ If a compiler is available, `smartarr` builds its C extension automatically. If not, installation still succeeds and falls back to the pure Python backend.
41
+
42
+ ## Quick start
43
+
44
+ ```python
45
+ from smartarr import smart
46
+
47
+ arr = smart([1, 2, 3, 4])
48
+
49
+ print(arr.first()) # 1
50
+ print(arr.last()) # 4
51
+ print(arr.middle()) # 3
52
+ print(arr.middle(mode="left")) # 2
53
+ print(arr.middle(mode="avg")) # 2.5
54
+ print(arr.rotate(1).to_list()) # [4, 1, 2, 3]
55
+ print(arr.reverse().to_list()) # [4, 3, 2, 1]
56
+ print(arr.chunk(2).to_list()) # [[1, 2], [3, 4]]
57
+ print(arr.window(2).to_list()) # [[1, 2], [2, 3], [3, 4]]
58
+ ```
59
+
60
+ ## Design notes
61
+
62
+ - `middle()` defaults to the right-middle element for even-length arrays, matching `arr[len(arr) // 2]`.
63
+ - Structural methods return a new `SmartArray`, so chaining works naturally.
64
+ - Terminal methods return a final value, such as an element, a number, or a dictionary.
65
+ - Flat transformations preserve the original adapter where practical. Shape-changing operations return list-shaped data by default.
66
+
67
+ ## Supported input types
68
+
69
+ - `list`
70
+ - `tuple`
71
+ - NumPy `ndarray` when NumPy is installed
72
+ - general iterables such as `range`
73
+
74
+ ## Current feature coverage
75
+
76
+ ### V1
77
+
78
+ - `first`
79
+ - `last`
80
+ - `middle`
81
+ - `rotate`
82
+ - `reverse`
83
+ - `len`
84
+ - `is_empty`
85
+
86
+ ### V2
87
+
88
+ - `chunk`
89
+ - `window`
90
+ - `random`
91
+ - `find`
92
+ - `count`
93
+ - `contains`
94
+ - `is_sorted`
95
+ - `sorted`
96
+
97
+ ### V3
98
+
99
+ - `map`
100
+ - `filter`
101
+ - `reduce`
102
+ - `sum`
103
+ - `mean`
104
+ - `median`
105
+ - `min`
106
+ - `max`
107
+ - `peaks`
108
+ - `unique`
109
+ - `duplicates`
110
+ - `frequency`
111
+ - `flatten`
112
+ - `reshape`
113
+
114
+ ## Development
115
+
116
+ Run tests:
117
+
118
+ ```bash
119
+ python -m unittest discover -s tests -v
120
+ ```
121
+
122
+ ## License
123
+
124
+ MIT
@@ -0,0 +1,37 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "smartarr"
7
+ version = "0.1.0"
8
+ description = "Expressive array utilities with an optional C backend."
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ license = "MIT"
12
+ authors = [
13
+ { name = "OpenAI Codex" }
14
+ ]
15
+ keywords = ["array", "utilities", "c-extension", "numpy"]
16
+ classifiers = [
17
+ "Development Status :: 3 - Alpha",
18
+ "Intended Audience :: Developers",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3 :: Only",
21
+ "Programming Language :: Python :: 3.9",
22
+ "Programming Language :: Python :: 3.10",
23
+ "Programming Language :: Python :: 3.11",
24
+ "Programming Language :: Python :: 3.12",
25
+ "Programming Language :: C",
26
+ "Topic :: Software Development :: Libraries :: Python Modules",
27
+ "Topic :: Utilities"
28
+ ]
29
+
30
+ [project.optional-dependencies]
31
+ numpy = ["numpy>=1.24"]
32
+
33
+ [tool.setuptools]
34
+ package-dir = {"" = "src"}
35
+
36
+ [tool.setuptools.packages.find]
37
+ where = ["src"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,40 @@
1
+ from __future__ import annotations
2
+
3
+ from distutils.errors import CCompilerError, DistutilsExecError, DistutilsPlatformError
4
+
5
+ from setuptools import Extension, setup
6
+ from setuptools.command.build_ext import build_ext
7
+
8
+
9
+ class OptionalBuildExt(build_ext):
10
+ """Allow installation to continue when the optional C build is unavailable."""
11
+
12
+ def run(self) -> None:
13
+ try:
14
+ super().run()
15
+ except (DistutilsPlatformError, DistutilsExecError, CCompilerError, OSError, ValueError) as exc:
16
+ self._announce_skip(exc)
17
+
18
+ def build_extension(self, ext: Extension) -> None:
19
+ try:
20
+ super().build_extension(ext)
21
+ except (DistutilsPlatformError, DistutilsExecError, CCompilerError, OSError, ValueError) as exc:
22
+ self._announce_skip(exc)
23
+
24
+ def _announce_skip(self, exc: BaseException) -> None:
25
+ self.warn(
26
+ f"Skipping optional C extension for smartarr. "
27
+ f"The pure Python backend will be used instead. Reason: {exc}"
28
+ )
29
+
30
+
31
+ setup(
32
+ ext_modules=[
33
+ Extension(
34
+ "smartarr._smartarr",
35
+ sources=["src/smartarr/_smartarr.c"],
36
+ optional=True,
37
+ )
38
+ ],
39
+ cmdclass={"build_ext": OptionalBuildExt},
40
+ )
@@ -0,0 +1,4 @@
1
+ from .api import SmartArray, smart
2
+
3
+ __all__ = ["SmartArray", "smart"]
4
+ __version__ = "0.1.0"
@@ -0,0 +1,25 @@
1
+ from __future__ import annotations
2
+
3
+ from . import _pybackend
4
+
5
+ try: # pragma: no cover - depends on build environment
6
+ from . import _smartarr as _cbackend
7
+ except ImportError: # pragma: no cover - exercised when C build is unavailable
8
+ _cbackend = None
9
+
10
+
11
+ BACKEND_NAME = "c" if _cbackend is not None else "python"
12
+
13
+ length = _cbackend.length if _cbackend is not None else _pybackend.length
14
+ is_empty = _cbackend.is_empty if _cbackend is not None else _pybackend.is_empty
15
+ first = _cbackend.first if _cbackend is not None else _pybackend.first
16
+ last = _cbackend.last if _cbackend is not None else _pybackend.last
17
+ middle = _cbackend.middle if _cbackend is not None else _pybackend.middle
18
+ rotate = _cbackend.rotate if _cbackend is not None else _pybackend.rotate
19
+ reverse = _cbackend.reverse if _cbackend is not None else _pybackend.reverse
20
+ find = _cbackend.find if _cbackend is not None else _pybackend.find
21
+ count = _cbackend.count if _cbackend is not None else _pybackend.count
22
+ contains = _cbackend.contains if _cbackend is not None else _pybackend.contains
23
+ chunk = _cbackend.chunk if _cbackend is not None else _pybackend.chunk
24
+ window = _cbackend.window if _cbackend is not None else _pybackend.window
25
+ is_sorted = _cbackend.is_sorted if _cbackend is not None else _pybackend.is_sorted
@@ -0,0 +1,106 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+
6
+ def length(values: list[Any]) -> int:
7
+ return len(values)
8
+
9
+
10
+ def is_empty(values: list[Any]) -> bool:
11
+ return len(values) == 0
12
+
13
+
14
+ def first(values: list[Any]) -> Any:
15
+ if not values:
16
+ raise ValueError("smartarr.first() cannot operate on an empty sequence")
17
+ return values[0]
18
+
19
+
20
+ def last(values: list[Any]) -> Any:
21
+ if not values:
22
+ raise ValueError("smartarr.last() cannot operate on an empty sequence")
23
+ return values[-1]
24
+
25
+
26
+ def middle(values: list[Any], mode: str = "right") -> Any:
27
+ if not values:
28
+ raise ValueError("smartarr.middle() cannot operate on an empty sequence")
29
+ if mode not in {"left", "right", "avg"}:
30
+ raise ValueError("middle mode must be one of: right, left, avg")
31
+
32
+ size = len(values)
33
+ if size % 2 == 1:
34
+ return values[size // 2]
35
+
36
+ if mode == "left":
37
+ return values[(size // 2) - 1]
38
+ if mode == "right":
39
+ return values[size // 2]
40
+
41
+ return (values[(size // 2) - 1] + values[size // 2]) / 2
42
+
43
+
44
+ def rotate(values: list[Any], steps: int) -> list[Any]:
45
+ if not values:
46
+ return []
47
+ steps = steps % len(values)
48
+ if steps == 0:
49
+ return list(values)
50
+ return list(values[-steps:] + values[:-steps])
51
+
52
+
53
+ def reverse(values: list[Any]) -> list[Any]:
54
+ return list(reversed(values))
55
+
56
+
57
+ def find(values: list[Any], needle: Any) -> int:
58
+ for index, item in enumerate(values):
59
+ if item == needle:
60
+ return index
61
+ return -1
62
+
63
+
64
+ def count(values: list[Any], needle: Any) -> int:
65
+ total = 0
66
+ for item in values:
67
+ if item == needle:
68
+ total += 1
69
+ return total
70
+
71
+
72
+ def contains(values: list[Any], needle: Any) -> bool:
73
+ return find(values, needle) != -1
74
+
75
+
76
+ def chunk(values: list[Any], size: int, drop_last: bool = False) -> list[list[Any]]:
77
+ if size <= 0:
78
+ raise ValueError("chunk size must be greater than 0")
79
+
80
+ chunks = [values[index : index + size] for index in range(0, len(values), size)]
81
+ if drop_last and chunks and len(chunks[-1]) < size:
82
+ chunks.pop()
83
+ return chunks
84
+
85
+
86
+ def window(values: list[Any], size: int, step: int = 1) -> list[list[Any]]:
87
+ if size <= 0:
88
+ raise ValueError("window size must be greater than 0")
89
+ if step <= 0:
90
+ raise ValueError("window step must be greater than 0")
91
+ if size > len(values):
92
+ return []
93
+
94
+ return [
95
+ values[index : index + size]
96
+ for index in range(0, len(values) - size + 1, step)
97
+ ]
98
+
99
+
100
+ def is_sorted(values: list[Any], reverse: bool = False) -> bool:
101
+ if len(values) < 2:
102
+ return True
103
+
104
+ if reverse:
105
+ return all(values[index - 1] >= values[index] for index in range(1, len(values)))
106
+ return all(values[index - 1] <= values[index] for index in range(1, len(values)))