Properly handle bigint strings that are strings of large numbers that end with 'n'.

pull/3585/head
derekpierre 2025-03-20 15:26:21 -04:00
parent 1b13c50b02
commit a4df4662aa
No known key found for this signature in database
3 changed files with 48 additions and 21 deletions

View File

@ -36,7 +36,11 @@ from nucypher.policy.conditions.exceptions import (
ReturnValueEvaluationError,
)
from nucypher.policy.conditions.types import ConditionDict, Lingo
from nucypher.policy.conditions.utils import CamelCaseSchema, ConditionProviderManager
from nucypher.policy.conditions.utils import (
CamelCaseSchema,
ConditionProviderManager,
check_and_convert_big_int_string_to_int,
)
class AnyField(fields.Field):
@ -46,23 +50,15 @@ class AnyField(fields.Field):
numbers as integers, so those need converting to integers.
"""
def _convert_any_large_integers_from_string(self, value):
def _convert_any_big_ints_from_string(self, value):
if isinstance(value, list):
return [
self._convert_any_large_integers_from_string(item) for item in value
]
return [self._convert_any_big_ints_from_string(item) for item in value]
elif isinstance(value, dict):
return {
k: self._convert_any_large_integers_from_string(v)
for k, v in value.items()
k: self._convert_any_big_ints_from_string(v) for k, v in value.items()
}
elif isinstance(value, str):
try:
result = int(value)
return result
except ValueError:
# ignore
pass
return check_and_convert_big_int_string_to_int(value)
return value
@ -70,7 +66,23 @@ class AnyField(fields.Field):
return value
def _deserialize(self, value, attr, data, **kwargs):
return self._convert_any_large_integers_from_string(value)
return self._convert_any_big_ints_from_string(value)
class IntegerField(fields.Int):
"""
Integer field that also converts big int strings to integers.
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def _deserialize(self, value, attr, data, **kwargs):
if isinstance(value, str):
value = check_and_convert_big_int_string_to_int(value)
return super()._deserialize(value, attr, data, **kwargs)
class _ConditionField(fields.Dict):
"""Serializes/Deserializes Conditions to/from dictionaries"""

View File

@ -1,6 +1,6 @@
import re
from http import HTTPStatus
from typing import Dict, Iterator, List, Optional, Tuple
from typing import Dict, Iterator, List, Optional, Tuple, Union
from marshmallow import Schema, post_dump
from marshmallow.exceptions import SCHEMA
@ -223,3 +223,18 @@ def extract_single_error_message_from_schema_errors(
else ""
)
return f"{message_prefix}{message}"
def check_and_convert_big_int_string_to_int(value: str) -> Union[str, int]:
"""
Check if a string is a big int string and convert it to an integer, otherwise return the string.
"""
if value.endswith("n"):
try:
result = int(value[:-1])
return result
except ValueError:
# ignore
pass
return value

View File

@ -426,16 +426,16 @@ def test_any_field_integer_str_and_no_str_conversion(integer_value):
deserialized_raw_integer = field._deserialize(
value=integer_value, attr=None, data=None
)
deserialized_string_integer = field._deserialize(
value=str(integer_value), attr=None, data=None
deserialized_big_int_string = field._deserialize(
value=f"{integer_value}n", attr=None, data=None
)
assert deserialized_raw_integer == deserialized_string_integer
assert deserialized_raw_integer == deserialized_big_int_string
assert (
field._serialize(deserialized_raw_integer, attr=None, obj=None) == integer_value
)
assert (
field._serialize(deserialized_string_integer, attr=None, obj=None)
field._serialize(deserialized_big_int_string, attr=None, obj=None)
== integer_value
)
@ -448,8 +448,8 @@ def test_any_field_nested_integer():
regular_number = 12341231
parameters = [
f"{uint256_max}",
{"a": [f"{int256_min}", "my_string_value", "0xdeadbeef"], "b": regular_number},
f"{uint256_max}n",
{"a": [f"{int256_min}n", "my_string_value", "0xdeadbeef"], "b": regular_number},
]
# quoted numbers get unquoted after deserialization
expected_parameters = [