prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Natsort import error
  # Brief Description
  
  The module `natsort` isn't found because it was added (in #627) to dev requirements but needs to be in the main requirements file. It is imported with all functions from the init script. 
  
  Rather than requiring it, perhaps it could also be brought in with a `try`, `except` per #97 
  
  # Error Messages
  
  ```
   /usr/local/lib/python3.7/site-packages/janitor/functions.py:25: in <module>
       from natsort import index_natsorted, natsorted
   E   ModuleNotFoundError: No module named 'natsort'
  ```
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `setup.py`
  Content:
  ```
  1 import re
  2 from pathlib import Path
  3 
  4 from setuptools import setup
  5 
  6 
  7 def requirements():
  8     with open("requirements.txt", "r+") as f:
  9         return f.read()
  10 
  11 
  12 def generate_long_description() -> str:
  13     """
  14     Extra chunks from README for PyPI description.
  15 
  16     Target chunks must be contained within `.. pypi-doc` pair comments,
  17     so there must be an even number of comments in README.
  18 
  19     :returns: Extracted description from README
  20 
  21     """
  22     # Read the contents of README file
  23     this_directory = Path(__file__).parent
  24     with open(this_directory / "README.rst", encoding="utf-8") as f:
  25         readme = f.read()
  26 
  27     # Find pypi-doc comments in README
  28     indices = [m.start() for m in re.finditer(".. pypi-doc", readme)]
  29     if len(indices) % 2 != 0:
  30         raise Exception("Odd number of `.. pypi-doc` comments in README")
  31 
  32     # Loop through pairs of comments and save text between pairs
  33     long_description = ""
  34     for i in range(0, len(indices), 2):
  35         start_index = indices[i] + 11
  36         end_index = indices[i + 1]
  37         long_description += readme[start_index:end_index]
  38     return long_description
  39 
  40 
  41 extra_spark = ["pyspark"]
  42 extra_biology = ["biopython"]
  43 extra_chemistry = ["rdkit"]
  44 extra_engineering = ["unyt"]
  45 extra_all = extra_biology + extra_engineering + extra_spark
  46 
  47 setup(
  48     name="pyjanitor",
  49     version="0.20.1",
  50     description="Tools for cleaning pandas DataFrames",
  51     author="Eric J. Ma",
  52     author_email="ericmajinglong@gmail.com",
  53     url="https://github.com/ericmjl/pyjanitor",
  54     license="MIT",
  55     packages=["janitor"],
  56     install_requires=requirements(),
  57     extras_require={
  58         "all": extra_all,
  59         "biology": extra_biology,
  60         # "chemistry": extra_chemistry, should be inserted once rdkit
  61         # fixes https://github.com/rdkit/rdkit/issues/1812
  62         "engineering": extra_engineering,
  63         "spark": extra_spark,
  64     },
  65     python_requires=">=3.6",
  66     long_description=generate_long_description(),
  67     long_description_content_type="text/x-rst",
  68 )
  69
  ```
  
  Path: `janitor/__init__.py`
  Content:
  ```
  1 try:
  2     import janitor.xarray
  3 except ImportError:
  4     pass
  5 
  6 from .functions import *  # noqa: F403, F401
  7 from .math import *
  8 from .ml import get_features_targets as _get_features_targets
  9 from .utils import refactored_function
  10 
  11 # from .dataframe import JanitorDataFrame as DataFrame  # noqa: F401
  12 # from .dataframe import JanitorSeries as Series  # noqa: F401
  13 
  14 
  15 @refactored_function(
  16     "get_features_targets() has moved. Please use ml.get_features_targets()."
  17 )
  18 def get_features_targets(*args, **kwargs):
  19     return _get_features_targets(*args, **kwargs)
  20 
  21 
  22 __version__ = "0.20.1"
  23
  ```
  --- 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()
  
  ```
  
golden_diff: diff --git a/janitor/__init__.py b/janitor/__init__.py
  --- a/janitor/__init__.py
  +++ b/janitor/__init__.py
  @@ -19,4 +19,4 @@
       return _get_features_targets(*args, **kwargs)
   
   
  -__version__ = "0.20.1"
  +__version__ = "0.20.2"
  diff --git a/setup.py b/setup.py
  --- a/setup.py
  +++ b/setup.py
  @@ -46,7 +46,7 @@
   
   setup(
       name="pyjanitor",
  -    version="0.20.1",
  +    version="0.20.2",
       description="Tools for cleaning pandas DataFrames",
       author="Eric J. Ma",
       author_email="ericmajinglong@gmail.com",
  
verification_info: {"golden_diff": "diff --git a/janitor/__init__.py b/janitor/__init__.py\n--- a/janitor/__init__.py\n+++ b/janitor/__init__.py\n@@ -19,4 +19,4 @@\n     return _get_features_targets(*args, **kwargs)\n \n \n-__version__ = \"0.20.1\"\n+__version__ = \"0.20.2\"\ndiff --git a/setup.py b/setup.py\n--- a/setup.py\n+++ b/setup.py\n@@ -46,7 +46,7 @@\n \n setup(\n     name=\"pyjanitor\",\n-    version=\"0.20.1\",\n+    version=\"0.20.2\",\n     description=\"Tools for cleaning pandas DataFrames\",\n     author=\"Eric J. Ma\",\n     author_email=\"ericmajinglong@gmail.com\",\n", "issue": "Natsort import error\n# Brief Description\r\n\r\nThe module `natsort` isn't found because it was added (in #627) to dev requirements but needs to be in the main requirements file. It is imported with all functions from the init script. \r\n\r\nRather than requiring it, perhaps it could also be brought in with a `try`, `except` per #97 \r\n\r\n# Error Messages\r\n\r\n```\r\n /usr/local/lib/python3.7/site-packages/janitor/functions.py:25: in <module>\r\n     from natsort import index_natsorted, natsorted\r\n E   ModuleNotFoundError: No module named 'natsort'\r\n```\n", "before_files": [{"content": "import re\nfrom pathlib import Path\n\nfrom setuptools import setup\n\n\ndef requirements():\n    with open(\"requirements.txt\", \"r+\") as f:\n        return f.read()\n\n\ndef generate_long_description() -> str:\n    \"\"\"\n    Extra chunks from README for PyPI description.\n\n    Target chunks must be contained within `.. pypi-doc` pair comments,\n    so there must be an even number of comments in README.\n\n    :returns: Extracted description from README\n\n    \"\"\"\n    # Read the contents of README file\n    this_directory = Path(__file__).parent\n    with open(this_directory / \"README.rst\", encoding=\"utf-8\") as f:\n        readme = f.read()\n\n    # Find pypi-doc comments in README\n    indices = [m.start() for m in re.finditer(\".. pypi-doc\", readme)]\n    if len(indices) % 2 != 0:\n        raise Exception(\"Odd number of `.. pypi-doc` comments in README\")\n\n    # Loop through pairs of comments and save text between pairs\n    long_description = \"\"\n    for i in range(0, len(indices), 2):\n        start_index = indices[i] + 11\n        end_index = indices[i + 1]\n        long_description += readme[start_index:end_index]\n    return long_description\n\n\nextra_spark = [\"pyspark\"]\nextra_biology = [\"biopython\"]\nextra_chemistry = [\"rdkit\"]\nextra_engineering = [\"unyt\"]\nextra_all = extra_biology + extra_engineering + extra_spark\n\nsetup(\n    name=\"pyjanitor\",\n    version=\"0.20.1\",\n    description=\"Tools for cleaning pandas DataFrames\",\n    author=\"Eric J. Ma\",\n    author_email=\"ericmajinglong@gmail.com\",\n    url=\"https://github.com/ericmjl/pyjanitor\",\n    license=\"MIT\",\n    packages=[\"janitor\"],\n    install_requires=requirements(),\n    extras_require={\n        \"all\": extra_all,\n        \"biology\": extra_biology,\n        # \"chemistry\": extra_chemistry, should be inserted once rdkit\n        # fixes https://github.com/rdkit/rdkit/issues/1812\n        \"engineering\": extra_engineering,\n        \"spark\": extra_spark,\n    },\n    python_requires=\">=3.6\",\n    long_description=generate_long_description(),\n    long_description_content_type=\"text/x-rst\",\n)\n", "path": "setup.py"}, {"content": "try:\n    import janitor.xarray\nexcept ImportError:\n    pass\n\nfrom .functions import *  # noqa: F403, F401\nfrom .math import *\nfrom .ml import get_features_targets as _get_features_targets\nfrom .utils import refactored_function\n\n# from .dataframe import JanitorDataFrame as DataFrame  # noqa: F401\n# from .dataframe import JanitorSeries as Series  # noqa: F401\n\n\n@refactored_function(\n    \"get_features_targets() has moved. Please use ml.get_features_targets().\"\n)\ndef get_features_targets(*args, **kwargs):\n    return _get_features_targets(*args, **kwargs)\n\n\n__version__ = \"0.20.1\"\n", "path": "janitor/__init__.py"}], "after_files": [{"content": "import re\nfrom pathlib import Path\n\nfrom setuptools import setup\n\n\ndef requirements():\n    with open(\"requirements.txt\", \"r+\") as f:\n        return f.read()\n\n\ndef generate_long_description() -> str:\n    \"\"\"\n    Extra chunks from README for PyPI description.\n\n    Target chunks must be contained within `.. pypi-doc` pair comments,\n    so there must be an even number of comments in README.\n\n    :returns: Extracted description from README\n\n    \"\"\"\n    # Read the contents of README file\n    this_directory = Path(__file__).parent\n    with open(this_directory / \"README.rst\", encoding=\"utf-8\") as f:\n        readme = f.read()\n\n    # Find pypi-doc comments in README\n    indices = [m.start() for m in re.finditer(\".. pypi-doc\", readme)]\n    if len(indices) % 2 != 0:\n        raise Exception(\"Odd number of `.. pypi-doc` comments in README\")\n\n    # Loop through pairs of comments and save text between pairs\n    long_description = \"\"\n    for i in range(0, len(indices), 2):\n        start_index = indices[i] + 11\n        end_index = indices[i + 1]\n        long_description += readme[start_index:end_index]\n    return long_description\n\n\nextra_spark = [\"pyspark\"]\nextra_biology = [\"biopython\"]\nextra_chemistry = [\"rdkit\"]\nextra_engineering = [\"unyt\"]\nextra_all = extra_biology + extra_engineering + extra_spark\n\nsetup(\n    name=\"pyjanitor\",\n    version=\"0.20.2\",\n    description=\"Tools for cleaning pandas DataFrames\",\n    author=\"Eric J. Ma\",\n    author_email=\"ericmajinglong@gmail.com\",\n    url=\"https://github.com/ericmjl/pyjanitor\",\n    license=\"MIT\",\n    packages=[\"janitor\"],\n    install_requires=requirements(),\n    extras_require={\n        \"all\": extra_all,\n        \"biology\": extra_biology,\n        # \"chemistry\": extra_chemistry, should be inserted once rdkit\n        # fixes https://github.com/rdkit/rdkit/issues/1812\n        \"engineering\": extra_engineering,\n        \"spark\": extra_spark,\n    },\n    python_requires=\">=3.6\",\n    long_description=generate_long_description(),\n    long_description_content_type=\"text/x-rst\",\n)\n", "path": "setup.py"}, {"content": "try:\n    import janitor.xarray\nexcept ImportError:\n    pass\n\nfrom .functions import *  # noqa: F403, F401\nfrom .math import *\nfrom .ml import get_features_targets as _get_features_targets\nfrom .utils import refactored_function\n\n# from .dataframe import JanitorDataFrame as DataFrame  # noqa: F401\n# from .dataframe import JanitorSeries as Series  # noqa: F401\n\n\n@refactored_function(\n    \"get_features_targets() has moved. Please use ml.get_features_targets().\"\n)\ndef get_features_targets(*args, **kwargs):\n    return _get_features_targets(*args, **kwargs)\n\n\n__version__ = \"0.20.2\"\n", "path": "janitor/__init__.py"}]}