Repository: pandas-dev/pandas (python)

Issue:
BUG: read_csv throws TypeError with iterator, nrows
### Pandas version checks

- [X] I have checked that this issue has not already been reported.

- [X] I have confirmed this bug exists on the [latest version](https://pandas.pydata.org/docs/whatsnew/index.html) of pandas.

- [ ] I have confirmed this bug exists on the [main branch](https://pandas.pydata.org/docs/dev/getting_started/install.html#installing-the-development-version-of-pandas) of pandas.


### Reproducible Example

```python
from io import BytesIO
import pandas

csv = b'a,b\n1,2\n3,4'
with BytesIO(csv) as f:
    it = pd.read_csv(
                f,
                nrows=1,
                iterator=True,
            )
    for df in it:
        pass
```

Behavior:

```
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[82], line 11
      5 with BytesIO(csv) as f:
      6     it = pd.read_csv(
      7                 f,
      8                 nrows=1,
      9                 iterator=True,
     10             )
---> 11     for df in it:
     12         pass

File ~\AppData\Local\anaconda3\Lib\site-packages\pandas\io\parsers\readers.py:1843, in TextFileReader.__next__(self)
   1841 def __next__(self) -> DataFrame:
   1842     try:
-> 1843         return self.get_chunk()
   1844     except StopIteration:
   1845         self.close()

File ~\AppData\Local\anaconda3\Lib\site-packages\pandas\io\parsers\readers.py:1984, in TextFileReader.get_chunk(self, size)
   1982     if self._currow >= self.nrows:
   1983         raise StopIteration
-> 1984     size = min(size, self.nrows - self._currow)
   1985 return self.read(nrows=size)

TypeError: '<' not supported between instances of 'int' and 'NoneType'
```
```


### Issue Description

It seems that `read_csv` throws a `TypeError` when combining `nrows` and `iterable`.


My context: I want to convert a CSV to parquet. The CSV is larger than memory, so I want to use `iterator=True`. The CSV contains a footer. But since `skipfooter` is not supported for the fast engines (c or pyarrow), and `comment` can only be a single character, I want to instead indirectly skip the footer by using `nrows`. (I know in advance the number of rows.) My data contains `\r\n` line endings, although the error happens with normal `\n`.

### Expected Behavior

The script runs without error. `nrows` rows of data are returned (across one chunk in this small example). 

### Installed Versions

<details>
INSTALLED VERSIONS
------------------
commit                : d9cdd2ee5a58015ef6f4d15c7226110c9aab8140
python                : 3.11.9.final.0
python-bits           : 64
OS                    : Windows
OS-release            : 10
Version               : 10.0.19045
machine               : AMD64
processor             : Intel64 Family 6 Model 142 Stepping 12, GenuineIntel
byteorder             : little
LC_ALL                : None
LANG                  : None
LOCALE                : English_Australia.1252

pandas                : 2.2.2
numpy                 : 1.26.4
pytz                  : 2024.1
dateutil              : 2.9.0.post0
setuptools            : 69.5.1
pip                   : 24.0
Cython                : None
pytest                : 7.4.4
hypothesis            : None
sphinx                : 7.3.7
blosc                 : None
feather               : 0.4.1
xlsxwriter            : 3.2.0
lxml.etree            : 5.2.1
html5lib              : 1.1
pymysql               : None
psycopg2              : None
jinja2                : 3.1.4
IPython               : 8.25.0
pandas_datareader     : None
adbc-driver-postgresql: None
adbc-driver-sqlite    : None
bs4                   : 4.12.2
bottleneck            : 1.3.7
dataframe-api-compat  : None
fastparquet           : None
fsspec                : 2024.3.1
gcsfs                 : None
matplotlib            : 3.8.4
numba                 : 0.59.1
numexpr               : 2.8.7
odfpy                 : None
openpyxl              : 3.1.2
pandas_gbq            : None
pyarrow               : 14.0.2
pyreadstat            : None
python-calamine       : None
pyxlsb                : None
s3fs                  : 2024.3.1
scipy                 : 1.13.1
sqlalchemy            : 2.0.30
tables                : 3.9.2
tabulate              : 0.9.0
xarray                : 2023.6.0
xlrd                  : 2.0.1
zstandard             : 0.22.0
tzdata                : 2023.3
qtpy                  : 2.4.1
pyqt5                 : None
</details>


Pull request:
BUG: Fix read_csv raising TypeError when iterator and nrows are specified without chunksize
- [x] closes #59079
- [x] [Tests added and passed](https://pandas.pydata.org/pandas-docs/dev/development/contributing_codebase.html#writing-tests) if fixing a bug or adding a new feature
- [x] All [code checks passed](https://pandas.pydata.org/pandas-docs/dev/development/contributing_codebase.html#pre-commit).
- [ ] Added [type annotations](https://pandas.pydata.org/pandas-docs/dev/development/contributing_codebase.html#type-hints) to new arguments/methods/functions.
- [x] Added an entry in the latest `doc/source/whatsnew/vX.X.X.rst` file if fixing a bug or adding a new feature.


Patch:
diff --git a/ci/code_checks.sh b/ci/code_checks.sh
index 013f7abe5f..424171cee7 100755
--- a/ci/code_checks.sh
+++ b/ci/code_checks.sh
@@ -231,7 +231,6 @@ if [[ -z "$CHECK" || "$CHECK" == "docstrings" ]]; then
         -i "pandas.Timestamp.ctime SA01" \
         -i "pandas.Timestamp.date SA01" \
         -i "pandas.Timestamp.day GL08" \
-        -i "pandas.Timestamp.floor SA01" \
         -i "pandas.Timestamp.fold GL08" \
         -i "pandas.Timestamp.fromordinal SA01" \
         -i "pandas.Timestamp.fromtimestamp PR01,SA01" \
diff --git a/doc/source/whatsnew/v3.0.0.rst b/doc/source/whatsnew/v3.0.0.rst
index 3d869bf31f..73e939e7f4 100644
--- a/doc/source/whatsnew/v3.0.0.rst
+++ b/doc/source/whatsnew/v3.0.0.rst
@@ -554,6 +554,7 @@ I/O
 - Bug in :meth:`DataFrame.to_string` that raised ``StopIteration`` with nested DataFrames. (:issue:`16098`)
 - Bug in :meth:`HDFStore.get` was failing to save data of dtype datetime64[s] correctly (:issue:`59004`)
 - Bug in :meth:`read_csv` raising ``TypeError`` when ``index_col`` is specified and ``na_values`` is a dict containing the key ``None``. (:issue:`57547`)
+- Bug in :meth:`read_csv` raising ``TypeError`` when ``nrows`` and ``iterator`` are specified without specifying a ``chunksize``. (:issue:`59079`)
 - Bug in :meth:`read_stata` raising ``KeyError`` when input file is stored in big-endian format and contains strL data. (:issue:`58638`)
 
 Period
diff --git a/pandas/_libs/tslibs/nattype.pyx b/pandas/_libs/tslibs/nattype.pyx
index c483814a3e..6530970264 100644
--- a/pandas/_libs/tslibs/nattype.pyx
+++ b/pandas/_libs/tslibs/nattype.pyx
@@ -1139,6 +1139,12 @@ timedelta}, default 'raise'
         ------
         ValueError if the freq cannot be converted.
 
+        See Also
+        --------
+        Timestamp.ceil : Round up a Timestamp to the specified resolution.
+        Timestamp.round : Round a Timestamp to the specified resolution.
+        Series.dt.floor : Round down the datetime values in a Series.
+
         Notes
         -----
         If the Timestamp has a timezone, flooring will take place relative to the
diff --git a/pandas/_libs/tslibs/timestamps.pyx b/pandas/_libs/tslibs/timestamps.pyx
index 9cd0fea1d6..707e36a848 100644
--- a/pandas/_libs/tslibs/timestamps.pyx
+++ b/pandas/_libs/tslibs/timestamps.pyx
@@ -2207,6 +2207,12 @@ timedelta}, default 'raise'
         ------
         ValueError if the freq cannot be converted.
 
+        See Also
+        --------
+        Timestamp.ceil : Round up a Timestamp to the specified resolution.
+        Timestamp.round : Round a Timestamp to the specified resolution.
+        Series.dt.floor : Round down the datetime values in a Series.
+
         Notes
         -----
         If the Timestamp has a timezone, flooring will take place relative to the
diff --git a/pandas/io/parsers/readers.py b/pandas/io/parsers/readers.py
index 8a07c99b0f..d00fc3b159 100644
--- a/pandas/io/parsers/readers.py
+++ b/pandas/io/parsers/readers.py
@@ -1534,7 +1534,10 @@ class TextFileReader(abc.Iterator):
         if self.nrows is not None:
             if self._currow >= self.nrows:
                 raise StopIteration
-            size = min(size, self.nrows - self._currow)
+            if size is None:
+                size = self.nrows - self._currow
+            else:
+                size = min(size, self.nrows - self._currow)
         return self.read(nrows=size)
 
     def __enter__(self) -> Self:


Test patch:
diff --git a/pandas/tests/io/parser/common/test_iterator.py b/pandas/tests/io/parser/common/test_iterator.py
index 091edb67f6..668aab05b9 100644
--- a/pandas/tests/io/parser/common/test_iterator.py
+++ b/pandas/tests/io/parser/common/test_iterator.py
@@ -98,6 +98,31 @@ baz,7,8,9
     tm.assert_frame_equal(concat(result), expected)
 
 
+def test_nrows_iterator_without_chunksize(all_parsers):
+    # GH 59079
+    parser = all_parsers
+    data = """A,B,C
+foo,1,2,3
+bar,4,5,6
+baz,7,8,9
+"""
+    if parser.engine == "pyarrow":
+        msg = "The 'iterator' option is not supported with the 'pyarrow' engine"
+        with pytest.raises(ValueError, match=msg):
+            parser.read_csv(StringIO(data), iterator=True, nrows=2)
+        return
+
+    with parser.read_csv(StringIO(data), iterator=True, nrows=2) as reader:
+        result = reader.get_chunk()
+
+    expected = DataFrame(
+        [[1, 2, 3], [4, 5, 6]],
+        index=["foo", "bar"],
+        columns=["A", "B", "C"],
+    )
+    tm.assert_frame_equal(result, expected)
+
+
 @pytest.mark.parametrize(
     "kwargs", [{"iterator": True, "chunksize": 1}, {"iterator": True}, {"chunksize": 1}]
 )