Make backend argument type errors more specific

This commit is contained in:
Tim Van Baak 2021-08-13 16:38:47 -07:00
parent d6f558a92b
commit 7645c85c9d
12 changed files with 63 additions and 53 deletions

View File

@ -7,7 +7,7 @@ from typing import Optional
from sqlalchemy import select
from amanuensis.db import *
from amanuensis.errors import ArgumentError
from amanuensis.errors import ArgumentError, BackendArgumentTypeError
def create(
@ -21,11 +21,11 @@ def create(
"""
# Verify argument types are correct
if not isinstance(lexicon_id, int):
raise ArgumentError("lexicon_id")
raise BackendArgumentTypeError(int, lexicon_id=lexicon_id)
if not isinstance(user_id, int):
raise ArgumentError("user_id")
raise BackendArgumentTypeError(int, user_id=user_id)
if character_id is not None and not isinstance(character_id, int):
raise ArgumentError("character_id")
raise BackendArgumentTypeError(int, character_id=character_id)
# Check that the user is a member of this lexicon
mem: Membership = db(

View File

@ -7,7 +7,7 @@ from typing import Optional
from sqlalchemy import select, func
from amanuensis.db import *
from amanuensis.errors import ArgumentError
from amanuensis.errors import ArgumentError, BackendArgumentTypeError
def create(
@ -22,13 +22,13 @@ def create(
"""
# Verify argument types are correct
if not isinstance(lexicon_id, int):
raise ArgumentError("lexicon_id")
raise BackendArgumentTypeError(int, lexicon_id=lexicon_id)
if not isinstance(user_id, int):
raise ArgumentError("user_id")
raise BackendArgumentTypeError(int, user_id=user_id)
if not isinstance(name, str):
raise ArgumentError("name")
raise BackendArgumentTypeError(str, name=name)
if signature is not None and not isinstance(signature, str):
raise ArgumentError("signature")
raise BackendArgumentTypeError(str, signature=signature)
# Verify character name is valid
if not name.strip():

View File

@ -6,7 +6,7 @@ import re
from typing import Optional
from amanuensis.db import DbContext, ArticleIndex, IndexType
from amanuensis.errors import ArgumentError
from amanuensis.errors import ArgumentError, BackendArgumentTypeError
def create(
@ -23,17 +23,17 @@ def create(
"""
# Verify argument types are correct
if not isinstance(lexicon_id, int):
raise ArgumentError("lexicon_id")
raise BackendArgumentTypeError(int, lexicon_id=lexicon_id)
if not isinstance(index_type, IndexType):
raise ArgumentError("index_type")
raise BackendArgumentTypeError(IndexType, index_type=index_type)
if not isinstance(pattern, str):
raise ArgumentError("pattern")
raise BackendArgumentTypeError(str, pattern=pattern)
if not isinstance(logical_order, int):
raise ArgumentError("logical_order")
raise BackendArgumentTypeError(int, logical_order=logical_order)
if not isinstance(display_order, int):
raise ArgumentError("display_order")
raise BackendArgumentTypeError(int, display_order=display_order)
if capacity is not None and not isinstance(capacity, int):
raise ArgumentError("capacity")
raise BackendArgumentTypeError(int, capacity=capacity)
# Verify the pattern is valid for the index type:
if index_type == IndexType.CHAR:

View File

@ -8,7 +8,7 @@ from typing import Sequence, Optional
from sqlalchemy import select, func
from amanuensis.db import DbContext, Lexicon, Membership
from amanuensis.errors import ArgumentError
from amanuensis.errors import ArgumentError, BackendArgumentTypeError
RE_ALPHANUM_DASH_UNDER = re.compile(r"^[A-Za-z0-9-_]*$")
@ -25,7 +25,7 @@ def create(
"""
# Verify name
if not isinstance(name, str):
raise ArgumentError("Lexicon name must be a string")
raise BackendArgumentTypeError(str, name=name)
if not name.strip():
raise ArgumentError("Lexicon name must not be blank")
if not RE_ALPHANUM_DASH_UNDER.match(name):
@ -34,12 +34,12 @@ def create(
)
# Verify title
if title is not None and not isinstance(name, str):
raise ArgumentError("Lexicon name must be a string")
if title is not None and not isinstance(title, str):
raise BackendArgumentTypeError(str, title=title)
# Verify prompt
if not isinstance(prompt, str):
raise ArgumentError("Lexicon prompt must be a string")
raise BackendArgumentTypeError(str, prompt=prompt)
# Query the db to make sure the lexicon name isn't taken
if db(select(func.count(Lexicon.id)).where(Lexicon.name == name)).scalar() > 0:

View File

@ -6,7 +6,7 @@ from sqlalchemy import select, func
from amanuensis.db import DbContext, Membership
from amanuensis.db.models import Lexicon
from amanuensis.errors import ArgumentError
from amanuensis.errors import ArgumentError, BackendArgumentTypeError
def create(
@ -20,11 +20,11 @@ def create(
"""
# Verify argument types are correct
if not isinstance(user_id, int):
raise ArgumentError("user_id")
raise BackendArgumentTypeError(int, user_id=user_id)
if not isinstance(lexicon_id, int):
raise ArgumentError("lexicon_id")
raise BackendArgumentTypeError(int, lexicon_id=lexicon_id)
if not isinstance(is_editor, bool):
raise ArgumentError("is_editor")
raise BackendArgumentTypeError(bool, is_editor=is_editor)
# Verify user has not already joined lexicon
if (

View File

@ -8,7 +8,7 @@ from sqlalchemy import select
from amanuensis.db import DbContext, Post
from amanuensis.db.models import Lexicon
from amanuensis.errors import ArgumentError
from amanuensis.errors import ArgumentError, BackendArgumentTypeError
def create(
@ -23,15 +23,15 @@ def create(
# Verify lexicon id
if not isinstance(lexicon_id, int):
raise ArgumentError("Lexicon id must be an integer.")
raise BackendArgumentTypeError(int, lexicon_id=lexicon_id)
# Verify user_id
if not (isinstance(user_id, int) or user_id is None):
raise ArgumentError("User id must be an integer.")
if user_id is not None and not isinstance(user_id, int):
raise BackendArgumentTypeError(int, user_id=user_id)
# Verify body
if not isinstance(body, str):
raise ArgumentError("Post body must be a string.")
raise BackendArgumentTypeError(str, body=body)
if not body.strip():
raise ArgumentError("Post body cannot be empty.")

View File

@ -10,7 +10,7 @@ from sqlalchemy import select, func, update
from werkzeug.security import generate_password_hash, check_password_hash
from amanuensis.db import DbContext, User
from amanuensis.errors import ArgumentError
from amanuensis.errors import ArgumentError, BackendArgumentTypeError
RE_NO_LETTERS = re.compile(r"^[0-9-_]*$")
@ -30,7 +30,7 @@ def create(
"""
# Verify username
if not isinstance(username, str):
raise ArgumentError("Username must be a string")
raise BackendArgumentTypeError(str, username=username)
if len(username) < 3 or len(username) > 32:
raise ArgumentError("Username must be between 3 and 32 characters")
if RE_NO_LETTERS.match(username):
@ -42,18 +42,18 @@ def create(
# Verify password
if not isinstance(password, str):
raise ArgumentError("Password must be a string")
raise BackendArgumentTypeError(str, password=password)
# Verify display name
if display_name is not None and not isinstance(display_name, str):
raise ArgumentError("Display name must be a string")
raise BackendArgumentTypeError(str, display_name=display_name)
# If display name is not provided, use the username
if not display_name or not display_name.strip():
display_name = username
# Verify email
if not isinstance(email, str):
raise ArgumentError("Email must be a string")
raise BackendArgumentTypeError(str, email=email)
# Query the db to make sure the username isn't taken
if db(select(func.count(User.id)).where(User.username == username)).scalar() > 0:

View File

@ -4,8 +4,21 @@ Submodule of custom exception types
class AmanuensisError(Exception):
"""Base class for exceptions in amanuensis"""
"""Base class for exceptions in Amanuensis"""
class ArgumentError(AmanuensisError):
"""An internal call was made with invalid arguments"""
"""An internal call was made with invalid arguments."""
class BackendArgumentTypeError(ArgumentError):
"""
A call to a backend function was made with a value of an invalid type for the parameter.
Specify the invalid parameter and value as a kwarg.
"""
def __init__(self, obj_type, **kwarg):
if not kwarg:
raise ValueError("Missing kwarg")
param, value = next(iter(kwarg.items()))
msg = f"Expected {param} of type {obj_type}, got {type(value)}"
super().__init__(msg)

View File

@ -2,7 +2,7 @@ import pytest
from amanuensis.backend import charq
from amanuensis.db import *
from amanuensis.errors import ArgumentError
from amanuensis.errors import ArgumentError, BackendArgumentTypeError
def test_create_character(db: DbContext, lexicon_with_editor, make):
@ -20,13 +20,13 @@ def test_create_character(db: DbContext, lexicon_with_editor, make):
kwargs: dict
# Bad argument types
with pytest.raises(ArgumentError):
with pytest.raises(BackendArgumentTypeError):
kwargs = {**defaults, "name": b"bytestring"}
charq.create(**kwargs)
with pytest.raises(ArgumentError):
with pytest.raises(BackendArgumentTypeError):
kwargs = {**defaults, "name": None}
charq.create(**kwargs)
with pytest.raises(ArgumentError):
with pytest.raises(BackendArgumentTypeError):
kwargs = {**defaults, "signature": b"bytestring"}
charq.create(**kwargs)

View File

@ -5,7 +5,7 @@ import pytest
from amanuensis.backend import lexiq
from amanuensis.db import DbContext, Lexicon, User
from amanuensis.errors import ArgumentError
from amanuensis.errors import ArgumentError, BackendArgumentTypeError
from tests.conftest import ObjectFactory
@ -20,7 +20,7 @@ def test_create_lexicon(db: DbContext):
kwargs: dict
# Test name constraints
with pytest.raises(ArgumentError):
with pytest.raises(BackendArgumentTypeError):
kwargs = {**defaults, "name": None}
lexiq.create(**kwargs)
with pytest.raises(ArgumentError):

View File

@ -3,7 +3,7 @@ import pytest
from amanuensis.backend import postq
from amanuensis.db import DbContext
from amanuensis.errors import ArgumentError
from amanuensis.errors import ArgumentError, BackendArgumentTypeError
def test_create_post(db: DbContext, lexicon_with_editor):
@ -20,19 +20,16 @@ def test_create_post(db: DbContext, lexicon_with_editor):
kwargs: dict
# ids are integers
with pytest.raises(ArgumentError):
with pytest.raises(BackendArgumentTypeError):
kwargs = {**defaults, "user_id": "zero"}
postq.create(**kwargs)
with pytest.raises(ArgumentError):
with pytest.raises(BackendArgumentTypeError):
kwargs = {**defaults, "lexicon_id": "zero"}
postq.create(**kwargs)
# empty arguments don't work
with pytest.raises(ArgumentError):
kwargs = {**defaults, "lexicon_id": ""}
postq.create(**kwargs)
with pytest.raises(ArgumentError):
kwargs = {**defaults, "user_id": ""}
with pytest.raises(BackendArgumentTypeError):
kwargs = {**defaults, "lexicon_id": None}
postq.create(**kwargs)
with pytest.raises(ArgumentError):
kwargs = {**defaults, "body": ""}

View File

@ -4,7 +4,7 @@ import pytest
from amanuensis.backend import userq
from amanuensis.db import DbContext, User
from amanuensis.errors import ArgumentError
from amanuensis.errors import ArgumentError, BackendArgumentTypeError
def test_create_user(db: DbContext):
@ -33,7 +33,7 @@ def test_create_user(db: DbContext):
userq.create(**kwargs)
# No password
with pytest.raises(ArgumentError):
with pytest.raises(BackendArgumentTypeError):
kwargs = {**defaults, "password": None}
userq.create(**kwargs)