Repository: modin-project/modin

Issue:
`read_csv` fails with `skiprows` and `header` parameters passed
### System information
- **OS Platform and Distribution (e.g., Linux Ubuntu 16.04)**: Any
- **Modin version** (`modin.__version__`): 203b9a59d2be1622241c2e0eaa949a42dc0f99d8
- **Python version**: 3.8.10
- **Code we can use to reproduce**:
```
import os
import modin.pandas as pd
from modin.config import NPartitions
from modin.pandas.test.utils import df_equals
import pandas

NPartitions.put(4)

test_filename = "test.csv"
data = """col1,col2
1,2
3,4
5,6
"""

skiprows = [2]

try :
    with open(test_filename, "w") as f:
        f.write(data)
    
    df_pandas = pandas.read_csv(test_filename, skiprows=[0, 2], header=0)
    df_pd = pd.read_csv(test_filename, skiprows=[0, 2], header=0)

    df_equals(df_pd, df_pandas)

finally:
    os.remove(test_filename)
```

<!--
You can obtain the Modin version with

python -c "import modin; print(modin.__version__)"
-->

### Describe the problem
<!-- Describe the problem clearly here. -->
Errors occurs if `skiprows` and `header` parameters have intersections.

### 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. -->
```
AssertionError: DataFrame.iloc[:, 0] (column name="1") are different

DataFrame.iloc[:, 0] (column name="1") values are different (100.0 %)
[index]: [0]
[left]:  [1]
[right]: [5]
```



Discussion:

Resolving patch:
diff --git a/modin/core/io/text/fwf_dispatcher.py b/modin/core/io/text/fwf_dispatcher.py
--- a/modin/core/io/text/fwf_dispatcher.py
+++ b/modin/core/io/text/fwf_dispatcher.py
@@ -14,6 +14,7 @@
 """Module houses `FWFDispatcher` class, that is used for reading of tables with fixed-width formatted lines."""
 
 import pandas
+from typing import Union, Sequence
 
 from modin.core.io.text.text_file_dispatcher import TextFileDispatcher
 
@@ -28,6 +29,8 @@ def check_parameters_support(
         cls,
         filepath_or_buffer,
         read_kwargs: dict,
+        skiprows_md: Union[Sequence, callable, int],
+        header_size: int,
     ):
         """
         Check support of parameters of `read_fwf` function.
@@ -38,6 +41,10 @@ def check_parameters_support(
             `filepath_or_buffer` parameter of `read_fwf` function.
         read_kwargs : dict
             Parameters of `read_fwf` function.
+        skiprows_md : int, array or callable
+            `skiprows` parameter modified for easier handling by Modin.
+        header_size : int
+            Number of rows that are used by header.
 
         Returns
         -------
@@ -48,4 +55,6 @@ def check_parameters_support(
             # If infer_nrows is a significant portion of the number of rows, pandas may be
             # faster.
             return False
-        return super().check_parameters_support(filepath_or_buffer, read_kwargs)
+        return super().check_parameters_support(
+            filepath_or_buffer, read_kwargs, skiprows_md, header_size
+        )
diff --git a/modin/core/io/text/text_file_dispatcher.py b/modin/core/io/text/text_file_dispatcher.py
--- a/modin/core/io/text/text_file_dispatcher.py
+++ b/modin/core/io/text/text_file_dispatcher.py
@@ -34,6 +34,7 @@
 from modin.utils import _inherit_docstrings
 from modin.core.io.text.utils import CustomNewlineIterator
 from modin.config import NPartitions
+from modin.error_message import ErrorMessage
 
 ColumnNamesTypes = Tuple[Union[pandas.Index, pandas.MultiIndex]]
 IndexColType = Union[int, str, bool, Sequence[int], Sequence[str], None]
@@ -615,6 +616,8 @@ def check_parameters_support(
         cls,
         filepath_or_buffer,
         read_kwargs: dict,
+        skiprows_md: Union[Sequence, callable, int],
+        header_size: int,
     ) -> bool:
         """
         Check support of only general parameters of `read_*` function.
@@ -625,12 +628,17 @@ def check_parameters_support(
             `filepath_or_buffer` parameter of `read_*` function.
         read_kwargs : dict
             Parameters of `read_*` function.
+        skiprows_md : int, array or callable
+            `skiprows` parameter modified for easier handling by Modin.
+        header_size : int
+            Number of rows that are used by header.
 
         Returns
         -------
         bool
             Whether passed parameters are supported or not.
         """
+        skiprows = read_kwargs.get("skiprows")
         if isinstance(filepath_or_buffer, str):
             if not cls.file_exists(filepath_or_buffer):
                 return False
@@ -640,6 +648,24 @@ def check_parameters_support(
         if read_kwargs["chunksize"] is not None:
             return False
 
+        skiprows_supported = True
+        if is_list_like(skiprows_md) and skiprows_md[0] < header_size:
+            skiprows_supported = False
+        elif callable(skiprows):
+            # check if `skiprows` callable gives True for any of header indices
+            is_intersection = any(
+                cls._get_skip_mask(pandas.RangeIndex(header_size), skiprows)
+            )
+            if is_intersection:
+                skiprows_supported = False
+
+        if not skiprows_supported:
+            ErrorMessage.single_warning(
+                "Values of `header` and `skiprows` parameters have intersections. "
+                "This case is unsupported by Modin, so pandas implementation will be used"
+            )
+            return False
+
         return True
 
     @classmethod
@@ -758,7 +784,7 @@ def _manage_skiprows_parameter(
                 )
                 skiprows_partitioning = len(skiprows_md)
                 skiprows_md = 0
-            else:
+            elif skiprows_md[0] > header_size:
                 skiprows_md = skiprows_md - header_size
         elif callable(skiprows):
 
@@ -963,6 +989,8 @@ def _read(cls, filepath_or_buffer, **kwargs):
         use_modin_impl = cls.check_parameters_support(
             filepath_or_buffer,
             kwargs,
+            skiprows_md,
+            header_size,
         )
         if not use_modin_impl:
             return cls.single_worker_read(


Test patch:
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
@@ -1145,7 +1145,13 @@ def test_read_csv_empty_frame(self):
     @pytest.mark.parametrize(
         "skiprows",
         [
+            [x for x in range(10)],
+            [x + 5 for x in range(15)],
+            [x for x in range(10) if x % 2 == 0],
+            [x + 5 for x in range(15) if x % 2 == 0],
+            lambda x: x % 2,
             lambda x: x > 20,
+            lambda x: x < 20,
             lambda x: True,
             lambda x: x in [10, 20],
             pytest.param(
@@ -1157,13 +1163,16 @@ def test_read_csv_empty_frame(self):
             ),
         ],
     )
-    def test_read_csv_skiprows_corner_cases(self, skiprows):
+    @pytest.mark.parametrize("header", ["infer", None, 0, 1, 150])
+    def test_read_csv_skiprows_corner_cases(self, skiprows, header):
         eval_io(
             fn_name="read_csv",
             check_kwargs_callable=not callable(skiprows),
             # read_csv kwargs
             filepath_or_buffer=pytest.csvs_names["test_read_csv_regular"],
             skiprows=skiprows,
+            header=header,
+            dtype="str",  # to avoid issues with heterogeneous data
         )
 
     def test_to_csv_with_index(self):