Repository: modin-project/modin

Issue:
pd.read_csv throws error when used with parse_dates and index_col together
### System information
- **OS Platform and Distribution (e.g., Linux Ubuntu 16.04)**: Ubuntu 18.04.2 LTS
- **Modin installed from (source or binary)**: pip3 install modin
- **Modin version**: 0.4.0
- **Python version**: 3.6.5

### Describe the problem
As the title says, ValueError is thrown when using pd.read_csv with parse_dates and index_col together. 

### Source code / logs
<!-- Include any logs or source code that would be helpful to diagnose the problem. If including tracebacks, please include the full traceback. Large logs and files should be attached. Try to provide a reproducible test case that is the bare minimum necessary to generate the problem. -->
This is the line that throws an error:

`pd.read_csv(cb_filepath, names=['timestamp', 'symbol', 'high', 'low', 'open', 'close', 'spread', 'volume'], header=0, index_col=0, parse_dates=['timestamp'], encoding='utf-8')`


The csv file is formed like this:

> timestamp,symbol,high,low,open,close,spread,volume
> 2010-04-01 00:00:00,USD/JPY,93.52600,93.36100,93.51800,93.38200,0.00500,3049
> 2010-04-01 00:30:00,USD/JPY,93.47500,93.35200,93.38500,93.39100,0.00600,2251
> 2010-04-01 01:00:00,USD/JPY,93.42100,93.32600,93.39100,93.38400,0.00600,1577

Error:

> File "/home/censored/tensorflow/venv/lib/python3.6/site-packages/pandas/io/parsers.py", line 1122, in _make_engine
>     self._engine = CParserWrapper(self.f, **self.options)
>   File "/home/censored/tensorflow/venv/lib/python3.6/site-packages/pandas/io/parsers.py", line 1904, in __init__
>     self._set_noconvert_columns()
>   File "/home/censored/tensorflow/venv/lib/python3.6/site-packages/pandas/io/parsers.py", line 1973, in _set_noconvert_columns
>     _set(val)
>   File "/home/censored/tensorflow/venv/lib/python3.6/site-packages/pandas/io/parsers.py", line 1963, in _set
>     x = names.index(x)
> ValueError: 'timestamp' is not in list

[error.log](https://github.com/modin-project/modin/files/3048366/error.log)



Discussion:
Thanks for posting @eralmansouri! 

This looks like an issue with the way we are using `BytesIO` as a way to parallel read the file. This should be a pretty straightforward fix, we've had to use something similar for the Apache Arrow reader in #502. Great find, thanks!

Resolving patch:
diff --git a/modin/engines/ray/generic/io.py b/modin/engines/ray/generic/io.py
--- a/modin/engines/ray/generic/io.py
+++ b/modin/engines/ray/generic/io.py
@@ -228,6 +228,19 @@ def _read_csv_from_file_pandas_on_ray(cls, filepath, kwargs={}):
         Returns:
             DataFrame or Series constructed from CSV file.
         """
+        names = kwargs.get("names", None)
+        index_col = kwargs.get("index_col", None)
+        if names is None:
+            # For the sake of the empty df, we assume no `index_col` to get the correct
+            # column names before we build the index. Because we pass `names` in, this
+            # step has to happen without removing the `index_col` otherwise it will not
+            # be assigned correctly
+            kwargs["index_col"] = None
+            names = pandas.read_csv(
+                open_file(filepath, "rb"), **dict(kwargs, nrows=0, skipfooter=0)
+            ).columns
+            kwargs["index_col"] = index_col
+
         empty_pd_df = pandas.read_csv(
             open_file(filepath, "rb"), **dict(kwargs, nrows=0, skipfooter=0)
         )
@@ -238,7 +251,7 @@ def _read_csv_from_file_pandas_on_ray(cls, filepath, kwargs={}):
         partition_kwargs = dict(
             kwargs,
             header=None,
-            names=column_names,
+            names=names,
             skipfooter=0,
             skiprows=None,
             parse_dates=parse_dates,
@@ -288,7 +301,6 @@ def _read_csv_from_file_pandas_on_ray(cls, filepath, kwargs={}):
                 )
                 index_ids.append(partition_id[-1])
 
-        index_col = kwargs.get("index_col", None)
         if index_col is None:
             new_index = pandas.RangeIndex(sum(ray.get(index_ids)))
         else:
diff --git a/modin/engines/ray/pandas_on_ray/io.py b/modin/engines/ray/pandas_on_ray/io.py
--- a/modin/engines/ray/pandas_on_ray/io.py
+++ b/modin/engines/ray/pandas_on_ray/io.py
@@ -78,7 +78,7 @@ def _read_csv_with_offset_pandas_on_ray(
             This is used to determine the total length of the DataFrame to build a
             default Index.
     """
-    index_col = kwargs.pop("index_col", None)
+    index_col = kwargs.get("index_col", None)
     bio = open_file(fname, "rb")
     bio.seek(start)
     to_read = header + bio.read(end - start)


Test patch:
diff --git a/modin/pandas/test/data/test_time_parsing.csv b/modin/pandas/test/data/test_time_parsing.csv
new file mode 100644
--- /dev/null
+++ b/modin/pandas/test/data/test_time_parsing.csv
@@ -0,0 +1,4 @@
+timestamp,symbol,high,low,open,close,spread,volume
+2010-04-01 00:00:00,USD/JPY,93.52600,93.36100,93.51800,93.38200,0.00500,3049
+2010-04-01 00:30:00,USD/JPY,93.47500,93.35200,93.38500,93.39100,0.00600,2251
+2010-04-01 01:00:00,USD/JPY,93.42100,93.32600,93.39100,93.38400,0.00600,1577
\ No newline at end of file
diff --git a/modin/pandas/test/test_io.py b/modin/pandas/test/test_io.py
--- a/modin/pandas/test/test_io.py
+++ b/modin/pandas/test/test_io.py
@@ -528,6 +528,118 @@ def test_from_csv(make_csv_file):
         assert modin_df_equals_pandas(modin_df, pandas_df)
 
 
+def test_parse_dates_read_csv():
+    pandas_df = pandas.read_csv("modin/pandas/test/data/test_time_parsing.csv")
+    modin_df = pd.read_csv("modin/pandas/test/data/test_time_parsing.csv")
+    modin_df_equals_pandas(modin_df, pandas_df)
+
+    pandas_df = pandas.read_csv(
+        "modin/pandas/test/data/test_time_parsing.csv",
+        names=[
+            "timestamp",
+            "symbol",
+            "high",
+            "low",
+            "open",
+            "close",
+            "spread",
+            "volume",
+        ],
+        header=0,
+        index_col=0,
+        encoding="utf-8",
+    )
+    modin_df = pd.read_csv(
+        "modin/pandas/test/data/test_time_parsing.csv",
+        names=[
+            "timestamp",
+            "symbol",
+            "high",
+            "low",
+            "open",
+            "close",
+            "spread",
+            "volume",
+        ],
+        header=0,
+        index_col=0,
+        encoding="utf-8",
+    )
+    modin_df_equals_pandas(modin_df, pandas_df)
+
+    pandas_df = pandas.read_csv(
+        "modin/pandas/test/data/test_time_parsing.csv",
+        names=[
+            "timestamp",
+            "symbol",
+            "high",
+            "low",
+            "open",
+            "close",
+            "spread",
+            "volume",
+        ],
+        header=0,
+        index_col=0,
+        parse_dates=["timestamp"],
+        encoding="utf-8",
+    )
+    modin_df = pd.read_csv(
+        "modin/pandas/test/data/test_time_parsing.csv",
+        names=[
+            "timestamp",
+            "symbol",
+            "high",
+            "low",
+            "open",
+            "close",
+            "spread",
+            "volume",
+        ],
+        header=0,
+        index_col=0,
+        parse_dates=["timestamp"],
+        encoding="utf-8",
+    )
+    modin_df_equals_pandas(modin_df, pandas_df)
+
+    pandas_df = pandas.read_csv(
+        "modin/pandas/test/data/test_time_parsing.csv",
+        names=[
+            "timestamp",
+            "symbol",
+            "high",
+            "low",
+            "open",
+            "close",
+            "spread",
+            "volume",
+        ],
+        header=0,
+        index_col=2,
+        parse_dates=["timestamp"],
+        encoding="utf-8",
+    )
+    modin_df = pd.read_csv(
+        "modin/pandas/test/data/test_time_parsing.csv",
+        names=[
+            "timestamp",
+            "symbol",
+            "high",
+            "low",
+            "open",
+            "close",
+            "spread",
+            "volume",
+        ],
+        header=0,
+        index_col=2,
+        parse_dates=["timestamp"],
+        encoding="utf-8",
+    )
+    modin_df_equals_pandas(modin_df, pandas_df)
+
+
 def test_from_table(make_csv_file):
     make_csv_file(delimiter="\t")