coveralls: 
[![Coverage Status](https://coveralls.io/builds/2278632/badge)](https://coveralls.io/builds/2278632)

Coverage decreased (-0.05%) to 90.88% when pulling **da1a700cebe8bc3698a501766295befafccaa404 on hayd:fix_74** into **cfb99aba49789019542ec6cb2b3f7215d1f9a04f on google:master**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/2278632/badge)](https://coveralls.io/builds/2278632)

Coverage decreased (-0.81%) to 90.12% when pulling **da1a700cebe8bc3698a501766295befafccaa404 on hayd:fix_74** into **cfb99aba49789019542ec6cb2b3f7215d1f9a04f on google:master**.

diff --git a/plugins/yapf.vim b/plugins/yapf.vim
index cdbb048..3b43104 100644
--- a/plugins/yapf.vim
+++ b/plugins/yapf.vim
@@ -23,7 +23,7 @@
 function! yapf#YAPF() range
   " Determine range to format.
   let l:line_ranges = a:firstline . '-' . a:lastline
-  let l:cmd = 'yapf --lines=' . l:line_ranges
+  let l:cmd = 'env PYTHONPATH=<path_to_srcdir>/yapf <path_to_python>/python -m yapf --lines=' . l:line_ranges
 
   " Call YAPF with the current buffer
   let l:formatted_text = system(l:cmd, join(getline(1, '$'), "\n") . "\n")
diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py
index d8fcd79..6d0f5f2 100644
--- a/yapf/yapflib/reformatter.py
+++ b/yapf/yapflib/reformatter.py
@@ -102,7 +102,10 @@ def _RetainVerticalSpacing(prev_uwline, cur_uwline):
   """Retain all vertical spacing between lines."""
   if not prev_uwline:
     return
-  prev_lineno = prev_uwline.last.lineno
+  if prev_uwline.last.is_string:
+    prev_lineno = prev_uwline.last.lineno + prev_uwline.last.value.count('\n')
+  else:
+    prev_lineno = prev_uwline.last.lineno
   if cur_uwline.first.is_comment:
     cur_lineno = cur_uwline.first.lineno - cur_uwline.first.value.count('\n')
   else:

Fixing lines with a multi-line string inserts too many lines
Note: I have a fix for this #74.

```
code = '"""\ndocstring\n\n"""\n\nimport blah'
from yapf.yapflib.yapf_api import FormatCode

In [4]: FormatCode(code)
Out[4]: '"""\ndocstring\n\n"""\n\nimport blah\n'

In [5]: FormatCode(code, lines=[(2, 2)])
Out[5]: '"""\ndocstring\n\n"""\n\n\n\n\nimport blah\n'
```

The latter now has (the number of lines in the multi-line string) too many newlines.

*This is an off-by-number-of-lines due to [this value](https://github.com/google/yapf/blob/cfb99aba49789019542ec6cb2b3f7215d1f9a04f/yapf/yapflib/reformatter.py#L105).*
diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py
index 5ae4e46..fb9f201 100644
--- a/yapftests/yapf_test.py
+++ b/yapftests/yapf_test.py
@@ -503,6 +503,24 @@ class CommandLineTest(unittest.TestCase):
     self.assertIsNone(stderrdata)
     self.assertEqual(reformatted_code.decode('utf-8'), expected_formatted_code)
 
+    unformatted_code = textwrap.dedent(u"""\
+        '''
+        docstring
+
+        '''
+
+        import blah
+        """)
+
+    p = subprocess.Popen(YAPF_BINARY + ['--lines', '2-2'],
+                         stdout=subprocess.PIPE,
+                         stdin=subprocess.PIPE,
+                         stderr=subprocess.STDOUT)
+    reformatted_code, stderrdata = p.communicate(
+        unformatted_code.encode('utf-8'))
+    self.assertIsNone(stderrdata)
+    self.assertEqual(reformatted_code.decode('utf-8'), unformatted_code)
+
 
 if __name__ == '__main__':
   unittest.main()

pip install -e .
parse_log_pytest
requirements.txt
pytest
3.9
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
exceptiongroup==1.2.2
iniconfig==2.1.0
packaging==24.2
pluggy==1.5.0
pytest==8.3.5
tomli==2.2.1
-e git+https://github.com/google/yapf.git@cfb99aba49789019542ec6cb2b3f7215d1f9a04f#egg=yapf

name: yapf
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - exceptiongroup==1.2.2
      - iniconfig==2.1.0
      - packaging==24.2
      - pluggy==1.5.0
      - pytest==8.3.5
      - tomli==2.2.1
prefix: /opt/conda/envs/yapf

yapftests/yapf_test.py::CommandLineTest::testREtainingVerticalWhitespace
yapftests/yapf_test.py::YapfTest::testNoEndingNewline yapftests/yapf_test.py::YapfTest::testSimple yapftests/yapf_test.py::CommandLineTest::testDisableButAdjustIndentations yapftests/yapf_test.py::CommandLineTest::testDisableWholeDataStructure yapftests/yapf_test.py::CommandLineTest::testEncodingVerification yapftests/yapf_test.py::CommandLineTest::testInPlaceReformatting yapftests/yapf_test.py::CommandLineTest::testReadFromStdin yapftests/yapf_test.py::CommandLineTest::testReadSingleLineCodeFromStdin yapftests/yapf_test.py::CommandLineTest::testReformattingSkippingLines yapftests/yapf_test.py::CommandLineTest::testReformattingSkippingSingleLine yapftests/yapf_test.py::CommandLineTest::testReformattingSkippingToEndOfFile yapftests/yapf_test.py::CommandLineTest::testReformattingSpecificLines yapftests/yapf_test.py::CommandLineTest::testRetainingHorizontalWhitespace yapftests/yapf_test.py::CommandLineTest::testSetCustomStyleBasedOnGoogle yapftests/yapf_test.py::CommandLineTest::testSetGoogleStyle yapftests/yapf_test.py::CommandLineTest::testUnicodeEncodingPipedToFile
plugins/yapf.vim yapf/yapflib/reformatter.py
plugins/yapf.vim yapf/yapflib/reformatter.py