From bed1749048506f2aeca7e7fca77573af4a252c63 Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sat, 24 Feb 2024 23:07:59 +0100 Subject: [PATCH 01/48] added default workflow --- .gitea/workflows/default.yaml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .gitea/workflows/default.yaml diff --git a/.gitea/workflows/default.yaml b/.gitea/workflows/default.yaml new file mode 100644 index 0000000..827e8c9 --- /dev/null +++ b/.gitea/workflows/default.yaml @@ -0,0 +1,26 @@ +name: pipeline +run-name: ${{ gitea.actor }} is running the script +runs-on: ubuntu-latest +on: push +image: python:3.12 +jobs: + test: + name: Test + runs-on: ubuntu-latest + steps: + - name: Checkout Code + uses: actions/checkout@v3 + - name: Setup Environment + uses: https://github.com/actions/setup-python@v3 + with: + python-verison: "3.12" + architecture: "x64" + - name: Install Packages + run: | + python -m pip install --upgrade pip + pip install poetry + poetry install + - name: PEP8 Check + run: flake8 ./src --benchmark + - name: Type Check + run: mypy ./src \ No newline at end of file From f0b628d924ab4c07da62d9b54c127d868e62a45b Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sat, 24 Feb 2024 23:09:38 +0100 Subject: [PATCH 02/48] added default workflow --- .gitea/workflows/default.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/default.yaml b/.gitea/workflows/default.yaml index 827e8c9..042cb90 100644 --- a/.gitea/workflows/default.yaml +++ b/.gitea/workflows/default.yaml @@ -1,5 +1,5 @@ name: pipeline -run-name: ${{ gitea.actor }} is running the script +run-name: ${{ gitea.actor }} is running the script... runs-on: ubuntu-latest on: push image: python:3.12 From 201ca0a8eef1f3bbb6db14a1b59dee0593d4c39b Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sat, 24 Feb 2024 23:12:05 +0100 Subject: [PATCH 03/48] updated workflow --- .gitea/workflows/default.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/default.yaml b/.gitea/workflows/default.yaml index 042cb90..1eeacb4 100644 --- a/.gitea/workflows/default.yaml +++ b/.gitea/workflows/default.yaml @@ -1,5 +1,5 @@ name: pipeline -run-name: ${{ gitea.actor }} is running the script... +run-name: ${{ gitea.actor }} is running the script runs-on: ubuntu-latest on: push image: python:3.12 @@ -18,7 +18,7 @@ jobs: - name: Install Packages run: | python -m pip install --upgrade pip - pip install poetry + pip install flake8 mypy poetry poetry install - name: PEP8 Check run: flake8 ./src --benchmark From 993c9a122b376655eb4da4cef917062e26be9145 Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sat, 24 Feb 2024 23:19:43 +0100 Subject: [PATCH 04/48] added flake8 config --- .flake8 | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .flake8 diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..3c4d656 --- /dev/null +++ b/.flake8 @@ -0,0 +1,2 @@ +[flake8] +per-file-ignores = __init__.py:F401 \ No newline at end of file From fa2230d5cf9b960021ecfd8247ff05bd2a248629 Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sat, 24 Feb 2024 23:42:55 +0100 Subject: [PATCH 05/48] 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}") From fc19c31af94f9142cb270df58b2ea4d4612af422 Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sat, 24 Feb 2024 23:43:17 +0100 Subject: [PATCH 06/48] installed packages --- poetry.lock | 51 +++++++++++++++++++++++++++++++++++++++++++++++++- pyproject.toml | 3 +++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index 117fbbb..d24dc59 100644 --- a/poetry.lock +++ b/poetry.lock @@ -287,6 +287,22 @@ idna = ["idna (>=3.6)"] trio = ["trio (>=0.23)"] wmi = ["wmi (>=1.5.1)"] +[[package]] +name = "flake8" +version = "7.0.0" +description = "the modular source code checker: pep8 pyflakes and co" +optional = false +python-versions = ">=3.8.1" +files = [ + {file = "flake8-7.0.0-py2.py3-none-any.whl", hash = "sha256:a6dfbb75e03252917f2473ea9653f7cd799c3064e54d4c8140044c5c065f53c3"}, + {file = "flake8-7.0.0.tar.gz", hash = "sha256:33f96621059e65eec474169085dc92bf26e7b2d47366b70be2f67ab80dc25132"}, +] + +[package.dependencies] +mccabe = ">=0.7.0,<0.8.0" +pycodestyle = ">=2.11.0,<2.12.0" +pyflakes = ">=3.2.0,<3.3.0" + [[package]] name = "flask" version = "3.0.2" @@ -456,6 +472,17 @@ files = [ {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, ] +[[package]] +name = "mccabe" +version = "0.7.0" +description = "McCabe checker, plugin for flake8" +optional = false +python-versions = ">=3.6" +files = [ + {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, + {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, +] + [[package]] name = "nest-asyncio" version = "1.6.0" @@ -578,6 +605,17 @@ files = [ packaging = "*" tenacity = ">=6.2.0" +[[package]] +name = "pycodestyle" +version = "2.11.1" +description = "Python style guide checker" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pycodestyle-2.11.1-py2.py3-none-any.whl", hash = "sha256:44fe31000b2d866f2e41841b18528a505fbd7fef9017b04eff4e2648a0fadc67"}, + {file = "pycodestyle-2.11.1.tar.gz", hash = "sha256:41ba0e7afc9752dfb53ced5489e89f8186be00e599e712660695b7a75ff2663f"}, +] + [[package]] name = "pydantic" version = "2.6.1" @@ -688,6 +726,17 @@ files = [ [package.dependencies] typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" +[[package]] +name = "pyflakes" +version = "3.2.0" +description = "passive checker of Python programs" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pyflakes-3.2.0-py2.py3-none-any.whl", hash = "sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a"}, + {file = "pyflakes-3.2.0.tar.gz", hash = "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f"}, +] + [[package]] name = "pymongo" version = "4.6.1" @@ -944,4 +993,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.12" -content-hash = "d4df77270fa7781e482a10c4671c5c22d23f4d461bbe007f98b929142078a653" +content-hash = "598aca4396fc86bb93d5070acdff5e0579210f65cd8e4747d7b1bc609da55cbb" diff --git a/pyproject.toml b/pyproject.toml index bf86f43..5fed649 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,6 +21,9 @@ pymongo = "^4.6.1" dash-auth = "^2.2.0" +[tool.poetry.group.test.dependencies] +flake8 = "^7.0.0" + [build-system] requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" From b37fea850a1cad5e66b7b6eebe7dc4e21f0715e9 Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sat, 24 Feb 2024 23:43:42 +0100 Subject: [PATCH 07/48] updated workflow --- .gitea/workflows/default.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/default.yaml b/.gitea/workflows/default.yaml index 1eeacb4..879c2ba 100644 --- a/.gitea/workflows/default.yaml +++ b/.gitea/workflows/default.yaml @@ -18,8 +18,8 @@ jobs: - name: Install Packages run: | python -m pip install --upgrade pip - pip install flake8 mypy poetry - poetry install + pip install poetry + poetry install --with test - name: PEP8 Check run: flake8 ./src --benchmark - name: Type Check From 9872edda7c17bd733edb7714df00d94dfbd14957 Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sat, 24 Feb 2024 23:48:12 +0100 Subject: [PATCH 08/48] updated workflow --- .gitea/workflows/default.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/default.yaml b/.gitea/workflows/default.yaml index 879c2ba..d9063d4 100644 --- a/.gitea/workflows/default.yaml +++ b/.gitea/workflows/default.yaml @@ -18,7 +18,7 @@ jobs: - name: Install Packages run: | python -m pip install --upgrade pip - pip install poetry + pip install flake8 mypy poetry poetry install --with test - name: PEP8 Check run: flake8 ./src --benchmark From f74e7af8b18a13e8b66ebb94f8fbe697d6b34b7f Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sat, 24 Feb 2024 23:49:28 +0100 Subject: [PATCH 09/48] installed packages --- poetry.lock | 59 +++++++++++++++++++++++++++++++++++++++++++++++++- pyproject.toml | 1 + 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index d24dc59..12682d4 100644 --- a/poetry.lock +++ b/poetry.lock @@ -483,6 +483,63 @@ files = [ {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, ] +[[package]] +name = "mypy" +version = "1.8.0" +description = "Optional static typing for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "mypy-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:485a8942f671120f76afffff70f259e1cd0f0cfe08f81c05d8816d958d4577d3"}, + {file = "mypy-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:df9824ac11deaf007443e7ed2a4a26bebff98d2bc43c6da21b2b64185da011c4"}, + {file = "mypy-1.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2afecd6354bbfb6e0160f4e4ad9ba6e4e003b767dd80d85516e71f2e955ab50d"}, + {file = "mypy-1.8.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8963b83d53ee733a6e4196954502b33567ad07dfd74851f32be18eb932fb1cb9"}, + {file = "mypy-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:e46f44b54ebddbeedbd3d5b289a893219065ef805d95094d16a0af6630f5d410"}, + {file = "mypy-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:855fe27b80375e5c5878492f0729540db47b186509c98dae341254c8f45f42ae"}, + {file = "mypy-1.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4c886c6cce2d070bd7df4ec4a05a13ee20c0aa60cb587e8d1265b6c03cf91da3"}, + {file = "mypy-1.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d19c413b3c07cbecf1f991e2221746b0d2a9410b59cb3f4fb9557f0365a1a817"}, + {file = "mypy-1.8.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9261ed810972061388918c83c3f5cd46079d875026ba97380f3e3978a72f503d"}, + {file = "mypy-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:51720c776d148bad2372ca21ca29256ed483aa9a4cdefefcef49006dff2a6835"}, + {file = "mypy-1.8.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:52825b01f5c4c1c4eb0db253ec09c7aa17e1a7304d247c48b6f3599ef40db8bd"}, + {file = "mypy-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f5ac9a4eeb1ec0f1ccdc6f326bcdb464de5f80eb07fb38b5ddd7b0de6bc61e55"}, + {file = "mypy-1.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afe3fe972c645b4632c563d3f3eff1cdca2fa058f730df2b93a35e3b0c538218"}, + {file = "mypy-1.8.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:42c6680d256ab35637ef88891c6bd02514ccb7e1122133ac96055ff458f93fc3"}, + {file = "mypy-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:720a5ca70e136b675af3af63db533c1c8c9181314d207568bbe79051f122669e"}, + {file = "mypy-1.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:028cf9f2cae89e202d7b6593cd98db6759379f17a319b5faf4f9978d7084cdc6"}, + {file = "mypy-1.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4e6d97288757e1ddba10dd9549ac27982e3e74a49d8d0179fc14d4365c7add66"}, + {file = "mypy-1.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f1478736fcebb90f97e40aff11a5f253af890c845ee0c850fe80aa060a267c6"}, + {file = "mypy-1.8.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42419861b43e6962a649068a61f4a4839205a3ef525b858377a960b9e2de6e0d"}, + {file = "mypy-1.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:2b5b6c721bd4aabaadead3a5e6fa85c11c6c795e0c81a7215776ef8afc66de02"}, + {file = "mypy-1.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5c1538c38584029352878a0466f03a8ee7547d7bd9f641f57a0f3017a7c905b8"}, + {file = "mypy-1.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ef4be7baf08a203170f29e89d79064463b7fc7a0908b9d0d5114e8009c3a259"}, + {file = "mypy-1.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7178def594014aa6c35a8ff411cf37d682f428b3b5617ca79029d8ae72f5402b"}, + {file = "mypy-1.8.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ab3c84fa13c04aeeeabb2a7f67a25ef5d77ac9d6486ff33ded762ef353aa5592"}, + {file = "mypy-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:99b00bc72855812a60d253420d8a2eae839b0afa4938f09f4d2aa9bb4654263a"}, + {file = "mypy-1.8.0-py3-none-any.whl", hash = "sha256:538fd81bb5e430cc1381a443971c0475582ff9f434c16cd46d2c66763ce85d9d"}, + {file = "mypy-1.8.0.tar.gz", hash = "sha256:6ff8b244d7085a0b425b56d327b480c3b29cafbd2eff27316a004f9a7391ae07"}, +] + +[package.dependencies] +mypy-extensions = ">=1.0.0" +typing-extensions = ">=4.1.0" + +[package.extras] +dmypy = ["psutil (>=4.0)"] +install-types = ["pip"] +mypyc = ["setuptools (>=50)"] +reports = ["lxml"] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.5" +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + [[package]] name = "nest-asyncio" version = "1.6.0" @@ -993,4 +1050,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.12" -content-hash = "598aca4396fc86bb93d5070acdff5e0579210f65cd8e4747d7b1bc609da55cbb" +content-hash = "8d402928021790b163281dfa68403d73a008a8d93ccd998a496a5c819a12ed13" diff --git a/pyproject.toml b/pyproject.toml index 5fed649..cd5c475 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,6 +23,7 @@ dash-auth = "^2.2.0" [tool.poetry.group.test.dependencies] flake8 = "^7.0.0" +mypy = "^1.8.0" [build-system] requires = ["poetry-core"] From 4719117d71c322cf6b84f83d79194916d1db0f69 Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sun, 25 Feb 2024 00:03:48 +0100 Subject: [PATCH 10/48] installed packages --- poetry.lock | 13 ++++++++++++- pyproject.toml | 1 + 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index 12682d4..eebdfb1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -987,6 +987,17 @@ files = [ [package.extras] doc = ["reno", "sphinx", "tornado (>=4.5)"] +[[package]] +name = "types-pillow" +version = "10.2.0.20240213" +description = "Typing stubs for Pillow" +optional = false +python-versions = ">=3.8" +files = [ + {file = "types-Pillow-10.2.0.20240213.tar.gz", hash = "sha256:4800b61bf7eabdae2f1b17ade0d080709ed33e9f26a2e900e470e8b56ebe2387"}, + {file = "types_Pillow-10.2.0.20240213-py3-none-any.whl", hash = "sha256:062c5a0f20301a30f2df4db583f15b3c2a1283a12518d1f9d81396154e12c1af"}, +] + [[package]] name = "typing-extensions" version = "4.9.0" @@ -1050,4 +1061,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.12" -content-hash = "8d402928021790b163281dfa68403d73a008a8d93ccd998a496a5c819a12ed13" +content-hash = "659fbec7604539854b960d7ffaf5c61ab80ae9fba4f6ab320a615a3104710122" diff --git a/pyproject.toml b/pyproject.toml index cd5c475..e8ddf1e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,7 @@ dash-auth = "^2.2.0" [tool.poetry.group.test.dependencies] flake8 = "^7.0.0" mypy = "^1.8.0" +types-pillow = "^10.2.0.20240213" [build-system] requires = ["poetry-core"] From 8e107b785e3749bd2003707bab2e43aaefc7d472 Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sun, 25 Feb 2024 00:04:01 +0100 Subject: [PATCH 11/48] mypy compliant --- src/database/classes.py | 4 ++-- src/database/utils.py | 9 ++++----- src/web/app.py | 4 ++-- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/database/classes.py b/src/database/classes.py index 2fcda2a..90ffab9 100644 --- a/src/database/classes.py +++ b/src/database/classes.py @@ -52,7 +52,7 @@ class ModelOutputs(BaseModel): def from_random(cls) -> ModelOutputs: """Instantiate with random numbers.""" kwargs = { - field: field_info.annotation.from_random() + field: field_info.annotation.from_random() # type: ignore for field, field_info in cls.model_fields.items() } @@ -124,7 +124,7 @@ class VisualCommunication(BaseModel): return VisualCommunication(name=name, image=image) @field_serializer("image") - def serialize_image(image: Image.Image) -> bytes: + def serialize_image(image: Image.Image) -> bytes: # type: ignore buffer = BytesIO() image.save(buffer, format="JPEG") return buffer.getvalue() diff --git a/src/database/utils.py b/src/database/utils.py index 22bf085..75420c1 100644 --- a/src/database/utils.py +++ b/src/database/utils.py @@ -36,7 +36,7 @@ def get_visual_communication( if with_annotation: query["annotation"] = {"$ne": None} else: - query["annotation"] = None + query["annotation"] = {"$eq": None} data = collection.aggregate([ { "$match": query # find using filters @@ -47,13 +47,12 @@ def get_visual_communication( } } ]) - data = list(data) # read data from cursor object - if len(data) == 0: + data_list = list(data) # read data from cursor object + if len(data_list) == 0: logging.error("failed getting visual communication") raise NoDocumentFoundException() - data = data[0] logging.info("finished") - return VisualCommunication.model_validate(data) + return VisualCommunication.model_validate(data_list[0]) def upsert_predictions( diff --git a/src/web/app.py b/src/web/app.py index 4e6549c..fe465f6 100644 --- a/src/web/app.py +++ b/src/web/app.py @@ -103,13 +103,13 @@ def cycle_visual_communication_data( for elem in annotation_values ] - annotations = { + annotation_map = { key: value for key, value in zip(annotation_keys, annotation_values) } # instantiate ModelOutputs object - annotations = ModelOutputs.from_annotations(**annotations) + annotations = ModelOutputs.from_annotations(**annotation_map) # save data to database upsert_annotations( collection=collection, From 68ca576639b0ec549cf130feba734eab63e43c5f Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sun, 25 Feb 2024 00:04:09 +0100 Subject: [PATCH 12/48] updated workflow --- .gitea/workflows/default.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/default.yaml b/.gitea/workflows/default.yaml index d9063d4..c8aac97 100644 --- a/.gitea/workflows/default.yaml +++ b/.gitea/workflows/default.yaml @@ -23,4 +23,4 @@ jobs: - name: PEP8 Check run: flake8 ./src --benchmark - name: Type Check - run: mypy ./src \ No newline at end of file + run: mypy ./src --explicit-package-bases --disable-error-code=import-untyped \ No newline at end of file From 3353f60a56d44e0a3d36199fa5f2bfee46ad770b Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sun, 25 Feb 2024 00:07:32 +0100 Subject: [PATCH 13/48] updated workflow --- .gitea/workflows/default.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/default.yaml b/.gitea/workflows/default.yaml index c8aac97..7d54aaa 100644 --- a/.gitea/workflows/default.yaml +++ b/.gitea/workflows/default.yaml @@ -18,8 +18,8 @@ jobs: - name: Install Packages run: | python -m pip install --upgrade pip - pip install flake8 mypy poetry - poetry install --with test + pip install poetry + poetry install --with main,test - name: PEP8 Check run: flake8 ./src --benchmark - name: Type Check From 3767e0e9dbf20ef7ba1cb3504b47a6bc748b3cf1 Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sun, 25 Feb 2024 00:14:22 +0100 Subject: [PATCH 14/48] updated workflow --- .gitea/workflows/default.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/default.yaml b/.gitea/workflows/default.yaml index 7d54aaa..dd2fe33 100644 --- a/.gitea/workflows/default.yaml +++ b/.gitea/workflows/default.yaml @@ -18,7 +18,7 @@ jobs: - name: Install Packages run: | python -m pip install --upgrade pip - pip install poetry + pip install poetry flake8 mypy types-pillow poetry install --with main,test - name: PEP8 Check run: flake8 ./src --benchmark From 1790c5d886d771139abd7b12399be2c057333629 Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sun, 25 Feb 2024 00:23:25 +0100 Subject: [PATCH 15/48] added pre-commit file --- .pre-commit-config.yaml | 44 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 .pre-commit-config.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..c428788 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,44 @@ +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.5.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: debug-statements + - id: double-quote-string-fixer + - id: name-tests-test + - id: requirements-txt-fixer +- repo: https://github.com/asottile/setup-cfg-fmt + rev: v2.5.0 + hooks: + - id: setup-cfg-fmt +- repo: https://github.com/asottile/reorder-python-imports + rev: v3.12.0 + hooks: + - id: reorder-python-imports + exclude: ^(pre_commit/resources/|testing/resources/python3_hooks_repo/) + args: [--py39-plus, --add-import, 'from __future__ import annotations'] +- repo: https://github.com/asottile/add-trailing-comma + rev: v3.1.0 + hooks: + - id: add-trailing-comma +- repo: https://github.com/asottile/pyupgrade + rev: v3.15.1 + hooks: + - id: pyupgrade + args: [--py39-plus] +- repo: https://github.com/hhatto/autopep8 + rev: v2.0.4 + hooks: + - id: autopep8 +- repo: https://github.com/PyCQA/flake8 + rev: 7.0.0 + hooks: + - id: flake8 +- repo: https://github.com/pre-commit/mirrors-mypy + rev: v1.8.0 + hooks: + - id: mypy + additional_dependencies: [types-all] + exclude: ^testing/resources/ From 4282e9a393936aa7921317433524077f9d067ae5 Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sun, 25 Feb 2024 00:27:15 +0100 Subject: [PATCH 16/48] updated workflow --- .gitea/workflows/default.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/default.yaml b/.gitea/workflows/default.yaml index dd2fe33..6bda995 100644 --- a/.gitea/workflows/default.yaml +++ b/.gitea/workflows/default.yaml @@ -19,8 +19,8 @@ jobs: run: | python -m pip install --upgrade pip pip install poetry flake8 mypy types-pillow - poetry install --with main,test + poetry install - name: PEP8 Check run: flake8 ./src --benchmark - name: Type Check - run: mypy ./src --explicit-package-bases --disable-error-code=import-untyped \ No newline at end of file + run: mypy ./src --explicit-package-bases --disable-error-code=import-untyped From ea28f233042f1b6296a324ff3b21257f004e9b4b Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sun, 25 Feb 2024 00:28:58 +0100 Subject: [PATCH 17/48] updated workflow --- .gitea/workflows/default.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/default.yaml b/.gitea/workflows/default.yaml index 6bda995..8b73ce3 100644 --- a/.gitea/workflows/default.yaml +++ b/.gitea/workflows/default.yaml @@ -23,4 +23,4 @@ jobs: - name: PEP8 Check run: flake8 ./src --benchmark - name: Type Check - run: mypy ./src --explicit-package-bases --disable-error-code=import-untyped + run: mypy ./src --disable-error-code=import-untyped From ce063822b5e8d4c4cb1bc380f623e5c37088d5f5 Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sun, 25 Feb 2024 14:26:54 +0100 Subject: [PATCH 18/48] pre-commit renamed files to PEP standard and removed unused imports --- src/database/classes.py | 82 ++++++++-------- src/main.py | 36 +++---- src/web/app.py | 88 +++++++++-------- src/web/layout/labels.py | 97 +++++++++---------- ....py => generate_random_prediction_test.py} | 13 ++- ...on.py => get_visual_communication_test.py} | 18 ++-- ...age_download.py => image_download_test.py} | 17 ++-- ...t_image_upload.py => image_upload_test.py} | 21 ++-- ... => model_outputs_from_annotation_test.py} | 6 +- ...on_upload.py => prediction_upload_test.py} | 31 +++--- ...l_annotated.py => total_annotated_test.py} | 18 ++-- ...l_documents.py => total_documents_test.py} | 18 ++-- 12 files changed, 230 insertions(+), 215 deletions(-) rename tests/{test_generate_random_prediction.py => generate_random_prediction_test.py} (57%) rename tests/{test_get_visual_communication.py => get_visual_communication_test.py} (59%) rename tests/{test_image_download.py => image_download_test.py} (67%) rename tests/{test_image_upload.py => image_upload_test.py} (70%) rename tests/{test_model_outputs_from_annotation.py => model_outputs_from_annotation_test.py} (74%) rename tests/{test_prediction_upload.py => prediction_upload_test.py} (66%) rename tests/{test_total_annotated.py => total_annotated_test.py} (60%) rename tests/{test_total_documents.py => total_documents_test.py} (60%) diff --git a/src/database/classes.py b/src/database/classes.py index 90ffab9..eceff66 100644 --- a/src/database/classes.py +++ b/src/database/classes.py @@ -1,29 +1,27 @@ from __future__ import annotations -from pydantic import BaseModel, field_validator, field_serializer -from PIL import Image + +import logging +from base64 import b64encode from io import BytesIO from pathlib import Path -from base64 import b64encode -import logging -from typing import List -from src.model_experiential import ( - VisualSyntaxModelOutput -) -from src.model_interpersonal import ( - ContactModelOutput, - AngleModelOutput, - PointOfViewModelOutput, - DistanceModelOutput, - ModalityLightingModelOutput, - ModalityColorModelOutput, - ModalityDepthModelOutput -) -from src.model_textual import ( - InformationValueModelOutput, - FramingModelOutput, - SalienceModelOutput +from model_experiential import ( + VisualSyntaxModelOutput, ) +from model_interpersonal import AngleModelOutput +from model_interpersonal import ContactModelOutput +from model_interpersonal import DistanceModelOutput +from model_interpersonal import ModalityColorModelOutput +from model_interpersonal import ModalityDepthModelOutput +from model_interpersonal import ModalityLightingModelOutput +from model_interpersonal import PointOfViewModelOutput +from model_textual import FramingModelOutput +from model_textual import InformationValueModelOutput +from model_textual import SalienceModelOutput +from PIL import Image +from pydantic import BaseModel +from pydantic import field_serializer +from pydantic import field_validator class NoDocumentFoundException(Exception): @@ -44,7 +42,7 @@ class ModelOutputs(BaseModel): salience: SalienceModelOutput @classmethod - def list_fields(cls) -> List[str]: + def list_fields(cls) -> list[str]: """List options that are stored as attributes.""" return list(cls.model_fields.keys()) @@ -71,32 +69,32 @@ class ModelOutputs(BaseModel): modality_depth: str, information_value: str, framing: str, - salience: str + salience: str, ) -> ModelOutputs: """Instantiate from annotation.""" kwargs = { - "visual_syntax": VisualSyntaxModelOutput + 'visual_syntax': VisualSyntaxModelOutput .from_choice(visual_syntax), - "contact": ContactModelOutput + 'contact': ContactModelOutput .from_choice(contact), - "angle": AngleModelOutput + 'angle': AngleModelOutput .from_choice(angle), - "point_of_view": PointOfViewModelOutput + 'point_of_view': PointOfViewModelOutput .from_choice(point_of_view), - "distance": DistanceModelOutput + 'distance': DistanceModelOutput .from_choice(distance), - "modality_lighting": ModalityLightingModelOutput + 'modality_lighting': ModalityLightingModelOutput .from_choice(modality_lighting), - "modality_color": ModalityColorModelOutput + 'modality_color': ModalityColorModelOutput .from_choice(modality_color), - "modality_depth": ModalityDepthModelOutput + 'modality_depth': ModalityDepthModelOutput .from_choice(modality_depth), - "information_value": InformationValueModelOutput + 'information_value': InformationValueModelOutput .from_choice(information_value), - "framing": FramingModelOutput + 'framing': FramingModelOutput .from_choice(framing), - "salience": SalienceModelOutput - .from_choice(salience) + 'salience': SalienceModelOutput + .from_choice(salience), } return cls(**kwargs) @@ -123,17 +121,17 @@ class VisualCommunication(BaseModel): image.load() return VisualCommunication(name=name, image=image) - @field_serializer("image") + @field_serializer('image') def serialize_image(image: Image.Image) -> bytes: # type: ignore buffer = BytesIO() - image.save(buffer, format="JPEG") + image.save(buffer, format='JPEG') return buffer.getvalue() - @field_validator("image", mode="before") + @field_validator('image', mode='before') @classmethod def convert_to_image( cls, - image: Image.Image | BytesIO | bytes + image: Image.Image | BytesIO | bytes, ) -> Image.Image: if isinstance(image, bytes): image = BytesIO(image) @@ -148,12 +146,12 @@ class VisualCommunication(BaseModel): """Convert image to be displayed on webpage.""" # convert images to bytes string buffer = BytesIO() - self.image.save(buffer, format="png") - img_enc = b64encode(buffer.getvalue()).decode("utf-8") + self.image.save(buffer, format='png') + img_enc = b64encode(buffer.getvalue()).decode('utf-8') return f"data:image/png;base64, {img_enc}" def generate_random_prediction(self, force: bool = False) -> None: """Generate random prediction values.""" if not force and self.prediction is not None: - logging.warning("set force=True to overwrite existing values.") + logging.warning('set force=True to overwrite existing values.') self.prediction = ModelOutputs.from_random() diff --git a/src/main.py b/src/main.py index 597f8e7..9177f3c 100644 --- a/src/main.py +++ b/src/main.py @@ -1,23 +1,25 @@ -import logging -from dotenv import load_dotenv -from pathlib import Path -import os +from __future__ import annotations -from src.web import app +import logging +import os +from pathlib import Path + +from dotenv import load_dotenv +from web import app # prepare optional local setup -env_path = Path(__file__).parent.parent / "local.env" +env_path = Path(__file__).parent.parent / 'local.env' load_dotenv(env_path) # ensure env vars set necesasary_var_list = { - "MONGO_HOST", - "MONGO_DB", - "MONGO_COLLECTION", - "MONGO_USER", - "MONGO_PASSWORD", - "DASH_AUTH_USERNAME", - "DASH_AUTH_PASSWORD" + 'MONGO_HOST', + 'MONGO_DB', + 'MONGO_COLLECTION', + 'MONGO_USER', + 'MONGO_PASSWORD', + 'DASH_AUTH_USERNAME', + 'DASH_AUTH_PASSWORD', } for env_var in necesasary_var_list: # ensure env var set @@ -38,12 +40,12 @@ fmt = ( datefmt = '%Y-%m-%d %H:%M:%S' logging.basicConfig(format=fmt, datefmt=datefmt, level=logging.INFO) -logging.info("initialized app") +logging.info('initialized app') server = app.server -if __name__ == "__main__": +if __name__ == '__main__': # prepare local env vars - os.environ["MONGO_HOST"] = "localhost" + os.environ['MONGO_HOST'] = 'localhost' # run app app.run(debug=True) - logging.info("started app") + logging.info('started app') diff --git a/src/web/app.py b/src/web/app.py index fe465f6..fb94d05 100644 --- a/src/web/app.py +++ b/src/web/app.py @@ -1,29 +1,33 @@ -from dash import Dash, Input, Output, State, ALL -import dash_bootstrap_components as dbc -from dash_auth import BasicAuth +from __future__ import annotations + import logging -from typing import List -from pydantic import ValidationError import os +import dash_bootstrap_components as dbc +from dash import ALL +from dash import Dash +from dash import Input +from dash import Output +from dash import State +from dash_auth import BasicAuth +from database import connect +from database import get_visual_communication +from database import ModelOutputs +from database import NoDocumentFoundException +from database import upsert_annotations +from pydantic import ValidationError + from .layout import app_layout -from src.database import ( - connect, - get_visual_communication, - NoDocumentFoundException, - upsert_annotations, - ModelOutputs -) # setup app app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP]) -app.title = "visual critical discourse analysis".title() +app.title = 'visual critical discourse analysis'.title() app.layout = app_layout server = app.server # setup authentication AUTH_DICT = { - os.getenv("DASH_AUTH_USERNAME"): os.getenv("DASH_AUTH_PASSWORD") + os.getenv('DASH_AUTH_USERNAME'): os.getenv('DASH_AUTH_PASSWORD'), } BasicAuth(app, AUTH_DICT) @@ -33,58 +37,58 @@ collection, db, client = connect() # define callbacks @app.callback( - Output("alert-element", "is_open"), - Output("alert-element", "children"), - Input("alert-message", "data") + Output('alert-element', 'is_open'), + Output('alert-element', 'children'), + Input('alert-message', 'data'), ) def show_alert( - msg: str | None + msg: str | None, ): - if msg is None or msg == "": - return False, "" + if msg is None or msg == '': + return False, '' logging.info(f"updated alert message: {msg}") return True, msg @app.callback( - Output("alert-message", "data"), - Output("vis-com-name", "data"), - Output("image-container", "src"), - Output({"type": "annotation", "index": ALL}, "value"), - Input("next-button", "n_clicks"), - State("vis-com-name", "data"), - State("image-container", "src"), - State({"type": "annotation", "index": ALL}, "id"), - State({"type": "annotation", "index": ALL}, "value"), + Output('alert-message', 'data'), + Output('vis-com-name', 'data'), + Output('image-container', 'src'), + Output({'type': 'annotation', 'index': ALL}, 'value'), + Input('next-button', 'n_clicks'), + State('vis-com-name', 'data'), + State('image-container', 'src'), + State({'type': 'annotation', 'index': ALL}, 'id'), + State({'type': 'annotation', 'index': ALL}, 'value'), prevent_initial_call=True, ) def cycle_visual_communication_data( n_clicks: int, vis_com_name: str, image_src: str, - annotation_keys: List, - annotation_values: List, + annotation_keys: list, + annotation_values: list, ): - logging.info("began cycling visual communication data") + logging.info('began cycling visual communication data') global collection # prepare default response response = [ - "", + '', vis_com_name, image_src, - annotation_values + annotation_values, ] # check if next-button clicked if n_clicks == 0: - logging.info("stopping early: next-button has not yet been clicked") + logging.info('stopping early: next-button has not yet been clicked') return response # check if visual communication name is set if len(vis_com_name) > 0: - logging.info("saving annotations to database: %s", vis_com_name) + logging.info('saving annotations to database: %s', vis_com_name) try: # extract option keys annotation_keys = [ - elem["index"] + elem['index'] for elem in annotation_keys ] # ensure all options are set @@ -114,7 +118,7 @@ def cycle_visual_communication_data( upsert_annotations( collection=collection, vis_com_name=vis_com_name, - annotations=annotations + annotations=annotations, ) except (ValueError, ValidationError) as exc: msg = f"failed saving annotation: {exc}" @@ -122,12 +126,12 @@ def cycle_visual_communication_data( response[0] = msg return tuple(response) # get new visual communication - logging.info("trying to get new visual communication") + logging.info('trying to get new visual communication') try: # get data vis_com = get_visual_communication( collection=collection, - with_annotation=False + with_annotation=False, ) # set variables vis_com_name = vis_com.name @@ -139,7 +143,7 @@ def cycle_visual_communication_data( # reset annotations annotation_values = [None for elem in annotation_values] except NoDocumentFoundException: - msg = "no unannotated data in database" + msg = 'no unannotated data in database' logging.warning(msg) response[0] = msg return tuple(response) @@ -147,5 +151,5 @@ def cycle_visual_communication_data( response[1] = vis_com_name response[2] = image_src response[3] = annotation_values - logging.info("finished getting visual communication: %s", vis_com_name) + logging.info('finished getting visual communication: %s', vis_com_name) return tuple(response) diff --git a/src/web/layout/labels.py b/src/web/layout/labels.py index 616008b..f89519b 100644 --- a/src/web/layout/labels.py +++ b/src/web/layout/labels.py @@ -1,27 +1,24 @@ -from dash import html, dcc +from __future__ import annotations + import dash_mantine_components as dmc -from typing import List - -from src.model_experiential import ( - VisualSyntaxModelOutput -) -from src.model_interpersonal import ( - ContactModelOutput, - AngleModelOutput, - PointOfViewModelOutput, - DistanceModelOutput, - ModalityLightingModelOutput, - ModalityColorModelOutput, - ModalityDepthModelOutput -) -from src.model_textual import ( - InformationValueModelOutput, - FramingModelOutput, - SalienceModelOutput +from dash import dcc +from dash import html +from model_experiential import ( + VisualSyntaxModelOutput, ) +from model_interpersonal import AngleModelOutput +from model_interpersonal import ContactModelOutput +from model_interpersonal import DistanceModelOutput +from model_interpersonal import ModalityColorModelOutput +from model_interpersonal import ModalityDepthModelOutput +from model_interpersonal import ModalityLightingModelOutput +from model_interpersonal import PointOfViewModelOutput +from model_textual import FramingModelOutput +from model_textual import InformationValueModelOutput +from model_textual import SalienceModelOutput -def generate_option_labels(model) -> List[str]: +def generate_option_labels(model) -> list[str]: """Generate presentable list of attributes from an OutputModel.""" labels = [ label.replace('_', ' ').title() @@ -34,8 +31,8 @@ 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 @@ -44,20 +41,20 @@ 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['contact'] = generate_option_labels(ContactModelOutput) + options_map['angle'] = generate_option_labels(AngleModelOutput) + 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['distance'] = generate_option_labels(DistanceModelOutput) + options_map['modality lighting'] = generate_option_labels( + ModalityLightingModelOutput, ) - options_map["modality color"] = generate_option_labels( - ModalityColorModelOutput + options_map['modality color'] = generate_option_labels( + ModalityColorModelOutput, ) - options_map["modality depth"] = generate_option_labels( - ModalityDepthModelOutput + options_map['modality depth'] = generate_option_labels( + ModalityDepthModelOutput, ) return options_map @@ -66,11 +63,11 @@ 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) + options_map['framing'] = generate_option_labels(FramingModelOutput) + options_map['salience'] = generate_option_labels(SalienceModelOutput) return options_map @@ -78,11 +75,11 @@ def generate_textual_options_map(): experiential_map = generate_visual_syntax_options_map() experiential_container = dmc.Col( children=[ - html.H4("experiential".title()), - ], span=5 + html.H4('experiential'.title()), + ], span=5, ) for title, options in experiential_map.items(): - id_dict = {"type": "annotation", "index": title.replace('_', '-')} + id_dict = {'type': 'annotation', 'index': title.replace('_', '-')} experiential_container.children.append( dmc.Container([ html.B(title.title()), @@ -90,17 +87,17 @@ for title, options in experiential_map.items(): options=options, id=id_dict, ), - ]) + ]), ) # prepare interpersonal container interpersonal_map = generate_interpersonal_options_map() interpersonal_container = dmc.Col( children=[ - html.H4("interpersonal".title()), - ], span=3 + html.H4('interpersonal'.title()), + ], span=3, ) for title, options in interpersonal_map.items(): - id_dict = {"type": "annotation", "index": title.replace('_', '-')} + id_dict = {'type': 'annotation', 'index': title.replace('_', '-')} interpersonal_container.children.append( dmc.Container([ html.B(title.title()), @@ -108,17 +105,17 @@ for title, options in interpersonal_map.items(): options=options, id=id_dict, ), - ]) + ]), ) # prepare textual container textual_map = generate_textual_options_map() textual_container = dmc.Col( children=[ - html.H4("textual".title()), - ], span=4 + html.H4('textual'.title()), + ], span=4, ) for title, options in textual_map.items(): - id_dict = {"type": "annotation", "index": title.replace('_', '-')} + id_dict = {'type': 'annotation', 'index': title.replace('_', '-')} textual_container.children.append( dmc.Container([ html.B(title), @@ -126,7 +123,7 @@ for title, options in textual_map.items(): options=options, id=id_dict, ), - ]) + ]), ) labels_element = dmc.Grid( @@ -134,5 +131,5 @@ labels_element = dmc.Grid( experiential_container, interpersonal_container, textual_container, - ] + ], ) diff --git a/tests/test_generate_random_prediction.py b/tests/generate_random_prediction_test.py similarity index 57% rename from tests/test_generate_random_prediction.py rename to tests/generate_random_prediction_test.py index cc92bd4..ead903a 100644 --- a/tests/test_generate_random_prediction.py +++ b/tests/generate_random_prediction_test.py @@ -1,13 +1,15 @@ +from __future__ import annotations + from pathlib import Path -from src.database import VisualCommunication +from database import VisualCommunication -if __name__ == "__main__": +if __name__ == '__main__': # get list of image paths test_dir = Path(__file__).parent - img_dir = test_dir / "imgs" - img_path_list = [path for path in img_dir.glob("*.jpeg") if path.is_file()] + img_dir = test_dir / 'imgs' + 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 = [ @@ -16,6 +18,7 @@ if __name__ == "__main__": 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: + vis_com.generate_random_prediction() for vis_com in vis_com_list: print(vis_com) diff --git a/tests/test_get_visual_communication.py b/tests/get_visual_communication_test.py similarity index 59% rename from tests/test_get_visual_communication.py rename to tests/get_visual_communication_test.py index 21787c3..f701f2a 100644 --- a/tests/test_get_visual_communication.py +++ b/tests/get_visual_communication_test.py @@ -1,18 +1,18 @@ -from pathlib import Path -from dotenv import load_dotenv +from __future__ import annotations + import os +from pathlib import Path -from src.database import ( - connect, - get_visual_communication -) +from database import connect +from database import get_visual_communication +from dotenv import load_dotenv -if __name__ == "__main__": +if __name__ == '__main__': # prepare env vars - env_path = Path(__file__).parent.parent / "local.env" + env_path = Path(__file__).parent.parent / 'local.env' assert env_path.exists() load_dotenv(env_path) - os.environ["MONGO_HOST"] = "localhost" + os.environ['MONGO_HOST'] = 'localhost' # connect to database collection, db, client = connect() print(client.server_info()) diff --git a/tests/test_image_download.py b/tests/image_download_test.py similarity index 67% rename from tests/test_image_download.py rename to tests/image_download_test.py index bbb6ac6..76a166f 100644 --- a/tests/test_image_download.py +++ b/tests/image_download_test.py @@ -1,15 +1,18 @@ -from pathlib import Path -from dotenv import load_dotenv +from __future__ import annotations + import os +from pathlib import Path -from src.database import VisualCommunication, connect +from database import connect +from database import VisualCommunication +from dotenv import load_dotenv -if __name__ == "__main__": +if __name__ == '__main__': # prepare env vars - env_path = Path(__file__).parent.parent / "local.env" + env_path = Path(__file__).parent.parent / 'local.env' assert env_path.exists() load_dotenv(env_path) - os.environ["MONGO_HOST"] = "localhost" + os.environ['MONGO_HOST'] = 'localhost' # connect to database collection, db, client = connect() print(client.server_info()) @@ -17,7 +20,7 @@ if __name__ == "__main__": data = None for data in collection.find().limit(3): if data is None: - print("no document found") + print('no document found') break vis_com: VisualCommunication = VisualCommunication.model_validate(data) print(repr(vis_com)) diff --git a/tests/test_image_upload.py b/tests/image_upload_test.py similarity index 70% rename from tests/test_image_upload.py rename to tests/image_upload_test.py index a89086e..30447e7 100644 --- a/tests/test_image_upload.py +++ b/tests/image_upload_test.py @@ -1,15 +1,18 @@ +from __future__ import annotations + +import os from pathlib import Path + +from database import connect +from database import VisualCommunication from dotenv import load_dotenv from pymongo.errors import DuplicateKeyError -import os -from src.database import VisualCommunication, connect - -if __name__ == "__main__": +if __name__ == '__main__': # get list of image paths test_dir = Path(__file__).parent - img_dir = test_dir / "imgs" - img_path_list = [path for path in img_dir.glob("*.jpeg") if path.is_file()] + img_dir = test_dir / 'imgs' + 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 = [ @@ -20,10 +23,10 @@ if __name__ == "__main__": for vis_com in vis_com_list: print(repr(vis_com)) # prepare env vars - env_path = test_dir.parent / "local.env" + env_path = test_dir.parent / 'local.env' assert env_path.exists() load_dotenv(env_path) - os.environ["MONGO_HOST"] = "localhost" + os.environ['MONGO_HOST'] = 'localhost' # connect to database collection, db, client = connect() print(client.server_info()) @@ -32,6 +35,6 @@ if __name__ == "__main__": try: result = collection.insert_one(vis_com.model_dump()) except DuplicateKeyError as exc: - print("ignoring:\n", exc) + print('ignoring:\n', exc) else: print(f"inserted document: {result}") diff --git a/tests/test_model_outputs_from_annotation.py b/tests/model_outputs_from_annotation_test.py similarity index 74% rename from tests/test_model_outputs_from_annotation.py rename to tests/model_outputs_from_annotation_test.py index 865c5d6..e3dc04e 100644 --- a/tests/test_model_outputs_from_annotation.py +++ b/tests/model_outputs_from_annotation_test.py @@ -1,7 +1,9 @@ -from src.database import ModelOutputs +from __future__ import annotations + +from database import ModelOutputs -if __name__ == "__main__": +if __name__ == '__main__': # instantiate data object vis_com_list = [ ModelOutputs.from_random() diff --git a/tests/test_prediction_upload.py b/tests/prediction_upload_test.py similarity index 66% rename from tests/test_prediction_upload.py rename to tests/prediction_upload_test.py index 6a94134..e517b84 100644 --- a/tests/test_prediction_upload.py +++ b/tests/prediction_upload_test.py @@ -1,15 +1,15 @@ -from pathlib import Path -from dotenv import load_dotenv -import os +from __future__ import annotations + import logging +import os +from pathlib import Path -from src.database import ( - VisualCommunication, - connect, - upsert_predictions -) +from database import connect +from database import upsert_predictions +from database import VisualCommunication +from dotenv import load_dotenv -if __name__ == "__main__": +if __name__ == '__main__': # setup logging fmt = ( '%(asctime)s | ' @@ -22,8 +22,8 @@ if __name__ == "__main__": logging.basicConfig(format=fmt, datefmt=datefmt, level=logging.INFO) # get list of image paths test_dir = Path(__file__).parent - img_dir = test_dir / "imgs" - img_path_list = [path for path in img_dir.glob("*.jpeg") if path.is_file()] + 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) @@ -31,16 +31,19 @@ if __name__ == "__main__": 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: + vis_com.generate_random_prediction() # prepare env vars - env_path = test_dir.parent / "local.env" + env_path = test_dir.parent / 'local.env' assert env_path.exists() load_dotenv(env_path) - os.environ["MONGO_HOST"] = "localhost" + os.environ['MONGO_HOST'] = 'localhost' # connect to database collection, db, client = connect() # upload visual communication for vis_com in vis_com_list: + if vis_com.prediction is None: + continue upsert_predictions( collection=collection, vis_com_name=vis_com.name, diff --git a/tests/test_total_annotated.py b/tests/total_annotated_test.py similarity index 60% rename from tests/test_total_annotated.py rename to tests/total_annotated_test.py index 1194b37..355a90d 100644 --- a/tests/test_total_annotated.py +++ b/tests/total_annotated_test.py @@ -1,18 +1,18 @@ -from pathlib import Path -from dotenv import load_dotenv +from __future__ import annotations + import os +from pathlib import Path -from src.database import ( - connect, - total_annotated -) +from database import connect +from database import total_annotated +from dotenv import load_dotenv -if __name__ == "__main__": +if __name__ == '__main__': # prepare env vars - env_path = Path(__file__).parent.parent / "local.env" + env_path = Path(__file__).parent.parent / 'local.env' assert env_path.exists() load_dotenv(env_path) - os.environ["MONGO_HOST"] = "localhost" + os.environ['MONGO_HOST'] = 'localhost' # connect to database collection, db, client = connect() # get visual communication diff --git a/tests/test_total_documents.py b/tests/total_documents_test.py similarity index 60% rename from tests/test_total_documents.py rename to tests/total_documents_test.py index e8bc1df..7a150f4 100644 --- a/tests/test_total_documents.py +++ b/tests/total_documents_test.py @@ -1,18 +1,18 @@ -from pathlib import Path -from dotenv import load_dotenv +from __future__ import annotations + import os +from pathlib import Path -from src.database import ( - connect, - total_documents -) +from database import connect +from database import total_documents +from dotenv import load_dotenv -if __name__ == "__main__": +if __name__ == '__main__': # prepare env vars - env_path = Path(__file__).parent.parent / "local.env" + env_path = Path(__file__).parent.parent / 'local.env' assert env_path.exists() load_dotenv(env_path) - os.environ["MONGO_HOST"] = "localhost" + os.environ['MONGO_HOST'] = 'localhost' # connect to database collection, db, client = connect() # get visual communication From d6f6f1b0beeab10a2e49fca46b4633206f883545 Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sun, 25 Feb 2024 14:38:07 +0100 Subject: [PATCH 19/48] updated workflow --- .gitea/workflows/default.yaml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.gitea/workflows/default.yaml b/.gitea/workflows/default.yaml index 8b73ce3..d039f92 100644 --- a/.gitea/workflows/default.yaml +++ b/.gitea/workflows/default.yaml @@ -18,9 +18,11 @@ jobs: - name: Install Packages run: | python -m pip install --upgrade pip - pip install poetry flake8 mypy types-pillow - poetry install + pip install poetry + poetry install --with main,test - name: PEP8 Check run: flake8 ./src --benchmark - name: Type Check - run: mypy ./src --disable-error-code=import-untyped + run: | + poetry run flake8 --version + mypy ./src --disable-error-code=import-untyped From 65f7b44690fa7cee604226bdddcc23e6ca3bfbc8 Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sun, 25 Feb 2024 14:44:49 +0100 Subject: [PATCH 20/48] updated workflow --- .gitea/workflows/default.yaml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.gitea/workflows/default.yaml b/.gitea/workflows/default.yaml index d039f92..13b5676 100644 --- a/.gitea/workflows/default.yaml +++ b/.gitea/workflows/default.yaml @@ -19,10 +19,13 @@ jobs: run: | python -m pip install --upgrade pip pip install poetry - poetry install --with main,test + poetry install + poetry show - name: PEP8 Check - run: flake8 ./src --benchmark - - name: Type Check run: | poetry run flake8 --version + poetry run flake8 ./src --benchmark + - name: Type Check + run: | + poetry run mypy --version mypy ./src --disable-error-code=import-untyped From e302f229a884aa5bb1b2fbfbca533f63b3a22333 Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sun, 25 Feb 2024 14:46:31 +0100 Subject: [PATCH 21/48] updated workflow --- .gitea/workflows/default.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitea/workflows/default.yaml b/.gitea/workflows/default.yaml index 13b5676..9834d6a 100644 --- a/.gitea/workflows/default.yaml +++ b/.gitea/workflows/default.yaml @@ -17,7 +17,6 @@ jobs: architecture: "x64" - name: Install Packages run: | - python -m pip install --upgrade pip pip install poetry poetry install poetry show @@ -28,4 +27,4 @@ jobs: - name: Type Check run: | poetry run mypy --version - mypy ./src --disable-error-code=import-untyped + poetry run mypy ./src --disable-error-code=import-untyped From b98376f27deef1148b4b14361bcc6269f34ad610 Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sun, 25 Feb 2024 14:48:16 +0100 Subject: [PATCH 22/48] updated workflow --- .gitea/workflows/default.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.gitea/workflows/default.yaml b/.gitea/workflows/default.yaml index 9834d6a..1f6036b 100644 --- a/.gitea/workflows/default.yaml +++ b/.gitea/workflows/default.yaml @@ -19,12 +19,9 @@ jobs: run: | pip install poetry poetry install - poetry show - name: PEP8 Check run: | - poetry run flake8 --version poetry run flake8 ./src --benchmark - name: Type Check run: | - poetry run mypy --version poetry run mypy ./src --disable-error-code=import-untyped From 7722572e19ad018781fa66cba44f84891cddcb34 Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sun, 25 Feb 2024 15:07:51 +0100 Subject: [PATCH 23/48] added publish workflow --- .gitea/workflows/publish.yaml | 44 +++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 .gitea/workflows/publish.yaml diff --git a/.gitea/workflows/publish.yaml b/.gitea/workflows/publish.yaml new file mode 100644 index 0000000..132d1f5 --- /dev/null +++ b/.gitea/workflows/publish.yaml @@ -0,0 +1,44 @@ +name: CI Pipeline +run-name: Build and Publish Pipeline +runs-on: ubuntu-latest +on: + pull_request: + branches: + - main +jobs: + test: + name: Test + runs-on: ubuntu-latest + steps: + - name: Checkout Code + uses: actions/checkout@v3 + - name: Setup Environment + uses: https://github.com/actions/setup-python@v3 + with: + python-verison: "3.12" + architecture: "x64" + - name: Install Packages + run: | + pip install poetry + poetry install + - name: PEP8 Check + run: | + poetry run flake8 ./src --benchmark + - name: Type Check + run: | + poetry run mypy ./src --disable-error-code=import-untyped + publish: + name: Build and Publish + runs-on: ubuntu-latest + needs: [test] + steps: + - name: Checkout Code + uses: actions/checkout@v3 + - name: Set Environment Variables + run: | + echo "sha_short=$(git rev-parse --short "$GITEA_SHA")" >> "$GITEA_ENV" + echo "branch=$(echo ${GITEA_REF#refs/heads/})" >> "$GITEA_ENV" + - name: Print Env Vars + run: | + echo "Branch: ${{ env.branch }}" + echo "Sha: ${{ env.sha_short }}" From 2789c275fa21ee3593e3bae78f2fe37fbd3c73d2 Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sun, 25 Feb 2024 15:14:26 +0100 Subject: [PATCH 24/48] added publish workflow --- .gitea/workflows/publish.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitea/workflows/publish.yaml b/.gitea/workflows/publish.yaml index 132d1f5..cad7372 100644 --- a/.gitea/workflows/publish.yaml +++ b/.gitea/workflows/publish.yaml @@ -37,7 +37,6 @@ jobs: - name: Set Environment Variables run: | echo "sha_short=$(git rev-parse --short "$GITEA_SHA")" >> "$GITEA_ENV" - echo "branch=$(echo ${GITEA_REF#refs/heads/})" >> "$GITEA_ENV" - name: Print Env Vars run: | echo "Branch: ${{ env.branch }}" From 15459711875b381f925fae6ab60c7e08bec08719 Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sun, 25 Feb 2024 15:31:11 +0100 Subject: [PATCH 25/48] updated workflow --- .gitea/workflows/default.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitea/workflows/default.yaml b/.gitea/workflows/default.yaml index 1f6036b..cc46c3e 100644 --- a/.gitea/workflows/default.yaml +++ b/.gitea/workflows/default.yaml @@ -25,3 +25,6 @@ jobs: - name: Type Check run: | poetry run mypy ./src --disable-error-code=import-untyped + - name: Show Environment Variables + run: | + echo "REPOSITORY: ${{ gitea.repository }}" From e72b0d92f4d500c5d47ab32316414ad00e3622ff Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sun, 25 Feb 2024 15:41:38 +0100 Subject: [PATCH 26/48] updated workflow --- .gitea/workflows/default.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitea/workflows/default.yaml b/.gitea/workflows/default.yaml index cc46c3e..a3b999c 100644 --- a/.gitea/workflows/default.yaml +++ b/.gitea/workflows/default.yaml @@ -28,3 +28,4 @@ jobs: - name: Show Environment Variables run: | echo "REPOSITORY: ${{ gitea.repository }}" + echo "DOCKER_REPO_URL: ${{vars.docker_repo_url }}" From a9dd56dc651dc41a2a9f926223ebc0cec6ffbdc2 Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sun, 25 Feb 2024 15:46:10 +0100 Subject: [PATCH 27/48] updated workflow --- .gitea/workflows/default.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitea/workflows/default.yaml b/.gitea/workflows/default.yaml index a3b999c..c8e200b 100644 --- a/.gitea/workflows/default.yaml +++ b/.gitea/workflows/default.yaml @@ -28,4 +28,5 @@ jobs: - name: Show Environment Variables run: | echo "REPOSITORY: ${{ gitea.repository }}" - echo "DOCKER_REPO_URL: ${{vars.docker_repo_url }}" + echo "DOCKER_REPO_URL: ${{ vars.docker_repo_url }}" + echo "COMMIT_SHA: ${{ env.gitea_sha }}" From 2866647e2e35550cff3795bbfb63151267048221 Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sun, 25 Feb 2024 15:53:14 +0100 Subject: [PATCH 28/48] updated workflow --- .gitea/workflows/default.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/default.yaml b/.gitea/workflows/default.yaml index c8e200b..586d1db 100644 --- a/.gitea/workflows/default.yaml +++ b/.gitea/workflows/default.yaml @@ -29,4 +29,4 @@ jobs: run: | echo "REPOSITORY: ${{ gitea.repository }}" echo "DOCKER_REPO_URL: ${{ vars.docker_repo_url }}" - echo "COMMIT_SHA: ${{ env.gitea_sha }}" + echo "COMMIT_SHA: ${{ gitea.sha }}" From 20e53c74a09e66706cfb339cc670962a6f09a42d Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sun, 25 Feb 2024 15:57:49 +0100 Subject: [PATCH 29/48] updated workflow --- .gitea/workflows/default.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitea/workflows/default.yaml b/.gitea/workflows/default.yaml index 586d1db..4061cbd 100644 --- a/.gitea/workflows/default.yaml +++ b/.gitea/workflows/default.yaml @@ -30,3 +30,5 @@ jobs: echo "REPOSITORY: ${{ gitea.repository }}" echo "DOCKER_REPO_URL: ${{ vars.docker_repo_url }}" echo "COMMIT_SHA: ${{ gitea.sha }}" + sha_short = $(git rev-parse --short ${{gitea.sha }}) + echo "SHA_SHORT: ${ sha_short }" From 544972342abd981f10cc129aeb9cf01170159250 Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sun, 25 Feb 2024 15:59:35 +0100 Subject: [PATCH 30/48] updated workflow --- .gitea/workflows/default.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/default.yaml b/.gitea/workflows/default.yaml index 4061cbd..7044903 100644 --- a/.gitea/workflows/default.yaml +++ b/.gitea/workflows/default.yaml @@ -30,5 +30,5 @@ jobs: echo "REPOSITORY: ${{ gitea.repository }}" echo "DOCKER_REPO_URL: ${{ vars.docker_repo_url }}" echo "COMMIT_SHA: ${{ gitea.sha }}" - sha_short = $(git rev-parse --short ${{gitea.sha }}) - echo "SHA_SHORT: ${ sha_short }" + sha_short = $(git rev-parse --short ${{ gitea.sha }}) + echo "SHA_SHORT: $sha_short" From 64d034966ba8410384ca828b4a66158b9581ca5f Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sun, 25 Feb 2024 16:01:11 +0100 Subject: [PATCH 31/48] updated workflow --- .gitea/workflows/default.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/default.yaml b/.gitea/workflows/default.yaml index 7044903..79b6d4e 100644 --- a/.gitea/workflows/default.yaml +++ b/.gitea/workflows/default.yaml @@ -31,4 +31,4 @@ jobs: echo "DOCKER_REPO_URL: ${{ vars.docker_repo_url }}" echo "COMMIT_SHA: ${{ gitea.sha }}" sha_short = $(git rev-parse --short ${{ gitea.sha }}) - echo "SHA_SHORT: $sha_short" + echo "SHA_SHORT: ${{ sha_short }}" From eda95fe051d5219ad077cffe6a34568f4607c119 Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sun, 25 Feb 2024 16:05:11 +0100 Subject: [PATCH 32/48] updated workflow --- .gitea/workflows/default.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitea/workflows/default.yaml b/.gitea/workflows/default.yaml index 79b6d4e..7b7fe49 100644 --- a/.gitea/workflows/default.yaml +++ b/.gitea/workflows/default.yaml @@ -30,5 +30,4 @@ jobs: echo "REPOSITORY: ${{ gitea.repository }}" echo "DOCKER_REPO_URL: ${{ vars.docker_repo_url }}" echo "COMMIT_SHA: ${{ gitea.sha }}" - sha_short = $(git rev-parse --short ${{ gitea.sha }}) - echo "SHA_SHORT: ${{ sha_short }}" + echo $(git rev-parse --short ${{ gitea.sha }}) From 67b3cc894b77fc99f2174c67f8c78b6e3a2e9558 Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sun, 25 Feb 2024 16:10:56 +0100 Subject: [PATCH 33/48] updated workflow --- .gitea/workflows/default.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitea/workflows/default.yaml b/.gitea/workflows/default.yaml index 7b7fe49..fc28817 100644 --- a/.gitea/workflows/default.yaml +++ b/.gitea/workflows/default.yaml @@ -31,3 +31,6 @@ jobs: echo "DOCKER_REPO_URL: ${{ vars.docker_repo_url }}" echo "COMMIT_SHA: ${{ gitea.sha }}" echo $(git rev-parse --short ${{ gitea.sha }}) + commit_sha = $(git rev-parse --short ${{ gitea.sha }}) + echo "${ commit_sha }" + echo "${{ gitea.env }}" From bc5afe3d6e61905bcc504d84a298d9d0d2e13d90 Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sun, 25 Feb 2024 16:20:16 +0100 Subject: [PATCH 34/48] updated workflow --- .gitea/workflows/default.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/default.yaml b/.gitea/workflows/default.yaml index fc28817..b98eeb8 100644 --- a/.gitea/workflows/default.yaml +++ b/.gitea/workflows/default.yaml @@ -26,11 +26,12 @@ jobs: run: | poetry run mypy ./src --disable-error-code=import-untyped - name: Show Environment Variables + id: vars run: | echo "REPOSITORY: ${{ gitea.repository }}" echo "DOCKER_REPO_URL: ${{ vars.docker_repo_url }}" echo "COMMIT_SHA: ${{ gitea.sha }}" echo $(git rev-parse --short ${{ gitea.sha }}) - commit_sha = $(git rev-parse --short ${{ gitea.sha }}) - echo "${ commit_sha }" + echo ::set-output name=SHA_SHORT::$(git rev-parse --short ${{ gitea.sha }}) + echo "${ steps.vars.outputs.SHA_SHORT }" echo "${{ gitea.env }}" From 074d258621ab92db0a06340de8f0ef0bbda2b36d Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sun, 25 Feb 2024 16:26:18 +0100 Subject: [PATCH 35/48] updated workflow --- .gitea/workflows/default.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/default.yaml b/.gitea/workflows/default.yaml index b98eeb8..504f8c0 100644 --- a/.gitea/workflows/default.yaml +++ b/.gitea/workflows/default.yaml @@ -32,6 +32,6 @@ jobs: echo "DOCKER_REPO_URL: ${{ vars.docker_repo_url }}" echo "COMMIT_SHA: ${{ gitea.sha }}" echo $(git rev-parse --short ${{ gitea.sha }}) - echo ::set-output name=SHA_SHORT::$(git rev-parse --short ${{ gitea.sha }}) - echo "${ steps.vars.outputs.SHA_SHORT }" + echo "SHA_SHORT=$(git rev-parse --short ${{ gitea.sha }} )"" + echo "${ SHA_SHORT }" echo "${{ gitea.env }}" From 277d647aa1407643c35e0bdbf4cafc21241a8031 Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sun, 25 Feb 2024 16:28:48 +0100 Subject: [PATCH 36/48] updated workflow --- .gitea/workflows/default.yaml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/.gitea/workflows/default.yaml b/.gitea/workflows/default.yaml index 504f8c0..1f6036b 100644 --- a/.gitea/workflows/default.yaml +++ b/.gitea/workflows/default.yaml @@ -25,13 +25,3 @@ jobs: - name: Type Check run: | poetry run mypy ./src --disable-error-code=import-untyped - - name: Show Environment Variables - id: vars - run: | - echo "REPOSITORY: ${{ gitea.repository }}" - echo "DOCKER_REPO_URL: ${{ vars.docker_repo_url }}" - echo "COMMIT_SHA: ${{ gitea.sha }}" - echo $(git rev-parse --short ${{ gitea.sha }}) - echo "SHA_SHORT=$(git rev-parse --short ${{ gitea.sha }} )"" - echo "${ SHA_SHORT }" - echo "${{ gitea.env }}" From 266f02280d42799ddf2f3538601117ba3ae8c2f9 Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sun, 25 Feb 2024 16:29:07 +0100 Subject: [PATCH 37/48] added show env vars workflow --- .gitea/workflows/show_env_vars.yaml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 .gitea/workflows/show_env_vars.yaml diff --git a/.gitea/workflows/show_env_vars.yaml b/.gitea/workflows/show_env_vars.yaml new file mode 100644 index 0000000..4390c63 --- /dev/null +++ b/.gitea/workflows/show_env_vars.yaml @@ -0,0 +1,20 @@ +name: pipeline +run-name: ${{ gitea.actor }} is running the script +runs-on: ubuntu-latest +on: push +image: python:3.12 +jobs: + show: + name: Show + runs-on: ubuntu-latest + steps: + - name: Show Environment Variables + id: vars + run: | + echo "REPOSITORY: ${{ gitea.repository }}" + echo "DOCKER_REPO_URL: ${{ vars.docker_repo_url }}" + echo "COMMIT_SHA: ${{ gitea.sha }}" + echo $(git rev-parse --short ${{ gitea.sha }}) + echo "SHA_SHORT=$(git rev-parse --short ${{ gitea.sha }} )" + echo "${ SHA_SHORT }" + echo "${{ gitea.env }}" From 09594e7fd153e86a77181486b9311a21cf2d48bb Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sun, 25 Feb 2024 16:31:59 +0100 Subject: [PATCH 38/48] updated workflow --- .gitea/workflows/show_env_vars.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitea/workflows/show_env_vars.yaml b/.gitea/workflows/show_env_vars.yaml index 4390c63..3f87dbc 100644 --- a/.gitea/workflows/show_env_vars.yaml +++ b/.gitea/workflows/show_env_vars.yaml @@ -8,6 +8,8 @@ jobs: name: Show runs-on: ubuntu-latest steps: + - name: Checkout Code + uses: actions/checkout@v3 - name: Show Environment Variables id: vars run: | From 8fe8b27aad8e6252da0fffdb396577a1d35cd97c Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sun, 25 Feb 2024 16:38:09 +0100 Subject: [PATCH 39/48] updated workflow --- .gitea/workflows/show_env_vars.yaml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.gitea/workflows/show_env_vars.yaml b/.gitea/workflows/show_env_vars.yaml index 3f87dbc..3023abc 100644 --- a/.gitea/workflows/show_env_vars.yaml +++ b/.gitea/workflows/show_env_vars.yaml @@ -10,13 +10,18 @@ jobs: steps: - name: Checkout Code uses: actions/checkout@v3 - - name: Show Environment Variables + - name: Set Environment Variables id: vars run: | echo "REPOSITORY: ${{ gitea.repository }}" echo "DOCKER_REPO_URL: ${{ vars.docker_repo_url }}" echo "COMMIT_SHA: ${{ gitea.sha }}" echo $(git rev-parse --short ${{ gitea.sha }}) - echo "SHA_SHORT=$(git rev-parse --short ${{ gitea.sha }} )" - echo "${ SHA_SHORT }" + echo "sha_short=$(git rev-parse --short ${{ gitea.sha }} )" >> "$vars" echo "${{ gitea.env }}" + - name: Show Environment Variables + run: | + echo "REPOSITORY: ${{ gitea.repository }}" + echo "DOCKER_REPO_URL: ${{ vars.docker_repo_url }}" + echo "COMMIT_SHA: ${{ gitea.sha }}" + echo "${{ vars.sha_short }}" From 82d34a7412826268536ec5977223cbd60b5d2039 Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sun, 25 Feb 2024 16:42:47 +0100 Subject: [PATCH 40/48] updated workflow --- .gitea/workflows/show_env_vars.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/show_env_vars.yaml b/.gitea/workflows/show_env_vars.yaml index 3023abc..63a15d9 100644 --- a/.gitea/workflows/show_env_vars.yaml +++ b/.gitea/workflows/show_env_vars.yaml @@ -17,7 +17,7 @@ jobs: echo "DOCKER_REPO_URL: ${{ vars.docker_repo_url }}" echo "COMMIT_SHA: ${{ gitea.sha }}" echo $(git rev-parse --short ${{ gitea.sha }}) - echo "sha_short=$(git rev-parse --short ${{ gitea.sha }} )" >> "$vars" + echo "sha_short=$(git rev-parse --short ${{ gitea.sha }} )" >> "$GITHUB_ENV" echo "${{ gitea.env }}" - name: Show Environment Variables run: | From 73cc268bc60e6fcbec62814dde2fec222ca3a2ed Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sun, 25 Feb 2024 16:44:45 +0100 Subject: [PATCH 41/48] updated workflow --- .gitea/workflows/show_env_vars.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitea/workflows/show_env_vars.yaml b/.gitea/workflows/show_env_vars.yaml index 63a15d9..66a0ec9 100644 --- a/.gitea/workflows/show_env_vars.yaml +++ b/.gitea/workflows/show_env_vars.yaml @@ -23,5 +23,4 @@ jobs: run: | echo "REPOSITORY: ${{ gitea.repository }}" echo "DOCKER_REPO_URL: ${{ vars.docker_repo_url }}" - echo "COMMIT_SHA: ${{ gitea.sha }}" - echo "${{ vars.sha_short }}" + echo "COMMIT_SHA: ${{ env.sha_short }}" From bfb079a9b75be95078309ddf891b39025dd2ca3e Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sun, 25 Feb 2024 16:50:59 +0100 Subject: [PATCH 42/48] updated workflow --- .gitea/workflows/show_env_vars.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitea/workflows/show_env_vars.yaml b/.gitea/workflows/show_env_vars.yaml index 66a0ec9..b8d342e 100644 --- a/.gitea/workflows/show_env_vars.yaml +++ b/.gitea/workflows/show_env_vars.yaml @@ -17,8 +17,7 @@ jobs: echo "DOCKER_REPO_URL: ${{ vars.docker_repo_url }}" echo "COMMIT_SHA: ${{ gitea.sha }}" echo $(git rev-parse --short ${{ gitea.sha }}) - echo "sha_short=$(git rev-parse --short ${{ gitea.sha }} )" >> "$GITHUB_ENV" - echo "${{ gitea.env }}" + echo "sha_short=$(git rev-parse --short ${{ gitea.sha }} )" >> "$GITEA_ENV" - name: Show Environment Variables run: | echo "REPOSITORY: ${{ gitea.repository }}" From 5b1a49ec71efc848f9936e1740f16ed0c4c4a9d5 Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sun, 25 Feb 2024 16:53:10 +0100 Subject: [PATCH 43/48] updated workflow --- .gitea/workflows/show_env_vars.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/show_env_vars.yaml b/.gitea/workflows/show_env_vars.yaml index b8d342e..2fc22fe 100644 --- a/.gitea/workflows/show_env_vars.yaml +++ b/.gitea/workflows/show_env_vars.yaml @@ -17,7 +17,7 @@ jobs: echo "DOCKER_REPO_URL: ${{ vars.docker_repo_url }}" echo "COMMIT_SHA: ${{ gitea.sha }}" echo $(git rev-parse --short ${{ gitea.sha }}) - echo "sha_short=$(git rev-parse --short ${{ gitea.sha }} )" >> "$GITEA_ENV" + echo "sha_short=$(git rev-parse --short ${{ gitea.sha }} )" >> "$GITHUB_ENV" - name: Show Environment Variables run: | echo "REPOSITORY: ${{ gitea.repository }}" From 0922f5ee3583cae59b50a7d9414b2bd4303a7133 Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sun, 25 Feb 2024 16:56:08 +0100 Subject: [PATCH 44/48] updated workflow --- .gitea/workflows/show_env_vars.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitea/workflows/show_env_vars.yaml b/.gitea/workflows/show_env_vars.yaml index 2fc22fe..5bd051a 100644 --- a/.gitea/workflows/show_env_vars.yaml +++ b/.gitea/workflows/show_env_vars.yaml @@ -11,7 +11,6 @@ jobs: - name: Checkout Code uses: actions/checkout@v3 - name: Set Environment Variables - id: vars run: | echo "REPOSITORY: ${{ gitea.repository }}" echo "DOCKER_REPO_URL: ${{ vars.docker_repo_url }}" From c9cd778f31fa4f88d8372712f5b547f8d5f67c8f Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sun, 25 Feb 2024 17:03:35 +0100 Subject: [PATCH 45/48] updated workflow --- .gitea/workflows/publish.yaml | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/.gitea/workflows/publish.yaml b/.gitea/workflows/publish.yaml index cad7372..e4fef86 100644 --- a/.gitea/workflows/publish.yaml +++ b/.gitea/workflows/publish.yaml @@ -36,8 +36,16 @@ jobs: uses: actions/checkout@v3 - name: Set Environment Variables run: | - echo "sha_short=$(git rev-parse --short "$GITEA_SHA")" >> "$GITEA_ENV" - - name: Print Env Vars + echo $(git rev-parse --short ${{ gitea.sha }}) + echo "sha_short=$(git rev-parse --short ${{ gitea.sha }} )" >> "$GITHUB_ENV" + - name: Show Environment Variables run: | - echo "Branch: ${{ env.branch }}" - echo "Sha: ${{ env.sha_short }}" + echo "DOCKER_REPO_URL: ${{ vars.docker_repo_url }}" + echo "REPOSITORY: ${{ gitea.repository }}" + echo "COMMIT_SHA: ${{ env.sha_short }}" + - name: Build and Push Image + uses: docker/build-push-action@v2 + with: + context: . + push: true + tags: ${{vars.docker_repo_url}}/${{gitea.repository}}:latest From 53a03d780dd66f645ed058eea3b15596e8bea1ee Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sun, 25 Feb 2024 17:23:33 +0100 Subject: [PATCH 46/48] updated workflow name --- .gitea/workflows/default.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/default.yaml b/.gitea/workflows/default.yaml index 1f6036b..c7fbce7 100644 --- a/.gitea/workflows/default.yaml +++ b/.gitea/workflows/default.yaml @@ -1,5 +1,5 @@ -name: pipeline -run-name: ${{ gitea.actor }} is running the script +name: Code Quality Pipeline +run-name: ${{ gitea.actor }} is running the Code Quality Pipeline runs-on: ubuntu-latest on: push image: python:3.12 From b2b69981a101a2e8b2ca7842493796b3f3ad9404 Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sun, 25 Feb 2024 17:23:55 +0100 Subject: [PATCH 47/48] added multiple tags to docker push --- .gitea/workflows/publish.yaml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.gitea/workflows/publish.yaml b/.gitea/workflows/publish.yaml index e4fef86..fcbf00d 100644 --- a/.gitea/workflows/publish.yaml +++ b/.gitea/workflows/publish.yaml @@ -1,5 +1,5 @@ name: CI Pipeline -run-name: Build and Publish Pipeline +run-name: ${{ gitea.actor }} is running the CI Pipeline runs-on: ubuntu-latest on: pull_request: @@ -36,7 +36,6 @@ jobs: uses: actions/checkout@v3 - name: Set Environment Variables run: | - echo $(git rev-parse --short ${{ gitea.sha }}) echo "sha_short=$(git rev-parse --short ${{ gitea.sha }} )" >> "$GITHUB_ENV" - name: Show Environment Variables run: | @@ -48,4 +47,6 @@ jobs: with: context: . push: true - tags: ${{vars.docker_repo_url}}/${{gitea.repository}}:latest + tags: | + ${{ vars.docker_repo_url }}/${{ gitea.repository }}:${{ env.sha_short }} + ${{ vars.docker_repo_url }}/${{ gitea.repository }}:latest From 7334b278496c014fe0ef7e6a03ec3aed2c64f0f7 Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Sun, 25 Feb 2024 17:56:55 +0100 Subject: [PATCH 48/48] updated relative imports --- src/__init__.py | 0 src/database/classes.py | 27 ++++++++++++++------------- src/main.py | 3 ++- src/web/__init__.py | 8 ++++---- src/web/app.py | 10 +++++----- src/web/layout/labels.py | 25 ++++++++++++------------- 6 files changed, 37 insertions(+), 36 deletions(-) create mode 100644 src/__init__.py diff --git a/src/__init__.py b/src/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/database/classes.py b/src/database/classes.py index eceff66..e3106cc 100644 --- a/src/database/classes.py +++ b/src/database/classes.py @@ -5,24 +5,25 @@ from base64 import b64encode from io import BytesIO from pathlib import Path -from model_experiential import ( - VisualSyntaxModelOutput, -) -from model_interpersonal import AngleModelOutput -from model_interpersonal import ContactModelOutput -from model_interpersonal import DistanceModelOutput -from model_interpersonal import ModalityColorModelOutput -from model_interpersonal import ModalityDepthModelOutput -from model_interpersonal import ModalityLightingModelOutput -from model_interpersonal import PointOfViewModelOutput -from model_textual import FramingModelOutput -from model_textual import InformationValueModelOutput -from model_textual import SalienceModelOutput from PIL import Image from pydantic import BaseModel from pydantic import field_serializer from pydantic import field_validator +from src.model_experiential import ( + VisualSyntaxModelOutput, +) +from src.model_interpersonal import AngleModelOutput +from src.model_interpersonal import ContactModelOutput +from src.model_interpersonal import DistanceModelOutput +from src.model_interpersonal import ModalityColorModelOutput +from src.model_interpersonal import ModalityDepthModelOutput +from src.model_interpersonal import ModalityLightingModelOutput +from src.model_interpersonal import PointOfViewModelOutput +from src.model_textual import FramingModelOutput +from src.model_textual import InformationValueModelOutput +from src.model_textual import SalienceModelOutput + class NoDocumentFoundException(Exception): pass diff --git a/src/main.py b/src/main.py index 9177f3c..803d203 100644 --- a/src/main.py +++ b/src/main.py @@ -5,7 +5,8 @@ import os from pathlib import Path from dotenv import load_dotenv -from web import app + +from src.web import app # prepare optional local setup env_path = Path(__file__).parent.parent / 'local.env' diff --git a/src/web/__init__.py b/src/web/__init__.py index 2bbf8b9..3bb26dd 100644 --- a/src/web/__init__.py +++ b/src/web/__init__.py @@ -1,4 +1,4 @@ -from .app import ( - app, - server -) +from __future__ import annotations + +from src.web.app import app +from src.web.app import server diff --git a/src/web/app.py b/src/web/app.py index fb94d05..b6ece1c 100644 --- a/src/web/app.py +++ b/src/web/app.py @@ -10,14 +10,14 @@ from dash import Input from dash import Output from dash import State from dash_auth import BasicAuth -from database import connect -from database import get_visual_communication -from database import ModelOutputs -from database import NoDocumentFoundException -from database import upsert_annotations from pydantic import ValidationError from .layout import app_layout +from src.database import connect +from src.database import get_visual_communication +from src.database import ModelOutputs +from src.database import NoDocumentFoundException +from src.database import upsert_annotations # setup app app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP]) diff --git a/src/web/layout/labels.py b/src/web/layout/labels.py index f89519b..b7081d7 100644 --- a/src/web/layout/labels.py +++ b/src/web/layout/labels.py @@ -3,19 +3,18 @@ from __future__ import annotations import dash_mantine_components as dmc from dash import dcc from dash import html -from model_experiential import ( - VisualSyntaxModelOutput, -) -from model_interpersonal import AngleModelOutput -from model_interpersonal import ContactModelOutput -from model_interpersonal import DistanceModelOutput -from model_interpersonal import ModalityColorModelOutput -from model_interpersonal import ModalityDepthModelOutput -from model_interpersonal import ModalityLightingModelOutput -from model_interpersonal import PointOfViewModelOutput -from model_textual import FramingModelOutput -from model_textual import InformationValueModelOutput -from model_textual import SalienceModelOutput + +from src.model_experiential import VisualSyntaxModelOutput +from src.model_interpersonal import AngleModelOutput +from src.model_interpersonal import ContactModelOutput +from src.model_interpersonal import DistanceModelOutput +from src.model_interpersonal import ModalityColorModelOutput +from src.model_interpersonal import ModalityDepthModelOutput +from src.model_interpersonal import ModalityLightingModelOutput +from src.model_interpersonal import PointOfViewModelOutput +from src.model_textual import FramingModelOutput +from src.model_textual import InformationValueModelOutput +from src.model_textual import SalienceModelOutput def generate_option_labels(model) -> list[str]: