# Buggy code
def agg(groupby, func, method="auto", *args, **kwargs):
    """
    Aggregate using one or more operations on grouped data.
    :param groupby: Groupby data.
    :param func: Aggregation functions.
    :param method: 'shuffle' or 'tree', 'tree' method provide a better performance, 'shuffle' is recommended
    if aggregated result is very large, 'auto' will use 'shuffle' method in distributed mode and use 'tree'
    in local mode.
    :return: Aggregated result.
    """

    # When perform a computation on the grouped data, we won't shuffle
    # the data in the stage of groupby and do shuffle after aggregation.
    if not isinstance(groupby, GROUPBY_TYPE):
        raise TypeError(f"Input should be type of groupby, not {type(groupby)}")

    if method not in ["shuffle", "tree", "auto"]:
        raise ValueError(
            f"Method {method} is not available, please specify 'tree' or 'shuffle"
        )

    if not _check_if_func_available(func):
        return groupby.transform(func, *args, _call_agg=True, **kwargs)

    agg_op = DataFrameGroupByAgg(
        func=func,
        method=method,
        raw_func=func,
        groupby_params=groupby.op.groupby_params,
    )
    return agg_op(groupby)


# Traceback (ValueError)
In [9]: df = pd.DataFrame({
...:     'col1': np.random.randint(0, 100, (100000,)),
...:     'col2': np.random.choice(['a', 'b', 'c'], (100000,)),
...:     'col3': np.arange(100000)
...: })
...: df.iloc[-100:, :] = pd.NA

In [10]: df.to_csv('test.csv', index=False)

In [11]: md.read_csv('test.csv').execute()
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-11-560f5a720bd9> in <module>
----> 1 md.read_csv('test.csv').execute()

~/Documents/mars_dev/mars/mars/core.py in execute(self, session, **kw)
626
627         if wait:
--> 628             return run()
629         else:
630             thread_executor = ThreadPoolExecutor(1)

~/Documents/mars_dev/mars/mars/core.py in run()
622
623         def run():
--> 624             self.data.execute(session, **kw)
625             return self
626

~/Documents/mars_dev/mars/mars/core.py in execute(self, session, **kw)
373
374         if wait:
--> 375             return run()
376         else:
377             # leverage ThreadPoolExecutor to submit task,

~/Documents/mars_dev/mars/mars/core.py in run()
368         def run():
369             # no more fetch, thus just fire run
--> 370             session.run(self, **kw)
371             # return Tileable or ExecutableTuple itself
372             return self

~/Documents/mars_dev/mars/mars/session.py in run(self, *tileables, **kw)
476         tileables = tuple(mt.tensor(t) if not isinstance(t, (Entity, Base)) else t
477                           for t in tileables)
--> 478         result = self._sess.run(*tileables, **kw)
479
480         for t in tileables:

~/Documents/mars_dev/mars/mars/session.py in run(self, *tileables, **kw)
105             # set number of running cores
106             self.context.set_ncores(kw['n_parallel'])
--> 107             res = self._executor.execute_tileables(tileables, **kw)
108             return res
109

~/Documents/mars_dev/mars/mars/utils.py in _inner(*args, **kwargs)
437         def _inner(*args, **kwargs):
438             with self:
--> 439                 return func(*args, **kwargs)
440
441         return _inner

~/Documents/mars_dev/mars/mars/executor.py in execute_tileables(self, tileables, fetch, n_parallel, n_thread, print_progress, mock, compose, name)
876                                    n_parallel=n_parallel or n_thread,
877                                    print_progress=print_progress, mock=mock,
--> 878                                    chunk_result=chunk_result)
879
880                 # update shape of tileable and its chunks whatever it's successful or not

~/Documents/mars_dev/mars/mars/executor.py in execute_graph(self, graph, keys, n_parallel, print_progress, mock, no_intermediate, compose, retval, chunk_result)
688             print_progress=print_progress, mock=mock, mock_max_memory=self._mock_max_memory,
689             fetch_keys=fetch_keys, no_intermediate=no_intermediate)
--> 690         res = graph_execution.execute(retval)
691         self._mock_max_memory = max(self._mock_max_memory, graph_execution._mock_max_memory)
692         if mock:

~/Documents/mars_dev/mars/mars/executor.py in execute(self, retval)
569         # wait until all the futures completed
570         for future in executed_futures:
--> 571             future.result()
572
573         if retval:

~/miniconda3/envs/py3.7.2/lib/python3.7/concurrent/futures/_base.py in result(self, timeout)
430                 raise CancelledError()
431             elif self._state == FINISHED:
--> 432                 return self.__get_result()
433             else:
434                 raise TimeoutError()

~/miniconda3/envs/py3.7.2/lib/python3.7/concurrent/futures/_base.py in __get_result(self)
382     def __get_result(self):
383         if self._exception:
--> 384             raise self._exception
385         else:
386             return self._result

~/miniconda3/envs/py3.7.2/lib/python3.7/concurrent/futures/thread.py in run(self)
55
56         try:
---> 57             result = self.fn(*self.args, **self.kwargs)
58         except BaseException as exc:
59             self.future.set_exception(exc)

~/Documents/mars_dev/mars/mars/utils.py in _inner(*args, **kwargs)
437         def _inner(*args, **kwargs):
438             with self:
--> 439                 return func(*args, **kwargs)
440
441         return _inner

~/Documents/mars_dev/mars/mars/executor.py in _execute_operand(self, op)
441             # so we pass the first operand's first output to Executor.handle
442             first_op = ops[0]
--> 443             Executor.handle(first_op, results, self._mock)
444
445             # update maximal memory usage during execution

~/Documents/mars_dev/mars/mars/executor.py in handle(cls, op, results, mock)
639                 # The `UFuncTypeError` was introduced by numpy#12593 since v1.17.0.
640                 try:
--> 641                     return runner(results, op)
642                 except UFuncTypeError as e:
643                     raise TypeError(str(e)).with_traceback(sys.exc_info()[2]) from None

~/Documents/mars_dev/mars/mars/dataframe/datasource/read_csv.py in execute(cls, ctx, op)
321                     df = df[op.usecols]
322             else:
--> 323                 df = cls._cudf_read_csv(op) if op.gpu else cls._pandas_read_csv(f, op)
324
325         ctx[out_df.key] = df

~/Documents/mars_dev/mars/mars/dataframe/datasource/read_csv.py in _pandas_read_csv(cls, f, op)
272                 csv_kwargs['keep_default_na'] = False
273             df = pd.read_csv(b, sep=op.sep, names=op.names, index_col=op.index_col, usecols=usecols,
--> 274                              dtype=dtypes.to_dict(), nrows=op.nrows, **csv_kwargs)
275             if op.keep_usecols_order:
276                 df = df[op.usecols]

~/miniconda3/envs/py3.7.2/lib/python3.7/site-packages/pandas/io/parsers.py in parser_f(filepath_or_buffer, sep, delimiter, header, names, index_col, usecols, squeeze, prefix, mangle_dupe_cols, dtype, engine, converters, true_values, false_values, skipinitialspace, skiprows, skipfooter, nrows, na_values, keep_default_na, na_filter, verbose, skip_blank_lines, parse_dates, infer_datetime_format, keep_date_col, date_parser, dayfirst, cache_dates, iterator, chunksize, compression, thousands, decimal, lineterminator, quotechar, quoting, doublequote, escapechar, comment, encoding, dialect, error_bad_lines, warn_bad_lines, delim_whitespace, low_memory, memory_map, float_precision)
674         )
675
--> 676         return _read(filepath_or_buffer, kwds)
677
678     parser_f.__name__ = name

~/miniconda3/envs/py3.7.2/lib/python3.7/site-packages/pandas/io/parsers.py in _read(filepath_or_buffer, kwds)
452
453     try:
--> 454         data = parser.read(nrows)
455     finally:
456         parser.close()

~/miniconda3/envs/py3.7.2/lib/python3.7/site-packages/pandas/io/parsers.py in read(self, nrows)
1131     def read(self, nrows=None):
1132         nrows = _validate_integer("nrows", nrows)
-> 1133         ret = self._engine.read(nrows)
1134
1135         # May alter columns / col_dict

~/miniconda3/envs/py3.7.2/lib/python3.7/site-packages/pandas/io/parsers.py in read(self, nrows)
2035     def read(self, nrows=None):
2036         try:
-> 2037             data = self._reader.read(nrows)
2038         except StopIteration:
2039             if self._first_chunk:

pandas/_libs/parsers.pyx in pandas._libs.parsers.TextReader.read()

pandas/_libs/parsers.pyx in pandas._libs.parsers.TextReader._read_low_memory()

pandas/_libs/parsers.pyx in pandas._libs.parsers.TextReader._read_rows()

pandas/_libs/parsers.pyx in pandas._libs.parsers.TextReader._convert_column_data()

pandas/_libs/parsers.pyx in pandas._libs.parsers.TextReader._convert_tokens()

pandas/_libs/parsers.pyx in pandas._libs.parsers.TextReader._convert_with_dtype()

ValueError: Integer column has NA values in column 0

# Fixed code
def agg(groupby, func, method="auto", *args, **kwargs):
    """
    Aggregate using one or more operations on grouped data.

    Parameters
    ----------
    groupby : Mars Groupby
        Groupby data.
    func : str or list-like
        Aggregation functions.
    method : {'auto', 'shuffle', 'tree'}, default 'auto'
        'tree' method provide a better performance, 'shuffle' is recommended
        if aggregated result is very large, 'auto' will use 'shuffle' method
        in distributed mode and use 'tree' in local mode.

    Returns
    -------
    Series or DataFrame
        Aggregated result.
    """

    # When perform a computation on the grouped data, we won't shuffle
    # the data in the stage of groupby and do shuffle after aggregation.
    if not isinstance(groupby, GROUPBY_TYPE):
        raise TypeError(f"Input should be type of groupby, not {type(groupby)}")

    if method not in ["shuffle", "tree", "auto"]:
        raise ValueError(
            f"Method {method} is not available, please specify 'tree' or 'shuffle"
        )

    if not _check_if_func_available(func):
        return groupby.transform(func, *args, _call_agg=True, **kwargs)

    agg_op = DataFrameGroupByAgg(
        func=func,
        method=method,
        raw_func=func,
        groupby_params=groupby.op.groupby_params,
    )
    return agg_op(groupby)