From cd12f43cd2c98826bb0ea092ef590a91e5842886 Mon Sep 17 00:00:00 2001 From: Scott Bahling Date: Thu, 6 Feb 2020 22:16:02 +0100 Subject: Handle passing bytes to the FileInfo class Move class to own file and enhance tests --- obsapi/__init__.py | 1 - obsapi/core.py | 119 ++++------------------------------------------- obsapi/fileinfo.py | 102 ++++++++++++++++++++++++++++++++++++++++ obsapi/helpers.py | 23 +++++++++ test/binary_fileinfo.xml | 40 ++++++++++++++++ test/test_api.py | 23 +++------ test/test_fileinfo.py | 26 +++++++++++ 7 files changed, 207 insertions(+), 127 deletions(-) create mode 100644 obsapi/fileinfo.py create mode 100644 obsapi/helpers.py create mode 100644 test/binary_fileinfo.xml create mode 100644 test/test_fileinfo.py diff --git a/obsapi/__init__.py b/obsapi/__init__.py index 6b3af61..547af96 100644 --- a/obsapi/__init__.py +++ b/obsapi/__init__.py @@ -3,4 +3,3 @@ from obsapi.core import * from ._version import get_versions __version__ = get_versions()['version'] del get_versions - diff --git a/obsapi/core.py b/obsapi/core.py index d4980dc..80067d6 100644 --- a/obsapi/core.py +++ b/obsapi/core.py @@ -1,14 +1,13 @@ # -*- coding: utf-8 -*- # import re -from io import BytesIO from lxml import etree from collections import namedtuple -from datetime import datetime +from obsapi import helpers from obsapi.sourceapi import ObsSourceApi from obsapi.buildapi import ObsBuildApi -from obsapi.formatter import Formatter from obsapi.repoflags import RepoFlags +from obsapi.fileinfo import FileInfo LSItem = namedtuple('LSItem', 'name md5 size mtime') @@ -25,102 +24,7 @@ emptyxml = '' EMPTYTREE = etree.fromstring(emptyxml) EMPTY = EMPTYTREE.xpath('.')[0] - -class FileInfo(object): - file_str_template = ('{filename}' - 'size : {size}' - 'mtime : {mtime}' - ) - - pkg_str_template = ('{filename}' - 'Name : {name}' - 'Version : {version}' - 'Release : {release}' - 'Architecture: {arch}' - 'Size : {size}' - 'Source RPM : {source}' - 'Build Date : {mtime}' - 'Summary : {summary}' - 'Description :' - '{description}' - 'Provides :' - '{provides}' - ) - - src_str_template = ('{filename}' - 'Name : {name}' - 'Version : {version}' - 'Release : {release}' - 'Architecture: {arch}' - 'Size : {size}' - 'Build Date : {mtime}' - 'Summary : {summary}' - 'Description :' - '{description}' - ) - - def __init__(self, xml): - self.finfo = etree.fromstring(xml) - self.filename = self.finfo.get('filename', None) - self.formatter = Formatter(self) - - @property - def info(self): - info = {'filename': [self.filename]} - for item in self.finfo: - info.setdefault(item.tag, []).append(item.text) - - for item, value in info.items(): - if len(value) == 1: - info[item] = value[0] - # info[item] = '\n'.join(value) - - return info - - def __str__(self): - return self.formatter.render() - - def __getattr__(self, attr): - try: - values = [value.text for value in self.finfo.findall(attr)] - except Exception: - values = [None] - - if len(values) == 1: - return values[0] - else: - return values - - @property - def datetime(self): - if self.mtime: - return datetime.fromtimestamp(int(self.mtime)) - - @property - def xml(self): - return etree.tostring(self.finfo) - - @property - def is_pkg(self): - if self.arch: - return True - else: - return False - - @property - def is_src(self): - if self.source: - return False - else: - return True - - @property - def is_debug_info(self): - if '-' in self.name: - if self.name.split('-')[-1] in ('debuginfo', 'debugsource'): - return True - - return False +xml2etree = helpers.xml2etree class ObsApi(object): @@ -137,11 +41,6 @@ class ObsApi(object): self.build.verify_ssl = True self.lastapi = None - def __xml2etree(self, xml): - xml = xml.encode('utf-8') - parser = etree.XMLParser(remove_blank_text=True) - return etree.parse(BytesIO(xml), parser).xpath('.')[0] - def get_meta(self, prj, pkg=None): return self.source.get_meta(prj, pkg=pkg) @@ -162,7 +61,7 @@ class ObsApi(object): if xml is None: return [] - d = self.__xml2etree(xml) + d = xml2etree(xml) lsitems = [e.get('name') for e in d.findall('entry')] return lsitems @@ -303,7 +202,7 @@ class ObsApi(object): return RepoFlags(self.get_meta(prj, pkg)) def locked(self, prj, pkg=None): - meta = self.__xml2etree(self.get_meta(prj, pkg)) + meta = xml2etree(self.get_meta(prj, pkg)) if meta.find('lock') is not None: return True return False @@ -328,7 +227,7 @@ class ObsApi(object): if role is None: role = '.*' # regex to match all - meta = self.__xml2etree(xml) + meta = xml2etree(xml) persons = meta.xpath('.//person[re:test(@role, role)]', namespaces={'re': REGEX_NS}) return [User(userid=p.get('userid'), role=p.get('role')) for p in persons] @@ -340,7 +239,7 @@ class ObsApi(object): if role is None: role = '.*' # regex to match all - meta = self.__xml2etree(xml) + meta = xml2etree(xml) groups = meta.xpath('.//group[re:test(@role, role)]', namespaces={'re': REGEX_NS}) return [Group(groupid=g.get('groupid'), role=g.get('role')) for g in groups] @@ -359,7 +258,7 @@ class ObsApi(object): if xml is None: raise Exception('unable to retrieve project meta') - meta = self.__xml2etree(xml) + meta = xml2etree(xml) etree.SubElement(meta, 'person', userid=userid, role=role) return self.put_meta(prj, pkg, etree.tostring(meta)) @@ -378,7 +277,7 @@ class ObsApi(object): if xml is None: raise Exception('unable to retrieve project meta') - meta = self.__xml2etree(xml) + meta = xml2etree(xml) etree.SubElement(meta, 'group', groupid=groupid, role=role) return self.put_meta(prj, pkg, etree.tostring(meta)) diff --git a/obsapi/fileinfo.py b/obsapi/fileinfo.py new file mode 100644 index 0000000..7024bdd --- /dev/null +++ b/obsapi/fileinfo.py @@ -0,0 +1,102 @@ +# -*- coding: utf-8 -*- + +from lxml import etree +from datetime import datetime +from obsapi.formatter import Formatter +from obsapi.helpers import xml2etree + +class FileInfo(object): + file_str_template = ('{filename}' + 'size : {size}' + 'mtime : {mtime}' + ) + + pkg_str_template = ('{filename}' + 'Name : {name}' + 'Version : {version}' + 'Release : {release}' + 'Architecture: {arch}' + 'Size : {size}' + 'Source RPM : {source}' + 'Build Date : {mtime}' + 'Summary : {summary}' + 'Description :' + '{description}' + 'Provides :' + '{provides}' + ) + + src_str_template = ('{filename}' + 'Name : {name}' + 'Version : {version}' + 'Release : {release}' + 'Architecture: {arch}' + 'Size : {size}' + 'Build Date : {mtime}' + 'Summary : {summary}' + 'Description :' + '{description}' + ) + + def __init__(self, xml): + self.finfo = xml2etree(xml) + self.filename = self.finfo.get('filename', None) + self.formatter = Formatter(self) + + @property + def info(self): + info = {'filename': [self.filename]} + for item in self.finfo: + info.setdefault(item.tag, []).append(item.text) + + for item, value in info.items(): + if len(value) == 1: + info[item] = value[0] + # info[item] = '\n'.join(value) + + return info + + def __str__(self): + return self.formatter.render() + + def __getattr__(self, attr): + try: + values = [value.text for value in self.finfo.findall(attr)] + except Exception: + values = [None] + + if len(values) == 1: + return values[0] + else: + return values + + @property + def datetime(self): + if self.mtime: + return datetime.fromtimestamp(int(self.mtime)) + + @property + def xml(self): + return etree.tostring(self.finfo) + + @property + def is_pkg(self): + if self.arch: + return True + else: + return False + + @property + def is_src(self): + if self.source: + return False + else: + return True + + @property + def is_debug_info(self): + if '-' in self.name: + if self.name.split('-')[-1] in ('debuginfo', 'debugsource'): + return True + + return False diff --git a/obsapi/helpers.py b/obsapi/helpers.py new file mode 100644 index 0000000..6912035 --- /dev/null +++ b/obsapi/helpers.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +""" + obsapi: helper module + ~~~~~~~~~~~~~~~~~~~~~ + + This module contains helper functions + + + :copyright: Copyright (c) 2020 Scott Bahling, SUSE Linux GmbH + :license: GPL-2.0, see COPYING for details +""" +from io import BytesIO +from lxml import etree + + +def xml2etree(xml): + try: + if not isinstance(xml, bytes): + xml = xml.encode('utf-8') + parser = etree.XMLParser(remove_blank_text=True) + return etree.parse(BytesIO(xml), parser).xpath('.')[0] + except Exception as e: + raise e diff --git a/test/binary_fileinfo.xml b/test/binary_fileinfo.xml new file mode 100644 index 0000000..28a8dd5 --- /dev/null +++ b/test/binary_fileinfo.xml @@ -0,0 +1,40 @@ + + apache2 + 2.4.41 + 12.1 + src + The Apache Web Server + This version of httpd is a major release of the 2.4 stable branch, +and represents the best available version of Apache HTTP Server. +New features include Loadable MPMs, major improvements to OCSP support, +mod_lua, Dynamic Reverse Proxy configuration, Improved Authentication/ +Authorization, FastCGI Proxy, New Expression Parser, and a Small Object +Caching API. + + See /usr/share/doc/packages/apache2/, http://httpd.apache.org/, and +http://httpd.apache.org/docs-2.4/upgrading.html. + 7657917 + 1580719265 + apache-rpm-macros-control + apr-devel >= 1.5.0 + apr-util-devel + automake + db-devel + ed + firewall-macros + libcap-devel + libxml2-devel + lua-devel + openldap2-devel + openssl-devel >= 0.9.8a + pcre-devel + pkgconfig + pkgconfig(libbrotlidec) + pkgconfig(libbrotlienc) + pkgconfig(libnghttp2) >= 1.2.1 + pkgconfig(libsystemd) + pkgconfig(systemd) + systemd-rpm-macros + xz + zlib-devel + diff --git a/test/test_api.py b/test/test_api.py index 5769543..e45a284 100644 --- a/test/test_api.py +++ b/test/test_api.py @@ -47,6 +47,12 @@ def project_config(): return f.read() +@pytest.fixture +def binary_fileinfo(): + with open(os.path.join(test_dir, 'binary_fileinfo.xml'), 'rb') as f: + return f.read() + + @pytest.fixture def source_info(): return """ @@ -94,21 +100,6 @@ def binarylist(): """ -@pytest.fixture -def binary_fileinfo(): - return """ -suse-helloi -1.0 -1.1 -src -Sample Kernel Module Package -This package contains the hello.ko module. -51811507137122 -kmod-compat -kernel-syms -""" - - @pytest.fixture def project_meta(): return """ @@ -340,7 +331,7 @@ def test_source_info(requests_mock, source_info, rev): def test_get_binary_fileinfo(requests_mock, binary_fileinfo): matcher = re.compile('/build/.*/.*/.*/.*/.*?view=fileinfo') - requests_mock.get(matcher, text=binary_fileinfo) + requests_mock.get(matcher, content=binary_fileinfo) binary = 'suse-hello-1.0-1.1.src.rpm' expected_bfinfo = etree.fromstring(binary_fileinfo) diff --git a/test/test_fileinfo.py b/test/test_fileinfo.py new file mode 100644 index 0000000..18d1f15 --- /dev/null +++ b/test/test_fileinfo.py @@ -0,0 +1,26 @@ +import os +import pytest +from lxml import etree +from obsapi import FileInfo +from . import test_dir + + +with open(os.path.join(test_dir, 'binary_fileinfo.xml'), 'rb') as f: + xml_as_bytes = f.read() + + +with open(os.path.join(test_dir, 'binary_fileinfo.xml'), 'r') as f: + xml_as_str = f.read() + + +@pytest.mark.parametrize('xml', (xml_as_bytes, xml_as_str)) +def test_fileinfo(xml): + finfo = FileInfo(xml) + root = etree.fromstring(xml) + assert finfo.name == root.find('name').text + assert finfo.version == root.find('version').text + assert finfo.release == root.find('release').text + assert finfo.arch == root.find('arch').text + assert finfo.summary == root.find('summary').text + assert finfo.description == root.find('description').text + assert len(finfo.requires) == len(root.findall('requires')) -- cgit v1.2.3