From de09030b1c0bb0d418d81d2656a2a245416f4595 Mon Sep 17 00:00:00 2001 From: Tim Van Baak Date: Wed, 2 Jun 2021 20:05:33 -0700 Subject: [PATCH] black style pass --- amanuensis/backend/article.py | 9 ++------- amanuensis/backend/character.py | 12 ++++++------ amanuensis/backend/lexicon.py | 15 +++++---------- amanuensis/backend/membership.py | 19 +++++++++---------- amanuensis/backend/post.py | 13 +++---------- amanuensis/backend/user.py | 14 +++++++------- amanuensis/db/__init__.py | 2 +- amanuensis/db/database.py | 19 +++++++++++-------- amanuensis/db/models.py | 25 ++++++++++++++++++++----- amanuensis/errors.py | 1 + tests/conftest.py | 21 ++++++++++++++------- tests/test_character.py | 8 ++++++-- tests/test_lexicon.py | 6 +----- tests/test_post.py | 6 +----- tests/test_user.py | 6 ++++-- 15 files changed, 91 insertions(+), 85 deletions(-) diff --git a/amanuensis/backend/article.py b/amanuensis/backend/article.py index 932f70b..514ff0a 100644 --- a/amanuensis/backend/article.py +++ b/amanuensis/backend/article.py @@ -8,11 +8,7 @@ from amanuensis.db import * from amanuensis.errors import ArgumentError -def create( - db: DbContext, - lexicon_id: int, - user_id: int, - character_id: int) -> Article: +def create(db: DbContext, lexicon_id: int, user_id: int, character_id: int) -> Article: """ Create a new article in a lexicon. """ @@ -37,8 +33,7 @@ def create( # and the character belongs to the lexicon if character_id is not None: character: Character = db( - select(Character) - .where(Character.id == character_id) + select(Character).where(Character.id == character_id) ).scalar_one_or_none() if not character: raise ArgumentError('Character does not exist') diff --git a/amanuensis/backend/character.py b/amanuensis/backend/character.py index c8f04da..3606e4e 100644 --- a/amanuensis/backend/character.py +++ b/amanuensis/backend/character.py @@ -9,11 +9,8 @@ from amanuensis.errors import ArgumentError def create( - db: DbContext, - lexicon_id: int, - user_id: int, - name: str, - signature: str) -> Character: + db: DbContext, lexicon_id: int, user_id: int, name: str, signature: str +) -> Character: """ Create a new character for a user. """ @@ -50,7 +47,10 @@ def create( .where(Character.lexicon_id == lexicon_id) .where(Character.user_id == user_id) ).scalar() - if mem.lexicon.character_limit is not None and num_user_chars >= mem.lexicon.character_limit: + if ( + mem.lexicon.character_limit is not None + and num_user_chars >= mem.lexicon.character_limit + ): raise ArgumentError('User is at character limit') new_character = Character( diff --git a/amanuensis/backend/lexicon.py b/amanuensis/backend/lexicon.py index 7e20790..659abb9 100644 --- a/amanuensis/backend/lexicon.py +++ b/amanuensis/backend/lexicon.py @@ -13,11 +13,7 @@ from amanuensis.errors import ArgumentError RE_ALPHANUM_DASH_UNDER = re.compile(r'^[A-Za-z0-9-_]*$') -def create( - db: DbContext, - name: str, - title: str, - prompt: str) -> Lexicon: +def create(db: DbContext, name: str, title: str, prompt: str) -> Lexicon: """ Create a new lexicon. """ @@ -27,7 +23,9 @@ def create( if not name.strip(): raise ArgumentError('Lexicon name must not be blank') if not RE_ALPHANUM_DASH_UNDER.match(name): - raise ArgumentError('Lexicon name may only contain alphanumerics, dash, and underscore') + raise ArgumentError( + 'Lexicon name may only contain alphanumerics, dash, and underscore' + ) # Verify title if title is not None and not isinstance(name, str): @@ -38,10 +36,7 @@ def create( raise ArgumentError('Lexicon prompt must be a string') # 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: + if db(select(func.count(Lexicon.id)).where(Lexicon.name == name)).scalar() > 0: raise ArgumentError('Lexicon name is already taken') new_lexicon = Lexicon( diff --git a/amanuensis/backend/membership.py b/amanuensis/backend/membership.py index c112b01..5bc061a 100644 --- a/amanuensis/backend/membership.py +++ b/amanuensis/backend/membership.py @@ -8,11 +8,7 @@ from amanuensis.db import DbContext, Membership from amanuensis.errors import ArgumentError -def create( - db: DbContext, - user_id: int, - lexicon_id: int, - is_editor: bool) -> Membership: +def create(db: DbContext, user_id: int, lexicon_id: int, is_editor: bool) -> Membership: """ Create a new user membership in a lexicon. """ @@ -25,11 +21,14 @@ def create( raise ArgumentError('is_editor') # Verify user has not already joined lexicon - if db( - select(func.count(Membership.id)) - .where(Membership.user_id == user_id) - .where(Membership.lexicon_id == lexicon_id) - ).scalar() > 0: + if ( + db( + select(func.count(Membership.id)) + .where(Membership.user_id == user_id) + .where(Membership.lexicon_id == lexicon_id) + ).scalar() + > 0 + ): raise ArgumentError('User is already a member of lexicon') new_membership = Membership( diff --git a/amanuensis/backend/post.py b/amanuensis/backend/post.py index 9ce635f..3732be1 100644 --- a/amanuensis/backend/post.py +++ b/amanuensis/backend/post.py @@ -9,11 +9,8 @@ from sqlalchemy import select, func from amanuensis.db import DbContext, Post from amanuensis.errors import ArgumentError -def create( - db: DbContext, - lexicon_id: int, - user_id: int, - body: str) -> Post: + +def create(db: DbContext, lexicon_id: int, user_id: int, body: str) -> Post: """ Create a new post """ @@ -32,11 +29,7 @@ def create( if not body.strip(): raise ArgumentError('Post body cannot be empty.') - new_post = Post( - lexicon_id=lexicon_id, - user_id=user_id, - body=body - ) + new_post = Post(lexicon_id=lexicon_id, user_id=user_id, body=body) db.session.add(new_post) db.session.commit() return new_post diff --git a/amanuensis/backend/user.py b/amanuensis/backend/user.py index 6b30032..044b496 100644 --- a/amanuensis/backend/user.py +++ b/amanuensis/backend/user.py @@ -11,7 +11,7 @@ from amanuensis.db import DbContext, User from amanuensis.errors import ArgumentError -RE_NO_LETTERS = re.compile(r'^[0-9-_]*$') +RE_NO_LETTERS = re.compile(r'^[0-9-_]*$') RE_ALPHANUM_DASH_UNDER = re.compile(r'^[A-Za-z0-9-_]*$') @@ -21,7 +21,8 @@ def create( password: str, display_name: str, email: str, - is_site_admin: bool) -> User: + is_site_admin: bool, +) -> User: """ Create a new user. """ @@ -33,7 +34,9 @@ def create( if RE_NO_LETTERS.match(username): raise ArgumentError('Username must contain a letter') if not RE_ALPHANUM_DASH_UNDER.match(username): - raise ArgumentError('Username may only contain alphanumerics, dash, and underscore') + raise ArgumentError( + 'Username may only contain alphanumerics, dash, and underscore' + ) # Verify password if not isinstance(password, str): @@ -51,10 +54,7 @@ def create( raise ArgumentError('Email must be a string') # Query the db to make sure the username isn't taken - if db( - select(func.count(User.id)) - .where(User.username == username) - ).scalar() > 0: + if db(select(func.count(User.id)).where(User.username == username)).scalar() > 0: raise ArgumentError('Username is already taken') new_user = User( diff --git a/amanuensis/db/__init__.py b/amanuensis/db/__init__.py index ecec332..afc8c53 100644 --- a/amanuensis/db/__init__.py +++ b/amanuensis/db/__init__.py @@ -28,4 +28,4 @@ __all__ = [ 'ArticleContentRuleType', 'ArticleContentRule', 'Post', -] \ No newline at end of file +] diff --git a/amanuensis/db/database.py b/amanuensis/db/database.py index 988a6ba..254a488 100644 --- a/amanuensis/db/database.py +++ b/amanuensis/db/database.py @@ -8,22 +8,25 @@ from sqlalchemy.orm import sessionmaker # Define naming conventions for generated constraints -metadata = MetaData(naming_convention={ - "ix": "ix_%(column_0_label)s", - "uq": "uq_%(table_name)s_%(column_0_name)s", - "ck": "ck_%(table_name)s_%(constraint_name)s", - "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s", - "pk": "pk_%(table_name)s" -}) +metadata = MetaData( + naming_convention={ + "ix": "ix_%(column_0_label)s", + "uq": "uq_%(table_name)s_%(column_0_name)s", + "ck": "ck_%(table_name)s_%(constraint_name)s", + "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s", + "pk": "pk_%(table_name)s", + } +) # Base class for ORM models ModelBase = declarative_base(metadata=metadata) -class DbContext(): +class DbContext: def __init__(self, db_uri, debug=False): # Create an engine and enable foreign key constraints in sqlite self.engine = create_engine(db_uri, echo=debug) + @event.listens_for(self.engine, "connect") def set_sqlite_pragma(dbapi_connection, connection_record): cursor = dbapi_connection.cursor() diff --git a/amanuensis/db/models.py b/amanuensis/db/models.py index 1aca951..1254b94 100644 --- a/amanuensis/db/models.py +++ b/amanuensis/db/models.py @@ -28,6 +28,7 @@ class Uuid(TypeDecorator): """ A uuid backed by a char(32) field in sqlite. """ + impl = CHAR(32) def process_bind_param(self, value, dialect): @@ -51,6 +52,7 @@ class User(ModelBase): """ Represents a single user of Amanuensis. """ + __tablename__ = 'user' ############# @@ -104,6 +106,7 @@ class Lexicon(ModelBase): """ Represents a single game of Lexicon. """ + __tablename__ = 'lexicon' ############# @@ -131,7 +134,9 @@ class Lexicon(ModelBase): created = Column(DateTime, nullable=False, server_default=text('CURRENT_TIMESTAMP')) # The timestamp of the last change in game state - last_updated = Column(DateTime, nullable=False, server_default=text('CURRENT_TIMESTAMP')) + last_updated = Column( + DateTime, nullable=False, server_default=text('CURRENT_TIMESTAMP') + ) # The timestamp the first turn was started # This is NULL until the game starts @@ -234,10 +239,9 @@ class Membership(ModelBase): """ Represents a user's participation in a Lexicon game. """ + __tablename__ = 'membership' - __table_args__ = ( - UniqueConstraint('user_id', 'lexicon_id'), - ) + __table_args__ = (UniqueConstraint('user_id', 'lexicon_id'),) ################### # Membership keys # @@ -295,6 +299,7 @@ class Character(ModelBase): """ Represents a character played by a uaser in a Lexicon game. """ + __tablename__ = 'character' ################## @@ -333,6 +338,7 @@ class ArticleState(enum.Enum): """ The step of the editorial process an article is in. """ + DRAFT = 0 SUBMITTED = 1 APPROVED = 2 @@ -342,6 +348,7 @@ class Article(ModelBase): """ Represents a single article in a lexicon. """ + __tablename__ = 'article' ################ @@ -386,7 +393,9 @@ class Article(ModelBase): #################### # Timestamp the content of the article was last updated - last_updated = Column(DateTime, nullable=False, server_default=text('CURRENT_TIMESTAMP')) + last_updated = Column( + DateTime, nullable=False, server_default=text('CURRENT_TIMESTAMP') + ) # Timestamp the article was last submitted # This is NULL until the article is submitted @@ -420,6 +429,7 @@ class IndexType(enum.Enum): """ The title-matching behavior of an article index. """ + CHAR = 0 RANGE = 1 PREFIX = 2 @@ -430,6 +440,7 @@ class ArticleIndex(ModelBase): """ Represents an index definition. """ + __tablename__ = 'article_index' ############## @@ -472,6 +483,7 @@ class ArticleIndexRule(ModelBase): A character with multiple index rules may write in any index that satisfies a rule. A character with no index rules may write in any index. """ + __tablename__ = 'article_index_rule' ################### @@ -510,6 +522,7 @@ class ArticleContentRuleType(enum.Enum): """ The possible article content rules. """ + # Whether characters can cite themselves ALLOW_SELF_CITE = 0 # Whether characters can write new articles instead of phantoms @@ -543,6 +556,7 @@ class ArticleContentRule(ModelBase): """ Represents a restriction on the content of an article for a turn. """ + __tablename__ = 'article_content_rule' ##################### @@ -584,6 +598,7 @@ class Post(ModelBase): """ Represents a post in the game feed. """ + __tablename__ = 'post' ############# diff --git a/amanuensis/errors.py b/amanuensis/errors.py index dca7c6f..b6a9145 100644 --- a/amanuensis/errors.py +++ b/amanuensis/errors.py @@ -2,6 +2,7 @@ Submodule of custom exception types """ + class AmanuensisError(Exception): """Base class for exceptions in amanuensis""" diff --git a/tests/conftest.py b/tests/conftest.py index dc6662a..eb2ba4c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -21,6 +21,7 @@ def db(): @pytest.fixture def make_user(db: DbContext): """Provides a factory function for creating users, with valid default values.""" + def user_factory(state={'nonce': 1}, **kwargs): default_kwargs = { 'username': f'test_user_{state["nonce"]}', @@ -32,39 +33,45 @@ def make_user(db: DbContext): state['nonce'] += 1 updated_kwargs = {**default_kwargs, **kwargs} return userq.create(db, **updated_kwargs) + return user_factory @pytest.fixture def make_lexicon(db: DbContext): """Provides a factory function for creating lexicons, with valid default values.""" + def lexicon_factory(state={'nonce': 1}, **kwargs): default_kwargs = { 'name': f'Test_{state["nonce"]}', 'title': None, - 'prompt': f'Test Lexicon game {state["nonce"]}' + 'prompt': f'Test Lexicon game {state["nonce"]}', } state['nonce'] += 1 updated_kwargs = {**default_kwargs, **kwargs} return lexiq.create(db, **updated_kwargs) + return lexicon_factory @pytest.fixture def make_membership(db: DbContext): """Provides a factory function for creating memberships, with valid default values.""" + def membership_factory(**kwargs): default_kwargs = { 'is_editor': False, } updated_kwargs = {**default_kwargs, **kwargs} return memq.create(db, **updated_kwargs) + return membership_factory @pytest.fixture def make_character(db: DbContext): """Provides a factory function for creating characters, with valid default values.""" + def character_factory(state={'nonce': 1}, **kwargs): default_kwargs = { 'name': f'Character {state["nonce"]}', @@ -73,6 +80,7 @@ def make_character(db: DbContext): state['nonce'] += 1 updated_kwargs = {**default_kwargs, **kwargs} return charq.create(db, **updated_kwargs) + return character_factory @@ -87,11 +95,8 @@ class TestFactory: @pytest.fixture def make( - db: DbContext, - make_user, - make_lexicon, - make_membership, - make_character) -> TestFactory: + db: DbContext, make_user, make_lexicon, make_membership, make_character +) -> TestFactory: """Fixture that groups all factory fixtures together.""" return TestFactory( db, @@ -109,6 +114,8 @@ def lexicon_with_editor(make): assert editor lexicon = make.lexicon() assert lexicon - membership = make.membership(user_id=editor.id, lexicon_id=lexicon.id, is_editor=True) + membership = make.membership( + user_id=editor.id, lexicon_id=lexicon.id, is_editor=True + ) assert membership return (lexicon, editor) diff --git a/tests/test_character.py b/tests/test_character.py index 0a1e2e5..ac5c2b1 100644 --- a/tests/test_character.py +++ b/tests/test_character.py @@ -52,7 +52,9 @@ def test_character_limits(db: DbContext, lexicon_with_editor): # Creating a second character should fail with pytest.raises(ArgumentError): - char2 = charq.create(db, lexicon.id, user.id, 'Test Character 2', signature=None) + char2 = charq.create( + db, lexicon.id, user.id, 'Test Character 2', signature=None + ) assert char2 # Raising the limit to 2 should allow a second character @@ -63,7 +65,9 @@ def test_character_limits(db: DbContext, lexicon_with_editor): # Creating a third character should fail with pytest.raises(ArgumentError): - char3 = charq.create(db, lexicon.id, user.id, 'Test Character 3', signature=None) + char3 = charq.create( + db, lexicon.id, user.id, 'Test Character 3', signature=None + ) assert char3 # Setting the limit to null should allow a third character diff --git a/tests/test_lexicon.py b/tests/test_lexicon.py index b0dfe9b..2dfd202 100644 --- a/tests/test_lexicon.py +++ b/tests/test_lexicon.py @@ -9,11 +9,7 @@ from amanuensis.errors import ArgumentError def test_create_lexicon(db: DbContext): """Test new game creation.""" - kwargs = { - 'name': 'Test', - 'title': None, - 'prompt': 'A test Lexicon game' - } + kwargs = {'name': 'Test', 'title': None, 'prompt': 'A test Lexicon game'} # Test name constraints with pytest.raises(ArgumentError): lexiq.create(db, **{**kwargs, 'name': None}) diff --git a/tests/test_post.py b/tests/test_post.py index 0e14cdd..552bfa7 100644 --- a/tests/test_post.py +++ b/tests/test_post.py @@ -11,11 +11,7 @@ def test_create_post(db: DbContext, lexicon_with_editor): lexicon, editor = lexicon_with_editor # argument dictionary for post object - kwargs = { - 'lexicon_id': lexicon.id, - 'user_id': editor.id, - 'body': 'body' - } + kwargs = {'lexicon_id': lexicon.id, 'user_id': editor.id, 'body': 'body'} # ids are integers with pytest.raises(ArgumentError): diff --git a/tests/test_user.py b/tests/test_user.py index 099f871..563d25b 100644 --- a/tests/test_user.py +++ b/tests/test_user.py @@ -12,14 +12,16 @@ def test_create_user(db: DbContext): 'password': 'password', 'display_name': 'User Name', 'email': 'user@example.com', - 'is_site_admin': False + 'is_site_admin': False, } # Test length constraints with pytest.raises(ArgumentError): userq.create(db, **{**kwargs, 'username': 'me'}) with pytest.raises(ArgumentError): - userq.create(db, **{**kwargs, 'username': 'the right honorable user-name, esquire'}) + userq.create( + db, **{**kwargs, 'username': 'the right honorable user-name, esquire'} + ) # Test allowed characters with pytest.raises(ArgumentError): userq.create(db, **{**kwargs, 'username': 'user name'})