@@ -59,6 +59,63 @@ def new(cls, *args, **kwargs):
5959 return new_cls
6060
6161
62+ @_inflate_to_namedtuple
63+ class IPRiskReason :
64+ """Reason for the IP risk.
65+
66+ This class provides both a machine-readable code and a human-readable
67+ explanation of the reason for the IP risk score.
68+
69+ Although more codes may be added in the future, the current codes are:
70+
71+ - ``ANONYMOUS_IP`` - The IP address belongs to an anonymous network. See
72+ the object at ``->ipAddress->traits`` for more details.
73+ - ``BILLING_POSTAL_VELOCITY`` - Many different billing postal codes have
74+ been seen on this IP address.
75+ - ``EMAIL_VELOCITY`` - Many different email addresses have been seen on this
76+ IP address.
77+ - ``HIGH_RISK_DEVICE`` - A high risk device was seen on this IP address.
78+ - ``HIGH_RISK_EMAIL`` - A high risk email address was seen on this IP
79+ address in your past transactions.
80+ - ``ISSUER_ID_NUMBER_VELOCITY`` - Many different issuer ID numbers have been
81+ seen on this IP address.
82+ - ``MINFRAUD_NETWORK_ACTIVITY`` - Suspicious activity has been seen on this
83+ IP address across minFraud customers.
84+
85+ .. attribute:: code
86+
87+ This value is a machine-readable code identifying the
88+ reason.
89+
90+ :type: str | None
91+
92+ .. attribute:: reason
93+
94+ This property provides a human-readable explanation of the
95+ reason. The text may change at any time and should not be matched
96+ against.
97+
98+ :type: str | None
99+ """
100+
101+ code : Optional [str ]
102+ reason : Optional [str ]
103+
104+ __slots__ = ()
105+ _fields = {
106+ "code" : None ,
107+ "reason" : None ,
108+ }
109+
110+
111+ def _create_ip_risk_reasons (
112+ reasons : Optional [List [Dict [str , str ]]]
113+ ) -> Tuple [IPRiskReason , ...]:
114+ if not reasons :
115+ return ()
116+ return tuple ([IPRiskReason (x ) for x in reasons ]) # type: ignore
117+
118+
62119class GeoIP2Location (geoip2 .records .Location ):
63120 """Location information for the IP address.
64121
@@ -126,6 +183,14 @@ class IPAddress(geoip2.models.Insights):
126183
127184 :type: float | None
128185
186+ .. attribute:: risk_reasons
187+
188+ This tuple contains :class:`.IPRiskReason` objects identifying the
189+ reasons why the IP address received the associated risk. This will be
190+ an empty tuple if there are no reasons.
191+
192+ :type: tuple[IPRiskReason]
193+
129194 .. attribute:: city
130195
131196 City object for the requested IP address.
@@ -189,6 +254,7 @@ class IPAddress(geoip2.models.Insights):
189254 country : GeoIP2Country
190255 location : GeoIP2Location
191256 risk : Optional [float ]
257+ risk_reasons : Tuple [IPRiskReason , ...]
192258
193259 def __init__ (self , ip_address : Dict [str , Any ]) -> None :
194260 if ip_address is None :
@@ -200,6 +266,7 @@ def __init__(self, ip_address: Dict[str, Any]) -> None:
200266 self .country = GeoIP2Country (locales , ** ip_address .get ("country" , {}))
201267 self .location = GeoIP2Location (** ip_address .get ("location" , {}))
202268 self .risk = ip_address .get ("risk" , None )
269+ self .risk_reasons = _create_ip_risk_reasons (ip_address .get ("risk_reasons" ))
203270 self ._finalized = True
204271
205272 # Unfortunately the GeoIP2 models are not immutable, only the records. This
@@ -1058,7 +1125,7 @@ class Factors:
10581125 risk_score : float
10591126 shipping_address : ShippingAddress
10601127 subscores : Subscores
1061- warnings : List [ServiceWarning ]
1128+ warnings : Tuple [ServiceWarning , ... ]
10621129
10631130 __slots__ = ()
10641131 _fields = {
@@ -1182,7 +1249,7 @@ class Insights:
11821249 queries_remaining : int
11831250 risk_score : float
11841251 shipping_address : ShippingAddress
1185- warnings : List [ServiceWarning ]
1252+ warnings : Tuple [ServiceWarning , ... ]
11861253
11871254 __slots__ = ()
11881255 _fields = {
@@ -1266,7 +1333,7 @@ class Score:
12661333 ip_address : ScoreIPAddress
12671334 queries_remaining : int
12681335 risk_score : float
1269- warnings : List [ServiceWarning ]
1336+ warnings : Tuple [ServiceWarning , ... ]
12701337
12711338 __slots__ = ()
12721339 _fields = {
0 commit comments