Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,5 @@
# Welcome to dumbpy

| | |
|------------------------------------|------------------------------------|
| Package | [![Latest PyPI Version](https://img.shields.io/pypi/v/dumbpy.svg)](https://pypi.org/project/dumbpy/) [![Supported Python Versions](https://img.shields.io/pypi/pyversions/dumbpy.svg)](https://pypi.org/project/dumbpy/) |
| Meta | [![Code of Conduct](https://img.shields.io/badge/Contributor%20Covenant-v2.0%20adopted-ff69b4.svg)](CODE_OF_CONDUCT.md) |

*TODO: the above badges that indicate python version and package version will only work if your package is on PyPI. If you don't plan to publish to PyPI, you can remove them.*

DumbPy is an alternative version of NumPy, which facilitates scientific computing using Python. DumbPy contains numeric functions that provide useful summary statistics of numerical lists, listed below. DumbPy additionally carries out strict input testing to provide clear and user-friendly error messages and facilitate proper usage.

DumbPy Functions:
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ requires = ["hatchling"]
[project]
name = "dumbpy"
# You can chose to use dynamic versioning with hatch or static where you add it manually.
version = "0.1.0"
version = "0.0.9"

description = "A dumber version of numpy"
authors = [
Expand Down
13 changes: 13 additions & 0 deletions tests/unit/test_arithmetic_mean.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
- Accepts general iterables (e.g., tuples, generators)
- Raises ValueError on empty input
- Raises TypeError when non-numeric values appear after flattening
- Raises TypeError on top-level string/bytes inputs (propagated from flatten_list)
"""


from typing import Any, Iterable

import pytest
Expand Down Expand Up @@ -156,3 +158,14 @@ def test_arithmetic_mean_non_numeric_raises_typeerror(values: Any) -> None:
"""
with pytest.raises(TypeError, match="not a numeric value"):
arithmetic_mean(values)

def test_arithmetic_mean_top_level_string_raises_typeerror() -> None:
"""
Test that arithmetic_mean raises TypeError on top-level string input.

Returns
-------
None
"""
with pytest.raises(TypeError, match="non-string, non-bytes iterable"):
arithmetic_mean("1234")
20 changes: 20 additions & 0 deletions tests/unit/test_median.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@
- Odd number of data points
- Even number of data points
- Even-length branch where the middle two values are equal
- Works on bool-only inputs (bool treated as numeric)
- Nested numeric iterables are flattened via validate_list
- Empty input raises ValueError
- Non-numeric input raises TypeError
"""


from typing import Any

import pytest
Expand Down Expand Up @@ -102,3 +104,21 @@ def test_median_non_numeric_raises_typeerror(values: Any) -> None:
"""
with pytest.raises(TypeError, match="not a numeric value"):
median(values)

def test_median_all_bools_odd_length() -> None:
"""
Test median on an odd-length bool-only list.

Notes
-----
``bool`` is a subclass of ``int`` in Python, so sorting and comparisons are
numeric in nature (False == 0, True == 1).

Returns
-------
None
"""
values: list[bool] = [True, False, False]
expected: bool = False

assert median(values) == expected
15 changes: 15 additions & 0 deletions tests/unit/test_std_deviation.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@
- Works on a single-element list
- Works with negative values
- Nested numeric iterables are flattened via validate_list
- Accepts general iterables (e.g., tuples)
- Empty input raises ValueError
- Non-numeric input raises TypeError
"""


from typing import Any

import pytest
Expand Down Expand Up @@ -121,3 +123,16 @@ def test_std_deviation_non_numeric_raises_typeerror() -> None:
"""
with pytest.raises(TypeError, match="not a numeric value"):
std_deviation([1, "a", 3])

def test_std_deviation_accepts_tuple_input() -> None:
"""
Test that std_deviation accepts a tuple as input.

Returns
-------
None
"""
values: tuple[int, int, int, int] = (1, 2, 3, 4)
expected: float = 1.118033988749895

assert std_deviation(values) == pytest.approx(expected)
42 changes: 42 additions & 0 deletions tests/unit/test_support_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@
- Recursively flattens nested iterables
- Treats str/bytes as atomic leaf values when nested
- Raises TypeError for non-iterables and for string/bytes at top-level
- Flattens dictionaries by iterating over their keys (standard Python behavior)

validate_list:
- Flattens input via flatten_list
- Ensures every flattened element is int, float, or bool
- Returns the flattened list if valid
- Raises TypeError if any flattened element is non-numeric
- Propagates flatten_list TypeError for invalid top-level input
- Accepts dictionaries if their flattened keys are numeric (dict values are not iterated)
"""

from collections import Counter
Expand Down Expand Up @@ -136,6 +138,26 @@ def test_flatten_list_raises_typeerror_for_invalid_top_level_inputs(bad_input: A
with pytest.raises(TypeError, match="non-string, non-bytes iterable"):
flatten_list(bad_input)

def test_flatten_list_dict_is_flattened_by_iterating_over_keys_order_irrelevant() -> None:
"""
Test flatten_list flattens dictionaries by iterating over their keys.

Notes
-----
Dict iteration yields keys. Ordering is not asserted; only membership and
multiplicity are checked.

Returns
-------
None
"""
values: list[Any] = [{"a": 1, "b": 2}, ["c"]]
expected_elements: list[str] = ["a", "b", "c"]

actual: list[Any] = flatten_list(values)

assert isinstance(actual, list)
assert Counter(actual) == Counter(expected_elements)

def test_validate_list_all_int_list_returns_flat_list() -> None:
"""
Expand Down Expand Up @@ -283,3 +305,23 @@ def test_validate_list_propagates_flatten_list_typeerror_on_invalid_input(bad_in
"""
with pytest.raises(TypeError, match="non-string, non-bytes iterable"):
validate_list(bad_input)

def test_validate_list_dict_with_numeric_keys_returns_flat_key_list() -> None:
"""
Test validate_list accepts a dictionary with numeric keys.

Notes
-----
Dictionaries are iterated by keys, so values are not validated.

Returns
-------
None
"""
values: dict[int, str] = {1: "x", 2: "y", 3: "z"}
expected_elements: list[int] = [1, 2, 3]

actual = validate_list(values)

assert isinstance(actual, list)
assert Counter(actual) == Counter(expected_elements)