Skip to content

Commit

Permalink
Fix problem in sanitize_for_serialization for Python (pydantic type S…
Browse files Browse the repository at this point in the history
…ecretStr ) BUG#16086 (2nd pull) (OpenAPITools#18023)

* fix-for-bug-16086

* add to_dict alternative

* fix assertEqual

* remove extra blank line + test_model Argument SecretStr set

* update samples / remove extra blank line

* restore sanitize test for serialization with different data types

* remove empty line in api_client.mustache

* remove 2nd empty line in api_client.mustache
  • Loading branch information
azdolinski authored Mar 20, 2024
1 parent e2df0d6 commit c15e267
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import tempfile

from urllib.parse import quote
from typing import Tuple, Optional, List, Dict, Union
from pydantic import SecretStr
{{#tornado}}
import tornado.gen
{{/tornado}}
Expand Down Expand Up @@ -344,6 +345,7 @@ class ApiClient:
"""Builds a JSON POST object.

If obj is None, return None.
If obj is SecretStr, return obj.get_secret_value()
If obj is str, int, long, float, bool, return directly.
If obj is datetime.datetime, datetime.date
convert to string in iso8601 format.
Expand All @@ -356,6 +358,8 @@ class ApiClient:
"""
if obj is None:
return None
elif isinstance(obj, SecretStr):
return obj.get_secret_value()
elif isinstance(obj, self.PRIMITIVE_TYPES):
return obj
elif isinstance(obj, list):
Expand All @@ -377,7 +381,10 @@ class ApiClient:
# and attributes which value is not None.
# Convert attribute name to json key in
# model definition for request.
obj_dict = obj.to_dict()
if hasattr(obj, 'to_dict') and callable(getattr(obj, 'to_dict')):
obj_dict = obj.to_dict()
else:
obj_dict = obj.__dict__

return {
key: self.sanitize_for_serialization(val)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

from urllib.parse import quote
from typing import Tuple, Optional, List, Dict, Union
from pydantic import SecretStr

from openapi_client.configuration import Configuration
from openapi_client.api_response import ApiResponse, T as ApiResponseT
Expand Down Expand Up @@ -337,6 +338,7 @@ def sanitize_for_serialization(self, obj):
"""Builds a JSON POST object.
If obj is None, return None.
If obj is SecretStr, return obj.get_secret_value()
If obj is str, int, long, float, bool, return directly.
If obj is datetime.datetime, datetime.date
convert to string in iso8601 format.
Expand All @@ -349,6 +351,8 @@ def sanitize_for_serialization(self, obj):
"""
if obj is None:
return None
elif isinstance(obj, SecretStr):
return obj.get_secret_value()
elif isinstance(obj, self.PRIMITIVE_TYPES):
return obj
elif isinstance(obj, list):
Expand All @@ -370,7 +374,10 @@ def sanitize_for_serialization(self, obj):
# and attributes which value is not None.
# Convert attribute name to json key in
# model definition for request.
obj_dict = obj.to_dict()
if hasattr(obj, 'to_dict') and callable(getattr(obj, 'to_dict')):
obj_dict = obj.to_dict()
else:
obj_dict = obj.__dict__

return {
key: self.sanitize_for_serialization(val)
Expand Down
9 changes: 8 additions & 1 deletion samples/client/echo_api/python/openapi_client/api_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

from urllib.parse import quote
from typing import Tuple, Optional, List, Dict, Union
from pydantic import SecretStr

from openapi_client.configuration import Configuration
from openapi_client.api_response import ApiResponse, T as ApiResponseT
Expand Down Expand Up @@ -337,6 +338,7 @@ def sanitize_for_serialization(self, obj):
"""Builds a JSON POST object.
If obj is None, return None.
If obj is SecretStr, return obj.get_secret_value()
If obj is str, int, long, float, bool, return directly.
If obj is datetime.datetime, datetime.date
convert to string in iso8601 format.
Expand All @@ -349,6 +351,8 @@ def sanitize_for_serialization(self, obj):
"""
if obj is None:
return None
elif isinstance(obj, SecretStr):
return obj.get_secret_value()
elif isinstance(obj, self.PRIMITIVE_TYPES):
return obj
elif isinstance(obj, list):
Expand All @@ -370,7 +374,10 @@ def sanitize_for_serialization(self, obj):
# and attributes which value is not None.
# Convert attribute name to json key in
# model definition for request.
obj_dict = obj.to_dict()
if hasattr(obj, 'to_dict') and callable(getattr(obj, 'to_dict')):
obj_dict = obj.to_dict()
else:
obj_dict = obj.__dict__

return {
key: self.sanitize_for_serialization(val)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

from urllib.parse import quote
from typing import Tuple, Optional, List, Dict, Union
from pydantic import SecretStr

from petstore_api.configuration import Configuration
from petstore_api.api_response import ApiResponse, T as ApiResponseT
Expand Down Expand Up @@ -339,6 +340,7 @@ def sanitize_for_serialization(self, obj):
"""Builds a JSON POST object.
If obj is None, return None.
If obj is SecretStr, return obj.get_secret_value()
If obj is str, int, long, float, bool, return directly.
If obj is datetime.datetime, datetime.date
convert to string in iso8601 format.
Expand All @@ -351,6 +353,8 @@ def sanitize_for_serialization(self, obj):
"""
if obj is None:
return None
elif isinstance(obj, SecretStr):
return obj.get_secret_value()
elif isinstance(obj, self.PRIMITIVE_TYPES):
return obj
elif isinstance(obj, list):
Expand All @@ -372,7 +376,10 @@ def sanitize_for_serialization(self, obj):
# and attributes which value is not None.
# Convert attribute name to json key in
# model definition for request.
obj_dict = obj.to_dict()
if hasattr(obj, 'to_dict') and callable(getattr(obj, 'to_dict')):
obj_dict = obj.to_dict()
else:
obj_dict = obj.__dict__

return {
key: self.sanitize_for_serialization(val)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

from urllib.parse import quote
from typing import Tuple, Optional, List, Dict, Union
from pydantic import SecretStr

from petstore_api.configuration import Configuration
from petstore_api.api_response import ApiResponse, T as ApiResponseT
Expand Down Expand Up @@ -336,6 +337,7 @@ def sanitize_for_serialization(self, obj):
"""Builds a JSON POST object.
If obj is None, return None.
If obj is SecretStr, return obj.get_secret_value()
If obj is str, int, long, float, bool, return directly.
If obj is datetime.datetime, datetime.date
convert to string in iso8601 format.
Expand All @@ -348,6 +350,8 @@ def sanitize_for_serialization(self, obj):
"""
if obj is None:
return None
elif isinstance(obj, SecretStr):
return obj.get_secret_value()
elif isinstance(obj, self.PRIMITIVE_TYPES):
return obj
elif isinstance(obj, list):
Expand All @@ -369,7 +373,10 @@ def sanitize_for_serialization(self, obj):
# and attributes which value is not None.
# Convert attribute name to json key in
# model definition for request.
obj_dict = obj.to_dict()
if hasattr(obj, 'to_dict') and callable(getattr(obj, 'to_dict')):
obj_dict = obj.to_dict()
else:
obj_dict = obj.__dict__

return {
key: self.sanitize_for_serialization(val)
Expand Down
12 changes: 10 additions & 2 deletions samples/openapi3/client/petstore/python/tests/test_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import time
import unittest

from pydantic import ValidationError
from pydantic import ValidationError, SecretStr, BaseModel, StrictStr, Field
import pytest

import petstore_api
Expand Down Expand Up @@ -407,9 +407,17 @@ def test_valdiator(self):
a.pattern_with_digits_and_delimiter = "image_123"
self.assertEqual(a.pattern_with_digits_and_delimiter, "image_123")

# test sanitize for serializaation with SecretStr (format: password)
# test sanitize for serialization with different data types
self.assertEquals(petstore_api.ApiClient().sanitize_for_serialization(a), {'byte': b'string', 'date': '2013-09-17', 'number': 123.45, 'password': 'testing09876', 'pattern_with_digits_and_delimiter': 'image_123'})

# test sanitize for serialization with SecretStr (format: password)
class LoginTest(BaseModel):
username: StrictStr = Field(min_length=2, strict=True, max_length=64)
password: SecretStr

l = LoginTest(username="admin", password=SecretStr("testing09876"))
self.assertEqual(petstore_api.ApiClient().sanitize_for_serialization(l), {'username': "admin", 'password': "testing09876"})

def test_inline_enum_validator(self):
self.pet = petstore_api.Pet(name="test name", photoUrls=["string"])
self.pet.id = 1
Expand Down

0 comments on commit c15e267

Please sign in to comment.