Skip to content

Fix #18: encode() only if type is unicode (only for Py2) #23

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 26 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
05a4e60
python3: use six.string_types not version-dependant types
ydirson Jul 18, 2022
84d172a
python3: use "six.ensure_binary" and "six.ensure_text" for str/bytes …
ydirson Jul 18, 2022
7ac16be
Remove direct call's to file's constructor and replace them with call…
brettcannon May 25, 2007
520d419
python3: xcp.net.mac: use six.python_2_unicode_compatible for stringi…
ydirson Jul 18, 2022
a59c3ba
xcp.net.ifrename.logic: use "logger.warning", "logger.warn" is deprec…
ydirson Jul 18, 2022
0832486
python3: use raw strings for regexps, fixes insufficient quoting
ydirson Jul 18, 2022
7e14499
test_dom0: mock "open()" in a python3-compatible way
ydirson Jul 19, 2022
9c64243
ifrename: don't rely on dict ordering in tests
ydirson Jul 19, 2022
ae79078
test_cpio: ensure paths are handled as text
ydirson Jul 20, 2022
346ebc0
cpiofile: migrate last "list.sort()" call still using a "cmp" argument
ydirson Jul 26, 2022
5fd6cdf
WIP python3: fix xmlunwrap and its test to align with the use of bytes
ydirson Jul 25, 2022
67225f7
xcp.repository: switch from md5 to hashlib.md5
ydirson Jul 26, 2022
27fdfe9
WIP xcp.repository: switch from ConfigParser to configparser
ydirson Jul 26, 2022
b004cab
test: use parametrized tests
ydirson Sep 26, 2022
cdd5ee8
WIP test_accessor: check for I/O on binary files
ydirson Sep 26, 2022
71183e4
WIP test_accessor: write into copy file as binary
ydirson Sep 26, 2022
d6566dd
Pylint complements: honor len-as-condition convention
ydirson Jul 20, 2022
ac1b1b8
Pylint complements: whitespace in expressions
ydirson Jul 15, 2022
d58e988
Pylint complements: test_ifrename_logic: disable "no-member" warning
ydirson Aug 8, 2022
efeecfa
Pylint complements: avoid no-else-raise "refactor" issues
ydirson Aug 8, 2022
09ba68a
CI: also run tests with python3
ydirson Jul 26, 2022
75520a2
xcp/xmlunwrap.py:getText() Fix #18: encode only if not str(means: uni…
bernhardkaindl Apr 24, 2023
bc879ea
xcp/xmlunwrap.py:getText() follow-up for #18: Add type comments
bernhardkaindl Apr 24, 2023
b3eecaf
xcp/xmlunwrap.py: if len(matching) == 0 -> if not matching
bernhardkaindl Apr 24, 2023
9a82225
xcp/xmlunwrap.py: (default == None) -> default is None
bernhardkaindl Apr 24, 2023
6ea9741
xcp/xmlunwrap.py: Apply fixes for remarks by code checkers
bernhardkaindl Apr 24, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 19 additions & 13 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,48 +3,54 @@ name: Unit tests
on: [push, pull_request]

jobs:
test_py2:
runs-on: ubuntu-20.04
test:
strategy:
matrix:
include:
- pyversion: '2.7'
os: ubuntu-20.04
- pyversion: '3'
os: ubuntu-latest
runs-on: ${{ matrix.os }}

steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Set up Python 2.7
- name: Set up Python ${{ matrix.pyversion }}
uses: actions/setup-python@v2
with:
python-version: '2.7'
python-version: ${{ matrix.pyversion }}

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements-dev.txt
# FIXME: branding.py still has no permanent home
curl https://gist.github.com/ydirson/3c36a7e19d762cc529a6c82340894ccc/raw/5ca39f621b1feab813e171f535c1aad1bd483f1d/branding.py -O -L
pip install pyliblzma
pip install -e .
command -v xz

- name: Test
run: |
pytest --cov -rP
coverage xml
coverage html
coverage html -d htmlcov-tests --include="tests/*"
diff-cover --html-report coverage-diff.html coverage.xml
coverage html -d htmlcov-${{ matrix.pyversion }}
coverage html -d htmlcov-tests-${{ matrix.pyversion }} --include="tests/*"
diff-cover --compare-branch=origin/master --html-report coverage-diff-${{ matrix.pyversion }}.html coverage.xml

- name: Pylint
run: |
pylint --version
pylint --exit-zero xcp/ tests/ setup.py
pylint --exit-zero --msg-template="{path}:{line}: [{msg_id}({symbol}), {obj}] {msg}" xcp/ tests/ setup.py > pylint.txt
diff-quality --violations=pylint --html-report pylint-diff.html pylint.txt
diff-quality --compare-branch=origin/master --violations=pylint --html-report pylint-diff-${{ matrix.pyversion }}.html pylint.txt

- uses: actions/upload-artifact@v3
with:
name: Coverage and pylint reports
path: |
coverage-diff.html
pylint-diff.html
htmlcov
htmlcov-tests
coverage-diff-${{ matrix.pyversion }}.html
pylint-diff-${{ matrix.pyversion }}.html
htmlcov-${{ matrix.pyversion }}
htmlcov-tests-${{ matrix.pyversion }}
5 changes: 5 additions & 0 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ diff_cover
mock
pytest
pytest-cov
parameterized
# dependencies also in setup.py until they can be used
six
future

# python-2.7 only
configparser ; python_version < "3.0"
pyliblzma ; python_version < "3.0"
Binary file added tests/data/repo/boot/isolinux/mboot.c32
Binary file not shown.
37 changes: 29 additions & 8 deletions tests/test_accessor.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,42 @@
import unittest
import hashlib
from tempfile import NamedTemporaryFile

from parameterized import parameterized_class

import xcp.accessor

@parameterized_class([{"url": "file://tests/data/repo/"},
{"url": "https://updates.xcp-ng.org/netinstall/8.2.1"}])
class TestAccessor(unittest.TestCase):
def test_http(self):
raise unittest.SkipTest("comment out if you really mean it")
a = xcp.accessor.createAccessor("https://updates.xcp-ng.org/netinstall/8.2.1", True)
def test_access(self):
a = xcp.accessor.createAccessor(self.url, True)
a.start()
self.assertTrue(a.access('.treeinfo'))
self.assertFalse(a.access('no_such_file'))
self.assertEqual(a.lastError, 404)
a.finish()

def test_file(self):
a = xcp.accessor.createAccessor("file://tests/data/repo/", True)
def test_file_binfile(self):
BINFILE = "boot/isolinux/mboot.c32"
a = xcp.accessor.createAccessor(self.url, True)
a.start()
self.assertTrue(a.access('.treeinfo'))
self.assertFalse(a.access('no_such_file'))
self.assertEqual(a.lastError, 404)
self.assertTrue(a.access(BINFILE))
inf = a.openAddress(BINFILE)
with NamedTemporaryFile("wb") as outf:
while True:
data = inf.read()
if not data: # EOF
break
outf.write(data)
outf.flush()
hasher = hashlib.md5()
with open(outf.name, "rb") as bincontents:
while True:
data = bincontents.read()
if not data: # EOF
break
hasher.update(data)
csum = hasher.hexdigest()
self.assertEqual(csum, "eab52cebc3723863432dc672360f6dac")
a.finish()
4 changes: 2 additions & 2 deletions tests/test_cpio.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ def writeRandomFile(fn, size, start=b'', add=b'a'):
with open(fn, 'wb') as f:
m = md5()
m.update(start)
assert(len(add) != 0)
assert add
while size > 0:
d = m.digest()
if size < len(d):
d=d[:size]
d = d[:size]
f.write(d)
size -= len(d)
m.update(add)
Expand Down
4 changes: 2 additions & 2 deletions tests/test_dom0.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def mock_version(open_mock, version):
(2*1024, 4*1024, 8*1024), # Above max
]

with patch("__builtin__.open") as open_mock:
with patch("xcp.dom0.open") as open_mock:
for host_gib, dom0_mib, _ in test_values:
mock_version(open_mock, '2.8.0')
expected = dom0_mib * 1024;
Expand All @@ -39,7 +39,7 @@ def mock_version(open_mock, version):

open_mock.assert_called_with("/etc/xensource-inventory")

with patch("__builtin__.open") as open_mock:
with patch("xcp.dom0.open") as open_mock:
for host_gib, _, dom0_mib in test_values:
mock_version(open_mock, '2.9.0')
expected = dom0_mib * 1024;
Expand Down
4 changes: 2 additions & 2 deletions tests/test_ifrename_dynamic.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,10 @@ def test_pci_matching_invert(self):
MACPCI("c8:cb:b8:d3:0c:cf", "0000:04:00.0", kname="eth1",
ppn="", label="")])

self.assertEqual(dr.rules,[
self.assertEqual(set(dr.rules), set([
MACPCI("c8:cb:b8:d3:0c:ce", "0000:04:00.0", tname="eth1"),
MACPCI("c8:cb:b8:d3:0c:cf", "0000:04:00.0", tname="eth0")
])
]))

def test_pci_missing(self):

Expand Down
1 change: 1 addition & 0 deletions tests/test_ifrename_logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,7 @@ def test_ibft_nic_to_ibft(self):


class TestInputSanitisation(unittest.TestCase):
# pylint: disable=no-member

def setUp(self):
"""
Expand Down
24 changes: 12 additions & 12 deletions tests/test_ifrename_static.py
Original file line number Diff line number Diff line change
Expand Up @@ -375,10 +375,10 @@ def test_pci_matching(self):

sr.generate(self.state)

self.assertEqual(sr.rules,[
MACPCI("c8:cb:b8:d3:0c:cf", "0000:04:00.0", tname="eth1"),
MACPCI("c8:cb:b8:d3:0c:ce", "0000:04:00.0", tname="eth0")
])
self.assertEqual(set(sr.rules), set([
MACPCI("c8:cb:b8:d3:0c:cf", "0000:04:00.0", tname="eth1"),
MACPCI("c8:cb:b8:d3:0c:ce", "0000:04:00.0", tname="eth0")
]))

def test_pci_matching_invert(self):

Expand All @@ -389,10 +389,10 @@ def test_pci_matching_invert(self):

sr.generate(self.state)

self.assertEqual(sr.rules,[
MACPCI("c8:cb:b8:d3:0c:ce", "0000:04:00.0", tname="eth1"),
MACPCI("c8:cb:b8:d3:0c:cf", "0000:04:00.0", tname="eth0")
])
self.assertEqual(set(sr.rules), set([
MACPCI("c8:cb:b8:d3:0c:ce", "0000:04:00.0", tname="eth1"),
MACPCI("c8:cb:b8:d3:0c:cf", "0000:04:00.0", tname="eth0")
]))

def test_pci_matching_mixed(self):

Expand All @@ -403,10 +403,10 @@ def test_pci_matching_mixed(self):

sr.generate(self.state)

self.assertEqual(sr.rules,[
MACPCI("c8:cb:b8:d3:0c:cf", "0000:04:00.0", tname="eth0"),
MACPCI("c8:cb:b8:d3:0c:ce", "0000:04:00.0", tname="eth1")
])
self.assertEqual(set(sr.rules), set([
MACPCI("c8:cb:b8:d3:0c:cf", "0000:04:00.0", tname="eth0"),
MACPCI("c8:cb:b8:d3:0c:ce", "0000:04:00.0", tname="eth1")
]))

def test_pci_missing(self):

Expand Down
17 changes: 5 additions & 12 deletions tests/test_repository.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,15 @@
import unittest
from parameterized import parameterized_class

import xcp.accessor
from xcp import repository
from xcp.version import Version

@parameterized_class([{"url": "file://tests/data/repo/"},
{"url": "https://updates.xcp-ng.org/netinstall/8.2.1"}])
class TestRepository(unittest.TestCase):
def test_http(self):
raise unittest.SkipTest("comment out if you really mean it")
a = xcp.accessor.createAccessor("https://updates.xcp-ng.org/netinstall/8.2.1", True)
repo_ver = repository.BaseRepository.getRepoVer(a)
self.assertEqual(repo_ver, Version([3, 2, 1]))
product_ver = repository.BaseRepository.getProductVersion(a)
self.assertEqual(product_ver, Version([8, 2, 1]))
repos = repository.BaseRepository.findRepositories(a)
self.assertEqual(len(repos), 1)

def test_file(self):
a = xcp.accessor.createAccessor("file://tests/data/repo/", True)
def test_basicinfo(self):
a = xcp.accessor.createAccessor(self.url, True)
repo_ver = repository.BaseRepository.getRepoVer(a)
self.assertEqual(repo_ver, Version([3, 2, 1]))
product_ver = repository.BaseRepository.getProductVersion(a)
Expand Down
6 changes: 3 additions & 3 deletions xcp/bootloader.py
Original file line number Diff line number Diff line change
Expand Up @@ -336,19 +336,19 @@ def create_label(title):
try:
for line in fh:
l = line.strip()
menu_match = re.match("menuentry ['\"]([^']*)['\"](.*){", l)
menu_match = re.match(r"menuentry ['\"]([^']*)['\"](.*){", l)

# Only parse unindented default and timeout lines to prevent
# changing these lines in if statements.
if l.startswith('set default=') and l == line.rstrip():
default = l.split('=')[1]
match = re.match("['\"](.*)['\"]$", default)
match = re.match(r"['\"](.*)['\"]$", default)
if match:
default = match.group(1)
elif l.startswith('set timeout=') and l == line.rstrip():
timeout = int(l.split('=')[1]) * 10
elif l.startswith('serial'):
match = re.match("serial --unit=(\d+) --speed=(\d+)", l)
match = re.match(r"serial --unit=(\d+) --speed=(\d+)", l)
if match:
serial = {
'port': int(match.group(1)),
Expand Down
11 changes: 6 additions & 5 deletions xcp/cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,16 @@
"""Command processing"""

import subprocess
import six

import xcp.logger as logger

def runCmd(command, with_stdout = False, with_stderr = False, inputtext = None):
cmd = subprocess.Popen(command, bufsize = 1,
stdin = (inputtext and subprocess.PIPE or None),
stdout = subprocess.PIPE,
stderr = subprocess.PIPE,
shell = isinstance(command, str))
cmd = subprocess.Popen(command, bufsize=1,
stdin=(inputtext and subprocess.PIPE or None),
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
shell=isinstance(command, six.string_types))

(out, err) = cmd.communicate(inputtext)
rv = cmd.returncode
Expand Down
22 changes: 11 additions & 11 deletions xcp/cpiofile.py
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ def _init_write_gz(self):
self.__write(b"\037\213\010\010%s\002\377" % timestamp)
if self.name.endswith(".gz"):
self.name = self.name[:-3]
self.__write(self.name + NUL)
self.__write(six.ensure_binary(self.name) + NUL)

def write(self, s):
"""Write string s to the stream.
Expand Down Expand Up @@ -951,7 +951,7 @@ def __init__(self, name=None, mode="r", fileobj=None):
self.mode = {"r": "rb", "a": "r+b", "w": "wb"}[mode]

if not fileobj:
fileobj = file(name, self.mode)
fileobj = bltn_open(name, self.mode)
self._extfileobj = False
else:
if name is None and hasattr(fileobj, "name"):
Expand Down Expand Up @@ -1109,7 +1109,7 @@ def gzopen(cls, name, mode="r", fileobj=None, compresslevel=9):
raise CompressionError("gzip module is not available")

if fileobj is None:
fileobj = file(name, mode + "b")
fileobj = bltn_open(name, mode + "b")

try:
t = cls.cpioopen(name, mode, gzip.GzipFile(name, mode, compresslevel, fileobj))
Expand Down Expand Up @@ -1354,7 +1354,7 @@ def add(self, name, arcname=None, recursive=True):

# Append the cpio header and data to the archive.
if cpioinfo.isreg():
f = file(name, "rb")
f = bltn_open(name, "rb")
self.addfile(cpioinfo, f)
f.close()

Expand Down Expand Up @@ -1420,20 +1420,20 @@ def extractall(self, path=".", members=None):
# Extract directory with a safe mode, so that
# all files below can be extracted as well.
try:
os.makedirs(os.path.join(path, cpioinfo.name), 0o777)
os.makedirs(os.path.join(path, six.ensure_text(cpioinfo.name)), 0o777)
except EnvironmentError:
pass
directories.append(cpioinfo)
else:
self.extract(cpioinfo, path)

# Reverse sort directories.
directories.sort(lambda a, b: cmp(a.name, b.name))
directories.sort(key=lambda x: x.name)
directories.reverse()

# Set correct owner, mtime and filemode on directories.
for cpioinfo in directories:
path = os.path.join(path, cpioinfo.name)
path = os.path.join(path, six.ensure_text(cpioinfo.name))
try:
self.chown(cpioinfo, path)
self.utime(cpioinfo, path)
Expand Down Expand Up @@ -1462,7 +1462,7 @@ def extract(self, member, path=""):
cpioinfo._link_path = path

try:
self._extract_member(cpioinfo, os.path.join(path, cpioinfo.name))
self._extract_member(cpioinfo, os.path.join(path, six.ensure_text(cpioinfo.name)))
except EnvironmentError as e:
if self.errorlevel > 0:
raise
Expand Down Expand Up @@ -1594,7 +1594,7 @@ def makefile(self, cpioinfo, targetpath):

if extractinfo:
source = self.extractfile(extractinfo)
target = file(targetpath, "wb")
target = bltn_open(targetpath, "wb")
copyfileobj(source, target)
source.close()
target.close()
Expand Down Expand Up @@ -1926,5 +1926,5 @@ def is_cpiofile(name):
except CpioError:
return False

def cpioOpen(*al, **ad):
return CpioFile.open(*al, **ad)
bltn_open = open
open = CpioFile.open
2 changes: 1 addition & 1 deletion xcp/dom0.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ def default_memory(host_mem_kib):
return default_memory_for_version(host_mem_kib, platform_version)


_size_and_unit_re = re.compile("^(-?\d+)([bkmg]?)$", re.IGNORECASE)
_size_and_unit_re = re.compile(r"^(-?\d+)([bkmg]?)$", re.IGNORECASE)

def _parse_size_and_unit(s):
m = _size_and_unit_re.match(s)
Expand Down
Loading