Coverage for src/dummypy/things.py: 100%

23 statements  

« prev     ^ index     » next       coverage.py v7.14.3, created at 2026-06-29 05:53 +0000

1"""Core data structures for the dummypy analytics library.""" 

2 

3import attrs 

4import numpy as np 

5import pandas as pd 

6 

7 

8def _check_n(_instance: object, _attribute: "attrs.Attribute[int]", value: object) -> None: 

9 """Reject non-integer or negative grid sizes with a clear error. 

10 

11 Args: 

12 _instance: The Grid instance being validated (unused). 

13 _attribute: The attrs attribute being validated (unused). 

14 value: The proposed value for ``n``. 

15 

16 Raises: 

17 TypeError: If ``value`` is not an integer (bool is rejected too). 

18 ValueError: If ``value`` is negative. 

19 """ 

20 # bool is a subclass of int; reject it to avoid Grid(n=True) surprises. 

21 if not isinstance(value, int) or isinstance(value, bool): 

22 msg = f"Grid size n must be an integer, got {type(value).__name__}" 

23 raise TypeError(msg) 

24 if value < 0: 

25 msg = f"Grid size n must be non-negative, got {value}" 

26 raise ValueError(msg) 

27 

28 

29@attrs.define 

30class Grid: 

31 """A grid representing data points for analytics calculations. 

32 

33 Creates two DataFrames (x and y) with goal-like structure for data analysis. 

34 

35 Args: 

36 n: Maximum size for the grid (default: 10). Must be a non-negative 

37 integer. 

38 

39 Raises: 

40 TypeError: If ``n`` is not an integer (e.g. a float or a bool). 

41 ValueError: If ``n`` is negative. 

42 """ 

43 

44 n: int = attrs.field(init=True, repr=True, default=10, validator=_check_n) 

45 x: pd.DataFrame = attrs.field(repr=False, init=False) 

46 y: pd.DataFrame = attrs.field(repr=False, init=False) 

47 

48 def __attrs_post_init__(self) -> None: 

49 """Initialize the x and y data matrices after object creation.""" 

50 nn = np.arange(self.n + 1) 

51 cols = [str(n) for n in nn] 

52 data = np.tile(nn, (self.n + 1, 1)) 

53 self.y = pd.DataFrame(data, index=pd.Index(cols), columns=pd.Index(cols)) 

54 self.x = self.y.T 

55 

56 def diff(self) -> pd.DataFrame: 

57 """Returns a grid of differences. 

58 

59 Returns: 

60 DataFrame of element-wise differences (x - y). 

61 """ 

62 return self.x - self.y