Coverage for fingerprint_server_sdk/models/event.py: 73%
150 statements
« prev ^ index » next coverage.py v7.14.3, created at 2026-08-13 12:56 +0000
« prev ^ index » next coverage.py v7.14.3, created at 2026-08-13 12:56 +0000
1"""
2Server API
3Fingerprint Server API allows you to get, search, and update Events in a server environment. It can be used for data exports, decision-making, and data analysis scenarios.
4Server API is intended for server-side usage, it's not intended to be used from the client side, whether it's a browser or a mobile device.
5The API also supports collection of Automation Intelligence for requests to your server in edge, pre-origin, or middleware contexts.
7The version of the OpenAPI document: 4
8Contact: support@fingerprint.com
9Generated by OpenAPI Generator (https://openapi-generator.tech)
11Do not edit the class manually.
12""" # noqa: E501
14from __future__ import annotations
16import json
17import pprint
18import re # noqa: F401
19from typing import Annotated, Any, ClassVar, Optional, Union
21from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictInt, StrictStr
22from typing_extensions import Self
24from fingerprint_server_sdk.models.bot_info import BotInfo
25from fingerprint_server_sdk.models.bot_result import BotResult
26from fingerprint_server_sdk.models.browser_details import BrowserDetails
27from fingerprint_server_sdk.models.event_rule_action import EventRuleAction
28from fingerprint_server_sdk.models.event_source import EventSource
29from fingerprint_server_sdk.models.identification import Identification
30from fingerprint_server_sdk.models.incremental_identification_status import (
31 IncrementalIdentificationStatus,
32)
33from fingerprint_server_sdk.models.ip_block_list import IPBlockList
34from fingerprint_server_sdk.models.ip_info import IPInfo
35from fingerprint_server_sdk.models.labels_inner import LabelsInner
36from fingerprint_server_sdk.models.proximity import Proximity
37from fingerprint_server_sdk.models.proxy_confidence import ProxyConfidence
38from fingerprint_server_sdk.models.proxy_details import ProxyDetails
39from fingerprint_server_sdk.models.rare_device_percentile_bucket import RareDevicePercentileBucket
40from fingerprint_server_sdk.models.raw_device_attributes import RawDeviceAttributes
41from fingerprint_server_sdk.models.sdk import SDK
42from fingerprint_server_sdk.models.supplementary_id_high_recall import SupplementaryIDHighRecall
43from fingerprint_server_sdk.models.tampering_confidence import TamperingConfidence
44from fingerprint_server_sdk.models.tampering_details import TamperingDetails
45from fingerprint_server_sdk.models.velocity import Velocity
46from fingerprint_server_sdk.models.vpn_confidence import VpnConfidence
47from fingerprint_server_sdk.models.vpn_methods import VpnMethods
50class Event(BaseModel):
51 """
52 Contains results from Fingerprint Identification and all active Smart Signals. Some Smart Signals are only supported for certain device types, these fields will be omitted for events not generated from the supported devices. Consult the [Smart Signals reference](https://docs.fingerprint.com/docs/smart-signals-reference) for more details.
53 """
55 event_id: StrictStr = Field(
56 description="Unique identifier of the user's request. The first portion of the event_id is a unix epoch milliseconds timestamp. "
57 )
58 timestamp: StrictInt = Field(
59 description='Timestamp of the event with millisecond precision in Unix time.'
60 )
61 source: Optional[EventSource] = None
62 incremental_identification_status: Optional[IncrementalIdentificationStatus] = None
63 linked_id: Optional[StrictStr] = Field(
64 default=None, description='A customer-provided id that was sent with the request.'
65 )
66 environment_id: Optional[StrictStr] = Field(
67 default=None, description='Environment Id of the event.'
68 )
69 suspect: Optional[StrictBool] = Field(
70 default=None,
71 description='Field is `true` if you have previously set the `suspect` flag for this event using the [Server API Update event endpoint](https://docs.fingerprint.com/reference/server-api-v4-update-event).',
72 )
73 sdk: Optional[SDK] = None
74 replayed: Optional[StrictBool] = Field(
75 default=None,
76 description='`true` if we determined that this payload was replayed, `false` otherwise. ',
77 )
78 identification: Optional[Identification] = None
79 supplementary_id_high_recall: Optional[SupplementaryIDHighRecall] = None
80 tags: Optional[dict[str, Any]] = Field(
81 default=None,
82 description='A customer-provided value or an object that was sent with the identification request or updated later.',
83 )
84 url: Optional[StrictStr] = Field(
85 default=None, description='Page URL from which the request was sent.'
86 )
87 bundle_id: Optional[StrictStr] = Field(
88 default=None,
89 description='Bundle Id of the iOS application integrated with the Fingerprint SDK for the event. ',
90 )
91 package_name: Optional[StrictStr] = Field(
92 default=None,
93 description='Package name of the Android application integrated with the Fingerprint SDK for the event. ',
94 )
95 ip_address: Optional[StrictStr] = Field(
96 default=None, description='IP address of the requesting browser or bot.'
97 )
98 user_agent: Optional[StrictStr] = Field(default=None, description='User Agent of the client.')
99 device: Optional[StrictStr] = Field(
100 default=None,
101 description='Device model or family extracted from the user agent string. On web, this field is also present inside `browser_details`. ',
102 )
103 os: Optional[StrictStr] = Field(
104 default=None,
105 description='Operating system family extracted from the user agent string. On web, this field is also present inside `browser_details`. ',
106 )
107 os_version: Optional[StrictStr] = Field(
108 default=None,
109 description='Operating system version string extracted from the user agent string. On web, this field is also present inside `browser_details`. ',
110 )
111 client_referrer: Optional[StrictStr] = Field(
112 default=None,
113 description='Client Referrer field corresponds to the `document.referrer` field gathered during an identification request. The value is an empty string if the user navigated to the page directly (not through a link, but, for example, by using a bookmark). ',
114 )
115 browser_details: Optional[BrowserDetails] = None
116 proximity: Optional[Proximity] = None
117 active_call: Optional[StrictBool] = Field(
118 default=None,
119 description='Indicates whether the mobile device had an active call (cellular or VoIP) at the time of the request. Available from SDK 2.16.0+ on iOS and Android. ',
120 )
121 bot: Optional[BotResult] = None
122 bot_type: Optional[StrictStr] = Field(
123 default=None, description='Additional classification of the bot type if detected. '
124 )
125 bot_info: Optional[BotInfo] = None
126 cloned_app: Optional[StrictBool] = Field(
127 default=None,
128 description='Android specific cloned application detection. There are 2 values: * `true` - Presence of app cloners work detected (e.g. fully cloned application found or launch of it inside of a not main working profile detected). * `false` - No signs of cloned application detected or the client is not Android. ',
129 )
130 developer_tools: Optional[StrictBool] = Field(
131 default=None,
132 description='`true` if the browser has DevTools open (Chrome, Firefox) or the Android/iOS device has Developer Tools enabled, `false` otherwise. ',
133 )
134 emulator: Optional[StrictBool] = Field(
135 default=None,
136 description='Android specific emulator detection. There are 2 values: * `true` - Emulated environment detected (e.g. launch inside of AVD). * `false` - No signs of emulated environment detected or the client is not Android. ',
137 )
138 factory_reset_timestamp: Optional[StrictInt] = Field(
139 default=None,
140 description='The time of the most recent factory reset that happened on the **mobile device** is expressed as Unix epoch time. When a factory reset cannot be detected on the mobile device or when the request is initiated from a browser, this field will correspond to the *epoch* time (i.e 1 Jan 1970 UTC) as a value of 0. See [Factory Reset Detection](https://docs.fingerprint.com/docs/smart-signals-reference#factory-reset-detection) to learn more about this Smart Signal. ',
141 )
142 frida: Optional[StrictBool] = Field(
143 default=None,
144 description='[Frida](https://frida.re/docs/) detection for Android and iOS devices. There are 2 values: * `true` - Frida detected * `false` - No signs of Frida or the client is not a mobile device. ',
145 )
146 ip_blocklist: Optional[IPBlockList] = None
147 ip_info: Optional[IPInfo] = None
148 proxy: Optional[StrictBool] = Field(
149 default=None,
150 description='IP address was used by a public proxy provider or belonged to a known recent residential proxy ',
151 )
152 proxy_confidence: Optional[ProxyConfidence] = None
153 proxy_details: Optional[ProxyDetails] = None
154 proxy_ml_score: Optional[
155 Union[
156 Annotated[float, Field(le=1, strict=True, ge=0)],
157 Annotated[int, Field(le=1, strict=True, ge=0)],
158 ]
159 ] = Field(
160 default=None,
161 description='Machine learning–based proxy score, represented as a floating-point value between 0 and 1 (inclusive), with up to three decimal places of precision. A higher score means a higher confidence in the positive `proxy` detection result. This Smart Signal is currently in beta and only available to select customers. If you are interested, please [contact our support team](https://fingerprint.com/support/). ',
162 )
163 incognito: Optional[StrictBool] = Field(
164 default=None,
165 description='`true` if we detected incognito mode used in the browser, `false` otherwise. ',
166 )
167 jailbroken: Optional[StrictBool] = Field(
168 default=None,
169 description='iOS specific jailbreak detection. There are 2 values: * `true` - Jailbreak detected. * `false` - No signs of jailbreak or the client is not iOS. ',
170 )
171 location_spoofing: Optional[StrictBool] = Field(
172 default=None,
173 description='Flag indicating whether the request came from a mobile device with location spoofing enabled.',
174 )
175 mitm_attack: Optional[StrictBool] = Field(
176 default=None,
177 description="* `true` - When requests made from your users' mobile devices to Fingerprint servers have been intercepted and potentially modified. * `false` - Otherwise or when the request originated from a browser. See [MitM Attack Detection](https://docs.fingerprint.com/docs/smart-signals-reference#mitm-attack-detection) to learn more about this Smart Signal. ",
178 )
179 privacy_settings: Optional[StrictBool] = Field(
180 default=None,
181 description='`true` if the request is from a privacy aware browser (e.g. Tor) or from a browser in which fingerprinting is blocked. Otherwise `false`. ',
182 )
183 root_apps: Optional[StrictBool] = Field(
184 default=None,
185 description="Android specific root management apps detection. There are 2 values: * `true` - Root Management Apps detected (e.g. Magisk). * `false` - No Root Management Apps detected or the client isn't Android. ",
186 )
187 rule_action: Optional[EventRuleAction] = None
188 simulator: Optional[StrictBool] = Field(
189 default=None,
190 description='iOS specific simulator detection. There are 2 values: * `true` - Simulator environment detected. * `false` - No signs of simulator or the client is not iOS. ',
191 )
192 suspect_score: Optional[StrictInt] = Field(
193 default=None,
194 description='Suspect Score is an easy way to integrate Smart Signals into your fraud protection work flow. It is a weighted representation of all Smart Signals present in the payload that helps identify suspicious activity. The value range is [0; S] where S is sum of all Smart Signals weights. See more details here: https://docs.fingerprint.com/docs/suspect-score ',
195 )
196 tampering: Optional[StrictBool] = Field(
197 default=None,
198 description='The field can be used as a standalone flag for tampering detection. Alternatively, the more granular fields documented below can be used for workflows that require more context. * `true` if tampering is detected through an anomalous browser signature, anti-detect browser detection, or other tampering-related methods * `false` if none of the tampering checks return a positive result ',
199 )
200 tampering_confidence: Optional[TamperingConfidence] = None
201 tampering_ml_score: Optional[
202 Union[
203 Annotated[float, Field(le=1, strict=True, ge=0)],
204 Annotated[int, Field(le=1, strict=True, ge=0)],
205 ]
206 ] = Field(
207 default=None,
208 description='The output of this model is captured as tampering_ml_score, a number indicating how likely an event is coming from an anti detect browser. Values close to 1 signify higher confidence and we consider anything above the threshold of 0.8 to be actionable (the result and anti_detect_browser fields conveniently captures that fact) ',
209 )
210 tampering_details: Optional[TamperingDetails] = None
211 velocity: Optional[Velocity] = None
212 virtual_machine: Optional[StrictBool] = Field(
213 default=None,
214 description='`true` if the request came from a browser running inside a virtual machine (e.g. VMWare), `false` otherwise. ',
215 )
216 virtual_machine_ml_score: Optional[
217 Union[
218 Annotated[float, Field(le=1, strict=True, ge=0)],
219 Annotated[int, Field(le=1, strict=True, ge=0)],
220 ]
221 ] = Field(
222 default=None,
223 description='Machine learning–based virtual machine score, represented as a floating-point value between 0 and 1 (inclusive), with up to three decimal places of precision. A higher score means a higher confidence in the positive `virtual_machine` detection result. This Smart Signal is currently in beta and only available to select customers. If you are interested, please [contact our support team](https://fingerprint.com/support/). ',
224 )
225 vpn: Optional[StrictBool] = Field(
226 default=None,
227 description='VPN or other anonymizing service has been used when sending the request. ',
228 )
229 vpn_confidence: Optional[VpnConfidence] = None
230 vpn_ml_score: Optional[
231 Union[
232 Annotated[float, Field(le=1, strict=True, ge=0)],
233 Annotated[int, Field(le=1, strict=True, ge=0)],
234 ]
235 ] = Field(
236 default=None,
237 description='Machine learning–based VPN score, represented as a floating-point value between 0 and 1 (inclusive), with up to three decimal places of precision. A higher score means a higher confidence in the positive `vpn` detection result. This Smart Signal is currently in beta and only available to select customers. If you are interested, please [contact our support team](https://fingerprint.com/support/). ',
238 )
239 vpn_origin_timezone: Optional[StrictStr] = Field(
240 default=None, description='Local timezone which is used in timezone_mismatch method. '
241 )
242 vpn_origin_country: Optional[StrictStr] = Field(
243 default=None,
244 description='Country of the request (Android SDK version >= 2.4.0, iOS SDK version >= 2.9.0, JS agent >= 3.12.9 / 4.0.2), ISO 3166 format or unknown. ',
245 )
246 vpn_methods: Optional[VpnMethods] = None
247 high_activity_device: Optional[StrictBool] = Field(
248 default=None,
249 description='Flag indicating if the request came from a high-activity visitor.',
250 )
251 rare_device: Optional[StrictBool] = Field(
252 default=None,
253 description='`true` if the device is considered rare based on its combination of hardware and software attributes. A device is classified as rare if it falls within the top 99.9 percentile (lowest-frequency segment) of observed traffic, or if its configuration has not been previously seen (`not_seen`). > This Smart Signal is currently in beta and only available to select customers. If you are interested, please [contact our support team](https://fingerprint.com/support/). ',
254 )
255 rare_device_percentile_bucket: Optional[RareDevicePercentileBucket] = None
256 raw_device_attributes: Optional[RawDeviceAttributes] = None
257 labels: Optional[list[LabelsInner]] = Field(
258 default=None,
259 description='Each label returns a prediction (true or false) for a specific use case (label field) based on a machine learning score. The machine learning score is determined by a model trained on customer data for that use case. This field is in the beta phase and only available to select customers. If you are interested, please [contact our support team](https://fingerprint.com/support/). ',
260 )
261 __properties: ClassVar[list[str]] = [
262 'event_id',
263 'timestamp',
264 'source',
265 'incremental_identification_status',
266 'linked_id',
267 'environment_id',
268 'suspect',
269 'sdk',
270 'replayed',
271 'identification',
272 'supplementary_id_high_recall',
273 'tags',
274 'url',
275 'bundle_id',
276 'package_name',
277 'ip_address',
278 'user_agent',
279 'device',
280 'os',
281 'os_version',
282 'client_referrer',
283 'browser_details',
284 'proximity',
285 'active_call',
286 'bot',
287 'bot_type',
288 'bot_info',
289 'cloned_app',
290 'developer_tools',
291 'emulator',
292 'factory_reset_timestamp',
293 'frida',
294 'ip_blocklist',
295 'ip_info',
296 'proxy',
297 'proxy_confidence',
298 'proxy_details',
299 'proxy_ml_score',
300 'incognito',
301 'jailbroken',
302 'location_spoofing',
303 'mitm_attack',
304 'privacy_settings',
305 'root_apps',
306 'rule_action',
307 'simulator',
308 'suspect_score',
309 'tampering',
310 'tampering_confidence',
311 'tampering_ml_score',
312 'tampering_details',
313 'velocity',
314 'virtual_machine',
315 'virtual_machine_ml_score',
316 'vpn',
317 'vpn_confidence',
318 'vpn_ml_score',
319 'vpn_origin_timezone',
320 'vpn_origin_country',
321 'vpn_methods',
322 'high_activity_device',
323 'rare_device',
324 'rare_device_percentile_bucket',
325 'raw_device_attributes',
326 'labels',
327 ]
329 model_config = ConfigDict(
330 populate_by_name=True,
331 validate_assignment=True,
332 protected_namespaces=(),
333 )
335 def to_str(self) -> str:
336 """Returns the string representation of the model using alias"""
337 return pprint.pformat(self.model_dump(by_alias=True))
339 def to_json(self) -> str:
340 """Returns the JSON representation of the model using alias"""
341 # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead
342 return json.dumps(self.to_dict())
344 @classmethod
345 def from_json(cls, json_str: str) -> Optional[Self]:
346 """Create an instance of Event from a JSON string"""
347 return cls.from_dict(json.loads(json_str))
349 def to_dict(self) -> dict[str, Any]:
350 """Return the dictionary representation of the model using alias.
352 This has the following differences from calling pydantic's
353 `self.model_dump(by_alias=True)`:
355 * `None` is only added to the output dict for nullable fields that
356 were set at model initialization. Other fields with value `None`
357 are ignored.
358 """
359 excluded_fields: set[str] = set([])
361 _dict = self.model_dump(
362 by_alias=True,
363 exclude=excluded_fields,
364 exclude_none=True,
365 )
366 # override the default output from pydantic by calling `to_dict()` of sdk
367 if self.sdk:
368 _dict['sdk'] = self.sdk.to_dict()
369 # override the default output from pydantic by calling `to_dict()` of identification
370 if self.identification:
371 _dict['identification'] = self.identification.to_dict()
372 # override the default output from pydantic by calling `to_dict()` of supplementary_id_high_recall
373 if self.supplementary_id_high_recall:
374 _dict['supplementary_id_high_recall'] = self.supplementary_id_high_recall.to_dict()
375 # override the default output from pydantic by calling `to_dict()` of browser_details
376 if self.browser_details:
377 _dict['browser_details'] = self.browser_details.to_dict()
378 # override the default output from pydantic by calling `to_dict()` of proximity
379 if self.proximity:
380 _dict['proximity'] = self.proximity.to_dict()
381 # override the default output from pydantic by calling `to_dict()` of bot_info
382 if self.bot_info:
383 _dict['bot_info'] = self.bot_info.to_dict()
384 # override the default output from pydantic by calling `to_dict()` of ip_blocklist
385 if self.ip_blocklist:
386 _dict['ip_blocklist'] = self.ip_blocklist.to_dict()
387 # override the default output from pydantic by calling `to_dict()` of ip_info
388 if self.ip_info:
389 _dict['ip_info'] = self.ip_info.to_dict()
390 # override the default output from pydantic by calling `to_dict()` of proxy_details
391 if self.proxy_details:
392 _dict['proxy_details'] = self.proxy_details.to_dict()
393 # override the default output from pydantic by calling `to_dict()` of rule_action
394 if self.rule_action:
395 _dict['rule_action'] = self.rule_action.to_dict()
396 # override the default output from pydantic by calling `to_dict()` of tampering_details
397 if self.tampering_details:
398 _dict['tampering_details'] = self.tampering_details.to_dict()
399 # override the default output from pydantic by calling `to_dict()` of velocity
400 if self.velocity:
401 _dict['velocity'] = self.velocity.to_dict()
402 # override the default output from pydantic by calling `to_dict()` of vpn_methods
403 if self.vpn_methods:
404 _dict['vpn_methods'] = self.vpn_methods.to_dict()
405 # override the default output from pydantic by calling `to_dict()` of raw_device_attributes
406 if self.raw_device_attributes:
407 _dict['raw_device_attributes'] = self.raw_device_attributes.to_dict()
408 # override the default output from pydantic by calling `to_dict()` of each item in labels (list)
409 _items = []
410 if self.labels:
411 for _item_labels in self.labels:
412 if _item_labels:
413 _items.append(_item_labels.to_dict())
414 _dict['labels'] = _items
415 return _dict
417 @classmethod
418 def from_dict(cls, obj: Optional[dict[str, Any]]) -> Optional[Self]:
419 """Create an instance of Event from a dict"""
420 if obj is None:
421 return None
423 if not isinstance(obj, dict):
424 return cls.model_validate(obj)
426 _obj = cls.model_validate(
427 {
428 'event_id': obj.get('event_id'),
429 'timestamp': obj.get('timestamp'),
430 'source': obj.get('source'),
431 'incremental_identification_status': obj.get('incremental_identification_status'),
432 'linked_id': obj.get('linked_id'),
433 'environment_id': obj.get('environment_id'),
434 'suspect': obj.get('suspect'),
435 'sdk': SDK.from_dict(obj['sdk']) if obj.get('sdk') is not None else None,
436 'replayed': obj.get('replayed'),
437 'identification': Identification.from_dict(obj['identification'])
438 if obj.get('identification') is not None
439 else None,
440 'supplementary_id_high_recall': SupplementaryIDHighRecall.from_dict(
441 obj['supplementary_id_high_recall']
442 )
443 if obj.get('supplementary_id_high_recall') is not None
444 else None,
445 'tags': obj.get('tags'),
446 'url': obj.get('url'),
447 'bundle_id': obj.get('bundle_id'),
448 'package_name': obj.get('package_name'),
449 'ip_address': obj.get('ip_address'),
450 'user_agent': obj.get('user_agent'),
451 'device': obj.get('device'),
452 'os': obj.get('os'),
453 'os_version': obj.get('os_version'),
454 'client_referrer': obj.get('client_referrer'),
455 'browser_details': BrowserDetails.from_dict(obj['browser_details'])
456 if obj.get('browser_details') is not None
457 else None,
458 'proximity': Proximity.from_dict(obj['proximity'])
459 if obj.get('proximity') is not None
460 else None,
461 'active_call': obj.get('active_call'),
462 'bot': obj.get('bot'),
463 'bot_type': obj.get('bot_type'),
464 'bot_info': BotInfo.from_dict(obj['bot_info'])
465 if obj.get('bot_info') is not None
466 else None,
467 'cloned_app': obj.get('cloned_app'),
468 'developer_tools': obj.get('developer_tools'),
469 'emulator': obj.get('emulator'),
470 'factory_reset_timestamp': obj.get('factory_reset_timestamp'),
471 'frida': obj.get('frida'),
472 'ip_blocklist': IPBlockList.from_dict(obj['ip_blocklist'])
473 if obj.get('ip_blocklist') is not None
474 else None,
475 'ip_info': IPInfo.from_dict(obj['ip_info'])
476 if obj.get('ip_info') is not None
477 else None,
478 'proxy': obj.get('proxy'),
479 'proxy_confidence': obj.get('proxy_confidence'),
480 'proxy_details': ProxyDetails.from_dict(obj['proxy_details'])
481 if obj.get('proxy_details') is not None
482 else None,
483 'proxy_ml_score': obj.get('proxy_ml_score'),
484 'incognito': obj.get('incognito'),
485 'jailbroken': obj.get('jailbroken'),
486 'location_spoofing': obj.get('location_spoofing'),
487 'mitm_attack': obj.get('mitm_attack'),
488 'privacy_settings': obj.get('privacy_settings'),
489 'root_apps': obj.get('root_apps'),
490 'rule_action': EventRuleAction.from_dict(obj['rule_action'])
491 if obj.get('rule_action') is not None
492 else None,
493 'simulator': obj.get('simulator'),
494 'suspect_score': obj.get('suspect_score'),
495 'tampering': obj.get('tampering'),
496 'tampering_confidence': obj.get('tampering_confidence'),
497 'tampering_ml_score': obj.get('tampering_ml_score'),
498 'tampering_details': TamperingDetails.from_dict(obj['tampering_details'])
499 if obj.get('tampering_details') is not None
500 else None,
501 'velocity': Velocity.from_dict(obj['velocity'])
502 if obj.get('velocity') is not None
503 else None,
504 'virtual_machine': obj.get('virtual_machine'),
505 'virtual_machine_ml_score': obj.get('virtual_machine_ml_score'),
506 'vpn': obj.get('vpn'),
507 'vpn_confidence': obj.get('vpn_confidence'),
508 'vpn_ml_score': obj.get('vpn_ml_score'),
509 'vpn_origin_timezone': obj.get('vpn_origin_timezone'),
510 'vpn_origin_country': obj.get('vpn_origin_country'),
511 'vpn_methods': VpnMethods.from_dict(obj['vpn_methods'])
512 if obj.get('vpn_methods') is not None
513 else None,
514 'high_activity_device': obj.get('high_activity_device'),
515 'rare_device': obj.get('rare_device'),
516 'rare_device_percentile_bucket': obj.get('rare_device_percentile_bucket'),
517 'raw_device_attributes': RawDeviceAttributes.from_dict(
518 obj['raw_device_attributes']
519 )
520 if obj.get('raw_device_attributes') is not None
521 else None,
522 'labels': [LabelsInner.from_dict(_item) for _item in obj['labels']]
523 if obj.get('labels') is not None
524 else None,
525 }
526 )
527 return _obj