diff --git a/pyproject.toml b/pyproject.toml index f54171b..da9de17 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["setuptools"] +requires = ["setuptools >= 77.0.3"] build-backend = "setuptools.build_meta" [project] @@ -19,17 +19,17 @@ license = "MIT" license-files = ["LICENSE"] keywords = ["embroidery", "file conversion"] classifiers = [ - "Development Status :: 5 - Production/Stable", - "Intended Audience :: Developers", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12", - "Programming Language :: Python :: 3.13", - "Operating System :: OS Independent", - "Topic :: Software Development :: Libraries :: Python Modules" + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Operating System :: OS Independent", + "Topic :: Software Development :: Libraries :: Python Modules" ] [project.urls] -Repository = "https://github.com/inkstitch/pystitch" +Repository = "https://github.com/inkstitch/pystitch.git" Issues = "https://github.com/inkstitch/pystitch/issues" diff --git a/src/pystitch/EmbPattern.py b/src/pystitch/EmbPattern.py index 7bf9f3d..9d6a1d4 100644 --- a/src/pystitch/EmbPattern.py +++ b/src/pystitch/EmbPattern.py @@ -1,4 +1,5 @@ import os +from pathlib import PurePath from .EmbEncoder import Transcoder as Normalizer from .EmbFunctions import * @@ -86,7 +87,7 @@ def __iadd__(self, other): self.add_command(other) elif isinstance(other, list) or isinstance(other, tuple): # tuple or list if len(other) == 0: - return + return self v = other[0] if isinstance(v, list) or isinstance( v, tuple @@ -245,8 +246,8 @@ def bounds(self): min_x, min_y, max_x, max_y""" min_x = float("inf") min_y = float("inf") - max_x = -float("inf") - max_y = -float("inf") + max_x = float("-inf") + max_y = float("-inf") for stitch in self.stitches: if stitch[0] > max_x: @@ -541,7 +542,7 @@ def add_pattern(self, pattern, dx=None, dy=None, sx=None, sy=None, rotate=None): if dy is None: dy = 0 self.add_command(MATRIX_TRANSLATE, dx, dy) - if sx is not None or sx is not None: + if sx is not None or sy is not None: if sx is None: sx = sy if sy is None: @@ -625,15 +626,9 @@ def interpolate_frame_eject(self): while position < ie: stitch = self.stitches[position] data = stitch[2] & COMMAND_MASK - if ( - data == STITCH - or data == SEW_TO - or data == NEEDLE_AT - or data == COLOR_CHANGE - or data == COLOR_BREAK - or data == NEEDLE_SET - ): + if data in (STITCH, SEW_TO, NEEDLE_AT, COLOR_CHANGE, COLOR_BREAK, NEEDLE_SET): if mode == 3: + assert sequence_start_position is not None del self.stitches[sequence_start_position:position] position = sequence_start_position self.stitches.insert(position, [stop_x, stop_y, FRAME_EJECT]) @@ -652,6 +647,7 @@ def interpolate_frame_eject(self): stop_y = stitch[1] position += 1 if mode >= 2: # Frame_eject at end. + assert sequence_start_position is not None del self.stitches[sequence_start_position:position] position = sequence_start_position self.stitches.insert(position, [stop_x, stop_y, FRAME_EJECT]) @@ -798,7 +794,7 @@ def append_translation(self, x, y): @staticmethod def get_extension_by_filename(filename): """extracts the extension from a filename""" - return os.path.splitext(filename)[1][1:] + return PurePath(filename).suffix[1:] @staticmethod def read_embroidery(reader, f, settings=None, pattern=None): @@ -808,24 +804,20 @@ def read_embroidery(reader, f, settings=None, pattern=None): if pattern is None: pattern = EmbPattern() - if isinstance(f, str): - text_mode = False - try: - text_mode = reader.READ_FILE_IN_TEXT_MODE - except AttributeError: - pass + if isinstance(f, (str, os.PathLike)): + text_mode = getattr(reader, "READ_FILE_IN_TEXT_MODE", False) if text_mode: try: with open(f, "r", errors='ignore') as stream: - reader.read(stream, pattern, settings) - stream.close() + return EmbPattern.read_embroidery(reader, stream, settings, pattern) except IOError: - pass + return pattern else: with open(f, "rb") as stream: - reader.read(stream, pattern, settings) - else: - reader.read(f, pattern, settings) + return EmbPattern.read_embroidery(reader, stream, settings, pattern) + + reader.read(f, pattern, settings) + return pattern @@ -833,84 +825,76 @@ def read_embroidery(reader, f, settings=None, pattern=None): def write_embroidery(writer, pattern, stream, settings=None): if pattern is None: return + + if isinstance(stream, (str, os.PathLike)): + text_mode = getattr(writer, "WRITE_FILE_IN_TEXT_MODE", False) + file_mode = "w" if text_mode else "wb" + with open(stream, file_mode) as stream: + return EmbPattern.write_embroidery(writer, pattern, stream, settings) + if settings is None: settings = {} else: settings = settings.copy() - try: - encode = writer.ENCODE - except AttributeError: - encode = True + + encode = getattr(writer, "ENCODE", True) if settings.get("encode", encode): - if not ("max_jump" in settings): + if "max_jump" not in settings: try: settings["max_jump"] = writer.MAX_JUMP_DISTANCE except AttributeError: pass - if not ("max_stitch" in settings): + if "max_stitch" not in settings: try: settings["max_stitch"] = writer.MAX_STITCH_DISTANCE except AttributeError: pass - if not ("full_jump" in settings): + if "full_jump" not in settings: try: settings["full_jump"] = writer.FULL_JUMP except AttributeError: pass - if not ("round" in settings): + if "round" not in settings: try: settings["round"] = writer.ROUND except AttributeError: pass - if not ("writes_speeds" in settings): + if "writes_speeds" not in settings: try: settings["writes_speeds"] = writer.WRITES_SPEEDS except AttributeError: pass - if not ("sequin_contingency" in settings): + if "sequin_contingency" not in settings: try: settings["sequin_contingency"] = writer.SEQUIN_CONTINGENCY except AttributeError: pass - if not ("thread_change_command" in settings): + if "thread_change_command" not in settings: try: settings["thread_change_command"] = writer.THREAD_CHANGE_COMMAND except AttributeError: pass - if not ("explicit_trim" in settings): + if "explicit_trim" not in settings: try: settings["explicit_trim"] = writer.EXPLICIT_TRIM except AttributeError: pass - if not ("translate" in settings): + if "translate" not in settings: try: settings["translate"] = writer.TRANSLATE except AttributeError: pass - if not ("scale" in settings): + if "scale" not in settings: try: settings["scale"] = writer.SCALE except AttributeError: pass - if not ("rotate" in settings): + if "rotate" not in settings: try: settings["rotate"] = writer.ROTATE except AttributeError: pass pattern = pattern.get_normalized_pattern(settings) - if isinstance(stream, str): - text_mode = False - try: - text_mode = writer.WRITE_FILE_IN_TEXT_MODE - except AttributeError: - pass - if text_mode: - with open(stream, "w") as stream: - writer.write(pattern, stream, settings) - else: - with open(stream, "wb") as stream: - writer.write(pattern, stream, settings) - else: - writer.write(pattern, stream, settings) + writer.write(pattern, stream, settings) diff --git a/src/pystitch/EmbThread.py b/src/pystitch/EmbThread.py index 99b2beb..0db0ac1 100644 --- a/src/pystitch/EmbThread.py +++ b/src/pystitch/EmbThread.py @@ -1,3 +1,5 @@ +from typing import Optional + def build_unique_palette(thread_palette, threadlist): """Turns a threadlist into a unique index list with the thread palette""" chart = [None] * len(thread_palette) # Create a lookup chart. @@ -93,21 +95,21 @@ def color_distance_red_mean(r1, g1, b1, r2, g2, b2): class EmbThread: def __init__( self, - thread=None, - description=None, - catalog_number=None, - details=None, - brand=None, - chart=None, - weight=None, + thread = None, + description: Optional[str] = None, + catalog_number: Optional[str] = None, + details: Optional[str] = None, + brand: Optional[str] = None, + chart: Optional[str] = None, + weight: Optional[str] = None, ): - self.color = 0x000000 - self.description = description # type: str - self.catalog_number = catalog_number # type: str - self.details = details # type: str - self.brand = brand # type: str - self.chart = chart # type: str - self.weight = weight # type: str + self._color = 0x000000 + self.description = description + self.catalog_number = catalog_number + self.details = details + self.brand = brand + self.chart = chart + self.weight = weight # description, catalog_number, details, brand, chart, weight if thread is not None: self.set(thread) @@ -138,9 +140,8 @@ def __eq__(self, other): if isinstance(other, int): return self.color & 0xFFFFFF == other & 0xFFFFFF if isinstance(other, str): - return ( - self.color & 0xFFFFFF - == EmbThread.parse_string_color(other) & 0xFFFFFF + return self.__eq__( + EmbThread.parse_string_color(other) ) if not isinstance(other, EmbThread): return False @@ -169,33 +170,72 @@ def __str__(self): else: return "EmbThread %s %s" % (self.description, self.hex_color()) - def set_color(self, r, g, b): - self.color = color_rgb(r, g, b) + @property + def color(self): + return self._color - def get_opaque_color(self): + @color.setter + def color(self, color): + if isinstance(color, (tuple, list)): + r, g, b = tuple(color[:3]) + color = color_rgb(r, g, b) + + if not isinstance(color, int): + raise ValueError() + + self._color = color + + @property + def opaque_color(self): return 0xFF000000 | self.color - def get_red(self): + @property + def red(self): red = self.color >> 16 return red & 0xFF - def get_green(self): + @property + def green(self): green = self.color >> 8 return green & 0xFF - def get_blue(self): + @property + def blue(self): blue = self.color return blue & 0xFF - def find_nearest_color_index(self, values): - return find_nearest_color_index(int(self.color), values) + # @property + # def hex_color(self): + # return f"#{self.red:02X}{self.green:02X}{self.blue:02X}" + + # @hex_color.setter + # def hex_color(self, hex_string): + # self.color = color_hex(hex_string) + + def set_color(self, r, g, b): + self.color = (r, g, b) + + def get_opaque_color(self): + return self.opaque_color + + def get_red(self): + return self.red + + def get_green(self): + return self.green + + def get_blue(self): + return self.blue def hex_color(self): - return "#%02x%02x%02x" % (self.get_red(), self.get_green(), self.get_blue()) + return "#%02x%02x%02x" % (self.red, self.green, self.blue) def set_hex_color(self, hex_string): self.color = color_hex(hex_string) + def find_nearest_color_index(self, values): + return find_nearest_color_index(self.color, values) + def set(self, thread): if isinstance(thread, EmbThread): self.color = thread.color @@ -207,6 +247,8 @@ def set(self, thread): self.weight = thread.weight elif isinstance(thread, int): self.color = thread + elif isinstance(thread, str): + self.color = self.parse_string_color(thread) elif isinstance(thread, dict): if "name" in thread: self.description = thread["name"] @@ -225,31 +267,25 @@ def set(self, thread): color = thread["color"] except KeyError: color = thread["rgb"] - if isinstance(color, int): - self.color = color - elif isinstance(color, tuple) or isinstance(color, list): - self.color = ( - (color[0] & 0xFF) << 16 - | (color[1] & 0xFF) << 8 - | (color[2] & 0xFF) - ) - elif isinstance(color, str): + + if isinstance(color, str): self.color = self.parse_string_color(color) + + elif isinstance(color, (tuple, list, int)): + self.color = color if "hex" in thread: self.set_hex_color(thread["hex"]) if "id" in thread: self.catalog_number = thread["id"] if "catalog" in thread: self.catalog_number = thread["catalog"] - elif isinstance(thread, str): - self.color = self.parse_string_color(thread) @staticmethod def parse_string_color(color): if color == "random": import random - return random.randint(0, 0xFFFFFF) + return random.getrandbits(24) if color[0:1] == "#": return color_hex(color[1:]) color_dict = { @@ -401,5 +437,5 @@ def parse_string_color(color): "yellow": color_rgb(255, 255, 0), "yellowgreen": color_rgb(154, 205, 50), } - return color_dict.get(color.lower(), 0x000000) - # return color or black. + return color_dict.get(color.lower()) + # return color or None diff --git a/src/pystitch/__init__.py b/src/pystitch/__init__.py index 5d5ac2b..5646f05 100644 --- a/src/pystitch/__init__.py +++ b/src/pystitch/__init__.py @@ -1,5 +1,7 @@ name = "pystitch" +import os + # items available at the top level (e.g. pystitch.read) from .EmbConstant import * from .EmbFunctions import * @@ -88,40 +90,62 @@ import pystitch.ZxyReader as ZxyReader -def read(filename, settings=None, pattern=None): +def read(file, settings=None, pattern=None): """Reads file, assuming type by extension""" + + # Determine filename + filename = file + if not isinstance(filename, (str, os.PathLike)): + filename = getattr(file, "name") + extension = EmbPattern.get_extension_by_filename(filename) extension = extension.lower() - for file_type in supported_formats(): - if file_type["extension"] != extension: - continue - reader = file_type.get("reader", None) - return EmbPattern.read_embroidery(reader, filename, settings, pattern) - return None + file_type = {} + for format in supported_formats(): + if extension == format["extension"]: + file_type = format + break + + reader = file_type.get("reader") + + if reader is None: + return None + + return EmbPattern.read_embroidery(reader, file, settings, pattern) -def write(pattern, filename, settings=None): + +def write(pattern, file, settings=None): """Writes file, assuming type by extension""" + + # Determine filename + filename = file + if not isinstance(filename, (str, os.PathLike)): + filename = getattr(file, "name") + extension = EmbPattern.get_extension_by_filename(filename) extension = extension.lower() - supported_extensions = [file_type["extension"] for file_type in supported_formats()] - if extension not in supported_extensions: + file_type = None + for format in supported_formats(): + if extension == format["extension"]: + file_type = format + break + + if file_type is None: raise IOError("Conversion to file type '{extension}' is not supported".format(extension=extension)) - ext_to_file_type_lookup = {file_type["extension"]: file_type for file_type in supported_formats()} - writer = ext_to_file_type_lookup[extension].get("writer") + writer = file_type.get("writer") - if writer: - EmbPattern.write_embroidery(writer, pattern, filename, settings) - else: + if writer is None: raise IOError("No supported writer found.") + EmbPattern.write_embroidery(writer, pattern, file, settings) + def convert(filename_from, filename_to, settings=None): pattern = read(filename_from, settings) - if pattern is None: - return - write(pattern, filename_to, settings) + if pattern is not None: + write(pattern, filename_to, settings) def supported_formats(): """Generates dictionary entries for supported formats. Each entry will diff --git a/test/pattern_for_tests.py b/test/pattern_for_tests.py index 7568f99..49fed1b 100644 --- a/test/pattern_for_tests.py +++ b/test/pattern_for_tests.py @@ -1,7 +1,8 @@ -from pystitch import * - import math +from pystitch import * +from pystitch import EmbPattern +from pystitch import encode_thread_change def evaluate_lsystem(symbol, rules, depth): if depth <= 0 or symbol not in rules: @@ -263,12 +264,12 @@ def get_random_pattern_large(count=1000): pattern = EmbPattern() import random - for i in range(0, count): + for _ in range(count): pattern.add_block( [(random.uniform(-500, 500), random.uniform(-500, 500)), (random.uniform(-500, 500), random.uniform(-500, 500)), (random.uniform(-500, 500), random.uniform(-500, 500))], - random.randint(0x000000, 0xFFFFFF)) + random.getrandbits(24)) return pattern @@ -280,7 +281,7 @@ def get_random_pattern_small(): [(random.uniform(-500, 500), random.uniform(-500, 500)), (random.uniform(-500, 500), random.uniform(-500, 500)), (random.uniform(-500, 500), random.uniform(-500, 500))], - random.randint(0x000000, 0xFFFFFF)) + random.getrandbits(24)) return pattern @@ -291,7 +292,7 @@ def get_random_pattern_small_halfs(): [(random.randint(-500, 500) / 2.0, random.randint(-500, 500) / 2.0), (random.randint(-500, 500) / 2.0, random.randint(-500, 500) / 2.0), (random.randint(-500, 500) / 2.0, random.randint(-500, 500) / 2.0)], - random.randint(0x000000, 0xFFFFFF)) + random.getrandbits(24)) return pattern diff --git a/test/test_catalog.py b/test/test_catalog.py index 6660858..b753a82 100644 --- a/test/test_catalog.py +++ b/test/test_catalog.py @@ -1,8 +1,5 @@ -from __future__ import print_function - import unittest -from test.pattern_for_tests import * import pystitch diff --git a/test/test_color_fileformats.py b/test/test_color_fileformats.py index 5332541..14b72af 100644 --- a/test/test_color_fileformats.py +++ b/test/test_color_fileformats.py @@ -1,103 +1,98 @@ -from __future__ import print_function - +from pathlib import Path import unittest +import tempfile + +from test.pattern_for_tests import get_shift_pattern -from test.pattern_for_tests import * +import pystitch +from pystitch import EmbPattern, EmbThread class TestColorFormats(unittest.TestCase): + def assertPatternColorsEqual(self, pattern0, pattern1): + self.assertEqual(len(pattern0.threadlist), len(pattern1.threadlist)) + self.assertEqual( + [thread.color for thread in pattern0.threadlist], + [thread.color for thread in pattern1.threadlist], + ) def test_write_read_col(self): - file1 = "color.col" - for m in range(0,50): - pattern = EmbPattern() - for i in range(4, 20): - pattern.add_thread(EmbThread("random")) - write(pattern, file1) - w_pattern = read(file1) - self.assertEqual(len(pattern.threadlist), len(w_pattern.threadlist)) - for q in range(0,len(pattern.threadlist)): - self.assertEqual(pattern.threadlist[q].color, w_pattern.threadlist[q].color) - self.addCleanup(os.remove, file1) + with tempfile.TemporaryDirectory() as tmpdirname: + file1 = Path(tmpdirname) / "color.col" + for _ in range(50): + pattern = EmbPattern() + for _ in range(4, 20): + pattern.add_thread(EmbThread("random")) + pystitch.write(pattern, file1) + w_pattern = pystitch.read(file1) + self.assertPatternColorsEqual(pattern, w_pattern) def test_write_read_edr(self): - file1 = "color.edr" - for m in range(0, 50): - pattern = EmbPattern() - for i in range(4, 20): - pattern.add_thread(EmbThread("random")) - write(pattern, file1) - w_pattern = read(file1) - self.assertEqual(len(pattern.threadlist), len(w_pattern.threadlist)) - for q in range(0, len(pattern.threadlist)): - self.assertEqual(pattern.threadlist[q].color, w_pattern.threadlist[q].color) - self.addCleanup(os.remove, file1) + with tempfile.TemporaryDirectory() as tmpdirname: + file1 = Path(tmpdirname) / "color.edr" + for _ in range(50): + pattern = EmbPattern() + for _ in range(4, 20): + pattern.add_thread(EmbThread("random")) + pystitch.write(pattern, file1) + w_pattern = pystitch.read(file1) + self.assertPatternColorsEqual(pattern, w_pattern) def test_write_read_inf(self): - file1 = "color.inf" - for m in range(0, 50): - pattern = EmbPattern() - for i in range(4, 20): - pattern.add_thread(EmbThread("random")) - write(pattern, file1) - w_pattern = read(file1) - self.assertEqual(len(pattern.threadlist), len(w_pattern.threadlist)) - for q in range(0, len(pattern.threadlist)): - self.assertEqual(pattern.threadlist[q].color, w_pattern.threadlist[q].color) - self.addCleanup(os.remove, file1) + with tempfile.TemporaryDirectory() as tmpdirname: + file1 = Path(tmpdirname) / "color.inf" + for _ in range(0, 50): + pattern = EmbPattern() + for _ in range(4, 20): + pattern.add_thread(EmbThread("random")) + pystitch.write(pattern, file1) + w_pattern = pystitch.read(file1) + self.assertPatternColorsEqual(pattern, w_pattern) def test_write_edr_dst(self): pattern = get_shift_pattern() - file1 = "color.edr" - file2 = "color.dst" - write(pattern, file1) - write(pattern, file2) - w_pattern = read(file1) - w_pattern = read(file2, pattern=w_pattern) - self.assertEqual(len(pattern.threadlist), len(w_pattern.threadlist)) - for q in range(0, len(pattern.threadlist)): - self.assertEqual(pattern.threadlist[q].color, w_pattern.threadlist[q].color) - self.addCleanup(os.remove, file1) - self.addCleanup(os.remove, file2) + with tempfile.TemporaryDirectory() as tmpdirname: + tmpdir = Path(tmpdirname) + file1 = tmpdir / "color.edr" + file2 = tmpdir / "color.dst" + pystitch.write(pattern, file1) + pystitch.write(pattern, file2) + w_pattern = pystitch.read(file1) + w_pattern = pystitch.read(file2, pattern=w_pattern) + self.assertPatternColorsEqual(pattern, w_pattern) def test_write_dst_edr(self): pattern = get_shift_pattern() - file1 = "color.dst" - file2 = "color.edr" - write(pattern, file1) - write(pattern, file2) - w_pattern = read(file1) - w_pattern = read(file2, pattern=w_pattern) - self.assertEqual(len(pattern.threadlist), len(w_pattern.threadlist)) - for q in range(0, len(pattern.threadlist)): - self.assertEqual(pattern.threadlist[q].color, w_pattern.threadlist[q].color) - self.addCleanup(os.remove, file1) - self.addCleanup(os.remove, file2) + with tempfile.TemporaryDirectory() as tmpdirname: + tmpdir = Path(tmpdirname) + file1 = tmpdir / "color.dst" + file2 = tmpdir / "color.edr" + pystitch.write(pattern, file1) + pystitch.write(pattern, file2) + w_pattern = pystitch.read(file1) + w_pattern = pystitch.read(file2, pattern=w_pattern) + self.assertPatternColorsEqual(pattern, w_pattern) def test_write_dst_col(self): pattern = get_shift_pattern() - file1 = "color.dst" - file2 = "color.col" - write(pattern, file1) - write(pattern, file2) - w_pattern = read(file1) - w_pattern = read(file2, pattern=w_pattern) - self.assertEqual(len(pattern.threadlist), len(w_pattern.threadlist)) - for q in range(0, len(pattern.threadlist)): - self.assertEqual(pattern.threadlist[q].color, w_pattern.threadlist[q].color) - self.addCleanup(os.remove, file1) - self.addCleanup(os.remove, file2) + with tempfile.TemporaryDirectory() as tmpdirname: + tmpdir = Path(tmpdirname) + file1 = tmpdir / "color.dst" + file2 = tmpdir / "color.col" + pystitch.write(pattern, file1) + pystitch.write(pattern, file2) + w_pattern = pystitch.read(file1) + w_pattern = pystitch.read(file2, pattern=w_pattern) + self.assertPatternColorsEqual(pattern, w_pattern) def test_write_dst_inf(self): pattern = get_shift_pattern() - file1 = "color.dst" - file2 = "color.inf" - write(pattern, file1) - write(pattern, file2) - w_pattern = read(file1) - w_pattern = read(file2, pattern=w_pattern) - self.assertEqual(len(pattern.threadlist), len(w_pattern.threadlist)) - for q in range(0, len(pattern.threadlist)): - self.assertEqual(pattern.threadlist[q].color, w_pattern.threadlist[q].color) - self.addCleanup(os.remove, file1) - self.addCleanup(os.remove, file2) \ No newline at end of file + with tempfile.TemporaryDirectory() as tmpdirname: + tmpdir = Path(tmpdirname) + file1 = tmpdir / "color.dst" + file2 = tmpdir / "color.inf" + pystitch.write(pattern, file1) + pystitch.write(pattern, file2) + w_pattern = pystitch.read(file1) + w_pattern = pystitch.read(file2, pattern=w_pattern) + self.assertPatternColorsEqual(pattern, w_pattern) diff --git a/test/test_datapreservation.py b/test/test_datapreservation.py index 4c44400..f17d8a5 100644 --- a/test/test_datapreservation.py +++ b/test/test_datapreservation.py @@ -1,17 +1,22 @@ -from __future__ import print_function - +import tempfile import unittest -from test.pattern_for_tests import * + +from test.pattern_for_tests import get_big_pattern + +from pystitch import * +from pystitch import encode_thread_change, decode_embroidery_command +from pystitch import write_u01, read_u01 class TestDataPreservation(unittest.TestCase): def test_preserve_u01_needles(self): - file1 = "file.u01" pattern = get_big_pattern() pattern.add_command(encode_thread_change(SET_CHANGE_SEQUENCE, None, 6, 0)) - write_u01(pattern, file1) - read_pattern = read_u01(file1) + + with tempfile.NamedTemporaryFile(suffix=".u01") as fp: + write_u01(pattern, fp) + read_pattern = read_u01(fp) + for cmd in read_pattern.get_match_commands(NEEDLE_SET): print(decode_embroidery_command(cmd[2])) - self.addCleanup(os.remove, file1) diff --git a/test/test_embpattern.py b/test/test_embpattern.py index 52d0d5c..c7e5eb8 100644 --- a/test/test_embpattern.py +++ b/test/test_embpattern.py @@ -1,8 +1,12 @@ -from __future__ import print_function - +from pathlib import Path +import tempfile import unittest -from test.pattern_for_tests import * +from test.pattern_for_tests import get_shift_pattern, get_simple_pattern, get_random_pattern_small_halfs, get_random_pattern_large + +from pystitch import * +from pystitch import EmbPattern, EmbThread +from pystitch import encode_thread_change, decode_embroidery_command class TestEmbpattern(unittest.TestCase): @@ -11,29 +15,30 @@ def position_equals(self, stitches, j, k): self.assertEqual(stitches[j][:1], stitches[k][:1]) def test_thread_reorder(self): - test_file = "reorder.pes" shift = get_shift_pattern() shift.add_command(encode_thread_change(SET_CHANGE_SEQUENCE, thread=1, order=0)) shift.add_command(encode_thread_change(SET_CHANGE_SEQUENCE, 0, None, 1)) shift.add_command(encode_thread_change(SET_CHANGE_SEQUENCE, 1, None, 0)) self.assertEqual(0xFFFFFF & shift.threadlist[0].color, 0xFF0000) self.assertEqual(0xFFFFFF & shift.threadlist[1].color, 0x0000FF) - write_pes(shift, test_file, {"pes version": 6}) - read_pattern = read_pes(test_file) + with tempfile.NamedTemporaryFile(suffix=".pes") as fp: + write_pes(shift, fp, {"pes version": 6}) + fp.seek(0) + read_pattern = read_pes(fp) for thread in read_pattern.threadlist: print(0xFFFFFF & thread.color) self.assertEqual((0xFFFFFF & read_pattern.threadlist[0].color), 0x0000FF) self.assertEqual((0xFFFFFF & read_pattern.threadlist[1].color), 0xFF0000) - self.addCleanup(os.remove, test_file) def test_needle_count_limited_set(self): - needle_file = "needle-ls.u01" shift = get_shift_pattern() shift.add_command(encode_thread_change(SET_CHANGE_SEQUENCE, None, 6, 0)) shift.add_command(encode_thread_change(SET_CHANGE_SEQUENCE, 4, 6, 7)) shift.add_command(encode_thread_change(SET_CHANGE_SEQUENCE, None, 3, 0)) - write_u01(shift, needle_file, {"needle_count": 7}) - needle_pattern = read_u01(needle_file) + with tempfile.NamedTemporaryFile(suffix=".u01") as fp: + write_u01(shift, fp, {"needle_count": 7}) + fp.seek(0) + needle_pattern = read_u01(fp) self.assertEqual(needle_pattern.count_stitch_commands(NEEDLE_SET), 16) first = True for stitch in needle_pattern.get_match_commands(NEEDLE_SET): @@ -43,242 +48,260 @@ def test_needle_count_limited_set(self): # self.assertEqual(cmd[2], 3) first = False self.assertLessEqual(cmd[2], 7) - self.addCleanup(os.remove, needle_file) def test_needle_count_limit1(self): - needle_file = "needle-1.u01" - write_u01(get_shift_pattern(), needle_file, {"needle_count": 1}) - needle_pattern = read_u01(needle_file) + shift = get_shift_pattern() + with tempfile.NamedTemporaryFile(suffix=".u01") as fp: + write_u01(shift, fp, {"needle_count": 1}) + fp.seek(0) + needle_pattern = read_u01(fp) self.assertEqual(needle_pattern.count_stitch_commands(STOP), 16) for stitch in needle_pattern.get_match_commands(NEEDLE_SET): cmd = decode_embroidery_command(stitch[2]) self.assertLess(cmd[2], 1) - self.addCleanup(os.remove, needle_file) def test_needle_count_limit2(self): - needle_file = "needle.u01" - write_u01(get_shift_pattern(), needle_file, {"needle_count": 2}) - needle_pattern = read_u01(needle_file) + shift = get_shift_pattern() + with tempfile.NamedTemporaryFile(suffix=".u01") as fp: + write_u01(shift, fp, {"needle_count": 2}) + fp.seek(0) + needle_pattern = read_u01(fp) for stitch in needle_pattern.get_match_commands(NEEDLE_SET): cmd = decode_embroidery_command(stitch[2]) self.assertLessEqual(cmd[2], 2) self.assertEqual(needle_pattern.count_needle_sets(), 16) - self.addCleanup(os.remove, needle_file) def test_needle_count_limit3(self): - needle_file = "needle.u01" - write_u01(get_shift_pattern(), needle_file, {"needle_count": 3}) - needle_pattern = read_u01(needle_file) + shift = get_shift_pattern() + with tempfile.NamedTemporaryFile(suffix=".u01") as fp: + write_u01(shift, fp, {"needle_count": 3}) + fp.seek(0) + needle_pattern = read_u01(fp) for stitch in needle_pattern.get_match_commands(NEEDLE_SET): cmd = decode_embroidery_command(stitch[2]) self.assertLessEqual(cmd[2], 3) self.assertEqual(needle_pattern.count_needle_sets(), 16) - self.addCleanup(os.remove, needle_file) def test_needle_count_limit4(self): - needle_file = "needle.u01" - write_u01(get_shift_pattern(), needle_file, {"needle_count": 4}) - needle_pattern = read_u01(needle_file) + shift = get_shift_pattern() + with tempfile.NamedTemporaryFile(suffix=".u01") as fp: + write_u01(shift, fp, {"needle_count": 4}) + fp.seek(0) + needle_pattern = read_u01(fp) for stitch in needle_pattern.get_match_commands(NEEDLE_SET): cmd = decode_embroidery_command(stitch[2]) self.assertLessEqual(cmd[2], 4) self.assertEqual(needle_pattern.count_needle_sets(), 16) - self.addCleanup(os.remove, needle_file) def test_needle_count_limit5(self): - needle_file = "needle.u01" - write_u01(get_shift_pattern(), needle_file, {"needle_count": 5}) - needle_pattern = read_u01(needle_file) + shift = get_shift_pattern() + with tempfile.NamedTemporaryFile(suffix=".u01") as fp: + write_u01(shift, fp, {"needle_count": 5}) + fp.seek(0) + needle_pattern = read_u01(fp) for stitch in needle_pattern.get_match_commands(NEEDLE_SET): cmd = decode_embroidery_command(stitch[2]) self.assertLessEqual(cmd[2], 5) self.assertEqual(needle_pattern.count_needle_sets(), 16) - self.addCleanup(os.remove, needle_file) def test_needle_count_limit6(self): - needle_file = "needle.u01" - write_u01(get_shift_pattern(), needle_file, {"needle_count": 6}) - needle_pattern = read_u01(needle_file) + shift = get_shift_pattern() + with tempfile.NamedTemporaryFile(suffix=".u01") as fp: + write_u01(shift, fp, {"needle_count": 6}) + fp.seek(0) + needle_pattern = read_u01(fp) for stitch in needle_pattern.get_match_commands(NEEDLE_SET): cmd = decode_embroidery_command(stitch[2]) self.assertLessEqual(cmd[2], 6) self.assertEqual(needle_pattern.count_needle_sets(), 16) - self.addCleanup(os.remove, needle_file) def test_needle_count_limit7(self): - needle_file = "needle.u01" - write_u01(get_shift_pattern(), needle_file, {"needle_count": 7}) - needle_pattern = read_u01(needle_file) + shift = get_shift_pattern() + with tempfile.NamedTemporaryFile(suffix=".u01") as fp: + write_u01(shift, fp, {"needle_count": 7}) + fp.seek(0) + needle_pattern = read_u01(fp) for stitch in needle_pattern.get_match_commands(NEEDLE_SET): cmd = decode_embroidery_command(stitch[2]) self.assertLessEqual(cmd[2], 7) self.assertEqual(needle_pattern.count_needle_sets(), 16) - self.addCleanup(os.remove, needle_file) def test_needle_count_limit8(self): - needle_file = "needle.u01" - write_u01(get_shift_pattern(), needle_file, {"needle_count": 8}) - needle_pattern = read_u01(needle_file) + shift = get_shift_pattern() + with tempfile.NamedTemporaryFile(suffix=".u01") as fp: + write_u01(shift, fp, {"needle_count": 8}) + fp.seek(0) + needle_pattern = read_u01(fp) for stitch in needle_pattern.get_match_commands(NEEDLE_SET): cmd = decode_embroidery_command(stitch[2]) self.assertLessEqual(cmd[2], 8) self.assertEqual(needle_pattern.count_needle_sets(), 16) - self.addCleanup(os.remove, needle_file) def test_needle_count_limit9(self): - needle_file = "needle.u01" - write_u01(get_shift_pattern(), needle_file, {"needle_count": 9}) - needle_pattern = read_u01(needle_file) + shift = get_shift_pattern() + with tempfile.NamedTemporaryFile(suffix=".u01") as fp: + write_u01(shift, fp, {"needle_count": 9}) + fp.seek(0) + needle_pattern = read_u01(fp) for stitch in needle_pattern.get_match_commands(NEEDLE_SET): cmd = decode_embroidery_command(stitch[2]) self.assertLessEqual(cmd[2], 9) self.assertEqual(needle_pattern.count_needle_sets(), 16) - self.addCleanup(os.remove, needle_file) def test_needle_count_limit10(self): - needle_file = "needle.u01" - write_u01(get_shift_pattern(), needle_file, {"needle_count": 10}) - needle_pattern = read_u01(needle_file) + shift = get_shift_pattern() + with tempfile.NamedTemporaryFile(suffix=".u01") as fp: + write_u01(shift, fp, {"needle_count": 10}) + fp.seek(0) + needle_pattern = read_u01(fp) for stitch in needle_pattern.get_match_commands(NEEDLE_SET): cmd = decode_embroidery_command(stitch[2]) self.assertLessEqual(cmd[2], 10) self.assertEqual(needle_pattern.count_needle_sets(), 16) - self.addCleanup(os.remove, needle_file) def test_u01_tie_on(self): - needle_file = "tie_on.u01" - write_u01(get_shift_pattern(), needle_file, {"needle_count": 10, "tie_on": CONTINGENCY_TIE_ON_THREE_SMALL}) - needle_pattern = read_u01(needle_file) + shift = get_shift_pattern() + with tempfile.NamedTemporaryFile(suffix=".u01") as fp: + write_u01(shift, fp, {"needle_count": 10, "tie_on": CONTINGENCY_TIE_ON_THREE_SMALL}) + fp.seek(0) + needle_pattern = read_u01(fp) for stitch in needle_pattern.get_match_commands(NEEDLE_SET): cmd = decode_embroidery_command(stitch[2]) self.assertLessEqual(cmd[2], 10) self.assertEqual(needle_pattern.count_needle_sets(), 16) self.assertEqual(needle_pattern.count_stitch_commands(STITCH), 16 * (5 + 4)) # 5 for the actual stitch pattern. 3 small, and 1 extra tieon, start. - self.addCleanup(os.remove, needle_file) def test_u01_tie_off(self): - needle_file = "tie_on.u01" - write_u01(get_shift_pattern(), needle_file, {"needle_count": 10, "tie_off": CONTINGENCY_TIE_OFF_THREE_SMALL}) - needle_pattern = read_u01(needle_file) + shift = get_shift_pattern() + with tempfile.NamedTemporaryFile(suffix=".u01") as fp: + write_u01(get_shift_pattern(), fp, {"needle_count": 10, "tie_off": CONTINGENCY_TIE_OFF_THREE_SMALL}) + fp.seek(0) + needle_pattern = read_u01(fp) for stitch in needle_pattern.get_match_commands(NEEDLE_SET): cmd = decode_embroidery_command(stitch[2]) self.assertLessEqual(cmd[2], 10) self.assertEqual(needle_pattern.count_needle_sets(), 16) self.assertEqual(needle_pattern.count_stitch_commands(STITCH), 16 * (5 + 4)) # 5 for the actual stitch pattern. 3 small, and 1 extra tieoff, end. - self.addCleanup(os.remove, needle_file) def test_write_dst_read_dst_long_jump(self): - file1 = "file3.dst" pattern = EmbPattern() pattern.add_block([(0, 0), (0, 200)], "red") - write_dst(pattern, file1) - dst_pattern = read_dst(file1) + with tempfile.NamedTemporaryFile(suffix=".dst") as fp: + write_dst(pattern, fp) + fp.seek(0) + dst_pattern = read_dst(fp) + self.assertIsNotNone(dst_pattern) self.assertEqual(dst_pattern.count_stitch_commands(STITCH), 2) self.assertEqual(dst_pattern.stitches[1][1], 100) print("dst: ", dst_pattern.stitches) - self.addCleanup(os.remove, file1) def test_write_dst_read_dst_random_stitch(self): - file1 = "fsmall.dst" - for i in range(0, 12): - max = (i * 10) + 1 - write_dst(get_random_pattern_small_halfs(), file1, - {"long_stitch_contingency": CONTINGENCY_LONG_STITCH_SEW_TO, "max_stitch": max}) - dst_pattern = read_dst(file1) - xx = 0 - yy = 0 - command = NO_COMMAND - for stitch in dst_pattern.stitches: - dx = stitch[0] - xx - dy = stitch[1] - yy - xx += dx - yy += dy - last_command = command - command = stitch[2] & COMMAND_MASK - if command == STITCH and last_command == STITCH: - self.assertLessEqual(dx, max) - self.assertLessEqual(dy, max) - self.assertIsNotNone(dst_pattern) - self.addCleanup(os.remove, file1) + with tempfile.NamedTemporaryFile(suffix=".dst") as fp: + for i in range(0, 12): + max = (i * 10) + 1 + pattern = get_random_pattern_small_halfs() + write_dst(pattern, fp, + {"long_stitch_contingency": CONTINGENCY_LONG_STITCH_SEW_TO, "max_stitch": max}) + fp.seek(0) + dst_pattern = read_dst(fp) + xx = 0 + yy = 0 + command = NO_COMMAND + for stitch in dst_pattern.stitches: + dx = stitch[0] - xx + dy = stitch[1] - yy + xx += dx + yy += dy + last_command = command + command = stitch[2] & COMMAND_MASK + if command == STITCH and last_command == STITCH: + self.assertLessEqual(dx, max) + self.assertLessEqual(dy, max) + self.assertIsNotNone(dst_pattern) def test_write_dst_read_dst_long_jump_random_small(self): - file1 = "file3small.dst" - - for i in range(0, 1000): - write_dst(get_random_pattern_small_halfs(), file1, - {"long_stitch_contingency": CONTINGENCY_LONG_STITCH_SEW_TO}) - dst_pattern = read_dst(file1) - self.assertIsNotNone(dst_pattern) - self.addCleanup(os.remove, file1) + with tempfile.NamedTemporaryFile(suffix=".dst") as fp: + for i in range(0, 1000): + pattern = get_random_pattern_small_halfs() + write_dst(pattern, fp, + {"long_stitch_contingency": CONTINGENCY_LONG_STITCH_SEW_TO}) + fp.seek(0) + dst_pattern = read_dst(fp) + self.assertIsNotNone(dst_pattern) def test_write_dst_read_dst_long_jump_random_large(self): - file1 = "file3large.dst" - for i in range(0, 5): - write_dst(get_random_pattern_large(), file1, - {"long_stitch_contingency": CONTINGENCY_LONG_STITCH_SEW_TO}) - dst_pattern = read_dst(file1) - self.assertIsNotNone(dst_pattern) - self.addCleanup(os.remove, file1) + with tempfile.NamedTemporaryFile(suffix=".dst") as fp: + for i in range(0, 5): + pattern = get_random_pattern_large() + write_dst(pattern, fp, + {"long_stitch_contingency": CONTINGENCY_LONG_STITCH_SEW_TO}) + fp.seek(0) + dst_pattern = read_dst(fp) + self.assertIsNotNone(dst_pattern) def test_write_dst_read_dst_divide(self): - file1 = "file3.dst" pattern = EmbPattern() pattern.add_block([(0, 0), (0, 2)], "red") - write_dst(pattern, file1, {"scale": 100, "long_stitch_contingency": CONTINGENCY_LONG_STITCH_SEW_TO}) - dst_pattern = read_dst(file1) + with tempfile.NamedTemporaryFile(suffix=".dst") as fp: + write_dst(pattern, fp, {"scale": 100, "long_stitch_contingency": CONTINGENCY_LONG_STITCH_SEW_TO}) + fp.seek(0) + dst_pattern = read_dst(fp) + self.assertIsNotNone(dst_pattern) self.assertEqual(dst_pattern.count_stitch_commands(STITCH), 3) self.assertEqual(dst_pattern.stitches[1][1], 100) print("dst: ", dst_pattern.stitches) - self.addCleanup(os.remove, file1) def test_write_csv_read_csv_raw(self): - file1 = "file.csv" - write_csv(get_simple_pattern(), file1) - csv_pattern = read_csv(file1) + pattern = get_simple_pattern() + with tempfile.TemporaryDirectory() as tmpdirname: + file1 = Path(tmpdirname) / "file.csv" + write_csv(pattern, file1) + csv_pattern = read_csv(file1) self.assertIsNotNone(csv_pattern) self.assertEqual(csv_pattern.count_stitch_commands(COLOR_BREAK), 3) self.assertEqual(csv_pattern.count_stitch_commands(STITCH), 15) self.position_equals(csv_pattern.stitches, 0, -1) print("csv: ", csv_pattern.stitches) - self.addCleanup(os.remove, file1) def test_write_csv_read_csv_needle(self): - file1 = "file2.csv" - write_csv(get_simple_pattern(), "file2.csv", {"thread_change_command": NEEDLE_SET, "encode": True}) - csv_pattern = read_csv(file1) + pattern = get_simple_pattern() + with tempfile.TemporaryDirectory() as tmpdirname: + file2 = Path(tmpdirname) / "file2.csv" + write_csv(pattern, file2, {"thread_change_command": NEEDLE_SET, "encode": True}) + csv_pattern = read_csv(file2) self.assertIsNotNone(csv_pattern) self.assertEqual(csv_pattern.count_stitch_commands(NEEDLE_SET), 3) self.assertEqual(csv_pattern.count_stitch_commands(STITCH), 15) print("csv: ", csv_pattern.stitches) - self.addCleanup(os.remove, file1) def test_write_csv_read_csv_color(self): - file1 = "file3.csv" - write_csv(get_simple_pattern(), "file3.csv", {"thread_change_command": COLOR_CHANGE, "encode": True}) - csv_pattern = read_csv(file1) + pattern = get_simple_pattern() + with tempfile.TemporaryDirectory() as tmpdirname: + file3 = Path(tmpdirname) / "file3.csv" + write_csv(pattern, file3, {"thread_change_command": COLOR_CHANGE, "encode": True}) + csv_pattern = read_csv(file3) self.assertEqual(csv_pattern.count_stitch_commands(COLOR_CHANGE), 2) self.assertEqual(csv_pattern.count_stitch_commands(STITCH), 15) self.position_equals(csv_pattern.stitches, 0, -1) print("csv: ", csv_pattern.stitches) - self.addCleanup(os.remove, file1) def test_write_csv_read_csv_encoded_command(self): - file1 = "file-encoded.csv" pattern = EmbPattern() encoded_command = encode_thread_change(SET_CHANGE_SEQUENCE, 3, 4, 1) pattern.add_command(encoded_command) - write_csv(pattern, file1) - csv_pattern = read_csv(file1) + with tempfile.TemporaryDirectory() as tmpdirname: + file1 = Path(tmpdirname) / "file-encoded.csv" + write_csv(pattern, file1) + csv_pattern = read_csv(file1) self.assertIsNotNone(csv_pattern) print("csv-encoded: ", csv_pattern.stitches) self.assertEqual(encoded_command, csv_pattern.stitches[-1][2]) - self.addCleanup(os.remove, file1) def test_issue_87(self): """ diff --git a/test/test_encoder.py b/test/test_encoder.py index e9db563..ff81759 100644 --- a/test/test_encoder.py +++ b/test/test_encoder.py @@ -1,9 +1,9 @@ -from __future__ import print_function - import unittest -from test.pattern_for_tests import * +from test.pattern_for_tests import get_shift_pattern +from pystitch import * +from pystitch import EmbPattern class TestEmbpattern(unittest.TestCase): diff --git a/test/test_generic.py b/test/test_generic.py index 865c838..160a240 100644 --- a/test/test_generic.py +++ b/test/test_generic.py @@ -1,46 +1,49 @@ -from __future__ import print_function - +from pathlib import Path import unittest +import tempfile + +from test.pattern_for_tests import get_fractal_pattern -from test.pattern_for_tests import * -from pystitch import GenericWriter import pystitch +from pystitch import GenericWriter, EmbPattern class TestConverts(unittest.TestCase): def test_generic_write_stitch(self): - file1 = "convert.dst" - file2 = "convert.txt" - self.addCleanup(os.remove, file1) - self.addCleanup(os.remove, file2) pattern = get_fractal_pattern() - pystitch.write(pattern, file1) - - pattern = pystitch.read(file1) - - EmbPattern.write_embroidery( - GenericWriter, - pattern, - file2, - { - "segment_start": "\t\t", - "segment_end": "\n", - "segment": "{cmd_str} {x},{y}", - "stitch": "Stitch: {x},{y}", - "jump": "Jump {x},{y}", - "trim": "Trim: {x},{y}", - "color_change": "Color-Change: {x},{y}", - "block_start": "\t{{\n", - "block_end": "\t}}\n", - "color_start": "[\n", - "color_end": "]\n", - }, - ) - print("write generic: ", file1) + with tempfile.TemporaryDirectory() as tmpdirname: + tmpdir = Path(tmpdirname) + + file1 = tmpdir / "convert.dst" + file2 = tmpdir / "convert.txt" + + pystitch.write(pattern, file1) + pattern = pystitch.read(file1) + + EmbPattern.write_embroidery( + GenericWriter, + pattern, + file2, + { + "segment_start": "\t\t", + "segment_end": "\n", + "segment": "{cmd_str} {x},{y}", + "stitch": "Stitch: {x},{y}", + "jump": "Jump {x},{y}", + "trim": "Trim: {x},{y}", + "color_change": "Color-Change: {x},{y}", + "block_start": "\t{{\n", + "block_end": "\t}}\n", + "color_start": "[\n", + "color_end": "]\n", + }, + ) + + print("write generic") + + @unittest.skip("Ink/Stitch uses an other gcode writer") def test_generic_write_gcode(self): - # Ink/Stitch uses an other gcode writer - ''' gcode_writer_dict = { "scale": (-0.1, -0.1), "pattern_start": "(STITCH_COUNT: {stitch_total})\n" @@ -63,20 +66,25 @@ def test_generic_write_gcode(self): "stop": "M00\n", "end": "M30\n", } - file1 = "file-gcode.gcode" - file2 = "file-generic.gcode" + pattern = get_fractal_pattern() pattern.fix_color_count() - EmbPattern.write_embroidery( - GenericWriter, - pattern, - file2, - gcode_writer_dict, - ) - pattern.write(file1) - f1 = open(file1, "rb").read() - f2 = open(file2, "rb").read() + + with tempfile.TemporaryDirectory() as tmpdirname: + tmpdir = Path(tmpdirname) + + file1 = tmpdir / "file-gcode.gcode" + file2 = tmpdir / "file-generic.gcode" + + pystitch.write(pattern, file1) + f1 = file1.read_bytes() + + EmbPattern.write_embroidery( + GenericWriter, + pattern, + file2, + gcode_writer_dict, + ) + f2 = file2.read_bytes() + self.assertEqual(f1, f2) - self.addCleanup(os.remove, file1) - self.addCleanup(os.remove, file2) - ''' diff --git a/test/test_interpolate.py b/test/test_interpolate.py index c80014b..73dd3ef 100644 --- a/test/test_interpolate.py +++ b/test/test_interpolate.py @@ -1,9 +1,9 @@ -from __future__ import print_function - import unittest +from test.pattern_for_tests import get_fractal_pattern + from pystitch import * -from test.pattern_for_tests import * +from pystitch import EmbPattern class TestInterpolate(unittest.TestCase): diff --git a/test/test_io.py b/test/test_io.py index e0ca56b..e637815 100644 --- a/test/test_io.py +++ b/test/test_io.py @@ -1,6 +1,9 @@ +from pathlib import Path +import tempfile import unittest -from test.pattern_for_tests import * +from test.pattern_for_tests import get_simple_pattern + import pystitch @@ -10,8 +13,10 @@ def test_read_non_file(self): 1.5.0 adds explicit error raising. We test that now. """ - file1 = "nosuchfile.dst" - self.assertRaises(IOError, lambda: pystitch.read(file1)) + with tempfile.TemporaryDirectory() as tmpdirname: + file1 = Path(tmpdirname) / "nosuchfile.dst" + with self.assertRaises(IOError): + pystitch.read(str(file1)) def test_write_non_supported(self): """ @@ -19,8 +24,10 @@ def test_write_non_supported(self): We test that now. """ pattern = get_simple_pattern() - file1 = "nosuchfile.pdf" - self.assertRaises(IOError, lambda: pystitch.write(pattern, file1)) + with tempfile.TemporaryDirectory() as tmpdirname: + file1 = Path(tmpdirname) / "nosuchfile.pdf" + with self.assertRaises(IOError): + pystitch.write(pattern, str(file1)) def test_write_no_writer(self): """ @@ -28,5 +35,7 @@ def test_write_no_writer(self): We test that now. """ pattern = get_simple_pattern() - file1 = "nosuchfile.dat" - self.assertRaises(IOError, lambda: pystitch.write(pattern, file1)) + with tempfile.TemporaryDirectory() as tmpdirname: + file1 = Path(tmpdirname) / "nosuchfile.dat" + with self.assertRaises(IOError): + pystitch.write(pattern, str(file1)) diff --git a/test/test_matrix.py b/test/test_matrix.py index e01b526..7f25ec6 100644 --- a/test/test_matrix.py +++ b/test/test_matrix.py @@ -1,7 +1,8 @@ -from __future__ import print_function - import unittest +import tempfile + from pystitch import * +from pystitch import EmbMatrix, EmbPattern class TestMatrix(unittest.TestCase): @@ -57,9 +58,8 @@ def test_matrix_rotate(self): self.assertAlmostEqual(pattern.stitches[10][1], pattern.stitches[12][1]) self.assertAlmostEqual(pattern.stitches[4][0], pattern.stitches[12][0]) self.assertAlmostEqual(pattern.stitches[4][1], pattern.stitches[12][1]) - file1 = "file.svg" - write_svg(pattern, file1) - self.addCleanup(os.remove, file1) + with tempfile.NamedTemporaryFile(suffix=".svg") as fp: + write_svg(pattern, fp) def test_matrix_translate(self): pattern = EmbPattern() @@ -75,9 +75,8 @@ def test_matrix_translate(self): self.assertAlmostEqual(pattern.stitches[4][0], pattern.stitches[12][0]) self.assertAlmostEqual(pattern.stitches[4][1], pattern.stitches[12][1]) - file1 = "file2.svg" - write_svg(pattern, file1) - self.addCleanup(os.remove, file1) + with tempfile.NamedTemporaryFile(suffix=".svg") as fp: + write_svg(pattern, fp) def test_matrix_translate_rotate(self): pattern = EmbPattern() @@ -93,9 +92,8 @@ def test_matrix_translate_rotate(self): self.assertEqual(pattern.count_stitch_commands(MATRIX_ROTATE), 0) self.assertAlmostEqual(pattern.stitches[14][0], 140) self.assertAlmostEqual(pattern.stitches[14][1], -120) - file1 = "file3.svg" - write_svg(pattern, file1) - self.addCleanup(os.remove, file1) + with tempfile.NamedTemporaryFile(suffix=".svg") as fp: + write_svg(pattern, fp) def test_matrix_translate_scale(self): pattern = EmbPattern() @@ -111,6 +109,5 @@ def test_matrix_translate_scale(self): self.assertEqual(pattern.count_stitch_commands(MATRIX_SCALE), 0) self.assertAlmostEqual(pattern.stitches[13][0], 50) self.assertAlmostEqual(pattern.stitches[13][1], 290) - file1 = "file4.svg" - write_svg(pattern, file1) - self.addCleanup(os.remove, file1) + with tempfile.NamedTemporaryFile(suffix=".svg") as fp: + write_svg(pattern, fp) diff --git a/test/test_overloads.py b/test/test_overloads.py index 526f801..eeb918c 100644 --- a/test/test_overloads.py +++ b/test/test_overloads.py @@ -1,9 +1,9 @@ -from __future__ import print_function - import unittest -from test.pattern_for_tests import * +from test.pattern_for_tests import get_shift_pattern +from pystitch import * +from pystitch import EmbPattern, EmbThread, EmbMatrix class TestOverloads(unittest.TestCase): @@ -88,5 +88,3 @@ def test_matrix(self): m2.post_scale(2) m2.post_rotate(30) self.assertEqual(catted, m2) - - diff --git a/test/test_palette.py b/test/test_palette.py index b082b89..b99bd5a 100644 --- a/test/test_palette.py +++ b/test/test_palette.py @@ -1,9 +1,7 @@ -from __future__ import print_function - import unittest -from pystitch import * -from pystitch.EmbThreadPec import * +from pystitch import EmbPattern, EmbThread +from pystitch.EmbThreadPec import get_thread_set from pystitch.EmbThread import build_unique_palette, build_nonrepeat_palette, build_palette @@ -18,13 +16,13 @@ def test_unique_palette(self): pattern += "Red" threadset = get_thread_set() palette = build_unique_palette(threadset,pattern.threadlist) - self.assertNotEqual(palette[0],palette[3]) # Red and altered Red - self.assertEqual(palette[1], palette[2]) # Blue and Blue + self.assertNotEqual(palette[0], palette[3], "Red and altered Red") + self.assertEqual(palette[1], palette[2], "Blue and Blue") def test_unique_palette_large(self): """Excessive palette entries that all map, should be mapped""" pattern = EmbPattern() - for x in range(0, 100): + for _ in range(0, 100): pattern += "black" threadset = get_thread_set() palette = build_unique_palette(threadset, pattern.threadlist) @@ -51,7 +49,7 @@ def test_unique_palette_max(self): pattern += thread palette = build_unique_palette(threadset, pattern.threadlist) palette.sort() - for i in range(1,len(palette)): + for i in range(1, len(palette)): self.assertNotEqual(palette[i-1], palette[i]) def test_nonrepeat_palette_moving(self): @@ -63,8 +61,8 @@ def test_nonrepeat_palette_moving(self): pattern += "Red" threadset = get_thread_set() palette = build_nonrepeat_palette(threadset,pattern.threadlist) - self.assertEqual(palette[0],palette[3]) # Red and Red - self.assertNotEqual(palette[1], palette[2]) # Blue and altered Blue + self.assertEqual(palette[0], palette[3], "Red and Red") + self.assertNotEqual(palette[1], palette[2], "Blue and altered Blue") def test_nonrepeat_palette_stay_moved(self): """An almost same moved, only temporary""" @@ -76,9 +74,9 @@ def test_nonrepeat_palette_stay_moved(self): pattern += "#0100FF" threadset = get_thread_set() palette = build_nonrepeat_palette(threadset,pattern.threadlist) - self.assertEqual(palette[0],palette[3]) # Red and Red - self.assertNotEqual(palette[1], palette[2]) # Blue and altered Blue - self.assertNotEqual(palette[2], palette[4]) # same color, but color was moved + self.assertEqual(palette[0], palette[3], "Red and Red") + self.assertNotEqual(palette[1], palette[2], "Blue and altered Blue") + self.assertNotEqual(palette[2], palette[4], "same color, but color was moved") def test_nonrepeat_palette_same(self): """The same exact same color if repeated should remain""" @@ -89,8 +87,8 @@ def test_nonrepeat_palette_same(self): pattern += "Red" threadset = get_thread_set() palette = build_nonrepeat_palette(threadset,pattern.threadlist) - self.assertEqual(palette[0],palette[3]) # Red and Red - self.assertEqual(palette[1], palette[2]) # Blue and Blue + self.assertEqual(palette[0], palette[3], "Red and Red") + self.assertEqual(palette[1], palette[2], "Blue and Blue") def test_palette(self): """Similar colors map to the same index""" @@ -101,5 +99,5 @@ def test_palette(self): pattern += "Red" threadset = get_thread_set() palette = build_palette(threadset,pattern.threadlist) - self.assertEqual(palette[0],palette[3]) # Red and altered Red - self.assertEqual(palette[1], palette[2]) # Blue and Blue + self.assertEqual(palette[0], palette[3], "Red and altered Red") + self.assertEqual(palette[1], palette[2], "Blue and Blue") diff --git a/test/test_read_hus.py b/test/test_read_hus.py index 9b4c99b..a57ad13 100644 --- a/test/test_read_hus.py +++ b/test/test_read_hus.py @@ -1,17 +1,14 @@ -# from __future__ import print_function -# -# import random -# import unittest -# -# from EmbCompress import expand, compress -# -# -# class TestReadHus(unittest.TestCase): -# -# def test_fake_compression(self): -# for i in range(10): -# s = random.randint(10, 100000) -# test_bytes = bytearray(random.getrandbits(8) for _ in range(s)) -# compressed_bytes = compress(test_bytes) -# uncompressed = bytearray(expand(compressed_bytes, len(test_bytes))) -# self.assertEqual(test_bytes, uncompressed) +import random +import unittest + +from pystitch.EmbCompress import expand, compress + +@unittest.skip("") +class TestReadHus(unittest.TestCase): + def test_fake_compression(self): + for _ in range(10): + s = random.randint(10, 100000) + test_bytes = bytearray(random.getrandbits(8) for _ in range(s)) + compressed_bytes = compress(test_bytes) + uncompressed = bytearray(expand(compressed_bytes, len(test_bytes))) + self.assertEqual(test_bytes, uncompressed) diff --git a/test/test_writes.py b/test/test_writes.py index d0231e9..ef25ec5 100644 --- a/test/test_writes.py +++ b/test/test_writes.py @@ -1,9 +1,11 @@ -from __future__ import print_function - +from pathlib import Path import unittest +import tempfile + +from test.pattern_for_tests import get_shift_pattern, get_big_pattern -from test.pattern_for_tests import * from pystitch import * +from pystitch import EmbPattern class TestWrites(unittest.TestCase): @@ -12,137 +14,148 @@ def position_equals(self, stitches, j, k): self.assertEqual(stitches[j][:1], stitches[k][:1]) def test_write_png(self): - file1 = "file.png" - write_png(get_shift_pattern(), file1, {"background": "#F00", "linewidth": 5}) - self.addCleanup(os.remove, file1) + pattern = get_shift_pattern() + with tempfile.NamedTemporaryFile(suffix=".png") as fp: + write_png(pattern, fp, {"background": "#F00", "linewidth": 5}) def test_write_fancy_png(self): - file1 = "file-fancy.png" - write_png(get_shift_pattern(), file1, {"background": "#F00", "linewidth": 5, "fancy": True}) - self.addCleanup(os.remove, file1) + pattern = get_shift_pattern() + with tempfile.NamedTemporaryFile(suffix=".png") as fp: + write_png(pattern, fp, {"background": "#F00", "linewidth": 5, "fancy": True}) def test_write_guides_png(self): - file1 = "file-guides.png" - write_png(get_shift_pattern(), file1, {"background": "#F00", "linewidth": 5, "guides": True}) - self.addCleanup(os.remove, file1) + pattern = get_shift_pattern() + with tempfile.NamedTemporaryFile(suffix=".png") as fp: + write_png(pattern, fp, {"background": "#F00", "linewidth": 5, "guides": True}) def test_write_fancy_guides_png(self): - file1 = "file-fancy-guides.png" - write_png(get_shift_pattern(), file1, {"background": "#F00", "linewidth": 5, "fancy": True, "guides": True}) - self.addCleanup(os.remove, file1) + pattern = get_shift_pattern() + with tempfile.NamedTemporaryFile(suffix=".png") as fp: + write_png(pattern, fp, {"background": "#F00", "linewidth": 5, "fancy": True, "guides": True}) def test_write_dst_read_dst(self): - file1 = "file.dst" - write_dst(get_big_pattern(), file1) - dst_pattern = read_dst(file1) + pattern = get_big_pattern() + with tempfile.NamedTemporaryFile(suffix=".dst") as fp: + write_dst(pattern, fp) + fp.seek(0) + dst_pattern = read_dst(fp) self.assertEqual(len(dst_pattern.threadlist), 0) self.assertEqual(dst_pattern.count_stitch_commands(COLOR_CHANGE), 15) self.assertIsNotNone(dst_pattern) self.assertEqual(dst_pattern.count_stitch_commands(STITCH), 5 * 16) self.position_equals(dst_pattern.stitches, 0, -1) print("dst: ", dst_pattern.stitches) - self.addCleanup(os.remove, file1) def test_write_exp_read_exp(self): - file1 = "file.exp" - write_exp(get_big_pattern(), file1) - exp_pattern = read_exp(file1) + pattern = get_big_pattern() + with tempfile.NamedTemporaryFile(suffix=".exp") as fp: + write_exp(pattern, fp) + fp.seek(0) + exp_pattern = read_exp(fp) self.assertEqual(len(exp_pattern.threadlist), 0) self.assertEqual(exp_pattern.count_stitch_commands(COLOR_CHANGE), 15) self.assertIsNotNone(exp_pattern) self.assertEqual(exp_pattern.count_stitch_commands(STITCH), 5 * 16) self.position_equals(exp_pattern.stitches, 0, -1) print("exp: ", exp_pattern.stitches) - self.addCleanup(os.remove, file1) def test_write_vp3_read_vp3(self): - file1 = "file.vp3" - write_vp3(get_big_pattern(), file1) - vp3_pattern = read_vp3(file1) + pattern = get_big_pattern() + with tempfile.NamedTemporaryFile(suffix=".vp3") as fp: + write_vp3(pattern, fp) + fp.seek(0) + vp3_pattern = read_vp3(fp) self.assertEqual(len(vp3_pattern.threadlist), vp3_pattern.count_stitch_commands(COLOR_CHANGE) + 1) self.assertEqual(vp3_pattern.count_stitch_commands(COLOR_CHANGE), 15) self.assertIsNotNone(vp3_pattern) self.assertEqual(vp3_pattern.count_stitch_commands(STITCH), 5 * 16) self.position_equals(vp3_pattern.stitches, 0, -1) print("vp3: ", vp3_pattern.stitches) - self.addCleanup(os.remove, file1) def test_write_jef_read_jef(self): - file1 = "file.jef" - write_jef(get_big_pattern(), file1) - jef_pattern = read_jef(file1) + pattern = get_big_pattern() + with tempfile.NamedTemporaryFile(suffix=".jef") as fp: + write_jef(pattern, fp) + fp.seek(0) + jef_pattern = read_jef(fp) self.assertEqual(len(jef_pattern.threadlist), jef_pattern.count_stitch_commands(COLOR_CHANGE) + 1) self.assertEqual(jef_pattern.count_stitch_commands(COLOR_CHANGE), 15) self.assertIsNotNone(jef_pattern) self.assertEqual(jef_pattern.count_stitch_commands(STITCH), 5 * 16) self.position_equals(jef_pattern.stitches, 0, -1) print("jef: ", jef_pattern.stitches) - self.addCleanup(os.remove, file1) def test_write_pec_read_pec(self): - file1 = "file.pec" - write_pec(get_big_pattern(), file1) - pec_pattern = read_pec(file1) + pattern = get_big_pattern() + with tempfile.NamedTemporaryFile(suffix=".pec") as fp: + write_pec(pattern, fp) + fp.seek(0) + pec_pattern = read_pec(fp) self.assertEqual(len(pec_pattern.threadlist), pec_pattern.count_stitch_commands(COLOR_CHANGE) + 1) self.assertEqual(pec_pattern.count_stitch_commands(COLOR_CHANGE), 15) self.assertIsNotNone(pec_pattern) self.assertEqual(pec_pattern.count_stitch_commands(STITCH), 5 * 16) self.position_equals(pec_pattern.stitches, 0, -1) print("pec: ", pec_pattern.stitches) - self.addCleanup(os.remove, file1) def test_write_pes_read_pes(self): - file1 = "file.pes" - write_pes(get_big_pattern(), file1) - pes_pattern = read_pes(file1) + pattern = get_big_pattern() + with tempfile.NamedTemporaryFile(suffix=".pes") as fp: + write_pes(pattern, fp) + fp.seek(0) + pes_pattern = read_pes(fp) self.assertEqual(len(pes_pattern.threadlist), pes_pattern.count_stitch_commands(COLOR_CHANGE) + 1) self.assertEqual(pes_pattern.count_stitch_commands(COLOR_CHANGE), 15) self.assertIsNotNone(pes_pattern) self.assertEqual(pes_pattern.count_stitch_commands(STITCH), 5 * 16) self.position_equals(pes_pattern.stitches, 0, -1) print("pes: ", pes_pattern.stitches) - self.addCleanup(os.remove, file1) def test_write_xxx_read_xxx(self): - file1 = "file.xxx" - write_xxx(get_big_pattern(), file1) - pattern = read_xxx(file1) + pattern = get_big_pattern() + with tempfile.NamedTemporaryFile(suffix=".xxx") as fp: + write_xxx(pattern, fp) + fp.seek(0) + pattern = read_xxx(fp) self.assertEqual(len(pattern.threadlist), pattern.count_stitch_commands(COLOR_CHANGE) + 1) self.assertEqual(pattern.count_stitch_commands(COLOR_CHANGE), 15) self.assertIsNotNone(pattern) self.assertEqual(pattern.count_stitch_commands(STITCH), 5 * 16) self.position_equals(pattern.stitches, 0, -1) print("xxx: ", pattern.stitches) - self.addCleanup(os.remove, file1) def test_write_u01_read_u01(self): - file1 = "file.u01" - write_u01(get_big_pattern(), file1) - u01_pattern = read_u01(file1) + pattern = get_big_pattern() + with tempfile.NamedTemporaryFile(suffix=".u01") as fp: + write_u01(pattern, fp) + fp.seek(0) + u01_pattern = read_u01(fp) self.assertEqual(len(u01_pattern.threadlist), 0) self.assertEqual(u01_pattern.count_stitch_commands(NEEDLE_SET), 16) self.assertIsNotNone(u01_pattern) self.assertEqual(u01_pattern.count_stitch_commands(STITCH), 5 * 16) self.position_equals(u01_pattern.stitches, 0, -1) print("u01: ", u01_pattern.stitches) - self.addCleanup(os.remove, file1) def test_write_csv_read_csv(self): - file1 = "file.csv" - write_csv(get_big_pattern(), file1, {"encode": True}) - csv_pattern = read_csv(file1) + pattern = get_big_pattern() + with tempfile.TemporaryDirectory() as tmpdirname: + file1 = Path(tmpdirname) / "file.csv" + write_csv(pattern, file1, {"encode": True}) + csv_pattern = read_csv(file1) self.assertIsNotNone(csv_pattern) self.assertEqual(len(csv_pattern.threadlist), csv_pattern.count_stitch_commands(COLOR_CHANGE) + 1) self.assertEqual(csv_pattern.count_stitch_commands(COLOR_CHANGE), 15) self.assertEqual(csv_pattern.count_stitch_commands(STITCH), 5 * 16) self.position_equals(csv_pattern.stitches, 0, -1) print("csv: ", csv_pattern.stitches) - self.addCleanup(os.remove, file1) def test_write_gcode_read_gcode(self): - file1 = "file.gcode" - write_gcode(get_big_pattern(), file1) - gcode_pattern = read_gcode(file1) + pattern = get_big_pattern() + with tempfile.NamedTemporaryFile(suffix=".gcode") as fp: + write_gcode(pattern, fp) + fp.seek(0) + gcode_pattern = read_gcode(fp) self.assertIsNotNone(gcode_pattern) thread_count = len(gcode_pattern.threadlist) change_count = gcode_pattern.count_stitch_commands(COLOR_CHANGE) + 1 @@ -153,16 +166,16 @@ def test_write_gcode_read_gcode(self): self.assertEqual(gcode_pattern.count_stitch_commands(COLOR_CHANGE), 15) self.assertEqual(gcode_pattern.count_stitch_commands(STITCH), 5 * 16) self.position_equals(gcode_pattern.stitches, 0, -1) - self.addCleanup(os.remove, file1) def test_write_txt(self): - file1 = "file.txt" - write_txt(get_big_pattern(), file1) - write_txt(get_big_pattern(), file1, {"mimic": True}) - self.addCleanup(os.remove, file1) + pattern1 = get_big_pattern() + pattern2 = get_big_pattern() + with tempfile.NamedTemporaryFile(suffix=".txt") as fp: + write_txt(pattern1, fp) + fp.seek(0) + write_txt(pattern2, fp, {"mimic": True}) def test_write_pes_mismatched(self): - file1 = "file.pes" pattern = EmbPattern() pattern += "red" pattern += "red" @@ -174,13 +187,13 @@ def test_write_pes_mismatched(self): pattern += (0, 0), (100, 100) pattern += COLOR_CHANGE pattern += (100, 0), (0, 100) - write_pes(pattern, file1, {"version": "6t"}) - write_pes(pattern, file1) - self.addCleanup(os.remove, file1) + with tempfile.NamedTemporaryFile(suffix=".pes") as fp: + write_pes(pattern, fp, {"version": "6t"}) + fp.seek(0) + write_pes(pattern, fp) def test_pes_writes_stop(self): """Test if pes can read/write a stop command.""" - file1 = "file.pes" pattern = EmbPattern() pattern += "red" pattern += (0, 0), (100, 100) @@ -190,13 +203,13 @@ def test_pes_writes_stop(self): pattern += (0, 0), (100, 100) pattern += STOP pattern += (100, 0), (0, 100) - write_pes(pattern, file1, {"version": "6t"}) - loaded = read_pes(file1) + with tempfile.NamedTemporaryFile(suffix=".pes") as fp: + write_pes(pattern, fp, {"version": "6t"}) + fp.seek(0) + loaded = read_pes(fp) self.assertEqual(pattern.count_stitch_commands(STOP), 2) self.assertEqual(pattern.count_stitch_commands(COLOR_CHANGE), 1) self.assertEqual(pattern.count_threads(), 2) self.assertEqual(loaded.count_stitch_commands(STOP), 2) self.assertEqual(loaded.count_stitch_commands(COLOR_CHANGE), 1) self.assertEqual(loaded.count_threads(), 2) - self.addCleanup(os.remove, file1) -