Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-python-dotenv for 
openSUSE:Factory checked in at 2025-09-29 16:31:04
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-python-dotenv (Old)
 and      /work/SRC/openSUSE:Factory/.python-python-dotenv.new.11973 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-python-dotenv"

Mon Sep 29 16:31:04 2025 rev:19 rq:1307324 version:1.1.1

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-python-dotenv/python-python-dotenv.changes    
    2025-08-17 14:50:15.308292674 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-python-dotenv.new.11973/python-python-dotenv.changes
     2025-09-29 16:31:30.320602276 +0200
@@ -1,0 +2,7 @@
+Fri Sep 26 08:20:06 UTC 2025 - John Paul Adrian Glaubitz 
<[email protected]>
+
+- Update to 1.1.1
+  * CLI: Ensure `find_dotenv` work reliably on python 3.13
+  * CLI: revert the use of execvpe on Windows
+
+-------------------------------------------------------------------

Old:
----
  python-dotenv-1.1.0.tar.gz

New:
----
  python-dotenv-1.1.1.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-python-dotenv.spec ++++++
--- /var/tmp/diff_new_pack.bBeFEj/_old  2025-09-29 16:31:30.976629771 +0200
+++ /var/tmp/diff_new_pack.bBeFEj/_new  2025-09-29 16:31:30.980629939 +0200
@@ -24,7 +24,7 @@
 %endif
 %{?sle15_python_module_pythons}
 Name:           python-python-dotenv
-Version:        1.1.0
+Version:        1.1.1
 Release:        0
 Summary:        Python library for .env support
 License:        BSD-3-Clause

++++++ python-dotenv-1.1.0.tar.gz -> python-dotenv-1.1.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-dotenv-1.1.0/CHANGELOG.md 
new/python-dotenv-1.1.1/CHANGELOG.md
--- old/python-dotenv-1.1.0/CHANGELOG.md        2025-03-25 11:53:46.000000000 
+0100
+++ new/python-dotenv-1.1.1/CHANGELOG.md        2025-06-24 06:17:34.000000000 
+0200
@@ -5,17 +5,27 @@
 The format is based on [Keep a 
Changelog](https://keepachangelog.com/en/1.0.0/), and this
 project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 
+## [1.1.1] - 2025-06-24
+
+## Fixed
+
+* CLI: Ensure `find_dotenv` work reliably on python 3.13 by [@theskumar] in 
[#563](https://github.com/theskumar/python-dotenv/pull/563)
+* CLI: revert the use of execvpe on Windows by [@wrongontheinternet] in 
[#566](https://github.com/theskumar/python-dotenv/pull/566)
+
 
 ## [1.1.0] - 2025-03-25
 
 **Feature**
+
 - Add support for python 3.13
 - Enhance `dotenv run`, switch to `execvpe` for better resource management and 
signal handling ([#523]) by [@eekstunt]
 
 **Fixed**
+
 - `find_dotenv` and `load_dotenv` now correctly looks up at the current 
directory when running in debugger or pdb ([#553] by [@randomseed42])
 
 **Misc**
+
 - Drop support for Python 3.8
 
 ## [1.0.1] - 2024-01-23
@@ -406,8 +416,11 @@
 [@yannham]: https://github.com/yannham
 [@zueve]: https://github.com/zueve
 [@randomseed42]: https://github.com/zueve
+[@wrongontheinternet]: https://github.com/wrongontheinternet
 
-[Unreleased]: https://github.com/theskumar/python-dotenv/compare/v1.0.1...HEAD
+[Unreleased]: https://github.com/theskumar/python-dotenv/compare/v1.1.1...HEAD
+[1.1.1]: https://github.com/theskumar/python-dotenv/compare/v1.1.0...1.1.1
+[1.1.0]: https://github.com/theskumar/python-dotenv/compare/v1.0.1...v1.1.0
 [1.0.1]: https://github.com/theskumar/python-dotenv/compare/v1.0.0...v1.0.1
 [1.0.0]: https://github.com/theskumar/python-dotenv/compare/v0.21.0...v1.0.0
 [0.21.1]: https://github.com/theskumar/python-dotenv/compare/v0.21.0...v0.21.1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-dotenv-1.1.0/setup.cfg 
new/python-dotenv-1.1.1/setup.cfg
--- old/python-dotenv-1.1.0/setup.cfg   2025-03-25 11:53:46.000000000 +0100
+++ new/python-dotenv-1.1.1/setup.cfg   2025-06-24 06:17:34.000000000 +0200
@@ -1,5 +1,5 @@
 [bumpversion]
-current_version = 1.1.0
+current_version = 1.1.1
 commit = True
 tag = True
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-dotenv-1.1.0/src/dotenv/cli.py 
new/python-dotenv-1.1.1/src/dotenv/cli.py
--- old/python-dotenv-1.1.0/src/dotenv/cli.py   2025-03-25 11:53:46.000000000 
+0100
+++ new/python-dotenv-1.1.1/src/dotenv/cli.py   2025-06-24 06:17:34.000000000 
+0200
@@ -5,6 +5,9 @@
 from contextlib import contextmanager
 from typing import Any, Dict, IO, Iterator, List, Optional
 
+if sys.platform == 'win32':
+    from subprocess import Popen
+
 try:
     import click
 except ImportError:
@@ -187,4 +190,16 @@
     cmd_env = os.environ.copy()
     cmd_env.update(env)
 
-    os.execvpe(command[0], args=command, env=cmd_env)
+    if sys.platform == 'win32':
+        # execvpe on Windows returns control immediately
+        # rather than once the command has finished.
+        p = Popen(command,
+                  universal_newlines=True,
+                  bufsize=0,
+                  shell=False,
+                  env=cmd_env)
+        _, _ = p.communicate()
+
+        exit(p.returncode)
+    else:
+        os.execvpe(command[0], args=command, env=cmd_env)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-dotenv-1.1.0/src/dotenv/main.py 
new/python-dotenv-1.1.1/src/dotenv/main.py
--- old/python-dotenv-1.1.0/src/dotenv/main.py  2025-03-25 11:53:46.000000000 
+0100
+++ new/python-dotenv-1.1.1/src/dotenv/main.py  2025-06-24 06:17:34.000000000 
+0200
@@ -286,6 +286,8 @@
 
     def _is_interactive():
         """Decide whether this is running in a REPL or IPython notebook"""
+        if hasattr(sys, "ps1") or hasattr(sys, "ps2"):
+            return True
         try:
             main = __import__("__main__", None, None, fromlist=["__file__"])
         except ModuleNotFoundError:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-dotenv-1.1.0/src/dotenv/version.py 
new/python-dotenv-1.1.1/src/dotenv/version.py
--- old/python-dotenv-1.1.0/src/dotenv/version.py       2025-03-25 
11:53:46.000000000 +0100
+++ new/python-dotenv-1.1.1/src/dotenv/version.py       2025-06-24 
06:17:34.000000000 +0200
@@ -1 +1 @@
-__version__ = "1.1.0"
+__version__ = "1.1.1"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-dotenv-1.1.0/tests/test_is_interactive.py 
new/python-dotenv-1.1.1/tests/test_is_interactive.py
--- old/python-dotenv-1.1.0/tests/test_is_interactive.py        1970-01-01 
01:00:00.000000000 +0100
+++ new/python-dotenv-1.1.1/tests/test_is_interactive.py        2025-06-24 
06:17:34.000000000 +0200
@@ -0,0 +1,227 @@
+import sys
+import builtins
+from unittest import mock
+from dotenv.main import find_dotenv
+
+
+class TestIsInteractive:
+    """Tests for the _is_interactive helper function within find_dotenv.
+
+    The _is_interactive function is used by find_dotenv to determine if the 
code
+    is running in an interactive environment (like a REPL, IPython notebook, 
etc.)
+    versus a normal script execution.
+
+    Interactive environments include:
+    - Python REPL (has sys.ps1 or sys.ps2)
+    - IPython notebooks (no __file__ in __main__)
+    - Interactive shells
+
+    Non-interactive environments include:
+    - Normal script execution (has __file__ in __main__)
+    - Module imports
+
+    Examples of the behavior:
+    >>> import sys
+    >>> # In a REPL:
+    >>> hasattr(sys, 'ps1')  # True
+    >>> # In a script:
+    >>> hasattr(sys, 'ps1')  # False
+    """
+
+    def _create_dotenv_file(self, tmp_path):
+        """Helper to create a test .env file."""
+        dotenv_path = tmp_path / ".env"
+        dotenv_path.write_text("TEST=value")
+        return dotenv_path
+
+    def _setup_subdir_and_chdir(self, tmp_path, monkeypatch):
+        """Helper to create subdirectory and change to it."""
+        test_dir = tmp_path / "subdir"
+        test_dir.mkdir()
+        monkeypatch.chdir(test_dir)
+        return test_dir
+
+    def _remove_ps_attributes(self, monkeypatch):
+        """Helper to remove ps1/ps2 attributes if they exist."""
+        if hasattr(sys, "ps1"):
+            monkeypatch.delattr(sys, "ps1")
+        if hasattr(sys, "ps2"):
+            monkeypatch.delattr(sys, "ps2")
+
+    def _mock_main_import(self, monkeypatch, mock_main_module):
+        """Helper to mock __main__ module import."""
+        original_import = builtins.__import__
+
+        def mock_import(name, *args, **kwargs):
+            if name == "__main__":
+                return mock_main_module
+            return original_import(name, *args, **kwargs)
+
+        monkeypatch.setattr(builtins, "__import__", mock_import)
+
+    def _mock_main_import_error(self, monkeypatch):
+        """Helper to mock __main__ module import that raises 
ModuleNotFoundError."""
+        original_import = builtins.__import__
+
+        def mock_import(name, *args, **kwargs):
+            if name == "__main__":
+                raise ModuleNotFoundError("No module named '__main__'")
+            return original_import(name, *args, **kwargs)
+
+        monkeypatch.setattr(builtins, "__import__", mock_import)
+
+    def test_is_interactive_with_ps1(self, tmp_path, monkeypatch):
+        """Test that _is_interactive returns True when sys.ps1 exists."""
+        dotenv_path = self._create_dotenv_file(tmp_path)
+
+        # Mock sys.ps1 to simulate interactive shell
+        monkeypatch.setattr(sys, "ps1", ">>> ", raising=False)
+
+        self._setup_subdir_and_chdir(tmp_path, monkeypatch)
+
+        # When _is_interactive() returns True, find_dotenv should search from 
cwd
+        result = find_dotenv()
+        assert result == str(dotenv_path)
+
+    def test_is_interactive_with_ps2(self, tmp_path, monkeypatch):
+        """Test that _is_interactive returns True when sys.ps2 exists."""
+        dotenv_path = self._create_dotenv_file(tmp_path)
+
+        # Mock sys.ps2 to simulate multi-line interactive input
+        monkeypatch.setattr(sys, "ps2", "... ", raising=False)
+
+        self._setup_subdir_and_chdir(tmp_path, monkeypatch)
+
+        # When _is_interactive() returns True, find_dotenv should search from 
cwd
+        result = find_dotenv()
+        assert result == str(dotenv_path)
+
+    def test_is_interactive_main_module_not_found(self, tmp_path, monkeypatch):
+        """Test that _is_interactive returns False when __main__ module import 
fails."""
+        self._remove_ps_attributes(monkeypatch)
+        self._mock_main_import_error(monkeypatch)
+
+        # Change to directory and test
+        monkeypatch.chdir(tmp_path)
+
+        # Since _is_interactive() returns False, find_dotenv should not find 
anything
+        # without usecwd=True
+        result = find_dotenv()
+        assert result == ""
+
+    def test_is_interactive_main_without_file(self, tmp_path, monkeypatch):
+        """Test that _is_interactive returns True when __main__ has no 
__file__ attribute."""
+        self._remove_ps_attributes(monkeypatch)
+        dotenv_path = self._create_dotenv_file(tmp_path)
+
+        # Mock __main__ module without __file__ attribute
+        mock_main = mock.MagicMock()
+        del mock_main.__file__  # Remove __file__ attribute
+
+        self._mock_main_import(monkeypatch, mock_main)
+        self._setup_subdir_and_chdir(tmp_path, monkeypatch)
+
+        # When _is_interactive() returns True, find_dotenv should search from 
cwd
+        result = find_dotenv()
+        assert result == str(dotenv_path)
+
+    def test_is_interactive_main_with_file(self, tmp_path, monkeypatch):
+        """Test that _is_interactive returns False when __main__ has __file__ 
attribute."""
+        self._remove_ps_attributes(monkeypatch)
+
+        # Mock __main__ module with __file__ attribute
+        mock_main = mock.MagicMock()
+        mock_main.__file__ = "/path/to/script.py"
+
+        self._mock_main_import(monkeypatch, mock_main)
+
+        # Change to directory and test
+        monkeypatch.chdir(tmp_path)
+
+        # Since _is_interactive() returns False, find_dotenv should not find 
anything
+        # without usecwd=True
+        result = find_dotenv()
+        assert result == ""
+
+    def test_is_interactive_precedence_ps1_over_main(self, tmp_path, 
monkeypatch):
+        """Test that ps1/ps2 attributes take precedence over __main__ module 
check."""
+        dotenv_path = self._create_dotenv_file(tmp_path)
+
+        # Set ps1 attribute
+        monkeypatch.setattr(sys, "ps1", ">>> ", raising=False)
+
+        # Mock __main__ module with __file__ attribute (which would normally 
return False)
+        mock_main = mock.MagicMock()
+        mock_main.__file__ = "/path/to/script.py"
+
+        self._mock_main_import(monkeypatch, mock_main)
+        self._setup_subdir_and_chdir(tmp_path, monkeypatch)
+
+        # ps1 should take precedence, so _is_interactive() returns True
+        result = find_dotenv()
+        assert result == str(dotenv_path)
+
+    def test_is_interactive_ps1_and_ps2_both_exist(self, tmp_path, 
monkeypatch):
+        """Test that _is_interactive returns True when both ps1 and ps2 
exist."""
+        dotenv_path = self._create_dotenv_file(tmp_path)
+
+        # Set both ps1 and ps2 attributes
+        monkeypatch.setattr(sys, "ps1", ">>> ", raising=False)
+        monkeypatch.setattr(sys, "ps2", "... ", raising=False)
+
+        self._setup_subdir_and_chdir(tmp_path, monkeypatch)
+
+        # Should return True with either attribute present
+        result = find_dotenv()
+        assert result == str(dotenv_path)
+
+    def test_is_interactive_main_module_with_file_attribute_none(self, 
tmp_path, monkeypatch):
+        """Test _is_interactive when __main__ has __file__ attribute set to 
None."""
+        self._remove_ps_attributes(monkeypatch)
+
+        # Mock __main__ module with __file__ = None
+        mock_main = mock.MagicMock()
+        mock_main.__file__ = None
+
+        self._mock_main_import(monkeypatch, mock_main)
+
+        # Mock sys.gettrace to ensure debugger detection returns False
+        monkeypatch.setattr("sys.gettrace", lambda: None)
+
+        monkeypatch.chdir(tmp_path)
+
+        # __file__ = None should still be considered non-interactive
+        # and with no debugger, find_dotenv should not search from cwd
+        result = find_dotenv()
+        assert result == ""
+
+    def test_is_interactive_no_ps_attributes_and_normal_execution(self, 
tmp_path, monkeypatch):
+        """Test normal script execution scenario where _is_interactive should 
return False."""
+        self._remove_ps_attributes(monkeypatch)
+
+        # Don't mock anything - let it use the real __main__ module
+        # which should have a __file__ attribute in normal execution
+
+        # Change to directory and test
+        monkeypatch.chdir(tmp_path)
+
+        # In normal execution, _is_interactive() should return False
+        # so find_dotenv should not find anything without usecwd=True
+        result = find_dotenv()
+        assert result == ""
+
+    def test_is_interactive_with_usecwd_override(self, tmp_path, monkeypatch):
+        """Test that usecwd=True overrides _is_interactive behavior."""
+        self._remove_ps_attributes(monkeypatch)
+        dotenv_path = self._create_dotenv_file(tmp_path)
+
+        # Mock __main__ module with __file__ attribute (non-interactive)
+        mock_main = mock.MagicMock()
+        mock_main.__file__ = "/path/to/script.py"
+
+        self._mock_main_import(monkeypatch, mock_main)
+        self._setup_subdir_and_chdir(tmp_path, monkeypatch)
+
+        # Even though _is_interactive() returns False, usecwd=True should find 
the file
+        result = find_dotenv(usecwd=True)
+        assert result == str(dotenv_path)

Reply via email to