Repository: lastmile-ai/aiconfig (language: python)

Issue:
[ci/cd] Python Formatting Check
[ci/cd] Python Formatting Check

blocks on merging 

---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/lastmile-ai/aiconfig/pull/1458).
* __->__ #1458
* #1459


Discussion / hints:

Fix patch:
diff --git a/.github/workflows/check_formatting.yml b/.github/workflows/check_formatting.yml
new file mode 100644
index 000000000..7525d4fa7
--- /dev/null
+++ b/.github/workflows/check_formatting.yml
@@ -0,0 +1,12 @@
+name: Check Python Formatting
+
+on: [pull_request]
+
+jobs:
+  lint:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v3
+      - uses: psf/black@stable
+        with:
+          options: "--check --line-length=79" # In line with .vscode/settings.json
\ No newline at end of file
diff --git a/cookbooks/Claude-And-Azure/aiconfig_model_registry.py b/cookbooks/Claude-And-Azure/aiconfig_model_registry.py
index 27f61cfb3..5b66c4c98 100644
--- a/cookbooks/Claude-And-Azure/aiconfig_model_registry.py
+++ b/cookbooks/Claude-And-Azure/aiconfig_model_registry.py
@@ -7,7 +7,6 @@
     See example below.
 """
 
-
 from aiconfig import AzureOpenAIParser, ModelParserRegistry
 import dotenv
 
diff --git a/cookbooks/Groq/aiconfig_model_registry.py b/cookbooks/Groq/aiconfig_model_registry.py
index 7eb341979..0308bebc8 100644
--- a/cookbooks/Groq/aiconfig_model_registry.py
+++ b/cookbooks/Groq/aiconfig_model_registry.py
@@ -11,6 +11,7 @@
 from aiconfig import ModelParserRegistry
 import dotenv
 
+
 def register_model_parsers() -> None:
     groq_mixtral = GroqParser(model="mixtral-8x7b-32768")
     ModelParserRegistry.register_model_parser(groq_mixtral)
diff --git a/extensions/Gemini/python/src/aiconfig_extension_gemini/Gemini.py b/extensions/Gemini/python/src/aiconfig_extension_gemini/Gemini.py
index ddcc51352..6fc30a875 100644
--- a/extensions/Gemini/python/src/aiconfig_extension_gemini/Gemini.py
+++ b/extensions/Gemini/python/src/aiconfig_extension_gemini/Gemini.py
@@ -342,10 +342,10 @@ async def deserialize(
                     "Unable to deserialize input. Prompt input type is not a string, Gemini Model Parser expects prompt input to contain a 'contents' field as expected by Gemini API"
                 )
 
-            completion_data[
-                "contents"
-            ] = parameterize_supported_gemini_input_data(
-                prompt_input.contents, prompt, aiconfig, params
+            completion_data["contents"] = (
+                parameterize_supported_gemini_input_data(
+                    prompt_input.contents, prompt, aiconfig, params
+                )
             )
 
         await aiconfig.callback_manager.run_callbacks(
diff --git a/extensions/Groq/src/aiconfig_extension_groq/groq.py b/extensions/Groq/src/aiconfig_extension_groq/groq.py
index b3b1a4f9b..6a989edcd 100644
--- a/extensions/Groq/src/aiconfig_extension_groq/groq.py
+++ b/extensions/Groq/src/aiconfig_extension_groq/groq.py
@@ -3,9 +3,10 @@
 
 import os
 
+
 class GroqParser(DefaultOpenAIParser):
     def __init__(self, model: str):
-        super().__init__(model_id = model)
+        super().__init__(model_id=model)
 
         # "Model" field is a custom name for the specific model they want to use
         # when registering the Groq model parser. See the cookbook for reference:
@@ -21,5 +22,5 @@ async def deserialize(self, *args, **kwargs):
     def initialize_openai_client(self) -> None:
         # Initialize Groq Client
         self.client = Groq(
-          api_key=os.getenv("GROQ_API_KEY"),
+            api_key=os.getenv("GROQ_API_KEY"),
         )
diff --git a/extensions/HuggingFace/python/src/aiconfig_extension_hugging_face/local_inference/automatic_speech_recognition.py b/extensions/HuggingFace/python/src/aiconfig_extension_hugging_face/local_inference/automatic_speech_recognition.py
index c0cddcaf7..d3484aab8 100644
--- a/extensions/HuggingFace/python/src/aiconfig_extension_hugging_face/local_inference/automatic_speech_recognition.py
+++ b/extensions/HuggingFace/python/src/aiconfig_extension_hugging_face/local_inference/automatic_speech_recognition.py
@@ -346,9 +346,9 @@ def construct_outputs(response: list[Any]) -> list[Output]:
                 "output_type": "execute_result",
                 "data": text_output,
                 "execution_count": i,
-                "metadata": {"result": result}
-                if result.get("chunks", False)
-                else {},  # may contain timestamps and chunks, for now pass result
+                "metadata": (
+                    {"result": result} if result.get("chunks", False) else {}
+                ),  # may contain timestamps and chunks, for now pass result
             }
         )
         outputs.append(output)
diff --git a/extensions/HuggingFace/python/src/aiconfig_extension_hugging_face/remote_inference_client/image_2_text.py b/extensions/HuggingFace/python/src/aiconfig_extension_hugging_face/remote_inference_client/image_2_text.py
index 05446b4fb..cfdd91ad6 100644
--- a/extensions/HuggingFace/python/src/aiconfig_extension_hugging_face/remote_inference_client/image_2_text.py
+++ b/extensions/HuggingFace/python/src/aiconfig_extension_hugging_face/remote_inference_client/image_2_text.py
@@ -223,9 +223,9 @@ async def deserialize(
         completion_data = refine_completion_params(model_settings)
 
         # Add image input
-        completion_data[
-            "image"
-        ] = validate_and_retrieve_image_from_attachments(prompt)
+        completion_data["image"] = (
+            validate_and_retrieve_image_from_attachments(prompt)
+        )
 
         await aiconfig.callback_manager.run_callbacks(
             CallbackEvent(
diff --git a/gradio-notebook/backend/gradio_notebook/aiconfig_manager.py b/gradio-notebook/backend/gradio_notebook/aiconfig_manager.py
index 6748ffabe..bc715f42e 100644
--- a/gradio-notebook/backend/gradio_notebook/aiconfig_manager.py
+++ b/gradio-notebook/backend/gradio_notebook/aiconfig_manager.py
@@ -1,5 +1,6 @@
 """Helper class to reference the AIConfigRuntime state
 """
+
 import copy
 import heapq
 import time
@@ -100,10 +101,14 @@ def _register_model_parsers(self, parsers_path: str):
         AIConfigRuntime.register_model_parser(text_to_speech, "Text-to-Speech")
 
         text_generation = HuggingFaceTextGenerationRemoteInference()
-        AIConfigRuntime.register_model_parser(text_generation, "Text Generation")
+        AIConfigRuntime.register_model_parser(
+            text_generation, "Text Generation"
+        )
 
         text_summarization = HuggingFaceTextSummarizationRemoteInference()
-        AIConfigRuntime.register_model_parser(text_summarization, "Summarization")
+        AIConfigRuntime.register_model_parser(
+            text_summarization, "Summarization"
+        )
 
         text_translation = HuggingFaceTextTranslationRemoteInference()
         AIConfigRuntime.register_model_parser(text_translation, "Translation")
@@ -133,7 +138,9 @@ def _register_model_parsers(self, parsers_path: str):
 
         self._load_user_parser_module_if_exists(parsers_path)
 
-    def _load_user_parser_module_if_exists(self, parsers_module_path: str) -> None:
+    def _load_user_parser_module_if_exists(
+        self, parsers_module_path: str
+    ) -> None:
         try:
             parsers_path = get_validated_path(parsers_module_path)
             load_user_parser_module(parsers_path)
@@ -149,10 +156,16 @@ def get_config(self, session_id: str) -> AIConfigRuntime:
         """Get a config that is mapped to a session id"""
         update_time = time.time()
         if session_id not in self.session_data_map:
-            copied_config = copy.deepcopy(self.session_data_map["original"].config)
-            session_data = SessionData(config=copied_config, update_time=update_time)
+            copied_config = copy.deepcopy(
+                self.session_data_map["original"].config
+            )
+            session_data = SessionData(
+                config=copied_config, update_time=update_time
+            )
             self.session_data_map[session_id] = session_data
-            heapq.heappush(self.session_id_lru_min_heap, (update_time, session_id))
+            heapq.heappush(
+                self.session_id_lru_min_heap, (update_time, session_id)
+            )
 
         if show_debug():
             print(f"{self.session_data_map.keys()=}")
@@ -235,7 +248,9 @@ def clear_old_session_ids(self):
             if should_delete:
                 self.session_data_map.pop(session_id, None)
 
-    def remove_lru_session_if_not_updated(self, threshold_cutoff_time: float) -> bool:
+    def remove_lru_session_if_not_updated(
+        self, threshold_cutoff_time: float
+    ) -> bool:
         """
         Remove the least recently used session from the session_id_lru_min_heap
         If the session has been updated since it was added to the min_heap, and the
@@ -244,7 +259,9 @@ def remove_lru_session_if_not_updated(self, threshold_cutoff_time: float) -> boo
 
         @return bool: Whether the session was removed or not
         """
-        old_update_time, session_id = heapq.heappop(self.session_id_lru_min_heap)
+        old_update_time, session_id = heapq.heappop(
+            self.session_id_lru_min_heap
+        )
         actual_update_time = self.session_data_map[session_id].update_time
         if (
             old_update_time < actual_update_time
diff --git a/gradio-notebook/backend/gradio_notebook/events.py b/gradio-notebook/backend/gradio_notebook/events.py
index 065dda3f4..b7c01be5b 100644
--- a/gradio-notebook/backend/gradio_notebook/events.py
+++ b/gradio-notebook/backend/gradio_notebook/events.py
@@ -3,6 +3,7 @@
 In general, the value will be the payload passed from the frontend AIConfig as 
 a json string
 """
+
 import asyncio
 import copy
 import ctypes
@@ -106,11 +107,15 @@ def __init__(self, target: Union["Block", None], data: Any):
         self.prompt_name: str = data["prompt_name"]
 
         # Token to use for cancelling this particular run
-        self.cancellation_token: Optional[str] = data.get("cancellation_token", None)
+        self.cancellation_token: Optional[str] = data.get(
+            "cancellation_token", None
+        )
 
         # Whether we should run the other prompts that this depends on
         # TODO(rossdanlm): Make this generic kwargs
-        self.run_with_dependencies: bool = data.get("run_with_dependencies", True)
+        self.run_with_dependencies: bool = data.get(
+            "run_with_dependencies", True
+        )
 
         self.api_token: Optional[str] = data.get("api_token", None)
 
@@ -184,7 +189,9 @@ def __init__(self, target: Union["Block", None], data: Any):
         self.model_name: Optional[str] = data.get("model_name", None)
 
         # Model settings to update the prompt (if not None) or AIConfig with
-        self.model_settings: Optional[Dict[str, Any]] = data.get("model_settings", None)
+        self.model_settings: Optional[Dict[str, Any]] = data.get(
+            "model_settings", None
+        )
 
         # Name of the prompt to be updated. If None, update the overall config
         self.prompt_name: Optional[str] = data.get("prompt_name", None)
@@ -227,8 +234,12 @@ def add_prompt_impl(self, event: AddPromptEventData) -> str:
         prompt = Prompt.model_validate_json(prompt_json_str)
 
         config: AIConfigRuntime = self.config_manager.get_config(session_id)
-        config.add_prompt(prompt_name=prompt_name, prompt_data=prompt, index=index)
-        return json.dumps({"aiconfig": self.config_manager.get_config_json(session_id)})
+        config.add_prompt(
+            prompt_name=prompt_name, prompt_data=prompt, index=index
+        )
+        return json.dumps(
+            {"aiconfig": self.config_manager.get_config_json(session_id)}
+        )
 
     def cancel_run_impl(self, event: CancelRunEventData) -> str:
         """
@@ -236,11 +247,15 @@ def cancel_run_impl(self, event: CancelRunEventData) -> str:
         """
         cancellation_token_id: str = event.cancellation_token_id
         if cancellation_token_id is not None:
-            thread_event = self.config_manager.thread_events.get(cancellation_token_id)
+            thread_event = self.config_manager.thread_events.get(
+                cancellation_token_id
+            )
             if thread_event is not None:
                 thread_event.set()
                 self.config_manager.thread_events.pop(cancellation_token_id)
-                return json.dumps({"cancellation_token_id": cancellation_token_id})
+                return json.dumps(
+                    {"cancellation_token_id": cancellation_token_id}
+                )
 
             # Return a 422 Unprocessable Entity
             error_info = {
@@ -270,7 +285,9 @@ def clear_outputs_impl(self, event: EventWithSessionIdData) -> str:
         for prompt in config.prompts:
             prompt_name = prompt.name
             config.delete_output(prompt_name)
-        return json.dumps({"aiconfig": self.config_manager.get_config_json(session_id)})
+        return json.dumps(
+            {"aiconfig": self.config_manager.get_config_json(session_id)}
+        )
 
     def delete_prompt_impl(self, event: DeletePromptEventData) -> str:
         """
@@ -287,7 +304,9 @@ def get_aiconfig_impl(self, event: EventWithSessionIdData) -> str:
         Run this for the get_aiconfig event
         """
         session_id = event.session_id
-        return json.dumps({"aiconfig": self.config_manager.get_config_json(session_id)})
+        return json.dumps(
+            {"aiconfig": self.config_manager.get_config_json(session_id)}
+        )
 
     def remove_session_id_impl(self, event: EventWithSessionIdData) -> str:
         """
@@ -330,7 +349,9 @@ def update_output_queue(data, _accumulated_data, _index) -> None:
             cancellation_token_id = event.cancellation_token
             if not cancellation_token_id:
                 cancellation_token_id = str(uuid.uuid4())
-            self.config_manager.thread_events[cancellation_token_id] = threading.Event()
+            self.config_manager.thread_events[cancellation_token_id] = (
+                threading.Event()
+            )
 
             def generate(cancellation_token_id: str):  # type: ignore
                 # Use multi-threading so that we don't block run command from
@@ -400,7 +421,9 @@ def kill_thread(thread_id: int | None):
                         # If the response is not 1, the function didn't work
                         # correctly, and you should call it again with
                         # exc=NULL to reset it.
-                        ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id, None)
+                        ctypes.pythonapi.PyThreadState_SetAsyncExc(
+                            thread_id, None
+                        )
 
                 cancellation_event = self.config_manager.thread_events[
                     cancellation_token_id
@@ -433,7 +456,9 @@ def kill_thread(thread_id: int | None):
                         elif isinstance(text, dict) and "content" in text:
                             # TODO: Fix streaming output format so that it returns text
                             accumulated_output_text += text["content"]
-                        elif isinstance(text, dict) and "generated_text" in text:
+                        elif (
+                            isinstance(text, dict) and "generated_text" in text
+                        ):
                             # TODO: Fix streaming output format so that it returns text
                             accumulated_output_text += text["generated_text"]
 
@@ -450,7 +475,9 @@ def kill_thread(thread_id: int | None):
                         )
                         if show_debug():
                             print(f"{accumulated_output_text=}")
-                        yield json.dumps({"output_chunk": accumulated_output.to_json()})
+                        yield json.dumps(
+                            {"output_chunk": accumulated_output.to_json()}
+                        )
 
                 # Ensure that the run process is complete to yield final output
                 t.join()
@@ -459,13 +486,17 @@ def kill_thread(thread_id: int | None):
                     yield from handle_cancellation()
                     return
 
-                self.config_manager.thread_events.pop(cancellation_token_id, None)
+                self.config_manager.thread_events.pop(
+                    cancellation_token_id, None
+                )
                 aiconfig_json = self.config_manager.get_config_json(session_id)
                 yield json.dumps({"aiconfig_chunk": aiconfig_json})
                 yield json.dumps({"stop_streaming": True})
 
             if show_debug():
-                print(f"Running `aiconfig.run()` command with request: {event}")
+                print(
+                    f"Running `aiconfig.run()` command with request: {event}"
+                )
             yield from generate(cancellation_token_id)
         except Exception as e:
             # Return a 400 Bad Request error
@@ -478,7 +509,9 @@ def kill_thread(thread_id: int | None):
             }
             yield json.dumps(error_info)
 
-    def set_config_description_impl(self, event: SetConfigDescriptionEventData) -> str:
+    def set_config_description_impl(
+        self, event: SetConfigDescriptionEventData
+    ) -> str:
         """
         Run this for the set_config_description event. We don't need to return AIConfig
         for the Gradio frontend
@@ -526,14 +559,18 @@ def share_config_impl(self, event: ShareConfigEventData) -> str:
         #   const policy = await policyResponse.json();
         random_int: int = random.randint(0, 10001)
         bucket: str = "lastmileai.aiconfig.public"
-        upload_key: str = f"aiconfigs/{_get_date_time_string()}/{random_int}/{filename}"
+        upload_key: str = (
+            f"aiconfigs/{_get_date_time_string()}/{random_int}/{filename}"
+        )
 
         config_str: str = json.dumps(
             self.config_manager.get_config_json(session_id), indent=2
         )
         config_bytes: bytes = config_str.encode("utf-8")
 
-        s3_client = boto3.client("s3", config=Config(signature_version=UNSIGNED))
+        s3_client = boto3.client(
+            "s3", config=Config(signature_version=UNSIGNED)
+        )
         s3_client.put_object(
             Body=config_bytes,
             Bucket=bucket,
@@ -560,7 +597,9 @@ def share_config_impl(self, event: ShareConfigEventData) -> str:
             response.raise_for_status()
 
         uploaded_config_id: str = response.json()["id"]
-        rendering_uri: str = LASTMILE_BASE_URI + f"aiconfig/{uploaded_config_id}"
+        rendering_uri: str = (
+            LASTMILE_BASE_URI + f"aiconfig/{uploaded_config_id}"
+        )
         return json.dumps({"share_url": rendering_uri})
 
     def update_model_impl(self, event: UpdateModelEventData) -> str:
@@ -569,8 +608,12 @@ def update_model_impl(self, event: UpdateModelEventData) -> str:
         """
         session_id = event.session_id
         config: AIConfigRuntime = self.config_manager.get_config(session_id)
-        config.update_model(event.model_name, event.model_settings, event.prompt_name)
-        return json.dumps({"aiconfig": self.config_manager.get_config_json(session_id)})
+        config.update_model(
+            event.model_name, event.model_settings, event.prompt_name
+        )
+        return json.dumps(
+            {"aiconfig": self.config_manager.get_config_json(session_id)}
+        )
 
     def update_prompt_impl(self, event: UpdatePromptEventData) -> str:
         """
@@ -582,7 +625,9 @@ def update_prompt_impl(self, event: UpdatePromptEventData) -> str:
 
         config: AIConfigRuntime = self.config_manager.get_config(session_id)
         config.update_prompt(event.prompt_name, prompt)
-        return json.dumps({"aiconfig": self.config_manager.get_config_json(session_id)})
+        return json.dumps(
+            {"aiconfig": self.config_manager.get_config_json(session_id)}
+        )
 
 
 def _sanitize_filename(filename: str) -> str:
diff --git a/gradio-notebook/backend/gradio_notebook/gradio_notebook.py b/gradio-notebook/backend/gradio_notebook/gradio_notebook.py
index c109a11c8..3c977d34b 100644
--- a/gradio-notebook/backend/gradio_notebook/gradio_notebook.py
+++ b/gradio-notebook/backend/gradio_notebook/gradio_notebook.py
@@ -15,7 +15,9 @@ class GradioNotebook:
 
     config_manager: AIConfigManager
 
-    def __init__(self, config_path: str = "", parsers_path: str = "", **kwargs):
+    def __init__(
+        self, config_path: str = "", parsers_path: str = "", **kwargs
+    ):
         """
         Args:
             config_path: (str, optional): The filepath to load the AIConfig from.
@@ -35,7 +37,9 @@ def __init__(self, config_path: str = "", parsers_path: str = "", **kwargs):
         self.component = GradioNotebookComponent(
             value=json.dumps(
                 {
-                    "aiconfig": self.config_manager.get_config_json("original"),
+                    "aiconfig": self.config_manager.get_config_json(
+                        "original"
+                    ),
                     "model_ids": self.config_manager.get_models(),
                 }
             ),
@@ -87,16 +91,28 @@ def _register_events(self, component: GradioNotebookComponent) -> None:
             event_handler.cancel_run_impl, [], [component], show_progress=False
         )
         component.clear_outputs(
-            event_handler.clear_outputs_impl, [], [component], show_progress=False
+            event_handler.clear_outputs_impl,
+            [],
+            [component],
+            show_progress=False,
         )
         component.delete_prompt(
-            event_handler.delete_prompt_impl, [], [component], show_progress=False
+            event_handler.delete_prompt_impl,
+            [],
+            [component],
+            show_progress=False,
         )
         component.get_aiconfig(
-            event_handler.get_aiconfig_impl, [], [component], show_progress=False
+            event_handler.get_aiconfig_impl,
+            [],
+            [component],
+            show_progress=False,
         )
         component.remove_session_id(
-            event_handler.remove_session_id_impl, [], [component], show_progress=False
+            event_handler.remove_session_id_impl,
+            [],
+            [component],
+            show_progress=False,
         )
         component.run_prompt(
             event_handler.run_prompt_impl, [], [component], show_progress=False
@@ -108,17 +124,32 @@ def _register_events(self, component: GradioNotebookComponent) -> None:
             show_progress=False,
         )
         component.set_config_name(
-            event_handler.set_config_name_impl, [], [component], show_progress=False
+            event_handler.set_config_name_impl,
+            [],
+            [component],
+            show_progress=False,
         )
         component.set_parameters(
-            event_handler.set_parameters_impl, [], [component], show_progress=False
+            event_handler.set_parameters_impl,
+            [],
+            [component],
+            show_progress=False,
         )
         component.share_config(
-            event_handler.share_config_impl, [], [component], show_progress=False
+            event_handler.share_config_impl,
+            [],
+            [component],
+            show_progress=False,
         )
         component.update_model(
-            event_handler.update_model_impl, [], [component], show_progress=False
+            event_handler.update_model_impl,
+            [],
+            [component],
+            show_progress=False,
         )
         component.update_prompt(
-            event_handler.update_prompt_impl, [], [component], show_progress=False
+            event_handler.update_prompt_impl,
+            [],
+            [component],
+            show_progress=False,
         )
diff --git a/gradio-notebook/backend/gradio_notebook/utils.py b/gradio-notebook/backend/gradio_notebook/utils.py
index 48ae8671c..e14f84eb4 100644
--- a/gradio-notebook/backend/gradio_notebook/utils.py
+++ b/gradio-notebook/backend/gradio_notebook/utils.py
@@ -1,4 +1,5 @@
 """Simple utils file to be shared across backend"""
+
 import importlib
 import os
 import sys
diff --git a/gradio-notebook/frontend/config/examine.py b/gradio-notebook/frontend/config/examine.py
index 9d3473fe8..407ced209 100644
--- a/gradio-notebook/frontend/config/examine.py
+++ b/gradio-notebook/frontend/config/examine.py
@@ -19,7 +19,8 @@
     pyproject_toml = parse(pyproject_source)
     keywords = pyproject_toml["project"]["keywords"]
     custom_component = (
-        "gradio-custom-component" in keywords or "gradio custom component" in keywords
+        "gradio-custom-component" in keywords
+        or "gradio custom component" in keywords
     )
     if not custom_component:
         exit(0)
@@ -27,7 +28,9 @@
     module_name = pyproject_toml["project"]["name"]
     module = importlib.import_module(module_name)
 
-    artifacts: list[str] = pyproject_toml["tool"]["hatch"]["build"]["artifacts"]
+    artifacts: list[str] = pyproject_toml["tool"]["hatch"]["build"][
+        "artifacts"
+    ]
 
     def get_relative_path(path):
         return (
diff --git a/gradio-notebook/model_parsers.py b/gradio-notebook/model_parsers.py
index 795161573..5860943dc 100644
--- a/gradio-notebook/model_parsers.py
+++ b/gradio-notebook/model_parsers.py
@@ -16,28 +16,42 @@
 # Here we are registering all the local HuggingFace model parsers as an example
 def register_model_parsers() -> None:
     """Register model parsers for local HuggingFace models."""
-    automatic_speech_recognition = HuggingFaceAutomaticSpeechRecognitionTransformer()
+    automatic_speech_recognition = (
+        HuggingFaceAutomaticSpeechRecognitionTransformer()
+    )
     AIConfigRuntime.register_model_parser(
         automatic_speech_recognition, "Automatic Speech Recognition (Local)"
     )
 
     image_to_text = HuggingFaceImage2TextTransformer()
-    AIConfigRuntime.register_model_parser(image_to_text, "Image-to-Text (Local)")
+    AIConfigRuntime.register_model_parser(
+        image_to_text, "Image-to-Text (Local)"
+    )
 
     text_to_image = HuggingFaceText2ImageDiffusor()
-    AIConfigRuntime.register_model_parser(text_to_image, "Text-to-Image (Local)")
+    AIConfigRuntime.register_model_parser(
+        text_to_image, "Text-to-Image (Local)"
+    )
 
     text_to_speech = HuggingFaceText2SpeechTransformer()
-    AIConfigRuntime.register_model_parser(text_to_speech, "Text-to-Speech (Local)")
+    AIConfigRuntime.register_model_parser(
+        text_to_speech, "Text-to-Speech (Local)"
+    )
 
     text_generation = HuggingFaceTextGenerationTransformer()
-    AIConfigRuntime.register_model_parser(text_generation, "Text Generation (Local)")
+    AIConfigRuntime.register_model_parser(
+        text_generation, "Text Generation (Local)"
+    )
 
     text_summarization = HuggingFaceTextSummarizationTransformer()
-    AIConfigRuntime.register_model_parser(text_summarization, "Summarization (Local)")
+    AIConfigRuntime.register_model_parser(
+        text_summarization, "Summarization (Local)"
+    )
 
     text_translation = HuggingFaceTextTranslationTransformer()
-    AIConfigRuntime.register_model_parser(text_translation, "Translation (Local)")
+    AIConfigRuntime.register_model_parser(
+        text_translation, "Translation (Local)"
+    )
 
     # By default, model parsers will also have their own ids registered. Remove those
     # since we just want the task-based names registered
diff --git a/python/src/aiconfig/ChatCompletion.py b/python/src/aiconfig/ChatCompletion.py
index c6a0be421..399db1c10 100644
--- a/python/src/aiconfig/ChatCompletion.py
+++ b/python/src/aiconfig/ChatCompletion.py
@@ -3,6 +3,7 @@
 
 usage: see openai_wrapper.ipynb.
 """
+
 import asyncio
 import copy
 from types import ModuleType
diff --git a/python/src/aiconfig/__init__.py b/python/src/aiconfig/__init__.py
index a4c8c3ed9..b0b7691ad 100644
--- a/python/src/aiconfig/__init__.py
+++ b/python/src/aiconfig/__init__.py
@@ -16,7 +16,7 @@
 from .default_parsers.azure import AzureOpenAIParser
 from .default_parsers.claude import ClaudeBedrockModelParser
 from .default_parsers.dalle import DalleImageGenerationParser
-from .default_parsers.gemini import  GeminiModelParser
+from .default_parsers.gemini import GeminiModelParser
 from .default_parsers.openai import DefaultOpenAIParser, OpenAIInference
 from .default_parsers.palm import PaLMChatParser, PaLMTextParser
 from .default_parsers.parameterized_model_parser import (
diff --git a/python/src/aiconfig/default_parsers/azure.py b/python/src/aiconfig/default_parsers/azure.py
index b02c3b760..48a73ac9c 100644
--- a/python/src/aiconfig/default_parsers/azure.py
+++ b/python/src/aiconfig/default_parsers/azure.py
@@ -6,19 +6,19 @@
 
 class AzureOpenAIParser(DefaultOpenAIParser):
     def __init__(self, deployment: str):
-        super().__init__(model_id = deployment)
+        super().__init__(model_id=deployment)
 
-        # Deployment is a custom name that user defines in Azure portal. 
-        self.deployment = deployment 
+        # Deployment is a custom name that user defines in Azure portal.
+        self.deployment = deployment
 
     async def deserialize(self, *args, **kwargs):
-        # Logic doesn't depend on input, pass it forward to the openai model parser deserialize 
+        # Logic doesn't depend on input, pass it forward to the openai model parser deserialize
         openai_deserialized_params = await super().deserialize(*args, **kwargs)
 
-        # Should this just be the "model name" from config? 
-        # If so, Then the "model name" will have to be deployment name and be consistent 
+        # Should this just be the "model name" from config?
+        # If so, Then the "model name" will have to be deployment name and be consistent
         # Which would mean we don't need to have this custom deserialization
-        openai_deserialized_params["model"] = self.deployment 
+        openai_deserialized_params["model"] = self.deployment
         return openai_deserialized_params
 
     def initialize_openai_client(self) -> None:
diff --git a/python/src/aiconfig/default_parsers/claude.py b/python/src/aiconfig/default_parsers/claude.py
index eb8b803ed..1d7c73975 100644
--- a/python/src/aiconfig/default_parsers/claude.py
+++ b/python/src/aiconfig/default_parsers/claude.py
@@ -126,9 +126,9 @@ async def deserialize(
 
         # Claude is trained using RLHF, need to add the human prompt to the beginning of the prompt
         # See https://docs.anthropic.com/claude/docs/introduction-to-prompt-design#human--assistant-formatting
-        completion_data[
-            "prompt"
-        ] = f"{HUMAN_PROMPT} {resolved_prompt}{AI_PROMPT}"
+        completion_data["prompt"] = (
+            f"{HUMAN_PROMPT} {resolved_prompt}{AI_PROMPT}"
+        )
 
         await aiconfig.callback_manager.run_callbacks(
             CallbackEvent(
diff --git a/python/src/aiconfig/default_parsers/gemini.py b/python/src/aiconfig/default_parsers/gemini.py
index 3432eb9c5..5b7338660 100644
--- a/python/src/aiconfig/default_parsers/gemini.py
+++ b/python/src/aiconfig/default_parsers/gemini.py
@@ -4,14 +4,16 @@
 
 import google.generativeai as genai
 from aiconfig.callback import CallbackEvent
-from aiconfig.default_parsers.parameterized_model_parser import ParameterizedModelParser
+from aiconfig.default_parsers.parameterized_model_parser import (
+    ParameterizedModelParser,
+)
 from aiconfig.model_parser import InferenceOptions
 from aiconfig.schema import (
     ExecuteResult,
     Output,
     OutputDataWithValue,
     Prompt,
-    PromptInput
+    PromptInput,
 )
 from aiconfig.util.config_utils import get_api_key_from_environment
 from aiconfig.util.params import resolve_prompt, resolve_prompt_string
@@ -45,7 +47,9 @@
 """
 
 
-def construct_regular_outputs(response: "AsyncGenerateContentResponse") -> list[Output]:
+def construct_regular_outputs(
+    response: "AsyncGenerateContentResponse",
+) -> list[Output]:
     """
     Construct regular output per response result, without streaming enabled
     """
@@ -66,7 +70,9 @@ def construct_regular_outputs(response: "AsyncGenerateContentResponse") -> list[
     return output_list
 
 
-async def construct_stream_outputs(response: "AsyncGenerateContentResponse", options: InferenceOptions) -> list[Output]:
+async def construct_stream_outputs(
+    response: "AsyncGenerateContentResponse", options: InferenceOptions
+) -> list[Output]:
     """
     Construct Outputs while also streaming the response with stream callback
 
@@ -110,7 +116,9 @@ def __init__(self, id: str = "gemini-pro"):
         # as an env var genai.configure() will pick up the env var
         # `GOOGLE_API_KEY`, it's just that we prefer not to call
         # `get_api_key_from_environment` multiple times if we don't need to
-        self.api_key = get_api_key_from_environment("GOOGLE_API_KEY", required=False).unwrap()
+        self.api_key = get_api_key_from_environment(
+            "GOOGLE_API_KEY", required=False
+        ).unwrap()
 
     def id(self) -> str:
         """
@@ -195,23 +203,42 @@ async def serialize(
         prompts = []
 
         contents_is_str = isinstance(contents, str)
-        contents_is_list_of_strings = all(isinstance(item, str) for item in contents) if isinstance(contents, list) else False
+        contents_is_list_of_strings = (
+            all(isinstance(item, str) for item in contents)
+            if isinstance(contents, list)
+            else False
+        )
 
         # Role Dict looks like this:
         #     {'role':'user',
         #      'parts': ["Briefly explain how a computer works to a young child."]
         #     }
-        contents_is_role_dict = isinstance(contents, dict) and "role" in contents and "parts"
+        contents_is_role_dict = (
+            isinstance(contents, dict) and "role" in contents and "parts"
+        )
         # Multi Turn means that the contents is a list of dicts with alternating role and parts. See for more info: https://ai.google.dev/tutorials/python_quickstart#multi-turn_conversations
         contents_is_multi_turn = isinstance(contents, list) and all(
-            isinstance(item, dict) and "role" in item and "parts" in item for item in contents
+            isinstance(item, dict) and "role" in item and "parts" in item
+            for item in contents
         )
 
         if contents is None:
-            raise ValueError("No contents found in data. Gemini api request requires a contents field")
-        if contents_is_str or contents_is_list_of_strings or contents_is_role_dict:
+            raise ValueError(
+                "No contents found in data. Gemini api request requires a contents field"
+            )
+        if (
+            contents_is_str
+            or contents_is_list_of_strings
+            or contents_is_role_dict
+        ):
             # Just one string. Assume it's a single-turn prompt
-            prompt = Prompt(**{"name": prompt_name, "input": {"contents": contents}, "metadata": {"model": model_metadata}})
+            prompt = Prompt(
+                **{
+                    "name": prompt_name,
+                    "input": {"contents": contents},
+                    "metadata": {"model": model_metadata},
+                }
+            )
             prompts.append(prompt)
         elif contents_is_multi_turn:
             # Assume it's a multi-turn prompt. Each item in the list is a dict with role and parts
@@ -247,14 +274,23 @@ async def serialize(
                 prompts.append(prompt)
                 i += 1
         else:
-            raise ValueError("Unable to parse Data into prompts. Contents data is either invalid or contains unsupported objects like protobufs.")
+            raise ValueError(
+                "Unable to parse Data into prompts. Contents data is either invalid or contains unsupported objects like protobufs."
+            )
 
-        event = CallbackEvent("on_serialize_complete", __name__, {"result": prompts})
+        event = CallbackEvent(
+            "on_serialize_complete", __name__, {"result": prompts}
+        )
         await ai_config.callback_manager.run_callbacks(event)
 
         return prompts
 
-    async def deserialize(self, prompt: Prompt, aiconfig: "AIConfigRuntime", params: Optional[Dict] = None) -> Dict:
+    async def deserialize(
+        self,
+        prompt: Prompt,
+        aiconfig: "AIConfigRuntime",
+        params: Optional[Dict] = None,
+    ) -> Dict:
         """
         Defines how to parse a prompt in the .aiconfig for a particular model
         and constructs the completion params for that model.
@@ -265,7 +301,13 @@ async def deserialize(self, prompt: Prompt, aiconfig: "AIConfigRuntime", params:
         Returns:
             dict: Model-specific completion parameters.
         """
-        await aiconfig.callback_manager.run_callbacks(CallbackEvent("on_deserialize_start", __name__, {"prompt": prompt, "params": params}))
+        await aiconfig.callback_manager.run_callbacks(
+            CallbackEvent(
+                "on_deserialize_start",
+                __name__,
+                {"prompt": prompt, "params": params},
+            )
+        )
 
         # Build Completion data
         model_settings = self.get_model_settings(prompt, aiconfig)
@@ -277,7 +319,9 @@ async def deserialize(self, prompt: Prompt, aiconfig: "AIConfigRuntime", params:
 
             resolved_prompt = resolve_prompt(prompt, params, aiconfig)
 
-            messages.append({"role": "user", "parts": [{"text": resolved_prompt}]})
+            messages.append(
+                {"role": "user", "parts": [{"text": resolved_prompt}]}
+            )
 
             completion_data["contents"] = messages
         else:
@@ -297,9 +341,19 @@ async def deserialize(self, prompt: Prompt, aiconfig: "AIConfigRuntime", params:
                     "Unable to deserialize input. Prompt input type is not a string, Gemini Model Parser expects prompt input to contain a 'contents' field as expected by Gemini API"
                 )
 
-            completion_data["contents"] = parameterize_supported_gemini_input_data(prompt_input.contents, prompt, aiconfig, params)
+            completion_data["contents"] = (
+                parameterize_supported_gemini_input_data(
+                    prompt_input.contents, prompt, aiconfig, params
+                )
+            )
 
-        await aiconfig.callback_manager.run_callbacks(CallbackEvent("on_deserialize_complete", __name__, {"output": completion_data}))
+        await aiconfig.callback_manager.run_callbacks(
+            CallbackEvent(
+                "on_deserialize_complete",
+                __name__,
+                {"output": completion_data},
+            )
+        )
         return completion_data
 
     async def run_inference(
@@ -324,12 +378,18 @@ async def run_inference(
             CallbackEvent(
                 "on_run_start",
                 __name__,
-                {"prompt": prompt, "options": options, "parameters": parameters},
+                {
+                    "prompt": prompt,
+                    "options": options,
+                    "parameters": parameters,
+                },
             )
         )
 
         if not self.api_key:
-            self.api_key = get_api_key_from_environment("GOOGLE_API_KEY", required=True).unwrap()
+            self.api_key = get_api_key_from_environment(
+                "GOOGLE_API_KEY", required=True
+            ).unwrap()
 
         # Gemini api stores a reference to the currently executing async event loop.
         # This causes issues on reruns for the model parser, so to alleviate this, we
@@ -356,7 +416,11 @@ async def run_inference(
             outputs = construct_regular_outputs(response)
 
         prompt.outputs = outputs
-        await aiconfig.callback_manager.run_callbacks(CallbackEvent("on_run_complete", __name__, {"result": prompt.outputs}))
+        await aiconfig.callback_manager.run_callbacks(
+            CallbackEvent(
+                "on_run_complete", __name__, {"result": prompt.outputs}
+            )
+        )
         return prompt.outputs
 
     def get_output_text(
@@ -389,14 +453,19 @@ def get_output_text(
 """
         raise ValueError(error_message)
 
-    def _construct_chat_history(self, prompt: Prompt, aiconfig: "AIConfigRuntime", params: Dict) -> List:
+    def _construct_chat_history(
+        self, prompt: Prompt, aiconfig: "AIConfigRuntime", params: Dict
+    ) -> List:
         """
         Constructs the chat history for the model
         """
         messages = []
         # Default to always use chat context
-        remember_chat_context = not hasattr(prompt.metadata, "remember_chat_context") or (
-            hasattr(prompt.metadata, "remember_chat_context") and prompt.metadata.remember_chat_context != False
+        remember_chat_context = not hasattr(
+            prompt.metadata, "remember_chat_context"
+        ) or (
+            hasattr(prompt.metadata, "remember_chat_context")
+            and prompt.metadata.remember_chat_context != False
         )
         if remember_chat_context:
             # handle chat history. check previous prompts for the same model. if same model, add prompt and its output to completion data if it has a completed output
@@ -405,13 +474,26 @@ def _construct_chat_history(self, prompt: Prompt, aiconfig: "AIConfigRuntime", p
                 if previous_prompt.name == prompt.name:
                     break
 
-                previous_prompt_is_same_model = aiconfig.get_model_name(previous_prompt) == aiconfig.get_model_name(prompt)
+                previous_prompt_is_same_model = aiconfig.get_model_name(
+                    previous_prompt
+                ) == aiconfig.get_model_name(prompt)
                 if previous_prompt_is_same_model:
-                    previous_prompt_template = resolve_prompt(previous_prompt, params, aiconfig)
-                    previous_prompt_output = aiconfig.get_latest_output(previous_prompt)
-                    previous_prompt_output_text = self.get_output_text(previous_prompt, aiconfig, previous_prompt_output)
+                    previous_prompt_template = resolve_prompt(
+                        previous_prompt, params, aiconfig
+                    )
+                    previous_prompt_output = aiconfig.get_latest_output(
+                        previous_prompt
+                    )
+                    previous_prompt_output_text = self.get_output_text(
+                        previous_prompt, aiconfig, previous_prompt_output
+                    )
 
-                    messages.append({"role": "user", "parts": [{"text": previous_prompt_template}]})
+                    messages.append(
+                        {
+                            "role": "user",
+                            "parts": [{"text": previous_prompt_template}],
+                        }
+                    )
                     messages.append(
                         {
                             "role": "model",
@@ -421,7 +503,9 @@ def _construct_chat_history(self, prompt: Prompt, aiconfig: "AIConfigRuntime", p
 
         return messages
 
-    def get_prompt_template(self, prompt: Prompt, aiConfig: "AIConfigRuntime") -> str:
+    def get_prompt_template(
+        self, prompt: Prompt, aiConfig: "AIConfigRuntime"
+    ) -> str:
         """
         This method is overriden from the ParameterizedModelParser class. Its intended to be used only when collecting prompt references, nothing else.
 
@@ -444,12 +528,18 @@ def get_prompt_template(self, prompt: Prompt, aiConfig: "AIConfigRuntime") -> st
                     elif isinstance(parts, list):
                         return " ".join(parts)
                     else:
-                        raise Exception(f"Cannot get prompt template string from prompt input: {prompt.input}")
+                        raise Exception(
+                            f"Cannot get prompt template string from prompt input: {prompt.input}"
+                        )
                 else:
-                    raise Exception(f"Cannot get prompt template string from prompt input: {prompt.input}")
+                    raise Exception(
+                        f"Cannot get prompt template string from prompt input: {prompt.input}"
+                    )
 
         else:
-            raise Exception(f"Cannot get prompt template string from prompt input: {prompt.input}")
+            raise Exception(
+                f"Cannot get prompt template string from prompt input: {prompt.input}"
+            )
 
 
 def refine_chat_completion_params(model_settings):
@@ -469,7 +559,12 @@ def refine_chat_completion_params(model_settings):
     return completion_data
 
 
-def parameterize_supported_gemini_input_data(part: Any, prompt: Prompt, aiconfig: "AIConfigRuntime", input_params: dict[str, Any]):
+def parameterize_supported_gemini_input_data(
+    part: Any,
+    prompt: Prompt,
+    aiconfig: "AIConfigRuntime",
+    input_params: dict[str, Any],
+):
     """
     Parameterizes the input for the Gemini API based on the type of the input part.
     This function specifically handles string-based types in the context of Gemini API.
@@ -490,21 +585,34 @@ def parameterize_supported_gemini_input_data(part: Any, prompt: Prompt, aiconfig
         return resolve_prompt_string(prompt, input_params, aiconfig, part)
     elif isinstance(part, list):
         # This is expecting a list of strings. If its anything else, this will probably fail.
-        return [parameterize_supported_gemini_input_data(item, prompt, aiconfig, input_params) for item in part]
+        return [
+            parameterize_supported_gemini_input_data(
+                item, prompt, aiconfig, input_params
+            )
+            for item in part
+        ]
     elif isinstance(part, dict):
         # Expect "parts" key to be present in role dict
         if "parts" in part:
             part = copy.deepcopy(part)
-            part["parts"] = parameterize_supported_gemini_input_data(part["parts"], prompt, aiconfig, input_params)
+            part["parts"] = parameterize_supported_gemini_input_data(
+                part["parts"], prompt, aiconfig, input_params
+            )
             return part
         else:
-            raise ValueError(f"Input Dictionary to Gemini Model Parser must contain a 'parts' key. Input provided: {part}")
+            raise ValueError(
+                f"Input Dictionary to Gemini Model Parser must contain a 'parts' key. Input provided: {part}"
+            )
     else:
-        raise ValueError(f"Unable to parameterize part. Unsupported type: {type(part)} with value: {part}")
+        raise ValueError(
+            f"Unable to parameterize part. Unsupported type: {type(part)} with value: {part}"
+        )
 
 
 def contains_prompt_template(prompt: Prompt):
     """
     Check if a prompt's input is a valid string.
     """
-    return isinstance(prompt.input, str) or (hasattr(prompt.input, "data") and isinstance(prompt.input.data, str))
+    return isinstance(prompt.input, str) or (
+        hasattr(prompt.input, "data") and isinstance(prompt.input.data, str)
+    )
diff --git a/python/src/aiconfig/default_parsers/openai.py b/python/src/aiconfig/default_parsers/openai.py
index a340a0e23..9980d5abb 100644
--- a/python/src/aiconfig/default_parsers/openai.py
+++ b/python/src/aiconfig/default_parsers/openai.py
@@ -158,25 +158,29 @@ async def serialize(
                 prompts.append(prompt)
             elif i == 0 and role == "assistant":
                 # If the first message is an assistant message,
-                # build a prompt with an empty input, 
+                # build a prompt with an empty input,
                 # and the assistant response as the output
 
                 # Pull assistant response
-                assistant_output = build_output_data(conversation_data["messages"][i])
+                assistant_output = build_output_data(
+                    conversation_data["messages"][i]
+                )
                 prompt = Prompt(
-                    name= f"{prompt_name}_{len(prompts) + 1}",
+                    name=f"{prompt_name}_{len(prompts) + 1}",
                     input="",
                     metadata=PromptMetadata(
-                        model= copy.deepcopy(model_metadata),
-                        parameters= parameters,
-                        remember_chat_context = True
+                        model=copy.deepcopy(model_metadata),
+                        parameters=parameters,
+                        remember_chat_context=True,
                     ),
-                    outputs=[                        ExecuteResult(
+                    outputs=[
+                        ExecuteResult(
                             output_type="execute_result",
                             execution_count=None,
                             data=assistant_output,
                             metadata={},
-                        )],
+                        )
+                    ],
                 )
                 prompts.append(prompt)
             i += 1
@@ -261,13 +265,13 @@ async def deserialize(
         else:
             # If messages are already specified in the model settings, then just resolve each message with the given parameters and append the latest message
             for i in range(len(completion_params.get("messages"))):
-                completion_params["messages"][i][
-                    "content"
-                ] = resolve_prompt_string(
-                    prompt,
-                    params,
-                    aiconfig,
-                    completion_params["messages"][i]["content"],
+                completion_params["messages"][i]["content"] = (
+                    resolve_prompt_string(
+                        prompt,
+                        params,
+                        aiconfig,
+                        completion_params["messages"][i]["content"],
+                    )
                 )
 
         # Add in the latest prompt
@@ -420,7 +424,7 @@ async def run_inference(
             )
         )
         return prompt.outputs
-    
+
     def initialize_openai_client(self) -> None:
         """
         Initializes the client to be used with the OpenAI Module.
@@ -430,7 +434,7 @@ def initialize_openai_client(self) -> None:
         openai_api_key = get_api_key_from_environment(
             "OPENAI_API_KEY"
         ).unwrap()
-        self.client = openai.Client(api_key=openai_api_key)   
+        self.client = openai.Client(api_key=openai_api_key)
 
     def get_prompt_template(
         self, prompt: Prompt, aiconfig: "AIConfigRuntime"
diff --git a/python/src/aiconfig/editor/example_aiconfig_model_registry.py b/python/src/aiconfig/editor/example_aiconfig_model_registry.py
index 6b9b4a01f..bb76004e5 100644
--- a/python/src/aiconfig/editor/example_aiconfig_model_registry.py
+++ b/python/src/aiconfig/editor/example_aiconfig_model_registry.py
@@ -7,7 +7,6 @@
     See example below.
 """
 
-
 # from aiconfig import AIConfigRuntime
 # from llama import LlamaModelParser
 
diff --git a/python/src/aiconfig/editor/server/queue_iterator.py b/python/src/aiconfig/editor/server/queue_iterator.py
index b4dc8d4fe..74670d586 100644
--- a/python/src/aiconfig/editor/server/queue_iterator.py
+++ b/python/src/aiconfig/editor/server/queue_iterator.py
@@ -1,5 +1,6 @@
 """Queue iterator for streaming. Can only process strings for now
 but in future will try to make it generic"""
+
 # import asyncio
 from queue import Queue
 
diff --git a/python/src/aiconfig/editor/server/server_utils.py b/python/src/aiconfig/editor/server/server_utils.py
index 1425e004b..7da65164d 100644
--- a/python/src/aiconfig/editor/server/server_utils.py
+++ b/python/src/aiconfig/editor/server/server_utils.py
@@ -301,7 +301,9 @@ def init_server_state(
     )
     state = get_server_state(app)
     state.aiconfigrc_path = aiconfigrc_path
-    env_file_path_is_valid, message = validate_env_file_path(initialization_settings.env_file_path)
+    env_file_path_is_valid, message = validate_env_file_path(
+        initialization_settings.env_file_path
+    )
     if not env_file_path_is_valid:
         LOGGER.warning(f"{message}: '{initialization_settings.env_file_path}'")
     else:
@@ -506,7 +508,10 @@ def run_aiconfig_operation_with_request_json(
                 aiconfig=None,
             ).to_flask_format()
 
-def validate_env_file_path(request_env_path: str | None | Any) -> Tuple[bool, str]:
+
+def validate_env_file_path(
+    request_env_path: str | None | Any,
+) -> Tuple[bool, str]:
     """
     Validates the given env file path. If its not valid, returns a tuple of (False, str) with a message.
 
@@ -529,5 +534,5 @@ def validate_env_file_path(request_env_path: str | None | Any) -> Tuple[bool, st
 
     if filename_format_correct is False:
         return False, "Specified env file path is not a .env file"
-    
+
     return True, f".env file path {request_env_path} is valid"
diff --git a/python/src/aiconfig/eval/api/__init__.py b/python/src/aiconfig/eval/api/__init__.py
index 2ccf6e81a..69faa7191 100644
--- a/python/src/aiconfig/eval/api/__init__.py
+++ b/python/src/aiconfig/eval/api/__init__.py
@@ -9,6 +9,7 @@
     TestSuiteWithInputsSettings,
 )
 """
+
 from .. import common, metrics
 
 # pyright: reportWildcardImportFromLibrary=false
diff --git a/python/src/aiconfig/eval/common.py b/python/src/aiconfig/eval/common.py
index 666f8b783..1f9989124 100644
--- a/python/src/aiconfig/eval/common.py
+++ b/python/src/aiconfig/eval/common.py
@@ -58,7 +58,6 @@ async def __call__(self, datum: T_Evaluable) -> T_MetricValue:
 class EvaluationMetricMetadata(
     core_utils.Record, Generic[T_Evaluable, T_MetricValue]
 ):
-
     """A record to tie together metadata about an evaluation metric
     to ensure that numbers are interpreted as intended.
 
diff --git a/python/src/aiconfig/eval/metrics.py b/python/src/aiconfig/eval/metrics.py
index cd63e84a5..aa9c66bef 100644
--- a/python/src/aiconfig/eval/metrics.py
+++ b/python/src/aiconfig/eval/metrics.py
@@ -216,9 +216,9 @@ def make_sentiment_scores_metric(
     best_value: common.T_MetricValue | None = None,
     worst_value: common.T_MetricValue | None = None,
 ) -> Metric[str, common.T_MetricValue]:
-    evaluation_fn: common.EvaluationFunction[
-        str, common.T_MetricValue
-    ] = make_evaluation_fn(get_polarity_scores)
+    evaluation_fn: common.EvaluationFunction[str, common.T_MetricValue] = (
+        make_evaluation_fn(get_polarity_scores)
+    )
     out: Metric[str, common.T_MetricValue] = Metric(
         evaluation_fn=evaluation_fn,
         metric_metadata=common.EvaluationMetricMetadata(
@@ -313,7 +313,9 @@ def _with_description(key: str, value: dict[str, str]) -> dict[str, str]:
 
     required = required or list(properties.keys())
 
-    openai_eval_llm_chat_completion_create: common.CompletionTextToSerializedJSON = make_fn_completion_text_to_serialized_json(
+    openai_eval_llm_chat_completion_create: (
+        common.CompletionTextToSerializedJSON
+    ) = make_fn_completion_text_to_serialized_json(
         eval_llm_name=eval_llm_name,
         properties=properties,
         required=required,
diff --git a/python/src/aiconfig/util/params.py b/python/src/aiconfig/util/params.py
index dc14e266a..8a584bb24 100644
--- a/python/src/aiconfig/util/params.py
+++ b/python/src/aiconfig/util/params.py
@@ -264,7 +264,7 @@ def collect_prompt_references(
 
         # Note: not all model inputs are parameterizable. This can be None.
         prompt_input = get_prompt_template(previous_prompt, ai_config)
-        
+
         prompt_output = (
             ai_config.get_output_text(
                 previous_prompt, ai_config.get_latest_output(previous_prompt)
diff --git a/vscode-extension/static/example_aiconfig_model_registry.py b/vscode-extension/static/example_aiconfig_model_registry.py
index 6b9b4a01f..bb76004e5 100644
--- a/vscode-extension/static/example_aiconfig_model_registry.py
+++ b/vscode-extension/static/example_aiconfig_model_registry.py
@@ -7,7 +7,6 @@
     See example below.
 """
 
-
 # from aiconfig import AIConfigRuntime
 # from llama import LlamaModelParser
 


Test patch:
diff --git a/python/tests/test_registry.py b/python/tests/test_registry.py
index 6fc65e115..677d66b10 100644
--- a/python/tests/test_registry.py
+++ b/python/tests/test_registry.py
@@ -16,7 +16,6 @@ def ai_config_runtime():
 
 
 class TestModelParserRegistry:
-
     """
     ModelParserRegistry is a static class with static variables. Setup and Teardown methods ensure that the static variable _parsers is restored to its original value after these tests. Isolates the tests from others.
     """