Make backend argument type errors more specific
This commit is contained in:
parent
d6f558a92b
commit
7645c85c9d
@ -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(
|
||||
|
@ -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():
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -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 (
|
||||
|
@ -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.")
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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):
|
||||
|
@ -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": ""}
|
||||
|
@ -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)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user