BUG: Nrows cannot be zero for read_csv. Fixes #21141
State: closed

- [x] closes #21141
- [x] tests added / passed
- [x] passes `git diff upstream/master -u -- "*.py" | flake8 --diff`
- [ ] whatsnew entry


Labels:
name: API Design
name: IO CSV
description: read_csv, to_csv
name: Deprecate
description: Functionality to remove in pandas

Comments:
@jreback : Do we need to deprecate `nrow=0` before disallowing?  It's a (small, yet annoying) corner case, which is why I ask about it.

@cgopalan : This will be important, since it determines the type of `whatsnew` entry you're going to add.
I'm not sure about disallowing `nrows=0`.  It's generally useful when you need to dynamically read a subset of columns, where you do a two pass procedure along the lines of:

1. Read in the columns only, e.g. `all_cols = pd.read_csv('file.csv', nrows=0).columns`
2. Dynamically filter the columns, e.g. `good_cols = [c for c in all_cols if c.startswith('foo')]`
3. Read in only the desired columns, e.g. `df = pd.read_csv('file.csv', usecols=good_cols)`

I doubt you lose much performance by using `nrows=1` instead, so it's not the end of the world if this does get removed.  However, there are some established StackOverflow answers with `nrows=0` similar to my procedure above, so I imagine there are some users that have `nrows=0` in their codebase.  If this is going to be removed, it definitely seems like it should be deprecated first.
@jschendel : Good to know.  In the case of your example, couldn't you just read the first line of the file using the builtin `open` ?  Don't really need `pandas` for that. 🤷‍♂️ 
Yeah, I'm not saying that it's the _right_ solution, just that it's a solution people are likely using.  Certainly more concise than using `open` if you method chain to do the filtering.  I wouldn't complain if this was removed, but doing so without deprecating seems likely to break things for users.
> I wouldn't complain if this was removed, but doing so without deprecating seems likely to break things for users.

@jschendel : Nope, that's totally fair.  Let's deprecate then.

@cgopalan : Can you update your PR to deprecate `nrows=0` ?
> nrows=0 is valid
the combinations of options is invalid

@jreback : `nrows=0` has limited use and was a clean way to patch the corner case (though it seems like @jschendel has a case to keep it).

In any case, should we just disallow that combination of inputs then?  If `nrows=0` is considered valid, I'm a little uncertain as to why we would consider the combination invalid (it shouldn't depend on what the value of `low_memory` is IMO).
# [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/21431?src=pr&el=h1) Report
> Merging [#21431](https://codecov.io/gh/pandas-dev/pandas/pull/21431?src=pr&el=desc) into [master](https://codecov.io/gh/pandas-dev/pandas/commit/480790531ffcc4329f280ddf6877d028d08e969f?src=pr&el=desc) will **not change** coverage.
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/pandas-dev/pandas/pull/21431/graphs/tree.svg?width=650&height=150&src=pr&token=eZ4WkYLtcO)](https://codecov.io/gh/pandas-dev/pandas/pull/21431?src=pr&el=tree)

```diff
@@           Coverage Diff           @@
##           master   #21431   +/-   ##
=======================================
  Coverage   91.89%   91.89%           
=======================================
  Files         153      153           
  Lines       49596    49596           
=======================================
  Hits        45576    45576           
  Misses       4020     4020
```

| Flag | Coverage Δ | |
|---|---|---|
| #multiple | `90.29% <100%> (ø)` | :arrow_up: |
| #single | `41.86% <100%> (ø)` | :arrow_up: |

| [Impacted Files](https://codecov.io/gh/pandas-dev/pandas/pull/21431?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [pandas/io/parsers.py](https://codecov.io/gh/pandas-dev/pandas/pull/21431/diff?src=pr&el=tree#diff-cGFuZGFzL2lvL3BhcnNlcnMucHk=) | `95.46% <100%> (ø)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/21431?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/21431?src=pr&el=footer). Last update [4807905...947168b](https://codecov.io/gh/pandas-dev/pandas/pull/21431?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

@jreback @gfyoung i too agree that just the value of `low_memory` should not render the combination of values invalid. Because of this corner case, this is actually exhibiting weird behavior on an unrelated set of conditions. Better to suppress this corner case by removing/deprecating `nrows=0`.
Is there a way to deprecate just a value for an arg? I would assume we want to keep `nrows` as an argument.
> @jreback @gfyoung i too agree that just the value of low_memory should not render the combination of values invalid. Because of this corner case, this is actually exhibiting weird behavior on an unrelated set of conditions. Better to suppress this corner case by removing/deprecating nrows=0.
Is there a way to deprecate just a value for an arg? I would assume we want to keep nrows as an argument.

no reason to remove or even deprecate ``nrows=0``, you simply need to addees for this particular combination of options
@jreback so `read_csv(StringIO(data), low_memory=False, index_col=0, nrows=0)` is allowed but `read_csv(StringIO(data), low_memory=True, index_col=0, nrows=0)`  is not?
> no reason to remove or even deprecate nrows=0, you simply need to addees for this particular combination of options

@jreback : What you're saying sounds like we should revisit #21176?
yeah i thought that was fine


@jreback : 🤦‍♂️ well, I guess we're heading back there then. 😄 
@gfyoung should i delete this branch?
@cgopalan : Sure thing.