From 628d7caf9ca6ee819398a4b88c23e42094fe2c10 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Thu, 10 Nov 2011 17:20:58 +0100 Subject: fix build against apt in experimental --- python/tag.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'python/tag.cc') diff --git a/python/tag.cc b/python/tag.cc index 94554400..3996af8e 100644 --- a/python/tag.cc +++ b/python/tag.cc @@ -26,6 +26,7 @@ #include "apt_pkgmodule.h" #include +#include #include #include -- cgit v1.2.3 From 7e0a6a8421d0b1de85a69fad80c24b494385a1bf Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Fri, 3 Feb 2012 13:46:08 +0100 Subject: * python/tag.cc, tests/test_tagfile.py: - add support a filename argument in apt_pkg.TagFile() (in addition to the file object currently supported) --- debian/changelog | 3 +++ python/tag.cc | 44 +++++++++++++++++++++++++++++++++++--------- tests/test_tagfile.py | 30 +++++++++++++++--------------- 3 files changed, 53 insertions(+), 24 deletions(-) (limited to 'python/tag.cc') diff --git a/debian/changelog b/debian/changelog index 89c07119..5813656a 100644 --- a/debian/changelog +++ b/debian/changelog @@ -10,6 +10,9 @@ python-apt (0.8.4) UNRELEASED; urgency=low * tests/test_tagfile.py: - add test for apt_pkg.TagFile() both for compressed/uncompressed files + * python/tag.cc, tests/test_tagfile.py: + - add support a filename argument in apt_pkg.TagFile() (in addition + to the file object currently supported) -- Michael Vogt Wed, 04 Jan 2012 12:07:48 +0100 diff --git a/python/tag.cc b/python/tag.cc index 3996af8e..b680dc02 100644 --- a/python/tag.cc +++ b/python/tag.cc @@ -390,24 +390,50 @@ PyObject *ParseSection(PyObject *self,PyObject *Args) static PyObject *TagFileNew(PyTypeObject *type,PyObject *Args,PyObject *kwds) { + TagFileData *New; PyObject *File; + char *kwlist[] = {"file", 0}; if (PyArg_ParseTupleAndKeywords(Args,kwds,"O",kwlist,&File) == 0) return 0; - int fileno = PyObject_AsFileDescriptor(File); - if (fileno == -1) + + // check if we got a filename or a file object + int fileno = -1; + const char *filename = NULL; + if (PyString_Check(File)) + filename = PyObject_AsString(File); + else + fileno = PyObject_AsFileDescriptor(File); + + // handle invalid arguments + if (fileno == -1 && filename == NULL) + { + PyErr_SetString(PyExc_TypeError, + "Argument must be string, fd or have a fileno() method"); return 0; + } - TagFileData *New = (TagFileData*)type->tp_alloc(type, 0); + if (fileno > 0) + { + New = (TagFileData*)type->tp_alloc(type, 0); #ifdef APT_HAS_GZIP - new (&New->Fd) FileFd(); - New->Fd.OpenDescriptor(fileno, FileFd::ReadOnlyGzip, false); + new (&New->Fd) FileFd(); + New->Fd.OpenDescriptor(fileno, FileFd::ReadOnlyGzip, false); #else - new (&New->Fd) FileFd(fileno,false); + new (&New->Fd) FileFd(fileno,false); #endif - New->Owner = File; - Py_INCREF(New->Owner); - new (&New->Object) pkgTagFile(&New->Fd); + New->Owner = File; + Py_INCREF(New->Owner); + new (&New->Object) pkgTagFile(&New->Fd); + } + else + { + New = (TagFileData*)type->tp_alloc(type, 0); + new (&New->Fd) FileFd(filename, FileFd::ReadOnly, FileFd::Extension, false); + New->Owner = File; + Py_INCREF(New->Owner); + new (&New->Object) pkgTagFile(&New->Fd); + } // Create the section New->Section = (TagSecData*)(&PyTagSection_Type)->tp_alloc(&PyTagSection_Type, 0); diff --git a/tests/test_tagfile.py b/tests/test_tagfile.py index b14dd9b4..371cc6ee 100644 --- a/tests/test_tagfile.py +++ b/tests/test_tagfile.py @@ -7,6 +7,7 @@ # notice and this notice are preserved. """Unit tests for verifying the correctness of apt_pkg.TagFile""" +import glob import os import unittest @@ -21,22 +22,21 @@ class TestTagFile(unittest.TestCase): def test_tag_file(self): basepath = os.path.dirname(__file__) - tagfilepath = os.path.join( - basepath, "./data/tagfile/history.log") - tagfile = apt_pkg.TagFile(open(tagfilepath)) - for i, stanza in enumerate(tagfile): - pass - self.assertEqual(i, 2) + tagfilepath = os.path.join(basepath, "./data/tagfile/*") + # test once for compressed and uncompressed + for testfile in glob.glob(tagfilepath): + # test once using the open() method and once using the path + for f in [testfile, open(testfile)]: + tagfile = apt_pkg.TagFile(f) + for i, stanza in enumerate(tagfile): + pass + self.assertEqual(i, 2) - def test_tag_file_compressed(self): - basepath = os.path.dirname(__file__) - tagfilepath = os.path.join( - basepath, "./data/tagfile/history.1.log.gz") - tagfile = apt_pkg.TagFile(open(tagfilepath)) - for i, stanza in enumerate(tagfile): - #print stanza - pass - self.assertEqual(i, 2) + def test_errors(self): + # Raises SystemError via lbiapt + self.assertRaises(SystemError, apt_pkg.TagFile, "not-there-no-no") + # Raises Type error + self.assertRaises(TypeError, apt_pkg.TagFile, object()) if __name__ == "__main__": unittest.main() -- cgit v1.2.3 From e93ad4643202b6227ea9e4ab765cbb272c9d2413 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Mon, 6 Feb 2012 14:48:51 +0100 Subject: python/tag.cc: cleanup --- python/tag.cc | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'python/tag.cc') diff --git a/python/tag.cc b/python/tag.cc index b680dc02..88a48df9 100644 --- a/python/tag.cc +++ b/python/tag.cc @@ -413,27 +413,23 @@ static PyObject *TagFileNew(PyTypeObject *type,PyObject *Args,PyObject *kwds) return 0; } + New = (TagFileData*)type->tp_alloc(type, 0); if (fileno > 0) { - New = (TagFileData*)type->tp_alloc(type, 0); #ifdef APT_HAS_GZIP new (&New->Fd) FileFd(); New->Fd.OpenDescriptor(fileno, FileFd::ReadOnlyGzip, false); #else new (&New->Fd) FileFd(fileno,false); #endif - New->Owner = File; - Py_INCREF(New->Owner); - new (&New->Object) pkgTagFile(&New->Fd); } else { - New = (TagFileData*)type->tp_alloc(type, 0); new (&New->Fd) FileFd(filename, FileFd::ReadOnly, FileFd::Extension, false); - New->Owner = File; - Py_INCREF(New->Owner); - new (&New->Object) pkgTagFile(&New->Fd); } + New->Owner = File; + Py_INCREF(New->Owner); + new (&New->Object) pkgTagFile(&New->Fd); // Create the section New->Section = (TagSecData*)(&PyTagSection_Type)->tp_alloc(&PyTagSection_Type, 0); -- cgit v1.2.3 From 3514672ed2a333eb6791d425ebe59b883cf8d349 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Mon, 6 Feb 2012 14:55:25 +0100 Subject: python/tag.cc: make it build with older apt versions too --- python/tag.cc | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'python/tag.cc') diff --git a/python/tag.cc b/python/tag.cc index 88a48df9..49f53c31 100644 --- a/python/tag.cc +++ b/python/tag.cc @@ -425,7 +425,12 @@ static PyObject *TagFileNew(PyTypeObject *type,PyObject *Args,PyObject *kwds) } else { + // FileFd::Extension got added in this revision +#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR >= 12) new (&New->Fd) FileFd(filename, FileFd::ReadOnly, FileFd::Extension, false); +#else + new (&New->Fd) FileFd(filename, FileFd::ReadOnly, false); +#endif } New->Owner = File; Py_INCREF(New->Owner); -- cgit v1.2.3 From fd7d70ceeec91861e9ded9a7f01df0a978dcbaa5 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Fri, 15 Jun 2012 23:16:30 +0200 Subject: Merge patch from Colin Watson to handle non-UTF8 tag files in Python 3, by using bytes instead of str when requested; and document this in the RST documentation (Closes: #656288) --- debian/changelog | 5 ++ doc/source/library/apt_pkg.rst | 6 +- python/tag.cc | 128 +++++++++++++++++++++++++++++++---------- tests/test_tagfile.py | 93 +++++++++++++++++++++++++++++- 4 files changed, 201 insertions(+), 31 deletions(-) (limited to 'python/tag.cc') diff --git a/debian/changelog b/debian/changelog index f04326eb..60a573f0 100644 --- a/debian/changelog +++ b/debian/changelog @@ -35,6 +35,11 @@ python-apt (0.8.5) UNRELEASED; urgency=low * po/sl.po: Slovenian translation updated by Matej Urbančič * po/tl.po: Tagalog translation updated by Ariel S. Betan + [ Julian Andres Klode ] + * Merge patch from Colin Watson to handle non-UTF8 tag files in + Python 3, by using bytes instead of str when requested; and + document this in the RST documentation (Closes: #656288) + -- Michael Vogt Tue, 17 Apr 2012 14:09:24 +0200 python-apt (0.8.4) unstable; urgency=low diff --git a/doc/source/library/apt_pkg.rst b/doc/source/library/apt_pkg.rst index bba7491f..b5ee1a53 100644 --- a/doc/source/library/apt_pkg.rst +++ b/doc/source/library/apt_pkg.rst @@ -1904,7 +1904,7 @@ thereof and provides a function :func:`RewriteSection` which takes a :class:`TagSection()` object and sorting information and outputs a sorted section as a string. -.. class:: TagFile(file) +.. class:: TagFile(file, bytes: bool = False) An object which represents a typical debian control file. Can be used for Packages, Sources, control, Release, etc. Such an object provides two @@ -1921,6 +1921,10 @@ section as a string. .. versionchanged:: 0.7.100 Added support for using gzip files, via :class:`gzip.GzipFile` or any file containing a compressed gzip stream. + + .. versionadded:: 0.8.5 + + Added support for using bytes instead of str in Python 3 .. method:: next() diff --git a/python/tag.cc b/python/tag.cc index 49f53c31..bf79debf 100644 --- a/python/tag.cc +++ b/python/tag.cc @@ -38,6 +38,10 @@ using namespace std; struct TagSecData : public CppPyObject { char *Data; + bool Bytes; +#if PY_MAJOR_VERSION >= 3 + PyObject *Encoding; +#endif }; // The owner of the TagFile is a Python file object. @@ -45,6 +49,10 @@ struct TagFileData : public CppPyObject { TagSecData *Section; FileFd Fd; + bool Bytes; +#if PY_MAJOR_VERSION >= 3 + PyObject *Encoding; +#endif }; // Traversal and Clean for owned objects @@ -60,6 +68,35 @@ int TagFileClear(PyObject *self) { return 0; } +// Helpers to return Unicode or bytes as appropriate. +#if PY_MAJOR_VERSION < 3 +#define TagSecString_FromStringAndSize(self, v, len) \ + PyString_FromStringAndSize((v), (len)) +#define TagSecString_FromString(self, v) PyString_FromString(v) +#else +PyObject *TagSecString_FromStringAndSize(PyObject *self, const char *v, + Py_ssize_t len) { + TagSecData *Self = (TagSecData *)self; + if (Self->Bytes) + return PyBytes_FromStringAndSize(v, len); + else if (Self->Encoding) + return PyUnicode_Decode(v, len, PyUnicode_AsString(Self->Encoding), 0); + else + return PyUnicode_FromStringAndSize(v, len); +} + +PyObject *TagSecString_FromString(PyObject *self, const char *v) { + TagSecData *Self = (TagSecData *)self; + if (Self->Bytes) + return PyBytes_FromString(v); + else if (Self->Encoding) + return PyUnicode_Decode(v, strlen(v), + PyUnicode_AsString(Self->Encoding), 0); + else + return PyUnicode_FromString(v); +} +#endif + /*}}}*/ // TagSecFree - Free a Tag Section /*{{{*/ @@ -107,9 +144,9 @@ static PyObject *TagSecFind(PyObject *Self,PyObject *Args) { if (Default == 0) Py_RETURN_NONE; - return PyString_FromString(Default); + return TagSecString_FromString(Self,Default); } - return PyString_FromStringAndSize(Start,Stop-Start); + return TagSecString_FromStringAndSize(Self,Start,Stop-Start); } static char *doc_FindRaw = @@ -128,14 +165,14 @@ static PyObject *TagSecFindRaw(PyObject *Self,PyObject *Args) { if (Default == 0) Py_RETURN_NONE; - return PyString_FromString(Default); + return TagSecString_FromString(Self,Default); } const char *Start; const char *Stop; GetCpp(Self).Get(Start,Stop,Pos); - return PyString_FromStringAndSize(Start,Stop-Start); + return TagSecString_FromStringAndSize(Self,Start,Stop-Start); } static char *doc_FindFlag = @@ -161,21 +198,18 @@ static PyObject *TagSecFindFlag(PyObject *Self,PyObject *Args) // Map access, operator [] static PyObject *TagSecMap(PyObject *Self,PyObject *Arg) { - if (PyString_Check(Arg) == 0) - { - PyErr_SetNone(PyExc_TypeError); + const char *Name = PyObject_AsString(Arg); + if (Name == 0) return 0; - } - const char *Start; const char *Stop; - if (GetCpp(Self).Find(PyString_AsString(Arg),Start,Stop) == false) + if (GetCpp(Self).Find(Name,Start,Stop) == false) { - PyErr_SetString(PyExc_KeyError,PyString_AsString(Arg)); + PyErr_SetString(PyExc_KeyError,Name); return 0; } - return PyString_FromStringAndSize(Start,Stop-Start); + return TagSecString_FromStringAndSize(Self,Start,Stop-Start); } // len() operation @@ -230,9 +264,9 @@ static PyObject *TagSecExists(PyObject *Self,PyObject *Args) static int TagSecContains(PyObject *Self,PyObject *Arg) { - if (PyString_Check(Arg) == 0) - return 0; - const char *Name = PyString_AsString(Arg); + const char *Name = PyObject_AsString(Arg); + if (Name == 0) + return 0; const char *Start; const char *Stop; if (GetCpp(Self).Find(Name,Start,Stop) == false) @@ -256,7 +290,7 @@ static PyObject *TagSecStr(PyObject *Self) const char *Start; const char *Stop; GetCpp(Self).GetSection(Start,Stop); - return PyString_FromStringAndSize(Start,Stop-Start); + return TagSecString_FromStringAndSize(Self,Start,Stop-Start); } /*}}}*/ // TagFile Wrappers /*{{{*/ @@ -286,6 +320,12 @@ static PyObject *TagFileNext(PyObject *Self) Obj.Section->Owner = Self; Py_INCREF(Obj.Section->Owner); Obj.Section->Data = 0; + Obj.Section->Bytes = Obj.Bytes; +#if PY_MAJOR_VERSION >= 3 + // We don't need to incref Encoding as the previous Section object already + // held a reference to it. + Obj.Section->Encoding = Obj.Encoding; +#endif if (Obj.Object.Step(Obj.Section->Object) == false) return HandleErrors(NULL); @@ -347,11 +387,12 @@ static PyObject *TagFileJump(PyObject *Self,PyObject *Args) static PyObject *TagSecNew(PyTypeObject *type,PyObject *Args,PyObject *kwds) { char *Data; int Len; - char *kwlist[] = {"text", 0}; + char Bytes = 0; + char *kwlist[] = {"text", "bytes", 0}; // this allows reading "byte" types from python3 - but we don't // make (much) use of it yet - if (PyArg_ParseTupleAndKeywords(Args,kwds,"s#",kwlist,&Data,&Len) == 0) + if (PyArg_ParseTupleAndKeywords(Args,kwds,"s#|b",kwlist,&Data,&Len,&Bytes) == 0) return 0; // Create the object.. @@ -359,6 +400,10 @@ static PyObject *TagSecNew(PyTypeObject *type,PyObject *Args,PyObject *kwds) { new (&New->Object) pkgTagSection(); New->Data = new char[strlen(Data)+2]; snprintf(New->Data,strlen(Data)+2,"%s\n",Data); + New->Bytes = Bytes; +#if PY_MAJOR_VERSION >= 3 + New->Encoding = 0; +#endif if (New->Object.Scan(New->Data,strlen(New->Data)) == false) { @@ -391,19 +436,21 @@ PyObject *ParseSection(PyObject *self,PyObject *Args) static PyObject *TagFileNew(PyTypeObject *type,PyObject *Args,PyObject *kwds) { TagFileData *New; - PyObject *File; + PyObject *File = 0; + char Bytes = 0; - char *kwlist[] = {"file", 0}; - if (PyArg_ParseTupleAndKeywords(Args,kwds,"O",kwlist,&File) == 0) + char *kwlist[] = {"file", "bytes", 0}; + if (PyArg_ParseTupleAndKeywords(Args,kwds,"O|b",kwlist,&File,&Bytes) == 0) return 0; // check if we got a filename or a file object int fileno = -1; const char *filename = NULL; - if (PyString_Check(File)) - filename = PyObject_AsString(File); - else + filename = PyObject_AsString(File); + if (filename == NULL) { + PyErr_Clear(); fileno = PyObject_AsFileDescriptor(File); + } // handle invalid arguments if (fileno == -1 && filename == NULL) @@ -432,8 +479,18 @@ static PyObject *TagFileNew(PyTypeObject *type,PyObject *Args,PyObject *kwds) new (&New->Fd) FileFd(filename, FileFd::ReadOnly, false); #endif } + New->Bytes = Bytes; New->Owner = File; Py_INCREF(New->Owner); +#if PY_MAJOR_VERSION >= 3 + if (fileno > 0) { + New->Encoding = PyObject_GetAttr(File, PyUnicode_FromString("encoding")); + if (New->Encoding && !PyUnicode_Check(New->Encoding)) + New->Encoding = 0; + } else + New->Encoding = 0; + Py_XINCREF(New->Encoding); +#endif new (&New->Object) pkgTagFile(&New->Fd); // Create the section @@ -442,6 +499,11 @@ static PyObject *TagFileNew(PyTypeObject *type,PyObject *Args,PyObject *kwds) New->Section->Owner = New; Py_INCREF(New->Section->Owner); New->Section->Data = 0; + New->Section->Bytes = Bytes; +#if PY_MAJOR_VERSION >= 3 + New->Section->Encoding = New->Encoding; + Py_XINCREF(New->Section->Encoding); +#endif return HandleErrors(New); } @@ -519,7 +581,7 @@ PyObject *RewriteSection(PyObject *self,PyObject *Args) } // Return the string - PyObject *ResObj = PyString_FromStringAndSize(bp,size); + PyObject *ResObj = TagSecString_FromStringAndSize(Section,bp,size); free(bp); return HandleErrors(ResObj); } @@ -548,11 +610,15 @@ PySequenceMethods TagSecSeqMeth = {0,0,0,0,0,0,0,TagSecContains,0,0}; PyMappingMethods TagSecMapMeth = {TagSecLength,TagSecMap,0}; -static char *doc_TagSec = "TagSection(text: str)\n\n" +static char *doc_TagSec = "TagSection(text: str, [bytes: bool = False])\n\n" "Provide methods to access RFC822-style header sections, like those\n" "found in debian/control or Packages files.\n\n" "TagSection() behave like read-only dictionaries and also provide access\n" - "to the functions provided by the C++ class (e.g. find)"; + "to the functions provided by the C++ class (e.g. find).\n\n" + "By default, text read from files is treated as strings (binary data in\n" + "Python 2, Unicode strings in Python 3). Use bytes=True to cause all\n" + "header values read from this TagSection to be bytes even in Python 3.\n" + "Header names are always treated as Unicode."; PyTypeObject PyTagSection_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) @@ -623,7 +689,7 @@ static PyGetSetDef TagFileGetSet[] = { }; -static char *doc_TagFile = "TagFile(file)\n\n" +static char *doc_TagFile = "TagFile(file, [bytes: bool = False])\n\n" "TagFile() objects provide access to debian control files, which consist\n" "of multiple RFC822-style sections.\n\n" "To provide access to those sections, TagFile objects provide an iterator\n" @@ -635,7 +701,11 @@ static char *doc_TagFile = "TagFile(file)\n\n" "It is important to not mix the use of both APIs, because this can have\n" "unwanted effects.\n\n" "The parameter 'file' refers to an object providing a fileno() method or\n" - "a file descriptor (an integer)"; + "a file descriptor (an integer).\n\n" + "By default, text read from files is treated as strings (binary data in\n" + "Python 2, Unicode strings in Python 3). Use bytes=True to cause all\n" + "header values read from this TagFile to be bytes even in Python 3.\n" + "Header names are always treated as Unicode."; // Type for a Tag File PyTypeObject PyTagFile_Type = diff --git a/tests/test_tagfile.py b/tests/test_tagfile.py index 371cc6ee..33197e6a 100644 --- a/tests/test_tagfile.py +++ b/tests/test_tagfile.py @@ -1,18 +1,26 @@ #!/usr/bin/python +# -*- coding: utf-8 -*- # # Copyright (C) 2010 Michael Vogt +# Copyright (C) 2012 Canonical Ltd. +# Author: Colin Watson # # Copying and distribution of this file, with or without modification, # are permitted in any medium without royalty provided the copyright # notice and this notice are preserved. """Unit tests for verifying the correctness of apt_pkg.TagFile""" +from __future__ import print_function, unicode_literals + +import io import glob import os +import shutil +import sys +import tempfile import unittest from test_all import get_library_dir -import sys sys.path.insert(0, get_library_dir()) import apt_pkg @@ -20,6 +28,13 @@ import apt_pkg class TestTagFile(unittest.TestCase): """ test the apt_pkg.TagFile """ + def setUp(self): + apt_pkg.init() + self.temp_dir = tempfile.mkdtemp() + + def tearDown(self): + shutil.rmtree(self.temp_dir) + def test_tag_file(self): basepath = os.path.dirname(__file__) tagfilepath = os.path.join(basepath, "./data/tagfile/*") @@ -38,5 +53,81 @@ class TestTagFile(unittest.TestCase): # Raises Type error self.assertRaises(TypeError, apt_pkg.TagFile, object()) + def test_utf8(self): + value = "Tést Persön " + packages = os.path.join(self.temp_dir, "Packages") + with io.open(packages, "w", encoding="UTF-8") as packages_file: + print("Maintainer: %s" % value, file=packages_file) + print("", file=packages_file) + if sys.version < '3': + # In Python 2, test the traditional file interface. + with open(packages) as packages_file: + tagfile = apt_pkg.TagFile(packages_file) + tagfile.step() + self.assertEqual( + value.encode("UTF-8"), tagfile.section["Maintainer"]) + with io.open(packages, encoding="UTF-8") as packages_file: + tagfile = apt_pkg.TagFile(packages_file) + tagfile.step() + if sys.version < '3': + self.assertEqual( + value.encode("UTF-8"), tagfile.section["Maintainer"]) + else: + self.assertEqual(value, tagfile.section["Maintainer"]) + + def test_latin1(self): + value = "Tést Persön " + packages = os.path.join(self.temp_dir, "Packages") + with io.open(packages, "w", encoding="ISO-8859-1") as packages_file: + print("Maintainer: %s" % value, file=packages_file) + print("", file=packages_file) + if sys.version < '3': + # In Python 2, test the traditional file interface. + with open(packages) as packages_file: + tagfile = apt_pkg.TagFile(packages_file) + tagfile.step() + self.assertEqual( + value.encode("ISO-8859-1"), tagfile.section["Maintainer"]) + with io.open(packages) as packages_file: + tagfile = apt_pkg.TagFile(packages_file, bytes=True) + tagfile.step() + self.assertEqual( + value.encode("ISO-8859-1"), tagfile.section["Maintainer"]) + if sys.version >= '3': + # In Python 3, TagFile can pick up the encoding of the file + # object. + with io.open(packages, encoding="ISO-8859-1") as packages_file: + tagfile = apt_pkg.TagFile(packages_file) + tagfile.step() + self.assertEqual(value, tagfile.section["Maintainer"]) + + def test_mixed(self): + value = "Tést Persön " + packages = os.path.join(self.temp_dir, "Packages") + with io.open(packages, "w", encoding="UTF-8") as packages_file: + print("Maintainer: %s" % value, file=packages_file) + print("", file=packages_file) + with io.open(packages, "a", encoding="ISO-8859-1") as packages_file: + print("Maintainer: %s" % value, file=packages_file) + print("", file=packages_file) + if sys.version < '3': + # In Python 2, test the traditional file interface. + with open(packages) as packages_file: + tagfile = apt_pkg.TagFile(packages_file) + tagfile.step() + self.assertEqual( + value.encode("UTF-8"), tagfile.section["Maintainer"]) + tagfile.step() + self.assertEqual( + value.encode("ISO-8859-1"), tagfile.section["Maintainer"]) + with io.open(packages) as packages_file: + tagfile = apt_pkg.TagFile(packages_file, bytes=True) + tagfile.step() + self.assertEqual( + value.encode("UTF-8"), tagfile.section["Maintainer"]) + tagfile.step() + self.assertEqual( + value.encode("ISO-8859-1"), tagfile.section["Maintainer"]) + if __name__ == "__main__": unittest.main() -- cgit v1.2.3 From 4133baa95eaf2a8638c2ad8acea42e061049db02 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Sun, 17 Jun 2012 23:11:16 +0200 Subject: * python/tag.cc: - Correctly handle file descriptor 0 aka stdin (Closes: #669458) --- debian/changelog | 2 ++ python/tag.cc | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'python/tag.cc') diff --git a/debian/changelog b/debian/changelog index 2bb0c431..771fed36 100644 --- a/debian/changelog +++ b/debian/changelog @@ -47,6 +47,8 @@ python-apt (0.8.5) UNRELEASED; urgency=low - Handle the use of "del" on configuration values. Those are represented by calling the setter with NULL, which we did not handle before, causing a segmentation fault (Closes: #661062) + * python/tag.cc: + - Correctly handle file descriptor 0 aka stdin (Closes: #669458) -- Michael Vogt Tue, 17 Apr 2012 14:09:24 +0200 diff --git a/python/tag.cc b/python/tag.cc index bf79debf..248d818d 100644 --- a/python/tag.cc +++ b/python/tag.cc @@ -461,7 +461,7 @@ static PyObject *TagFileNew(PyTypeObject *type,PyObject *Args,PyObject *kwds) } New = (TagFileData*)type->tp_alloc(type, 0); - if (fileno > 0) + if (fileno != -1) { #ifdef APT_HAS_GZIP new (&New->Fd) FileFd(); @@ -483,7 +483,7 @@ static PyObject *TagFileNew(PyTypeObject *type,PyObject *Args,PyObject *kwds) New->Owner = File; Py_INCREF(New->Owner); #if PY_MAJOR_VERSION >= 3 - if (fileno > 0) { + if (fileno != -1) { New->Encoding = PyObject_GetAttr(File, PyUnicode_FromString("encoding")); if (New->Encoding && !PyUnicode_Check(New->Encoding)) New->Encoding = 0; -- cgit v1.2.3