We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Drop Python 3.6
We should now drop Python 3.6 as 0.19 is out.

_Originally posted by @Cadair in https://github.com/opsdroid/opsdroid/issues/1534#issuecomment-644825884_

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `opsdroid/cli/utils.py`
Content:
```
1 """Utilities for the opsdroid CLI commands."""
2 
3 import click
4 import contextlib
5 import gettext
6 import os
7 import logging
8 import subprocess
9 import sys
10 import time
11 
12 from opsdroid.core import OpsDroid
13 from opsdroid.configuration import load_config_file
14 from opsdroid.const import (
15     LOCALE_DIR,
16     DEFAULT_LANGUAGE,
17     DEFAULT_CONFIG_PATH,
18     DEFAULT_CONFIG_LOCATIONS,
19 )
20 from opsdroid.helper import get_config_option
21 from opsdroid.loader import Loader
22 from opsdroid.logging import configure_logging
23 
24 
25 _LOGGER = logging.getLogger("opsdroid")
26 
27 path_option = click.option(
28     "-f",
29     "path",
30     help="Load a configuration from a path instead of using the default location.",
31     type=click.Path(exists=True),
32 )
33 
34 
35 def edit_config(ctx, path):
36     """Open config/log file with favourite editor.
37 
38     Args:
39         ctx (:obj:`click.Context`): The current click cli context.
40         path (str or None): the path passed to the config option.
41         value (string): the value of this parameter after invocation.
42 
43     Returns:
44         int: the exit code. Always returns 0 in this case.
45 
46     """
47     file = path or DEFAULT_CONFIG_PATH
48     editor = os.environ.get("EDITOR", "vi")
49 
50     if editor == "vi":
51         click.echo(
52             "You are about to edit a file in vim. \n"
53             "Read the tutorial on vim at: https://bit.ly/2HRvvrB"
54         )
55         time.sleep(1.5)
56 
57     subprocess.run([editor, file])
58     ctx.exit(0)
59 
60 
61 def validate_config(ctx, path):
62     """Validate opsdroid configuration.
63 
64     We load the configuration and modules from it to run the validation on them.
65     Only modules that contain the constant variable `CONFIG_SCHEMA` will be validated
66     the ones without it will just be silent.
67 
68     Note that if the path doesn't exist or is a bad one click will throw an error telling
69     you that the path doesn't exist. Also, the file needs to be either a json or a yaml file.
70 
71 
72     Args:
73         ctx (:obj:`click.Context`): The current click cli context.
74         path (string): a string representing the path to load the config,
75             obtained from `ctx.obj`.
76         value (string): the value of this parameter after invocation.
77             It is either "config" or "log" depending on the program
78             calling this function.
79 
80     Returns:
81         int: the exit code. Always returns 0 in this case.
82 
83     """
84     with OpsDroid() as opsdroid:
85         loader = Loader(opsdroid)
86 
87         config = load_config_file([path] if path else DEFAULT_CONFIG_LOCATIONS)
88 
89         loader.load_modules_from_config(config)
90         click.echo("Configuration validated - No errors founds!")
91 
92         ctx.exit(0)
93 
94 
95 def configure_lang(config):
96     """Configure app language based on user config.
97 
98     Args:
99         config: Language Configuration and it uses ISO 639-1 code.
100         for more info https://en.m.wikipedia.org/wiki/List_of_ISO_639-1_codes
101 
102 
103     """
104     lang_code = config.get("lang", DEFAULT_LANGUAGE)
105     if lang_code != DEFAULT_LANGUAGE:
106         lang = gettext.translation("opsdroid", LOCALE_DIR, (lang_code,), fallback=True)
107         lang.install()
108 
109 
110 def check_dependencies():
111     """Check for system dependencies required by opsdroid.
112 
113     Returns:
114         int: the exit code. Returns 1 if the Python version installed is
115         below 3.6.
116 
117     """
118     if sys.version_info.major < 3 or sys.version_info.minor < 6:
119         logging.critical(_("Whoops! opsdroid requires python 3.6 or above."))
120         sys.exit(1)
121 
122 
123 def welcome_message(config):
124     """Add welcome message if set to true in configuration.
125 
126     Args:
127         config: config loaded by Loader
128 
129     Raises:
130         KeyError: If 'welcome-message' key is not found in configuration file
131 
132     """
133     try:
134         if config["welcome-message"]:
135             _LOGGER.info("=" * 40)
136             _LOGGER.info(
137                 _(
138                     "You can customise your opsdroid by modifying your configuration.yaml."
139                 )
140             )
141             _LOGGER.info(
142                 _("Read more at: http://opsdroid.readthedocs.io/#configuration")
143             )
144             _LOGGER.info(_("Watch the Get Started Videos at: http://bit.ly/2fnC0Fh"))
145             _LOGGER.info(
146                 _(
147                     "Install Opsdroid Desktop at: \n"
148                     "https://github.com/opsdroid/opsdroid-desktop/releases"
149                 )
150             )
151             _LOGGER.info("=" * 40)
152     except KeyError:
153         _LOGGER.warning(
154             _("'welcome-message: true/false' is missing in configuration.yaml")
155         )
156 
157 
158 def list_all_modules(ctx, path):
159     """List the active modules from config.
160 
161     This function will try to get information from the modules that are active in the
162     configuration file and print them as a table or will just print a sentence saying that
163     there are no active modules for that type.
164 
165     Args:
166         ctx (:obj:`click.Context`): The current click cli context.
167         path (str): a str that contains a path passed.
168 
169     Returns:
170         int: the exit code. Always returns 0 in this case.
171 
172     """
173     config = load_config_file([path] if path else DEFAULT_CONFIG_LOCATIONS)
174 
175     click.echo(
176         click.style(
177             f"{'NAME':15} {'TYPE':15} {'MODE':15} {'CACHED':15}  {'LOCATION':15}",
178             fg="blue",
179             bold=True,
180         )
181     )
182     for module_type, module in config.items():
183         if module_type in ("connectors", "databases", "parsers", "skills"):
184             for name, options in module.items():
185 
186                 mode = get_config_option(
187                     ["repo", "path", "gist"], options, True, "module"
188                 )
189                 cache = get_config_option(["no-cache"], options, "no", "yes")
190                 location = get_config_option(
191                     ["repo", "path", "gist"],
192                     options,
193                     True,
194                     f"opsdroid.{module_type}.{name}",
195                 )
196 
197                 click.echo(
198                     f"{name:15} {module_type:15} {mode[1]:15} {cache[0]:15}  {location[2]:15}"
199                 )
200 
201     ctx.exit(0)
202 
203 
204 def build_config(ctx, params):
205     """Load configuration, load modules and install dependencies.
206 
207     This function loads the configuration and install all necessary
208     dependencies defined on a `requirements.txt` file inside the module.
209     If the flag `--verbose` is passed the logging level will be set as debug and
210     all logs will be shown to the user.
211 
212 
213     Args:
214         ctx (:obj:`click.Context`): The current click cli context.
215         params (dict): a dictionary of all parameters pass to the click
216             context when invoking this function as a callback.
217 
218     Returns:
219         int: the exit code. Always returns 0 in this case.
220 
221     """
222     click.echo("Opsdroid will build modules from config.")
223     path = params.get("path")
224 
225     with contextlib.suppress(Exception):
226         check_dependencies()
227 
228         config = load_config_file([path] if path else DEFAULT_CONFIG_LOCATIONS)
229 
230         if params["verbose"]:
231             config["logging"] = {"level": "debug"}
232             configure_logging(config)
233 
234         with OpsDroid(config=config) as opsdroid:
235 
236             opsdroid.loader.load_modules_from_config(config)
237 
238             click.echo(click.style("SUCCESS:", bg="green", bold=True), nl=False)
239             click.echo(" Opsdroid modules successfully built from config.")
240
```

Path: `setup.py`
Content:
```
1 #!/usr/bin/env python3
2 import os
3 from setuptools import setup, find_packages
4 from setuptools.command.build_py import build_py
5 from setuptools.command.sdist import sdist
6 from setuptools.command.develop import develop
7 import versioneer
8 
9 PACKAGE_NAME = "opsdroid"
10 HERE = os.path.abspath(os.path.dirname(__file__))
11 README = open(os.path.join(HERE, "README.md"), encoding="utf8").read()
12 
13 PACKAGES = find_packages(
14     exclude=["tests", "tests.*", "modules", "modules.*", "docs", "docs.*"]
15 )
16 
17 
18 # For now we simply define the install_requires based on the contents
19 # of requirements.txt. In the future, install_requires may become much
20 # looser than the (automatically) resolved requirements.txt.
21 with open(os.path.join(HERE, "requirements.txt"), "r") as fh:
22     REQUIRES = [line.strip() for line in fh]
23 
24 
25 class Develop(develop):
26     """Custom `develop` command to always build mo files on install -e."""
27 
28     def run(self):
29         self.run_command("compile_catalog")
30         develop.run(self)  # old style class
31 
32 
33 class BuildPy(build_py):
34     """Custom `build_py` command to always build mo files for wheels."""
35 
36     def run(self):
37         self.run_command("compile_catalog")
38         build_py.run(self)  # old style class
39 
40 
41 class Sdist(sdist):
42     """Custom `sdist` command to ensure that mo files are always created."""
43 
44     def run(self):
45         self.run_command("compile_catalog")
46         sdist.run(self)  # old style class
47 
48 
49 setup(
50     name=PACKAGE_NAME,
51     version=versioneer.get_version(),
52     license="Apache License 2.0",
53     url="https://opsdroid.github.io/",
54     download_url="https://github.com/opsdroid/opsdroid/releases",
55     author="Jacob Tomlinson",
56     author_email="jacob@tom.linson.uk",
57     description="An open source ChatOps bot framework.",
58     long_description=README,
59     long_description_content_type="text/markdown",
60     packages=PACKAGES,
61     include_package_data=True,
62     zip_safe=False,
63     platforms="any",
64     classifiers=[
65         "Development Status :: 4 - Beta",
66         "Environment :: Console",
67         "Framework :: AsyncIO",
68         "Intended Audience :: Developers",
69         "Intended Audience :: System Administrators",
70         "Intended Audience :: Information Technology",
71         "License :: OSI Approved :: Apache Software License",
72         "Programming Language :: Python",
73         "Programming Language :: Python :: 3",
74         "Programming Language :: Python :: 3 :: Only",
75         "Programming Language :: Python :: 3.6",
76         "Programming Language :: Python :: 3.7",
77         "Programming Language :: Python :: 3.8",
78         "Topic :: Communications :: Chat",
79         "Topic :: Scientific/Engineering :: Artificial Intelligence",
80         "Topic :: Software Development :: Libraries :: Python Modules",
81     ],
82     install_requires=REQUIRES,
83     test_suite="tests",
84     keywords=[
85         "bot",
86         "bot-framework",
87         "opsdroid",
88         "botkit",
89         "python3",
90         "asyncio",
91         "chatops",
92         "devops",
93         "nlu",
94     ],
95     setup_requires=["Babel"],
96     cmdclass=versioneer.get_cmdclass(
97         {"sdist": Sdist, "build_py": BuildPy, "develop": Develop}
98     ),
99     entry_points={"console_scripts": ["opsdroid = opsdroid.cli:cli"]},
100 )
101
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/opsdroid/cli/utils.py b/opsdroid/cli/utils.py
--- a/opsdroid/cli/utils.py
+++ b/opsdroid/cli/utils.py
@@ -112,11 +112,11 @@
 
     Returns:
         int: the exit code. Returns 1 if the Python version installed is
-        below 3.6.
+        below 3.7.
 
     """
-    if sys.version_info.major < 3 or sys.version_info.minor < 6:
-        logging.critical(_("Whoops! opsdroid requires python 3.6 or above."))
+    if sys.version_info.major < 3 or sys.version_info.minor < 7:
+        logging.critical(_("Whoops! opsdroid requires python 3.7 or above."))
         sys.exit(1)
 
 
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -72,7 +72,6 @@
         "Programming Language :: Python",
         "Programming Language :: Python :: 3",
         "Programming Language :: Python :: 3 :: Only",
-        "Programming Language :: Python :: 3.6",
         "Programming Language :: Python :: 3.7",
         "Programming Language :: Python :: 3.8",
         "Topic :: Communications :: Chat",

{"golden_diff": "diff --git a/opsdroid/cli/utils.py b/opsdroid/cli/utils.py\n--- a/opsdroid/cli/utils.py\n+++ b/opsdroid/cli/utils.py\n@@ -112,11 +112,11 @@\n \n     Returns:\n         int: the exit code. Returns 1 if the Python version installed is\n-        below 3.6.\n+        below 3.7.\n \n     \"\"\"\n-    if sys.version_info.major < 3 or sys.version_info.minor < 6:\n-        logging.critical(_(\"Whoops! opsdroid requires python 3.6 or above.\"))\n+    if sys.version_info.major < 3 or sys.version_info.minor < 7:\n+        logging.critical(_(\"Whoops! opsdroid requires python 3.7 or above.\"))\n         sys.exit(1)\n \n \ndiff --git a/setup.py b/setup.py\n--- a/setup.py\n+++ b/setup.py\n@@ -72,7 +72,6 @@\n         \"Programming Language :: Python\",\n         \"Programming Language :: Python :: 3\",\n         \"Programming Language :: Python :: 3 :: Only\",\n-        \"Programming Language :: Python :: 3.6\",\n         \"Programming Language :: Python :: 3.7\",\n         \"Programming Language :: Python :: 3.8\",\n         \"Topic :: Communications :: Chat\",\n", "issue": "Drop Python 3.6\nWe should now drop Python 3.6 as 0.19 is out.\r\n\r\n_Originally posted by @Cadair in https://github.com/opsdroid/opsdroid/issues/1534#issuecomment-644825884_\n", "before_files": [{"content": "\"\"\"Utilities for the opsdroid CLI commands.\"\"\"\n\nimport click\nimport contextlib\nimport gettext\nimport os\nimport logging\nimport subprocess\nimport sys\nimport time\n\nfrom opsdroid.core import OpsDroid\nfrom opsdroid.configuration import load_config_file\nfrom opsdroid.const import (\n    LOCALE_DIR,\n    DEFAULT_LANGUAGE,\n    DEFAULT_CONFIG_PATH,\n    DEFAULT_CONFIG_LOCATIONS,\n)\nfrom opsdroid.helper import get_config_option\nfrom opsdroid.loader import Loader\nfrom opsdroid.logging import configure_logging\n\n\n_LOGGER = logging.getLogger(\"opsdroid\")\n\npath_option = click.option(\n    \"-f\",\n    \"path\",\n    help=\"Load a configuration from a path instead of using the default location.\",\n    type=click.Path(exists=True),\n)\n\n\ndef edit_config(ctx, path):\n    \"\"\"Open config/log file with favourite editor.\n\n    Args:\n        ctx (:obj:`click.Context`): The current click cli context.\n        path (str or None): the path passed to the config option.\n        value (string): the value of this parameter after invocation.\n\n    Returns:\n        int: the exit code. Always returns 0 in this case.\n\n    \"\"\"\n    file = path or DEFAULT_CONFIG_PATH\n    editor = os.environ.get(\"EDITOR\", \"vi\")\n\n    if editor == \"vi\":\n        click.echo(\n            \"You are about to edit a file in vim. \\n\"\n            \"Read the tutorial on vim at: https://bit.ly/2HRvvrB\"\n        )\n        time.sleep(1.5)\n\n    subprocess.run([editor, file])\n    ctx.exit(0)\n\n\ndef validate_config(ctx, path):\n    \"\"\"Validate opsdroid configuration.\n\n    We load the configuration and modules from it to run the validation on them.\n    Only modules that contain the constant variable `CONFIG_SCHEMA` will be validated\n    the ones without it will just be silent.\n\n    Note that if the path doesn't exist or is a bad one click will throw an error telling\n    you that the path doesn't exist. Also, the file needs to be either a json or a yaml file.\n\n\n    Args:\n        ctx (:obj:`click.Context`): The current click cli context.\n        path (string): a string representing the path to load the config,\n            obtained from `ctx.obj`.\n        value (string): the value of this parameter after invocation.\n            It is either \"config\" or \"log\" depending on the program\n            calling this function.\n\n    Returns:\n        int: the exit code. Always returns 0 in this case.\n\n    \"\"\"\n    with OpsDroid() as opsdroid:\n        loader = Loader(opsdroid)\n\n        config = load_config_file([path] if path else DEFAULT_CONFIG_LOCATIONS)\n\n        loader.load_modules_from_config(config)\n        click.echo(\"Configuration validated - No errors founds!\")\n\n        ctx.exit(0)\n\n\ndef configure_lang(config):\n    \"\"\"Configure app language based on user config.\n\n    Args:\n        config: Language Configuration and it uses ISO 639-1 code.\n        for more info https://en.m.wikipedia.org/wiki/List_of_ISO_639-1_codes\n\n\n    \"\"\"\n    lang_code = config.get(\"lang\", DEFAULT_LANGUAGE)\n    if lang_code != DEFAULT_LANGUAGE:\n        lang = gettext.translation(\"opsdroid\", LOCALE_DIR, (lang_code,), fallback=True)\n        lang.install()\n\n\ndef check_dependencies():\n    \"\"\"Check for system dependencies required by opsdroid.\n\n    Returns:\n        int: the exit code. Returns 1 if the Python version installed is\n        below 3.6.\n\n    \"\"\"\n    if sys.version_info.major < 3 or sys.version_info.minor < 6:\n        logging.critical(_(\"Whoops! opsdroid requires python 3.6 or above.\"))\n        sys.exit(1)\n\n\ndef welcome_message(config):\n    \"\"\"Add welcome message if set to true in configuration.\n\n    Args:\n        config: config loaded by Loader\n\n    Raises:\n        KeyError: If 'welcome-message' key is not found in configuration file\n\n    \"\"\"\n    try:\n        if config[\"welcome-message\"]:\n            _LOGGER.info(\"=\" * 40)\n            _LOGGER.info(\n                _(\n                    \"You can customise your opsdroid by modifying your configuration.yaml.\"\n                )\n            )\n            _LOGGER.info(\n                _(\"Read more at: http://opsdroid.readthedocs.io/#configuration\")\n            )\n            _LOGGER.info(_(\"Watch the Get Started Videos at: http://bit.ly/2fnC0Fh\"))\n            _LOGGER.info(\n                _(\n                    \"Install Opsdroid Desktop at: \\n\"\n                    \"https://github.com/opsdroid/opsdroid-desktop/releases\"\n                )\n            )\n            _LOGGER.info(\"=\" * 40)\n    except KeyError:\n        _LOGGER.warning(\n            _(\"'welcome-message: true/false' is missing in configuration.yaml\")\n        )\n\n\ndef list_all_modules(ctx, path):\n    \"\"\"List the active modules from config.\n\n    This function will try to get information from the modules that are active in the\n    configuration file and print them as a table or will just print a sentence saying that\n    there are no active modules for that type.\n\n    Args:\n        ctx (:obj:`click.Context`): The current click cli context.\n        path (str): a str that contains a path passed.\n\n    Returns:\n        int: the exit code. Always returns 0 in this case.\n\n    \"\"\"\n    config = load_config_file([path] if path else DEFAULT_CONFIG_LOCATIONS)\n\n    click.echo(\n        click.style(\n            f\"{'NAME':15} {'TYPE':15} {'MODE':15} {'CACHED':15}  {'LOCATION':15}\",\n            fg=\"blue\",\n            bold=True,\n        )\n    )\n    for module_type, module in config.items():\n        if module_type in (\"connectors\", \"databases\", \"parsers\", \"skills\"):\n            for name, options in module.items():\n\n                mode = get_config_option(\n                    [\"repo\", \"path\", \"gist\"], options, True, \"module\"\n                )\n                cache = get_config_option([\"no-cache\"], options, \"no\", \"yes\")\n                location = get_config_option(\n                    [\"repo\", \"path\", \"gist\"],\n                    options,\n                    True,\n                    f\"opsdroid.{module_type}.{name}\",\n                )\n\n                click.echo(\n                    f\"{name:15} {module_type:15} {mode[1]:15} {cache[0]:15}  {location[2]:15}\"\n                )\n\n    ctx.exit(0)\n\n\ndef build_config(ctx, params):\n    \"\"\"Load configuration, load modules and install dependencies.\n\n    This function loads the configuration and install all necessary\n    dependencies defined on a `requirements.txt` file inside the module.\n    If the flag `--verbose` is passed the logging level will be set as debug and\n    all logs will be shown to the user.\n\n\n    Args:\n        ctx (:obj:`click.Context`): The current click cli context.\n        params (dict): a dictionary of all parameters pass to the click\n            context when invoking this function as a callback.\n\n    Returns:\n        int: the exit code. Always returns 0 in this case.\n\n    \"\"\"\n    click.echo(\"Opsdroid will build modules from config.\")\n    path = params.get(\"path\")\n\n    with contextlib.suppress(Exception):\n        check_dependencies()\n\n        config = load_config_file([path] if path else DEFAULT_CONFIG_LOCATIONS)\n\n        if params[\"verbose\"]:\n            config[\"logging\"] = {\"level\": \"debug\"}\n            configure_logging(config)\n\n        with OpsDroid(config=config) as opsdroid:\n\n            opsdroid.loader.load_modules_from_config(config)\n\n            click.echo(click.style(\"SUCCESS:\", bg=\"green\", bold=True), nl=False)\n            click.echo(\" Opsdroid modules successfully built from config.\")\n", "path": "opsdroid/cli/utils.py"}, {"content": "#!/usr/bin/env python3\nimport os\nfrom setuptools import setup, find_packages\nfrom setuptools.command.build_py import build_py\nfrom setuptools.command.sdist import sdist\nfrom setuptools.command.develop import develop\nimport versioneer\n\nPACKAGE_NAME = \"opsdroid\"\nHERE = os.path.abspath(os.path.dirname(__file__))\nREADME = open(os.path.join(HERE, \"README.md\"), encoding=\"utf8\").read()\n\nPACKAGES = find_packages(\n    exclude=[\"tests\", \"tests.*\", \"modules\", \"modules.*\", \"docs\", \"docs.*\"]\n)\n\n\n# For now we simply define the install_requires based on the contents\n# of requirements.txt. In the future, install_requires may become much\n# looser than the (automatically) resolved requirements.txt.\nwith open(os.path.join(HERE, \"requirements.txt\"), \"r\") as fh:\n    REQUIRES = [line.strip() for line in fh]\n\n\nclass Develop(develop):\n    \"\"\"Custom `develop` command to always build mo files on install -e.\"\"\"\n\n    def run(self):\n        self.run_command(\"compile_catalog\")\n        develop.run(self)  # old style class\n\n\nclass BuildPy(build_py):\n    \"\"\"Custom `build_py` command to always build mo files for wheels.\"\"\"\n\n    def run(self):\n        self.run_command(\"compile_catalog\")\n        build_py.run(self)  # old style class\n\n\nclass Sdist(sdist):\n    \"\"\"Custom `sdist` command to ensure that mo files are always created.\"\"\"\n\n    def run(self):\n        self.run_command(\"compile_catalog\")\n        sdist.run(self)  # old style class\n\n\nsetup(\n    name=PACKAGE_NAME,\n    version=versioneer.get_version(),\n    license=\"Apache License 2.0\",\n    url=\"https://opsdroid.github.io/\",\n    download_url=\"https://github.com/opsdroid/opsdroid/releases\",\n    author=\"Jacob Tomlinson\",\n    author_email=\"jacob@tom.linson.uk\",\n    description=\"An open source ChatOps bot framework.\",\n    long_description=README,\n    long_description_content_type=\"text/markdown\",\n    packages=PACKAGES,\n    include_package_data=True,\n    zip_safe=False,\n    platforms=\"any\",\n    classifiers=[\n        \"Development Status :: 4 - Beta\",\n        \"Environment :: Console\",\n        \"Framework :: AsyncIO\",\n        \"Intended Audience :: Developers\",\n        \"Intended Audience :: System Administrators\",\n        \"Intended Audience :: Information Technology\",\n        \"License :: OSI Approved :: Apache Software License\",\n        \"Programming Language :: Python\",\n        \"Programming Language :: Python :: 3\",\n        \"Programming Language :: Python :: 3 :: Only\",\n        \"Programming Language :: Python :: 3.6\",\n        \"Programming Language :: Python :: 3.7\",\n        \"Programming Language :: Python :: 3.8\",\n        \"Topic :: Communications :: Chat\",\n        \"Topic :: Scientific/Engineering :: Artificial Intelligence\",\n        \"Topic :: Software Development :: Libraries :: Python Modules\",\n    ],\n    install_requires=REQUIRES,\n    test_suite=\"tests\",\n    keywords=[\n        \"bot\",\n        \"bot-framework\",\n        \"opsdroid\",\n        \"botkit\",\n        \"python3\",\n        \"asyncio\",\n        \"chatops\",\n        \"devops\",\n        \"nlu\",\n    ],\n    setup_requires=[\"Babel\"],\n    cmdclass=versioneer.get_cmdclass(\n        {\"sdist\": Sdist, \"build_py\": BuildPy, \"develop\": Develop}\n    ),\n    entry_points={\"console_scripts\": [\"opsdroid = opsdroid.cli:cli\"]},\n)\n", "path": "setup.py"}], "after_files": [{"content": "\"\"\"Utilities for the opsdroid CLI commands.\"\"\"\n\nimport click\nimport contextlib\nimport gettext\nimport os\nimport logging\nimport subprocess\nimport sys\nimport time\n\nfrom opsdroid.core import OpsDroid\nfrom opsdroid.configuration import load_config_file\nfrom opsdroid.const import (\n    LOCALE_DIR,\n    DEFAULT_LANGUAGE,\n    DEFAULT_CONFIG_PATH,\n    DEFAULT_CONFIG_LOCATIONS,\n)\nfrom opsdroid.helper import get_config_option\nfrom opsdroid.loader import Loader\nfrom opsdroid.logging import configure_logging\n\n\n_LOGGER = logging.getLogger(\"opsdroid\")\n\npath_option = click.option(\n    \"-f\",\n    \"path\",\n    help=\"Load a configuration from a path instead of using the default location.\",\n    type=click.Path(exists=True),\n)\n\n\ndef edit_config(ctx, path):\n    \"\"\"Open config/log file with favourite editor.\n\n    Args:\n        ctx (:obj:`click.Context`): The current click cli context.\n        path (str or None): the path passed to the config option.\n        value (string): the value of this parameter after invocation.\n\n    Returns:\n        int: the exit code. Always returns 0 in this case.\n\n    \"\"\"\n    file = path or DEFAULT_CONFIG_PATH\n    editor = os.environ.get(\"EDITOR\", \"vi\")\n\n    if editor == \"vi\":\n        click.echo(\n            \"You are about to edit a file in vim. \\n\"\n            \"Read the tutorial on vim at: https://bit.ly/2HRvvrB\"\n        )\n        time.sleep(1.5)\n\n    subprocess.run([editor, file])\n    ctx.exit(0)\n\n\ndef validate_config(ctx, path):\n    \"\"\"Validate opsdroid configuration.\n\n    We load the configuration and modules from it to run the validation on them.\n    Only modules that contain the constant variable `CONFIG_SCHEMA` will be validated\n    the ones without it will just be silent.\n\n    Note that if the path doesn't exist or is a bad one click will throw an error telling\n    you that the path doesn't exist. Also, the file needs to be either a json or a yaml file.\n\n\n    Args:\n        ctx (:obj:`click.Context`): The current click cli context.\n        path (string): a string representing the path to load the config,\n            obtained from `ctx.obj`.\n        value (string): the value of this parameter after invocation.\n            It is either \"config\" or \"log\" depending on the program\n            calling this function.\n\n    Returns:\n        int: the exit code. Always returns 0 in this case.\n\n    \"\"\"\n    with OpsDroid() as opsdroid:\n        loader = Loader(opsdroid)\n\n        config = load_config_file([path] if path else DEFAULT_CONFIG_LOCATIONS)\n\n        loader.load_modules_from_config(config)\n        click.echo(\"Configuration validated - No errors founds!\")\n\n        ctx.exit(0)\n\n\ndef configure_lang(config):\n    \"\"\"Configure app language based on user config.\n\n    Args:\n        config: Language Configuration and it uses ISO 639-1 code.\n        for more info https://en.m.wikipedia.org/wiki/List_of_ISO_639-1_codes\n\n\n    \"\"\"\n    lang_code = config.get(\"lang\", DEFAULT_LANGUAGE)\n    if lang_code != DEFAULT_LANGUAGE:\n        lang = gettext.translation(\"opsdroid\", LOCALE_DIR, (lang_code,), fallback=True)\n        lang.install()\n\n\ndef check_dependencies():\n    \"\"\"Check for system dependencies required by opsdroid.\n\n    Returns:\n        int: the exit code. Returns 1 if the Python version installed is\n        below 3.7.\n\n    \"\"\"\n    if sys.version_info.major < 3 or sys.version_info.minor < 7:\n        logging.critical(_(\"Whoops! opsdroid requires python 3.7 or above.\"))\n        sys.exit(1)\n\n\ndef welcome_message(config):\n    \"\"\"Add welcome message if set to true in configuration.\n\n    Args:\n        config: config loaded by Loader\n\n    Raises:\n        KeyError: If 'welcome-message' key is not found in configuration file\n\n    \"\"\"\n    try:\n        if config[\"welcome-message\"]:\n            _LOGGER.info(\"=\" * 40)\n            _LOGGER.info(\n                _(\n                    \"You can customise your opsdroid by modifying your configuration.yaml.\"\n                )\n            )\n            _LOGGER.info(\n                _(\"Read more at: http://opsdroid.readthedocs.io/#configuration\")\n            )\n            _LOGGER.info(_(\"Watch the Get Started Videos at: http://bit.ly/2fnC0Fh\"))\n            _LOGGER.info(\n                _(\n                    \"Install Opsdroid Desktop at: \\n\"\n                    \"https://github.com/opsdroid/opsdroid-desktop/releases\"\n                )\n            )\n            _LOGGER.info(\"=\" * 40)\n    except KeyError:\n        _LOGGER.warning(\n            _(\"'welcome-message: true/false' is missing in configuration.yaml\")\n        )\n\n\ndef list_all_modules(ctx, path):\n    \"\"\"List the active modules from config.\n\n    This function will try to get information from the modules that are active in the\n    configuration file and print them as a table or will just print a sentence saying that\n    there are no active modules for that type.\n\n    Args:\n        ctx (:obj:`click.Context`): The current click cli context.\n        path (str): a str that contains a path passed.\n\n    Returns:\n        int: the exit code. Always returns 0 in this case.\n\n    \"\"\"\n    config = load_config_file([path] if path else DEFAULT_CONFIG_LOCATIONS)\n\n    click.echo(\n        click.style(\n            f\"{'NAME':15} {'TYPE':15} {'MODE':15} {'CACHED':15}  {'LOCATION':15}\",\n            fg=\"blue\",\n            bold=True,\n        )\n    )\n    for module_type, module in config.items():\n        if module_type in (\"connectors\", \"databases\", \"parsers\", \"skills\"):\n            for name, options in module.items():\n\n                mode = get_config_option(\n                    [\"repo\", \"path\", \"gist\"], options, True, \"module\"\n                )\n                cache = get_config_option([\"no-cache\"], options, \"no\", \"yes\")\n                location = get_config_option(\n                    [\"repo\", \"path\", \"gist\"],\n                    options,\n                    True,\n                    f\"opsdroid.{module_type}.{name}\",\n                )\n\n                click.echo(\n                    f\"{name:15} {module_type:15} {mode[1]:15} {cache[0]:15}  {location[2]:15}\"\n                )\n\n    ctx.exit(0)\n\n\ndef build_config(ctx, params):\n    \"\"\"Load configuration, load modules and install dependencies.\n\n    This function loads the configuration and install all necessary\n    dependencies defined on a `requirements.txt` file inside the module.\n    If the flag `--verbose` is passed the logging level will be set as debug and\n    all logs will be shown to the user.\n\n\n    Args:\n        ctx (:obj:`click.Context`): The current click cli context.\n        params (dict): a dictionary of all parameters pass to the click\n            context when invoking this function as a callback.\n\n    Returns:\n        int: the exit code. Always returns 0 in this case.\n\n    \"\"\"\n    click.echo(\"Opsdroid will build modules from config.\")\n    path = params.get(\"path\")\n\n    with contextlib.suppress(Exception):\n        check_dependencies()\n\n        config = load_config_file([path] if path else DEFAULT_CONFIG_LOCATIONS)\n\n        if params[\"verbose\"]:\n            config[\"logging\"] = {\"level\": \"debug\"}\n            configure_logging(config)\n\n        with OpsDroid(config=config) as opsdroid:\n\n            opsdroid.loader.load_modules_from_config(config)\n\n            click.echo(click.style(\"SUCCESS:\", bg=\"green\", bold=True), nl=False)\n            click.echo(\" Opsdroid modules successfully built from config.\")\n", "path": "opsdroid/cli/utils.py"}, {"content": "#!/usr/bin/env python3\nimport os\nfrom setuptools import setup, find_packages\nfrom setuptools.command.build_py import build_py\nfrom setuptools.command.sdist import sdist\nfrom setuptools.command.develop import develop\nimport versioneer\n\nPACKAGE_NAME = \"opsdroid\"\nHERE = os.path.abspath(os.path.dirname(__file__))\nREADME = open(os.path.join(HERE, \"README.md\"), encoding=\"utf8\").read()\n\nPACKAGES = find_packages(\n    exclude=[\"tests\", \"tests.*\", \"modules\", \"modules.*\", \"docs\", \"docs.*\"]\n)\n\n\n# For now we simply define the install_requires based on the contents\n# of requirements.txt. In the future, install_requires may become much\n# looser than the (automatically) resolved requirements.txt.\nwith open(os.path.join(HERE, \"requirements.txt\"), \"r\") as fh:\n    REQUIRES = [line.strip() for line in fh]\n\n\nclass Develop(develop):\n    \"\"\"Custom `develop` command to always build mo files on install -e.\"\"\"\n\n    def run(self):\n        self.run_command(\"compile_catalog\")\n        develop.run(self)  # old style class\n\n\nclass BuildPy(build_py):\n    \"\"\"Custom `build_py` command to always build mo files for wheels.\"\"\"\n\n    def run(self):\n        self.run_command(\"compile_catalog\")\n        build_py.run(self)  # old style class\n\n\nclass Sdist(sdist):\n    \"\"\"Custom `sdist` command to ensure that mo files are always created.\"\"\"\n\n    def run(self):\n        self.run_command(\"compile_catalog\")\n        sdist.run(self)  # old style class\n\n\nsetup(\n    name=PACKAGE_NAME,\n    version=versioneer.get_version(),\n    license=\"Apache License 2.0\",\n    url=\"https://opsdroid.github.io/\",\n    download_url=\"https://github.com/opsdroid/opsdroid/releases\",\n    author=\"Jacob Tomlinson\",\n    author_email=\"jacob@tom.linson.uk\",\n    description=\"An open source ChatOps bot framework.\",\n    long_description=README,\n    long_description_content_type=\"text/markdown\",\n    packages=PACKAGES,\n    include_package_data=True,\n    zip_safe=False,\n    platforms=\"any\",\n    classifiers=[\n        \"Development Status :: 4 - Beta\",\n        \"Environment :: Console\",\n        \"Framework :: AsyncIO\",\n        \"Intended Audience :: Developers\",\n        \"Intended Audience :: System Administrators\",\n        \"Intended Audience :: Information Technology\",\n        \"License :: OSI Approved :: Apache Software License\",\n        \"Programming Language :: Python\",\n        \"Programming Language :: Python :: 3\",\n        \"Programming Language :: Python :: 3 :: Only\",\n        \"Programming Language :: Python :: 3.7\",\n        \"Programming Language :: Python :: 3.8\",\n        \"Topic :: Communications :: Chat\",\n        \"Topic :: Scientific/Engineering :: Artificial Intelligence\",\n        \"Topic :: Software Development :: Libraries :: Python Modules\",\n    ],\n    install_requires=REQUIRES,\n    test_suite=\"tests\",\n    keywords=[\n        \"bot\",\n        \"bot-framework\",\n        \"opsdroid\",\n        \"botkit\",\n        \"python3\",\n        \"asyncio\",\n        \"chatops\",\n        \"devops\",\n        \"nlu\",\n    ],\n    setup_requires=[\"Babel\"],\n    cmdclass=versioneer.get_cmdclass(\n        {\"sdist\": Sdist, \"build_py\": BuildPy, \"develop\": Develop}\n    ),\n    entry_points={\"console_scripts\": [\"opsdroid = opsdroid.cli:cli\"]},\n)\n", "path": "setup.py"}]}