From fa2230d5cf9b960021ecfd8247ff05bd2a248629 Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sat, 24 Feb 2024 23:42:55 +0100 Subject: [PATCH] flake8 compliant --- src/database/classes.py | 50 ++++++++++++++------- src/database/utils.py | 28 ++++++++---- src/main.py | 7 ++- src/model_experiential/__init__.py | 23 ---------- src/model_experiential/classes.py | 18 +++++--- src/model_interpersonal/__init__.py | 2 +- src/model_interpersonal/classes.py | 17 ++++--- src/model_textual/__init__.py | 2 +- src/model_textual/classes.py | 19 +++++--- src/web/app.py | 12 ++--- src/web/layout/__init__.py | 2 +- src/web/layout/alerts.py | 2 +- src/web/layout/body.py | 4 +- src/web/layout/inputs.py | 2 +- src/web/layout/labels.py | 31 ++++++++++--- src/web/layout/layout.py | 1 - src/web/layout/stores.py | 8 ++-- tests/test_generate_random_prediction.py | 8 +++- tests/test_image_upload.py | 6 ++- tests/test_model_outputs_from_annotation.py | 11 ++--- tests/test_prediction_upload.py | 6 ++- tests/test_total_annotated.py | 2 +- tests/test_total_documents.py | 2 +- 23 files changed, 157 insertions(+), 106 deletions(-) diff --git a/src/database/classes.py b/src/database/classes.py index 06387a0..2fcda2a 100644 --- a/src/database/classes.py +++ b/src/database/classes.py @@ -25,6 +25,11 @@ from src.model_textual import ( SalienceModelOutput ) + +class NoDocumentFoundException(Exception): + pass + + class ModelOutputs(BaseModel): visual_syntax: VisualSyntaxModelOutput contact: ContactModelOutput @@ -52,7 +57,7 @@ class ModelOutputs(BaseModel): in cls.model_fields.items() } return cls(**kwargs) - + @classmethod def from_annotations( cls, @@ -70,17 +75,28 @@ class ModelOutputs(BaseModel): ) -> ModelOutputs: """Instantiate from annotation.""" kwargs = { - "visual_syntax": VisualSyntaxModelOutput.from_choice(visual_syntax), - "contact": ContactModelOutput.from_choice(contact), - "angle": AngleModelOutput.from_choice(angle), - "point_of_view": PointOfViewModelOutput.from_choice(point_of_view), - "distance": DistanceModelOutput.from_choice(distance), - "modality_lighting": ModalityLightingModelOutput.from_choice(modality_lighting), - "modality_color": ModalityColorModelOutput.from_choice(modality_color), - "modality_depth": ModalityDepthModelOutput.from_choice(modality_depth), - "information_value": InformationValueModelOutput.from_choice(information_value), - "framing": FramingModelOutput.from_choice(framing), - "salience": SalienceModelOutput.from_choice(salience) + "visual_syntax": VisualSyntaxModelOutput + .from_choice(visual_syntax), + "contact": ContactModelOutput + .from_choice(contact), + "angle": AngleModelOutput + .from_choice(angle), + "point_of_view": PointOfViewModelOutput + .from_choice(point_of_view), + "distance": DistanceModelOutput + .from_choice(distance), + "modality_lighting": ModalityLightingModelOutput + .from_choice(modality_lighting), + "modality_color": ModalityColorModelOutput + .from_choice(modality_color), + "modality_depth": ModalityDepthModelOutput + .from_choice(modality_depth), + "information_value": InformationValueModelOutput + .from_choice(information_value), + "framing": FramingModelOutput + .from_choice(framing), + "salience": SalienceModelOutput + .from_choice(salience) } return cls(**kwargs) @@ -115,7 +131,10 @@ class VisualCommunication(BaseModel): @field_validator("image", mode="before") @classmethod - def convert_to_image(cls, image: Image.Image | BytesIO | bytes) -> Image.Image: + def convert_to_image( + cls, + image: Image.Image | BytesIO | bytes + ) -> Image.Image: if isinstance(image, bytes): image = BytesIO(image) if isinstance(image, BytesIO): @@ -124,7 +143,7 @@ class VisualCommunication(BaseModel): def __repr__(self) -> str: return f"{self.classname()}(name='{self.name}')" - + def webencoded_image(self) -> str: """Convert image to be displayed on webpage.""" # convert images to bytes string @@ -138,6 +157,3 @@ class VisualCommunication(BaseModel): if not force and self.prediction is not None: logging.warning("set force=True to overwrite existing values.") self.prediction = ModelOutputs.from_random() - -class NoDocumentFoundException(Exception): - pass diff --git a/src/database/utils.py b/src/database/utils.py index 9a08025..22bf085 100644 --- a/src/database/utils.py +++ b/src/database/utils.py @@ -20,15 +20,17 @@ def total_annotated( ) -> int: """Get total number of annotated documents in database.""" query = { - "annotation": { "$ne": None } + "annotation": { + "$ne": None + } } return collection.count_documents(filter=query) def get_visual_communication( - collection: Collection, - with_annotation: bool = False - ) -> VisualCommunication: + collection: Collection, + with_annotation: bool = False +) -> VisualCommunication: """Get a random visual communication from the database.""" query = {} if with_annotation: @@ -36,8 +38,14 @@ def get_visual_communication( else: query["annotation"] = None data = collection.aggregate([ - { "$match": query }, # find using filters - { "$sample": { "size": 1 } } # get one random + { + "$match": query # find using filters + }, + { + "$sample": { + "size": 1 # get one random + } + } ]) data = list(data) # read data from cursor object if len(data) == 0: @@ -58,7 +66,9 @@ def upsert_predictions( "name": vis_com_name } update = { - "$set": { "prediction": predictions.model_dump() } + "$set": { + "prediction": predictions.model_dump() + } } res = collection.update_one( filter=query, @@ -79,7 +89,9 @@ def upsert_annotations( "name": vis_com_name } update = { - "$set": { "annotation": annotations.model_dump() } + "$set": { + "annotation": annotations.model_dump() + } } res = collection.update_one( filter=query, diff --git a/src/main.py b/src/main.py index d2326aa..597f8e7 100644 --- a/src/main.py +++ b/src/main.py @@ -1,9 +1,10 @@ import logging from dotenv import load_dotenv from pathlib import Path -import logging import os +from src.web import app + # prepare optional local setup env_path = Path(__file__).parent.parent / "local.env" load_dotenv(env_path) @@ -38,8 +39,6 @@ datefmt = '%Y-%m-%d %H:%M:%S' logging.basicConfig(format=fmt, datefmt=datefmt, level=logging.INFO) logging.info("initialized app") - -from src.web import app server = app.server if __name__ == "__main__": @@ -47,4 +46,4 @@ if __name__ == "__main__": os.environ["MONGO_HOST"] = "localhost" # run app app.run(debug=True) - logging.info("started app") \ No newline at end of file + logging.info("started app") diff --git a/src/model_experiential/__init__.py b/src/model_experiential/__init__.py index 7842596..a63e45d 100644 --- a/src/model_experiential/__init__.py +++ b/src/model_experiential/__init__.py @@ -1,24 +1 @@ from .classes import VisualSyntaxModelOutput - - - -# CLASS_NAME_LIST = Literal[ -# "non transactional action", -# "non transactional reaction", -# "unidirectional transactional action", -# "unidirectional transactional reaction", -# "bidirectional transactional action", -# "bidirectional transactional reaction", -# "conversion", -# "speech process", -# "classification overt taxonomy", -# "analytical exhaustive", -# "analytical disarranged", -# "analytical temporal", -# "analytical distributed", -# "anaytical topological", -# "analytical exploded", -# "analytical inclusive", -# "symbolic suggestive", -# "symbolic attributive" -# ] \ No newline at end of file diff --git a/src/model_experiential/classes.py b/src/model_experiential/classes.py index cd8e9e0..1739af4 100644 --- a/src/model_experiential/classes.py +++ b/src/model_experiential/classes.py @@ -6,6 +6,7 @@ import random class OptionNotSetException(Exception): pass + class ModelOutput(BaseModel): @classmethod @@ -17,13 +18,13 @@ class ModelOutput(BaseModel): def list_fields(cls) -> List[str]: """List options that are stored as attributes.""" return list(cls.model_fields.keys()) - + @classmethod def from_random(cls): """Instantiate with random numbers.""" kwargs = {field: random.random() for field in cls.list_fields()} return cls(**kwargs) - + @classmethod def from_choice(cls, option: str): """Instantiate from choice.""" @@ -31,7 +32,8 @@ class ModelOutput(BaseModel): raise ValidationError() assert isinstance(option, str), "option is not a string" allowed_options_list = cls.list_fields() - assert option in allowed_options_list, f"{option} is not among allowed fields {allowed_options_list}" + assert option in allowed_options_list, \ + f"{option} is not among allowed fields {allowed_options_list}" kwargs = {field: 0 for field in cls.list_fields()} kwargs[option] = 1 return cls(**kwargs) @@ -39,15 +41,19 @@ class ModelOutput(BaseModel): def __repr__(self) -> str: model_dict = self.model_dump() model_repr_str = f"{self.classname()}(" - model_repr_str += ", ".join([f"{field}={value:.3f}" for field, value in model_dict.items()]) + model_repr_str += ", ".join([ + f"{field}={value:.3f}" + for field, value + in model_dict.items() + ]) model_repr_str += ")" return model_repr_str - + def highest_score_field(self) -> str: """Return name of field with highest score.""" model_dict = self.model_dump() return max(model_dict, key=lambda k: model_dict[k]) - + def highest_score_value(self) -> float: """Return value of field with highest score.""" model_dict = self.model_dump() diff --git a/src/model_interpersonal/__init__.py b/src/model_interpersonal/__init__.py index 74211a9..4599135 100644 --- a/src/model_interpersonal/__init__.py +++ b/src/model_interpersonal/__init__.py @@ -6,4 +6,4 @@ from .classes import ( ModalityLightingModelOutput, ModalityColorModelOutput, ModalityDepthModelOutput -) \ No newline at end of file +) diff --git a/src/model_interpersonal/classes.py b/src/model_interpersonal/classes.py index a702d1a..8444d64 100644 --- a/src/model_interpersonal/classes.py +++ b/src/model_interpersonal/classes.py @@ -14,13 +14,13 @@ class ModelOutput(BaseModel): def list_fields(cls) -> List[str]: """List options that are stored as attributes.""" return list(cls.model_fields.keys()) - + @classmethod def from_random(cls): """Instantiate with random numbers.""" kwargs = {field: random.random() for field in cls.list_fields()} return cls(**kwargs) - + @classmethod def from_choice(cls, option: str): """Instantiate from choice.""" @@ -28,7 +28,8 @@ class ModelOutput(BaseModel): raise ValidationError() assert isinstance(option, str) allowed_options_list = cls.list_fields() - assert option in allowed_options_list, f"{option} is not among allowed fields {allowed_options_list}" + assert option in allowed_options_list, \ + f"{option} is not among allowed fields {allowed_options_list}" kwargs = {field: 0 for field in cls.list_fields()} kwargs[option] = 1 return cls(**kwargs) @@ -36,15 +37,19 @@ class ModelOutput(BaseModel): def __repr__(self) -> str: model_dict = self.model_dump() model_repr_str = f"{self.classname()}(" - model_repr_str += ", ".join([f"{field}={value:.3f}" for field, value in model_dict.items()]) + model_repr_str += ", ".join([ + f"{field}={value:.3f}" + for field, value + in model_dict.items() + ]) model_repr_str += ")" return model_repr_str - + def highest_score_field(self) -> str: """Return name of field with highest score.""" model_dict = self.model_dump() return max(model_dict, key=lambda k: model_dict[k]) - + def highest_score_value(self) -> float: """Return value of field with highest score.""" model_dict = self.model_dump() diff --git a/src/model_textual/__init__.py b/src/model_textual/__init__.py index 9e7b87c..a60055f 100644 --- a/src/model_textual/__init__.py +++ b/src/model_textual/__init__.py @@ -2,4 +2,4 @@ from .classes import ( InformationValueModelOutput, FramingModelOutput, SalienceModelOutput -) \ No newline at end of file +) diff --git a/src/model_textual/classes.py b/src/model_textual/classes.py index bab0672..e0c269d 100644 --- a/src/model_textual/classes.py +++ b/src/model_textual/classes.py @@ -14,13 +14,13 @@ class ModelOutput(BaseModel): def list_fields(cls) -> List[str]: """List options that are stored as attributes.""" return list(cls.model_fields.keys()) - + @classmethod def from_random(cls): """Instantiate with random numbers.""" kwargs = {field: random.random() for field in cls.list_fields()} return cls(**kwargs) - + @classmethod def from_choice(cls, option: str): """Instantiate from choice.""" @@ -28,7 +28,8 @@ class ModelOutput(BaseModel): raise ValidationError() assert isinstance(option, str) allowed_options_list = cls.list_fields() - assert option in allowed_options_list, f"{option} is not among allowed fields {allowed_options_list}" + assert option in allowed_options_list, \ + f"{option} is not among allowed fields {allowed_options_list}" kwargs = {field: 0 for field in cls.list_fields()} kwargs[option] = 1 return cls(**kwargs) @@ -36,15 +37,19 @@ class ModelOutput(BaseModel): def __repr__(self) -> str: model_dict = self.model_dump() model_repr_str = f"{self.classname()}(" - model_repr_str += ", ".join([f"{field}={value:.3f}" for field, value in model_dict.items()]) + model_repr_str += ", ".join([ + f"{field}={value:.3f}" + for field, value + in model_dict.items() + ]) model_repr_str += ")" return model_repr_str - + def highest_score_field(self) -> str: """Return name of field with highest score.""" model_dict = self.model_dump() return max(model_dict, key=lambda k: model_dict[k]) - + def highest_score_value(self) -> float: """Return value of field with highest score.""" model_dict = self.model_dump() @@ -84,4 +89,4 @@ if __name__ == '__main__': m = SalienceModelOutput.from_random() print(repr(m)) print(m.highest_score_field()) - print(m.highest_score_value()) \ No newline at end of file + print(m.highest_score_value()) diff --git a/src/web/app.py b/src/web/app.py index 22094d0..4e6549c 100644 --- a/src/web/app.py +++ b/src/web/app.py @@ -30,6 +30,7 @@ BasicAuth(app, AUTH_DICT) # connect to database collection, db, client = connect() + # define callbacks @app.callback( Output("alert-element", "is_open"), @@ -44,6 +45,7 @@ def show_alert( logging.info(f"updated alert message: {msg}") return True, msg + @app.callback( Output("alert-message", "data"), Output("vis-com-name", "data"), @@ -73,7 +75,7 @@ def cycle_visual_communication_data( annotation_values ] # check if next-button clicked - if n_clicks == 0: + if n_clicks == 0: logging.info("stopping early: next-button has not yet been clicked") return response # check if visual communication name is set @@ -102,13 +104,13 @@ def cycle_visual_communication_data( in annotation_values ] annotations = { - key: value - for key, value + key: value + for key, value in zip(annotation_keys, annotation_values) } # instantiate ModelOutputs object annotations = ModelOutputs.from_annotations(**annotations) - # save data to + # save data to database upsert_annotations( collection=collection, vis_com_name=vis_com_name, @@ -137,7 +139,7 @@ def cycle_visual_communication_data( # reset annotations annotation_values = [None for elem in annotation_values] except NoDocumentFoundException: - msg = f"no unannotated data in database" + msg = "no unannotated data in database" logging.warning(msg) response[0] = msg return tuple(response) diff --git a/src/web/layout/__init__.py b/src/web/layout/__init__.py index d2bc031..e3ea6c9 100644 --- a/src/web/layout/__init__.py +++ b/src/web/layout/__init__.py @@ -1 +1 @@ -from .layout import app_layout \ No newline at end of file +from .layout import app_layout diff --git a/src/web/layout/alerts.py b/src/web/layout/alerts.py index 3eaa00f..a067849 100644 --- a/src/web/layout/alerts.py +++ b/src/web/layout/alerts.py @@ -1,4 +1,4 @@ -from dash import html, dcc +from dash import html import dash_bootstrap_components as dbc diff --git a/src/web/layout/body.py b/src/web/layout/body.py index c88bb59..0765e34 100644 --- a/src/web/layout/body.py +++ b/src/web/layout/body.py @@ -1,6 +1,4 @@ import dash_mantine_components as dmc -from dash import dcc, html -from typing import List from .image import image_element from .inputs import inputs_element @@ -17,4 +15,4 @@ body_element = dmc.Container( ], ) ], -) \ No newline at end of file +) diff --git a/src/web/layout/inputs.py b/src/web/layout/inputs.py index 5e37adc..a7a6802 100644 --- a/src/web/layout/inputs.py +++ b/src/web/layout/inputs.py @@ -20,4 +20,4 @@ inputs_element = dmc.SimpleGrid( labels_element, next_button ] -) \ No newline at end of file +) diff --git a/src/web/layout/labels.py b/src/web/layout/labels.py index f8a90bd..616008b 100644 --- a/src/web/layout/labels.py +++ b/src/web/layout/labels.py @@ -20,6 +20,7 @@ from src.model_textual import ( SalienceModelOutput ) + def generate_option_labels(model) -> List[str]: """Generate presentable list of attributes from an OutputModel.""" labels = [ @@ -28,35 +29,51 @@ def generate_option_labels(model) -> List[str]: ] return labels + def generate_visual_syntax_options_map(): """Generate map of titles and options for visual syntax labels.""" options_map = {} # add experiential labels - options_map["visual syntax"] = generate_option_labels(VisualSyntaxModelOutput) + options_map["visual syntax"] = generate_option_labels( + VisualSyntaxModelOutput + ) return options_map + def generate_interpersonal_options_map(): """Generate map of titles and options for interpersonal labels.""" options_map = {} # add interpersonal labels options_map["contact"] = generate_option_labels(ContactModelOutput) options_map["angle"] = generate_option_labels(AngleModelOutput) - options_map["point of view"] = generate_option_labels(PointOfViewModelOutput) + options_map["point of view"] = generate_option_labels( + PointOfViewModelOutput + ) options_map["distance"] = generate_option_labels(DistanceModelOutput) - options_map["modality lighting"] = generate_option_labels(ModalityLightingModelOutput) - options_map["modality color"] = generate_option_labels(ModalityColorModelOutput) - options_map["modality depth"] = generate_option_labels(ModalityDepthModelOutput) + options_map["modality lighting"] = generate_option_labels( + ModalityLightingModelOutput + ) + options_map["modality color"] = generate_option_labels( + ModalityColorModelOutput + ) + options_map["modality depth"] = generate_option_labels( + ModalityDepthModelOutput + ) return options_map + def generate_textual_options_map(): """Generate map of titles and options for textual labels.""" options_map = {} # add textual labels - options_map["information value"] = generate_option_labels(InformationValueModelOutput) + options_map["information value"] = generate_option_labels( + InformationValueModelOutput + ) options_map["framing"] = generate_option_labels(FramingModelOutput) options_map["salience"] = generate_option_labels(SalienceModelOutput) return options_map + # prepare experiential container experiential_map = generate_visual_syntax_options_map() experiential_container = dmc.Col( @@ -118,4 +135,4 @@ labels_element = dmc.Grid( interpersonal_container, textual_container, ] -) \ No newline at end of file +) diff --git a/src/web/layout/layout.py b/src/web/layout/layout.py index 7533366..b8995cb 100644 --- a/src/web/layout/layout.py +++ b/src/web/layout/layout.py @@ -1,4 +1,3 @@ -from dash import dcc import dash_mantine_components as dmc from .stores import stores_element diff --git a/src/web/layout/stores.py b/src/web/layout/stores.py index 7345d8b..9a9f58a 100644 --- a/src/web/layout/stores.py +++ b/src/web/layout/stores.py @@ -5,12 +5,14 @@ import os storage_type = "session" if "ENV" in os.environ and os.getenv("ENV") == "DEV": storage_type = "memory" - logging.info(f"ENV=DEV -> dcc.Stores changed to storage_type={storage_type}") - + logging.info( + "ENV=DEV -> dcc.Stores changed to storage_type=%s", + storage_type + ) stores_element = html.Div( children=[ dcc.Store(id="alert-message", storage_type=storage_type, data=""), dcc.Store(id="vis-com-name", storage_type=storage_type, data=""), ] -) \ No newline at end of file +) diff --git a/tests/test_generate_random_prediction.py b/tests/test_generate_random_prediction.py index f2a2845..cc92bd4 100644 --- a/tests/test_generate_random_prediction.py +++ b/tests/test_generate_random_prediction.py @@ -10,8 +10,12 @@ if __name__ == "__main__": img_path_list = [path for path in img_dir.glob("*.jpeg") if path.is_file()] print(img_path_list) # instantiate data object - vis_com_list = [VisualCommunication.from_file(path) for path in img_path_list] + vis_com_list = [ + VisualCommunication.from_file(path) + for path + in img_path_list + ] # generate random predictions [vis_com.generate_random_prediction() for vis_com in vis_com_list] for vis_com in vis_com_list: - print(vis_com) \ No newline at end of file + print(vis_com) diff --git a/tests/test_image_upload.py b/tests/test_image_upload.py index f4231f9..a89086e 100644 --- a/tests/test_image_upload.py +++ b/tests/test_image_upload.py @@ -12,7 +12,11 @@ if __name__ == "__main__": img_path_list = [path for path in img_dir.glob("*.jpeg") if path.is_file()] print(img_path_list) # instantiate data object - vis_com_list = [VisualCommunication.from_file(path) for path in img_path_list] + vis_com_list = [ + VisualCommunication.from_file(path) + for path + in img_path_list + ] for vis_com in vis_com_list: print(repr(vis_com)) # prepare env vars diff --git a/tests/test_model_outputs_from_annotation.py b/tests/test_model_outputs_from_annotation.py index d64b3b5..865c5d6 100644 --- a/tests/test_model_outputs_from_annotation.py +++ b/tests/test_model_outputs_from_annotation.py @@ -3,11 +3,12 @@ from src.database import ModelOutputs if __name__ == "__main__": # instantiate data object - annotation = { - - } - vis_com_list = [ModelOutputs.from_annotation(path) for path in img_path_list] + vis_com_list = [ + ModelOutputs.from_random() + for i + in range(3) + ] # generate random predictions [vis_com.generate_random_prediction() for vis_com in vis_com_list] for vis_com in vis_com_list: - print(vis_com) \ No newline at end of file + print(vis_com) diff --git a/tests/test_prediction_upload.py b/tests/test_prediction_upload.py index 871ef3f..6a94134 100644 --- a/tests/test_prediction_upload.py +++ b/tests/test_prediction_upload.py @@ -25,7 +25,11 @@ if __name__ == "__main__": img_dir = test_dir / "imgs" img_path_list = [path for path in img_dir.glob("*.jpeg") if path.is_file()] # instantiate data object - vis_com_list = [VisualCommunication.from_file(path) for path in img_path_list] + vis_com_list = [ + VisualCommunication.from_file(path) + for path + in img_path_list + ] # generate random predictions [vis_com.generate_random_prediction() for vis_com in vis_com_list] # prepare env vars diff --git a/tests/test_total_annotated.py b/tests/test_total_annotated.py index 3726870..1194b37 100644 --- a/tests/test_total_annotated.py +++ b/tests/test_total_annotated.py @@ -17,4 +17,4 @@ if __name__ == "__main__": collection, db, client = connect() # get visual communication num_docs = total_annotated(collection) - print(f"number of annotated documents in database: {num_docs}") \ No newline at end of file + print(f"number of annotated documents in database: {num_docs}") diff --git a/tests/test_total_documents.py b/tests/test_total_documents.py index 73e92c5..e8bc1df 100644 --- a/tests/test_total_documents.py +++ b/tests/test_total_documents.py @@ -17,4 +17,4 @@ if __name__ == "__main__": collection, db, client = connect() # get visual communication num_docs = total_documents(collection) - print(f"total number of documents in database: {num_docs}") \ No newline at end of file + print(f"total number of documents in database: {num_docs}")