mirror of
https://github.com/sprockets/sprockets.mixins.mediatype.git
synced 2024-12-27 11:17:30 +00:00
Rejected serialization of non-pair sequences.
This required a bit of change in _encode to detect non-pair sequences that are also not strings or byte strings.
This commit is contained in:
parent
e99d41a8b4
commit
4fd3864c04
2 changed files with 40 additions and 22 deletions
|
@ -323,36 +323,35 @@ class FormUrlEncodedTranscoder:
|
|||
|
||||
"""
|
||||
# Select the appropriate encoding table and use the default
|
||||
# character encoding if necessary. Binding these to locals
|
||||
# removes branches from the inner loop.
|
||||
# character encoding if necessary. Binding these to local
|
||||
# names removes branches from the inner loop.
|
||||
chr_map: typing.Mapping[int, str]
|
||||
chr_map = (_FORM_URLENCODING_PLUS
|
||||
if self.options.space_as_plus else _FORM_URLENCODING)
|
||||
if encoding is None:
|
||||
encoding = self.options.encoding
|
||||
|
||||
# Generate a sequence of name+value tuples to encode
|
||||
if isinstance(inst_data, type_info.SerializablePrimitives):
|
||||
encoded = self._encode(inst_data, chr_map, encoding)
|
||||
return self.content_type, encoded.encode('ascii')
|
||||
# Generate a sequence of name+value tuples to encode or
|
||||
# directly encode primitives
|
||||
try:
|
||||
tuples = self._convert_to_tuple_sequence(inst_data)
|
||||
except TypeError:
|
||||
# hopefully this is a primitive ... if not then the
|
||||
# call to _encode will fail below
|
||||
tuples = [(inst_data, None)]
|
||||
|
||||
if isinstance(inst_data, collections.abc.Mapping):
|
||||
tuples = inst_data.items()
|
||||
else:
|
||||
tuples = inst_data
|
||||
|
||||
# Encode each pair and run the encoded form through the
|
||||
# appropriate octet to string mapping table
|
||||
prefix = '' # micro-optimization removes if statement from inner loop
|
||||
prefix = '' # another micro-optimization
|
||||
buf = []
|
||||
for name, value in tuples:
|
||||
buf.append(prefix)
|
||||
buf.extend(self._encode(name, chr_map, encoding))
|
||||
buf.append('=')
|
||||
buf.extend(self._encode(value, chr_map, encoding))
|
||||
if value is not None:
|
||||
buf.append('=')
|
||||
buf.extend(self._encode(value, chr_map, encoding))
|
||||
prefix = '&'
|
||||
encoded = ''.join(buf)
|
||||
|
||||
return self.content_type, ''.join(buf).encode('ascii')
|
||||
return self.content_type, encoded.encode('ascii')
|
||||
|
||||
def from_bytes(
|
||||
self,
|
||||
|
@ -398,19 +397,32 @@ class FormUrlEncodedTranscoder:
|
|||
try:
|
||||
datum = self.options.literal_mapping[datum] # type: ignore
|
||||
except (KeyError, TypeError):
|
||||
if datum in {None, True, False}:
|
||||
if isinstance(datum, (bytearray, bytes, memoryview)):
|
||||
return ''.join(char_map[c] for c in datum)
|
||||
|
||||
if datum is None or isinstance(datum, bool):
|
||||
raise TypeError(
|
||||
f'{datum.__class__.__name__} is not serializable'
|
||||
) from None
|
||||
|
||||
if isinstance(datum, (float, int, str)):
|
||||
datum = str(datum)
|
||||
elif hasattr(datum, 'isoformat'):
|
||||
elif datum is not None and hasattr(datum, 'isoformat'):
|
||||
datum = datum.isoformat()
|
||||
elif isinstance(datum, (bytearray, bytes, memoryview)):
|
||||
return ''.join(char_map[c] for c in datum)
|
||||
else:
|
||||
raise TypeError(
|
||||
f'{datum.__class__.__name__} is not serializable'
|
||||
) from None
|
||||
|
||||
return ''.join(char_map[c] for c in datum.encode(encoding))
|
||||
|
||||
@staticmethod
|
||||
def _convert_to_tuple_sequence(
|
||||
value: type_info.Serializable
|
||||
) -> typing.Iterable[typing.Tuple[typing.Any, typing.Any]]:
|
||||
if isinstance(value, collections.abc.Mapping):
|
||||
return value.items()
|
||||
try:
|
||||
return [(a, b) for a, b in value] # type: ignore
|
||||
except (TypeError, ValueError):
|
||||
raise TypeError
|
||||
|
|
8
tests.py
8
tests.py
|
@ -589,7 +589,7 @@ class FormUrlEncodingTranscoderTests(unittest.TestCase):
|
|||
('', None),
|
||||
('name', None),
|
||||
])
|
||||
self.assertEqual(b'=&=true&=false&=&name=', result)
|
||||
self.assertEqual(b'=&=true&=false&&name', result)
|
||||
|
||||
def test_serialization_using_plusses(self):
|
||||
self.transcoder: transcoders.FormUrlEncodedTranscoder
|
||||
|
@ -643,3 +643,9 @@ class FormUrlEncodingTranscoderTests(unittest.TestCase):
|
|||
for value in {None, True, False}:
|
||||
with self.assertRaises(TypeError):
|
||||
self.transcoder.to_bytes(value)
|
||||
|
||||
def test_serialization_of_sequences(self):
|
||||
sequence = [[1, 2, 3], {1, 2, 3}, (1, 2, 3)]
|
||||
for value in sequence:
|
||||
with self.assertRaises(TypeError):
|
||||
self.transcoder.to_bytes(value)
|
||||
|
|
Loading…
Reference in a new issue