Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fix-array-schema-deserialization.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"fingerprint-pro-server-api-python-sdk": patch
---

**events**: Fix parsing of `GeolocationSubdivisions` so `subdivisions` returns a typed list of `GeolocationSubdivision`
6 changes: 6 additions & 0 deletions fingerprint_pro_server_api_sdk/api_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,12 @@ def __deserialize_model(data, klass):
if not klass.swagger_types and not ApiClientDeserializer.__hasattr(klass, 'get_real_child_model'):
if hasattr(klass, '__parent_class__') and klass.__parent_class__ == 'dict':
return klass(**data)
if hasattr(klass, '__parent_class__') and klass.__parent_class__ == 'list':
item_type = getattr(klass, '__list_item_type__', None)
if item_type is not None and isinstance(data, list):
return klass(ApiClientDeserializer.deserialize(sub_data, item_type)
for sub_data in data)
return klass(data)
Comment thread
erayaydin marked this conversation as resolved.
return data

kwargs = {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from fingerprint_pro_server_api_sdk.base_model import BaseModel


class GeolocationSubdivisions(BaseModel):
class GeolocationSubdivisions(list):
"""NOTE: This class is auto generated by the swagger code generator program.

Do not edit the class manually.
Expand All @@ -36,7 +36,6 @@ class GeolocationSubdivisions(BaseModel):
attribute_map = {
}

def __init__(self): # noqa: E501
"""GeolocationSubdivisions - a model defined in Swagger""" # noqa: E501
self.discriminator = None
__parent_class__ = 'list'
__list_item_type__ = 'GeolocationSubdivision'

6 changes: 6 additions & 0 deletions template/api_client.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,12 @@ class ApiClientDeserializer:
if not klass.swagger_types and not ApiClientDeserializer.__hasattr(klass, 'get_real_child_model'):
if hasattr(klass, '__parent_class__') and klass.__parent_class__ == 'dict':
return klass(**data)
if hasattr(klass, '__parent_class__') and klass.__parent_class__ == 'list':
item_type = getattr(klass, '__list_item_type__', None)
if item_type is not None and isinstance(data, list):
return klass(ApiClientDeserializer.deserialize(sub_data, item_type)
for sub_data in data)
return klass(data)
Comment thread
erayaydin marked this conversation as resolved.
return data

kwargs = {}
Expand Down
8 changes: 7 additions & 1 deletion template/model.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ from typing_extensions import deprecated
{{#schema.deprecated}}
@deprecated("This class is deprecated. Please avoid using it in new code.")
{{/schema.deprecated}}
class {{classname}}({{#parent}}{{parent}}{{/parent}}{{^parent}}BaseModel{{/parent}}):
class {{classname}}({{#isArrayModel}}list{{/isArrayModel}}{{^isArrayModel}}{{#parent}}{{parent}}{{/parent}}{{^parent}}BaseModel{{/parent}}{{/isArrayModel}}):
"""{{#description}}
{{{.}}}

Expand Down Expand Up @@ -72,6 +72,11 @@ class {{classname}}({{#parent}}{{parent}}{{/parent}}{{^parent}}BaseModel{{/paren
}
{{/discriminator}}

{{#isArrayModel}}
__parent_class__ = 'list'
__list_item_type__ = '{{{arrayModelType}}}'
{{/isArrayModel}}
{{^isArrayModel}}
{{#parent}}
__parent_class__ = '{{parent}}'
{{/parent}}
Expand All @@ -85,6 +90,7 @@ class {{classname}}({{#parent}}{{parent}}{{/parent}}{{^parent}}BaseModel{{/paren
{{/vars}}
self.discriminator = {{#discriminator}}'{{discriminator}}'{{/discriminator}}{{^discriminator}}None{{/discriminator}}
{{/parent}}
{{/isArrayModel}}
{{#vars}}{{#@first}}
{{/@first}}
{{#required}}
Expand Down
25 changes: 25 additions & 0 deletions test/test_base_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,31 @@ def test_to_dict_with_dict_of_models(self):
}
self.assertEqual(model.to_dict(), expected)

def test_to_dict_with_list_of_models(self):
"""Test conversion to dictionary when a list attribute holds models.

This mirrors how array schemas (e.g. GeolocationSubdivisions) expose a
list of typed items that each must be serialized via to_dict().
"""
model = ExampleModel(
name="Test Model",
details={"key": "value"},
items=[SubModel(id=1, value="first"), SubModel(id=2, value="second")],
sub_model=self.sub_model,
)
expected = {
'name': "Test Model",
'details': {"key": "value"},
'items': [{'id': 1, 'value': 'first'}, {'id': 2, 'value': 'second'}],
'sub_model': {'id': 1, 'value': 'sub_value'},
}
self.assertEqual(model.to_dict(), expected)

def test_to_dict_with_list_of_mixed_items(self):
"""Test that a list mixing models and primitives serializes each correctly."""
model = ExampleModel(items=[SubModel(id=1, value="first"), "plain", 3])
self.assertEqual(model.to_dict(), {'items': [{'id': 1, 'value': 'first'}, "plain", 3]})

def test_to_str(self):
"""Test conversion to string."""
expected_str = pprint.pformat(self.model.to_dict())
Expand Down
13 changes: 12 additions & 1 deletion test/test_fingerprint_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@

from fingerprint_pro_server_api_sdk import (Configuration, ErrorResponse, ErrorPlainResponse, ErrorCode,
RawDeviceAttributes, EventsUpdateRequest, RelatedVisitorsResponse,
SearchEventsResponse, SearchEventsResponseEvents, Products)
SearchEventsResponse, SearchEventsResponseEvents, Products,
GeolocationSubdivisions, GeolocationSubdivision)
from fingerprint_pro_server_api_sdk.api.fingerprint_api import FingerprintApi # noqa: E501
from fingerprint_pro_server_api_sdk.rest import KnownApiException, ApiException
from urllib.parse import urlencode
Expand Down Expand Up @@ -274,6 +275,16 @@ def test_get_event_correct_data(self):
self.assertIsNone(event_response_dict["products"]["identification"]["data"]["last_seen_at"]["subscription"])
self.assertIsInstance(event_response.products.raw_device_attributes.data, RawDeviceAttributes)

subdivisions = event_response.products.identification.data.ip_location.subdivisions
self.assertIsInstance(subdivisions, GeolocationSubdivisions)
self.assertEqual(len(subdivisions), 1)
self.assertIsInstance(subdivisions[0], GeolocationSubdivision)
self.assertEqual(subdivisions[0].iso_code, "63")
self.assertEqual(subdivisions[0].name, "North Rhine-Westphalia")
self.assertEqual(
event_response_dict["products"]["identification"]["data"]["ip_location"]["subdivisions"],
[{"iso_code": "63", "name": "North Rhine-Westphalia"}])

def test_get_event_errors_200(self):
"""Test checks correct code run result in scenario of arrors in BotD or identification API"""
mock_pool = MockPoolManager(self)
Expand Down
Loading