From 8aa440cb0b8933339df152d3d5aa3f85be3412d7 Mon Sep 17 00:00:00 2001 From: Martin Thoma Date: Fri, 15 Apr 2022 18:23:27 +0200 Subject: [PATCH] DEV: Add mutmut (#760) --- .gitignore | 4 ++++ Makefile | 7 +++++++ PyPDF2/filters.py | 14 +++++++------- PyPDF2/generic.py | 22 ++++++++++------------ PyPDF2/pdf.py | 10 +++++----- PyPDF2/utils.py | 9 +++++---- Tests/test_pagerange.py | 7 +++++++ mutmut-test.sh | 2 ++ 8 files changed, 47 insertions(+), 28 deletions(-) create mode 100644 mutmut-test.sh diff --git a/.gitignore b/.gitignore index c47edb777..4a9c9ab80 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,10 @@ build *.egg-info/ dist/* +# +.mutmut-cache +mutmut-results.* + # Code coverage artifacts .coverage* coverage.xml diff --git a/Makefile b/Makefile index 8516f1e25..a6bbb5ddc 100644 --- a/Makefile +++ b/Makefile @@ -15,3 +15,10 @@ clean: test: pytest Tests --cov --cov-report term-missing -vv --cov-report html + +mutation-test: + mutmut run + +mutmut-results: + mutmut junitxml --suspicious-policy=ignore --untested-policy=ignore > mutmut-results.xml + junit2html mutmut-results.xml mutmut-results.html diff --git a/PyPDF2/filters.py b/PyPDF2/filters.py index 8b72f0932..6a409a62e 100644 --- a/PyPDF2/filters.py +++ b/PyPDF2/filters.py @@ -157,11 +157,11 @@ def decode(data, decodeParms): # unsupported predictor raise PdfReadError("Unsupported flatedecode predictor %r" % predictor) return data - decode = staticmethod(decode) + decode = staticmethod(decode) # type: ignore def encode(data): return compress(data) - encode = staticmethod(encode) + encode = staticmethod(encode) # type: ignore class ASCIIHexDecode(object): @@ -183,7 +183,7 @@ def decode(data, decodeParms=None): x += 1 assert char == "" return retval - decode = staticmethod(decode) + decode = staticmethod(decode) # type: ignore class LZWDecode(object): @@ -339,17 +339,17 @@ def decode(data, decodeParms=None): out += struct.pack(b'>L',b)[:n-1] break return bytes(out) - decode = staticmethod(decode) + decode = staticmethod(decode) # type: ignore class DCTDecode(object): def decode(data, decodeParms=None): return data - decode = staticmethod(decode) + decode = staticmethod(decode) # type: ignore class JPXDecode(object): def decode(data, decodeParms=None): return data - decode = staticmethod(decode) + decode = staticmethod(decode) # type: ignore class CCITTFaxDecode(object): def decode(data, decodeParms=None, height=0): @@ -384,7 +384,7 @@ def decode(data, decodeParms=None, height=0): return tiffHeader + data - decode = staticmethod(decode) + decode = staticmethod(decode) # type: ignore def decodeStreamData(stream): from .generic import NameObject diff --git a/PyPDF2/generic.py b/PyPDF2/generic.py index 2ae9a7471..c0691694d 100644 --- a/PyPDF2/generic.py +++ b/PyPDF2/generic.py @@ -1,5 +1,3 @@ -# vim: sw=4:expandtab:foldmethod=marker -# # Copyright (c) 2006, Mathieu Fenniak # All rights reserved. # @@ -114,7 +112,7 @@ def readFromStream(stream): if nulltxt != b_("null"): raise utils.PdfReadError("Could not read Null object") return NullObject() - readFromStream = staticmethod(readFromStream) + readFromStream = staticmethod(readFromStream) # type: ignore class BooleanObject(PdfObject): @@ -136,7 +134,7 @@ def readFromStream(stream): return BooleanObject(False) else: raise utils.PdfReadError('Could not read Boolean object') - readFromStream = staticmethod(readFromStream) + readFromStream = staticmethod(readFromStream) # type: ignore class ArrayObject(list, PdfObject): @@ -166,7 +164,7 @@ def readFromStream(stream, pdf): # read and append obj arr.append(readObject(stream, pdf)) return arr - readFromStream = staticmethod(readFromStream) + readFromStream = staticmethod(readFromStream) # type: ignore class IndirectObject(PdfObject): @@ -219,7 +217,7 @@ def readFromStream(stream, pdf): if r != b_("R"): raise utils.PdfReadError("Error reading indirect object reference at byte %s" % utils.hexStr(stream.tell())) return IndirectObject(int(idnum), int(generation), pdf) - readFromStream = staticmethod(readFromStream) + readFromStream = staticmethod(readFromStream) # type: ignore class FloatObject(decimal.Decimal, PdfObject): @@ -270,7 +268,7 @@ def readFromStream(stream): return FloatObject(num) else: return NumberObject(num) - readFromStream = staticmethod(readFromStream) + readFromStream = staticmethod(readFromStream) # type: ignore def createStringObject(string): @@ -391,7 +389,7 @@ def readStringFromStream(stream): return createStringObject(txt) -class ByteStringObject(utils.bytes_type, PdfObject): +class ByteStringObject(utils.bytes_type, PdfObject): # type: ignore """ Represents a string object where the text encoding could not be determined. This occurs quite often, as the PDF spec doesn't provide an alternate way to @@ -413,7 +411,7 @@ def writeToStream(self, stream, encryption_key): stream.write(b_(">")) -class TextStringObject(utils.string_type, PdfObject): +class TextStringObject(utils.string_type, PdfObject): # type: ignore """ Represents a string object that has been decoded into a real unicode string. If read from a PDF document, this string appeared to match the @@ -497,7 +495,7 @@ def readFromStream(stream, pdf): else: raise utils.PdfReadError("Illegal character in Name Object") - readFromStream = staticmethod(readFromStream) + readFromStream = staticmethod(readFromStream) # type: ignore class DictionaryObject(dict, PdfObject): @@ -642,7 +640,7 @@ def readFromStream(stream, pdf): retval = DictionaryObject() retval.update(data) return retval - readFromStream = staticmethod(readFromStream) + readFromStream = staticmethod(readFromStream) # type: ignore class TreeObject(DictionaryObject): @@ -802,7 +800,7 @@ def initializeFromDictionary(data): del data["/Length"] retval.update(data) return retval - initializeFromDictionary = staticmethod(initializeFromDictionary) + initializeFromDictionary = staticmethod(initializeFromDictionary) # type: ignore def flateEncode(self): if "/Filter" in self: diff --git a/PyPDF2/pdf.py b/PyPDF2/pdf.py index 6d1824384..547284f80 100644 --- a/PyPDF2/pdf.py +++ b/PyPDF2/pdf.py @@ -2224,7 +2224,7 @@ def createBlankPage(pdf=None, width=None, height=None): RectangleObject([0, 0, width, height])) return page - createBlankPage = staticmethod(createBlankPage) + createBlankPage = staticmethod(createBlankPage) # type: ignore def rotateClockwise(self, angle): """ @@ -2266,7 +2266,7 @@ def _mergeResources(res1, res2, resource): elif key not in newRes: newRes[key] = page2Res.raw_get(key) return newRes, renameRes - _mergeResources = staticmethod(_mergeResources) + _mergeResources = staticmethod(_mergeResources) # type: ignore def _contentStreamRename(stream, rename, pdf): if not rename: @@ -2286,7 +2286,7 @@ def _contentStreamRename(stream, rename, pdf): else: raise KeyError ("type of operands is %s" % type (operands)) return stream - _contentStreamRename = staticmethod(_contentStreamRename) + _contentStreamRename = staticmethod(_contentStreamRename) # type: ignore def _pushPopGS(contents, pdf): # adds a graphics state "push" and "pop" to the beginning and end @@ -2296,7 +2296,7 @@ def _pushPopGS(contents, pdf): stream.operations.insert(0, [[], "q"]) stream.operations.append([[], "Q"]) return stream - _pushPopGS = staticmethod(_pushPopGS) + _pushPopGS = staticmethod(_pushPopGS) # type: ignore def _addTransformationMatrix(contents, pdf, ctm): # adds transformation matrix at the beginning of the given @@ -2307,7 +2307,7 @@ def _addTransformationMatrix(contents, pdf, ctm): FloatObject(c), FloatObject(d), FloatObject(e), FloatObject(f)], " cm"]) return contents - _addTransformationMatrix = staticmethod(_addTransformationMatrix) + _addTransformationMatrix = staticmethod(_addTransformationMatrix) # type: ignore def getContents(self): """ diff --git a/PyPDF2/utils.py b/PyPDF2/utils.py index 87b3a8b24..639471d4a 100644 --- a/PyPDF2/utils.py +++ b/PyPDF2/utils.py @@ -35,9 +35,10 @@ import sys try: - import __builtin__ as builtins -except ImportError: # Py3 import builtins + from typing import Dict +except ImportError: # Py2.7 + import __builtin__ as builtins # type: ignore ERR_STREAM_TRUNCATED_PREMATURELY = "Stream has ended unexpectedly" xrange_fn = getattr(builtins, "xrange", range) @@ -45,7 +46,7 @@ bytes_type = type(bytes()) # Works the same in Python 2.X and 3.X string_type = getattr(builtins, "unicode", str) -int_types = (int, long) if sys.version_info[0] < 3 else (int,) # noqa +int_types = (int, long) if sys.version_info[0] < 3 else (int,) # type: ignore # noqa # Make basic type tests more consistent @@ -227,7 +228,7 @@ class PdfStreamError(PdfReadError): def b_(s): return s else: - B_CACHE = {} + B_CACHE = {} # type: Dict[str, bytes] def b_(s): bc = B_CACHE diff --git a/Tests/test_pagerange.py b/Tests/test_pagerange.py index 05bd5fee0..b90feef00 100644 --- a/Tests/test_pagerange.py +++ b/Tests/test_pagerange.py @@ -58,3 +58,10 @@ def test_parse_filename_page_ranges(params, expected): def test_parse_filename_page_ranges_err(): with pytest.raises(ValueError): parse_filename_page_ranges(["1:5", "foo.pdf"]) + + +def test_page_range_help(): + from PyPDF2.pagerange import PAGE_RANGE_HELP + assert len(PAGE_RANGE_HELP) > 20 + assert "0:3" in PAGE_RANGE_HELP + assert PAGE_RANGE_HELP.endswith("\n") diff --git a/mutmut-test.sh b/mutmut-test.sh new file mode 100644 index 000000000..94cbc86a8 --- /dev/null +++ b/mutmut-test.sh @@ -0,0 +1,2 @@ +#!/bin/bash -e +pytest -x \ No newline at end of file