1
0
mirror of https://github.com/python-escpos/python-escpos synced 2025-08-24 09:03:34 +00:00

start removal of six and improve type annotation (#607)

* fix unfinished Python2 -> 3 translation
* remove some six usage
* annotate
* fix regression in Six removal
* mypy: self.enf is always defined
* fix return type of cups.py
* Usb idVendor/idProduct are integers
* self.default_args is always defined
* tweak usb_args, PEP589 is better
* lp.py: reassure mypy
* correctly cast call to CashDrawerError()
* update CUPS test
* add missing close() method in metaclass
* document a bug in typeshed
* query_status() returns bytes as seen in constants.py
* remove more SIX usage
* test examples too
* remove type comment where type is annotated
* adapt behavior of cups printer to match other implementations

---------

Co-authored-by: Patrick Kanzler <dev@pkanzler.de>
Co-authored-by: Patrick Kanzler <4189642+patkan@users.noreply.github.com>
This commit is contained in:
Alexandre Detiste
2023-12-16 22:02:24 +01:00
committed by GitHub
parent 06bdb56937
commit 66a2e78e16
31 changed files with 245 additions and 237 deletions

View File

@@ -7,7 +7,6 @@ import os
import shutil
import tempfile
import pytest
from scripttest import TestFileEnvironment as TFE
import escpos
@@ -31,22 +30,19 @@ class TestCLI:
"""Contains setups, teardowns, and tests for CLI"""
@classmethod
def setup_class(cls):
def setup_class(cls) -> None:
"""Create a config file to read from"""
with open(CONFIGFILE, "w") as config:
config.write(CONFIG_YAML)
@classmethod
def teardown_class(cls):
def teardown_class(cls) -> None:
"""Remove config file"""
os.remove(CONFIGFILE)
shutil.rmtree(TEST_DIR)
def setup_method(self):
def setup_method(self) -> None:
"""Create a file to print to and set up env"""
self.env = None
self.default_args = None
self.env = TFE(
base_path=TEST_DIR,
cwd=os.getcwd(),
@@ -64,24 +60,24 @@ class TestCLI:
finally:
fhandle.close()
def teardown_method(self):
def teardown_method(self) -> None:
"""Destroy printer file and env"""
os.remove(DEVFILE)
self.env.clear()
def test_cli_help(self):
def test_cli_help(self) -> None:
"""Test getting help from cli"""
result = self.env.run("python-escpos", "-h")
assert not result.stderr
assert "usage" in result.stdout
def test_cli_version(self):
def test_cli_version(self) -> None:
"""Test the version string"""
result = self.env.run("python-escpos", "version")
assert not result.stderr
assert escpos.__version__ == result.stdout.strip()
def test_cli_version_extended(self):
def test_cli_version_extended(self) -> None:
"""Test the extended version information"""
result = self.env.run("python-escpos", "version_extended")
assert not result.stderr
@@ -89,7 +85,7 @@ class TestCLI:
# test that additional information on e.g. Serial is printed
assert "Serial" in result.stdout
def test_cli_text(self):
def test_cli_text(self) -> None:
"""Make sure text returns what we sent it"""
test_text = "this is some text"
result = self.env.run(
@@ -108,7 +104,7 @@ class TestCLI:
result.files_updated[DEVFILE_NAME].bytes == "\x1bt\x00" + test_text + "\n"
)
def test_cli_text_invalid_args(self):
def test_cli_text_invalid_args(self) -> None:
"""Test a failure to send valid arguments"""
result = self.env.run(
*(self.default_args + ("text", "--invalid-param", "some data")),

View File

@@ -1,14 +1,13 @@
import pytest
import six
from escpos import printer
from escpos.constants import BUZZER
def test_buzzer_function_with_default_params():
def test_buzzer_function_with_default_params() -> None:
instance = printer.Dummy()
instance.buzzer()
expected = BUZZER + six.int2byte(2) + six.int2byte(4)
expected = BUZZER + bytes((2, 4))
assert instance.output == expected
@@ -26,10 +25,10 @@ def test_buzzer_function_with_default_params():
[9, 9],
],
)
def test_buzzer_function(times, duration):
def test_buzzer_function(times: int, duration: int) -> None:
instance = printer.Dummy()
instance.buzzer(times, duration)
expected = BUZZER + six.int2byte(times) + six.int2byte(duration)
expected = BUZZER + bytes((times, duration))
assert instance.output == expected
@@ -46,7 +45,9 @@ def test_buzzer_function(times, duration):
[3, 11, "duration must be between 1 and 9"],
],
)
def test_buzzer_fuction_with_outrange_values(times, duration, expected_message):
def test_buzzer_fuction_with_outrange_values(
times: int, duration: int, expected_message: str
) -> None:
instance = printer.Dummy()
with pytest.raises(ValueError) as e:
instance.buzzer(times, duration)

View File

@@ -1,5 +1,3 @@
import six
import escpos.printer as printer
from escpos.constants import GS
@@ -8,5 +6,5 @@ def test_cut_without_feed():
"""Test cut without feeding paper"""
instance = printer.Dummy()
instance.cut(feed=False)
expected = GS + b"V" + six.int2byte(66) + b"\x00"
expected = GS + b"V" + bytes((66,)) + b"\x00"
assert instance.output == expected

View File

@@ -16,7 +16,7 @@ from escpos.exceptions import ImageWidthError
# Raster format print
def test_bit_image_black():
def test_bit_image_black() -> None:
"""
Test printing solid black bit image (raster)
"""
@@ -30,7 +30,7 @@ def test_bit_image_black():
assert instance.output == b"\x1dv0\x00\x01\x00\x01\x00\x80"
def test_bit_image_white():
def test_bit_image_white() -> None:
"""
Test printing solid white bit image (raster)
"""
@@ -39,7 +39,7 @@ def test_bit_image_white():
assert instance.output == b"\x1dv0\x00\x01\x00\x01\x00\x00"
def test_bit_image_both():
def test_bit_image_both() -> None:
"""
Test printing black/white bit image (raster)
"""
@@ -58,7 +58,7 @@ def test_bit_image_transparent():
# Column format print
def test_bit_image_colfmt_black():
def test_bit_image_colfmt_black() -> None:
"""
Test printing solid black bit image (column format)
"""
@@ -67,7 +67,7 @@ def test_bit_image_colfmt_black():
assert instance.output == b"\x1b3\x10\x1b*!\x01\x00\x80\x00\x00\x0a\x1b2"
def test_bit_image_colfmt_white():
def test_bit_image_colfmt_white() -> None:
"""
Test printing solid white bit image (column format)
"""
@@ -76,7 +76,7 @@ def test_bit_image_colfmt_white():
assert instance.output == b"\x1b3\x10\x1b*!\x01\x00\x00\x00\x00\x0a\x1b2"
def test_bit_image_colfmt_both():
def test_bit_image_colfmt_both() -> None:
"""
Test printing black/white bit image (column format)
"""
@@ -87,7 +87,7 @@ def test_bit_image_colfmt_both():
)
def test_bit_image_colfmt_transparent():
def test_bit_image_colfmt_transparent() -> None:
"""
Test printing black/transparent bit image (column format)
"""
@@ -99,7 +99,7 @@ def test_bit_image_colfmt_transparent():
# Graphics print
def test_graphics_black():
def test_graphics_black() -> None:
"""
Test printing solid black graphics
"""
@@ -111,7 +111,7 @@ def test_graphics_black():
)
def test_graphics_white():
def test_graphics_white() -> None:
"""
Test printing solid white graphics
"""
@@ -123,7 +123,7 @@ def test_graphics_white():
)
def test_graphics_both():
def test_graphics_both() -> None:
"""
Test printing black/white graphics
"""
@@ -135,7 +135,7 @@ def test_graphics_both():
)
def test_graphics_transparent():
def test_graphics_transparent() -> None:
"""
Test printing black/transparent graphics
"""
@@ -147,7 +147,7 @@ def test_graphics_transparent():
)
def test_large_graphics():
def test_large_graphics() -> None:
"""
Test whether 'large' graphics that induce a fragmentation are handled correctly.
"""
@@ -162,13 +162,13 @@ def test_large_graphics():
@pytest.fixture
def dummy_with_width():
def dummy_with_width() -> printer.Dummy:
instance = printer.Dummy()
instance.profile.profile_data = {"media": {"width": {"pixels": 384}}}
return instance
def test_width_too_large(dummy_with_width):
def test_width_too_large(dummy_with_width: printer.Dummy) -> None:
"""
Test printing an image that is too large in width.
"""
@@ -180,7 +180,7 @@ def test_width_too_large(dummy_with_width):
instance.image(Image.new("RGB", (384, 200)))
def test_center_image(dummy_with_width):
def test_center_image(dummy_with_width: printer.Dummy) -> None:
instance = dummy_with_width
with pytest.raises(ImageWidthError):

View File

@@ -11,21 +11,21 @@
import escpos.printer as printer
def test_function_linedisplay_select_on():
def test_function_linedisplay_select_on() -> None:
"""test the linedisplay_select function (activate)"""
instance = printer.Dummy()
instance.linedisplay_select(select_display=True)
assert instance.output == b"\x1B\x3D\x02"
def test_function_linedisplay_select_off():
def test_function_linedisplay_select_off() -> None:
"""test the linedisplay_select function (deactivate)"""
instance = printer.Dummy()
instance.linedisplay_select(select_display=False)
assert instance.output == b"\x1B\x3D\x01"
def test_function_linedisplay_clear():
def test_function_linedisplay_clear() -> None:
"""test the linedisplay_clear function"""
instance = printer.Dummy()
instance.linedisplay_clear()

View File

@@ -1,3 +1,5 @@
from typing import Optional
import pytest
import six
@@ -6,7 +8,7 @@ from escpos.constants import SET_FONT, TXT_NORMAL, TXT_SIZE, TXT_STYLE
from escpos.exceptions import SetVariableError
def test_default_values_with_default():
def test_default_values_with_default() -> None:
"""Default test, please copy and paste this block to test set method calls"""
instance = printer.Dummy()
instance.set_with_default()
@@ -26,7 +28,7 @@ def test_default_values_with_default():
assert instance.output == b"".join(expected_sequence)
def test_default_values():
def test_default_values() -> None:
"""Default test"""
instance = printer.Dummy()
instance.set()
@@ -37,7 +39,7 @@ def test_default_values():
# Size tests
def test_set_size_2h():
def test_set_size_2h() -> None:
instance = printer.Dummy()
instance.set_with_default(double_height=True)
@@ -56,7 +58,7 @@ def test_set_size_2h():
assert instance.output == b"".join(expected_sequence)
def test_set_size_2h_no_default():
def test_set_size_2h_no_default() -> None:
instance = printer.Dummy()
instance.set(double_height=True)
@@ -68,7 +70,7 @@ def test_set_size_2h_no_default():
assert instance.output == b"".join(expected_sequence)
def test_set_size_2w():
def test_set_size_2w() -> None:
instance = printer.Dummy()
instance.set_with_default(double_width=True)
@@ -87,7 +89,7 @@ def test_set_size_2w():
assert instance.output == b"".join(expected_sequence)
def test_set_size_2w_no_default():
def test_set_size_2w_no_default() -> None:
instance = printer.Dummy()
instance.set(double_width=True)
@@ -99,7 +101,7 @@ def test_set_size_2w_no_default():
assert instance.output == b"".join(expected_sequence)
def test_set_size_2x():
def test_set_size_2x() -> None:
instance = printer.Dummy()
instance.set_with_default(double_height=True, double_width=True)
@@ -118,7 +120,7 @@ def test_set_size_2x():
assert instance.output == b"".join(expected_sequence)
def test_set_size_2x_no_default():
def test_set_size_2x_no_default() -> None:
instance = printer.Dummy()
instance.set(double_width=True, double_height=True)
@@ -130,7 +132,7 @@ def test_set_size_2x_no_default():
assert instance.output == b"".join(expected_sequence)
def test_set_size_custom():
def test_set_size_custom() -> None:
instance = printer.Dummy()
instance.set_with_default(custom_size=True, width=8, height=7)
@@ -151,7 +153,7 @@ def test_set_size_custom():
@pytest.mark.parametrize("width", [1, 8])
@pytest.mark.parametrize("height", [1, 8])
def test_set_size_custom_no_default(width, height):
def test_set_size_custom_no_default(width: int, height: int) -> None:
instance = printer.Dummy()
instance.set(custom_size=True, width=width, height=height)
@@ -165,7 +167,9 @@ def test_set_size_custom_no_default(width, height):
@pytest.mark.parametrize("width", [None, 0, 9, 10, 4444])
@pytest.mark.parametrize("height", [None, 0, 9, 10, 4444])
def test_set_size_custom_invalid_input(width, height):
def test_set_size_custom_invalid_input(
width: Optional[int], height: Optional[int]
) -> None:
instance = printer.Dummy()
with pytest.raises(SetVariableError):
instance.set(custom_size=True, width=width, height=height)
@@ -174,7 +178,7 @@ def test_set_size_custom_invalid_input(width, height):
# Flip
def test_set_flip():
def test_set_flip() -> None:
instance = printer.Dummy()
instance.set_with_default(flip=True)
@@ -193,7 +197,7 @@ def test_set_flip():
assert instance.output == b"".join(expected_sequence)
def test_set_flip_no_default():
def test_set_flip_no_default() -> None:
instance = printer.Dummy()
instance.set(flip=True)
@@ -205,7 +209,7 @@ def test_set_flip_no_default():
# Smooth
def test_smooth():
def test_smooth() -> None:
instance = printer.Dummy()
instance.set_with_default(smooth=True)
@@ -227,7 +231,7 @@ def test_smooth():
# Type
def test_set_bold():
def test_set_bold() -> None:
instance = printer.Dummy()
instance.set_with_default(bold=True)
@@ -246,7 +250,7 @@ def test_set_bold():
assert instance.output == b"".join(expected_sequence)
def test_set_underline():
def test_set_underline() -> None:
instance = printer.Dummy()
instance.set_with_default(underline=1)
@@ -265,7 +269,7 @@ def test_set_underline():
assert instance.output == b"".join(expected_sequence)
def test_set_underline2():
def test_set_underline2() -> None:
instance = printer.Dummy()
instance.set_with_default(underline=2)
@@ -287,7 +291,7 @@ def test_set_underline2():
# Align
def test_align_center():
def test_align_center() -> None:
instance = printer.Dummy()
instance.set_with_default(align="center")
@@ -306,7 +310,7 @@ def test_align_center():
assert instance.output == b"".join(expected_sequence)
def test_align_right():
def test_align_right() -> None:
instance = printer.Dummy()
instance.set_with_default(align="right")
@@ -328,7 +332,7 @@ def test_align_right():
# Densities
def test_densities():
def test_densities() -> None:
for density in range(8):
instance = printer.Dummy()
instance.set_with_default(density=density)
@@ -352,7 +356,7 @@ def test_densities():
# Invert
def test_invert():
def test_invert() -> None:
instance = printer.Dummy()
instance.set_with_default(invert=True)

View File

@@ -10,8 +10,7 @@
import hypothesis.strategies as st
import mock
import pytest
from hypothesis import assume, given
from hypothesis import given
from escpos.printer import Dummy
@@ -21,7 +20,7 @@ def get_printer():
@given(text=st.text())
def test_text(text):
def test_text(text: str) -> None:
"""Test that text() calls the MagicEncode object."""
instance = get_printer()
instance.magic.write = mock.Mock()
@@ -29,7 +28,7 @@ def test_text(text):
instance.magic.write.assert_called_with(text)
def test_block_text():
def test_block_text() -> None:
printer = get_printer()
printer.block_text(
"All the presidents men were eating falafel for breakfast.", font="a"
@@ -39,25 +38,25 @@ def test_block_text():
)
def test_textln():
def test_textln() -> None:
printer = get_printer()
printer.textln("hello, world")
assert printer.output == b"hello, world\n"
def test_textln_empty():
def test_textln_empty() -> None:
printer = get_printer()
printer.textln()
assert printer.output == b"\n"
def test_ln():
def test_ln() -> None:
printer = get_printer()
printer.ln()
assert printer.output == b"\n"
def test_multiple_ln():
def test_multiple_ln() -> None:
printer = get_printer()
printer.ln(3)
assert printer.output == b"\n\n\n"

View File

@@ -7,11 +7,12 @@ converted to ESC/POS column & raster formats.
:copyright: Copyright (c) 2016 `Michael Billington <michael.billington@gmail.com>`_
:license: MIT
"""
from typing import List
from escpos.image import EscposImage
def test_image_black():
def test_image_black() -> None:
"""
Test rendering solid black image
"""
@@ -19,7 +20,7 @@ def test_image_black():
_load_and_check_img("canvas_black." + img_format, 1, 1, b"\x80", [b"\x80"])
def test_image_black_transparent():
def test_image_black_transparent() -> None:
"""
Test rendering black/transparent image
"""
@@ -29,7 +30,7 @@ def test_image_black_transparent():
)
def test_image_black_white():
def test_image_black_white() -> None:
"""
Test rendering black/white image
"""
@@ -39,7 +40,7 @@ def test_image_black_white():
)
def test_image_white():
def test_image_white() -> None:
"""
Test rendering solid white image
"""
@@ -47,7 +48,7 @@ def test_image_white():
_load_and_check_img("canvas_white." + img_format, 1, 1, b"\x00", [b"\x00"])
def test_split():
def test_split() -> None:
"""
test whether the split-function works as expected
"""
@@ -62,12 +63,12 @@ def test_split():
def _load_and_check_img(
filename,
width_expected,
height_expected,
raster_format_expected,
column_format_expected,
):
filename: str,
width_expected: int,
height_expected: int,
raster_format_expected: bytes,
column_format_expected: List[bytes],
) -> None:
"""
Load an image, and test whether raster & column formatted output, sizes, etc match expectations.
"""

View File

@@ -13,7 +13,7 @@ import hypothesis.strategies as st
import pytest
from hypothesis import example, given
from escpos.exceptions import CharCodeError, Error
from escpos.exceptions import Error
from escpos.katakana import encode_katakana
from escpos.magicencode import Encoder, MagicEncode
@@ -23,23 +23,23 @@ class TestEncoder:
Tests the single encoders.
"""
def test_can_encode(self):
def test_can_encode(self) -> None:
assert not Encoder({"CP437": 1}).can_encode("CP437", "")
assert Encoder({"CP437": 1}).can_encode("CP437", "á")
assert not Encoder({"foobar": 1}).can_encode("foobar", "a")
def test_find_suitable_encoding(self):
def test_find_suitable_encoding(self) -> None:
assert not Encoder({"CP437": 1}).find_suitable_encoding("")
assert Encoder({"CP858": 1}).find_suitable_encoding("") == "CP858"
def test_find_suitable_encoding_unnecessary_codepage_swap(self):
def test_find_suitable_encoding_unnecessary_codepage_swap(self) -> None:
enc = Encoder({"CP857": 1, "CP437": 2, "CP1252": 3, "CP852": 4, "CP858": 5})
# desired behavior would be that the encoder always stays in the lower
# available codepages if possible
for character in ("Á", "É", "Í", "Ó", "Ú"):
assert enc.find_suitable_encoding(character) == "CP857"
def test_get_encoding(self):
def test_get_encoding(self) -> None:
with pytest.raises(ValueError):
Encoder({}).get_encoding_name("latin1")
@@ -122,9 +122,9 @@ class TestKatakana:
@example("カタカナ")
@example("あいうえお")
@example("ハンカクカタカナ")
def test_accept(self, text):
def test_accept(self, text: str) -> None:
encode_katakana(text)
def test_result(self):
def test_result(self) -> None:
assert encode_katakana("カタカナ") == b"\xb6\xc0\xb6\xc5"
assert encode_katakana("あいうえお") == b"\xb1\xb2\xb3\xb4\xb5"

View File

@@ -19,7 +19,7 @@ pytestmark = pytest.mark.skipif(
)
def test_device_not_initialized(cupsprinter):
def test_device_not_initialized(cupsprinter) -> None:
"""
GIVEN a cups printer object
WHEN it is not initialized
@@ -28,7 +28,7 @@ def test_device_not_initialized(cupsprinter):
assert cupsprinter._device is False
def test_open_raise_exception(cupsprinter, devicenotfounderror):
def test_open_raise_exception(cupsprinter, devicenotfounderror) -> None:
"""
GIVEN a cups printer object
WHEN open() is set to raise a DeviceNotFoundError on error
@@ -40,7 +40,7 @@ def test_open_raise_exception(cupsprinter, devicenotfounderror):
cupsprinter.open(raise_not_found=True)
def test_open_not_raise_exception(cupsprinter, caplog):
def test_open_not_raise_exception(cupsprinter, caplog) -> None:
"""
GIVEN a cups printer object
WHEN open() is set to not raise on error but simply cancel
@@ -55,7 +55,7 @@ def test_open_not_raise_exception(cupsprinter, caplog):
assert cupsprinter.device is None
def test_open(cupsprinter, caplog, mocker):
def test_open(cupsprinter, caplog, mocker) -> None:
"""
GIVEN a cups printer object and a mocked pycups device
WHEN a valid connection to a device is opened
@@ -74,7 +74,7 @@ def test_open(cupsprinter, caplog, mocker):
assert cupsprinter.device
def test_close_on_reopen(cupsprinter, mocker):
def test_close_on_reopen(cupsprinter, mocker) -> None:
"""
GIVEN a cups printer object and a mocked connection
WHEN a valid connection to a device is reopened before close
@@ -112,7 +112,7 @@ def test_close(cupsprinter, caplog, mocker):
assert cupsprinter._device is False
def test_send_on_close(cupsprinter, mocker):
def test_send_on_close(cupsprinter, mocker) -> None:
"""
GIVEN a cups printer object and a mocked pycups device
WHEN closing connection before send the buffer
@@ -133,7 +133,7 @@ def test_send_on_close(cupsprinter, mocker):
assert cupsprinter.pending_job is False
def test_raw_raise_exception(cupsprinter):
def test_raw_raise_exception(cupsprinter) -> None:
"""
GIVEN a cups printer object
WHEN passing a non byte string to _raw()
@@ -145,7 +145,7 @@ def test_raw_raise_exception(cupsprinter):
assert cupsprinter.pending_job is False
def test_raw(cupsprinter):
def test_raw(cupsprinter) -> None:
"""
GIVEN a cups printer object
WHEN passing a byte string to _raw()
@@ -156,7 +156,7 @@ def test_raw(cupsprinter):
assert cupsprinter.tmpfile.read() == b"Test"
def test_printers_no_device(cupsprinter):
def test_printers_no_device(cupsprinter) -> None:
"""
GIVEN a cups printer object
WHEN device is None
@@ -166,11 +166,11 @@ def test_printers_no_device(cupsprinter):
assert cupsprinter.printers == {}
def test_read_no_device(cupsprinter):
def test_read_no_device(cupsprinter) -> None:
"""
GIVEN a cups printer object
WHEN device is None
THEN check the return value is []
THEN check the return value is b'8'
"""
cupsprinter.device = None
assert cupsprinter._read() == []
assert cupsprinter._read() == b"8"