Skip to content

Commit

Permalink
Add error when trying to parse the bad type
Browse files Browse the repository at this point in the history
  • Loading branch information
Rémy Lavainne committed Jul 16, 2024
2 parents 6b6fe8b + 6e8d384 commit d0baeac
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 6 deletions.
1 change: 1 addition & 0 deletions src/pyckson/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from pyckson.json import *
from pyckson.parser import parse
from pyckson.parsers.base import Parser
from pyckson.parsers.base import ParserException
from pyckson.serializer import serialize
from pyckson.serializers.base import Serializer
from pyckson.dates.helpers import configure_date_formatter, configure_explicit_nulls
Expand Down
18 changes: 17 additions & 1 deletion src/pyckson/parsers/base.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
from decimal import Decimal
from enum import Enum

class ParserException(Exception):
pass


class Parser:
def parse(self, json_value):
Expand All @@ -17,6 +20,8 @@ def __init__(self, cls):
self.cls = cls

def parse(self, json_value):
if not isinstance(json_value, self.cls):
raise ParserException(f'"{json_value}" is supposed to be a {self.cls.__name__}.')
return self.cls(json_value)


Expand All @@ -26,6 +31,8 @@ def __init__(self, sub_parser: Parser):
self.cls = list

def parse(self, json_value):
if not isinstance(json_value, list):
raise ParserException(f'"{json_value}" is supposed to be a list.')
return [self.sub_parser.parse(item) for item in json_value]


Expand All @@ -35,6 +42,8 @@ def __init__(self, sub_parser: Parser):
self.cls = set

def parse(self, json_value):
if not isinstance(json_value, set) and not isinstance(json_value, list):
raise ParserException(f'"{json_value}" is supposed to be a set or a list.')
return {self.sub_parser.parse(item) for item in json_value}


Expand All @@ -43,6 +52,8 @@ def __init__(self, cls):
self.cls = cls

def parse(self, value):
if value not in self.cls.__members__:
raise ParserException(f'"{value}" is not a valid value for "{self.cls.__name__}" Enum.')
return self.cls[value]


Expand All @@ -52,6 +63,8 @@ def __init__(self, cls):
self.cls = Enum

def parse(self, value):
if value.lower() not in self.values:
raise ParserException(f'"{value}" is not a valid value for "{self.cls.__name__}" Enum.')
return self.values[value.lower()]


Expand Down Expand Up @@ -88,5 +101,8 @@ def __init__(self, value_parsers: list[Parser]):
def parse(self, json_value):
for parser in self.value_parsers:
if hasattr(parser, 'cls') and isinstance(json_value, parser.cls):
return parser.parse(json_value)
try:
return parser.parse(json_value)
except:
pass
raise TypeError(f'{json_value} is not compatible with Union type in Pyckson.')
59 changes: 58 additions & 1 deletion tests/parsers/test_base.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,20 @@
from assertpy import assert_that

from pyckson.parsers.base import UnionParser, BasicParserWithCast, ListParser, TypingDictParser, BasicParser
from pyckson.parsers.base import ParserException, SetParser, UnionParser, BasicParserWithCast, ListParser, BasicParser


class TestBasicParserWithCast:
def test_should_handle_simple_type(self):
parser = BasicParserWithCast(int)

result = parser.parse(5)

assert_that(result).is_equal_to(5)

def test_should_raise_when_it_is_not_the_correct_type(self):
parser = BasicParserWithCast(str)

assert_that(parser.parse).raises(ParserException).when_called_with(5)


class TestUnionParser:
Expand Down Expand Up @@ -29,3 +43,46 @@ def test_should_not_raise_if_parser_does_not_have_cls(self):
result = parser.parse(5)

assert_that(result).is_equal_to(5)

def test_should_parse_list_of_list_in_union(self):
parser = UnionParser([ListParser(BasicParserWithCast(int)), ListParser(ListParser(BasicParserWithCast(int)))])

result = parser.parse([[5], [6]])

assert result == [[5], [6]]



class TestListParser:
def test_should_accept_list(self):
parser = ListParser(BasicParserWithCast(int))

result = parser.parse([5])

assert_that(result).is_equal_to([5])

def test_should_raise_when_parse_other_than_list(self):
parser = ListParser(BasicParserWithCast(int))

assert_that(parser.parse).raises(ParserException).when_called_with(5)


class TestSetParser:
def test_should_accept_set(self):
parser = SetParser(BasicParserWithCast(int))

result = parser.parse({5})

assert_that(result).is_equal_to({5})

def test_should_accept_list_as_set(self):
parser = SetParser(BasicParserWithCast(int))

result = parser.parse([5])

assert_that(result).is_equal_to({5})

def test_should_raise_when_parse_other_than_list(self):
parser = SetParser(BasicParserWithCast(int))

assert_that(parser.parse).raises(ParserException).when_called_with(5)
8 changes: 4 additions & 4 deletions tests/parsers/test_enum.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from enum import Enum
from unittest import TestCase

from pyckson.parsers.base import DefaultEnumParser, CaseInsensitiveEnumParser
from pyckson.parsers.base import DefaultEnumParser, CaseInsensitiveEnumParser, ParserException


class MyEnum(Enum):
Expand All @@ -20,11 +20,11 @@ def test_should_parse_value_in_enum(self):
self.assertEqual(self.parser.parse('b'), MyEnum.b)

def test_should_not_parse_uppercase_not_in_enum(self):
with self.assertRaises(KeyError):
with self.assertRaises(ParserException):
self.parser.parse('B')

def test_should_not_parse_value_not_in_enum(self):
with self.assertRaises(KeyError):
with self.assertRaises(ParserException):
self.parser.parse('c')


Expand All @@ -46,5 +46,5 @@ def test_should_parse_case_insensitive(self):
self.assertEqual(self.parser.parse('b'), MyInsensitiveEnum.B)

def test_should_not_parse_value_not_in_enum(self):
with self.assertRaises(KeyError):
with self.assertRaises(ParserException):
self.parser.parse('c')

0 comments on commit d0baeac

Please sign in to comment.