Coverage for fingerprint_server_sdk/models/event.py: 72%

148 statements  

« prev     ^ index     » next       coverage.py v7.14.3, created at 2026-08-05 16:08 +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. 

6 

7The version of the OpenAPI document: 4 

8Contact: support@fingerprint.com 

9Generated by OpenAPI Generator (https://openapi-generator.tech) 

10 

11Do not edit the class manually. 

12""" # noqa: E501 

13 

14from __future__ import annotations 

15 

16import json 

17import pprint 

18import re # noqa: F401 

19from typing import Annotated, Any, ClassVar, Optional, Union 

20 

21from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictInt, StrictStr 

22from typing_extensions import Self 

23 

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.identification import Identification 

29from fingerprint_server_sdk.models.incremental_identification_status import ( 

30 IncrementalIdentificationStatus, 

31) 

32from fingerprint_server_sdk.models.ip_block_list import IPBlockList 

33from fingerprint_server_sdk.models.ip_info import IPInfo 

34from fingerprint_server_sdk.models.labels_inner import LabelsInner 

35from fingerprint_server_sdk.models.proximity import Proximity 

36from fingerprint_server_sdk.models.proxy_confidence import ProxyConfidence 

37from fingerprint_server_sdk.models.proxy_details import ProxyDetails 

38from fingerprint_server_sdk.models.rare_device_percentile_bucket import RareDevicePercentileBucket 

39from fingerprint_server_sdk.models.raw_device_attributes import RawDeviceAttributes 

40from fingerprint_server_sdk.models.sdk import SDK 

41from fingerprint_server_sdk.models.supplementary_id_high_recall import SupplementaryIDHighRecall 

42from fingerprint_server_sdk.models.tampering_confidence import TamperingConfidence 

43from fingerprint_server_sdk.models.tampering_details import TamperingDetails 

44from fingerprint_server_sdk.models.velocity import Velocity 

45from fingerprint_server_sdk.models.vpn_confidence import VpnConfidence 

46from fingerprint_server_sdk.models.vpn_methods import VpnMethods 

47 

48 

49class Event(BaseModel): 

50 """ 

51 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. 

52 """ 

53 

54 event_id: StrictStr = Field( 

55 description="Unique identifier of the user's request. The first portion of the event_id is a unix epoch milliseconds timestamp. " 

56 ) 

57 timestamp: StrictInt = Field( 

58 description='Timestamp of the event with millisecond precision in Unix time.' 

59 ) 

60 incremental_identification_status: Optional[IncrementalIdentificationStatus] = None 

61 linked_id: Optional[StrictStr] = Field( 

62 default=None, description='A customer-provided id that was sent with the request.' 

63 ) 

64 environment_id: Optional[StrictStr] = Field( 

65 default=None, description='Environment Id of the event.' 

66 ) 

67 suspect: Optional[StrictBool] = Field( 

68 default=None, 

69 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).', 

70 ) 

71 sdk: Optional[SDK] = None 

72 replayed: Optional[StrictBool] = Field( 

73 default=None, 

74 description='`true` if we determined that this payload was replayed, `false` otherwise. ', 

75 ) 

76 identification: Optional[Identification] = None 

77 supplementary_id_high_recall: Optional[SupplementaryIDHighRecall] = None 

78 tags: Optional[dict[str, Any]] = Field( 

79 default=None, 

80 description='A customer-provided value or an object that was sent with the identification request or updated later.', 

81 ) 

82 url: Optional[StrictStr] = Field( 

83 default=None, description='Page URL from which the request was sent.' 

84 ) 

85 bundle_id: Optional[StrictStr] = Field( 

86 default=None, 

87 description='Bundle Id of the iOS application integrated with the Fingerprint SDK for the event. ', 

88 ) 

89 package_name: Optional[StrictStr] = Field( 

90 default=None, 

91 description='Package name of the Android application integrated with the Fingerprint SDK for the event. ', 

92 ) 

93 ip_address: Optional[StrictStr] = Field( 

94 default=None, description='IP address of the requesting browser or bot.' 

95 ) 

96 user_agent: Optional[StrictStr] = Field(default=None, description='User Agent of the client.') 

97 device: Optional[StrictStr] = Field( 

98 default=None, 

99 description='Device model or family extracted from the user agent string. On web, this field is also present inside `browser_details`. ', 

100 ) 

101 os: Optional[StrictStr] = Field( 

102 default=None, 

103 description='Operating system family extracted from the user agent string. On web, this field is also present inside `browser_details`. ', 

104 ) 

105 os_version: Optional[StrictStr] = Field( 

106 default=None, 

107 description='Operating system version string extracted from the user agent string. On web, this field is also present inside `browser_details`. ', 

108 ) 

109 client_referrer: Optional[StrictStr] = Field( 

110 default=None, 

111 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). ', 

112 ) 

113 browser_details: Optional[BrowserDetails] = None 

114 proximity: Optional[Proximity] = None 

115 active_call: Optional[StrictBool] = Field( 

116 default=None, 

117 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. ', 

118 ) 

119 bot: Optional[BotResult] = None 

120 bot_type: Optional[StrictStr] = Field( 

121 default=None, description='Additional classification of the bot type if detected. ' 

122 ) 

123 bot_info: Optional[BotInfo] = None 

124 cloned_app: Optional[StrictBool] = Field( 

125 default=None, 

126 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. ', 

127 ) 

128 developer_tools: Optional[StrictBool] = Field( 

129 default=None, 

130 description='`true` if the browser has DevTools open (Chrome, Firefox) or the Android/iOS device has Developer Tools enabled, `false` otherwise. ', 

131 ) 

132 emulator: Optional[StrictBool] = Field( 

133 default=None, 

134 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. ', 

135 ) 

136 factory_reset_timestamp: Optional[StrictInt] = Field( 

137 default=None, 

138 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. ', 

139 ) 

140 frida: Optional[StrictBool] = Field( 

141 default=None, 

142 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. ', 

143 ) 

144 ip_blocklist: Optional[IPBlockList] = None 

145 ip_info: Optional[IPInfo] = None 

146 proxy: Optional[StrictBool] = Field( 

147 default=None, 

148 description='IP address was used by a public proxy provider or belonged to a known recent residential proxy ', 

149 ) 

150 proxy_confidence: Optional[ProxyConfidence] = None 

151 proxy_details: Optional[ProxyDetails] = None 

152 proxy_ml_score: Optional[ 

153 Union[ 

154 Annotated[float, Field(le=1, strict=True, ge=0)], 

155 Annotated[int, Field(le=1, strict=True, ge=0)], 

156 ] 

157 ] = Field( 

158 default=None, 

159 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/). ', 

160 ) 

161 incognito: Optional[StrictBool] = Field( 

162 default=None, 

163 description='`true` if we detected incognito mode used in the browser, `false` otherwise. ', 

164 ) 

165 jailbroken: Optional[StrictBool] = Field( 

166 default=None, 

167 description='iOS specific jailbreak detection. There are 2 values: * `true` - Jailbreak detected. * `false` - No signs of jailbreak or the client is not iOS. ', 

168 ) 

169 location_spoofing: Optional[StrictBool] = Field( 

170 default=None, 

171 description='Flag indicating whether the request came from a mobile device with location spoofing enabled.', 

172 ) 

173 mitm_attack: Optional[StrictBool] = Field( 

174 default=None, 

175 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. ", 

176 ) 

177 privacy_settings: Optional[StrictBool] = Field( 

178 default=None, 

179 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`. ', 

180 ) 

181 root_apps: Optional[StrictBool] = Field( 

182 default=None, 

183 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. ", 

184 ) 

185 rule_action: Optional[EventRuleAction] = None 

186 simulator: Optional[StrictBool] = Field( 

187 default=None, 

188 description='iOS specific simulator detection. There are 2 values: * `true` - Simulator environment detected. * `false` - No signs of simulator or the client is not iOS. ', 

189 ) 

190 suspect_score: Optional[StrictInt] = Field( 

191 default=None, 

192 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 ', 

193 ) 

194 tampering: Optional[StrictBool] = Field( 

195 default=None, 

196 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 ', 

197 ) 

198 tampering_confidence: Optional[TamperingConfidence] = None 

199 tampering_ml_score: Optional[ 

200 Union[ 

201 Annotated[float, Field(le=1, strict=True, ge=0)], 

202 Annotated[int, Field(le=1, strict=True, ge=0)], 

203 ] 

204 ] = Field( 

205 default=None, 

206 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) ', 

207 ) 

208 tampering_details: Optional[TamperingDetails] = None 

209 velocity: Optional[Velocity] = None 

210 virtual_machine: Optional[StrictBool] = Field( 

211 default=None, 

212 description='`true` if the request came from a browser running inside a virtual machine (e.g. VMWare), `false` otherwise. ', 

213 ) 

214 virtual_machine_ml_score: Optional[ 

215 Union[ 

216 Annotated[float, Field(le=1, strict=True, ge=0)], 

217 Annotated[int, Field(le=1, strict=True, ge=0)], 

218 ] 

219 ] = Field( 

220 default=None, 

221 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/). ', 

222 ) 

223 vpn: Optional[StrictBool] = Field( 

224 default=None, 

225 description='VPN or other anonymizing service has been used when sending the request. ', 

226 ) 

227 vpn_confidence: Optional[VpnConfidence] = None 

228 vpn_ml_score: Optional[ 

229 Union[ 

230 Annotated[float, Field(le=1, strict=True, ge=0)], 

231 Annotated[int, Field(le=1, strict=True, ge=0)], 

232 ] 

233 ] = Field( 

234 default=None, 

235 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/). ', 

236 ) 

237 vpn_origin_timezone: Optional[StrictStr] = Field( 

238 default=None, description='Local timezone which is used in timezone_mismatch method. ' 

239 ) 

240 vpn_origin_country: Optional[StrictStr] = Field( 

241 default=None, 

242 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. ', 

243 ) 

244 vpn_methods: Optional[VpnMethods] = None 

245 high_activity_device: Optional[StrictBool] = Field( 

246 default=None, 

247 description='Flag indicating if the request came from a high-activity visitor.', 

248 ) 

249 rare_device: Optional[StrictBool] = Field( 

250 default=None, 

251 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/). ', 

252 ) 

253 rare_device_percentile_bucket: Optional[RareDevicePercentileBucket] = None 

254 raw_device_attributes: Optional[RawDeviceAttributes] = None 

255 labels: Optional[list[LabelsInner]] = Field( 

256 default=None, 

257 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/). ', 

258 ) 

259 __properties: ClassVar[list[str]] = [ 

260 'event_id', 

261 'timestamp', 

262 'incremental_identification_status', 

263 'linked_id', 

264 'environment_id', 

265 'suspect', 

266 'sdk', 

267 'replayed', 

268 'identification', 

269 'supplementary_id_high_recall', 

270 'tags', 

271 'url', 

272 'bundle_id', 

273 'package_name', 

274 'ip_address', 

275 'user_agent', 

276 'device', 

277 'os', 

278 'os_version', 

279 'client_referrer', 

280 'browser_details', 

281 'proximity', 

282 'active_call', 

283 'bot', 

284 'bot_type', 

285 'bot_info', 

286 'cloned_app', 

287 'developer_tools', 

288 'emulator', 

289 'factory_reset_timestamp', 

290 'frida', 

291 'ip_blocklist', 

292 'ip_info', 

293 'proxy', 

294 'proxy_confidence', 

295 'proxy_details', 

296 'proxy_ml_score', 

297 'incognito', 

298 'jailbroken', 

299 'location_spoofing', 

300 'mitm_attack', 

301 'privacy_settings', 

302 'root_apps', 

303 'rule_action', 

304 'simulator', 

305 'suspect_score', 

306 'tampering', 

307 'tampering_confidence', 

308 'tampering_ml_score', 

309 'tampering_details', 

310 'velocity', 

311 'virtual_machine', 

312 'virtual_machine_ml_score', 

313 'vpn', 

314 'vpn_confidence', 

315 'vpn_ml_score', 

316 'vpn_origin_timezone', 

317 'vpn_origin_country', 

318 'vpn_methods', 

319 'high_activity_device', 

320 'rare_device', 

321 'rare_device_percentile_bucket', 

322 'raw_device_attributes', 

323 'labels', 

324 ] 

325 

326 model_config = ConfigDict( 

327 populate_by_name=True, 

328 validate_assignment=True, 

329 protected_namespaces=(), 

330 ) 

331 

332 def to_str(self) -> str: 

333 """Returns the string representation of the model using alias""" 

334 return pprint.pformat(self.model_dump(by_alias=True)) 

335 

336 def to_json(self) -> str: 

337 """Returns the JSON representation of the model using alias""" 

338 # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead 

339 return json.dumps(self.to_dict()) 

340 

341 @classmethod 

342 def from_json(cls, json_str: str) -> Optional[Self]: 

343 """Create an instance of Event from a JSON string""" 

344 return cls.from_dict(json.loads(json_str)) 

345 

346 def to_dict(self) -> dict[str, Any]: 

347 """Return the dictionary representation of the model using alias. 

348 

349 This has the following differences from calling pydantic's 

350 `self.model_dump(by_alias=True)`: 

351 

352 * `None` is only added to the output dict for nullable fields that 

353 were set at model initialization. Other fields with value `None` 

354 are ignored. 

355 """ 

356 excluded_fields: set[str] = set([]) 

357 

358 _dict = self.model_dump( 

359 by_alias=True, 

360 exclude=excluded_fields, 

361 exclude_none=True, 

362 ) 

363 # override the default output from pydantic by calling `to_dict()` of sdk 

364 if self.sdk: 

365 _dict['sdk'] = self.sdk.to_dict() 

366 # override the default output from pydantic by calling `to_dict()` of identification 

367 if self.identification: 

368 _dict['identification'] = self.identification.to_dict() 

369 # override the default output from pydantic by calling `to_dict()` of supplementary_id_high_recall 

370 if self.supplementary_id_high_recall: 

371 _dict['supplementary_id_high_recall'] = self.supplementary_id_high_recall.to_dict() 

372 # override the default output from pydantic by calling `to_dict()` of browser_details 

373 if self.browser_details: 

374 _dict['browser_details'] = self.browser_details.to_dict() 

375 # override the default output from pydantic by calling `to_dict()` of proximity 

376 if self.proximity: 

377 _dict['proximity'] = self.proximity.to_dict() 

378 # override the default output from pydantic by calling `to_dict()` of bot_info 

379 if self.bot_info: 

380 _dict['bot_info'] = self.bot_info.to_dict() 

381 # override the default output from pydantic by calling `to_dict()` of ip_blocklist 

382 if self.ip_blocklist: 

383 _dict['ip_blocklist'] = self.ip_blocklist.to_dict() 

384 # override the default output from pydantic by calling `to_dict()` of ip_info 

385 if self.ip_info: 

386 _dict['ip_info'] = self.ip_info.to_dict() 

387 # override the default output from pydantic by calling `to_dict()` of proxy_details 

388 if self.proxy_details: 

389 _dict['proxy_details'] = self.proxy_details.to_dict() 

390 # override the default output from pydantic by calling `to_dict()` of rule_action 

391 if self.rule_action: 

392 _dict['rule_action'] = self.rule_action.to_dict() 

393 # override the default output from pydantic by calling `to_dict()` of tampering_details 

394 if self.tampering_details: 

395 _dict['tampering_details'] = self.tampering_details.to_dict() 

396 # override the default output from pydantic by calling `to_dict()` of velocity 

397 if self.velocity: 

398 _dict['velocity'] = self.velocity.to_dict() 

399 # override the default output from pydantic by calling `to_dict()` of vpn_methods 

400 if self.vpn_methods: 

401 _dict['vpn_methods'] = self.vpn_methods.to_dict() 

402 # override the default output from pydantic by calling `to_dict()` of raw_device_attributes 

403 if self.raw_device_attributes: 

404 _dict['raw_device_attributes'] = self.raw_device_attributes.to_dict() 

405 # override the default output from pydantic by calling `to_dict()` of each item in labels (list) 

406 _items = [] 

407 if self.labels: 

408 for _item_labels in self.labels: 

409 if _item_labels: 

410 _items.append(_item_labels.to_dict()) 

411 _dict['labels'] = _items 

412 return _dict 

413 

414 @classmethod 

415 def from_dict(cls, obj: Optional[dict[str, Any]]) -> Optional[Self]: 

416 """Create an instance of Event from a dict""" 

417 if obj is None: 

418 return None 

419 

420 if not isinstance(obj, dict): 

421 return cls.model_validate(obj) 

422 

423 _obj = cls.model_validate( 

424 { 

425 'event_id': obj.get('event_id'), 

426 'timestamp': obj.get('timestamp'), 

427 'incremental_identification_status': obj.get('incremental_identification_status'), 

428 'linked_id': obj.get('linked_id'), 

429 'environment_id': obj.get('environment_id'), 

430 'suspect': obj.get('suspect'), 

431 'sdk': SDK.from_dict(obj['sdk']) if obj.get('sdk') is not None else None, 

432 'replayed': obj.get('replayed'), 

433 'identification': Identification.from_dict(obj['identification']) 

434 if obj.get('identification') is not None 

435 else None, 

436 'supplementary_id_high_recall': SupplementaryIDHighRecall.from_dict( 

437 obj['supplementary_id_high_recall'] 

438 ) 

439 if obj.get('supplementary_id_high_recall') is not None 

440 else None, 

441 'tags': obj.get('tags'), 

442 'url': obj.get('url'), 

443 'bundle_id': obj.get('bundle_id'), 

444 'package_name': obj.get('package_name'), 

445 'ip_address': obj.get('ip_address'), 

446 'user_agent': obj.get('user_agent'), 

447 'device': obj.get('device'), 

448 'os': obj.get('os'), 

449 'os_version': obj.get('os_version'), 

450 'client_referrer': obj.get('client_referrer'), 

451 'browser_details': BrowserDetails.from_dict(obj['browser_details']) 

452 if obj.get('browser_details') is not None 

453 else None, 

454 'proximity': Proximity.from_dict(obj['proximity']) 

455 if obj.get('proximity') is not None 

456 else None, 

457 'active_call': obj.get('active_call'), 

458 'bot': obj.get('bot'), 

459 'bot_type': obj.get('bot_type'), 

460 'bot_info': BotInfo.from_dict(obj['bot_info']) 

461 if obj.get('bot_info') is not None 

462 else None, 

463 'cloned_app': obj.get('cloned_app'), 

464 'developer_tools': obj.get('developer_tools'), 

465 'emulator': obj.get('emulator'), 

466 'factory_reset_timestamp': obj.get('factory_reset_timestamp'), 

467 'frida': obj.get('frida'), 

468 'ip_blocklist': IPBlockList.from_dict(obj['ip_blocklist']) 

469 if obj.get('ip_blocklist') is not None 

470 else None, 

471 'ip_info': IPInfo.from_dict(obj['ip_info']) 

472 if obj.get('ip_info') is not None 

473 else None, 

474 'proxy': obj.get('proxy'), 

475 'proxy_confidence': obj.get('proxy_confidence'), 

476 'proxy_details': ProxyDetails.from_dict(obj['proxy_details']) 

477 if obj.get('proxy_details') is not None 

478 else None, 

479 'proxy_ml_score': obj.get('proxy_ml_score'), 

480 'incognito': obj.get('incognito'), 

481 'jailbroken': obj.get('jailbroken'), 

482 'location_spoofing': obj.get('location_spoofing'), 

483 'mitm_attack': obj.get('mitm_attack'), 

484 'privacy_settings': obj.get('privacy_settings'), 

485 'root_apps': obj.get('root_apps'), 

486 'rule_action': EventRuleAction.from_dict(obj['rule_action']) 

487 if obj.get('rule_action') is not None 

488 else None, 

489 'simulator': obj.get('simulator'), 

490 'suspect_score': obj.get('suspect_score'), 

491 'tampering': obj.get('tampering'), 

492 'tampering_confidence': obj.get('tampering_confidence'), 

493 'tampering_ml_score': obj.get('tampering_ml_score'), 

494 'tampering_details': TamperingDetails.from_dict(obj['tampering_details']) 

495 if obj.get('tampering_details') is not None 

496 else None, 

497 'velocity': Velocity.from_dict(obj['velocity']) 

498 if obj.get('velocity') is not None 

499 else None, 

500 'virtual_machine': obj.get('virtual_machine'), 

501 'virtual_machine_ml_score': obj.get('virtual_machine_ml_score'), 

502 'vpn': obj.get('vpn'), 

503 'vpn_confidence': obj.get('vpn_confidence'), 

504 'vpn_ml_score': obj.get('vpn_ml_score'), 

505 'vpn_origin_timezone': obj.get('vpn_origin_timezone'), 

506 'vpn_origin_country': obj.get('vpn_origin_country'), 

507 'vpn_methods': VpnMethods.from_dict(obj['vpn_methods']) 

508 if obj.get('vpn_methods') is not None 

509 else None, 

510 'high_activity_device': obj.get('high_activity_device'), 

511 'rare_device': obj.get('rare_device'), 

512 'rare_device_percentile_bucket': obj.get('rare_device_percentile_bucket'), 

513 'raw_device_attributes': RawDeviceAttributes.from_dict( 

514 obj['raw_device_attributes'] 

515 ) 

516 if obj.get('raw_device_attributes') is not None 

517 else None, 

518 'labels': [LabelsInner.from_dict(_item) for _item in obj['labels']] 

519 if obj.get('labels') is not None 

520 else None, 

521 } 

522 ) 

523 return _obj