diff --git a/CHANGELOG.md b/CHANGELOG.md
index 47163f3..8566a50 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,6 +16,7 @@ project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 
 - Fix escaping of quoted values written by `set_key` (#236 by [@bbc2]).
 - Fix `dotenv run` crashing on environment variables without values (#237 by [@yannham]).
+- Remove warning when last line is empty (#238 by [@bbc2]).
 
 ## [0.11.0] - 2020-02-07
 
diff --git a/src/dotenv/parser.py b/src/dotenv/parser.py
index 2904af8..2c93cbd 100644
--- a/src/dotenv/parser.py
+++ b/src/dotenv/parser.py
@@ -197,6 +197,13 @@ def parse_binding(reader):
     reader.set_mark()
     try:
         reader.read_regex(_multiline_whitespace)
+        if not reader.has_next():
+            return Binding(
+                key=None,
+                value=None,
+                original=reader.get_marked(),
+                error=False,
+            )
         reader.read_regex(_export)
         key = parse_key(reader)
         reader.read_regex(_whitespace)

Python-dotenv could not parse statement
Hi Guys,

I use dotenv in my Django app and ran into one issue when i runserver:

`> Python-dotenv could not parse statement starting at line 10`

although the django seem working fine, but I couldn't feel right about this.

Here is my .env file:
```
DJANGO_SECRET_KEY="xxxxxxxxxxxxxxxxx"
DEBUG=True
DATABASE_DEFAULT_ENGINE="django.db.backends.postgresql"
DATABASE_DEFAULT_NAME="postgres"
DATABASE_DEFAULT_USER="postgres"
DATABASE_DEFAULT_PASSWORD="abc123"
DATABASE_DEFAULT_HOST="localhost"
DATABASE_DEFAULT_PORT="5432"
SENDGRID_API_KEY="xxxxxxxxxxxxxxxxxxxxxxxx"
```
And i have load the dotenv in wsgi.py:
```
import os

from dotenv import load_dotenv

from django.core.wsgi import get_wsgi_application

load_dotenv()

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'webapp.settings')

application = get_wsgi_application()
```

and i even done it in manage.py:
```
import os
import sys

from pathlib import Path

from dotenv import load_dotenv

env_path = Path('webapp') / '.env'
load_dotenv(dotenv_path=env_path)
... the rest as usual
```

is this a bug or my own mistakes?


diff --git a/tests/test_main.py b/tests/test_main.py
index a4fb5b4..d867858 100644
--- a/tests/test_main.py
+++ b/tests/test_main.py
@@ -30,63 +30,32 @@ def test_set_key_no_file(tmp_path):
 
 
 @pytest.mark.parametrize(
-    "key,value,expected,content",
+    "before,key,value,expected,after",
     [
-        ("a", "", (True, "a", ""), 'a=""\n'),
-        ("a", "b", (True, "a", "b"), 'a="b"\n'),
-        ("a", "'b'", (True, "a", "b"), 'a="b"\n'),
-        ("a", "\"b\"", (True, "a", "b"), 'a="b"\n'),
-        ("a", "b'c", (True, "a", "b'c"), 'a="b\'c"\n'),
-        ("a", "b\"c", (True, "a", "b\"c"), 'a="b\\\"c"\n'),
+        ("", "a", "", (True, "a", ""), 'a=""\n'),
+        ("", "a", "b", (True, "a", "b"), 'a="b"\n'),
+        ("", "a", "'b'", (True, "a", "b"), 'a="b"\n'),
+        ("", "a", "\"b\"", (True, "a", "b"), 'a="b"\n'),
+        ("", "a", "b'c", (True, "a", "b'c"), 'a="b\'c"\n'),
+        ("", "a", "b\"c", (True, "a", "b\"c"), 'a="b\\\"c"\n'),
+        ("a=b", "a", "c", (True, "a", "c"), 'a="c"\n'),
+        ("a=b\n", "a", "c", (True, "a", "c"), 'a="c"\n'),
+        ("a=b\n\n", "a", "c", (True, "a", "c"), 'a="c"\n\n'),
+        ("a=b\nc=d", "a", "e", (True, "a", "e"), 'a="e"\nc=d'),
+        ("a=b\nc=d\ne=f", "c", "g", (True, "c", "g"), 'a=b\nc="g"\ne=f'),
+        ("a=b\n", "c", "d", (True, "c", "d"), 'a=b\nc="d"\n'),
     ],
 )
-def test_set_key_new(dotenv_file, key, value, expected, content):
+def test_set_key(dotenv_file, before, key, value, expected, after):
     logger = logging.getLogger("dotenv.main")
+    with open(dotenv_file, "w") as f:
+        f.write(before)
 
     with mock.patch.object(logger, "warning") as mock_warning:
         result = dotenv.set_key(dotenv_file, key, value)
 
     assert result == expected
-    assert open(dotenv_file, "r").read() == content
-    mock_warning.assert_not_called()
-
-
-def test_set_key_new_with_other_values(dotenv_file):
-    logger = logging.getLogger("dotenv.main")
-    with open(dotenv_file, "w") as f:
-        f.write("a=b\n")
-
-    with mock.patch.object(logger, "warning") as mock_warning:
-        result = dotenv.set_key(dotenv_file, "foo", "bar")
-
-    assert result == (True, "foo", "bar")
-    assert open(dotenv_file, "r").read() == 'a=b\nfoo="bar"\n'
-    mock_warning.assert_not_called()
-
-
-def test_set_key_existing(dotenv_file):
-    logger = logging.getLogger("dotenv.main")
-    with open(dotenv_file, "w") as f:
-        f.write("foo=bar")
-
-    with mock.patch.object(logger, "warning") as mock_warning:
-        result = dotenv.set_key(dotenv_file, "foo", "baz")
-
-    assert result == (True, "foo", "baz")
-    assert open(dotenv_file, "r").read() == 'foo="baz"\n'
-    mock_warning.assert_not_called()
-
-
-def test_set_key_existing_with_other_values(dotenv_file):
-    logger = logging.getLogger("dotenv.main")
-    with open(dotenv_file, "w") as f:
-        f.write("a=b\nfoo=bar\nc=d")
-
-    with mock.patch.object(logger, "warning") as mock_warning:
-        result = dotenv.set_key(dotenv_file, "foo", "baz")
-
-    assert result == (True, "foo", "baz")
-    assert open(dotenv_file, "r").read() == 'a=b\nfoo="baz"\nc=d'
+    assert open(dotenv_file, "r").read() == after
     mock_warning.assert_not_called()
 
 
diff --git a/tests/test_parser.py b/tests/test_parser.py
index dae51d3..f807513 100644
--- a/tests/test_parser.py
+++ b/tests/test_parser.py
@@ -86,6 +86,19 @@ from dotenv.parser import Binding, Original, parse_stream
             Binding(key=u"b", value=u'c', original=Original(string=u"b=c", line=2), error=False),
         ]
     ),
+    (
+        u"\n\n",
+        [
+            Binding(key=None, value=None, original=Original(string=u"\n\n", line=1), error=False),
+        ]
+    ),
+    (
+        u"a=b\n\n",
+        [
+            Binding(key=u"a", value=u"b", original=Original(string=u"a=b\n", line=1), error=False),
+            Binding(key=None, value=None, original=Original(string=u"\n", line=2), error=False),
+        ]
+    ),
     (
         u'a=b\n\nc=d',
         [

pip install -e .[cli]
parse_log_pytest
requirements.txt
pytest
3.9
requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
asttokens==3.0.0
backports.tarfile==1.2.0
bump2version==1.0.1
bumpversion==0.6.0
cachetools==5.5.2
certifi==2025.1.31
cffi==1.17.1
chardet==5.2.0
charset-normalizer==3.4.1
click==8.1.8
colorama==0.4.6
coverage==7.8.0
cryptography==44.0.2
decorator==5.2.1
distlib==0.3.9
docstring_parser==0.16
docutils==0.21.2
exceptiongroup==1.2.2
executing==2.2.0
falcon==2.0.0
filelock==3.18.0
flake8==7.2.0
ghp-import==2.1.0
gitdb==4.0.12
GitPython==3.1.44
hug==2.6.1
id==1.5.0
idna==3.10
importlib_metadata==8.6.1
iniconfig==2.1.0
ipython==8.18.1
jaraco.classes==3.4.0
jaraco.context==6.0.1
jaraco.functools==4.1.0
jedi==0.19.2
jeepney==0.9.0
Jinja2==3.1.6
keyring==25.6.0
livereload==2.7.1
Mako==1.3.9
Markdown==3.3.7
markdown-it-py==3.0.0
MarkupSafe==3.0.2
matplotlib-inline==0.1.7
mccabe==0.7.0
mdurl==0.1.2
mergedeep==1.3.4
mkdocs==1.3.1
mkdocs-material==8.5.4
mkdocs-material-extensions==1.3.1
mock==5.2.0
more-itertools==10.6.0
nh3==0.2.21
packaging==24.2
parso==0.8.4
pdocs==1.2.0
pexpect==4.9.0
platformdirs==4.3.7
pluggy==1.5.0
portray==1.8.0
prompt_toolkit==3.0.50
ptyprocess==0.7.0
pure_eval==0.2.3
pycodestyle==2.13.0
pycparser==2.22
pyflakes==3.3.1
Pygments==2.19.1
pymdown-extensions==10.4
pyproject-api==1.9.0
pytest==8.3.5
pytest-cov==6.0.0
python-dateutil==2.9.0.post0
-e git+https://github.com/theskumar/python-dotenv.git@2f58bccad26e0b728d32ec9bf9493671212dc24f#egg=python_dotenv
PyYAML==6.0.2
pyyaml_env_tag==0.1
readme_renderer==44.0
requests==2.32.3
requests-toolbelt==1.0.0
rfc3986==2.0.0
rich==14.0.0
SecretStorage==3.3.3
sh==2.2.2
six==1.17.0
smmap==5.0.2
stack-data==0.6.3
termcolor==2.5.0
toml==0.10.2
tomli==2.2.1
tornado==6.4.2
tox==4.25.0
traitlets==5.14.3
twine==6.1.0
typing_extensions==4.13.0
urllib3==2.3.0
virtualenv==20.29.3
watchdog==6.0.0
wcwidth==0.2.13
yaspin==2.5.0
zipp==3.21.0

name: python-dotenv
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:
      - asttokens==3.0.0
      - backports-tarfile==1.2.0
      - bump2version==1.0.1
      - bumpversion==0.6.0
      - cachetools==5.5.2
      - certifi==2025.1.31
      - cffi==1.17.1
      - chardet==5.2.0
      - charset-normalizer==3.4.1
      - click==8.1.8
      - colorama==0.4.6
      - coverage==7.8.0
      - cryptography==44.0.2
      - decorator==5.2.1
      - distlib==0.3.9
      - docstring-parser==0.16
      - docutils==0.21.2
      - exceptiongroup==1.2.2
      - executing==2.2.0
      - falcon==2.0.0
      - filelock==3.18.0
      - flake8==7.2.0
      - ghp-import==2.1.0
      - gitdb==4.0.12
      - gitpython==3.1.44
      - hug==2.6.1
      - id==1.5.0
      - idna==3.10
      - importlib-metadata==8.6.1
      - iniconfig==2.1.0
      - ipython==8.18.1
      - jaraco-classes==3.4.0
      - jaraco-context==6.0.1
      - jaraco-functools==4.1.0
      - jedi==0.19.2
      - jeepney==0.9.0
      - jinja2==3.1.6
      - keyring==25.6.0
      - livereload==2.7.1
      - mako==1.3.9
      - markdown==3.3.7
      - markdown-it-py==3.0.0
      - markupsafe==3.0.2
      - matplotlib-inline==0.1.7
      - mccabe==0.7.0
      - mdurl==0.1.2
      - mergedeep==1.3.4
      - mkdocs==1.3.1
      - mkdocs-material==8.5.4
      - mkdocs-material-extensions==1.3.1
      - mock==5.2.0
      - more-itertools==10.6.0
      - nh3==0.2.21
      - packaging==24.2
      - parso==0.8.4
      - pdocs==1.2.0
      - pexpect==4.9.0
      - platformdirs==4.3.7
      - pluggy==1.5.0
      - portray==1.8.0
      - prompt-toolkit==3.0.50
      - ptyprocess==0.7.0
      - pure-eval==0.2.3
      - pycodestyle==2.13.0
      - pycparser==2.22
      - pyflakes==3.3.1
      - pygments==2.19.1
      - pymdown-extensions==10.4
      - pyproject-api==1.9.0
      - pytest==8.3.5
      - pytest-cov==6.0.0
      - python-dateutil==2.9.0.post0
      - python-dotenv==0.11.0
      - pyyaml==6.0.2
      - pyyaml-env-tag==0.1
      - readme-renderer==44.0
      - requests==2.32.3
      - requests-toolbelt==1.0.0
      - rfc3986==2.0.0
      - rich==14.0.0
      - secretstorage==3.3.3
      - sh==2.2.2
      - six==1.17.0
      - smmap==5.0.2
      - stack-data==0.6.3
      - termcolor==2.5.0
      - toml==0.10.2
      - tomli==2.2.1
      - tornado==6.4.2
      - tox==4.25.0
      - traitlets==5.14.3
      - twine==6.1.0
      - typing-extensions==4.13.0
      - urllib3==2.3.0
      - virtualenv==20.29.3
      - watchdog==6.0.0
      - wcwidth==0.2.13
      - yaspin==2.5.0
      - zipp==3.21.0
prefix: /opt/conda/envs/python-dotenv

tests/test_main.py::test_set_key[a=b\n\n-a-c-expected8-a="c"\n\n] tests/test_parser.py::test_parse_stream[\n\n-expected30] tests/test_parser.py::test_parse_stream[a=b\n\n-expected31]
tests/test_main.py::test_set_key_permission_error
tests/test_main.py::test_set_key_no_file tests/test_main.py::test_set_key[-a--expected0-a=""\n] tests/test_main.py::test_set_key[-a-b-expected1-a="b"\n] tests/test_main.py::test_set_key[-a-'b'-expected2-a="b"\n] tests/test_main.py::test_set_key[-a-"b"-expected3-a="b"\n] tests/test_main.py::test_set_key[-a-b'c-expected4-a="b'c"\n] tests/test_main.py::test_set_key[-a-b"c-expected5-a="b\\"c"\n] tests/test_main.py::test_set_key[a=b-a-c-expected6-a="c"\n] tests/test_main.py::test_set_key[a=b\n-a-c-expected7-a="c"\n] tests/test_main.py::test_set_key[a=b\nc=d-a-e-expected9-a="e"\nc=d] tests/test_main.py::test_set_key[a=b\nc=d\ne=f-c-g-expected10-a=b\nc="g"\ne=f] tests/test_main.py::test_set_key[a=b\n-c-d-expected11-a=b\nc="d"\n] tests/test_main.py::test_get_key_no_file tests/test_main.py::test_get_key_not_found tests/test_main.py::test_get_key_ok tests/test_main.py::test_get_key_none tests/test_main.py::test_unset_with_value tests/test_main.py::test_unset_no_value tests/test_main.py::test_unset_non_existent_file tests/test_main.py::test_find_dotenv_no_file_raise tests/test_main.py::test_find_dotenv_no_file_no_raise tests/test_main.py::test_find_dotenv_found tests/test_main.py::test_load_dotenv_existing_file tests/test_main.py::test_load_dotenv_no_file_verbose tests/test_main.py::test_load_dotenv_existing_variable_no_override tests/test_main.py::test_load_dotenv_existing_variable_override tests/test_main.py::test_load_dotenv_utf_8 tests/test_main.py::test_load_dotenv_in_current_dir tests/test_main.py::test_dotenv_values_file tests/test_main.py::test_dotenv_values_stream[env0-a=$b-False-expected0] tests/test_main.py::test_dotenv_values_stream[env1-a=$b-True-expected1] tests/test_main.py::test_dotenv_values_stream[env2-a=${b}-False-expected2] tests/test_main.py::test_dotenv_values_stream[env3-a=${b}-True-expected3] tests/test_main.py::test_dotenv_values_stream[env4-b=c\na=${b}-True-expected4] tests/test_main.py::test_dotenv_values_stream[env5-a=${b}-True-expected5] tests/test_main.py::test_dotenv_values_stream[env6-a="${b}"-True-expected6] tests/test_main.py::test_dotenv_values_stream[env7-a='${b}'-True-expected7] tests/test_main.py::test_dotenv_values_stream[env8-a=${a}-True-expected8] tests/test_main.py::test_dotenv_values_stream[env9-a=${a}-True-expected9] tests/test_parser.py::test_parse_stream[-expected0] tests/test_parser.py::test_parse_stream[a=b-expected1] tests/test_parser.py::test_parse_stream['a'=b-expected2] tests/test_parser.py::test_parse_stream[[=b-expected3] tests/test_parser.py::test_parse_stream[ tests/test_parser.py::test_parse_stream[export tests/test_parser.py::test_parse_stream[# tests/test_parser.py::test_parse_stream[a=b#c-expected8] tests/test_parser.py::test_parse_stream[a=b tests/test_parser.py::test_parse_stream[a='b tests/test_parser.py::test_parse_stream[a="b tests/test_parser.py::test_parse_stream[a="b\nc"-expected15] tests/test_parser.py::test_parse_stream[a='b\nc'-expected16] tests/test_parser.py::test_parse_stream[a="b\nc"-expected17] tests/test_parser.py::test_parse_stream[a="b\\nc"-expected18] tests/test_parser.py::test_parse_stream[a='b\\nc'-expected19] tests/test_parser.py::test_parse_stream[a="b\\"c"-expected20] tests/test_parser.py::test_parse_stream[a='b\\'c'-expected21] tests/test_parser.py::test_parse_stream[a=\xe0-expected22] tests/test_parser.py::test_parse_stream[a="\xe0"-expected23] tests/test_parser.py::test_parse_stream[no_value_var-expected24] tests/test_parser.py::test_parse_stream[a: tests/test_parser.py::test_parse_stream[a=b\nc=d-expected26] tests/test_parser.py::test_parse_stream[a=b\rc=d-expected27] tests/test_parser.py::test_parse_stream[a=b\r\nc=d-expected28] tests/test_parser.py::test_parse_stream[a=\nb=c-expected29] tests/test_parser.py::test_parse_stream[a=b\n\nc=d-expected32] tests/test_parser.py::test_parse_stream[a="\nb=c-expected33] tests/test_parser.py::test_parse_stream[a=b\n# tests/test_parser.py::test_parse_stream[uglyKey[%$="S3cr3t_P4ssw#rD"
CHANGELOG.md src/dotenv/parser.py
CHANGELOG.md src/dotenv/parser.py