Repository: pytest-dev/pyfakefs (python)

Issue:
Row dropped with pandas read_csv on linux
**Describe the bug**
When using pyfakefs with pandas, sometimes a single row is dropped on write / read. This only occurs on linux systems (tested with ubuntu laptop), with no issue on Windows. Totally understand if this issue is out of scope - as there are known issues with pandas listed in the docs!

**How To Reproduce**
Run the following on a linux system via pytest:
```
import pandas as pd

def test_minimal_example(fs):

    fs.create_dir("/TEST")

    n_rows = 46
    df = pd.DataFrame({
     "abcdefghlmnopqrst": [1]*n_rows,
     "abcdef": [1]*n_rows,
     "abcdefghijklm": ['ABCD']*n_rows,
     "abcdefghijklmnopqrstuvw": [pd.Timestamp('2023-06-13 02:24:46.996459+0000', tz='UTC')]*n_rows,
     "abcdefghijklmnopqrstuv": [pd.Timestamp('2023-06-02 09:20:20+0000', tz='UTC')]*n_rows,
     "abcdefghijklmnopqr": [pd.NaT]*35 + [pd.Timestamp('2023-06-15 18:00:00+0000', tz='UTC')]*11,
     "abcdefghijklmn": ['ABCDEFGHIJ']*n_rows,
     "abcdefghlmnopqr": ['ABCDEFG']*n_rows,
     "abcdefghijklmnopqrstuvwxyz": ['ABCD']*n_rows,
     "abcdefghijklmnopqrstuvwxy": ['ABCDEFGHIJK', None]*(int(n_rows/2)),
     "abcdefghij": ['ABC']*n_rows,
     "abcdefghi": [pd.Timestamp('2017-01-22 08:01:44.253136+0000', tz='UTC')]*n_rows,
     "abcdefghijk": [pd.Timestamp('2018-10-11 12:03:31.663658+0000', tz='UTC')]*n_rows
    })
    df.to_csv("/TEST/test.csv", index=False)

    read_df = pd.read_csv("/TEST/test.csv")
    assert len(read_df) == len(df)
```
Once read, the dataframe will drop one row (from 46 to 45). Changing pretty much anything about this dataframe e.g. names of columns, number of rows etc... will lead to this test passing.

**Your environment**
I'm running on WSL, but a colleague had the same issue on their ubuntu system:
```
Linux-5.15.167.4-microsoft-standard-WSL2-x86_64-with-glibc2.35
Python 3.11.11 (main, Dec 11 2024, 16:28:39) [GCC 11.2.0]
pyfakefs 5.7.4
pytest 8.3.4
```


Pull request description:
Fix content update after flush
- caused missing content if writing over the buffer end
- fixes #1120
- temporarily disable Python 3.14 in CI (current alpha 5 fails some tests)

#### Tasks
- [x] Unit tests added that reproduce the issue or prove feature is working
- [x] Fix or feature added
- [x] Entry to release notes added
- [x] Pre-commit CI shows no errors
- [x] Unit tests passing


Patch:
diff --git a/CHANGES.md b/CHANGES.md
index c6229bb..ff299d5 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -17,6 +17,10 @@ The released versions correspond to PyPI releases.
 ### Changes
 * added some preliminary support for Python 3.14
 
+### Fixes
+* fixed a problem with flushing if writing over the buffer end
+  (see [#1120](../../issues/1120))
+
 ## [Version 5.7.4](https://pypi.python.org/pypi/pyfakefs/5.7.4) (2025-01-14)
 Minor bugfix release.
 
diff --git a/pyfakefs/fake_file.py b/pyfakefs/fake_file.py
index d43eb6d..73aec9d 100644
--- a/pyfakefs/fake_file.py
+++ b/pyfakefs/fake_file.py
@@ -910,8 +910,8 @@ class FakeFileWrapper:
         self._check_open_file()
 
         if self.allow_update:
-            contents = self._io.getvalue()
             if self._append:
+                contents = self._io.getvalue()
                 self._sync_io()
                 old_contents = self.file_object.byte_contents
                 assert old_contents is not None
@@ -919,6 +919,7 @@ class FakeFileWrapper:
                 self._set_stream_contents(contents)
             else:
                 self._io.flush()
+                contents = self._io.getvalue()
             changed = self.file_object.set_contents(contents, self._encoding)
             self.update_flush_pos()
             if changed:


Test patch:
diff --git a/.github/workflows/testsuite.yml b/.github/workflows/testsuite.yml
index 8231af2..07d175e 100644
--- a/.github/workflows/testsuite.yml
+++ b/.github/workflows/testsuite.yml
@@ -32,7 +32,8 @@ jobs:
       fail-fast: false
       matrix:
         os: [ubuntu-latest, macOS-latest, windows-latest]
-        python-version: [3.8, 3.9, "3.10", "3.11", "3.12", "3.13", "3.14"]
+        python-version: [3.8, 3.9, "3.10", "3.11", "3.12", "3.13"]
+#        python-version: [3.8, 3.9, "3.10", "3.11", "3.12", "3.13", "3.14"]
         include:
           - python-version: "pypy-3.7"
             os: ubuntu-22.04
diff --git a/pyfakefs/tests/fake_open_test.py b/pyfakefs/tests/fake_open_test.py
index f5ffa87..d760e0a 100644
--- a/pyfakefs/tests/fake_open_test.py
+++ b/pyfakefs/tests/fake_open_test.py
@@ -1366,6 +1366,22 @@ class BufferingModeTest(FakeFileOpenTestBase):
                 x = r.read()
                 self.assertEqual(b"a" * 50, x)
 
+    def test_writing_over_buffer_end(self):
+        # regression test for #1120
+        dir_path = self.make_path("foo")
+        self.create_dir(dir_path)
+        file_path = self.os.path.join(dir_path, "bar.txt")
+        line_end_size = len(self.os.linesep)
+        char_count = io.DEFAULT_BUFFER_SIZE // 256 - line_end_size
+        for line_count in (255, 256, 257, 511, 512, 513):
+            with self.open(file_path, "w") as f:
+                for i in range(line_count):
+                    f.write("x" * char_count + "\n")
+
+            with self.open(file_path) as f:
+                lines = f.readlines()
+                self.assertEqual(line_count, len(lines))
+
 
 class RealBufferingTest(BufferingModeTest):
     def use_real_fs(self):