Hello community,

here is the log from the commit of package python-pytest for openSUSE:Factory 
checked in at 2020-04-19 21:42:03
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-pytest (Old)
 and      /work/SRC/openSUSE:Factory/.python-pytest.new.2738 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-pytest"

Sun Apr 19 21:42:03 2020 rev:54 rq:786286 version:5.3.5

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-pytest/python-pytest.changes      
2020-02-24 15:49:50.611129424 +0100
+++ /work/SRC/openSUSE:Factory/.python-pytest.new.2738/python-pytest.changes    
2020-04-19 21:42:18.143217933 +0200
@@ -1,0 +2,6 @@
+Wed Mar 18 07:45:23 UTC 2020 - Steve Kowalik <steven.kowa...@suse.com>
+
+- Add patch tidy-up-embeddedfile.patch based on an upstream PR. Can
+  be dropped when updating.
+
+-------------------------------------------------------------------

New:
----
  tidy-up-embeddedfile.patch

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

Other differences:
------------------
++++++ python-pytest.spec ++++++
--- /var/tmp/diff_new_pack.I327kp/_old  2020-04-19 21:42:22.115225903 +0200
+++ /var/tmp/diff_new_pack.I327kp/_new  2020-04-19 21:42:22.119225911 +0200
@@ -33,6 +33,8 @@
 License:        MIT
 URL:            https://github.com/pytest-dev/pytest
 Source:         
https://files.pythonhosted.org/packages/source/p/pytest/pytest-%{version}.tar.gz
+# UPSTREAM FIX: gh/pytest-dev#6899
+Patch0:         tidy-up-embeddedfile.patch
 BuildRequires:  %{python_module setuptools >= 40.0}
 BuildRequires:  %{python_module setuptools_scm}
 BuildRequires:  fdupes
@@ -90,6 +92,7 @@
 
 %prep
 %setup -q -n pytest-%{version}
+%autopatch -p1
 
 %build
 %python_build

++++++ tidy-up-embeddedfile.patch ++++++
>From 29e4cb5d45f44379aba948c2cd791b3b97210e31 Mon Sep 17 00:00:00 2001
From: Ran Benita <r...@unusedvar.com>
Date: Sat, 7 Mar 2020 18:38:22 +0200
Subject: [PATCH] Remove safe_text_dupfile() and simplify EncodedFile

I tried to understand what the `safe_text_dupfile()` function and
`EncodedFile` class do. Outside tests, `EncodedFile` is only used by
`safe_text_dupfile`, and `safe_text_dupfile` is only used by
`FDCaptureBinary.__init__()`. I then started to eliminate always-true
conditions based on the single call site, and in the end nothing was
left except of a couple workarounds that are still needed.
---
 src/_pytest/capture.py  | 66 ++++++++++--------------------------
 testing/test_capture.py | 75 ++++++-----------------------------------
 2 files changed, 28 insertions(+), 113 deletions(-)

Index: pytest-5.3.5/src/_pytest/capture.py
===================================================================
--- pytest-5.3.5.orig/src/_pytest/capture.py
+++ pytest-5.3.5/src/_pytest/capture.py
@@ -391,57 +391,21 @@ class CaptureFixture:
             yield
 
 
-def safe_text_dupfile(f, mode, default_encoding="UTF8"):
-    """ return an open text file object that's a duplicate of f on the
-        FD-level if possible.
-    """
-    encoding = getattr(f, "encoding", None)
-    try:
-        fd = f.fileno()
-    except Exception:
-        if "b" not in getattr(f, "mode", "") and hasattr(f, "encoding"):
-            # we seem to have a text stream, let's just use it
-            return f
-    else:
-        newfd = os.dup(fd)
-        if "b" not in mode:
-            mode += "b"
-        f = os.fdopen(newfd, mode, 0)  # no buffering
-    return EncodedFile(f, encoding or default_encoding)
-
-
-class EncodedFile:
-    errors = "strict"  # possibly needed by py3 code (issue555)
-
-    def __init__(self, buffer, encoding):
-        self.buffer = buffer
-        self.encoding = encoding
-
-    def write(self, obj):
-        if isinstance(obj, str):
-            obj = obj.encode(self.encoding, "replace")
-        else:
-            raise TypeError(
-                "write() argument must be str, not 
{}".format(type(obj).__name__)
-            )
-        self.buffer.write(obj)
-
-    def writelines(self, linelist):
-        data = "".join(linelist)
-        self.write(data)
+class EncodedFile(io.TextIOWrapper):
+    __slots__ = ()
 
     @property
     def name(self):
-        """Ensure that file.name is a string."""
+        # Ensure that file.name is a string. Workaround for a Python bug
+        # fixed in >=3.7.4: https://bugs.python.org/issue36015
         return repr(self.buffer)
 
     @property
     def mode(self):
+        # TextIOWrapper doesn't expose a mode, but at least some of our
+        # tests check it.
         return self.buffer.mode.replace("b", "")
 
-    def __getattr__(self, name):
-        return getattr(object.__getattribute__(self, "buffer"), name)
-
 
 CaptureResult = collections.namedtuple("CaptureResult", ["out", "err"])
 
@@ -555,9 +519,12 @@ class FDCaptureBinary:
                 self.syscapture = SysCapture(targetfd)
             else:
                 if tmpfile is None:
-                    f = TemporaryFile()
-                    with f:
-                        tmpfile = safe_text_dupfile(f, mode="wb+")
+                    tmpfile = EncodedFile(
+                        TemporaryFile(buffering=0),
+                        encoding="utf-8",
+                        errors="replace",
+                        write_through=True,
+                    )
                 if targetfd in patchsysdict:
                     self.syscapture = SysCapture(targetfd, tmpfile)
                 else:
@@ -582,7 +549,7 @@ class FDCaptureBinary:
 
     def snap(self):
         self.tmpfile.seek(0)
-        res = self.tmpfile.read()
+        res = self.tmpfile.buffer.read()
         self.tmpfile.seek(0)
         self.tmpfile.truncate()
         return res
@@ -624,10 +591,10 @@ class FDCapture(FDCaptureBinary):
     EMPTY_BUFFER = str()  # type: ignore
 
     def snap(self):
-        res = super().snap()
-        enc = getattr(self.tmpfile, "encoding", None)
-        if enc and isinstance(res, bytes):
-            res = str(res, enc, "replace")
+        self.tmpfile.seek(0)
+        res = self.tmpfile.read()
+        self.tmpfile.seek(0)
+        self.tmpfile.truncate()
         return res
 
 
Index: pytest-5.3.5/testing/test_capture.py
===================================================================
--- pytest-5.3.5.orig/testing/test_capture.py
+++ pytest-5.3.5/testing/test_capture.py
@@ -1,14 +1,11 @@
 import contextlib
 import io
 import os
-import pickle
 import subprocess
 import sys
 import textwrap
-from io import StringIO
 from io import UnsupportedOperation
-from typing import List
-from typing import TextIO
+from typing import BinaryIO
 
 import pytest
 from _pytest import capture
@@ -838,49 +835,6 @@ def tmpfile(testdir):
         f.close()
 
 
-@needsosdup
-def test_dupfile(tmpfile) -> None:
-    flist = []  # type: List[TextIO]
-    for i in range(5):
-        nf = capture.safe_text_dupfile(tmpfile, "wb")
-        assert nf != tmpfile
-        assert nf.fileno() != tmpfile.fileno()
-        assert nf not in flist
-        print(i, end="", file=nf)
-        flist.append(nf)
-
-    fname_open = flist[0].name
-    assert fname_open == repr(flist[0].buffer)
-
-    for i in range(5):
-        f = flist[i]
-        f.close()
-    fname_closed = flist[0].name
-    assert fname_closed == repr(flist[0].buffer)
-    assert fname_closed != fname_open
-    tmpfile.seek(0)
-    s = tmpfile.read()
-    assert "01234" in repr(s)
-    tmpfile.close()
-    assert fname_closed == repr(flist[0].buffer)
-
-
-def test_dupfile_on_bytesio():
-    bio = io.BytesIO()
-    f = capture.safe_text_dupfile(bio, "wb")
-    f.write("hello")
-    assert bio.getvalue() == b"hello"
-    assert "BytesIO object" in f.name
-
-
-def test_dupfile_on_textio():
-    sio = StringIO()
-    f = capture.safe_text_dupfile(sio, "wb")
-    f.write("hello")
-    assert sio.getvalue() == "hello"
-    assert not hasattr(f, "name")
-
-
 @contextlib.contextmanager
 def lsof_check():
     pid = os.getpid()
@@ -1299,8 +1253,8 @@ def test_error_attribute_issue555(testdi
         """
         import sys
         def test_capattr():
-            assert sys.stdout.errors == "strict"
-            assert sys.stderr.errors == "strict"
+            assert sys.stdout.errors == "replace"
+            assert sys.stderr.errors == "replace"
     """
     )
     reprec = testdir.inline_run()
@@ -1375,15 +1329,6 @@ def test_crash_on_closing_tmpfile_py27(t
     result.stdout.no_fnmatch_line("*IOError*")
 
 
-def test_pickling_and_unpickling_encoded_file():
-    # See https://bitbucket.org/pytest-dev/pytest/pull-request/194
-    # pickle.loads() raises infinite recursion if
-    # EncodedFile.__getattr__ is not implemented properly
-    ef = capture.EncodedFile(None, None)
-    ef_as_str = pickle.dumps(ef)
-    pickle.loads(ef_as_str)
-
-
 def test_global_capture_with_live_logging(testdir):
     # Issue 3819
     # capture should work with live cli logging
@@ -1489,6 +1434,19 @@ def test_typeerror_encodedfile_write(tes
     result_with_capture = testdir.runpytest(str(p))
 
     assert result_with_capture.ret == result_without_capture.ret
-    result_with_capture.stdout.fnmatch_lines(
-        ["E * TypeError: write() argument must be str, not bytes"]
+    out = result_with_capture.stdout.str()
+    assert ("TypeError: write() argument must be str, not bytes" in out) or (
+        "TypeError: unicode argument expected, got 'bytes'" in out
     )
+
+def test_encodedfile_writelines(tmpfile: BinaryIO) -> None:
+    ef = capture.EncodedFile(tmpfile, encoding="utf-8")
+    with pytest.raises(TypeError):
+        ef.writelines([b"line1", b"line2"])
+    assert ef.writelines(["line3", "line4"]) is None  # type: 
ignore[func-returns-value]  # noqa: F821
+    ef.flush()
+    tmpfile.seek(0)
+    assert tmpfile.read() == b"line3line4"
+    tmpfile.close()
+    with pytest.raises(ValueError):
+        ef.read()

Reply via email to