Coverage for src/usaspending/models/spending.py: 100%

33 statements  

« prev     ^ index     » next       coverage.py v7.10.6, created at 2025-09-03 17:15 -0700

1"""Base spending model for USASpending spending by category data.""" 

2 

3from __future__ import annotations 

4 

5from typing import Optional, TYPE_CHECKING 

6from ..utils.formatter import to_float 

7from .base_model import BaseModel 

8 

9if TYPE_CHECKING: 

10 from ..client import USASpending 

11 

12 

13class Spending(BaseModel): 

14 """Base model for spending by category data. 

15 

16 Represents common fields across spending by recipient and district categories. 

17 This model provides access to spending data with amounts, names, codes, and outlays. 

18 """ 

19 

20 def __init__(self, data: dict, client: Optional["USASpending"] = None): 

21 """Initialize Spending model. 

22 

23 Args: 

24 data: Raw spending data from API 

25 client: USASpending client instance 

26 """ 

27 super().__init__(data) 

28 self._client = client 

29 

30 @property 

31 def id(self) -> Optional[int]: 

32 """Database ID for the spending record.""" 

33 return self.get_value(["id"]) 

34 

35 @property 

36 def name(self) -> Optional[str]: 

37 """Display name for the spending category (recipient name or district name).""" 

38 return self.get_value(["name"]) 

39 

40 @property 

41 def code(self) -> Optional[str]: 

42 """Code associated with the spending record (DUNS, district code, etc.).""" 

43 return self.get_value(["code"]) 

44 

45 @property 

46 def amount(self) -> Optional[float]: 

47 """Total spending amount for this record.""" 

48 return to_float(self.get_value(["amount"])) 

49 

50 @property 

51 def total_outlays(self) -> Optional[float]: 

52 """Total outlays for this spending record.""" 

53 return to_float(self.get_value(["total_outlays"])) 

54 

55 @property 

56 def spending_level(self) -> Optional[str]: 

57 """The spending level used for this data (transactions, awards, subawards).""" 

58 return self.get_value(["spending_level"]) 

59 

60 @property 

61 def category(self) -> Optional[str]: 

62 """The category type (recipient or district).""" 

63 return self.get_value(["category"]) 

64 

65 def __repr__(self) -> str: 

66 """String representation of Spending.""" 

67 name = self.name or "Unknown" 

68 amount = self.amount or 0 

69 return f"<Spending {name}: ${amount:,.2f}>"