Repository: gradio-app/gradio
Pull request: Blocks components
Combine all input output and static components under components. A huge refactoring, detailed review would be great!

Fixes: #639 
- create general structure
- move Textbox into component.py

Problem statement:
[Blocks] Allow any output component to be used to display statically 
It should be possible to treat ANY output component like a static component by simply dumping an appropriate value to it. Like this:

```python
with Blocks() as block:
  outputs.Dataframe(df)
```

I think in order to do this, we would have to refactor the arguments for the `Output` components so that instead of the first argument being label, the first argument could be some sort of default value. So perhaps we should save this for `gradio 3.x` but I think this will be very convenient.

A non-breaking alternative that is a bit more cumbersome may be:

```python
df = ...

with Blocks() as block:
  outputs.Dataframe(value=df)
```

If we implement this, we could upgrade `Markdown` to a proper `Output` component instead of it being a `Static` component like it is now.

Hints from issue discussion:
I think we should reconsider this with Inputs and Outputs merging into Components.

Inputs and Outputs both can have default values.
In addition to default values, components should be able to display suitable variables statically for convenience. For example, we should be able to use `Image` to display an image easily, `Dataframe` to display a pandas DataFrame, `Audio` to display audio files, etc.

As an example of why this is useful, see this website: https://erlj.notion.site/Neural-Instrument-Cloning-from-very-few-samples-2cf41d8b630842ee8c7eb55036a1bfd6 -- we want people to be able to put stuff like this together with Blocks
@pngwn I think this will be the case when a component is not used as either an input or output in any event.
I think you are handling this currently as well, assigning it to you :)

Commit message: fixing test_inputs.py

Patch to review:
diff --git a/gradio/__init__.py b/gradio/__init__.py
index d29c8db627..b631326713 100644
--- a/gradio/__init__.py
+++ b/gradio/__init__.py
@@ -3,7 +3,7 @@
 import gradio.components as components
 import gradio.inputs as inputs
 import gradio.outputs as outputs
-from gradio.blocks import Blocks, Column, Row, Tabs, TabItem
+from gradio.blocks import Blocks, Column, Row, TabItem, Tabs
 from gradio.flagging import (
     CSVLogger,
     FlaggingCallback,
diff --git a/gradio/blocks.py b/gradio/blocks.py
index 0c4b4598b9..9bcd3f676e 100644
--- a/gradio/blocks.py
+++ b/gradio/blocks.py
@@ -113,13 +113,16 @@ class Row(BlockContext):
     def get_template_context(self):
         return {"type": "row"}
 
+
 class Column(BlockContext):
     def get_template_context(self):
         return {"type": "column"}
 
+
 class Tabs(BlockContext):
     pass
 
+
 class TabItem(BlockContext):
     def __init__(self, label):
         self.label = label
@@ -180,7 +183,9 @@ def get_config_file(self):
                 {
                     "id": _id,
                     "type": block.__class__.__name__.lower(),
-                    "props": block.get_template_context() if hasattr(block, "get_template_context") else None
+                    "props": block.get_template_context()
+                    if hasattr(block, "get_template_context")
+                    else None,
                 }
             )
 
diff --git a/gradio/components.py b/gradio/components.py
index f58bf7e30f..1b95a3f5ed 100644
--- a/gradio/components.py
+++ b/gradio/components.py
@@ -384,9 +384,8 @@ def __init__(
         default (float): default value.
         label (str): component name in interface.
         """
-        default = float(default)
-        self.default = default
-        self.test_input = default if default is not None else 1
+        self.default = float(default) if default is not None else None
+        self.test_input = self.default if self.default is not None else 1
         self.interpret_by_tokens = False
         super().__init__(label=label, **kwargs)
 
@@ -509,7 +508,7 @@ def __init__(
         if step is None:
             difference = maximum - minimum
             power = math.floor(math.log10(difference) - 2)
-            step = 10 ** power
+            step = 10**power
         self.step = step
         self.default = minimum if default is None else default
         self.test_input = self.default
@@ -1283,7 +1282,7 @@ def preprocess(self, x: Dict[str, str] | None) -> str | None:
         file_name = file.name
         uploaded_format = file_name.split(".")[-1].lower()
         if self.type is not None and uploaded_format != self.type:
-            output_file_name = file_name[0: file_name.rindex(".") + 1] + self.type
+            output_file_name = file_name[0 : file_name.rindex(".") + 1] + self.type
             ff = FFmpeg(inputs={file_name: None}, outputs={output_file_name: None})
             ff.run()
             return output_file_name
@@ -1313,7 +1312,7 @@ def postprocess(self, y):
         """
         returned_format = y.split(".")[-1].lower()
         if self.type is not None and returned_format != self.type:
-            output_file_name = y[0: y.rindex(".") + 1] + self.type
+            output_file_name = y[0 : y.rindex(".") + 1] + self.type
             ff = FFmpeg(inputs={y: None}, outputs={output_file_name: None})
             ff.run()
             y = output_file_name
@@ -2098,36 +2097,9 @@ def __init__(self, default: str = " ", *, label: Optional[str] = None, **kwargs)
         default (str): IGNORED
         label (str): component name in interface.
         """
-        super().__init__(label=label, **kwargs)
-
-    def postprocess(self, y):
-        """
-        Parameters:
-        y (Union[Dict, List[Tuple[str, Union[str, int, float]]]]): dictionary or tuple list representing key value pairs
-        Returns:
-        (List[Tuple[str, Union[str, number]]]): list of key value pairs
-        """
-        if isinstance(y, dict):
-            return list(y.items())
-        elif isinstance(y, list):
-            return y
-        else:
-            raise ValueError(
-                "The `KeyValues` output interface expects an output that is a dictionary whose keys are "
-                "labels and values are corresponding values."
-            )
-
-    @classmethod
-    def get_shortcut_implementations(cls):
-        return {
-            "key_values": {},
-        }
-
-    def save_flagged(self, dir, label, data, encryption_key):
-        return json.dumps(data)
-
-    def restore_flagged(self, dir, data, encryption_key):
-        return json.loads(data)
+        raise DeprecationWarning(
+            "The KeyValues component is deprecated. Please use the DataFrame or JSON "
+            "components instead.")
 
 
 class HighlightedText(Component):
@@ -2389,7 +2361,7 @@ def __init__(self, label):
 # TODO: (faruk) does this take component or interface as a input?
 # see this line in Carousel
 # self.components = [get_component_instance(component) for component in components]
-def get_component_instance(iface: "Interface"):
+def get_component_instance(iface: Component):
     # TODO: function may not work properly, and it needs updates regarding its design. See:
     # https://github.com/gradio-app/gradio/issues/731
     if isinstance(iface, str):
diff --git a/gradio/external.py b/gradio/external.py
index 9b30252346..6423b8ad3e 100644
--- a/gradio/external.py
+++ b/gradio/external.py
@@ -4,7 +4,7 @@
 
 import requests
 
-from gradio import inputs, outputs
+from gradio import components
 
 
 def get_huggingface_interface(model_name, api_key, alias):
@@ -49,8 +49,8 @@ def encode_to_base64(r: requests.Response) -> str:
     pipelines = {
         "audio-classification": {
             # example model: https://hf.co/ehcalabres/wav2vec2-lg-xlsr-en-speech-emotion-recognition
-            "inputs": inputs.Audio(label="Input", source="upload", type="filepath"),
-            "outputs": outputs.Label(label="Class", type="confidences"),
+            "inputs": components.Audio(label="Input", source="upload", type="filepath"),
+            "outputs": components.Label(label="Class"),
             "preprocess": lambda i: base64.b64decode(
                 i["data"].split(",")[1]
             ),  # convert the base64 representation to binary
@@ -60,8 +60,8 @@ def encode_to_base64(r: requests.Response) -> str:
         },
         "audio-to-audio": {
             # example model: https://hf.co/speechbrain/mtl-mimic-voicebank
-            "inputs": inputs.Audio(label="Input", source="upload", type="filepath"),
-            "outputs": outputs.Audio(label="Output"),
+            "inputs": components.Audio(label="Input", source="upload", type="filepath"),
+            "outputs": components.Audio(label="Output"),
             "preprocess": lambda i: base64.b64decode(
                 i["data"].split(",")[1]
             ),  # convert the base64 representation to binary
@@ -69,8 +69,8 @@ def encode_to_base64(r: requests.Response) -> str:
         },
         "automatic-speech-recognition": {
             # example model: https://hf.co/jonatasgrosman/wav2vec2-large-xlsr-53-english
-            "inputs": inputs.Audio(label="Input", source="upload", type="filepath"),
-            "outputs": outputs.Textbox(label="Output"),
+            "inputs": components.Audio(label="Input", source="upload", type="filepath"),
+            "outputs": components.Textbox(label="Output"),
             "preprocess": lambda i: base64.b64decode(
                 i["data"].split(",")[1]
             ),  # convert the base64 representation to binary
@@ -78,21 +78,21 @@ def encode_to_base64(r: requests.Response) -> str:
         },
         "feature-extraction": {
             # example model: hf.co/julien-c/distilbert-feature-extraction
-            "inputs": inputs.Textbox(label="Input"),
-            "outputs": outputs.Dataframe(label="Output"),
+            "inputs": components.Textbox(label="Input"),
+            "outputs": components.Dataframe(label="Output"),
             "preprocess": lambda x: {"inputs": x},
             "postprocess": lambda r: r.json()[0],
         },
         "fill-mask": {
-            "inputs": inputs.Textbox(label="Input"),
-            "outputs": outputs.Label(label="Classification", type="confidences"),
+            "inputs": components.Textbox(label="Input"),
+            "outputs": components.Label(label="Classification"),
             "preprocess": lambda x: {"inputs": x},
             "postprocess": lambda r: {i["token_str"]: i["score"] for i in r.json()},
         },
         "image-classification": {
             # Example: https://huggingface.co/google/vit-base-patch16-224
-            "inputs": inputs.Image(label="Input Image", type="filepath"),
-            "outputs": outputs.Label(label="Classification", type="confidences"),
+            "inputs": components.Image(label="Input Image", type="filepath"),
+            "outputs": components.Label(label="Classification"),
             "preprocess": lambda i: base64.b64decode(
                 i.split(",")[1]
             ),  # convert the base64 representation to binary
@@ -111,52 +111,52 @@ def encode_to_base64(r: requests.Response) -> str:
         # TODO: also: support NER pipeline, object detection, table question answering
         "question-answering": {
             "inputs": [
-                inputs.Textbox(label="Context", lines=7),
-                inputs.Textbox(label="Question"),
+                components.Textbox(label="Context", lines=7),
+                components.Textbox(label="Question"),
             ],
-            "outputs": [outputs.Textbox(label="Answer"), outputs.Label(label="Score")],
+            "outputs": [components.Textbox(label="Answer"), components.Label(label="Score")],
             "preprocess": lambda c, q: {"inputs": {"context": c, "question": q}},
             "postprocess": lambda r: (r.json()["answer"], r.json()["score"]),
         },
         "summarization": {
-            "inputs": inputs.Textbox(label="Input"),
-            "outputs": outputs.Textbox(label="Summary"),
+            "inputs": components.Textbox(label="Input"),
+            "outputs": components.Textbox(label="Summary"),
             "preprocess": lambda x: {"inputs": x},
             "postprocess": lambda r: r.json()[0]["summary_text"],
         },
         "text-classification": {
-            "inputs": inputs.Textbox(label="Input"),
-            "outputs": outputs.Label(label="Classification", type="confidences"),
+            "inputs": components.Textbox(label="Input"),
+            "outputs": components.Label(label="Classification", type="confidences"),
             "preprocess": lambda x: {"inputs": x},
             "postprocess": lambda r: {
                 i["label"].split(", ")[0]: i["score"] for i in r.json()[0]
             },
         },
         "text-generation": {
-            "inputs": inputs.Textbox(label="Input"),
-            "outputs": outputs.Textbox(label="Output"),
+            "inputs": components.Textbox(label="Input"),
+            "outputs": components.Textbox(label="Output"),
             "preprocess": lambda x: {"inputs": x},
             "postprocess": lambda r: r.json()[0]["generated_text"],
         },
         "text2text-generation": {
-            "inputs": inputs.Textbox(label="Input"),
-            "outputs": outputs.Textbox(label="Generated Text"),
+            "inputs": components.Textbox(label="Input"),
+            "outputs": components.Textbox(label="Generated Text"),
             "preprocess": lambda x: {"inputs": x},
             "postprocess": lambda r: r.json()[0]["generated_text"],
         },
         "translation": {
-            "inputs": inputs.Textbox(label="Input"),
-            "outputs": outputs.Textbox(label="Translation"),
+            "inputs": components.Textbox(label="Input"),
+            "outputs": components.Textbox(label="Translation"),
             "preprocess": lambda x: {"inputs": x},
             "postprocess": lambda r: r.json()[0]["translation_text"],
         },
         "zero-shot-classification": {
             "inputs": [
-                inputs.Textbox(label="Input"),
-                inputs.Textbox(label="Possible class names (" "comma-separated)"),
-                inputs.Checkbox(label="Allow multiple true classes"),
+                components.Textbox(label="Input"),
+                components.Textbox(label="Possible class names (" "comma-separated)"),
+                components.Checkbox(label="Allow multiple true classes"),
             ],
-            "outputs": outputs.Label(label="Classification", type="confidences"),
+            "outputs": components.Label(label="Classification", type="confidences"),
             "preprocess": lambda i, c, m: {
                 "inputs": i,
                 "parameters": {"candidate_labels": c, "multi_class": m},
@@ -169,16 +169,16 @@ def encode_to_base64(r: requests.Response) -> str:
         "sentence-similarity": {
             # example model: hf.co/sentence-transformers/distilbert-base-nli-stsb-mean-tokens
             "inputs": [
-                inputs.Textbox(
+                components.Textbox(
                     label="Source Sentence", default="That is a happy person"
                 ),
-                inputs.Textbox(
+                components.Textbox(
                     lines=7,
                     label="Sentences to compare to",
                     placeholder="Separate each sentence by a newline",
                 ),
             ],
-            "outputs": outputs.Label(label="Classification", type="confidences"),
+            "outputs": components.Label(label="Classification"),
             "preprocess": lambda src, sentences: {
                 "inputs": {
                     "source_sentence": src,
@@ -191,15 +191,15 @@ def encode_to_base64(r: requests.Response) -> str:
         },
         "text-to-speech": {
             # example model: hf.co/julien-c/ljspeech_tts_train_tacotron2_raw_phn_tacotron_g2p_en_no_space_train
-            "inputs": inputs.Textbox(label="Input"),
-            "outputs": outputs.Audio(label="Audio"),
+            "inputs": components.Textbox(label="Input"),
+            "outputs": components.Audio(label="Audio"),
             "preprocess": lambda x: {"inputs": x},
             "postprocess": encode_to_base64,
         },
         "text-to-image": {
             # example model: hf.co/osanseviero/BigGAN-deep-128
-            "inputs": inputs.Textbox(label="Input"),
-            "outputs": outputs.Image(label="Output"),
+            "inputs": components.Textbox(label="Input"),
+            "outputs": components.Image(label="Output"),
             "preprocess": lambda x: {"inputs": x},
             "postprocess": encode_to_base64,
         },
@@ -261,11 +261,11 @@ def load_interface(name, src=None, api_key=None, alias=None):
 def interface_params_from_config(config_dict):
     # instantiate input component and output component
     config_dict["inputs"] = [
-        inputs.get_input_instance(component)
+        components.get_component_instance(component)
         for component in config_dict["input_components"]
     ]
     config_dict["outputs"] = [
-        outputs.get_output_instance(component)
+        components.get_component_instance(component)
         for component in config_dict["output_components"]
     ]
     parameters = {
@@ -354,8 +354,8 @@ def load_from_pipeline(pipeline):
         pipeline, transformers.AudioClassificationPipeline
     ):
         pipeline_info = {
-            "inputs": inputs.Audio(label="Input", source="microphone", type="filepath"),
-            "outputs": outputs.Label(label="Class", type="confidences"),
+            "inputs": components.Audio(label="Input", source="microphone", type="filepath"),
+            "outputs": components.Label(label="Class"),
             "preprocess": lambda i: {"inputs": i},
             "postprocess": lambda r: {i["label"].split(", ")[0]: i["score"] for i in r},
         }
@@ -363,8 +363,8 @@ def load_from_pipeline(pipeline):
         pipeline, transformers.AutomaticSpeechRecognitionPipeline
     ):
         pipeline_info = {
-            "inputs": inputs.Audio(label="Input", source="microphone", type="filepath"),
-            "outputs": outputs.Textbox(label="Output"),
+            "inputs": components.Audio(label="Input", source="microphone", type="filepath"),
+            "outputs": components.Textbox(label="Output"),
             "preprocess": lambda i: {"inputs": i},
             "postprocess": lambda r: r["text"],
         }
@@ -372,8 +372,8 @@ def load_from_pipeline(pipeline):
         pipeline, transformers.FeatureExtractionPipeline
     ):
         pipeline_info = {
-            "inputs": inputs.Textbox(label="Input"),
-            "outputs": outputs.Dataframe(label="Output"),
+            "inputs": components.Textbox(label="Input"),
+            "outputs": components.Dataframe(label="Output"),
             "preprocess": lambda x: {"inputs": x},
             "postprocess": lambda r: r[0],
         }
@@ -381,8 +381,8 @@ def load_from_pipeline(pipeline):
         pipeline, transformers.FillMaskPipeline
     ):
         pipeline_info = {
-            "inputs": inputs.Textbox(label="Input"),
-            "outputs": outputs.Label(label="Classification", type="confidences"),
+            "inputs": components.Textbox(label="Input"),
+            "outputs": components.Label(label="Classification"),
             "preprocess": lambda x: {"inputs": x},
             "postprocess": lambda r: {i["token_str"]: i["score"] for i in r},
         }
@@ -390,8 +390,8 @@ def load_from_pipeline(pipeline):
         pipeline, transformers.ImageClassificationPipeline
     ):
         pipeline_info = {
-            "inputs": inputs.Image(label="Input Image", type="filepath"),
-            "outputs": outputs.Label(label="Classification", type="confidences"),
+            "inputs": components.Image(label="Input Image", type="filepath"),
+            "outputs": components.Label(label="Classification", type="confidences"),
             "preprocess": lambda i: {"images": i},
             "postprocess": lambda r: {i["label"].split(", ")[0]: i["score"] for i in r},
         }
@@ -400,10 +400,11 @@ def load_from_pipeline(pipeline):
     ):
         pipeline_info = {
             "inputs": [
-                inputs.Textbox(label="Context", lines=7),
-                inputs.Textbox(label="Question"),
+                components.Textbox(label="Context", lines=7),
+                components.Textbox(label="Question"),
             ],
-            "outputs": [outputs.Textbox(label="Answer"), outputs.Label(label="Score")],
+            "outputs": [components.Textbox(label="Answer"), 
+                        components.Label(label="Score")],
             "preprocess": lambda c, q: {"context": c, "question": q},
             "postprocess": lambda r: (r["answer"], r["score"]),
         }
@@ -411,8 +412,8 @@ def load_from_pipeline(pipeline):
         pipeline, transformers.SummarizationPipeline
     ):
         pipeline_info = {
-            "inputs": inputs.Textbox(label="Input", lines=7),
-            "outputs": outputs.Textbox(label="Summary"),
+            "inputs": components.Textbox(label="Input", lines=7),
+            "outputs": components.Textbox(label="Summary"),
             "preprocess": lambda x: {"inputs": x},
             "postprocess": lambda r: r[0]["summary_text"],
         }
@@ -420,8 +421,8 @@ def load_from_pipeline(pipeline):
         pipeline, transformers.TextClassificationPipeline
     ):
         pipeline_info = {
-            "inputs": inputs.Textbox(label="Input"),
-            "outputs": outputs.Label(label="Classification", type="confidences"),
+            "inputs": components.Textbox(label="Input"),
+            "outputs": components.Label(label="Classification"),
             "preprocess": lambda x: [x],
             "postprocess": lambda r: {i["label"].split(", ")[0]: i["score"] for i in r},
         }
@@ -429,8 +430,8 @@ def load_from_pipeline(pipeline):
         pipeline, transformers.TextGenerationPipeline
     ):
         pipeline_info = {
-            "inputs": inputs.Textbox(label="Input"),
-            "outputs": outputs.Textbox(label="Output"),
+            "inputs": components.Textbox(label="Input"),
+            "outputs": components.Textbox(label="Output"),
             "preprocess": lambda x: {"text_inputs": x},
             "postprocess": lambda r: r[0]["generated_text"],
         }
@@ -438,8 +439,8 @@ def load_from_pipeline(pipeline):
         pipeline, transformers.TranslationPipeline
     ):
         pipeline_info = {
-            "inputs": inputs.Textbox(label="Input"),
-            "outputs": outputs.Textbox(label="Translation"),
+            "inputs": components.Textbox(label="Input"),
+            "outputs": components.Textbox(label="Translation"),
             "preprocess": lambda x: [x],
             "postprocess": lambda r: r[0]["translation_text"],
         }
@@ -447,8 +448,8 @@ def load_from_pipeline(pipeline):
         pipeline, transformers.Text2TextGenerationPipeline
     ):
         pipeline_info = {
-            "inputs": inputs.Textbox(label="Input"),
-            "outputs": outputs.Textbox(label="Generated Text"),
+            "inputs": components.Textbox(label="Input"),
+            "outputs": components.Textbox(label="Generated Text"),
             "preprocess": lambda x: [x],
             "postprocess": lambda r: r[0]["generated_text"],
         }
@@ -457,11 +458,11 @@ def load_from_pipeline(pipeline):
     ):
         pipeline_info = {
             "inputs": [
-                inputs.Textbox(label="Input"),
-                inputs.Textbox(label="Possible class names (" "comma-separated)"),
-                inputs.Checkbox(label="Allow multiple true classes"),
+                components.Textbox(label="Input"),
+                components.Textbox(label="Possible class names (" "comma-separated)"),
+                components.Checkbox(label="Allow multiple true classes"),
             ],
-            "outputs": outputs.Label(label="Classification", type="confidences"),
+            "outputs": components.Label(label="Classification"),
             "preprocess": lambda i, c, m: {
                 "sequences": i,
                 "candidate_labels": c,
diff --git a/gradio/inputs.py b/gradio/inputs.py
index cf9e700132..b7986a34e6 100644
--- a/gradio/inputs.py
+++ b/gradio/inputs.py
@@ -6,23 +6,13 @@
 
 from __future__ import annotations
 
-import json
-import os
-import tempfile
 import warnings
-from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple
+from typing import Any, List, Optional, Tuple
 
-import numpy as np
-import pandas as pd
-import PIL
-from ffmpy import FFmpeg
-
-from gradio import processing_utils, test_data
 from gradio.components import (
     Audio,
     Checkbox,
     CheckboxGroup,
-    Component,
     Dataframe,
     Dropdown,
     File,
@@ -33,13 +23,10 @@
     State,
     Textbox,
     Timeseries,
+    Video,
 )
 
-if TYPE_CHECKING:  # Only import for type checking (is False at runtime).
-    from gradio import Interface
-
 
-# TODO: (faruk) Remove this file in version 3.0
 class Textbox(Textbox):
     def __init__(
         self,
@@ -299,7 +286,7 @@ def __init__(
         )
 
 
-class Video(Component):
+class Video(Video):
     """
     Component creates a video file upload that is converted to a file path.
 
diff --git a/gradio/interface.py b/gradio/interface.py
index dfe03445c9..cd7d28422b 100644
--- a/gradio/interface.py
+++ b/gradio/interface.py
@@ -18,6 +18,7 @@
 from mdit_py_plugins.footnote import footnote_plugin
 
 from gradio import interpretation, utils
+from gradio.components import Component, get_component_instance
 from gradio.external import load_from_pipeline, load_interface  # type: ignore
 from gradio.flagging import CSVLogger, FlaggingCallback  # type: ignore
 from gradio.inputs import State as i_State  # type: ignore
@@ -96,8 +97,8 @@ def from_pipeline(cls, pipeline: transformers.Pipeline, **kwargs) -> Interface:
     def __init__(
         self,
         fn: Callable | List[Callable],
-        inputs: str | InputComponent | List[str | InputComponent] = None,
-        outputs: str | OutputComponent | List[str | OutputComponent] = None,
+        inputs: str | Component | List[str | Component] = None,
+        outputs: str | Component | List[str | Component] = None,
         verbose: bool = False,
         examples: Optional[List[Any] | List[List[Any]] | str] = None,
         examples_per_page: int = 10,
@@ -167,8 +168,8 @@ def __init__(
         if not isinstance(outputs, list):
             outputs = [outputs]
 
-        self.input_components = [get_input_instance(i) for i in inputs]
-        self.output_components = [get_output_instance(o) for o in outputs]
+        self.input_components = [get_component_instance(i) for i in inputs]
+        self.output_components = [get_component_instance(o) for o in outputs]
         if repeat_outputs_per_model:
             self.output_components *= len(fn)
 
diff --git a/gradio/interpretation.py b/gradio/interpretation.py
index 42d833de7c..217480a753 100644
--- a/gradio/interpretation.py
+++ b/gradio/interpretation.py
@@ -3,7 +3,7 @@
 
 import numpy as np
 
-from gradio.outputs import Label, Textbox
+from gradio.components import Label, Textbox, Number
 
 
 def run_interpret(interface, raw_input):
@@ -198,7 +198,7 @@ def quantify_difference_in_label(interface, original_output, perturbed_output):
             score = diff(original_label, perturbed_label)
         return score
 
-    elif isinstance(output_component, Textbox):
+    elif isinstance(output_component, (Textbox, Number)):
         score = diff(post_original_output, post_perturbed_output)
         return score
 
diff --git a/gradio/outputs.py b/gradio/outputs.py
index 4f26b92ad3..d5630fc6d6 100644
--- a/gradio/outputs.py
+++ b/gradio/outputs.py
@@ -6,21 +6,9 @@
 
 from __future__ import annotations
 
-import json
-import operator
-import os
-import tempfile
+from typing import Dict, List, Optional
 import warnings
-from numbers import Number
-from types import ModuleType
-from typing import TYPE_CHECKING, Dict, List, Optional
 
-import numpy as np
-import pandas as pd
-import PIL
-from ffmpy import FFmpeg
-
-from gradio import processing_utils
 from gradio.components import (
     HTML,
     JSON,
@@ -40,18 +28,12 @@
     Video,
 )
 
-if TYPE_CHECKING:  # Only import for type checking (is False at runtime).
-    from gradio import Interface
-
-
-# TODO: (faruk) Remove this file in version 3.0
 class Textbox(Textbox):
     def __init__(
         self,
         type: str = "auto",
         label: Optional[str] = None,
     ):
-        # TODO: (faruk) Remove this file in version 3.0
         warnings.warn(
             "Usage of gradio.outputs is deprecated, and will not be supported in the future, please import your components from gradio.components",
             DeprecationWarning,
@@ -351,56 +333,6 @@ def __init__(
         )
         super().__init__(label=label, components=components)
 
-    def get_template_context(self):
-        return {
-            "components": [
-                component.get_template_context() for component in self.components
-            ],
-            **super().get_template_context(),
-        }
-
-    def postprocess(self, y):
-        """
-        Parameters:
-        y (List[List[Any]]): carousel output
-        Returns:
-        (List[List[Any]]): 2D array, where each sublist represents one set of outputs or 'slide' in the carousel
-        """
-        if isinstance(y, list):
-            if len(y) != 0 and not isinstance(y[0], list):
-                y = [[z] for z in y]
-            output = []
-            for row in y:
-                output_row = []
-                for i, cell in enumerate(row):
-                    output_row.append(self.components[i].postprocess(cell))
-                output.append(output_row)
-            return output
-        else:
-            raise ValueError("Unknown type. Please provide a list for the Carousel.")
-
-    def save_flagged(self, dir, label, data, encryption_key):
-        return json.dumps(
-            [
-                [
-                    component.save_flagged(
-                        dir, f"{label}_{j}", data[i][j], encryption_key
-                    )
-                    for j, component in enumerate(self.components)
-                ]
-                for i, _ in enumerate(data)
-            ]
-        )
-
-    def restore_flagged(self, dir, data, encryption_key):
-        return [
-            [
-                component.restore_flagged(dir, sample, encryption_key)
-                for component, sample in zip(self.components, sample_set)
-            ]
-            for sample_set in json.loads(data)
-        ]
-
 
 class Chatbot(Chatbot):
     """
@@ -420,21 +352,3 @@ def __init__(self, label: Optional[str] = None):
         )
         super().__init__(label=label)
 
-    def get_template_context(self):
-        return {**super().get_template_context()}
-
-    @classmethod
-    def get_shortcut_implementations(cls):
-        return {
-            "chatbot": {},
-        }
-
-    def postprocess(self, y):
-        """
-        Parameters:
-        y (List[Tuple[str, str]]): List of tuples representing the message and response
-        Returns:
-        (List[Tuple[str, str]]): Returns same list of tuples
-
-        """
-        return y
diff --git a/gradio/templates/frontend/index.html b/gradio/templates/frontend/index.html
index 791df88b32..953e0ae8bd 100644
--- a/gradio/templates/frontend/index.html
+++ b/gradio/templates/frontend/index.html
@@ -45,9 +45,9 @@
 		</script>
 		<script src="https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/4.3.1/iframeResizer.contentWindow.min.js"></script>
 		<title>Gradio</title>
-		<script type="module" crossorigin src="./assets/index.f11fc79b.js"></script>
+		<script type="module" crossorigin src="./assets/index.a875c593.js"></script>
 		<link rel="modulepreload" href="./assets/vendor.cb9b505c.js">
-		<link rel="stylesheet" href="./assets/index.d9a85447.css">
+		<link rel="stylesheet" href="./assets/index.5f57d3ce.css">
 	</head>
 
 	<body style="height: 100%; margin: 0; padding: 0">
diff --git a/test/test_context.py b/test/test_context.py
index ad3432d828..37d304f451 100644
--- a/test/test_context.py
+++ b/test/test_context.py
@@ -1,5 +1,6 @@
 def test_context():
     from gradio.context import Context
+
     assert Context.id == 0
     Context.id += 1
     assert Context.id == 1
diff --git a/test/test_external.py b/test/test_external.py
index 6f081f68a0..c2421da204 100644
--- a/test/test_external.py
+++ b/test/test_external.py
@@ -24,8 +24,8 @@ def test_audio_to_audio(self):
             alias=model_type,
         )
         self.assertEqual(interface_info["fn"].__name__, model_type)
-        self.assertIsInstance(interface_info["inputs"], gr.inputs.Audio)
-        self.assertIsInstance(interface_info["outputs"], gr.outputs.Audio)
+        self.assertIsInstance(interface_info["inputs"], gr.components.Audio)
+        self.assertIsInstance(interface_info["outputs"], gr.components.Audio)
 
     def test_question_answering(self):
         model_type = "question-answering"
@@ -33,8 +33,8 @@ def test_question_answering(self):
             "lysandre/tiny-vit-random", api_key=None, alias=model_type
         )
         self.assertEqual(interface_info["fn"].__name__, model_type)
-        self.assertIsInstance(interface_info["inputs"], gr.inputs.Image)
-        self.assertIsInstance(interface_info["outputs"], gr.outputs.Label)
+        self.assertIsInstance(interface_info["inputs"], gr.components.Image)
+        self.assertIsInstance(interface_info["outputs"], gr.components.Label)
 
     def test_text_generation(self):
         model_type = "text_generation"
@@ -42,8 +42,8 @@ def test_text_generation(self):
             "gpt2", api_key=None, alias=model_type
         )
         self.assertEqual(interface_info["fn"].__name__, model_type)
-        self.assertIsInstance(interface_info["inputs"], gr.inputs.Textbox)
-        self.assertIsInstance(interface_info["outputs"], gr.outputs.Textbox)
+        self.assertIsInstance(interface_info["inputs"], gr.components.Textbox)
+        self.assertIsInstance(interface_info["outputs"], gr.components.Textbox)
 
     def test_summarization(self):
         model_type = "summarization"
@@ -51,8 +51,8 @@ def test_summarization(self):
             "facebook/bart-large-cnn", api_key=None, alias=model_type
         )
         self.assertEqual(interface_info["fn"].__name__, model_type)
-        self.assertIsInstance(interface_info["inputs"], gr.inputs.Textbox)
-        self.assertIsInstance(interface_info["outputs"], gr.outputs.Textbox)
+        self.assertIsInstance(interface_info["inputs"], gr.components.Textbox)
+        self.assertIsInstance(interface_info["outputs"], gr.components.Textbox)
 
     def test_translation(self):
         model_type = "translation"
@@ -60,8 +60,8 @@ def test_translation(self):
             "facebook/bart-large-cnn", api_key=None, alias=model_type
         )
         self.assertEqual(interface_info["fn"].__name__, model_type)
-        self.assertIsInstance(interface_info["inputs"], gr.inputs.Textbox)
-        self.assertIsInstance(interface_info["outputs"], gr.outputs.Textbox)
+        self.assertIsInstance(interface_info["inputs"], gr.components.Textbox)
+        self.assertIsInstance(interface_info["outputs"], gr.components.Textbox)
 
     def test_text2text_generation(self):
         model_type = "text2text-generation"
@@ -69,8 +69,8 @@ def test_text2text_generation(self):
             "sshleifer/tiny-mbart", api_key=None, alias=model_type
         )
         self.assertEqual(interface_info["fn"].__name__, model_type)
-        self.assertIsInstance(interface_info["inputs"], gr.inputs.Textbox)
-        self.assertIsInstance(interface_info["outputs"], gr.outputs.Textbox)
+        self.assertIsInstance(interface_info["inputs"], gr.components.Textbox)
+        self.assertIsInstance(interface_info["outputs"], gr.components.Textbox)
 
     def test_text_classification(self):
         model_type = "text-classification"
@@ -80,8 +80,8 @@ def test_text_classification(self):
             alias=model_type,
         )
         self.assertEqual(interface_info["fn"].__name__, model_type)
-        self.assertIsInstance(interface_info["inputs"], gr.inputs.Textbox)
-        self.assertIsInstance(interface_info["outputs"], gr.outputs.Label)
+        self.assertIsInstance(interface_info["inputs"], gr.components.Textbox)
+        self.assertIsInstance(interface_info["outputs"], gr.components.Label)
 
     def test_fill_mask(self):
         model_type = "fill-mask"
@@ -89,8 +89,8 @@ def test_fill_mask(self):
             "bert-base-uncased", api_key=None, alias=model_type
         )
         self.assertEqual(interface_info["fn"].__name__, model_type)
-        self.assertIsInstance(interface_info["inputs"], gr.inputs.Textbox)
-        self.assertIsInstance(interface_info["outputs"], gr.outputs.Label)
+        self.assertIsInstance(interface_info["inputs"], gr.components.Textbox)
+        self.assertIsInstance(interface_info["outputs"], gr.components.Label)
 
     def test_zero_shot_classification(self):
         model_type = "zero-shot-classification"
@@ -98,10 +98,10 @@ def test_zero_shot_classification(self):
             "facebook/bart-large-mnli", api_key=None, alias=model_type
         )
         self.assertEqual(interface_info["fn"].__name__, model_type)
-        self.assertIsInstance(interface_info["inputs"][0], gr.inputs.Textbox)
-        self.assertIsInstance(interface_info["inputs"][1], gr.inputs.Textbox)
-        self.assertIsInstance(interface_info["inputs"][2], gr.inputs.Checkbox)
-        self.assertIsInstance(interface_info["outputs"], gr.outputs.Label)
+        self.assertIsInstance(interface_info["inputs"][0], gr.components.Textbox)
+        self.assertIsInstance(interface_info["inputs"][1], gr.components.Textbox)
+        self.assertIsInstance(interface_info["inputs"][2], gr.components.Checkbox)
+        self.assertIsInstance(interface_info["outputs"], gr.components.Label)
 
     def test_automatic_speech_recognition(self):
         model_type = "automatic-speech-recognition"
@@ -109,8 +109,8 @@ def test_automatic_speech_recognition(self):
             "facebook/wav2vec2-base-960h", api_key=None, alias=model_type
         )
         self.assertEqual(interface_info["fn"].__name__, model_type)
-        self.assertIsInstance(interface_info["inputs"], gr.inputs.Audio)
-        self.assertIsInstance(interface_info["outputs"], gr.outputs.Textbox)
+        self.assertIsInstance(interface_info["inputs"], gr.components.Audio)
+        self.assertIsInstance(interface_info["outputs"], gr.components.Textbox)
 
     def test_image_classification(self):
         model_type = "image-classification"
@@ -118,8 +118,8 @@ def test_image_classification(self):
             "google/vit-base-patch16-224", api_key=None, alias=model_type
         )
         self.assertEqual(interface_info["fn"].__name__, model_type)
-        self.assertIsInstance(interface_info["inputs"], gr.inputs.Image)
-        self.assertIsInstance(interface_info["outputs"], gr.outputs.Label)
+        self.assertIsInstance(interface_info["inputs"], gr.components.Image)
+        self.assertIsInstance(interface_info["outputs"], gr.components.Label)
 
     def test_feature_extraction(self):
         model_type = "feature-extraction"
@@ -129,8 +129,8 @@ def test_feature_extraction(self):
             alias=model_type,
         )
         self.assertEqual(interface_info["fn"].__name__, model_type)
-        self.assertIsInstance(interface_info["inputs"], gr.inputs.Textbox)
-        self.assertIsInstance(interface_info["outputs"], gr.outputs.Dataframe)
+        self.assertIsInstance(interface_info["inputs"], gr.components.Textbox)
+        self.assertIsInstance(interface_info["outputs"], gr.components.Dataframe)
 
     def test_sentence_similarity(self):
         model_type = "text-to-speech"
@@ -140,8 +140,8 @@ def test_sentence_similarity(self):
             alias=model_type,
         )
         self.assertEqual(interface_info["fn"].__name__, model_type)
-        self.assertIsInstance(interface_info["inputs"], gr.inputs.Textbox)
-        self.assertIsInstance(interface_info["outputs"], gr.outputs.Audio)
+        self.assertIsInstance(interface_info["inputs"], gr.components.Textbox)
+        self.assertIsInstance(interface_info["outputs"], gr.components.Audio)
 
     def test_text_to_speech(self):
         model_type = "text-to-speech"
@@ -151,8 +151,8 @@ def test_text_to_speech(self):
             alias=model_type,
         )
         self.assertEqual(interface_info["fn"].__name__, model_type)
-        self.assertIsInstance(interface_info["inputs"], gr.inputs.Textbox)
-        self.assertIsInstance(interface_info["outputs"], gr.outputs.Audio)
+        self.assertIsInstance(interface_info["inputs"], gr.components.Textbox)
+        self.assertIsInstance(interface_info["outputs"], gr.components.Audio)
 
     def test_text_to_image(self):
         model_type = "text-to-image"
@@ -160,15 +160,15 @@ def test_text_to_image(self):
             "osanseviero/BigGAN-deep-128", api_key=None, alias=model_type
         )
         self.assertEqual(interface_info["fn"].__name__, model_type)
-        self.assertIsInstance(interface_info["inputs"], gr.inputs.Textbox)
-        self.assertIsInstance(interface_info["outputs"], gr.outputs.Image)
+        self.assertIsInstance(interface_info["inputs"], gr.components.Textbox)
+        self.assertIsInstance(interface_info["outputs"], gr.components.Image)
 
     def test_english_to_spanish(self):
         interface_info = gr.external.get_spaces_interface(
             "abidlabs/english_to_spanish", api_key=None, alias=None
         )
-        self.assertIsInstance(interface_info["inputs"][0], gr.inputs.Textbox)
-        self.assertIsInstance(interface_info["outputs"][0], gr.outputs.Textbox)
+        self.assertIsInstance(interface_info["inputs"][0], gr.components.Textbox)
+        self.assertIsInstance(interface_info["outputs"][0], gr.components.Textbox)
 
 
 class TestLoadInterface(unittest.TestCase):
@@ -176,8 +176,8 @@ def test_english_to_spanish(self):
         interface_info = gr.external.load_interface(
             "spaces/abidlabs/english_to_spanish"
         )
-        self.assertIsInstance(interface_info["inputs"][0], gr.inputs.Textbox)
-        self.assertIsInstance(interface_info["outputs"][0], gr.outputs.Textbox)
+        self.assertIsInstance(interface_info["inputs"][0], gr.components.Textbox)
+        self.assertIsInstance(interface_info["outputs"][0], gr.components.Textbox)
 
     def test_sentiment_model(self):
         interface_info = gr.external.load_interface(
diff --git a/test/test_inputs.py b/test/test_inputs.py
index 83b8fe4a7c..6b6309287a 100644
--- a/test/test_inputs.py
+++ b/test/test_inputs.py
@@ -13,18 +13,6 @@
 os.environ["GRADIO_ANALYTICS_ENABLED"] = "False"
 
 
-class InputComponent(unittest.TestCase):
-    def test_as_component(self):
-        input = gr.inputs.InputComponent(label="Test Input")
-        self.assertEqual(input.preprocess("Hello World!"), "Hello World!")
-        self.assertEqual(input.preprocess_example(["1", "2", "3"]), ["1", "2", "3"])
-        self.assertEqual(input.serialize(1, True), 1)
-        self.assertEqual(input.set_interpret_parameters(), input)
-        self.assertIsNone(input.get_interpretation_neighbors("Hi!"))
-        self.assertIsNone(input.get_interpretation_scores("Hi!", [], []))
-        self.assertIsNone(input.generate_sample())
-
-
 class TestTextbox(unittest.TestCase):
     def test_as_component(self):
         text_input = gr.inputs.Textbox()
@@ -783,9 +771,9 @@ def test_in_interface(self):
 
 
 class TestNames(unittest.TestCase):
-    # this ensures that `inputs.get_input_instance()` works correctly when instantiating from components
+    # this ensures that `components.get_component_instance()` works correctly when instantiating from components
     def test_no_duplicate_uncased_names(self):
-        subclasses = gr.inputs.InputComponent.__subclasses__()
+        subclasses = gr.components.Component.__subclasses__()
         unique_subclasses_uncased = set([s.__name__.lower() for s in subclasses])
         self.assertEqual(len(subclasses), len(unique_subclasses_uncased))
 


Code review comments:
diff_hunk: @@ -198,7 +198,7 @@ def quantify_difference_in_label(interface, original_output, perturbed_output):
             score = diff(original_label, perturbed_label)
         return score
 
-    elif isinstance(output_component, Textbox):
+    elif isinstance(output_component, (Textbox, Number)):
path: gradio/interpretation.py
text: @author:
I think only having Number here would be enough, because we only support Text with Textbox and Number with Number from now on.

@user1:
Makes sense. Will change.