Repository: pyjanitor-devs/pyjanitor

Issue:
[DOC] PyPI page has no project description
# Brief Description of Fix

The PyPI page for `pyjanitor` has no project description. I'm not sure if it previously did, and was lost in a recent version update. I'm not sure how to fix it, but I assume it's something that @ericmjl would be able to change. 

# Relevant Context
- [Link to PyPI page](https://pypi.org/project/pyjanitor/)



Discussion:
Turns out, this is something that can be done via PR! 

https://packaging.python.org/guides/making-a-pypi-friendly-readme/

In other words, I’m not necessarily the bottleneck here 😉. 

Of course, I would be the one who would have to upload the release in order to see whether it works or not. 

Jokes aside, I’d be happy to let this one be handled by another person if they’d like to do it, but no pressure. For someone who is looking for information, I _think_ the GitHub repository is higher-ranked on Google than the PyPI page. That said, it’d be super nice to have the PyPI page rendered nicely too :smile:.
Awesome! It's a nice chance to understand some more of the packaging process too.
What do we want to include in the PyPI description? I tested, and we could simply link the entirety of the current `README.rst` if we wanted. Or we could use a shorter description, specifically, the start of the `README.rst` (with formatting):

> pyjanitor is a Python implementation of the R package janitor, and provides a clean API for cleaning data.
> Why janitor?
> 
> Originally a port of the R package, pyjanitor has evolved from a set of convenient data cleaning routines into an experiment with the method chaining paradigm.
> 
> Data preprocessing usually consists of a series of steps that involve transforming raw data into an understandable/usable format. These series of steps need to be run in a certain sequence to achieve success. We take a base data file as the starting point, and perform actions on it, such as removing null/empty rows, replacing them with other values, adding/renaming/removing columns of data, filtering rows and others. More formally, these steps along with their relationships and dependencies are commonly referred to as a Directed Acyclic Graph (DAG).
> 
> The pandas API has been invaluable for the Python data science ecosystem, and implements method chaining of a subset of methods as part of the API. For example, resetting indexes (.reset_index()), dropping null values (.dropna()), and more, are accomplished via the appropriate pd.DataFrame method calls.
> 
> Inspired by the ease-of-use and expressiveness of the dplyr package of the R statistical language ecosystem, we have evolved pyjanitor into a language for expressing the data processing DAG for pandas users.
> 
I am leaning more towards the truncated version.


The test is temporarily at <https://test.pypi.org/project/pyjanitor/>
I have no strong opinions - let's go with what you suggested, @hectormz!

Resolving patch:
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -1,3 +1,6 @@
+import re
+from pathlib import Path
+
 from setuptools import setup
 
 
@@ -6,6 +9,36 @@ def requirements():
         return f.read()
 
 
+def generate_long_description() -> str:
+    """
+    Extra chunks from README for PyPI description.
+
+    Target chunks must be contained within `.. pypi-doc` pair comments,
+    so there must be an even number of comments in README.
+
+    :returns: Extracted description from README
+
+    """
+    # Read the contents of README file
+    this_directory = Path(__file__).parent
+    with open(this_directory / "README.rst", encoding="utf-8") as f:
+        readme = f.read()
+
+    # Find pypi-doc comments in README
+    indices = [m.start() for m in re.finditer(".. pypi-doc", readme)]
+    assert (
+        len(indices) % 2 == 0
+    ), "Odd number of `.. pypi-doc` comments in README"
+
+    # Loop through pairs of comments and save text between pairs
+    long_description = ""
+    for i in range(0, len(indices), 2):
+        start_index = indices[i] + 11
+        end_index = indices[i + 1]
+        long_description += readme[start_index:end_index]
+    return long_description
+
+
 setup(
     name="pyjanitor",
     version="0.18.0",
@@ -16,4 +49,6 @@ def requirements():
     packages=["janitor"],
     install_requires=requirements(),
     python_requires=">=3.6",
+    long_description=generate_long_description(),
+    long_description_content_type="text/x-rst",
 )


Test patch: