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:
parent
06bdb56937
commit
66a2e78e16
|
@ -3,8 +3,6 @@
|
|||
|
||||
import sys
|
||||
|
||||
import six
|
||||
|
||||
from escpos import printer
|
||||
from escpos.constants import (
|
||||
CODEPAGE_CHANGE,
|
||||
|
@ -38,7 +36,7 @@ def print_codepage(printer, codepage):
|
|||
"""Print a codepage."""
|
||||
if codepage.isdigit():
|
||||
codepage = int(codepage)
|
||||
printer._raw(CODEPAGE_CHANGE + six.int2byte(codepage))
|
||||
printer._raw(CODEPAGE_CHANGE + bytes((codepage,)))
|
||||
printer._raw("after")
|
||||
else:
|
||||
printer.charcode(codepage)
|
||||
|
@ -58,7 +56,9 @@ def print_codepage(printer, codepage):
|
|||
printer.set()
|
||||
|
||||
for y in range(0, 16):
|
||||
byte = six.int2byte(x * 16 + y)
|
||||
byte = bytes(
|
||||
(x * 16 + y),
|
||||
)
|
||||
|
||||
if byte in (ESC, CTL_LF, CTL_FF, CTL_CR, CTL_HT, CTL_VT):
|
||||
byte = " "
|
||||
|
|
|
@ -18,8 +18,8 @@ import calendar
|
|||
import json
|
||||
import os
|
||||
import time
|
||||
import urllib
|
||||
from datetime import datetime
|
||||
from urllib.request import urlopen
|
||||
|
||||
from escpos.printer import Usb
|
||||
|
||||
|
@ -93,7 +93,7 @@ url = (
|
|||
+ LONG
|
||||
+ "?exclude=[alerts,minutely,hourly,flags]&units=si"
|
||||
) # change last bit to 'us' for Fahrenheit
|
||||
response = urllib.urlopen(url)
|
||||
response = urlopen(url)
|
||||
data = json.loads(response.read())
|
||||
|
||||
printer.print_and_feed(n=1)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""python-escpos enables you to manipulate escpos-printers."""
|
||||
|
||||
__all__ = ["constants", "escpos", "exceptions", "printer"]
|
||||
__all__ = ["constants", "escpos", "exceptions", "printer", "__version__"]
|
||||
|
||||
try:
|
||||
from .version import version as __version__ # noqa
|
||||
|
|
|
@ -11,7 +11,6 @@ from tempfile import mkdtemp
|
|||
from typing import Any, Dict, Optional, Type
|
||||
|
||||
import importlib_resources
|
||||
import six
|
||||
import yaml
|
||||
|
||||
logging.basicConfig()
|
||||
|
@ -92,7 +91,7 @@ class NotSupported(Exception):
|
|||
BARCODE_B = "barcodeB"
|
||||
|
||||
|
||||
class BaseProfile(object):
|
||||
class BaseProfile:
|
||||
"""This represents a printer profile.
|
||||
|
||||
A printer profile knows about the number of columns, supported
|
||||
|
@ -111,20 +110,22 @@ class BaseProfile(object):
|
|||
Makes sure that the requested `font` is valid.
|
||||
"""
|
||||
font = {"a": 0, "b": 1}.get(font, font)
|
||||
if not six.text_type(font) in self.fonts:
|
||||
if not str(font) in self.fonts:
|
||||
raise NotSupported(f'"{font}" is not a valid font in the current profile')
|
||||
return font
|
||||
|
||||
def get_columns(self, font):
|
||||
def get_columns(self, font) -> int:
|
||||
"""Return the number of columns for the given font."""
|
||||
font = self.get_font(font)
|
||||
return self.fonts[six.text_type(font)]["columns"]
|
||||
columns = self.fonts[str(font)]["columns"]
|
||||
assert type(columns) is int
|
||||
return columns
|
||||
|
||||
def supports(self, feature):
|
||||
def supports(self, feature) -> bool:
|
||||
"""Return true/false for the given feature."""
|
||||
return self.features.get(feature)
|
||||
|
||||
def get_code_pages(self):
|
||||
def get_code_pages(self) -> Dict[str, int]:
|
||||
"""Return the support code pages as a ``{name: index}`` dict."""
|
||||
return {v: k for k, v in self.codePages.items()}
|
||||
|
||||
|
@ -161,7 +162,7 @@ def get_profile_class(name: str) -> Type[BaseProfile]:
|
|||
return CLASS_CACHE[name]
|
||||
|
||||
|
||||
def clean(s):
|
||||
def clean(s: str) -> str:
|
||||
"""Clean profile name."""
|
||||
# Remove invalid characters
|
||||
s = re.sub("[^0-9a-zA-Z_]", "", s)
|
||||
|
@ -180,14 +181,14 @@ class Profile(ProfileBaseClass):
|
|||
For users, who want to provide their own profile.
|
||||
"""
|
||||
|
||||
def __init__(self, columns=None, features=None):
|
||||
def __init__(self, columns: Optional[int] = None, features=None) -> None:
|
||||
"""Initialize profile."""
|
||||
super(Profile, self).__init__()
|
||||
|
||||
self.columns = columns
|
||||
self.features = features or {}
|
||||
|
||||
def get_columns(self, font):
|
||||
def get_columns(self, font) -> int:
|
||||
"""Get column count of printer."""
|
||||
if self.columns is not None:
|
||||
return self.columns
|
||||
|
|
|
@ -20,15 +20,13 @@ except ImportError:
|
|||
pass # noqa
|
||||
import sys
|
||||
|
||||
import six
|
||||
|
||||
from . import config
|
||||
from . import printer as escpos_printer_module
|
||||
from . import version
|
||||
|
||||
|
||||
# Must be defined before it's used in DEMO_FUNCTIONS
|
||||
def str_to_bool(string):
|
||||
def str_to_bool(string: str) -> bool:
|
||||
"""Convert string to bool.
|
||||
|
||||
Used as a type in argparse so that we get back a proper
|
||||
|
@ -563,7 +561,7 @@ def generate_parser() -> argparse.ArgumentParser:
|
|||
return parser
|
||||
|
||||
|
||||
def main():
|
||||
def main() -> None:
|
||||
"""Handle main entry point of CLI script.
|
||||
|
||||
Handles loading of configuration and creating and processing of command
|
||||
|
@ -580,9 +578,7 @@ def main():
|
|||
if not args_dict:
|
||||
parser.print_help()
|
||||
sys.exit()
|
||||
command_arguments = dict(
|
||||
[k, v] for k, v in six.iteritems(args_dict) if v is not None
|
||||
)
|
||||
command_arguments = dict([k, v] for k, v in args_dict.items() if v is not None)
|
||||
|
||||
# If version should be printed, do this, then exit
|
||||
print_version = command_arguments.pop("version", None)
|
||||
|
@ -621,7 +617,7 @@ def main():
|
|||
globals()[target_command](**command_arguments)
|
||||
|
||||
|
||||
def demo(printer, **kwargs):
|
||||
def demo(printer, **kwargs) -> None:
|
||||
"""Print demos.
|
||||
|
||||
Called when CLI is passed `demo`. This function
|
||||
|
|
|
@ -11,7 +11,7 @@ import yaml
|
|||
from . import exceptions, printer
|
||||
|
||||
|
||||
class Config(object):
|
||||
class Config:
|
||||
"""Configuration handler class.
|
||||
|
||||
This class loads configuration from a default or specified directory. It
|
||||
|
@ -21,7 +21,7 @@ class Config(object):
|
|||
_app_name = "python-escpos"
|
||||
_config_file = "config.yaml"
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self) -> None:
|
||||
"""Initialize configuration.
|
||||
|
||||
Remember to add anything that needs to be reset between configurations
|
||||
|
@ -33,7 +33,7 @@ class Config(object):
|
|||
self._printer_name = None
|
||||
self._printer_config = None
|
||||
|
||||
def _reset_config(self):
|
||||
def _reset_config(self) -> None:
|
||||
"""Clear the loaded configuration.
|
||||
|
||||
If we are loading a changed config, we don't want to have leftover
|
||||
|
|
|
@ -46,9 +46,7 @@ HW_RESET: bytes = ESC + b"\x3f\x0a\x00" # Reset printer hardware
|
|||
# (TODO: Where is this specified?)
|
||||
|
||||
# Cash Drawer (ESC p <pin> <on time: 2*ms> <off time: 2*ms>)
|
||||
_CASH_DRAWER = (
|
||||
lambda m, t1="", t2="": ESC + b"p" + m + six.int2byte(t1) + six.int2byte(t2)
|
||||
)
|
||||
_CASH_DRAWER = lambda m, t1="", t2="": ESC + b"p" + m + bytes((t1, t2))
|
||||
|
||||
#: decimal cash drawer kick sequence
|
||||
CD_KICK_DEC_SEQUENCE = (
|
||||
|
|
|
@ -9,13 +9,14 @@ This module contains the abstract base class :py:class:`Escpos`.
|
|||
:copyright: Copyright (c) 2012-2017 Bashlinux and python-escpos
|
||||
:license: MIT
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import textwrap
|
||||
import warnings
|
||||
from abc import ABCMeta, abstractmethod # abstract base class support
|
||||
from re import match as re_match
|
||||
from typing import List, Literal, Optional, Union
|
||||
from types import TracebackType
|
||||
from typing import Any, Literal, Optional, Union
|
||||
|
||||
import barcode
|
||||
import qrcode
|
||||
|
@ -107,8 +108,7 @@ SW_BARCODE_NAMES = {
|
|||
}
|
||||
|
||||
|
||||
@six.add_metaclass(ABCMeta)
|
||||
class Escpos(object):
|
||||
class Escpos(object, metaclass=ABCMeta):
|
||||
"""ESC/POS Printer object.
|
||||
|
||||
This class is the abstract base class for an Esc/Pos-printer. The printer implementations are children of this
|
||||
|
@ -154,6 +154,10 @@ class Escpos(object):
|
|||
"""Open a printer device/connection."""
|
||||
pass
|
||||
|
||||
def close(self):
|
||||
"""Close a printer device/connection."""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def _raw(self, msg: bytes) -> None:
|
||||
"""Send raw data to the printer.
|
||||
|
@ -164,7 +168,7 @@ class Escpos(object):
|
|||
"""
|
||||
pass
|
||||
|
||||
def _read(self):
|
||||
def _read(self) -> bytes:
|
||||
"""Read from printer.
|
||||
|
||||
Returns a NotImplementedError if the instance of the class doesn't override this method.
|
||||
|
@ -250,7 +254,7 @@ class Escpos(object):
|
|||
header = (
|
||||
GS
|
||||
+ b"v0"
|
||||
+ six.int2byte(density_byte)
|
||||
+ bytes((density_byte,))
|
||||
+ self._int_low_high(im.width_bytes, 2)
|
||||
+ self._int_low_high(im.height, 2)
|
||||
)
|
||||
|
@ -263,8 +267,8 @@ class Escpos(object):
|
|||
)
|
||||
tone = b"0"
|
||||
colors = b"1"
|
||||
ym = six.int2byte(1 if high_density_vertical else 2)
|
||||
xm = six.int2byte(1 if high_density_horizontal else 2)
|
||||
ym = b"\x01" if high_density_vertical else b"\x02"
|
||||
xm = b"\x01" if high_density_horizontal else b"\x02"
|
||||
header = tone + xm + ym + colors + img_header
|
||||
raster_data = im.to_raster_format()
|
||||
self._image_send_graphics_data(b"0", b"p", header + raster_data)
|
||||
|
@ -847,7 +851,7 @@ class Escpos(object):
|
|||
image = my_code.writer._image
|
||||
self.image(image, impl=impl, center=center)
|
||||
|
||||
def text(self, txt):
|
||||
def text(self, txt: str) -> None:
|
||||
"""Print alpha-numeric text.
|
||||
|
||||
The text has to be encoded in the currently selected codepage.
|
||||
|
@ -856,10 +860,9 @@ class Escpos(object):
|
|||
:param txt: text to be printed
|
||||
:raises: :py:exc:`~escpos.exceptions.TextError`
|
||||
"""
|
||||
txt = six.text_type(txt)
|
||||
self.magic.write(txt)
|
||||
self.magic.write(str(txt))
|
||||
|
||||
def textln(self, txt=""):
|
||||
def textln(self, txt: str = "") -> None:
|
||||
"""Print alpha-numeric text with a newline.
|
||||
|
||||
The text has to be encoded in the currently selected codepage.
|
||||
|
@ -870,7 +873,7 @@ class Escpos(object):
|
|||
"""
|
||||
self.text(f"{txt}\n")
|
||||
|
||||
def ln(self, count=1):
|
||||
def ln(self, count: int = 1) -> None:
|
||||
"""Print a newline or more.
|
||||
|
||||
:param count: number of newlines to print
|
||||
|
@ -881,7 +884,7 @@ class Escpos(object):
|
|||
if count > 0:
|
||||
self.text("\n" * count)
|
||||
|
||||
def block_text(self, txt, font="0", columns=None):
|
||||
def block_text(self, txt, font="0", columns=None) -> None:
|
||||
"""Print text wrapped to specific columns.
|
||||
|
||||
Text has to be encoded in unicode.
|
||||
|
@ -1132,7 +1135,7 @@ class Escpos(object):
|
|||
try:
|
||||
self._raw(CD_KICK_DEC_SEQUENCE(*pin))
|
||||
except TypeError as err:
|
||||
raise CashDrawerError(err)
|
||||
raise CashDrawerError(str(err))
|
||||
|
||||
def linedisplay_select(self, select_display: bool = False) -> None:
|
||||
"""Select the line display or the printer.
|
||||
|
@ -1265,10 +1268,10 @@ class Escpos(object):
|
|||
else:
|
||||
self._raw(PANEL_BUTTON_OFF)
|
||||
|
||||
def query_status(self, mode: bytes) -> List[int]:
|
||||
def query_status(self, mode: bytes) -> bytes:
|
||||
"""Query the printer for its status.
|
||||
|
||||
Returns an array of integers containing it.
|
||||
Returns byte array containing it.
|
||||
|
||||
:param mode: Integer that sets the status mode queried to the printer.
|
||||
- RT_STATUS_ONLINE: Printer status.
|
||||
|
@ -1288,7 +1291,7 @@ class Escpos(object):
|
|||
return False
|
||||
return not (status[0] & RT_MASK_ONLINE)
|
||||
|
||||
def paper_status(self):
|
||||
def paper_status(self) -> int: # could be IntEnum
|
||||
"""Query the paper status of the printer.
|
||||
|
||||
Returns 2 if there is plenty of paper, 1 if the paper has arrived to
|
||||
|
@ -1305,6 +1308,8 @@ class Escpos(object):
|
|||
return 1
|
||||
if status[0] & RT_MASK_PAPER == RT_MASK_PAPER:
|
||||
return 2
|
||||
# not reached
|
||||
return 0
|
||||
|
||||
def target(self, type: str = "ROLL") -> None:
|
||||
"""Select where to print to.
|
||||
|
@ -1359,7 +1364,7 @@ class Escpos(object):
|
|||
self._raw(BUZZER + six.int2byte(times) + six.int2byte(duration))
|
||||
|
||||
|
||||
class EscposIO(object):
|
||||
class EscposIO:
|
||||
r"""ESC/POS Printer IO object.
|
||||
|
||||
Allows the class to be used together with the `with`-statement. You have to define a printer instance
|
||||
|
@ -1405,12 +1410,12 @@ class EscposIO(object):
|
|||
"""
|
||||
self.params.update(kwargs)
|
||||
|
||||
def writelines(self, text, **kwargs):
|
||||
def writelines(self, text: str, **kwargs) -> None:
|
||||
"""Print text."""
|
||||
params = dict(self.params)
|
||||
params.update(kwargs)
|
||||
|
||||
if isinstance(text, six.text_type):
|
||||
if isinstance(text, str):
|
||||
lines = text.split("\n")
|
||||
elif isinstance(text, list) or isinstance(text, tuple):
|
||||
lines = text
|
||||
|
@ -1423,23 +1428,22 @@ class EscposIO(object):
|
|||
# TODO flush? or on print? (this should prob rather be handled by the _raw-method)
|
||||
for line in lines:
|
||||
self.printer.set(**params)
|
||||
if isinstance(text, six.text_type):
|
||||
self.printer.text(f"{line}\n")
|
||||
else:
|
||||
self.printer.text(f"{line}\n")
|
||||
self.printer.text(f"{line}\n")
|
||||
|
||||
def close(self):
|
||||
def close(self) -> None:
|
||||
"""Close printer.
|
||||
|
||||
Called upon closing the `with`-statement.
|
||||
"""
|
||||
self.printer.close()
|
||||
|
||||
def __enter__(self, **kwargs):
|
||||
def __enter__(self, **kwargs: Any) -> "EscposIO":
|
||||
"""Enter context."""
|
||||
return self
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
def __exit__(
|
||||
self, type: type[BaseException], value: BaseException, traceback: TracebackType
|
||||
) -> None:
|
||||
"""Cut and close if configured.
|
||||
|
||||
If :py:attr:`autocut <escpos.escpos.EscposIO.autocut>` is `True` (set by this class' constructor),
|
||||
|
|
|
@ -26,6 +26,8 @@ Result/Exit codes:
|
|||
:license: MIT
|
||||
"""
|
||||
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class Error(Exception):
|
||||
"""Base class for ESC/POS errors.
|
||||
|
@ -37,7 +39,7 @@ class Error(Exception):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self, msg, status=None):
|
||||
def __init__(self, msg: str, status: Optional[int] = None) -> None:
|
||||
"""Initialize Error object."""
|
||||
Exception.__init__(self)
|
||||
self.msg = msg
|
||||
|
@ -45,7 +47,7 @@ class Error(Exception):
|
|||
if status is not None:
|
||||
self.resultcode = status
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self) -> str:
|
||||
"""Return string representation of Error."""
|
||||
return self.msg
|
||||
|
||||
|
@ -64,13 +66,13 @@ class BarcodeTypeError(Error):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self, msg=""):
|
||||
def __init__(self, msg: str = "") -> None:
|
||||
"""Initialize BarcodeTypeError object."""
|
||||
Error.__init__(self, msg)
|
||||
self.msg = msg
|
||||
self.resultcode = 10
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self) -> str:
|
||||
"""Return string representation of BarcodeTypeError."""
|
||||
return f"No Barcode type is defined ({self.msg})"
|
||||
|
||||
|
@ -89,13 +91,13 @@ class BarcodeSizeError(Error):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self, msg=""):
|
||||
def __init__(self, msg: str = "") -> None:
|
||||
"""Initialize BarcodeSizeError object."""
|
||||
Error.__init__(self, msg)
|
||||
self.msg = msg
|
||||
self.resultcode = 20
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self) -> str:
|
||||
"""Return string representation of BarcodeSizeError."""
|
||||
return f"Barcode size is out of range ({self.msg})"
|
||||
|
||||
|
@ -114,13 +116,13 @@ class BarcodeCodeError(Error):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self, msg=""):
|
||||
def __init__(self, msg: str = "") -> None:
|
||||
"""Initialize BarcodeCodeError object."""
|
||||
Error.__init__(self, msg)
|
||||
self.msg = msg
|
||||
self.resultcode = 30
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self) -> str:
|
||||
"""Return string representation of BarcodeCodeError."""
|
||||
return f"No Barcode code was supplied ({self.msg})"
|
||||
|
||||
|
@ -137,13 +139,13 @@ class ImageSizeError(Error):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self, msg=""):
|
||||
def __init__(self, msg: str = "") -> None:
|
||||
"""Initialize ImageSizeError object."""
|
||||
Error.__init__(self, msg)
|
||||
self.msg = msg
|
||||
self.resultcode = 40
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self) -> str:
|
||||
"""Return string representation of ImageSizeError."""
|
||||
return f"Image height is longer than 255px and can't be printed ({self.msg})"
|
||||
|
||||
|
@ -160,13 +162,13 @@ class ImageWidthError(Error):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self, msg=""):
|
||||
def __init__(self, msg: str = "") -> None:
|
||||
"""Initialize ImageWidthError object."""
|
||||
Error.__init__(self, msg)
|
||||
self.msg = msg
|
||||
self.resultcode = 41
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self) -> str:
|
||||
"""Return string representation of ImageWidthError."""
|
||||
return f"Image width is too large ({self.msg})"
|
||||
|
||||
|
@ -184,13 +186,13 @@ class TextError(Error):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self, msg=""):
|
||||
def __init__(self, msg: str = "") -> None:
|
||||
"""Initialize TextError object."""
|
||||
Error.__init__(self, msg)
|
||||
self.msg = msg
|
||||
self.resultcode = 50
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self) -> str:
|
||||
"""Return string representation of TextError."""
|
||||
return f"Text string must be supplied to the text() method ({self.msg})"
|
||||
|
||||
|
@ -208,13 +210,13 @@ class CashDrawerError(Error):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self, msg=""):
|
||||
def __init__(self, msg: str = "") -> None:
|
||||
"""Initialize CashDrawerError object."""
|
||||
Error.__init__(self, msg)
|
||||
self.msg = msg
|
||||
self.resultcode = 60
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self) -> str:
|
||||
"""Return string representation of CashDrawerError."""
|
||||
return f"Valid pin must be set to send pulse ({self.msg})"
|
||||
|
||||
|
@ -235,13 +237,13 @@ class TabPosError(Error):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self, msg=""):
|
||||
def __init__(self, msg: str = "") -> None:
|
||||
"""Initialize TabPosError object."""
|
||||
Error.__init__(self, msg)
|
||||
self.msg = msg
|
||||
self.resultcode = 70
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self) -> str:
|
||||
"""Return string representation of TabPosError."""
|
||||
return f"Valid tab positions must be in the range 0 to 16 ({self.msg})"
|
||||
|
||||
|
@ -259,13 +261,13 @@ class CharCodeError(Error):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self, msg=""):
|
||||
def __init__(self, msg: str = "") -> None:
|
||||
"""Initialize CharCodeError object."""
|
||||
Error.__init__(self, msg)
|
||||
self.msg = msg
|
||||
self.resultcode = 80
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self) -> str:
|
||||
"""Return string representation of CharCodeError."""
|
||||
return f"Valid char code must be set ({self.msg})"
|
||||
|
||||
|
@ -283,13 +285,13 @@ class DeviceNotFoundError(Error):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self, msg=""):
|
||||
def __init__(self, msg: str = "") -> None:
|
||||
"""Initialize DeviceNotFoundError object."""
|
||||
Error.__init__(self, msg)
|
||||
self.msg = msg
|
||||
self.resultcode = 90
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self) -> str:
|
||||
"""Return string representation of DeviceNotFoundError."""
|
||||
return f"Device not found ({self.msg})"
|
||||
|
||||
|
@ -307,13 +309,13 @@ class USBNotFoundError(DeviceNotFoundError):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self, msg=""):
|
||||
def __init__(self, msg: str = "") -> None:
|
||||
"""Initialize USBNotFoundError object."""
|
||||
Error.__init__(self, msg)
|
||||
self.msg = msg
|
||||
self.resultcode = 91
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self) -> str:
|
||||
"""Return string representation of USBNotFoundError."""
|
||||
return f"USB device not found ({self.msg})"
|
||||
|
||||
|
@ -331,13 +333,13 @@ class SetVariableError(Error):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self, msg=""):
|
||||
def __init__(self, msg: str = "") -> None:
|
||||
"""Initialize SetVariableError object."""
|
||||
Error.__init__(self, msg)
|
||||
self.msg = msg
|
||||
self.resultcode = 100
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self) -> str:
|
||||
"""Return string representation of SetVariableError."""
|
||||
return f"Set variable out of range ({self.msg})"
|
||||
|
||||
|
@ -358,13 +360,13 @@ class ConfigNotFoundError(Error):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self, msg=""):
|
||||
def __init__(self, msg: str = "") -> None:
|
||||
"""Initialize ConfigNotFoundError object."""
|
||||
Error.__init__(self, msg)
|
||||
self.msg = msg
|
||||
self.resultcode = 200
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self) -> str:
|
||||
"""Return string representation of ConfigNotFoundError."""
|
||||
return f"Configuration not found ({self.msg})"
|
||||
|
||||
|
@ -382,13 +384,13 @@ class ConfigSyntaxError(Error):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self, msg=""):
|
||||
def __init__(self, msg: str = "") -> None:
|
||||
"""Initialize ConfigSyntaxError object."""
|
||||
Error.__init__(self, msg)
|
||||
self.msg = msg
|
||||
self.resultcode = 210
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self) -> str:
|
||||
"""Return string representation of ConfigSyntaxError."""
|
||||
return f"Configuration syntax is invalid ({self.msg})"
|
||||
|
||||
|
@ -406,12 +408,12 @@ class ConfigSectionMissingError(Error):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self, msg=""):
|
||||
def __init__(self, msg: str = "") -> None:
|
||||
"""Initialize ConfigSectionMissingError object."""
|
||||
Error.__init__(self, msg)
|
||||
self.msg = msg
|
||||
self.resultcode = 220
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self) -> str:
|
||||
"""Return string representation of ConfigSectionMissingError."""
|
||||
return f"Configuration section is missing ({self.msg})"
|
||||
|
|
|
@ -10,12 +10,12 @@ This module contains the image format handler :py:class:`EscposImage`.
|
|||
|
||||
|
||||
import math
|
||||
from typing import Union
|
||||
from typing import Iterator, Union
|
||||
|
||||
from PIL import Image, ImageOps
|
||||
|
||||
|
||||
class EscposImage(object):
|
||||
class EscposImage:
|
||||
"""
|
||||
Load images in, and output ESC/POS formats.
|
||||
|
||||
|
@ -23,7 +23,7 @@ class EscposImage(object):
|
|||
PIL, rather than spend CPU cycles looping over pixels.
|
||||
"""
|
||||
|
||||
def __init__(self, img_source: Union[Image.Image, str]):
|
||||
def __init__(self, img_source: Union[Image.Image, str]) -> None:
|
||||
"""Load in an image.
|
||||
|
||||
:param img_source: PIL.Image, or filename to load one from.
|
||||
|
@ -65,7 +65,7 @@ class EscposImage(object):
|
|||
_, height_pixels = self._im.size
|
||||
return height_pixels
|
||||
|
||||
def to_column_format(self, high_density_vertical: bool = True):
|
||||
def to_column_format(self, high_density_vertical: bool = True) -> Iterator[bytes]:
|
||||
"""Extract slices of an image as equal-sized blobs of column-format data.
|
||||
|
||||
:param high_density_vertical: Printed line height in dots
|
||||
|
@ -82,7 +82,7 @@ class EscposImage(object):
|
|||
yield (im_bytes)
|
||||
left += line_height
|
||||
|
||||
def to_raster_format(self):
|
||||
def to_raster_format(self) -> bytes:
|
||||
"""Convert image to raster-format binary."""
|
||||
return self._im.tobytes()
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ except ImportError:
|
|||
jaconv = None
|
||||
|
||||
|
||||
def encode_katakana(text):
|
||||
def encode_katakana(text: str) -> bytes:
|
||||
"""I don't think this quite works yet."""
|
||||
encoded = []
|
||||
for char in text:
|
||||
|
|
|
@ -23,7 +23,7 @@ from .constants import CODEPAGE_CHANGE
|
|||
from .exceptions import Error
|
||||
|
||||
|
||||
class Encoder(object):
|
||||
class Encoder:
|
||||
"""Take available code spaces and pick the right one for a given character.
|
||||
|
||||
Note: To determine the code page, it needs to do the conversion, and
|
||||
|
@ -202,7 +202,7 @@ def split_writable_text(encoder, text, encoding):
|
|||
return text, None
|
||||
|
||||
|
||||
class MagicEncode(object):
|
||||
class MagicEncode:
|
||||
"""Help switching to the right code page.
|
||||
|
||||
A helper that helps us to automatically switch to the right
|
||||
|
@ -292,7 +292,7 @@ class MagicEncode(object):
|
|||
|
||||
def write_with_encoding(self, encoding, text):
|
||||
"""Write the text and inject necessary codepage switches."""
|
||||
if text is not None and type(text) is not six.text_type:
|
||||
if text is not None and type(text) is not str:
|
||||
raise Error(
|
||||
f"The supplied text has to be unicode, but is of type {type(text)}."
|
||||
)
|
||||
|
|
|
@ -84,7 +84,7 @@ class CupsPrinter(Escpos):
|
|||
return is_usable()
|
||||
|
||||
@dependency_pycups
|
||||
def __init__(self, printer_name: str = "", *args, **kwargs):
|
||||
def __init__(self, printer_name: str = "", *args, **kwargs) -> None:
|
||||
"""Class constructor for CupsPrinter.
|
||||
|
||||
:param printer_name: CUPS printer name (Optional)
|
||||
|
@ -163,11 +163,10 @@ class CupsPrinter(Escpos):
|
|||
return
|
||||
logging.info("CupsPrinter printer enabled")
|
||||
|
||||
def _raw(self, msg):
|
||||
def _raw(self, msg: bytes) -> None:
|
||||
"""Append any command sent in raw format to temporary file.
|
||||
|
||||
:param msg: arbitrary code to be printed
|
||||
:type msg: bytes
|
||||
"""
|
||||
self.pending_job = True
|
||||
try:
|
||||
|
@ -176,8 +175,9 @@ class CupsPrinter(Escpos):
|
|||
self.pending_job = False
|
||||
raise TypeError("Bytes required. Printer job not opened")
|
||||
|
||||
def send(self):
|
||||
def send(self) -> None:
|
||||
"""Send the print job to the printer."""
|
||||
assert self.device
|
||||
if self.pending_job:
|
||||
# Rewind tempfile
|
||||
self.tmpfile.seek(0)
|
||||
|
@ -190,7 +190,7 @@ class CupsPrinter(Escpos):
|
|||
)
|
||||
self._clear()
|
||||
|
||||
def _clear(self):
|
||||
def _clear(self) -> None:
|
||||
"""Finish the print job.
|
||||
|
||||
Remove temporary file.
|
||||
|
@ -198,18 +198,18 @@ class CupsPrinter(Escpos):
|
|||
self.tmpfile.close()
|
||||
self.pending_job = False
|
||||
|
||||
def _read(self):
|
||||
def _read(self) -> bytes:
|
||||
"""Return a single-item array with the accepting state of the print queue.
|
||||
|
||||
states: idle = [3], printing a job = [4], stopped = [5]
|
||||
"""
|
||||
printer = self.printers.get(self.printer_name, {})
|
||||
state = printer.get("printer-state")
|
||||
if not state:
|
||||
return []
|
||||
return [state]
|
||||
if not state or state in [4, 5]:
|
||||
return b"8" # offline
|
||||
return b"0" # online
|
||||
|
||||
def close(self):
|
||||
def close(self) -> None:
|
||||
"""Close CUPS connection.
|
||||
|
||||
Send pending job to the printer if needed.
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
:copyright: Copyright (c) 2012-2023 Bashlinux and python-escpos
|
||||
:license: MIT
|
||||
"""
|
||||
from typing import List
|
||||
|
||||
from ..escpos import Escpos
|
||||
|
||||
|
@ -39,25 +40,24 @@ class Dummy(Escpos):
|
|||
"""
|
||||
return is_usable()
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
def __init__(self, *args, **kwargs) -> None:
|
||||
"""Init with empty output list."""
|
||||
Escpos.__init__(self, *args, **kwargs)
|
||||
self._output_list = []
|
||||
self._output_list: List[bytes] = []
|
||||
|
||||
def _raw(self, msg):
|
||||
def _raw(self, msg: bytes) -> None:
|
||||
"""Print any command sent in raw format.
|
||||
|
||||
:param msg: arbitrary code to be printed
|
||||
:type msg: bytes
|
||||
"""
|
||||
self._output_list.append(msg)
|
||||
|
||||
@property
|
||||
def output(self):
|
||||
def output(self) -> bytes:
|
||||
"""Get the data that was sent to this printer."""
|
||||
return b"".join(self._output_list)
|
||||
|
||||
def clear(self):
|
||||
def clear(self) -> None:
|
||||
"""Clear the buffer of the printer.
|
||||
|
||||
This method can be called if you send the contents to a physical printer
|
||||
|
@ -65,6 +65,6 @@ class Dummy(Escpos):
|
|||
"""
|
||||
del self._output_list[:]
|
||||
|
||||
def close(self):
|
||||
def close(self) -> None:
|
||||
"""Close not implemented for Dummy printer."""
|
||||
pass
|
||||
|
|
|
@ -88,12 +88,12 @@ class File(Escpos):
|
|||
if self.device:
|
||||
self.device.flush()
|
||||
|
||||
def _raw(self, msg):
|
||||
def _raw(self, msg: bytes) -> None:
|
||||
"""Print any command sent in raw format.
|
||||
|
||||
:param msg: arbitrary code to be printed
|
||||
:type msg: bytes
|
||||
"""
|
||||
assert self.device
|
||||
self.device.write(msg)
|
||||
if self.auto_flush:
|
||||
self.flush()
|
||||
|
|
|
@ -182,12 +182,13 @@ class LP(Escpos):
|
|||
if not self._is_closing:
|
||||
self.open(_close_opened=False)
|
||||
|
||||
def _raw(self, msg):
|
||||
def _raw(self, msg: bytes) -> None:
|
||||
"""Write raw command(s) to the printer.
|
||||
|
||||
:param msg: arbitrary code to be printed
|
||||
:type msg: bytes
|
||||
"""
|
||||
assert self.device is not None
|
||||
assert self.device.stdin is not None
|
||||
if self.device.stdin.writable():
|
||||
self.device.stdin.write(msg)
|
||||
else:
|
||||
|
|
|
@ -110,16 +110,17 @@ class Network(Escpos):
|
|||
return
|
||||
logging.info("Network printer enabled")
|
||||
|
||||
def _raw(self, msg):
|
||||
def _raw(self, msg: bytes) -> None:
|
||||
"""Print any command sent in raw format.
|
||||
|
||||
:param msg: arbitrary code to be printed
|
||||
:type msg: bytes
|
||||
"""
|
||||
assert self.device
|
||||
self.device.sendall(msg)
|
||||
|
||||
def _read(self):
|
||||
def _read(self) -> bytes:
|
||||
"""Read data from the TCP socket."""
|
||||
assert self.device
|
||||
return self.device.recv(16)
|
||||
|
||||
def close(self) -> None:
|
||||
|
|
|
@ -155,16 +155,17 @@ class Serial(Escpos):
|
|||
return
|
||||
logging.info("Serial printer enabled")
|
||||
|
||||
def _raw(self, msg):
|
||||
def _raw(self, msg: bytes) -> None:
|
||||
"""Print any command sent in raw format.
|
||||
|
||||
:param msg: arbitrary code to be printed
|
||||
:type msg: bytes
|
||||
"""
|
||||
assert self.device
|
||||
self.device.write(msg)
|
||||
|
||||
def _read(self):
|
||||
def _read(self) -> bytes:
|
||||
"""Read the data buffer and return it to the caller."""
|
||||
assert self.device
|
||||
return self.device.read(16)
|
||||
|
||||
def close(self) -> None:
|
||||
|
|
|
@ -74,9 +74,9 @@ class Usb(Escpos):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
idVendor: str = "",
|
||||
idProduct: str = "",
|
||||
usb_args: Dict[str, str] = {},
|
||||
idVendor: Optional[int] = None,
|
||||
idProduct: Optional[int] = None,
|
||||
usb_args: Dict[str, Union[str, int]] = {},
|
||||
timeout: Union[int, float] = 0,
|
||||
in_ep: int = 0x82,
|
||||
out_ep: int = 0x01,
|
||||
|
@ -181,16 +181,17 @@ class Usb(Escpos):
|
|||
except usb.core.USBError as e:
|
||||
logging.error("Could not set configuration: %s", str(e))
|
||||
|
||||
def _raw(self, msg):
|
||||
def _raw(self, msg: bytes) -> None:
|
||||
"""Print any command sent in raw format.
|
||||
|
||||
:param msg: arbitrary code to be printed
|
||||
:type msg: bytes
|
||||
"""
|
||||
assert self.device
|
||||
self.device.write(self.out_ep, msg, self.timeout)
|
||||
|
||||
def _read(self):
|
||||
def _read(self) -> bytes:
|
||||
"""Read a data buffer and return it to the caller."""
|
||||
assert self.device
|
||||
return self.device.read(self.in_ep, 16)
|
||||
|
||||
@dependency_usb
|
||||
|
|
|
@ -76,7 +76,7 @@ class Win32Raw(Escpos):
|
|||
return is_usable()
|
||||
|
||||
@dependency_win32print
|
||||
def __init__(self, printer_name: str = "", *args, **kwargs):
|
||||
def __init__(self, printer_name: str = "", *args, **kwargs) -> None:
|
||||
"""Initialize default printer."""
|
||||
Escpos.__init__(self, *args, **kwargs)
|
||||
self.printer_name = printer_name
|
||||
|
@ -148,14 +148,17 @@ class Win32Raw(Escpos):
|
|||
win32print.ClosePrinter(self._device)
|
||||
self._device = False
|
||||
|
||||
def _raw(self, msg) -> None:
|
||||
def _raw(self, msg: bytes) -> None:
|
||||
"""Print any command sent in raw format.
|
||||
|
||||
:param msg: arbitrary code to be printed
|
||||
:type msg: bytes
|
||||
"""
|
||||
if self.printer_name is None:
|
||||
raise DeviceNotFoundError("Printer not found")
|
||||
if not self.device:
|
||||
raise DeviceNotFoundError("Printer job not opened")
|
||||
win32print.WritePrinter(self.device, msg)
|
||||
win32print.WritePrinter(self.device, msg) # type: ignore
|
||||
|
||||
# there is a bug in the typeshed
|
||||
# https://github.com/mhammond/pywin32/blob/main/win32/src/win32print/win32print.cpp#L976
|
||||
# https://github.com/python/typeshed/blob/main/stubs/pywin32/win32/win32print.pyi#L27C4-L27C4
|
||||
|
|
|
@ -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")),
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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.
|
||||
"""
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue