Coverage for functions \ flipdare \ payments \ dto \ safe_stripe_object.py: 82%

40 statements  

« prev     ^ index     » next       coverage.py v7.13.0, created at 2026-05-08 12:22 +1000

1# Copyright (c) 2026 Flipdare Pty Ltd. All rights reserved. 

2# 

3# This file is part of Flipdare's proprietary software and contains 

4# confidential and copyrighted material. Unauthorised copying, 

5# modification, distribution, or use of this file is strictly 

6# prohibited without prior written permission from Flipdare Pty Ltd. 

7# 

8# This software includes third-party components licensed under MIT, 

9# BSD, and Apache 2.0 licences. See THIRD_PARTY_NOTICES for details. 

10# 

11 

12from __future__ import annotations 

13from typing import Any, override 

14from collections.abc import Iterator 

15 

16 

17class SafeStripeObject: 

18 # 1. Explicitly declare the internal attribute type for Pylance 

19 _obj: Any 

20 

21 def __init__(self, obj: Any) -> None: 

22 # 2. Direct assignment is fine now that we declared it 

23 self.__dict__["_obj"] = obj 

24 

25 def __getattr__(self, name: str) -> SafeStripeObject: 

26 # Pylance now knows _obj can be None 

27 if self._obj is None: 

28 return SafeStripeObject(None) 

29 

30 try: 

31 val = getattr(self._obj, name) 

32 return SafeStripeObject(val) 

33 except (AttributeError, KeyError, TypeError): 

34 return SafeStripeObject(None) 

35 

36 def unwrap(self) -> Any: 

37 return self._obj 

38 

39 def __bool__(self) -> bool: 

40 return bool(self._obj) 

41 

42 def __len__(self) -> int: 

43 # If the wrapped object is a list or dict, return its length. 

44 # Otherwise (including None), return 0. 

45 if isinstance(self._obj, (list, dict)): 

46 return len(self._obj) 

47 return 0 

48 

49 def __iter__(self) -> Iterator[SafeStripeObject]: 

50 if isinstance(self._obj, list): 

51 for item in self._obj: 

52 yield SafeStripeObject(item) 

53 # mypy doesn't understand that this is a valid return type for __iter__ 

54 return 

55 

56 @override 

57 def __eq__(self, other: object) -> bool: 

58 # Explicitly cast to bool to satisfy the type checker 

59 return bool(self._obj == other) 

60 

61 @override 

62 def __hash__(self) -> int: 

63 return hash(self._obj) 

64 

65 @override 

66 def __str__(self) -> str: 

67 return str(self._obj) if self._obj is not None else "None" 

68 

69 @override 

70 def __repr__(self) -> str: 

71 return f"SafeStripeObject({self._obj!r})"