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
« 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#
12from __future__ import annotations
13from typing import Any, override
14from collections.abc import Iterator
17class SafeStripeObject:
18 # 1. Explicitly declare the internal attribute type for Pylance
19 _obj: Any
21 def __init__(self, obj: Any) -> None:
22 # 2. Direct assignment is fine now that we declared it
23 self.__dict__["_obj"] = obj
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)
30 try:
31 val = getattr(self._obj, name)
32 return SafeStripeObject(val)
33 except (AttributeError, KeyError, TypeError):
34 return SafeStripeObject(None)
36 def unwrap(self) -> Any:
37 return self._obj
39 def __bool__(self) -> bool:
40 return bool(self._obj)
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
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
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)
61 @override
62 def __hash__(self) -> int:
63 return hash(self._obj)
65 @override
66 def __str__(self) -> str:
67 return str(self._obj) if self._obj is not None else "None"
69 @override
70 def __repr__(self) -> str:
71 return f"SafeStripeObject({self._obj!r})"