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

147 statements  

« prev     ^ index     » next       coverage.py v7.14.3, created at 2026-07-14 10:45 +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. 

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 bot: Optional[BotResult] = None 

116 bot_type: Optional[StrictStr] = Field( 

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

118 ) 

119 bot_info: Optional[BotInfo] = None 

120 cloned_app: Optional[StrictBool] = Field( 

121 default=None, 

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

123 ) 

124 developer_tools: Optional[StrictBool] = Field( 

125 default=None, 

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

127 ) 

128 emulator: Optional[StrictBool] = Field( 

129 default=None, 

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

131 ) 

132 factory_reset_timestamp: Optional[StrictInt] = Field( 

133 default=None, 

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

135 ) 

136 frida: Optional[StrictBool] = Field( 

137 default=None, 

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

139 ) 

140 ip_blocklist: Optional[IPBlockList] = None 

141 ip_info: Optional[IPInfo] = None 

142 proxy: Optional[StrictBool] = Field( 

143 default=None, 

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

145 ) 

146 proxy_confidence: Optional[ProxyConfidence] = None 

147 proxy_details: Optional[ProxyDetails] = None 

148 proxy_ml_score: Optional[ 

149 Union[ 

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

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

152 ] 

153 ] = Field( 

154 default=None, 

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

156 ) 

157 incognito: Optional[StrictBool] = Field( 

158 default=None, 

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

160 ) 

161 jailbroken: Optional[StrictBool] = Field( 

162 default=None, 

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

164 ) 

165 location_spoofing: Optional[StrictBool] = Field( 

166 default=None, 

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

168 ) 

169 mitm_attack: Optional[StrictBool] = Field( 

170 default=None, 

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

172 ) 

173 privacy_settings: Optional[StrictBool] = Field( 

174 default=None, 

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

176 ) 

177 root_apps: Optional[StrictBool] = Field( 

178 default=None, 

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

180 ) 

181 rule_action: Optional[EventRuleAction] = None 

182 simulator: Optional[StrictBool] = Field( 

183 default=None, 

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

185 ) 

186 suspect_score: Optional[StrictInt] = Field( 

187 default=None, 

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

189 ) 

190 tampering: Optional[StrictBool] = Field( 

191 default=None, 

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

193 ) 

194 tampering_confidence: Optional[TamperingConfidence] = None 

195 tampering_ml_score: Optional[ 

196 Union[ 

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

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

199 ] 

200 ] = Field( 

201 default=None, 

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

203 ) 

204 tampering_details: Optional[TamperingDetails] = None 

205 velocity: Optional[Velocity] = None 

206 virtual_machine: Optional[StrictBool] = Field( 

207 default=None, 

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

209 ) 

210 virtual_machine_ml_score: Optional[ 

211 Union[ 

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

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

214 ] 

215 ] = Field( 

216 default=None, 

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

218 ) 

219 vpn: Optional[StrictBool] = Field( 

220 default=None, 

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

222 ) 

223 vpn_confidence: Optional[VpnConfidence] = None 

224 vpn_ml_score: Optional[ 

225 Union[ 

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

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

228 ] 

229 ] = Field( 

230 default=None, 

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

232 ) 

233 vpn_origin_timezone: Optional[StrictStr] = Field( 

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

235 ) 

236 vpn_origin_country: Optional[StrictStr] = Field( 

237 default=None, 

238 description='Country of the request (only for Android SDK version >= 2.4.0, ISO 3166 format or unknown). ', 

239 ) 

240 vpn_methods: Optional[VpnMethods] = None 

241 high_activity_device: Optional[StrictBool] = Field( 

242 default=None, 

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

244 ) 

245 rare_device: Optional[StrictBool] = Field( 

246 default=None, 

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

248 ) 

249 rare_device_percentile_bucket: Optional[RareDevicePercentileBucket] = None 

250 raw_device_attributes: Optional[RawDeviceAttributes] = None 

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

252 default=None, 

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

254 ) 

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

256 'event_id', 

257 'timestamp', 

258 'incremental_identification_status', 

259 'linked_id', 

260 'environment_id', 

261 'suspect', 

262 'sdk', 

263 'replayed', 

264 'identification', 

265 'supplementary_id_high_recall', 

266 'tags', 

267 'url', 

268 'bundle_id', 

269 'package_name', 

270 'ip_address', 

271 'user_agent', 

272 'device', 

273 'os', 

274 'os_version', 

275 'client_referrer', 

276 'browser_details', 

277 'proximity', 

278 'bot', 

279 'bot_type', 

280 'bot_info', 

281 'cloned_app', 

282 'developer_tools', 

283 'emulator', 

284 'factory_reset_timestamp', 

285 'frida', 

286 'ip_blocklist', 

287 'ip_info', 

288 'proxy', 

289 'proxy_confidence', 

290 'proxy_details', 

291 'proxy_ml_score', 

292 'incognito', 

293 'jailbroken', 

294 'location_spoofing', 

295 'mitm_attack', 

296 'privacy_settings', 

297 'root_apps', 

298 'rule_action', 

299 'simulator', 

300 'suspect_score', 

301 'tampering', 

302 'tampering_confidence', 

303 'tampering_ml_score', 

304 'tampering_details', 

305 'velocity', 

306 'virtual_machine', 

307 'virtual_machine_ml_score', 

308 'vpn', 

309 'vpn_confidence', 

310 'vpn_ml_score', 

311 'vpn_origin_timezone', 

312 'vpn_origin_country', 

313 'vpn_methods', 

314 'high_activity_device', 

315 'rare_device', 

316 'rare_device_percentile_bucket', 

317 'raw_device_attributes', 

318 'labels', 

319 ] 

320 

321 model_config = ConfigDict( 

322 populate_by_name=True, 

323 validate_assignment=True, 

324 protected_namespaces=(), 

325 ) 

326 

327 def to_str(self) -> str: 

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

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

330 

331 def to_json(self) -> str: 

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

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

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

335 

336 @classmethod 

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

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

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

340 

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

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

343 

344 This has the following differences from calling pydantic's 

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

346 

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

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

349 are ignored. 

350 """ 

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

352 

353 _dict = self.model_dump( 

354 by_alias=True, 

355 exclude=excluded_fields, 

356 exclude_none=True, 

357 ) 

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

359 if self.sdk: 

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

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

362 if self.identification: 

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

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

365 if self.supplementary_id_high_recall: 

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

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

368 if self.browser_details: 

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

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

371 if self.proximity: 

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

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

374 if self.bot_info: 

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

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

377 if self.ip_blocklist: 

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

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

380 if self.ip_info: 

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

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

383 if self.proxy_details: 

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

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

386 if self.rule_action: 

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

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

389 if self.tampering_details: 

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

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

392 if self.velocity: 

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

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

395 if self.vpn_methods: 

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

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

398 if self.raw_device_attributes: 

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

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

401 _items = [] 

402 if self.labels: 

403 for _item_labels in self.labels: 

404 if _item_labels: 

405 _items.append(_item_labels.to_dict()) 

406 _dict['labels'] = _items 

407 return _dict 

408 

409 @classmethod 

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

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

412 if obj is None: 

413 return None 

414 

415 if not isinstance(obj, dict): 

416 return cls.model_validate(obj) 

417 

418 _obj = cls.model_validate( 

419 { 

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

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

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

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

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

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

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

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

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

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

430 else None, 

431 'supplementary_id_high_recall': SupplementaryIDHighRecall.from_dict( 

432 obj['supplementary_id_high_recall'] 

433 ) 

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

435 else None, 

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

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

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

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

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

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

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

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

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

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

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

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

448 else None, 

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

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

451 else None, 

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

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

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

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

456 else None, 

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

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

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

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

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

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

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

464 else None, 

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

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

467 else None, 

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

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

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

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

472 else None, 

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

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

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

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

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

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

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

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

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

482 else None, 

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

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

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

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

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

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

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

490 else None, 

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

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

493 else None, 

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

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

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

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

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

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

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

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

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

503 else None, 

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

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

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

507 'raw_device_attributes': RawDeviceAttributes.from_dict( 

508 obj['raw_device_attributes'] 

509 ) 

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

511 else None, 

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

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

514 else None, 

515 } 

516 ) 

517 return _obj