From cb84f32edab717389d03a3855aa5bd4d0db1ae3c Mon Sep 17 00:00:00 2001 From: Andrew Cassidy Date: Mon, 18 Apr 2022 19:53:26 -0700 Subject: [PATCH] Migrate code style to Black --- docs/conf.py | 2 +- pyproject.toml | 5 ++ quicktex/__main__.py | 3 +- quicktex/cli/common.py | 5 +- quicktex/cli/decode.py | 47 +++++++++++----- quicktex/cli/encode.py | 121 ++++++++++++++++++++++++++++++---------- quicktex/dds.py | 28 +++++++++- quicktex/image_utils.py | 5 +- setup.py | 16 ++---- tests/test_bc1.py | 28 +++++----- tests/test_bc4.py | 21 ++++--- 11 files changed, 196 insertions(+), 85 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index f8f4079..dd0ab73 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -70,5 +70,5 @@ autodoc_default_options = { # should be linked to in this documentation. intersphinx_mapping = { 'python': ('https://docs.python.org/3', None), - 'PIL': ('https://pillow.readthedocs.io/en/stable/', None) + 'PIL': ('https://pillow.readthedocs.io/en/stable/', None), } diff --git a/pyproject.toml b/pyproject.toml index f71eaec..372f313 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -73,3 +73,8 @@ test-command = "cd /d {project} && python -m unittest --verbose" # windows why i skip = ["cp37-musllinux*", "*musllinux_aarch64*"] # skip targets without available Pillow wheels manylinux-x86_64-image = "manylinux2014" manylinux-aarch64-image = "manylinux2014" + +[tool.black] +line-length = 120 # 80-column is stupid +target-version = ['py37', 'py38', 'py39', 'py310'] +skip-string-normalization = true \ No newline at end of file diff --git a/quicktex/__main__.py b/quicktex/__main__.py index d001269..e650ac0 100644 --- a/quicktex/__main__.py +++ b/quicktex/__main__.py @@ -1,6 +1,7 @@ import click -from quicktex.cli.encode import encode + from quicktex.cli.decode import decode +from quicktex.cli.encode import encode @click.group() diff --git a/quicktex/cli/common.py b/quicktex/cli/common.py index 6efe26d..7c62897 100644 --- a/quicktex/cli/common.py +++ b/quicktex/cli/common.py @@ -1,7 +1,8 @@ -from PIL import Image -from typing import List import pathlib +from typing import List + import click +from PIL import Image def get_decoded_extensions(feature: str = 'open') -> List[str]: diff --git a/quicktex/cli/decode.py b/quicktex/cli/decode.py index 7674cc1..52a5462 100644 --- a/quicktex/cli/decode.py +++ b/quicktex/cli/decode.py @@ -1,28 +1,49 @@ -import click import os.path -import quicktex.dds as dds -import quicktex.cli.common as common + +import click from PIL import Image +import quicktex.cli.common as common +import quicktex.dds as dds + @click.command() -@click.option('-f/-F', '--flip/--no-flip', default=True, show_default=True, help="Vertically flip image after converting.") +@click.option( + '-f/-F', '--flip/--no-flip', default=True, show_default=True, help="Vertically flip image after converting." +) @click.option('-r', '--remove', is_flag=True, help="Remove input images after converting.") -@click.option('-s', '--suffix', type=str, default='', help="Suffix to append to output file(s). Ignored if output is a single file.") -@click.option('-x', '--extension', - callback=common.validate_decoded_extension, - type=str, default='.png', show_default=True, - help="Extension to use for output. Ignored if output is a single file. Output filetype is deduced from this") -@click.option('-o', '--output', - type=click.Path(writable=True), default=None, - help="Output file or directory. If outputting to a file, input filenames must be only a single item. By default, files are decoded in place.") +@click.option( + '-s', + '--suffix', + type=str, + default='', + help="Suffix to append to output file(s). Ignored if output is a single file.", +) +@click.option( + '-x', + '--extension', + callback=common.validate_decoded_extension, + type=str, + default='.png', + show_default=True, + help="Extension to use for output. Ignored if output is a single file. Output filetype is deduced from this", +) +@click.option( + '-o', + '--output', + type=click.Path(writable=True), + default=None, + help="Output file or directory. If outputting to a file, input filenames must be only a single item. By default, files are decoded in place.", +) @click.argument('filenames', nargs=-1, type=click.Path(exists=True, readable=True, dir_okay=False)) def decode(flip, remove, suffix, extension, output, filenames): """Decode DDS files to images.""" path_pairs = common.path_pairs(filenames, output, suffix, extension) - with click.progressbar(path_pairs, show_eta=False, show_pos=True, item_show_func=lambda x: str(x[0]) if x else '') as bar: + with click.progressbar( + path_pairs, show_eta=False, show_pos=True, item_show_func=lambda x: str(x[0]) if x else '' + ) as bar: for inpath, outpath in bar: if inpath.suffix != '.dds': raise click.BadArgumentUsage(f"Input file '{inpath}' is not a DDS file.") diff --git a/quicktex/cli/encode.py b/quicktex/cli/encode.py index 7438ea3..07a5113 100644 --- a/quicktex/cli/encode.py +++ b/quicktex/cli/encode.py @@ -1,13 +1,14 @@ -import click import os -import pathlib + +import click +from PIL import Image + +import quicktex.cli.common as common +import quicktex.dds as dds import quicktex.s3tc.bc1 import quicktex.s3tc.bc3 import quicktex.s3tc.bc4 import quicktex.s3tc.bc5 -import quicktex.dds as dds -import quicktex.cli.common as common -from PIL import Image @click.group() @@ -16,17 +17,31 @@ def encode(): @click.command() -@click.option('-f/-F', '--flip/--no-flip', default=True, show_default=True, help="Vertically flip image before converting.") +@click.option( + '-f/-F', '--flip/--no-flip', default=True, show_default=True, help="Vertically flip image before converting." +) @click.option('-r', '--remove', is_flag=True, help="Remove input images after converting.") -@click.option('-s', '--suffix', type=str, default='', help="Suffix to append to output file(s). Ignored if output is a single file.") -@click.option('-o', '--output', - type=click.Path(writable=True), default=None, - help="Output file or directory. If outputting to a file, input filenames must be only a single item. By default, files are decoded in place.") +@click.option( + '-s', + '--suffix', + type=str, + default='', + help="Suffix to append to output file(s). Ignored if output is a single file.", +) +@click.option( + '-o', + '--output', + type=click.Path(writable=True), + default=None, + help="Output file or directory. If outputting to a file, input filenames must be only a single item. By default, files are decoded in place.", +) @click.argument('filenames', nargs=-1, type=click.Path(exists=True, readable=True, dir_okay=False)) def encode_format(encoder, four_cc, flip, remove, suffix, output, filenames): path_pairs = common.path_pairs(filenames, output, suffix, '.dds') - with click.progressbar(path_pairs, show_eta=False, show_pos=True, item_show_func=lambda x: str(x[0]) if x else '') as bar: + with click.progressbar( + path_pairs, show_eta=False, show_pos=True, item_show_func=lambda x: str(x[0]) if x else '' + ) as bar: for inpath, outpath in bar: image = Image.open(inpath) @@ -40,17 +55,44 @@ def encode_format(encoder, four_cc, flip, remove, suffix, output, filenames): @click.command('auto') -@click.option('-l', '--level', type=click.IntRange(0, 18), default=18, help='Quality level to use. Higher values = higher quality, but slower.') -@click.option('-b/-B', '--black/--no-black', - help='[BC1 only] Enable 3-color mode for blocks containing black or very dark pixels. --3color must also be enabled for this to work.' - ' (Important: engine/shader MUST ignore decoded texture alpha if this flag is enabled!)') -@click.option('-3/-4', '--3color/--4color', 'threecolor', default=True, help='[BC1 only] Enable 3-color mode for non-black pixels. Higher quality, but slightly slower.') -@click.option('-f/-F', '--flip/--no-flip', default=True, show_default=True, help="Vertically flip image before converting.") +@click.option( + '-l', + '--level', + type=click.IntRange(0, 18), + default=18, + help='Quality level to use. Higher values = higher quality, but slower.', +) +@click.option( + '-b/-B', + '--black/--no-black', + help='[BC1 only] Enable 3-color mode for blocks containing black or very dark pixels. --3color must also be enabled for this to work.' + ' (Important: engine/shader MUST ignore decoded texture alpha if this flag is enabled!)', +) +@click.option( + '-3/-4', + '--3color/--4color', + 'threecolor', + default=True, + help='[BC1 only] Enable 3-color mode for non-black pixels. Higher quality, but slightly slower.', +) +@click.option( + '-f/-F', '--flip/--no-flip', default=True, show_default=True, help="Vertically flip image before converting." +) @click.option('-r', '--remove', is_flag=True, help="Remove input images after converting.") -@click.option('-s', '--suffix', type=str, default='', help="Suffix to append to output file(s). Ignored if output is a single file.") -@click.option('-o', '--output', - type=click.Path(writable=True), default=None, - help="Output file or directory. If outputting to a file, input filenames must be only a single item. By default, files are decoded in place.") +@click.option( + '-s', + '--suffix', + type=str, + default='', + help="Suffix to append to output file(s). Ignored if output is a single file.", +) +@click.option( + '-o', + '--output', + type=click.Path(writable=True), + default=None, + help="Output file or directory. If outputting to a file, input filenames must be only a single item. By default, files are decoded in place.", +) @click.argument('filenames', nargs=-1, type=click.Path(exists=True, readable=True, dir_okay=False)) def encode_auto(level, black, threecolor, flip, remove, suffix, output, filenames): """Encode images to BC1 or BC3, with the format chosen based on each image's alpha channel.""" @@ -67,7 +109,9 @@ def encode_auto(level, black, threecolor, flip, remove, suffix, output, filename bc3_encoder = quicktex.s3tc.bc3.BC3Encoder(level) path_pairs = common.path_pairs(filenames, output, suffix, '.dds') - with click.progressbar(path_pairs, show_eta=False, show_pos=True, item_show_func=lambda x: str(x[0]) if x else '') as bar: + with click.progressbar( + path_pairs, show_eta=False, show_pos=True, item_show_func=lambda x: str(x[0]) if x else '' + ) as bar: for inpath, outpath in bar: image = Image.open(inpath) @@ -90,11 +134,26 @@ def encode_auto(level, black, threecolor, flip, remove, suffix, output, filename @click.command('bc1') -@click.option('-l', '--level', type=click.IntRange(0, 18), default=18, help='Quality level to use. Higher values = higher quality, but slower.') -@click.option('-b/-B', '--black/--no-black', - help='Enable 3-color mode for blocks containing black or very dark pixels. --3color must also be enabled for this to work.' - ' (Important: engine/shader MUST ignore decoded texture alpha if this flag is enabled!)') -@click.option('-3/-4', '--3color/--4color', 'threecolor', default=True, help='Enable 3-color mode for non-black pixels. Higher quality, but slightly slower.') +@click.option( + '-l', + '--level', + type=click.IntRange(0, 18), + default=18, + help='Quality level to use. Higher values = higher quality, but slower.', +) +@click.option( + '-b/-B', + '--black/--no-black', + help='Enable 3-color mode for blocks containing black or very dark pixels. --3color must also be enabled for this to work.' + ' (Important: engine/shader MUST ignore decoded texture alpha if this flag is enabled!)', +) +@click.option( + '-3/-4', + '--3color/--4color', + 'threecolor', + default=True, + help='Enable 3-color mode for non-black pixels. Higher quality, but slightly slower.', +) def encode_bc1(level, black, threecolor, **kwargs): """Encode images to BC1 (RGB, no alpha).""" color_mode = quicktex.s3tc.bc1.BC1Encoder.ColorMode @@ -109,7 +168,13 @@ def encode_bc1(level, black, threecolor, **kwargs): @click.command('bc3') -@click.option('-l', '--level', type=click.IntRange(0, 18), default=18, help='Quality level to use. Higher values = higher quality, but slower.') +@click.option( + '-l', + '--level', + type=click.IntRange(0, 18), + default=18, + help='Quality level to use. Higher values = higher quality, but slower.', +) def encode_bc3(level, **kwargs): """Encode images to BC4 (RGBA, 8-bit interpolated alpha).""" encode_format.callback(quicktex.s3tc.bc3.BC3Encoder(level), 'DXT5', **kwargs) diff --git a/quicktex/dds.py b/quicktex/dds.py index a6ae106..aff5bd5 100644 --- a/quicktex/dds.py +++ b/quicktex/dds.py @@ -4,12 +4,14 @@ import enum import os import struct import typing + +from PIL import Image + import quicktex.image_utils import quicktex.s3tc.bc1 as bc1 import quicktex.s3tc.bc3 as bc3 import quicktex.s3tc.bc4 as bc4 import quicktex.s3tc.bc5 as bc5 -from PIL import Image class DDSFormat: @@ -165,8 +167,28 @@ class DDSFile: file.write(DDSFile.magic) # WRITE HEADER - file.write(struct.pack('<7I44x', DDSFile.header_bytes, int(self.flags), self.size[1], self.size[0], self.pitch, self.depth, self.mipmap_count)) - file.write(struct.pack('<2I4s5I', 32, int(self.pf_flags), bytes(self.four_cc, 'ascii'), self.pixel_size, *self.pixel_bitmasks)) + file.write( + struct.pack( + '<7I44x', + DDSFile.header_bytes, + int(self.flags), + self.size[1], + self.size[0], + self.pitch, + self.depth, + self.mipmap_count, + ) + ) + file.write( + struct.pack( + '<2I4s5I', + 32, + int(self.pf_flags), + bytes(self.four_cc, 'ascii'), + self.pixel_size, + *self.pixel_bitmasks, + ) + ) file.write(struct.pack('<4I4x', *self.caps)) assert file.tell() == 4 + DDSFile.header_bytes, 'error writing file: incorrect header size' diff --git a/quicktex/image_utils.py b/quicktex/image_utils.py index e9b6d4b..f44397a 100644 --- a/quicktex/image_utils.py +++ b/quicktex/image_utils.py @@ -1,8 +1,9 @@ """Various utilities for working with Pillow images""" -from PIL import Image -from typing import List, Tuple, Optional import math +from typing import List, Tuple, Optional + +from PIL import Image def mip_sizes(dimensions: Tuple[int, int], mip_count: Optional[int] = None) -> List[Tuple[int, int]]: diff --git a/setup.py b/setup.py index 51f7c12..c7af897 100644 --- a/setup.py +++ b/setup.py @@ -22,6 +22,7 @@ class CMakeExtension(Extension): class CMakeBuild(build_ext): def build_extension(self, ext): from setuptools_scm import get_version + version = get_version(root='.', relative_to=__file__) extdir = os.path.abspath(os.path.dirname(self.get_ext_fullpath(ext.name))) @@ -45,7 +46,8 @@ class CMakeBuild(build_ext): "-DQUICKTEX_VERSION_INFO={}".format(version), "-DCMAKE_BUILD_TYPE={}".format(cfg), # not used on MSVC, but no harm # clear cached make program binary, see https://github.com/pypa/setuptools/issues/2912 - "-U", "CMAKE_MAKE_PROGRAM", + "-U", + "CMAKE_MAKE_PROGRAM", ] build_args = [] @@ -81,9 +83,7 @@ class CMakeBuild(build_ext): # Multi-config generators have a different way to specify configs if not single_config: - cmake_args += [ - "-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_{}={}".format(cfg.upper(), extdir) - ] + cmake_args += ["-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_{}={}".format(cfg.upper(), extdir)] build_args += ["--config", cfg] if sys.platform.startswith("darwin"): @@ -104,12 +104,8 @@ class CMakeBuild(build_ext): if not os.path.exists(self.build_temp): os.makedirs(self.build_temp) - subprocess.check_call( - ["cmake", ext.sourcedir] + cmake_args, cwd=self.build_temp - ) - subprocess.check_call( - ["cmake", "--build", ".", "--target", ext.name] + build_args, cwd=self.build_temp - ) + subprocess.check_call(["cmake", ext.sourcedir] + cmake_args, cwd=self.build_temp) + subprocess.check_call(["cmake", "--build", ".", "--target", ext.name] + build_args, cwd=self.build_temp) # The information here can also be placed in setup.cfg - better separation of diff --git a/tests/test_bc1.py b/tests/test_bc1.py index c886a6d..1108c3a 100644 --- a/tests/test_bc1.py +++ b/tests/test_bc1.py @@ -58,12 +58,8 @@ class TestBC1Block(unittest.TestCase): @parameterized_class( - ("name", "w", "h", "wb", "hb"), [ - ("8x8", 8, 8, 2, 2), - ("9x9", 9, 9, 3, 3), - ("7x7", 7, 7, 2, 2), - ("7x9", 7, 9, 2, 3) - ]) + ("name", "w", "h", "wb", "hb"), [("8x8", 8, 8, 2, 2), ("9x9", 9, 9, 3, 3), ("7x7", 7, 7, 2, 2), ("7x9", 7, 9, 2, 3)] +) class TestBC1Texture(unittest.TestCase): def setUp(self): self.tex = BC1Texture(self.w, self.h) @@ -98,7 +94,7 @@ class TestBC1Texture(unittest.TestCase): for y in range(self.hb): index = (x + (y * self.wb)) * BC1Block.nbytes tb = self.tex[x, y] - fb = BC1Block.frombytes(b[index:index + BC1Block.nbytes]) + fb = BC1Block.frombytes(b[index : index + BC1Block.nbytes]) self.assertEqual(tb, blocks[y][x], 'incorrect block read from texture') self.assertEqual(fb, blocks[y][x], 'incorrect block read from texture bytes') @@ -124,11 +120,13 @@ class TestBC1Texture(unittest.TestCase): @parameterized_class( - ("name", "color_mode"), [ + ("name", "color_mode"), + [ ("4Color", BC1Encoder.ColorMode.FourColor), ("3Color", BC1Encoder.ColorMode.ThreeColor), ("3Color_Black", BC1Encoder.ColorMode.ThreeColorBlack), - ]) + ], +) class TestBC1Encoder(unittest.TestCase): """Test BC1Encoder""" @@ -189,11 +187,13 @@ class TestBC1Decoder(unittest.TestCase): def setUpClass(cls): cls.bc1_decoder = BC1Decoder() - @parameterized.expand([ - ("4color", BC1Blocks.greyscale.block, BC1Blocks.greyscale.image), - ("3color", BC1Blocks.three_color.block, BC1Blocks.three_color.image), - ("3color_black", BC1Blocks.three_color_black.block, BC1Blocks.three_color_black.image) - ]) + @parameterized.expand( + [ + ("4color", BC1Blocks.greyscale.block, BC1Blocks.greyscale.image), + ("3color", BC1Blocks.three_color.block, BC1Blocks.three_color.image), + ("3color_black", BC1Blocks.three_color_black.block, BC1Blocks.three_color_black.image), + ] + ) def test_block(self, _, block, image): """Test decoder output for a single block""" in_tex = BC1Texture(4, 4) diff --git a/tests/test_bc4.py b/tests/test_bc4.py index 207dee1..e5a6ad5 100644 --- a/tests/test_bc4.py +++ b/tests/test_bc4.py @@ -7,6 +7,7 @@ from PIL import Image, ImageChops class TestBC4Block(unittest.TestCase): """Tests for the BC1Block class""" + block_bytes = b'\xF0\x10\x88\x86\x68\xAC\xCF\xFA' selectors = [[0, 1, 2, 3]] * 2 + [[4, 5, 6, 7]] * 2 endpoints = (240, 16) @@ -68,12 +69,8 @@ class TestBC4Block(unittest.TestCase): @parameterized_class( - ("name", "w", "h", "wb", "hb"), [ - ("8x8", 8, 8, 2, 2), - ("9x9", 9, 9, 3, 3), - ("7x7", 7, 7, 2, 2), - ("7x9", 7, 9, 2, 3) - ]) + ("name", "w", "h", "wb", "hb"), [("8x8", 8, 8, 2, 2), ("9x9", 9, 9, 3, 3), ("7x7", 7, 7, 2, 2), ("7x9", 7, 9, 2, 3)] +) class TestBC4Texture(unittest.TestCase): def setUp(self): self.tex = BC4Texture(self.w, self.h) @@ -108,7 +105,7 @@ class TestBC4Texture(unittest.TestCase): for y in range(self.hb): index = (x + (y * self.wb)) * BC4Block.nbytes tb = self.tex[x, y] - fb = BC4Block.frombytes(b[index:index + BC4Block.nbytes]) + fb = BC4Block.frombytes(b[index : index + BC4Block.nbytes]) self.assertEqual(tb, blocks[y][x], 'incorrect block read from texture') self.assertEqual(fb, blocks[y][x], 'incorrect block read from texture bytes') @@ -160,10 +157,12 @@ class TestBC4Decoder(unittest.TestCase): def setUpClass(cls): cls.bc4_decoder = BC4Decoder(0) - @parameterized.expand([ - ("8value", BC4Blocks.eight_value.block, BC4Blocks.eight_value.image), - ("6value", BC4Blocks.six_value.block, BC4Blocks.six_value.image), - ]) + @parameterized.expand( + [ + ("8value", BC4Blocks.eight_value.block, BC4Blocks.eight_value.image), + ("6value", BC4Blocks.six_value.block, BC4Blocks.six_value.image), + ] + ) def test_block(self, _, block, image): """Test decoder output for a single block""" in_tex = BC4Texture(4, 4)