Skip to content

Commit

Permalink
Exception Handling - Created custom exception classes (#50)
Browse files Browse the repository at this point in the history
* Add base exceptions for error handling

* update pyright version for pipeline

* reformatting for black

* using ParsingError + unit tests

* type stub for pytest

* Fixed pyright errors with pytest + formatting for black

* Renamed DeserializationError

Co-authored-by: Yefri Gaitan <yefrigaitan@gmail.com>
  • Loading branch information
eozmen410 and yefrig committed Dec 10, 2020
1 parent f80d2bd commit 3e32f01
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 31 deletions.
41 changes: 20 additions & 21 deletions tests/json_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
from hypothesis import given
from volga.fields import Int, Bool, Float, Null, Str
from volga.json import deserialize
from volga.exceptions import ParsingError


import json
import pytest # type: ignore


@given(st.integers())
Expand Down Expand Up @@ -36,24 +38,21 @@ def test_serialize_none(x: None):
assert deserialize(json.dumps(x), Null) == None


# class User(Schema):
# # name: Str
# age: Int
# score: Float
# verified: Bool


# @given(
# a=st.integers(), s=st.floats(allow_infinity=False, allow_nan=False), v=st.booleans()
# )
# def test_deserialize_user(a: int, s: float, v: bool):
# userJSON = (
# '{"age":'
# + json.dumps(a)
# + ',"score":'
# + json.dumps(s)
# + ',"verified":'
# + json.dumps(v)
# + "}"
# )
# assert deserialize(userJSON, User) == User(age=a, score=s, verified=v)
def test_parsing_error_int():
with pytest.raises(ParsingError): # type: ignore
deserialize("Not an int", Int)


def test_parsing_error_bool():
with pytest.raises(ParsingError): # type: ignore
deserialize("Not a bool", Bool)


def test_parsing_error_float():
with pytest.raises(ParsingError): # type: ignore
deserialize("Not a float", Float)


def test_parsing_error_str():
with pytest.raises(ParsingError): # type: ignore
deserialize(0, Str) # type: ignore
34 changes: 34 additions & 0 deletions typings/pytest/__init__.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
"""
This type stub file was generated by pyright.
"""

from _pytest import __version__
from _pytest.assertion import register_assert_rewrite
from _pytest.compat import _setup_collect_fakemodule
from _pytest.config import ExitCode, UsageError, cmdline, hookimpl, hookspec, main
from _pytest.debugging import pytestPDB as __pytestPDB
from _pytest.fixtures import fillfixtures as _fillfuncargs, fixture, yield_fixture
from _pytest.freeze_support import freeze_includes
from _pytest.main import Session
from _pytest.mark import MARK_GEN as mark, param
from _pytest.nodes import Collector, File, Item
from _pytest.outcomes import exit, fail, importorskip, skip, xfail
from _pytest.python import Class, Function, Instance, Module, Package
from _pytest.python_api import approx, raises
from _pytest.recwarn import deprecated_call, warns
from _pytest.warning_types import (
PytestAssertRewriteWarning,
PytestCacheWarning,
PytestCollectionWarning,
PytestConfigWarning,
PytestDeprecationWarning,
PytestExperimentalApiWarning,
PytestUnhandledCoroutineWarning,
PytestUnknownMarkWarning,
PytestWarning,
)

"""
pytest: unit and functional testing with Python.
"""
set_trace = __pytestPDB.set_trace
8 changes: 8 additions & 0 deletions typings/pytest/__main__.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"""
This type stub file was generated by pyright.
"""

"""
pytest entry point
"""
if __name__ == "__main__": ...
16 changes: 16 additions & 0 deletions volga/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
class VolgaError(Exception):
"""Base class for all volga-related errors."""

pass


class DeserializationError(VolgaError):
"""Raised during serialization errors when parsing or building object instances."""

pass


class ParsingError(VolgaError):
"""Raised during deserialization errors when parsing object instances."""

pass
24 changes: 14 additions & 10 deletions volga/json.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@


import volga.format as format
import volga.exceptions as exceptions

RE_FLAGS = re.VERBOSE | re.MULTILINE | re.DOTALL

Expand Down Expand Up @@ -48,7 +49,7 @@ def _parse_bool(self) -> bool:
self.idx += 6
return False
else:
raise RuntimeError("Expected bool")
raise exceptions.ParsingError("Expected bool")

def _parse_float(self) -> float:

Expand All @@ -61,7 +62,7 @@ def _parse_float(self) -> float:
self.idx = match.end()
return n
else:
raise RuntimeError("Expected float")
raise exceptions.ParsingError("Expected float")

def _parse_int(self) -> int:

Expand All @@ -70,24 +71,27 @@ def _parse_int(self) -> int:
if match:
integer, frac, exp = match.groups()
if frac or exp:
raise RuntimeError("Expected integer value.")
raise exceptions.ParsingError("Expected integer value.")
else:
n = int(integer)
self.idx = match.end()
return n
else:
raise RuntimeError("Expected int")
raise exceptions.ParsingError("Expected int")

def _parse_str(self) -> str:

if type(self.s) != str:
raise exceptions.ParsingError("Expected String, not " + str(type(self.s)))

if self.s[self.idx] != '"':
raise RuntimeError("Expected String")
raise exceptions.ParsingError("Expected String")

# skip past first "
chunk = STRING_RE.match(self.s, self.idx + 1)

if chunk is None:
raise RuntimeError("Unterminated string.")
raise exceptions.ParsingError("Unterminated string.")

content, _ = chunk.groups()
self.idx = chunk.end()
Expand All @@ -101,7 +105,7 @@ def _parse_none(self) -> None:
self.idx += 5
return None
else:
raise RuntimeError("Expected null")
raise exceptions.ParsingError("Expected null")

def __deserialize_str__(
self, constructor: Type[types.supportsDeser]
Expand All @@ -115,7 +119,7 @@ def __deserialize_dict__(
res = {}

if self.s[self.idx] != "{":
raise RuntimeError("Expected dict")
raise exceptions.ParsingError("Expected dict")

# for each attribute in the schema

Expand All @@ -126,15 +130,15 @@ def __deserialize_dict__(
chunk = STRING_RE.match(self.s, self.idx + 2)

if chunk is None:
raise RuntimeError("Expected key string.")
raise exceptions.ParsingError("Expected key string.")

parsed_key, _ = chunk.groups()
self.idx = chunk.end()

assert parsed_key == key

if self.s[self.idx] != ":":
raise RuntimeError("Expected value for key")
raise exceptions.ParsingError("Expected value for key")
self.idx += 1

# parse the value according to schema
Expand Down

0 comments on commit 3e32f01

Please sign in to comment.