Your message dated Sat, 05 Dec 2020 15:30:05 +1100
with message-id <3229423.5iYIh5gStg@simurgh>
and subject line Re: Bug#642020: python-debian: ArFile (via DebFile) errors 
when given only a fileobj
has caused the Debian Bug report #642020,
regarding python-debian: ArFile (via DebFile) errors when given only a fileobj
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact [email protected]
immediately.)


-- 
642020: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=642020
Debian Bug Tracking System
Contact [email protected] with problems
--- Begin Message ---
Package: python-debian
Version: 0.1.14ubuntu2
Severity: normal
Tags: patch

Currently (tested using trunk), ArFile assumes that it will always receive a 
filename, and that filename relates to the local filesystem.
This means that, when instantiating a DebFile using only a fileobj parameter, 
you get something like:

>>> from debian import debfile
>>> package = debfile.DebFile(fileobj=open('some-package.deb', 'r'))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File 
"/usr/local/lib/python2.6/dist-packages/python_debian-_CHANGELOG_VERSION_-py2.6.egg/debian/debfile.py",
 line 236, in __init__
    self.__version = f.read().strip()
  File 
"/usr/local/lib/python2.6/dist-packages/python_debian-_CHANGELOG_VERSION_-py2.6.egg/debian/arfile.py",
 line 211, in read
    self.__fp = open(self.__fname, "r")
TypeError: coercing to Unicode: need string or buffer, NoneType found

The solution I've come up with will involve DebFile sharing the fileobj among 
several ArFile instances (is there a way to clone file-like objects?), which 
means ArFiles keep an internal seek-location, and don't actually close() the 
file pointer (leaky?).

A patch should be attached, or there is my fork on GitHub:
https://github.com/Raumkraut/python-debian



-- System Information:
Debian Release: squeeze/sid
  APT prefers lucid-updates
  APT policy: (500, 'lucid-updates'), (500, 'lucid-security'), (500, 'lucid')
Architecture: i386 (i686)

Kernel: Linux 2.6.32-33-generic-pae (SMP w/2 CPU cores)
Locale: LANG=en_GB.utf8, LC_CTYPE=en_GB.utf8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash

Versions of packages python-debian depends on:
ii  python                 2.6.5-0ubuntu1    An interactive high-level object-o
ii  python-apt             0.7.94.2ubuntu6.4 Python interface to libapt-pkg
ii  python-support         1.0.4ubuntu1      automated rebuilding support for P

python-debian recommends no packages.

Versions of packages python-debian suggests:
ii  gpgv                     1.4.10-2ubuntu1 GNU privacy guard - signature veri
diff --git a/lib/debian/arfile.py b/lib/debian/arfile.py
index 9ad757e..d881e5f 100644
--- a/lib/debian/arfile.py
+++ b/lib/debian/arfile.py
@@ -159,6 +159,7 @@ class ArMember(object):
         self.__fp = None        # file pointer 
         self.__offset = None    # start-of-data offset
         self.__end = None       # end-of-data offset
+        self.__cur = None       # current seek-location (for shared fp)
 
     def from_file(fp, fname):
         """fp is an open File object positioned on a valid file header inside
@@ -198,51 +199,68 @@ class ArMember(object):
         f.__fname = fname
         f.__offset = fp.tell() # start-of-data
         f.__end = f.__offset + f.__size
-
+        
+        if fname is None:
+            f.__fp = fp
+        f.__cur = f.__offset
+        
         return f
 
     from_file = staticmethod(from_file)
     
-    # file interface
-
-    # XXX this is not a sequence like file objects
-    def read(self, size=0):
+    def _init_fp(self):
+        """Readies the file pointer. """
         if self.__fp is None:
+            # We have just a filename, so open it (one time)
             self.__fp = open(self.__fname, "r")
             self.__fp.seek(self.__offset)
+            
+        elif self.__fname is None:
+            # Nameless (possibly shared) file-like object
+            self.__fp.seek(self.__cur)
+    
+    def _update_cur(self):
+        """Update our current position. """
+        self.__cur = self.__fp.tell()
+        
+    # file interface
 
-        cur = self.__fp.tell()
-
-        if size > 0 and size <= self.__end - cur: # there's room
-            return self.__fp.read(size)
+    # XXX this is not a sequence like file objects
+    def read(self, size=0):
+        self._init_fp()
 
-        if cur >= self.__end or cur < self.__offset:
-            return ''
+        if size > 0 and size <= self.__end - self.__cur: # there's room
+            ret = self.__fp.read(size)
 
-        return self.__fp.read(self.__end - cur)
+        elif self.__cur >= self.__end or self.__cur < self.__offset:
+            ret = ''
+            
+        else:
+            ret = self.__fp.read(self.__end - self.__cur)
+            
+        self._update_cur()
+        return ret
 
     def readline(self, size=None):
-        if self.__fp is None:
-            self.__fp = open(self.__fname, "r")
-            self.__fp.seek(self.__offset)
-
+        self._init_fp()
+        
         if size is not None: 
             buf = self.__fp.readline(size)
-            if self.__fp.tell() > self.__end:
+            self._update_cur()
+            if self.__cur > self.__end:
                 return ''
 
             return buf
 
         buf = self.__fp.readline()
-        if self.__fp.tell() > self.__end:
+        self._update_cur()
+        if self.__cur > self.__end:
             return ''
         else:
             return buf
 
     def readlines(self, sizehint=0):
-        if self.__fp is None:
-            self.__fp = open(self.__fname, "r")
-            self.__fp.seek(self.__offset)
+        self._init_fp()
         
         buf = None
         lines = []
@@ -255,11 +273,9 @@ class ArMember(object):
         return lines
 
     def seek(self, offset, whence=0):
-        if self.__fp is None:
-            self.__fp = open(self.__fname, "r")
-            self.__fp.seek(self.__offset)
+        self._init_fp()
 
-        if self.__fp.tell() < self.__offset:
+        if self.__cur < self.__offset:
             self.__fp.seek(self.__offset)
 
         if whence < 2 and offset + self.__fp.tell() < self.__offset:
@@ -271,20 +287,21 @@ class ArMember(object):
             self.__fp.seek(self.__offset + offset, 0)
         elif whence == 2:
             self.__fp.seek(self.__end + offset, 0)
+        
+        self._update_cur()
 
     def tell(self):
-        if self.__fp is None:
-            self.__fp = open(self.__fname, "r")
-            self.__fp.seek(self.__offset)
+        self._init_fp()
 
-        cur = self.__fp.tell()
-        
-        if cur < self.__offset:
+        if self.__cur < self.__offset:
             return 0L
         else:
-            return cur - self.__offset
+            return self.__cur - self.__offset
 
     def close(self):
+        if self.__fname is None:
+            # NB. self.__fp might be shared. Leaky to never explicitly close?
+            return
         if self.__fp is not None:
             self.__fp.close()
    
diff --git a/tests/test_debfile.py b/tests/test_debfile.py
index b37dfd7..1385cc4 100755
--- a/tests/test_debfile.py
+++ b/tests/test_debfile.py
@@ -98,6 +98,11 @@ class TestArFile(unittest.TestCase):
             m.close()
             f.close()
 
+class TestArFileObj(TestArFile):
+    def setUp(self):
+        TestArFile.setUp(self)
+        self.a = arfile.ArFile(fileobj=open("test.ar", "r"))
+        
 class TestDebFile(unittest.TestCase):
 
     def setUp(self):

--- End Message ---
--- Begin Message ---
Version: 0.1.36

Hi Mel & Simon

returning to this bug once again some years later, I think using fileobj with 
DebFile is actually supported from version 0.1.36:

In [1]: from debian import debfile

In [2]: package = debfile.DebFile(filename=None, 
fileobj=open('python3-debian_0.1.37_all.deb', 'rb'))

In [3]: package.changelog().author
Out[3]: 'Stuart Prescott <[email protected]>'

In [4]: 
package.data.get_content('/usr/share/doc/python3-debian/README.rst').splitlines()[0:3]
Out[4]: 
[b'The `debian` Python modules work with Debian-related data formats,',
 b'providing a means to read data from files involved in Debian packaging,',
 b'and the distribution of Debian packages. The ability to create or edit']

Thanks for your contribution to Debian!

cheers
Stuart

-- 
Stuart Prescott    http://www.nanonanonano.net/   [email protected]
Debian Developer   http://www.debian.org/         [email protected]
GPG fingerprint    90E2 D2C1 AD14 6A1B 7EBB 891D BBC1 7EBB 1396 F2F7

--- End Message ---
-- 
https://alioth-lists.debian.net/cgi-bin/mailman/listinfo/pkg-python-debian-maint

Reply via email to