Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • nE0sIghT-guest/python-debian
  • twolife/python-debian
  • nijel/python-debian
  • detiste-guest/python-debian
  • pmhahn/python-debian
  • kitterman/python-debian
  • mxmehl/python-debian
  • bdrung/python-debian
  • andersk/python-debian
  • stephanlachnit/python-debian
  • quba42/python-debian
  • schopin/python-debian
  • ddstreet/python-debian
  • athos/python-debian
  • janitor-team/proposed/python-debian
  • nthykier/python-debian
  • ovv/python-debian
  • fepitre/python-debian
  • rpavlik/python-debian
  • josch/python-debian
  • jrivero-guest/python-debian
  • federico/python-debian
  • dato/python-debian
  • morph/python-debian
  • mwhudson/python-debian
  • jak/python-debian
  • sankalp-guest/python-debian
  • cjwatson/python-debian
  • python-debian-team/python-debian
  • stuart/python-debian
  • olebole/python-debian
  • mibanescu-guest/python-debian
  • jelmer/python-debian
  • ra_kete-guest/python-debian
  • x9c4-guest/python-debian
  • carmenbianca/python-debian
36 results
Show changes
Commits on Source (15)
......@@ -19,7 +19,7 @@ pages:
- apt-get update && apt-get install -y make python3-sphinx
- rm -f docs/api/*
- cd lib && sphinx-apidoc -e --private -H python-debian -o ../docs/api/ . deb822.py debian/tests/ debian_bundle/ && cd ..
- make -C docs/ SPHINXOPTS="-a -v -n" html
- PYTHONPATH=$PWD/lib make -C docs/ SPHINXOPTS="-a -v -n" html
- mv build/sphinx/html/ public/
artifacts:
paths:
......
python-debian (0.1.34) unstable; urgency=medium
[ Jelmer Vernooij ]
* Fix typo in changelog.py documentation.
[ Stuart Prescott ]
* Fix "DeprecationWarning" regarding the move of ABCs from collections to
collections.abc, with thanks to Jakub Wilk for the report
(Closes: #914737).
* Add accessors for Version objects from Deb822 (Closes: #901651).
* Issue warnings if calling code requested use of python-apt for processing
a Deb822 file but that request could not be honoured (see: #913274).
* Make internal parser match python-apt in strictness when dealing with
Packages and Sources files (Closes: #913274).
* Update Standards-Version to 4.3.0 (no changes required).
-- Stuart Prescott <stuart@debian.org> Fri, 18 Jan 2019 01:14:54 +1100
python-debian (0.1.33) unstable; urgency=medium
* Switch to salsa.debian.org URLs for homepage, source location etc.
......
......@@ -25,7 +25,7 @@ Build-Depends:
python3-chardet,
python3-setuptools,
python3-six (>> 1.4~)
Standards-Version: 4.2.0
Standards-Version: 4.3.0
Vcs-Browser: https://salsa.debian.org/python-debian-team/python-debian
Vcs-Git: https://salsa.debian.org/python-debian-team/python-debian.git
Homepage: https://salsa.debian.org/python-debian-team/python-debian
......
......@@ -18,7 +18,7 @@ export PYBUILD_NAME=debian
override_dh_auto_clean:
dh_auto_clean
rm -f lib/debian/_version.py
rm -rf docs/api lib/debian/__pycache__
rm -rf docs/api docs/_static lib/debian/__pycache__ build/sphinx/ .mypy_cache/
override_dh_auto_build: lib/debian/_version.py
dh_auto_build
......@@ -54,6 +54,11 @@ apidoc:
deb822.py debian/tests/ debian_bundle/
doc: apidoc
make -C docs/ SPHINXOPTS="-a -v -n" html
PYTHONPATH=$(CURDIR)/lib \
make -C docs/ SPHINXOPTS="-a -v -n" html
.PHONY: dist doc apidoc
qa:
pylint3 --rcfile .pylintrc lib
mypy lib
.PHONY: dist doc apidoc qa
......@@ -86,6 +86,11 @@ Style guide
- Write docstrings in rst format so that sphinx can generate API
documentation.
The pylint and mypy tools can be run easily from debian/rules to track code
quality::
$ ./debian/rules qa
Test suite
----------
......
......@@ -48,7 +48,6 @@ FILE_MAGIC = b"`\n"
class ArError(Exception):
""" Common base for all exceptions raised within the arfile module """
pass
class ArFile(object):
......
......@@ -493,7 +493,7 @@ class Changelog(object):
# type: (...) -> None
""" Read and parse a changelog file
If you create an Changelog object without sepcifying a changelog
If you create an Changelog object without specifying a changelog
file, you can parse a changelog file with this method. If the
changelog doesn't parse cleanly, a :class:`ChangelogParseError`
exception is thrown. The constructor will parse the changelog on
......
......@@ -220,6 +220,19 @@ Deb822 Classes
from __future__ import absolute_import, print_function
import collections
try:
# Python 3
from collections.abc import (
Mapping,
MutableMapping,
)
except ImportError:
# Python 2.7 cruft
from collections import (
Mapping,
MutableMapping,
)
import datetime
import email.utils
import io
......@@ -272,6 +285,7 @@ except ImportError:
pass
from debian.deprecation import function_deprecated_by
import debian.debian_support
try:
import apt_pkg # type: ignore
......@@ -282,21 +296,17 @@ except (ImportError, AttributeError):
_have_apt_pkg = False
if sys.version >= '3':
def _is_real_file(f):
# type: (Any) -> bool
if not isinstance(f, io.IOBase):
return False
try:
f.fileno()
return True
except (AttributeError, io.UnsupportedOperation):
return False
else:
def _is_real_file(f):
# type: (Any) -> bool
# pylint: disable=undefined-variable
return isinstance(f, file) and hasattr(f, 'fileno') # type: ignore
def _has_fileno(f):
# type: (Any) -> bool
""" test that a file-like object is really a filehandle
Only filehandles can be given to apt_pkg.TagFile.
"""
try:
f.fileno()
return True
except (AttributeError, io.UnsupportedOperation):
return False
GPGV_DEFAULT_KEYRINGS = frozenset(['/usr/share/keyrings/debian-keyring.gpg'])
......@@ -311,7 +321,7 @@ class RestrictedFieldError(Error):
"""Raised when modifying the raw value of a field is not allowed."""
class TagSectionWrapper(collections.Mapping):
class TagSectionWrapper(Mapping):
"""Wrap a TagSection object, using its find_raw method to get field values
This allows us to pick which whitespace to strip off the beginning and end
......@@ -325,6 +335,7 @@ class TagSectionWrapper(collections.Mapping):
# type: (...) -> None
self.__section = section
self.decoder = decoder or _AutoDecoder()
super(TagSectionWrapper, self).__init__()
def __iter__(self):
# type: () -> Iterator[str]
......@@ -412,7 +423,7 @@ class OrderedSet(object):
# ###
class Deb822Dict(collections.MutableMapping):
class Deb822Dict(MutableMapping):
"""A dictionary-like object suitable for storing RFC822-like data.
Deb822Dict behaves like a normal dict, except:
......@@ -441,6 +452,7 @@ class Deb822Dict(collections.MutableMapping):
self.__parsed = None # type: Optional[Union[Deb822, TagSectionWrapper]]
self.encoding = encoding
self.decoder = _AutoDecoder(self.encoding)
super(Deb822Dict, self).__init__()
if _dict is not None:
# _dict may be a dict or a list of two-sized tuples
......@@ -469,7 +481,7 @@ class Deb822Dict(collections.MutableMapping):
else:
self.__keys.extend([_strI(f) for f in _fields if f in self.__parsed])
# ### BEGIN collections.MutableMapping methods
# ### BEGIN collections.abc.MutableMapping methods
def __iter__(self):
# type: () -> Iterator[str]
......@@ -523,7 +535,7 @@ class Deb822Dict(collections.MutableMapping):
if sys.version < '3':
has_key = __contains__
# ### END collections.MutableMapping methods
# ### END collections.abc.MutableMapping methods
def __repr__(self):
return '{%s}' % ', '.join(['%r: %r' % (k, v) for k, v in self.items()])
......@@ -572,6 +584,34 @@ class Deb822(Deb822Dict):
:param encoding: When parsing strings, interpret them in this encoding.
(All values are given back as unicode objects, so an encoding is
necessary in order to properly interpret the strings.)
:param strict: Dict controlling the strictness of the internal parser
to permit tuning of its behaviour between "generous in what it
accepts" and "strict conformance". Known keys are described below.
*Internal parser tuning*
- `whitespace-separates-paragraphs`: (default: `True`)
Blank lines between paragraphs should not have any whitespace in them
at all. However:
- Policy §5.1 permits `debian/control` in source packages to separate
packages with lines containing whitespace to allow human edited
files to have stray whitespace. Failing to honour this breaks
tools such as
`wrap-and-sort <https://manpages.debian.org/wrap-and-sort>`_
(see, for example,
`Debian Bug 715558 <https://bugs.debian.org/715558/>`_).
- `apt_pkg.TagFile` accepts whitespace-only lines within the
`Description` field; strictly matching the behaviour of apt's
Deb822 parser requires setting this key to `False` (as is done
by default for :class:`Sources` and :class:`Packages`.
(see, for example,
`Debian Bug 913274 <https://bugs.debian.org/913274/>`_).
Note that these tuning parameter are only for the parser that is
internal to `Deb822` and do not apply to python-apt's apt_pkg.TagFile
parser which would normally be used for Packages and Sources files.
"""
def __init__(self,
......@@ -579,6 +619,7 @@ class Deb822(Deb822Dict):
fields=None, # type: Optional[List[str]]
_parsed=None, # type: Optional[Union[Deb822, TagSectionWrapper]]
encoding="utf-8", # type: str
strict=None, # type: Optional[Dict]
):
# type: (...) -> None
......@@ -594,7 +635,7 @@ class Deb822(Deb822Dict):
if iterable is not None:
try:
self._internal_parser(iterable, fields)
self._internal_parser(iterable, fields, strict)
except EOFError:
pass
......@@ -608,6 +649,7 @@ class Deb822(Deb822Dict):
use_apt_pkg=False, # type: bool
shared_storage=False, # type: bool
encoding="utf-8", # type: str
strict=None, # type: Optional[Dict]
):
# type: (...) -> Iterator[Deb822]
"""Generator that yields a Deb822 object for each paragraph in sequence.
......@@ -629,10 +671,33 @@ class Deb822(Deb822Dict):
:param encoding: Interpret the paragraphs in this encoding.
(All values are given back as unicode objects, so an encoding is
necessary in order to properly interpret the strings.)
:param strict: dict of settings to tune the internal parser if that is
being used. See the documentation for :class:`Deb822` for details.
"""
# pylint: disable=unused-argument
if _have_apt_pkg and use_apt_pkg and _is_real_file(sequence):
apt_pkg_allowed = use_apt_pkg and _has_fileno(sequence)
if use_apt_pkg and not _have_apt_pkg:
# warn that apt_pkg was requested but not installed
msg = (
"Parsing of Deb822 data with python{pyver}-apt's apt_pkg was "
"requested but this package is not importable. "
"Is python{pyver}-apt installed?"
).format(
pyver=('3' if sys.version_info[0] == 3 else '')
)
warnings.warn(msg)
elif use_apt_pkg and not apt_pkg_allowed:
# warn that apt_pkg was requested but can't be used
msg = (
"Parsing of Deb822 data with python-apt's apt_pkg was "
"requested but this cannot be done on non-file input."
)
warnings.warn(msg)
if _have_apt_pkg and apt_pkg_allowed:
kwargs = {}
if sys.version >= '3':
# bytes=True is supported for both Python 2 and 3, but we
......@@ -662,7 +727,7 @@ class Deb822(Deb822Dict):
# StringIO/list can be iterated directly
iterable = iter(sequence) # type: ignore
while True:
x = cls(iterable, fields, encoding=encoding)
x = cls(iterable, fields, encoding=encoding, strict=strict)
if not x:
break
yield x
......@@ -702,6 +767,7 @@ class Deb822(Deb822Dict):
def _internal_parser(self,
sequence, # type: IterableDataSourceType
fields=None, # type: Optional[List[str]]
strict=None, # type: Optional[Dict]
):
# The key is non-whitespace, non-colon characters before any colon.
key_part = r"^(?P<key>[^: \t\n\r\f\v]+)\s*:\s*"
......@@ -720,7 +786,7 @@ class Deb822(Deb822Dict):
content = ""
for linebytes in self.gpg_stripped_paragraph(
self._skip_useless_lines(sequence)):
self._skip_useless_lines(sequence), strict):
line = self.decoder.decode(linebytes)
m = single.match(line)
......@@ -937,24 +1003,41 @@ class Deb822(Deb822Dict):
mergeFields = function_deprecated_by(merge_fields)
@staticmethod
def split_gpg_and_payload(sequence):
# type: (Iterable[bytes]) -> Tuple[List[bytes], List[bytes], List[bytes]]
def split_gpg_and_payload(sequence, # type: Iterable[bytes]
strict=None, # type: Optional[Dict]
):
# type: (...) -> Tuple[List[bytes], List[bytes], List[bytes]]
"""Return a (gpg_pre, payload, gpg_post) tuple
Each element of the returned tuple is a list of lines (with trailing
whitespace stripped).
:param sequence: iterable.
An iterable that yields lines of data (str, unicode,
bytes) to be parsed, possibly including a GPG in-line signature.
:param strict: dict, optional.
Control over the strictness of the parser. See the :class:`Deb822`
class documentation for details.
"""
# pylint: disable=too-many-branches
if not strict:
strict = {}
gpg_pre_lines = [] # type: List[bytes]
lines = [] # type: List[bytes]
gpg_post_lines = [] # type: List[bytes]
state = b'SAFE'
gpgre = re.compile(br'^-----(?P<action>BEGIN|END) '
br'PGP (?P<what>[^-]+)-----[\r\t ]*$')
initial_blank_line = re.compile(br'^\s*$')
# Include whitespace-only lines in blank lines to split paragraphs.
# (see #715558)
blank_line = re.compile(br'^\s*$')
if strict.get('whitespace-separates-paragraphs', True):
blank_line = re.compile(br'^\s*$')
else:
blank_line = re.compile(br'^$')
first_line = True
for line in sequence:
......@@ -969,7 +1052,7 @@ class Deb822(Deb822Dict):
# skip initial blank lines, if any
if first_line:
if blank_line.match(line):
if initial_blank_line.match(line):
continue
else:
first_line = False
......@@ -1010,9 +1093,9 @@ class Deb822(Deb822Dict):
raise EOFError('only blank lines found in input')
@classmethod
def gpg_stripped_paragraph(cls, sequence):
# type: (Iterator) -> List[bytes]
return cls.split_gpg_and_payload(sequence)[1]
def gpg_stripped_paragraph(cls, sequence, strict=None):
# type: (Iterator, Optional[Dict]) -> List[bytes]
return cls.split_gpg_and_payload(sequence, strict)[1]
def get_gpg_info(self, keyrings=None):
# type: (List[str]) -> GpgInfo
......@@ -1095,7 +1178,6 @@ class GpgInfo(dict):
# XXX handle utf-8 %-encoding
def uid(self):
"""Return the primary ID of the signee key, None is not available"""
pass
@classmethod
def from_output(cls, out, err=None):
......@@ -1387,6 +1469,16 @@ class _lowercase_dict(dict):
return dict.__getitem__(self, key.lower())
class _VersionAccessorMixin(object):
"""Give access to Version keys as debian_support.Version objects."""
def get_version(self):
return debian.debian_support.Version(self['Version'])
def set_version(self, version):
self['Version'] = str(version)
class _PkgRelationMixin(object):
"""Package relationship mixin
......@@ -1617,6 +1709,7 @@ class _gpg_multivalued(_multivalued):
sequence = args[0]
except IndexError:
sequence = kwargs.get("sequence", None)
strict = kwargs.get("strict", None)
if sequence is not None:
# If the input is a unicode object or a file opened in text mode,
......@@ -1639,7 +1732,8 @@ class _gpg_multivalued(_multivalued):
try:
gpg_pre_lines, lines, gpg_post_lines = \
self.split_gpg_and_payload(
self._bytes(s, encoding) for s in sequence)
(self._bytes(s, encoding) for s in sequence),
strict)
except EOFError:
# Empty input
gpg_pre_lines = lines = gpg_post_lines = []
......@@ -1674,7 +1768,7 @@ class _gpg_multivalued(_multivalued):
raise TypeError('bytes or unicode/string required, not %s' % type(s))
class Dsc(_gpg_multivalued):
class Dsc(_gpg_multivalued, _VersionAccessorMixin):
""" Representation of a .dsc (Debian Source Control) file
This class is a thin wrapper around the transparent GPG handling
......@@ -1688,7 +1782,7 @@ class Dsc(_gpg_multivalued):
}
class Changes(_gpg_multivalued):
class Changes(_gpg_multivalued, _VersionAccessorMixin):
""" Representation of a .changes (archive changes) file
This class is a thin wrapper around the transparent GPG handling
......@@ -1827,6 +1921,7 @@ class Sources(Dsc, _PkgRelationMixin):
use_apt_pkg=True, # type: bool
shared_storage=False, # type: bool
encoding="utf-8", # type: str
strict=None, # type: Optional[Dict]
):
# type: (...) -> Iterator
"""Generator that yields a Deb822 object for each paragraph in Sources.
......@@ -1836,11 +1931,15 @@ class Sources(Dsc, _PkgRelationMixin):
See the :func:`~Deb822.iter_paragraphs` function for details.
"""
if not strict:
strict = {
'whitespace-separates-paragraphs': False,
}
return super(Sources, cls).iter_paragraphs(
sequence, fields, use_apt_pkg, shared_storage, encoding)
sequence, fields, use_apt_pkg, shared_storage, encoding, strict)
class Packages(Deb822, _PkgRelationMixin):
class Packages(Deb822, _PkgRelationMixin, _VersionAccessorMixin):
"""Represent an APT binary package list
This class is a thin wrapper around the parsing of :class:`Deb822`,
......@@ -1864,6 +1963,7 @@ class Packages(Deb822, _PkgRelationMixin):
use_apt_pkg=True, # type: bool
shared_storage=False, # type: bool
encoding="utf-8", # type: str
strict=None, # type: Optional[Dict]
):
# type: (...) -> Iterator
"""Generator that yields a Deb822 object for each paragraph in Packages.
......@@ -1873,8 +1973,12 @@ class Packages(Deb822, _PkgRelationMixin):
See the :func:`~Deb822.iter_paragraphs` function for details.
"""
if not strict:
strict = {
'whitespace-separates-paragraphs': False,
}
return super(Packages, cls).iter_paragraphs(
sequence, fields, use_apt_pkg, shared_storage, encoding)
sequence, fields, use_apt_pkg, shared_storage, encoding, strict)
class _ClassInitMeta(type):
......
......@@ -45,7 +45,7 @@ except ImportError:
# Missing types aren't important at runtime
pass
from debian.arfile import ArFile, ArError, ArMember
from debian.arfile import ArFile, ArError, ArMember # pylint: disable=unused-import
from debian.changelog import Changelog
from debian.deb822 import Deb822
......
......@@ -26,7 +26,10 @@ import os.path
import re
import sys
import tempfile
import unittest
if sys.version_info[0] >= 3:
import unittest
else:
import unittest2 as unittest
import warnings
import six
......@@ -40,6 +43,7 @@ else:
import apt_pkg #type: ignore
from debian import deb822
from debian.debian_support import Version
UNPARSED_PACKAGE = '''\
......@@ -455,14 +459,38 @@ class TestDeb822(unittest.TestCase):
for d in deb822.Deb822.iter_paragraphs(text):
self.assertWellParsed(d, PARSED_PACKAGE)
def test_iter_paragraphs_file(self):
def test_iter_paragraphs_file_io(self):
text = StringIO(UNPARSED_PACKAGE + '\n\n\n' + UNPARSED_PACKAGE)
for d in deb822.Deb822.iter_paragraphs(text, use_apt_pkg=False):
self.assertWellParsed(d, PARSED_PACKAGE)
for d in deb822.Deb822.iter_paragraphs(text, use_apt_pkg=True):
self.assertWellParsed(d, PARSED_PACKAGE)
with self.assertWarns(UserWarning):
# The StringIO is not a real file so this will raise a warning
for d in deb822.Deb822.iter_paragraphs(text, use_apt_pkg=True):
self.assertWellParsed(d, PARSED_PACKAGE)
def test_iter_paragraphs_file(self):
text = StringIO()
text.write(UNPARSED_PACKAGE)
text.write('\n\n\n')
text.write(UNPARSED_PACKAGE)
with tempfile.NamedTemporaryFile() as fh:
if sys.version_info[0] >= 3:
txt = text.getvalue().encode('UTF-8')
else:
txt = text.getvalue()
fh.write(txt)
fh.seek(0)
for d in deb822.Deb822.iter_paragraphs(fh, use_apt_pkg=False):
self.assertWellParsed(d, PARSED_PACKAGE)
fh.seek(0)
for d in deb822.Deb822.iter_paragraphs(fh, use_apt_pkg=True):
self.assertWellParsed(d, PARSED_PACKAGE)
def test_iter_paragraphs_with_gpg(self):
for string in GPG_SIGNED:
......@@ -484,7 +512,7 @@ class TestDeb822(unittest.TestCase):
self.assertWellParsed(d, PARSED_PACKAGE)
def test_iter_paragraphs_with_extra_whitespace(self):
""" Paragraphs not elided when stray whitespace is between
""" Paragraphs splitting when stray whitespace is between
From policy §5.1:
......@@ -494,33 +522,59 @@ class TestDeb822(unittest.TestCase):
On the principle of "be strict in what you send; be generous in
what you receive", deb822 should permit such extra whitespace between
deb822 stanzas.
deb822 stanzas. See #715558 for further details.
See #715558 for further details.
However, when dealing with Packages and Sources files, the behaviour
of apt is to not split on whitespace-only lines, and so the internal
parser must be able to avoid doing so when dealing with these data.
See #913274 for further details.
"""
for extra_space in (" ", " ", "\t"):
text = six.u(UNPARSED_PACKAGE) + '%s\n' % extra_space + \
six.u(UNPARSED_PACKAGE)
count = len(list(deb822.Deb822.iter_paragraphs(text)))
self.assertEqual(2, count,
"Wrong number paragraphs were found in list: 2 != %d" % count)
fd, filename = tempfile.mkstemp()
fp = os.fdopen(fd, 'wb')
fp.write(text.encode('utf-8'))
fp.close()
try:
def test_count(cmd, expected, *args, **kwargs):
#print("\n", cmd.__class__, expected)
with open_utf8(filename) as fh:
count = len(list(deb822.Deb822.iter_paragraphs(fh)))
self.assertEqual(2, count,
"Wrong number paragraphs were found in file: 2 != %d" % count)
with open_utf8(filename) as fh:
count = len(list(deb822.Packages.iter_paragraphs(fh)))
# this time the apt_pkg parser should be used and this
# *should* elide the paragraphs and make a mess
self.assertEqual(count, 1,
"Wrong number paragraphs were found in file: 1 != %d" % count)
count = len(list(cmd(fh, *args, **kwargs)))
self.assertEqual(
expected,
count,
"Wrong number paragraphs were found: expected {expected}, got {count}".format(
count=count,
expected=expected,
)
)
try:
# apt_pkg not used, should split
test_count(deb822.Deb822.iter_paragraphs, 2)
test_count(deb822.Deb822.iter_paragraphs, 2, use_apt_pkg=False)
# apt_pkg used, should not split
test_count(deb822.Deb822.iter_paragraphs, 1, use_apt_pkg=True)
# Specialised iter_paragraphs force use of apt_pkg and don't split
test_count(deb822.Packages.iter_paragraphs, 1, use_apt_pkg=True)
test_count(deb822.Sources.iter_paragraphs, 1, use_apt_pkg=True)
test_count(deb822.Packages.iter_paragraphs, 1, use_apt_pkg=False)
test_count(deb822.Sources.iter_paragraphs, 1, use_apt_pkg=False)
# Explicitly set internal parser to not split
strict = {'whitespace-separates-paragraphs': False}
test_count(deb822.Packages.iter_paragraphs, 1, use_apt_pkg=False, strict=strict)
test_count(deb822.Sources.iter_paragraphs, 1, use_apt_pkg=False, strict=strict)
# Explicitly set internal parser to split
strict = {'whitespace-separates-paragraphs': True}
test_count(deb822.Packages.iter_paragraphs, 2, use_apt_pkg=False, strict=strict)
test_count(deb822.Sources.iter_paragraphs, 2, use_apt_pkg=False, strict=strict)
finally:
os.remove(filename)
......@@ -1238,6 +1292,35 @@ class TestPkgRelations(unittest.TestCase):
self.assertEqual(deb822.PkgRelation.str(rel), r)
class TestVersionAccessor(unittest.TestCase):
def test_get_version(self):
# should not be available in most basic Deb822
p = deb822.Deb822(UNPARSED_PACKAGE.splitlines())
with self.assertRaises(AttributeError):
p.get_version()
# should be available in Packages
p = deb822.Packages(UNPARSED_PACKAGE.splitlines())
v = p.get_version()
self.assertEqual(str(v), '1.5.12-1')
self.assertTrue(isinstance(v, Version))
def test_set_version(self):
# should not be available in most basic Deb822
p = deb822.Deb822(UNPARSED_PACKAGE.splitlines())
with self.assertRaises(AttributeError):
p.set_version()
# should be available in Packages
p = deb822.Packages(UNPARSED_PACKAGE.splitlines())
newver = '9.8.7-1'
v = Version(newver)
p.set_version(v)
self.assertEqual(p['Version'], newver)
self.assertTrue(isinstance(p['Version'], six.string_types))
@unittest.skipUnless(os.path.exists('/usr/bin/gpgv'), "gpgv not installed")
class TestGpgInfo(unittest.TestCase):
......