Drop Py37, improve typing and docstrings (#544)
Drops Py3.7, improves typing and adds a mypy config, improves the docstrings and isorts the imports. * configure isort * sort with isort * add github action * enable flake8-docstrings * fix docstrings * add mypy env * no implicit optional * add type for raw * add some type hints
This commit is contained in:
parent
2b62c8e28d
commit
fbabd8ed88
|
@ -30,6 +30,11 @@ jobs:
|
||||||
python -m pip install --upgrade pip
|
python -m pip install --upgrade pip
|
||||||
pip install flake8 pytest tox tox-gh-actions
|
pip install flake8 pytest tox tox-gh-actions
|
||||||
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
|
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
|
||||||
|
- name: Check sorting of imports
|
||||||
|
uses: isort/isort-action@master
|
||||||
|
with:
|
||||||
|
requirementsFiles: "requirements.txt doc/requirements.txt"
|
||||||
|
sortPaths: "./doc ./src ./examples ./test ./setup.py"
|
||||||
- name: Lint with flake8
|
- name: Lint with flake8
|
||||||
run: |
|
run: |
|
||||||
# stop the build if there are Python syntax errors or undefined names
|
# stop the build if there are Python syntax errors or undefined names
|
||||||
|
|
|
@ -12,9 +12,8 @@
|
||||||
# All configuration values have a default; values that are commented out
|
# All configuration values have a default; values that are commented out
|
||||||
# serve to show the default.
|
# serve to show the default.
|
||||||
|
|
||||||
import sys
|
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
from importlib.metadata import version as imp_version
|
from importlib.metadata import version as imp_version
|
||||||
|
|
||||||
on_rtd = os.getenv("READTHEDOCS") == "True"
|
on_rtd = os.getenv("READTHEDOCS") == "True"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
"""Example for printing barcodes."""
|
||||||
from escpos.printer import Usb
|
from escpos.printer import Usb
|
||||||
|
|
||||||
|
|
||||||
# Adapt to your needs
|
# Adapt to your needs
|
||||||
p = Usb(0x0416, 0x5011, profile="TM-T88II")
|
p = Usb(0x0416, 0x5011, profile="TM-T88II")
|
||||||
|
|
||||||
|
|
|
@ -1,23 +1,24 @@
|
||||||
"""Prints code page tables.
|
"""Prints code page tables."""
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
import six
|
import six
|
||||||
import sys
|
|
||||||
|
|
||||||
from escpos import printer
|
from escpos import printer
|
||||||
from escpos.constants import (
|
from escpos.constants import (
|
||||||
CODEPAGE_CHANGE,
|
CODEPAGE_CHANGE,
|
||||||
ESC,
|
|
||||||
CTL_LF,
|
|
||||||
CTL_FF,
|
|
||||||
CTL_CR,
|
CTL_CR,
|
||||||
|
CTL_FF,
|
||||||
CTL_HT,
|
CTL_HT,
|
||||||
|
CTL_LF,
|
||||||
CTL_VT,
|
CTL_VT,
|
||||||
|
ESC,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
"""Init printer and print codepage tables."""
|
||||||
dummy = printer.Dummy()
|
dummy = printer.Dummy()
|
||||||
|
|
||||||
dummy.hw("init")
|
dummy.hw("init")
|
||||||
|
@ -34,6 +35,7 @@ def main():
|
||||||
|
|
||||||
|
|
||||||
def print_codepage(printer, codepage):
|
def print_codepage(printer, codepage):
|
||||||
|
"""Print a codepage."""
|
||||||
if codepage.isdigit():
|
if codepage.isdigit():
|
||||||
codepage = int(codepage)
|
codepage = int(codepage)
|
||||||
printer._raw(CODEPAGE_CHANGE + six.int2byte(codepage))
|
printer._raw(CODEPAGE_CHANGE + six.int2byte(codepage))
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
from escpos.printer import CupsPrinter
|
"""Example for a flask application."""
|
||||||
from flask import Flask
|
from flask import Flask
|
||||||
|
|
||||||
|
from escpos.printer import CupsPrinter
|
||||||
|
|
||||||
# Initialize Flask app
|
# Initialize Flask app
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
|
||||||
@app.route("/", methods=["GET"])
|
@app.route("/", methods=["GET"])
|
||||||
def do_print():
|
def do_print():
|
||||||
|
"""Print."""
|
||||||
# p = Usb(0x04b8, 0x0e28, 0)
|
# p = Usb(0x04b8, 0x0e28, 0)
|
||||||
p = CupsPrinter(host="localhost", port=631, printer_name="TM-T20III")
|
p = CupsPrinter(host="localhost", port=631, printer_name="TM-T20III")
|
||||||
p.text("Hello World\n")
|
p.text("Hello World\n")
|
||||||
|
|
|
@ -3,7 +3,6 @@ argcomplete==3.0.8
|
||||||
blinker==1.6.2
|
blinker==1.6.2
|
||||||
click==8.1.3
|
click==8.1.3
|
||||||
Flask==2.3.2
|
Flask==2.3.2
|
||||||
future==0.18.3
|
|
||||||
itsdangerous==2.1.2
|
itsdangerous==2.1.2
|
||||||
Jinja2==3.1.2
|
Jinja2==3.1.2
|
||||||
MarkupSafe==2.1.2
|
MarkupSafe==2.1.2
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
|
"""Print example QR codes."""
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from escpos.printer import Usb
|
from escpos.printer import Usb
|
||||||
|
|
||||||
|
|
||||||
def usage():
|
def usage():
|
||||||
|
"""Print information on usage."""
|
||||||
print("usage: qr_code.py <content>")
|
print("usage: qr_code.py <content>")
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
"""Example file for software barcodes."""
|
||||||
from escpos.printer import Usb
|
from escpos.printer import Usb
|
||||||
|
|
||||||
|
|
||||||
# Adapt to your needs
|
# Adapt to your needs
|
||||||
p = Usb(0x0416, 0x5011, profile="POS-5890")
|
p = Usb(0x0416, 0x5011, profile="POS-5890")
|
||||||
|
|
||||||
|
|
|
@ -1,28 +1,29 @@
|
||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
|
"""Weather forecast example.
|
||||||
|
|
||||||
|
Adapted script from Adafruit
|
||||||
|
Weather forecast for Raspberry Pi w/Adafruit Mini Thermal Printer.
|
||||||
|
Retrieves data from DarkSky.net's API, prints current conditions and
|
||||||
|
forecasts for next two days.
|
||||||
|
Weather example using nice bitmaps.
|
||||||
|
Written by Adafruit Industries. MIT license.
|
||||||
|
Adapted and enhanced for escpos library by MrWunderbar666
|
||||||
|
|
||||||
|
Icons taken from https://adamwhitcroft.com/climacons/
|
||||||
|
Check out his github: https://github.com/AdamWhitcroft/climacons
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
# Adapted script from Adafruit
|
|
||||||
# Weather forecast for Raspberry Pi w/Adafruit Mini Thermal Printer.
|
|
||||||
# Retrieves data from DarkSky.net's API, prints current conditions and
|
|
||||||
# forecasts for next two days.
|
|
||||||
# Weather example using nice bitmaps.
|
|
||||||
# Written by Adafruit Industries. MIT license.
|
|
||||||
# Adapted and enhanced for escpos library by MrWunderbar666
|
|
||||||
|
|
||||||
# Icons taken from https://adamwhitcroft.com/climacons/
|
|
||||||
# Check out his github: https://github.com/AdamWhitcroft/climacons
|
|
||||||
|
|
||||||
|
|
||||||
from datetime import datetime
|
|
||||||
import calendar
|
import calendar
|
||||||
import urllib
|
|
||||||
import json
|
import json
|
||||||
import time
|
|
||||||
import os
|
import os
|
||||||
|
import time
|
||||||
|
import urllib
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
from escpos.printer import Usb
|
from escpos.printer import Usb
|
||||||
|
|
||||||
""" Setting up the main pathing """
|
"""Set up the main pathing."""
|
||||||
this_dir, this_filename = os.path.split(__file__)
|
this_dir, this_filename = os.path.split(__file__)
|
||||||
GRAPHICS_PATH = os.path.join(this_dir, "graphics/climacons/")
|
GRAPHICS_PATH = os.path.join(this_dir, "graphics/climacons/")
|
||||||
|
|
||||||
|
@ -38,13 +39,14 @@ LONG = "114.189945" # Your Location
|
||||||
|
|
||||||
|
|
||||||
def forecast_icon(idx):
|
def forecast_icon(idx):
|
||||||
|
"""Get right icon for forecast."""
|
||||||
icon = data["daily"]["data"][idx]["icon"]
|
icon = data["daily"]["data"][idx]["icon"]
|
||||||
image = GRAPHICS_PATH + icon + ".png"
|
image = GRAPHICS_PATH + icon + ".png"
|
||||||
return image
|
return image
|
||||||
|
|
||||||
|
|
||||||
# Dumps one forecast line to the printer
|
|
||||||
def forecast(idx):
|
def forecast(idx):
|
||||||
|
"""Dump one forecast line to the printer."""
|
||||||
date = datetime.fromtimestamp(int(data["daily"]["data"][idx]["time"]))
|
date = datetime.fromtimestamp(int(data["daily"]["data"][idx]["time"]))
|
||||||
day = calendar.day_name[date.weekday()]
|
day = calendar.day_name[date.weekday()]
|
||||||
lo = data["daily"]["data"][idx]["temperatureMin"]
|
lo = data["daily"]["data"][idx]["temperatureMin"]
|
||||||
|
@ -73,6 +75,7 @@ def forecast(idx):
|
||||||
|
|
||||||
|
|
||||||
def icon():
|
def icon():
|
||||||
|
"""Get icon."""
|
||||||
icon = data["currently"]["icon"]
|
icon = data["currently"]["icon"]
|
||||||
image = GRAPHICS_PATH + icon + ".png"
|
image = GRAPHICS_PATH + icon + ".png"
|
||||||
return image
|
return image
|
||||||
|
|
|
@ -1,3 +1,15 @@
|
||||||
[tool.black]
|
[tool.black]
|
||||||
extend-exclude = 'capabilities-data'
|
extend-exclude = 'capabilities-data'
|
||||||
|
|
||||||
|
[tool.isort]
|
||||||
|
profile = "black"
|
||||||
|
|
||||||
|
[tool.pytest.ini_options]
|
||||||
|
minversion = "6.0"
|
||||||
|
addopts = "--doctest-modules --cov escpos --cov-report=xml"
|
||||||
|
testpaths = [
|
||||||
|
"test",
|
||||||
|
"src",
|
||||||
|
"src/escpos",
|
||||||
|
"escpos",
|
||||||
|
]
|
||||||
|
|
|
@ -31,7 +31,7 @@ project_urls =
|
||||||
Release Notes = https://github.com/python-escpos/python-escpos/releases
|
Release Notes = https://github.com/python-escpos/python-escpos/releases
|
||||||
|
|
||||||
[options]
|
[options]
|
||||||
python_requires = >=3.6
|
python_requires = >=3.8
|
||||||
zip_safe = false
|
zip_safe = false
|
||||||
include_package_data = true
|
include_package_data = true
|
||||||
install_requires =
|
install_requires =
|
||||||
|
@ -46,7 +46,6 @@ install_requires =
|
||||||
PyYAML
|
PyYAML
|
||||||
argparse
|
argparse
|
||||||
argcomplete
|
argcomplete
|
||||||
future
|
|
||||||
importlib_resources
|
importlib_resources
|
||||||
setup_requires = setuptools_scm
|
setup_requires = setuptools_scm
|
||||||
tests_require =
|
tests_require =
|
||||||
|
@ -65,4 +64,3 @@ tests_require =
|
||||||
exclude = .git,.tox,.github,.eggs,__pycache__,doc/conf.py,build,dist,capabilities-data,test,src/escpos/constants.py
|
exclude = .git,.tox,.github,.eggs,__pycache__,doc/conf.py,build,dist,capabilities-data,test,src/escpos/constants.py
|
||||||
max-line-length = 120
|
max-line-length = 120
|
||||||
extend-ignore = E203, W503
|
extend-ignore = E203, W503
|
||||||
# future-imports = absolute_import, division, print_function, unicode_literals # we are not there yet
|
|
||||||
|
|
15
setup.py
15
setup.py
|
@ -1,9 +1,10 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
"""Setup script for python package."""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from setuptools import find_packages, setup
|
|
||||||
|
|
||||||
|
from setuptools import find_packages, setup
|
||||||
|
|
||||||
base_dir = os.path.dirname(__file__)
|
base_dir = os.path.dirname(__file__)
|
||||||
src_dir = os.path.join(base_dir, "src")
|
src_dir = os.path.join(base_dir, "src")
|
||||||
|
@ -14,14 +15,18 @@ sys.path.insert(0, src_dir)
|
||||||
|
|
||||||
|
|
||||||
def read(fname):
|
def read(fname):
|
||||||
"""read file from same path as setup.py"""
|
"""Read file from same path as setup.py."""
|
||||||
return open(os.path.join(os.path.dirname(__file__), fname)).read()
|
return open(os.path.join(os.path.dirname(__file__), fname)).read()
|
||||||
|
|
||||||
|
|
||||||
setuptools_scm_template = """\
|
setuptools_scm_template = """\
|
||||||
# coding: utf-8
|
#!/usr/bin/python
|
||||||
# file generated by setuptools_scm
|
# -*- coding: utf-8 -*-
|
||||||
# don't change, don't track in version control
|
\"\"\"Version identifier.
|
||||||
|
|
||||||
|
file generated by setuptools_scm
|
||||||
|
don't change, don't track in version control
|
||||||
|
\"\"\"
|
||||||
|
|
||||||
version = '{version}'
|
version = '{version}'
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""python-escpos enables you to manipulate escpos-printers."""
|
||||||
python-escpos enables you to manipulate escpos-printers
|
|
||||||
"""
|
|
||||||
|
|
||||||
__all__ = ["constants", "escpos", "exceptions", "printer"]
|
__all__ = ["constants", "escpos", "exceptions", "printer"]
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,19 @@
|
||||||
import re
|
"""Handler for capabilities data."""
|
||||||
from os import environ, path
|
|
||||||
import atexit
|
import atexit
|
||||||
import pickle
|
|
||||||
import logging
|
import logging
|
||||||
|
import pickle
|
||||||
|
import platform
|
||||||
|
import re
|
||||||
import time
|
import time
|
||||||
import importlib_resources
|
from contextlib import ExitStack
|
||||||
|
from os import environ, path
|
||||||
|
from tempfile import mkdtemp
|
||||||
|
from typing import Any, Dict, Optional
|
||||||
|
|
||||||
|
import importlib_resources
|
||||||
import six
|
import six
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
from contextlib import ExitStack
|
|
||||||
from tempfile import mkdtemp
|
|
||||||
import platform
|
|
||||||
|
|
||||||
from typing import Any, Dict
|
|
||||||
|
|
||||||
logging.basicConfig()
|
logging.basicConfig()
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -60,9 +59,7 @@ PROFILES: Dict[str, Any] = CAPABILITIES["profiles"]
|
||||||
|
|
||||||
|
|
||||||
class NotSupported(Exception):
|
class NotSupported(Exception):
|
||||||
"""Raised if a requested feature is not supported by the
|
"""Raised if a requested feature is not supported by the printer profile."""
|
||||||
printer profile.
|
|
||||||
"""
|
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -80,11 +77,13 @@ class BaseProfile(object):
|
||||||
profile_data: Dict[str, Any] = {}
|
profile_data: Dict[str, Any] = {}
|
||||||
|
|
||||||
def __getattr__(self, name):
|
def __getattr__(self, name):
|
||||||
|
"""Get a data element from the profile."""
|
||||||
return self.profile_data[name]
|
return self.profile_data[name]
|
||||||
|
|
||||||
def get_font(self, font) -> int:
|
def get_font(self, font) -> int:
|
||||||
"""Return the escpos index for `font`. Makes sure that
|
"""Return the escpos index for `font`.
|
||||||
the requested `font` is valid.
|
|
||||||
|
Makes sure that the requested `font` is valid.
|
||||||
"""
|
"""
|
||||||
font = {"a": 0, "b": 1}.get(font, font)
|
font = {"a": 0, "b": 1}.get(font, font)
|
||||||
if not six.text_type(font) in self.fonts:
|
if not six.text_type(font) in self.fonts:
|
||||||
|
@ -107,9 +106,10 @@ class BaseProfile(object):
|
||||||
return {v: k for k, v in self.codePages.items()}
|
return {v: k for k, v in self.codePages.items()}
|
||||||
|
|
||||||
|
|
||||||
def get_profile(name: str = None, **kwargs):
|
def get_profile(name: Optional[str] = None, **kwargs):
|
||||||
"""Get the profile by name; if no name is given, return the
|
"""Get a profile by name.
|
||||||
default profile.
|
|
||||||
|
If no name is given, return the default profile.
|
||||||
"""
|
"""
|
||||||
if isinstance(name, Profile):
|
if isinstance(name, Profile):
|
||||||
return name
|
return name
|
||||||
|
@ -122,7 +122,9 @@ CLASS_CACHE = {}
|
||||||
|
|
||||||
|
|
||||||
def get_profile_class(name: str):
|
def get_profile_class(name: str):
|
||||||
"""For the given profile name, load the data from the external
|
"""Load a profile class.
|
||||||
|
|
||||||
|
For the given profile name, load the data from the external
|
||||||
database, then generate dynamically a class.
|
database, then generate dynamically a class.
|
||||||
"""
|
"""
|
||||||
if name not in CLASS_CACHE:
|
if name not in CLASS_CACHE:
|
||||||
|
@ -136,6 +138,7 @@ def get_profile_class(name: str):
|
||||||
|
|
||||||
|
|
||||||
def clean(s):
|
def clean(s):
|
||||||
|
"""Clean profile name."""
|
||||||
# Remove invalid characters
|
# Remove invalid characters
|
||||||
s = re.sub("[^0-9a-zA-Z_]", "", s)
|
s = re.sub("[^0-9a-zA-Z_]", "", s)
|
||||||
# Remove leading characters until we find a letter or underscore
|
# Remove leading characters until we find a letter or underscore
|
||||||
|
@ -144,17 +147,20 @@ def clean(s):
|
||||||
|
|
||||||
|
|
||||||
class Profile(get_profile_class("default")):
|
class Profile(get_profile_class("default")):
|
||||||
"""
|
"""Profile class for user usage.
|
||||||
For users, who want to provide their profile
|
|
||||||
|
For users, who want to provide their own profile.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, columns=None, features=None):
|
def __init__(self, columns=None, features=None):
|
||||||
|
"""Initialize profile."""
|
||||||
super(Profile, self).__init__()
|
super(Profile, self).__init__()
|
||||||
|
|
||||||
self.columns = columns
|
self.columns = columns
|
||||||
self.features = features or {}
|
self.features = features or {}
|
||||||
|
|
||||||
def get_columns(self, font):
|
def get_columns(self, font):
|
||||||
|
"""Get column count of printer."""
|
||||||
if self.columns is not None:
|
if self.columns is not None:
|
||||||
return self.columns
|
return self.columns
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# PYTHON_ARGCOMPLETE_OK
|
# PYTHON_ARGCOMPLETE_OK
|
||||||
""" CLI
|
"""CLI.
|
||||||
|
|
||||||
This module acts as a command line interface for python-escpos. It mirrors
|
This module acts as a command line interface for python-escpos. It mirrors
|
||||||
closely the available ESCPOS commands while adding a couple extra ones for convenience.
|
closely the available ESCPOS commands while adding a couple extra ones for convenience.
|
||||||
|
@ -18,15 +18,18 @@ except ImportError:
|
||||||
# this CLI works nevertheless without argcomplete
|
# this CLI works nevertheless without argcomplete
|
||||||
pass # noqa
|
pass # noqa
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import six
|
import six
|
||||||
from . import config
|
|
||||||
from . import version
|
from . import config, version
|
||||||
|
|
||||||
|
|
||||||
# Must be defined before it's used in DEMO_FUNCTIONS
|
# Must be defined before it's used in DEMO_FUNCTIONS
|
||||||
def str_to_bool(string):
|
def str_to_bool(string):
|
||||||
"""Used as a type in argparse so that we get back a proper
|
"""Convert string to Bool.
|
||||||
bool instead of always True
|
|
||||||
|
Used as a type in argparse so that we get back a proper
|
||||||
|
bool instead of always True.
|
||||||
"""
|
"""
|
||||||
return string.lower() in ("y", "yes", "1", "true")
|
return string.lower() in ("y", "yes", "1", "true")
|
||||||
|
|
||||||
|
@ -452,13 +455,11 @@ ESCPOS_COMMANDS = [
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
"""
|
"""Handle main entry point of CLI script.
|
||||||
|
|
||||||
Handles loading of configuration and creating and processing of command
|
Handles loading of configuration and creating and processing of command
|
||||||
line arguments. Called when run from a CLI.
|
line arguments. Called when run from a CLI.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
description="CLI for python-escpos",
|
description="CLI for python-escpos",
|
||||||
epilog="Printer configuration is defined in the python-escpos config"
|
epilog="Printer configuration is defined in the python-escpos config"
|
||||||
|
@ -569,8 +570,9 @@ def main():
|
||||||
|
|
||||||
|
|
||||||
def demo(printer, **kwargs):
|
def demo(printer, **kwargs):
|
||||||
"""
|
"""Print demos.
|
||||||
Prints demos. Called when CLI is passed `demo`. This function
|
|
||||||
|
Called when CLI is passed `demo`. This function
|
||||||
uses the DEMO_FUNCTIONS dictionary.
|
uses the DEMO_FUNCTIONS dictionary.
|
||||||
|
|
||||||
:param printer: A printer from escpos.printer
|
:param printer: A printer from escpos.printer
|
||||||
|
|
|
@ -1,23 +1,31 @@
|
||||||
|
"""Helper module for codepage handling."""
|
||||||
from .capabilities import CAPABILITIES
|
from .capabilities import CAPABILITIES
|
||||||
|
|
||||||
|
|
||||||
class CodePageManager:
|
class CodePageManager:
|
||||||
"""Holds information about all the code pages (as defined
|
"""Holds information about all the code pages.
|
||||||
in escpos-printer-db).
|
|
||||||
|
Information as defined in escpos-printer-db.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, data):
|
def __init__(self, data):
|
||||||
|
"""Initialize codepage manager."""
|
||||||
self.data = data
|
self.data = data
|
||||||
|
|
||||||
def get_all(self):
|
def get_all(self):
|
||||||
|
"""Get list of all codepages."""
|
||||||
return self.data.values()
|
return self.data.values()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_encoding_name(encoding):
|
def get_encoding_name(encoding):
|
||||||
# TODO resolve the encoding alias
|
"""Get encoding name.
|
||||||
|
|
||||||
|
.. todo:: Resolve the encoding alias.
|
||||||
|
"""
|
||||||
return encoding.upper()
|
return encoding.upper()
|
||||||
|
|
||||||
def get_encoding(self, encoding):
|
def get_encoding(self, encoding):
|
||||||
|
"""Return the encoding data."""
|
||||||
return self.data[encoding]
|
return self.data[encoding]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,13 @@
|
||||||
"""ESC/POS configuration manager.
|
"""ESC/POS configuration manager.
|
||||||
|
|
||||||
This module contains the implementations of abstract base class :py:class:`Config`.
|
This module contains the implementations of abstract base class :py:class:`Config`.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
import appdirs
|
import appdirs
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
from . import printer
|
from . import exceptions, printer
|
||||||
from . import exceptions
|
|
||||||
|
|
||||||
|
|
||||||
class Config(object):
|
class Config(object):
|
||||||
|
@ -48,13 +45,11 @@ class Config(object):
|
||||||
self._printer_config = None
|
self._printer_config = None
|
||||||
|
|
||||||
def load(self, config_path=None):
|
def load(self, config_path=None):
|
||||||
"""Load and parse the configuration file using pyyaml
|
"""Load and parse the configuration file using pyyaml.
|
||||||
|
|
||||||
:param config_path: An optional file path, file handle, or byte string
|
:param config_path: An optional file path, file handle, or byte string
|
||||||
for the configuration file.
|
for the configuration file.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self._reset_config()
|
self._reset_config()
|
||||||
|
|
||||||
if not config_path:
|
if not config_path:
|
||||||
|
@ -96,8 +91,9 @@ class Config(object):
|
||||||
self._has_loaded = True
|
self._has_loaded = True
|
||||||
|
|
||||||
def printer(self):
|
def printer(self):
|
||||||
"""Returns a printer that was defined in the config, or throws an
|
"""Return a printer that was defined in the config.
|
||||||
exception.
|
|
||||||
|
Throw an exception on error.
|
||||||
|
|
||||||
This method loads the default config if one hasn't beeen already loaded.
|
This method loads the default config if one hasn't beeen already loaded.
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
""" Main class
|
"""Main class.
|
||||||
|
|
||||||
This module contains the abstract base class :py:class:`Escpos`.
|
This module contains the abstract base class :py:class:`Escpos`.
|
||||||
|
|
||||||
|
@ -11,80 +11,88 @@ This module contains the abstract base class :py:class:`Escpos`.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
import qrcode
|
|
||||||
import textwrap
|
import textwrap
|
||||||
import six
|
from abc import ABCMeta, abstractmethod # abstract base class support
|
||||||
from re import match as re_match
|
from re import match as re_match
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
import barcode
|
import barcode
|
||||||
|
import qrcode
|
||||||
|
import six
|
||||||
from barcode.writer import ImageWriter
|
from barcode.writer import ImageWriter
|
||||||
|
|
||||||
|
from escpos.capabilities import get_profile
|
||||||
|
from escpos.image import EscposImage
|
||||||
|
|
||||||
from .constants import (
|
from .constants import (
|
||||||
ESC,
|
BARCODE_FONT_A,
|
||||||
GS,
|
BARCODE_FONT_B,
|
||||||
NUL,
|
BARCODE_FORMATS,
|
||||||
QR_ECLEVEL_L,
|
|
||||||
QR_ECLEVEL_M,
|
|
||||||
QR_ECLEVEL_H,
|
|
||||||
QR_ECLEVEL_Q,
|
|
||||||
SHEET_ROLL_MODE,
|
|
||||||
SHEET_SLIP_MODE,
|
|
||||||
SLIP_PRINT_AND_EJECT,
|
|
||||||
SLIP_SELECT,
|
|
||||||
SLIP_EJECT,
|
|
||||||
)
|
|
||||||
from .constants import (
|
|
||||||
QR_MODEL_1,
|
|
||||||
QR_MODEL_2,
|
|
||||||
QR_MICRO,
|
|
||||||
BARCODE_TYPES,
|
|
||||||
BARCODE_HEIGHT,
|
BARCODE_HEIGHT,
|
||||||
BARCODE_WIDTH,
|
|
||||||
)
|
|
||||||
from .constants import BARCODE_FONT_A, BARCODE_FONT_B, BARCODE_FORMATS
|
|
||||||
from .constants import (
|
|
||||||
BARCODE_TXT_OFF,
|
|
||||||
BARCODE_TXT_BTH,
|
|
||||||
BARCODE_TXT_ABV,
|
BARCODE_TXT_ABV,
|
||||||
BARCODE_TXT_BLW,
|
BARCODE_TXT_BLW,
|
||||||
)
|
BARCODE_TXT_BTH,
|
||||||
from .constants import TXT_SIZE, TXT_NORMAL
|
BARCODE_TXT_OFF,
|
||||||
from .constants import SET_FONT
|
BARCODE_TYPES,
|
||||||
from .constants import LINESPACING_FUNCS, LINESPACING_RESET
|
BARCODE_WIDTH,
|
||||||
from .constants import LINE_DISPLAY_OPEN, LINE_DISPLAY_CLEAR, LINE_DISPLAY_CLOSE
|
|
||||||
from .constants import (
|
|
||||||
CD_KICK_DEC_SEQUENCE,
|
|
||||||
CD_KICK_5,
|
|
||||||
CD_KICK_2,
|
|
||||||
PAPER_FULL_CUT,
|
|
||||||
PAPER_PART_CUT,
|
|
||||||
BUZZER,
|
BUZZER,
|
||||||
)
|
CD_KICK_2,
|
||||||
from .constants import HW_RESET, HW_SELECT, HW_INIT
|
CD_KICK_5,
|
||||||
from .constants import (
|
CD_KICK_DEC_SEQUENCE,
|
||||||
CTL_VT,
|
|
||||||
CTL_CR,
|
CTL_CR,
|
||||||
CTL_FF,
|
CTL_FF,
|
||||||
CTL_LF,
|
CTL_LF,
|
||||||
CTL_SET_HT,
|
CTL_SET_HT,
|
||||||
|
CTL_VT,
|
||||||
|
ESC,
|
||||||
|
GS,
|
||||||
|
HW_INIT,
|
||||||
|
HW_RESET,
|
||||||
|
HW_SELECT,
|
||||||
|
LINE_DISPLAY_CLEAR,
|
||||||
|
LINE_DISPLAY_CLOSE,
|
||||||
|
LINE_DISPLAY_OPEN,
|
||||||
|
LINESPACING_FUNCS,
|
||||||
|
LINESPACING_RESET,
|
||||||
|
NUL,
|
||||||
PANEL_BUTTON_OFF,
|
PANEL_BUTTON_OFF,
|
||||||
PANEL_BUTTON_ON,
|
PANEL_BUTTON_ON,
|
||||||
|
PAPER_FULL_CUT,
|
||||||
|
PAPER_PART_CUT,
|
||||||
|
QR_ECLEVEL_H,
|
||||||
|
QR_ECLEVEL_L,
|
||||||
|
QR_ECLEVEL_M,
|
||||||
|
QR_ECLEVEL_Q,
|
||||||
|
QR_MICRO,
|
||||||
|
QR_MODEL_1,
|
||||||
|
QR_MODEL_2,
|
||||||
|
RT_MASK_LOWPAPER,
|
||||||
|
RT_MASK_NOPAPER,
|
||||||
|
RT_MASK_ONLINE,
|
||||||
|
RT_MASK_PAPER,
|
||||||
|
RT_STATUS_ONLINE,
|
||||||
|
RT_STATUS_PAPER,
|
||||||
|
SET_FONT,
|
||||||
|
SHEET_ROLL_MODE,
|
||||||
|
SHEET_SLIP_MODE,
|
||||||
|
SLIP_EJECT,
|
||||||
|
SLIP_PRINT_AND_EJECT,
|
||||||
|
SLIP_SELECT,
|
||||||
|
TXT_NORMAL,
|
||||||
|
TXT_SIZE,
|
||||||
|
TXT_STYLE,
|
||||||
|
)
|
||||||
|
from .exceptions import (
|
||||||
|
BarcodeCodeError,
|
||||||
|
BarcodeSizeError,
|
||||||
|
BarcodeTypeError,
|
||||||
|
CashDrawerError,
|
||||||
|
ImageWidthError,
|
||||||
|
SetVariableError,
|
||||||
|
TabPosError,
|
||||||
)
|
)
|
||||||
from .constants import TXT_STYLE
|
|
||||||
from .constants import RT_STATUS_ONLINE, RT_MASK_ONLINE
|
|
||||||
from .constants import RT_STATUS_PAPER, RT_MASK_PAPER, RT_MASK_LOWPAPER, RT_MASK_NOPAPER
|
|
||||||
|
|
||||||
from .exceptions import BarcodeTypeError, BarcodeSizeError, TabPosError
|
|
||||||
from .exceptions import CashDrawerError, SetVariableError, BarcodeCodeError
|
|
||||||
from .exceptions import ImageWidthError
|
|
||||||
|
|
||||||
from .magicencode import MagicEncode
|
from .magicencode import MagicEncode
|
||||||
|
|
||||||
from abc import ABCMeta, abstractmethod # abstract base class support
|
|
||||||
from escpos.image import EscposImage
|
|
||||||
from escpos.capabilities import get_profile
|
|
||||||
|
|
||||||
|
|
||||||
# Remove special characters and whitespaces of the supported barcode names,
|
# Remove special characters and whitespaces of the supported barcode names,
|
||||||
# convert to uppercase and map them to their original names.
|
# convert to uppercase and map them to their original names.
|
||||||
HW_BARCODE_NAMES = {
|
HW_BARCODE_NAMES = {
|
||||||
|
@ -100,7 +108,7 @@ SW_BARCODE_NAMES = {
|
||||||
|
|
||||||
@six.add_metaclass(ABCMeta)
|
@six.add_metaclass(ABCMeta)
|
||||||
class Escpos(object):
|
class Escpos(object):
|
||||||
"""ESC/POS Printer object
|
"""ESC/POS Printer object.
|
||||||
|
|
||||||
This class is the abstract base class for an esc/pos-printer. The printer implementations are children of this
|
This class is the abstract base class for an esc/pos-printer. The printer implementations are children of this
|
||||||
class.
|
class.
|
||||||
|
@ -109,19 +117,20 @@ class Escpos(object):
|
||||||
device = None
|
device = None
|
||||||
|
|
||||||
def __init__(self, profile=None, magic_encode_args=None, **kwargs):
|
def __init__(self, profile=None, magic_encode_args=None, **kwargs):
|
||||||
"""Initialize ESCPOS Printer
|
"""Initialize ESCPOS Printer.
|
||||||
|
|
||||||
:param profile: Printer profile"""
|
:param profile: Printer profile
|
||||||
|
"""
|
||||||
self.profile = get_profile(profile)
|
self.profile = get_profile(profile)
|
||||||
self.magic = MagicEncode(self, **(magic_encode_args or {}))
|
self.magic = MagicEncode(self, **(magic_encode_args or {}))
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
"""call self.close upon deletion"""
|
"""Call self.close upon deletion."""
|
||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def _raw(self, msg):
|
def _raw(self, msg: bytes):
|
||||||
"""Sends raw data to the printer
|
"""Send raw data to the printer.
|
||||||
|
|
||||||
This function has to be individually implemented by the implementations.
|
This function has to be individually implemented by the implementations.
|
||||||
|
|
||||||
|
@ -131,7 +140,9 @@ class Escpos(object):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def _read(self):
|
def _read(self):
|
||||||
"""Returns a NotImplementedError if the instance of the class doesn't override this method.
|
"""Read from printer.
|
||||||
|
|
||||||
|
Returns a NotImplementedError if the instance of the class doesn't override this method.
|
||||||
:raises NotImplementedError
|
:raises NotImplementedError
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
@ -145,7 +156,7 @@ class Escpos(object):
|
||||||
fragment_height=960,
|
fragment_height=960,
|
||||||
center=False,
|
center=False,
|
||||||
):
|
):
|
||||||
"""Print an image
|
"""Print an image.
|
||||||
|
|
||||||
You can select whether the printer should print in high density or not. The default value is high density.
|
You can select whether the printer should print in high density or not. The default value is high density.
|
||||||
When printing in low density, the image will be stretched.
|
When printing in low density, the image will be stretched.
|
||||||
|
@ -252,8 +263,7 @@ class Escpos(object):
|
||||||
self._raw(b"".join(outp))
|
self._raw(b"".join(outp))
|
||||||
|
|
||||||
def _image_send_graphics_data(self, m, fn, data):
|
def _image_send_graphics_data(self, m, fn, data):
|
||||||
"""
|
"""Calculate and send correct data length for `GS ( L`.
|
||||||
Wrapper for GS ( L, to calculate and send correct data length.
|
|
||||||
|
|
||||||
:param m: Modifier//variant for function. Usually '0'
|
:param m: Modifier//variant for function. Usually '0'
|
||||||
:param fn: Function number to use, as byte
|
:param fn: Function number to use, as byte
|
||||||
|
@ -272,7 +282,7 @@ class Escpos(object):
|
||||||
center=False,
|
center=False,
|
||||||
impl="bitImageRaster",
|
impl="bitImageRaster",
|
||||||
):
|
):
|
||||||
"""Print QR Code for the provided string
|
"""Print QR Code for the provided string.
|
||||||
|
|
||||||
:param content: The content of the code. Numeric data will be more efficiently compacted.
|
:param content: The content of the code. Numeric data will be more efficiently compacted.
|
||||||
:param ec: Error-correction level to use. One of QR_ECLEVEL_L (default), QR_ECLEVEL_M, QR_ECLEVEL_Q or
|
:param ec: Error-correction level to use. One of QR_ECLEVEL_L (default), QR_ECLEVEL_M, QR_ECLEVEL_Q or
|
||||||
|
@ -345,7 +355,7 @@ class Escpos(object):
|
||||||
self._send_2d_code_data(six.int2byte(81), cn, b"", b"0")
|
self._send_2d_code_data(six.int2byte(81), cn, b"", b"0")
|
||||||
|
|
||||||
def _send_2d_code_data(self, fn, cn, data, m=b""):
|
def _send_2d_code_data(self, fn, cn, data, m=b""):
|
||||||
"""Wrapper for GS ( k, to calculate and send correct data length.
|
"""Calculate and send correct data length for`GS ( k`.
|
||||||
|
|
||||||
:param fn: Function to use.
|
:param fn: Function to use.
|
||||||
:param cn: Output code type. Affects available data.
|
:param cn: Output code type. Affects available data.
|
||||||
|
@ -379,8 +389,8 @@ class Escpos(object):
|
||||||
inp_number //= 256
|
inp_number //= 256
|
||||||
return outp
|
return outp
|
||||||
|
|
||||||
def charcode(self, code="AUTO"):
|
def charcode(self, code: str = "AUTO"):
|
||||||
"""Set Character Code Table
|
"""Set Character Code Table.
|
||||||
|
|
||||||
Sets the control sequence from ``CHARCODE`` in :py:mod:`escpos.constants` as active. It will be sent with
|
Sets the control sequence from ``CHARCODE`` in :py:mod:`escpos.constants` as active. It will be sent with
|
||||||
the next text sequence. If you set the variable code to ``AUTO`` it will try to automatically guess the
|
the next text sequence. If you set the variable code to ``AUTO`` it will try to automatically guess the
|
||||||
|
@ -396,7 +406,8 @@ class Escpos(object):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def check_barcode(bc, code):
|
def check_barcode(bc, code):
|
||||||
"""
|
"""Check if barcode is OK.
|
||||||
|
|
||||||
This method checks if the barcode is in the proper format.
|
This method checks if the barcode is in the proper format.
|
||||||
The validation concerns the barcode length and the set of characters, but won't compute/validate any checksum.
|
The validation concerns the barcode length and the set of characters, but won't compute/validate any checksum.
|
||||||
The full set of requirement for each barcode type is available in the ESC/POS documentation.
|
The full set of requirement for each barcode type is available in the ESC/POS documentation.
|
||||||
|
@ -444,15 +455,15 @@ class Escpos(object):
|
||||||
self,
|
self,
|
||||||
code,
|
code,
|
||||||
bc,
|
bc,
|
||||||
height=64,
|
height: int = 64,
|
||||||
width=3,
|
width: int = 3,
|
||||||
pos="BELOW",
|
pos: str = "BELOW",
|
||||||
font="A",
|
font: str = "A",
|
||||||
align_ct=True,
|
align_ct: bool = True,
|
||||||
function_type=None,
|
function_type=None,
|
||||||
check=True,
|
check: bool = True,
|
||||||
force_software=False,
|
force_software: Union[bool, str] = False,
|
||||||
):
|
) -> None:
|
||||||
"""Print barcode.
|
"""Print barcode.
|
||||||
|
|
||||||
Automatic hardware|software barcode renderer according to the printer capabilities.
|
Automatic hardware|software barcode renderer according to the printer capabilities.
|
||||||
|
@ -535,9 +546,11 @@ class Escpos(object):
|
||||||
raise BarcodeTypeError(f"Not supported or wrong barcode name {bc}.")
|
raise BarcodeTypeError(f"Not supported or wrong barcode name {bc}.")
|
||||||
|
|
||||||
if force_software or not capable["hw"] or not capable_bc["hw"]:
|
if force_software or not capable["hw"] or not capable_bc["hw"]:
|
||||||
|
# based on earlier checks, we require that software mode is not None
|
||||||
|
assert capable["sw"] is not None
|
||||||
# Select the best possible capable render mode
|
# Select the best possible capable render mode
|
||||||
impl = capable["sw"][0]
|
impl = capable["sw"][0]
|
||||||
if force_software in capable["sw"]:
|
if force_software in capable["sw"] and isinstance(force_software, str):
|
||||||
# Force to a specific mode
|
# Force to a specific mode
|
||||||
impl = force_software
|
impl = force_software
|
||||||
print(f"Using {impl} software barcode renderer")
|
print(f"Using {impl} software barcode renderer")
|
||||||
|
@ -567,15 +580,15 @@ class Escpos(object):
|
||||||
self,
|
self,
|
||||||
code,
|
code,
|
||||||
bc,
|
bc,
|
||||||
height=64,
|
height: int = 64,
|
||||||
width=3,
|
width: int = 3,
|
||||||
pos="BELOW",
|
pos: str = "BELOW",
|
||||||
font="A",
|
font: str = "A",
|
||||||
align_ct=True,
|
align_ct: bool = True,
|
||||||
function_type=None,
|
function_type=None,
|
||||||
check=True,
|
check: bool = True,
|
||||||
):
|
):
|
||||||
"""Print Barcode
|
"""Print Barcode.
|
||||||
|
|
||||||
This method allows to print barcodes. The rendering of the barcode is done by the printer and therefore has to
|
This method allows to print barcodes. The rendering of the barcode is done by the printer and therefore has to
|
||||||
be supported by the unit. By default, this method will check whether your barcode text is correct, that is
|
be supported by the unit. By default, this method will check whether your barcode text is correct, that is
|
||||||
|
@ -726,14 +739,14 @@ class Escpos(object):
|
||||||
self,
|
self,
|
||||||
barcode_type,
|
barcode_type,
|
||||||
data,
|
data,
|
||||||
impl="bitImageColumn",
|
impl: str = "bitImageColumn",
|
||||||
module_height=5,
|
module_height: Union[int, float] = 5,
|
||||||
module_width=0.2,
|
module_width: Union[int, float] = 0.2,
|
||||||
text_distance=5,
|
text_distance: Union[int, float] = 5,
|
||||||
font_size=10,
|
font_size: int = 10,
|
||||||
center=True,
|
center: bool = True,
|
||||||
):
|
):
|
||||||
"""Print Barcode
|
"""Print Barcode.
|
||||||
|
|
||||||
This method allows to print barcodes. The rendering of the barcode is done by
|
This method allows to print barcodes. The rendering of the barcode is done by
|
||||||
the `barcode` library and sent to the printer as image through one of the
|
the `barcode` library and sent to the printer as image through one of the
|
||||||
|
@ -773,13 +786,13 @@ class Escpos(object):
|
||||||
* bitImageRaster
|
* bitImageRaster
|
||||||
|
|
||||||
:param module_height: barcode module height (in mm).
|
:param module_height: barcode module height (in mm).
|
||||||
:type module_height: int | float
|
:type module_height: Union[int, float]
|
||||||
|
|
||||||
:param module_width: barcode module width (in mm).
|
:param module_width: barcode module width (in mm).
|
||||||
:type module_width: int | float
|
:type module_width: Union[int, float]
|
||||||
|
|
||||||
:param text_distance: distance from the barcode to the code text (in mm).
|
:param text_distance: distance from the barcode to the code text (in mm).
|
||||||
:type text_distance: int | float
|
:type text_distance: Union[int, float]
|
||||||
|
|
||||||
:param font_size: font size of the code text (in dots).
|
:param font_size: font size of the code text (in dots).
|
||||||
:type font_size: int
|
:type font_size: int
|
||||||
|
@ -817,7 +830,7 @@ class Escpos(object):
|
||||||
self.image(image, impl=impl, center=center)
|
self.image(image, impl=impl, center=center)
|
||||||
|
|
||||||
def text(self, txt):
|
def text(self, txt):
|
||||||
"""Print alpha-numeric text
|
"""Print alpha-numeric text.
|
||||||
|
|
||||||
The text has to be encoded in the currently selected codepage.
|
The text has to be encoded in the currently selected codepage.
|
||||||
The input text has to be encoded in unicode.
|
The input text has to be encoded in unicode.
|
||||||
|
@ -829,7 +842,7 @@ class Escpos(object):
|
||||||
self.magic.write(txt)
|
self.magic.write(txt)
|
||||||
|
|
||||||
def textln(self, txt=""):
|
def textln(self, txt=""):
|
||||||
"""Print alpha-numeric text with a newline
|
"""Print alpha-numeric text with a newline.
|
||||||
|
|
||||||
The text has to be encoded in the currently selected codepage.
|
The text has to be encoded in the currently selected codepage.
|
||||||
The input text has to be encoded in unicode.
|
The input text has to be encoded in unicode.
|
||||||
|
@ -840,7 +853,7 @@ class Escpos(object):
|
||||||
self.text("{}\n".format(txt))
|
self.text("{}\n".format(txt))
|
||||||
|
|
||||||
def ln(self, count=1):
|
def ln(self, count=1):
|
||||||
"""Print a newline or more
|
"""Print a newline or more.
|
||||||
|
|
||||||
:param count: number of newlines to print
|
:param count: number of newlines to print
|
||||||
:raises: :py:exc:`ValueError` if count < 0
|
:raises: :py:exc:`ValueError` if count < 0
|
||||||
|
@ -851,7 +864,7 @@ class Escpos(object):
|
||||||
self.text("\n" * count)
|
self.text("\n" * count)
|
||||||
|
|
||||||
def block_text(self, txt, font="0", columns=None):
|
def block_text(self, txt, font="0", columns=None):
|
||||||
"""Text is printed wrapped to specified columns
|
"""Print text wrapped to specifiec columns.
|
||||||
|
|
||||||
Text has to be encoded in unicode.
|
Text has to be encoded in unicode.
|
||||||
|
|
||||||
|
@ -879,7 +892,7 @@ class Escpos(object):
|
||||||
double_height=False,
|
double_height=False,
|
||||||
custom_size=False,
|
custom_size=False,
|
||||||
):
|
):
|
||||||
"""Set text properties by sending them to the printer
|
"""Set text properties by sending them to the printer.
|
||||||
|
|
||||||
:param align: horizontal position for text, possible values are:
|
:param align: horizontal position for text, possible values are:
|
||||||
|
|
||||||
|
@ -918,7 +931,6 @@ class Escpos(object):
|
||||||
:type height: int
|
:type height: int
|
||||||
:type density: int
|
:type density: int
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if custom_size:
|
if custom_size:
|
||||||
if (
|
if (
|
||||||
1 <= width <= 8
|
1 <= width <= 8
|
||||||
|
@ -996,7 +1008,6 @@ class Escpos(object):
|
||||||
:param feed: print and feed before cutting. default: true
|
:param feed: print and feed before cutting. default: true
|
||||||
:raises ValueError: if mode not in ('FULL', 'PART')
|
:raises ValueError: if mode not in ('FULL', 'PART')
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not feed:
|
if not feed:
|
||||||
self._raw(GS + b"V" + six.int2byte(66) + b"\x00")
|
self._raw(GS + b"V" + six.int2byte(66) + b"\x00")
|
||||||
return
|
return
|
||||||
|
@ -1019,7 +1030,7 @@ class Escpos(object):
|
||||||
self._raw(PAPER_PART_CUT)
|
self._raw(PAPER_PART_CUT)
|
||||||
|
|
||||||
def cashdraw(self, pin):
|
def cashdraw(self, pin):
|
||||||
"""Send pulse to kick the cash drawer
|
"""Send pulse to kick the cash drawer.
|
||||||
|
|
||||||
Kick cash drawer on pin 2 (:py:const:`~escpos.constants.CD_KICK_2`)
|
Kick cash drawer on pin 2 (:py:const:`~escpos.constants.CD_KICK_2`)
|
||||||
or pin 5 (:py:const:`~escpos.constants.CD_KICK_5`)
|
or pin 5 (:py:const:`~escpos.constants.CD_KICK_5`)
|
||||||
|
@ -1041,7 +1052,7 @@ class Escpos(object):
|
||||||
raise CashDrawerError(err)
|
raise CashDrawerError(err)
|
||||||
|
|
||||||
def linedisplay_select(self, select_display=False):
|
def linedisplay_select(self, select_display=False):
|
||||||
"""Selects the line display or the printer
|
"""Select the line display or the printer.
|
||||||
|
|
||||||
This method is used for line displays that are daisy-chained between your computer and printer.
|
This method is used for line displays that are daisy-chained between your computer and printer.
|
||||||
If you set `select_display` to true, only the display is selected and if you set it to false,
|
If you set `select_display` to true, only the display is selected and if you set it to false,
|
||||||
|
@ -1056,15 +1067,14 @@ class Escpos(object):
|
||||||
self._raw(LINE_DISPLAY_CLOSE)
|
self._raw(LINE_DISPLAY_CLOSE)
|
||||||
|
|
||||||
def linedisplay_clear(self):
|
def linedisplay_clear(self):
|
||||||
"""Clears the line display and resets the cursor
|
"""Clear the line display and resets the .
|
||||||
|
|
||||||
This method is used for line displays that are daisy-chained between your computer and printer.
|
This method is used for line displays that are daisy-chained between your computer and printer.
|
||||||
"""
|
"""
|
||||||
self._raw(LINE_DISPLAY_CLEAR)
|
self._raw(LINE_DISPLAY_CLEAR)
|
||||||
|
|
||||||
def linedisplay(self, text):
|
def linedisplay(self, text):
|
||||||
"""
|
"""Display text on a line display connected to your printer.
|
||||||
Display text on a line display connected to your printer
|
|
||||||
|
|
||||||
You should connect a line display to your printer. You can do this by daisy-chaining
|
You should connect a line display to your printer. You can do this by daisy-chaining
|
||||||
the display between your computer and printer.
|
the display between your computer and printer.
|
||||||
|
@ -1077,7 +1087,7 @@ class Escpos(object):
|
||||||
self.linedisplay_select(select_display=False)
|
self.linedisplay_select(select_display=False)
|
||||||
|
|
||||||
def hw(self, hw):
|
def hw(self, hw):
|
||||||
"""Hardware operations
|
"""Hardware operations.
|
||||||
|
|
||||||
:param hw: hardware action, may be:
|
:param hw: hardware action, may be:
|
||||||
|
|
||||||
|
@ -1095,7 +1105,7 @@ class Escpos(object):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def print_and_feed(self, n=1):
|
def print_and_feed(self, n=1):
|
||||||
"""Print data in print buffer and feed *n* lines
|
"""Print data in print buffer and feed *n* lines.
|
||||||
|
|
||||||
If n not in range (0, 255) then a ValueError will be raised.
|
If n not in range (0, 255) then a ValueError will be raised.
|
||||||
|
|
||||||
|
@ -1109,7 +1119,7 @@ class Escpos(object):
|
||||||
raise ValueError("n must be betwen 0 and 255")
|
raise ValueError("n must be betwen 0 and 255")
|
||||||
|
|
||||||
def control(self, ctl, count=5, tab_size=8):
|
def control(self, ctl, count=5, tab_size=8):
|
||||||
"""Feed control sequences
|
"""Feed control sequences.
|
||||||
|
|
||||||
:param ctl: string for the following control sequences:
|
:param ctl: string for the following control sequences:
|
||||||
|
|
||||||
|
@ -1145,7 +1155,7 @@ class Escpos(object):
|
||||||
self._raw(CTL_VT)
|
self._raw(CTL_VT)
|
||||||
|
|
||||||
def panel_buttons(self, enable=True):
|
def panel_buttons(self, enable=True):
|
||||||
"""Controls the panel buttons on the printer (e.g. FEED)
|
"""Control the panel buttons on the printer (e.g. FEED).
|
||||||
|
|
||||||
When enable is set to False the panel buttons on the printer
|
When enable is set to False the panel buttons on the printer
|
||||||
will be disabled.
|
will be disabled.
|
||||||
|
@ -1175,9 +1185,9 @@ class Escpos(object):
|
||||||
self._raw(PANEL_BUTTON_OFF)
|
self._raw(PANEL_BUTTON_OFF)
|
||||||
|
|
||||||
def query_status(self, mode):
|
def query_status(self, mode):
|
||||||
"""
|
"""Query the printer for its status.
|
||||||
Queries the printer for its status, and returns an array
|
|
||||||
of integers containing it.
|
Returns an array of integers containing it.
|
||||||
|
|
||||||
:param mode: Integer that sets the status mode queried to the printer.
|
:param mode: Integer that sets the status mode queried to the printer.
|
||||||
- RT_STATUS_ONLINE: Printer status.
|
- RT_STATUS_ONLINE: Printer status.
|
||||||
|
@ -1189,8 +1199,7 @@ class Escpos(object):
|
||||||
return status
|
return status
|
||||||
|
|
||||||
def is_online(self):
|
def is_online(self):
|
||||||
"""
|
"""Query the online status of the printer.
|
||||||
Queries the online status of the printer.
|
|
||||||
|
|
||||||
:returns: When online, returns ``True``; ``False`` otherwise.
|
:returns: When online, returns ``True``; ``False`` otherwise.
|
||||||
:rtype: bool
|
:rtype: bool
|
||||||
|
@ -1201,8 +1210,7 @@ class Escpos(object):
|
||||||
return not (status[0] & RT_MASK_ONLINE)
|
return not (status[0] & RT_MASK_ONLINE)
|
||||||
|
|
||||||
def paper_status(self):
|
def paper_status(self):
|
||||||
"""
|
"""Query the paper status of the printer.
|
||||||
Queries the paper status of the printer.
|
|
||||||
|
|
||||||
Returns 2 if there is plenty of paper, 1 if the paper has arrived to
|
Returns 2 if there is plenty of paper, 1 if the paper has arrived to
|
||||||
the near-end sensor and 0 if there is no paper.
|
the near-end sensor and 0 if there is no paper.
|
||||||
|
@ -1221,7 +1229,7 @@ class Escpos(object):
|
||||||
return 2
|
return 2
|
||||||
|
|
||||||
def target(self, type="ROLL"):
|
def target(self, type="ROLL"):
|
||||||
"""Select where to print to
|
"""Select where to print to.
|
||||||
|
|
||||||
Print to the thermal printer by default (ROLL) or
|
Print to the thermal printer by default (ROLL) or
|
||||||
print to the slip dot matrix printer if supported (SLIP)
|
print to the slip dot matrix printer if supported (SLIP)
|
||||||
|
@ -1234,11 +1242,11 @@ class Escpos(object):
|
||||||
raise ValueError("Unsupported target")
|
raise ValueError("Unsupported target")
|
||||||
|
|
||||||
def eject_slip(self):
|
def eject_slip(self):
|
||||||
"""Eject the slip/cheque"""
|
"""Eject the slip/cheque."""
|
||||||
self._raw(SLIP_EJECT)
|
self._raw(SLIP_EJECT)
|
||||||
|
|
||||||
def print_and_eject_slip(self):
|
def print_and_eject_slip(self):
|
||||||
"""Print and eject
|
"""Print and eject.
|
||||||
|
|
||||||
Prints data from the buffer to the slip station and if the paper
|
Prints data from the buffer to the slip station and if the paper
|
||||||
sensor is covered, reverses the slip out the front of the printer
|
sensor is covered, reverses the slip out the front of the printer
|
||||||
|
@ -1248,7 +1256,7 @@ class Escpos(object):
|
||||||
self._raw(SLIP_PRINT_AND_EJECT)
|
self._raw(SLIP_PRINT_AND_EJECT)
|
||||||
|
|
||||||
def use_slip_only(self):
|
def use_slip_only(self):
|
||||||
"""Selects the Slip Station for all functions.
|
"""Select the Slip Station for all functions.
|
||||||
|
|
||||||
The receipt station is the default setting after the printer
|
The receipt station is the default setting after the printer
|
||||||
is initialized or the Clear Printer (0x10) command is received
|
is initialized or the Clear Printer (0x10) command is received
|
||||||
|
@ -1256,7 +1264,7 @@ class Escpos(object):
|
||||||
self._raw(SLIP_SELECT)
|
self._raw(SLIP_SELECT)
|
||||||
|
|
||||||
def buzzer(self, times=2, duration=4):
|
def buzzer(self, times=2, duration=4):
|
||||||
"""Activate the internal printer buzzer (only supported printers).
|
"""Activate the internal printer buzzer on supported printers.
|
||||||
|
|
||||||
The 'times' parameter refers to the 'n' escpos command parameter,
|
The 'times' parameter refers to the 'n' escpos command parameter,
|
||||||
which means how many times the buzzer will be 'beeped'.
|
which means how many times the buzzer will be 'beeped'.
|
||||||
|
@ -1265,7 +1273,6 @@ class Escpos(object):
|
||||||
:param duration: Integer between 1 and 9, indicates the beep duration.
|
:param duration: Integer between 1 and 9, indicates the beep duration.
|
||||||
:returns: None
|
:returns: None
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not 1 <= times <= 9:
|
if not 1 <= times <= 9:
|
||||||
raise ValueError("times must be between 1 and 9")
|
raise ValueError("times must be between 1 and 9")
|
||||||
if not 1 <= duration <= 9:
|
if not 1 <= duration <= 9:
|
||||||
|
@ -1275,7 +1282,7 @@ class Escpos(object):
|
||||||
|
|
||||||
|
|
||||||
class EscposIO(object):
|
class EscposIO(object):
|
||||||
"""ESC/POS Printer IO object
|
r"""ESC/POS Printer IO object.
|
||||||
|
|
||||||
Allows the class to be used together with the `with`-statement. You have to define a printer instance
|
Allows the class to be used together with the `with`-statement. You have to define a printer instance
|
||||||
and assign it to the EscposIO class.
|
and assign it to the EscposIO class.
|
||||||
|
@ -1295,7 +1302,8 @@ class EscposIO(object):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, printer, autocut=True, autoclose=True, **kwargs):
|
def __init__(self, printer, autocut=True, autoclose=True, **kwargs):
|
||||||
"""
|
"""Initialize object.
|
||||||
|
|
||||||
:param printer: An EscPos-printer object
|
:param printer: An EscPos-printer object
|
||||||
:type printer: escpos.Escpos
|
:type printer: escpos.Escpos
|
||||||
:param autocut: If True, paper is automatically cut after the `with`-statement *default*: True
|
:param autocut: If True, paper is automatically cut after the `with`-statement *default*: True
|
||||||
|
@ -1307,7 +1315,7 @@ class EscposIO(object):
|
||||||
self.autoclose = autoclose
|
self.autoclose = autoclose
|
||||||
|
|
||||||
def set(self, **kwargs):
|
def set(self, **kwargs):
|
||||||
"""Set the printer-parameters
|
"""Set the printer-parameters.
|
||||||
|
|
||||||
Controls which parameters will be passed to :py:meth:`Escpos.set() <escpos.escpos.Escpos.set()>`.
|
Controls which parameters will be passed to :py:meth:`Escpos.set() <escpos.escpos.Escpos.set()>`.
|
||||||
For more information on the parameters see the :py:meth:`set() <escpos.escpos.Escpos.set()>`-methods
|
For more information on the parameters see the :py:meth:`set() <escpos.escpos.Escpos.set()>`-methods
|
||||||
|
@ -1319,6 +1327,7 @@ class EscposIO(object):
|
||||||
self.params.update(kwargs)
|
self.params.update(kwargs)
|
||||||
|
|
||||||
def writelines(self, text, **kwargs):
|
def writelines(self, text, **kwargs):
|
||||||
|
"""Print text."""
|
||||||
params = dict(self.params)
|
params = dict(self.params)
|
||||||
params.update(kwargs)
|
params.update(kwargs)
|
||||||
|
|
||||||
|
@ -1341,14 +1350,18 @@ class EscposIO(object):
|
||||||
self.printer.text("{0}\n".format(line))
|
self.printer.text("{0}\n".format(line))
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
"""called upon closing the `with`-statement"""
|
"""Close printer.
|
||||||
|
|
||||||
|
Called upon closing the `with`-statement.
|
||||||
|
"""
|
||||||
self.printer.close()
|
self.printer.close()
|
||||||
|
|
||||||
def __enter__(self, **kwargs):
|
def __enter__(self, **kwargs):
|
||||||
|
"""Enter context."""
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def __exit__(self, type, value, traceback):
|
def __exit__(self, type, value, traceback):
|
||||||
"""
|
"""Cut and close if configured.
|
||||||
|
|
||||||
If :py:attr:`autocut <escpos.escpos.EscposIO.autocut>` is `True` (set by this class' constructor),
|
If :py:attr:`autocut <escpos.escpos.EscposIO.autocut>` is `True` (set by this class' constructor),
|
||||||
then :py:meth:`printer.cut() <escpos.escpos.Escpos.cut()>` will be called here.
|
then :py:meth:`printer.cut() <escpos.escpos.Escpos.cut()>` will be called here.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
""" ESC/POS Exceptions classes
|
"""ESC/POS Exceptions classes.
|
||||||
|
|
||||||
Result/Exit codes:
|
Result/Exit codes:
|
||||||
|
|
||||||
|
@ -27,9 +27,10 @@ Result/Exit codes:
|
||||||
|
|
||||||
|
|
||||||
class Error(Exception):
|
class Error(Exception):
|
||||||
"""Base class for ESC/POS errors"""
|
"""Base class for ESC/POS errors."""
|
||||||
|
|
||||||
def __init__(self, msg, status=None):
|
def __init__(self, msg, status=None):
|
||||||
|
"""Initialize Error object."""
|
||||||
Exception.__init__(self)
|
Exception.__init__(self)
|
||||||
self.msg = msg
|
self.msg = msg
|
||||||
self.resultcode = 1
|
self.resultcode = 1
|
||||||
|
@ -37,6 +38,7 @@ class Error(Exception):
|
||||||
self.resultcode = status
|
self.resultcode = status
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
"""Return string representation of Error."""
|
||||||
return self.msg
|
return self.msg
|
||||||
|
|
||||||
|
|
||||||
|
@ -49,11 +51,13 @@ class BarcodeTypeError(Error):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, msg=""):
|
def __init__(self, msg=""):
|
||||||
|
"""Initialize BarcodeTypeError object."""
|
||||||
Error.__init__(self, msg)
|
Error.__init__(self, msg)
|
||||||
self.msg = msg
|
self.msg = msg
|
||||||
self.resultcode = 10
|
self.resultcode = 10
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
"""Return string representation of BarcodeTypeError."""
|
||||||
return "No Barcode type is defined ({msg})".format(msg=self.msg)
|
return "No Barcode type is defined ({msg})".format(msg=self.msg)
|
||||||
|
|
||||||
|
|
||||||
|
@ -66,11 +70,13 @@ class BarcodeSizeError(Error):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, msg=""):
|
def __init__(self, msg=""):
|
||||||
|
"""Initialize BarcodeSizeError object."""
|
||||||
Error.__init__(self, msg)
|
Error.__init__(self, msg)
|
||||||
self.msg = msg
|
self.msg = msg
|
||||||
self.resultcode = 20
|
self.resultcode = 20
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
"""Return string representation of BarcodeSizeError."""
|
||||||
return "Barcode size is out of range ({msg})".format(msg=self.msg)
|
return "Barcode size is out of range ({msg})".format(msg=self.msg)
|
||||||
|
|
||||||
|
|
||||||
|
@ -83,11 +89,13 @@ class BarcodeCodeError(Error):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, msg=""):
|
def __init__(self, msg=""):
|
||||||
|
"""Initialize BarcodeCodeError object."""
|
||||||
Error.__init__(self, msg)
|
Error.__init__(self, msg)
|
||||||
self.msg = msg
|
self.msg = msg
|
||||||
self.resultcode = 30
|
self.resultcode = 30
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
"""Return string representation of BarcodeCodeError."""
|
||||||
return "No Barcode code was supplied ({msg})".format(msg=self.msg)
|
return "No Barcode code was supplied ({msg})".format(msg=self.msg)
|
||||||
|
|
||||||
|
|
||||||
|
@ -98,11 +106,13 @@ class ImageSizeError(Error):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, msg=""):
|
def __init__(self, msg=""):
|
||||||
|
"""Initialize ImageSizeError object."""
|
||||||
Error.__init__(self, msg)
|
Error.__init__(self, msg)
|
||||||
self.msg = msg
|
self.msg = msg
|
||||||
self.resultcode = 40
|
self.resultcode = 40
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
"""Return string representation of ImageSizeError."""
|
||||||
return "Image height is longer than 255px and can't be printed ({msg})".format(
|
return "Image height is longer than 255px and can't be printed ({msg})".format(
|
||||||
msg=self.msg
|
msg=self.msg
|
||||||
)
|
)
|
||||||
|
@ -115,11 +125,13 @@ class ImageWidthError(Error):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, msg=""):
|
def __init__(self, msg=""):
|
||||||
|
"""Initialize ImageWidthError object."""
|
||||||
Error.__init__(self, msg)
|
Error.__init__(self, msg)
|
||||||
self.msg = msg
|
self.msg = msg
|
||||||
self.resultcode = 41
|
self.resultcode = 41
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
"""Return string representation of ImageWidthError."""
|
||||||
return "Image width is too large ({msg})".format(msg=self.msg)
|
return "Image width is too large ({msg})".format(msg=self.msg)
|
||||||
|
|
||||||
|
|
||||||
|
@ -131,11 +143,13 @@ class TextError(Error):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, msg=""):
|
def __init__(self, msg=""):
|
||||||
|
"""Initialize TextError object."""
|
||||||
Error.__init__(self, msg)
|
Error.__init__(self, msg)
|
||||||
self.msg = msg
|
self.msg = msg
|
||||||
self.resultcode = 50
|
self.resultcode = 50
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
"""Return string representation of TextError."""
|
||||||
return "Text string must be supplied to the text() method ({msg})".format(
|
return "Text string must be supplied to the text() method ({msg})".format(
|
||||||
msg=self.msg
|
msg=self.msg
|
||||||
)
|
)
|
||||||
|
@ -149,16 +163,20 @@ class CashDrawerError(Error):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, msg=""):
|
def __init__(self, msg=""):
|
||||||
|
"""Initialize CashDrawerError object."""
|
||||||
Error.__init__(self, msg)
|
Error.__init__(self, msg)
|
||||||
self.msg = msg
|
self.msg = msg
|
||||||
self.resultcode = 60
|
self.resultcode = 60
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
"""Return string representation of CashDrawerError."""
|
||||||
return "Valid pin must be set to send pulse ({msg})".format(msg=self.msg)
|
return "Valid pin must be set to send pulse ({msg})".format(msg=self.msg)
|
||||||
|
|
||||||
|
|
||||||
class TabPosError(Error):
|
class TabPosError(Error):
|
||||||
"""Valid tab positions must be set by using from 1 to 32 tabs, and between 1 and 255 tab size values.
|
"""Tab position is invalid.
|
||||||
|
|
||||||
|
Valid tab positions must be set by using from 1 to 32 tabs, and between 1 and 255 tab size values.
|
||||||
Both values multiplied must not exceed 255, since it is the maximum tab value.
|
Both values multiplied must not exceed 255, since it is the maximum tab value.
|
||||||
|
|
||||||
This exception is raised by :py:meth:`escpos.escpos.Escpos.control`.
|
This exception is raised by :py:meth:`escpos.escpos.Escpos.control`.
|
||||||
|
@ -166,11 +184,13 @@ class TabPosError(Error):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, msg=""):
|
def __init__(self, msg=""):
|
||||||
|
"""Initialize TabPosError object."""
|
||||||
Error.__init__(self, msg)
|
Error.__init__(self, msg)
|
||||||
self.msg = msg
|
self.msg = msg
|
||||||
self.resultcode = 70
|
self.resultcode = 70
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
"""Return string representation of TabPosError."""
|
||||||
return "Valid tab positions must be in the range 0 to 16 ({msg})".format(
|
return "Valid tab positions must be in the range 0 to 16 ({msg})".format(
|
||||||
msg=self.msg
|
msg=self.msg
|
||||||
)
|
)
|
||||||
|
@ -184,43 +204,49 @@ class CharCodeError(Error):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, msg=""):
|
def __init__(self, msg=""):
|
||||||
|
"""Initialize CharCodeError object."""
|
||||||
Error.__init__(self, msg)
|
Error.__init__(self, msg)
|
||||||
self.msg = msg
|
self.msg = msg
|
||||||
self.resultcode = 80
|
self.resultcode = 80
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
"""Return string representation of CharCodeError."""
|
||||||
return "Valid char code must be set ({msg})".format(msg=self.msg)
|
return "Valid char code must be set ({msg})".format(msg=self.msg)
|
||||||
|
|
||||||
|
|
||||||
class USBNotFoundError(Error):
|
class USBNotFoundError(Error):
|
||||||
"""Device wasn't found (probably not plugged in)
|
"""Device wasn't found (probably not plugged in).
|
||||||
|
|
||||||
The USB device seems to be not plugged in.
|
The USB device seems to be not plugged in.
|
||||||
Ths returncode for this exception is `90`.
|
Ths returncode for this exception is `90`.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, msg=""):
|
def __init__(self, msg=""):
|
||||||
|
"""Initialize USBNotFoundError object."""
|
||||||
Error.__init__(self, msg)
|
Error.__init__(self, msg)
|
||||||
self.msg = msg
|
self.msg = msg
|
||||||
self.resultcode = 90
|
self.resultcode = 90
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
"""Return string representation of USBNotFoundError."""
|
||||||
return "USB device not found ({msg})".format(msg=self.msg)
|
return "USB device not found ({msg})".format(msg=self.msg)
|
||||||
|
|
||||||
|
|
||||||
class SetVariableError(Error):
|
class SetVariableError(Error):
|
||||||
"""A set method variable was out of range
|
"""A set method variable was out of range.
|
||||||
|
|
||||||
Check set variables against minimum and maximum values
|
Check set variables against minimum and maximum values
|
||||||
Ths returncode for this exception is `100`.
|
Ths returncode for this exception is `100`.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, msg=""):
|
def __init__(self, msg=""):
|
||||||
|
"""Initialize SetVariableError object."""
|
||||||
Error.__init__(self, msg)
|
Error.__init__(self, msg)
|
||||||
self.msg = msg
|
self.msg = msg
|
||||||
self.resultcode = 100
|
self.resultcode = 100
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
"""Return string representation of SetVariableError."""
|
||||||
return "Set variable out of range ({msg})".format(msg=self.msg)
|
return "Set variable out of range ({msg})".format(msg=self.msg)
|
||||||
|
|
||||||
|
|
||||||
|
@ -228,48 +254,54 @@ class SetVariableError(Error):
|
||||||
|
|
||||||
|
|
||||||
class ConfigNotFoundError(Error):
|
class ConfigNotFoundError(Error):
|
||||||
"""The configuration file was not found
|
"""The configuration file was not found.
|
||||||
|
|
||||||
The default or passed configuration file could not be read
|
The default or passed configuration file could not be read
|
||||||
Ths returncode for this exception is `200`.
|
Ths returncode for this exception is `200`.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, msg=""):
|
def __init__(self, msg=""):
|
||||||
|
"""Initialize ConfigNotFoundError object."""
|
||||||
Error.__init__(self, msg)
|
Error.__init__(self, msg)
|
||||||
self.msg = msg
|
self.msg = msg
|
||||||
self.resultcode = 200
|
self.resultcode = 200
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
"""Return string representation of ConfigNotFoundError."""
|
||||||
return "Configuration not found ({msg})".format(msg=self.msg)
|
return "Configuration not found ({msg})".format(msg=self.msg)
|
||||||
|
|
||||||
|
|
||||||
class ConfigSyntaxError(Error):
|
class ConfigSyntaxError(Error):
|
||||||
"""The configuration file is invalid
|
"""The configuration file is invalid.
|
||||||
|
|
||||||
The syntax is incorrect
|
The syntax is incorrect
|
||||||
Ths returncode for this exception is `210`.
|
Ths returncode for this exception is `210`.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, msg=""):
|
def __init__(self, msg=""):
|
||||||
|
"""Initialize ConfigSyntaxError object."""
|
||||||
Error.__init__(self, msg)
|
Error.__init__(self, msg)
|
||||||
self.msg = msg
|
self.msg = msg
|
||||||
self.resultcode = 210
|
self.resultcode = 210
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
"""Return string representation of ConfigSyntaxError."""
|
||||||
return "Configuration syntax is invalid ({msg})".format(msg=self.msg)
|
return "Configuration syntax is invalid ({msg})".format(msg=self.msg)
|
||||||
|
|
||||||
|
|
||||||
class ConfigSectionMissingError(Error):
|
class ConfigSectionMissingError(Error):
|
||||||
"""The configuration file is missing a section
|
"""The configuration file is missing a section.
|
||||||
|
|
||||||
The part of the config asked for doesn't exist in the loaded configuration
|
The part of the config asked for doesn't exist in the loaded configuration
|
||||||
Ths returncode for this exception is `220`.
|
Ths returncode for this exception is `220`.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, msg=""):
|
def __init__(self, msg=""):
|
||||||
|
"""Initialize ConfigSectionMissingError object."""
|
||||||
Error.__init__(self, msg)
|
Error.__init__(self, msg)
|
||||||
self.msg = msg
|
self.msg = msg
|
||||||
self.resultcode = 220
|
self.resultcode = 220
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
"""Return string representation of ConfigSectionMissingError."""
|
||||||
return "Configuration section is missing ({msg})".format(msg=self.msg)
|
return "Configuration section is missing ({msg})".format(msg=self.msg)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
""" Image format handling class
|
"""Image format handling class.
|
||||||
|
|
||||||
This module contains the image format handler :py:class:`EscposImage`.
|
This module contains the image format handler :py:class:`EscposImage`.
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ This module contains the image format handler :py:class:`EscposImage`.
|
||||||
|
|
||||||
|
|
||||||
import math
|
import math
|
||||||
|
|
||||||
from PIL import Image, ImageOps
|
from PIL import Image, ImageOps
|
||||||
|
|
||||||
|
|
||||||
|
@ -22,8 +23,7 @@ class EscposImage(object):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, img_source):
|
def __init__(self, img_source):
|
||||||
"""
|
"""Load in an image.
|
||||||
Load in an image
|
|
||||||
|
|
||||||
:param img_source: PIL.Image, or filename to load one from.
|
:param img_source: PIL.Image, or filename to load one from.
|
||||||
"""
|
"""
|
||||||
|
@ -49,30 +49,23 @@ class EscposImage(object):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def width(self):
|
def width(self):
|
||||||
"""
|
"""Return width of image in pixels."""
|
||||||
Width of image in pixels
|
|
||||||
"""
|
|
||||||
width_pixels, _ = self._im.size
|
width_pixels, _ = self._im.size
|
||||||
return width_pixels
|
return width_pixels
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def width_bytes(self):
|
def width_bytes(self):
|
||||||
"""
|
"""Return width of image if you use 8 pixels per byte and 0-pad at the end."""
|
||||||
Width of image if you use 8 pixels per byte and 0-pad at the end.
|
|
||||||
"""
|
|
||||||
return (self.width + 7) >> 3
|
return (self.width + 7) >> 3
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def height(self):
|
def height(self):
|
||||||
"""
|
"""Height of image in pixels."""
|
||||||
Height of image in pixels
|
|
||||||
"""
|
|
||||||
_, height_pixels = self._im.size
|
_, height_pixels = self._im.size
|
||||||
return height_pixels
|
return height_pixels
|
||||||
|
|
||||||
def to_column_format(self, high_density_vertical=True):
|
def to_column_format(self, high_density_vertical=True):
|
||||||
"""
|
"""Extract slices of an image as equal-sized blobs of column-format data.
|
||||||
Extract slices of an image as equal-sized blobs of column-format data.
|
|
||||||
|
|
||||||
:param high_density_vertical: Printed line height in dots
|
:param high_density_vertical: Printed line height in dots
|
||||||
"""
|
"""
|
||||||
|
@ -89,14 +82,11 @@ class EscposImage(object):
|
||||||
left += line_height
|
left += line_height
|
||||||
|
|
||||||
def to_raster_format(self):
|
def to_raster_format(self):
|
||||||
"""
|
"""Convert image to raster-format binary."""
|
||||||
Convert image to raster-format binary
|
|
||||||
"""
|
|
||||||
return self._im.tobytes()
|
return self._im.tobytes()
|
||||||
|
|
||||||
def split(self, fragment_height):
|
def split(self, fragment_height):
|
||||||
"""
|
"""Split an image into multiple fragments after fragment_height pixels.
|
||||||
Split an image into multiple fragments after fragment_height pixels
|
|
||||||
|
|
||||||
:param fragment_height: height of fragment
|
:param fragment_height: height of fragment
|
||||||
:return: list of PIL objects
|
:return: list of PIL objects
|
||||||
|
@ -113,7 +103,7 @@ class EscposImage(object):
|
||||||
return fragments
|
return fragments
|
||||||
|
|
||||||
def center(self, max_width):
|
def center(self, max_width):
|
||||||
"""In-place image centering
|
"""Center image in place.
|
||||||
|
|
||||||
:param: Maximum width in order to deduce x offset for centering
|
:param: Maximum width in order to deduce x offset for centering
|
||||||
:return: None
|
:return: None
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
""" Magic Encode
|
"""Magic Encode.
|
||||||
|
|
||||||
This module tries to convert an UTF-8 string to an encoded string for the printer.
|
This module tries to convert an UTF-8 string to an encoded string for the printer.
|
||||||
It uses trial and error in order to guess the right codepage.
|
It uses trial and error in order to guess the right codepage.
|
||||||
|
@ -13,17 +13,18 @@ The code is based on the encoding-code in py-xml-escpos by @fvdsn.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
import re
|
||||||
from builtins import bytes
|
from builtins import bytes
|
||||||
|
|
||||||
|
import six
|
||||||
|
|
||||||
|
from .codepages import CodePages
|
||||||
from .constants import CODEPAGE_CHANGE
|
from .constants import CODEPAGE_CHANGE
|
||||||
from .exceptions import Error
|
from .exceptions import Error
|
||||||
from .codepages import CodePages
|
|
||||||
import six
|
|
||||||
import re
|
|
||||||
|
|
||||||
|
|
||||||
class Encoder(object):
|
class Encoder(object):
|
||||||
"""Takes a list of available code spaces. Picks the right one for a
|
"""Take available code spaces and pick the right one for a given character.
|
||||||
given character.
|
|
||||||
|
|
||||||
Note: To determine the code page, it needs to do the conversion, and
|
Note: To determine the code page, it needs to do the conversion, and
|
||||||
thus already knows what the final byte in the target encoding would
|
thus already knows what the final byte in the target encoding would
|
||||||
|
@ -39,20 +40,24 @@ class Encoder(object):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, codepage_map):
|
def __init__(self, codepage_map):
|
||||||
|
"""Initialize encoder."""
|
||||||
self.codepages = codepage_map
|
self.codepages = codepage_map
|
||||||
self.available_encodings = set(codepage_map.keys())
|
self.available_encodings = set(codepage_map.keys())
|
||||||
self.available_characters = {}
|
self.available_characters = {}
|
||||||
self.used_encodings = set()
|
self.used_encodings = set()
|
||||||
|
|
||||||
def get_sequence(self, encoding):
|
def get_sequence(self, encoding):
|
||||||
|
"""Get a sequence."""
|
||||||
return int(self.codepages[encoding])
|
return int(self.codepages[encoding])
|
||||||
|
|
||||||
def get_encoding_name(self, encoding):
|
def get_encoding_name(self, encoding):
|
||||||
"""Given an encoding provided by the user, will return a
|
"""Return a canonical encoding name.
|
||||||
|
|
||||||
|
Given an encoding provided by the user, will return a
|
||||||
canonical encoding name; and also validate that the encoding
|
canonical encoding name; and also validate that the encoding
|
||||||
is supported.
|
is supported.
|
||||||
|
|
||||||
TODO: Support encoding aliases: pc437 instead of cp437.
|
.. todo:: Support encoding aliases: pc437 instead of cp437.
|
||||||
"""
|
"""
|
||||||
encoding = CodePages.get_encoding_name(encoding)
|
encoding = CodePages.get_encoding_name(encoding)
|
||||||
if encoding not in self.codepages:
|
if encoding not in self.codepages:
|
||||||
|
@ -66,7 +71,7 @@ class Encoder(object):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _get_codepage_char_list(encoding):
|
def _get_codepage_char_list(encoding):
|
||||||
"""Get codepage character list
|
"""Get codepage character list.
|
||||||
|
|
||||||
Gets characters 128-255 for a given code page, as an array.
|
Gets characters 128-255 for a given code page, as an array.
|
||||||
|
|
||||||
|
@ -92,7 +97,7 @@ class Encoder(object):
|
||||||
raise LookupError("Can't find a known encoding for {}".format(encoding))
|
raise LookupError("Can't find a known encoding for {}".format(encoding))
|
||||||
|
|
||||||
def _get_codepage_char_map(self, encoding):
|
def _get_codepage_char_map(self, encoding):
|
||||||
"""Get codepage character map
|
"""Get codepage character map.
|
||||||
|
|
||||||
Process an encoding and return a map of UTF-characters to code points
|
Process an encoding and return a map of UTF-characters to code points
|
||||||
in this encoding.
|
in this encoding.
|
||||||
|
@ -130,7 +135,7 @@ class Encoder(object):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _encode_char(char, charmap, defaultchar):
|
def _encode_char(char, charmap, defaultchar):
|
||||||
"""Encode a single character with the given encoding map
|
"""Encode a single character with the given encoding map.
|
||||||
|
|
||||||
:param char: char to encode
|
:param char: char to encode
|
||||||
:param charmap: dictionary for mapping characters in this code page
|
:param charmap: dictionary for mapping characters in this code page
|
||||||
|
@ -142,7 +147,7 @@ class Encoder(object):
|
||||||
return ord(defaultchar)
|
return ord(defaultchar)
|
||||||
|
|
||||||
def encode(self, text, encoding, defaultchar="?"):
|
def encode(self, text, encoding, defaultchar="?"):
|
||||||
"""Encode text under the given encoding
|
"""Encode text under the given encoding.
|
||||||
|
|
||||||
:param text: Text to encode
|
:param text: Text to encode
|
||||||
:param encoding: Encoding name to use (must be defined in capabilities)
|
:param encoding: Encoding name to use (must be defined in capabilities)
|
||||||
|
@ -159,7 +164,9 @@ class Encoder(object):
|
||||||
return (key in self.used_encodings, index)
|
return (key in self.used_encodings, index)
|
||||||
|
|
||||||
def find_suitable_encoding(self, char):
|
def find_suitable_encoding(self, char):
|
||||||
"""The order of our search is a specific one:
|
"""Search in a specific order for a suitable encoding.
|
||||||
|
|
||||||
|
It is the following order:
|
||||||
|
|
||||||
1. code pages that we already tried before; there is a good
|
1. code pages that we already tried before; there is a good
|
||||||
chance they might work again, reducing the search space,
|
chance they might work again, reducing the search space,
|
||||||
|
@ -184,7 +191,9 @@ class Encoder(object):
|
||||||
|
|
||||||
|
|
||||||
def split_writable_text(encoder, text, encoding):
|
def split_writable_text(encoder, text, encoding):
|
||||||
"""Splits off as many characters from the beginning of text as
|
"""Split up the writable text.
|
||||||
|
|
||||||
|
Splits off as many characters from the beginning of text as
|
||||||
are writable with "encoding". Returns a 2-tuple (writable, rest).
|
are writable with "encoding". Returns a 2-tuple (writable, rest).
|
||||||
"""
|
"""
|
||||||
if not encoding:
|
if not encoding:
|
||||||
|
@ -199,7 +208,9 @@ def split_writable_text(encoder, text, encoding):
|
||||||
|
|
||||||
|
|
||||||
class MagicEncode(object):
|
class MagicEncode(object):
|
||||||
"""A helper that helps us to automatically switch to the right
|
"""Help switching to the right code page.
|
||||||
|
|
||||||
|
A helper that helps us to automatically switch to the right
|
||||||
code page to encode any given Unicode character.
|
code page to encode any given Unicode character.
|
||||||
|
|
||||||
This will consider the printers supported codepages, according
|
This will consider the printers supported codepages, according
|
||||||
|
@ -213,7 +224,7 @@ class MagicEncode(object):
|
||||||
def __init__(
|
def __init__(
|
||||||
self, driver, encoding=None, disabled=False, defaultsymbol="?", encoder=None
|
self, driver, encoding=None, disabled=False, defaultsymbol="?", encoder=None
|
||||||
):
|
):
|
||||||
"""
|
"""Initialize magic encode.
|
||||||
|
|
||||||
:param driver:
|
:param driver:
|
||||||
:param encoding: If you know the current encoding of the printer
|
:param encoding: If you know the current encoding of the printer
|
||||||
|
@ -235,7 +246,7 @@ class MagicEncode(object):
|
||||||
self.disabled = disabled
|
self.disabled = disabled
|
||||||
|
|
||||||
def force_encoding(self, encoding):
|
def force_encoding(self, encoding):
|
||||||
"""Sets a fixed encoding. The change is emitted right away.
|
"""Set a fixed encoding. The change is emitted right away.
|
||||||
|
|
||||||
From now one, this buffer will switch the code page anymore.
|
From now one, this buffer will switch the code page anymore.
|
||||||
However, it will still keep track of the current code page.
|
However, it will still keep track of the current code page.
|
||||||
|
@ -248,7 +259,6 @@ class MagicEncode(object):
|
||||||
|
|
||||||
def write(self, text):
|
def write(self, text):
|
||||||
"""Write the text, automatically switching encodings."""
|
"""Write the text, automatically switching encodings."""
|
||||||
|
|
||||||
if self.disabled:
|
if self.disabled:
|
||||||
self.write_with_encoding(self.encoding, text)
|
self.write_with_encoding(self.encoding, text)
|
||||||
return
|
return
|
||||||
|
@ -277,12 +287,16 @@ class MagicEncode(object):
|
||||||
self.write_with_encoding(encoding, to_write)
|
self.write_with_encoding(encoding, to_write)
|
||||||
|
|
||||||
def _handle_character_failed(self, char):
|
def _handle_character_failed(self, char):
|
||||||
"""Called when no codepage was found to render a character."""
|
"""Write a default symbol.
|
||||||
|
|
||||||
|
Called when no codepage was found to render a character.
|
||||||
|
"""
|
||||||
# Writing the default symbol via write() allows us to avoid
|
# Writing the default symbol via write() allows us to avoid
|
||||||
# unnecesary codepage switches.
|
# unnecesary codepage switches.
|
||||||
self.write(self.defaultsymbol)
|
self.write(self.defaultsymbol)
|
||||||
|
|
||||||
def write_with_encoding(self, encoding, text):
|
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 six.text_type:
|
||||||
raise Error(
|
raise Error(
|
||||||
"The supplied text has to be unicode, but is of type {type}.".format(
|
"The supplied text has to be unicode, but is of type {type}.".format(
|
||||||
|
|
|
@ -31,16 +31,17 @@ except ImportError:
|
||||||
|
|
||||||
_CUPSPRINT = False
|
_CUPSPRINT = False
|
||||||
try:
|
try:
|
||||||
import cups
|
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
|
import cups
|
||||||
|
|
||||||
_CUPSPRINT = True
|
_CUPSPRINT = True
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class Usb(Escpos):
|
class Usb(Escpos):
|
||||||
"""USB printer
|
"""USB printer.
|
||||||
|
|
||||||
This class describes a printer that natively speaks USB.
|
This class describes a printer that natively speaks USB.
|
||||||
|
|
||||||
|
@ -62,7 +63,8 @@ class Usb(Escpos):
|
||||||
*args,
|
*args,
|
||||||
**kwargs
|
**kwargs
|
||||||
): # noqa: N803
|
): # noqa: N803
|
||||||
"""
|
"""Initialize USB printer.
|
||||||
|
|
||||||
:param idVendor: Vendor ID
|
:param idVendor: Vendor ID
|
||||||
:param idProduct: Product ID
|
:param idProduct: Product ID
|
||||||
:param usb_args: Optional USB arguments (e.g. custom_match)
|
:param usb_args: Optional USB arguments (e.g. custom_match)
|
||||||
|
@ -122,7 +124,7 @@ class Usb(Escpos):
|
||||||
print("Could not set configuration: {0}".format(str(e)))
|
print("Could not set configuration: {0}".format(str(e)))
|
||||||
|
|
||||||
def _raw(self, msg):
|
def _raw(self, msg):
|
||||||
"""Print any command sent in raw format
|
"""Print any command sent in raw format.
|
||||||
|
|
||||||
:param msg: arbitrary code to be printed
|
:param msg: arbitrary code to be printed
|
||||||
:type msg: bytes
|
:type msg: bytes
|
||||||
|
@ -130,18 +132,18 @@ class Usb(Escpos):
|
||||||
self.device.write(self.out_ep, msg, self.timeout)
|
self.device.write(self.out_ep, msg, self.timeout)
|
||||||
|
|
||||||
def _read(self):
|
def _read(self):
|
||||||
"""Reads a data buffer and returns it to the caller."""
|
"""Read a data buffer and return it to the caller."""
|
||||||
return self.device.read(self.in_ep, 16)
|
return self.device.read(self.in_ep, 16)
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
"""Release USB interface"""
|
"""Release USB interface."""
|
||||||
if self.device:
|
if self.device:
|
||||||
usb.util.dispose_resources(self.device)
|
usb.util.dispose_resources(self.device)
|
||||||
self.device = None
|
self.device = None
|
||||||
|
|
||||||
|
|
||||||
class Serial(Escpos):
|
class Serial(Escpos):
|
||||||
"""Serial printer
|
"""Serial printer.
|
||||||
|
|
||||||
This class describes a printer that is connected by serial interface.
|
This class describes a printer that is connected by serial interface.
|
||||||
|
|
||||||
|
@ -165,7 +167,7 @@ class Serial(Escpos):
|
||||||
*args,
|
*args,
|
||||||
**kwargs
|
**kwargs
|
||||||
):
|
):
|
||||||
"""
|
"""Initialize serial printer.
|
||||||
|
|
||||||
:param devfile: Device file under dev filesystem
|
:param devfile: Device file under dev filesystem
|
||||||
:param baudrate: Baud rate for serial transmission
|
:param baudrate: Baud rate for serial transmission
|
||||||
|
@ -189,7 +191,7 @@ class Serial(Escpos):
|
||||||
self.open()
|
self.open()
|
||||||
|
|
||||||
def open(self):
|
def open(self):
|
||||||
"""Setup serial port and set is as escpos device"""
|
"""Set up serial port and set is as escpos device."""
|
||||||
if self.device is not None and self.device.is_open:
|
if self.device is not None and self.device.is_open:
|
||||||
self.close()
|
self.close()
|
||||||
self.device = serial.Serial(
|
self.device = serial.Serial(
|
||||||
|
@ -209,7 +211,7 @@ class Serial(Escpos):
|
||||||
print("Unable to open serial printer on: {0}".format(str(self.devfile)))
|
print("Unable to open serial printer on: {0}".format(str(self.devfile)))
|
||||||
|
|
||||||
def _raw(self, msg):
|
def _raw(self, msg):
|
||||||
"""Print any command sent in raw format
|
"""Print any command sent in raw format.
|
||||||
|
|
||||||
:param msg: arbitrary code to be printed
|
:param msg: arbitrary code to be printed
|
||||||
:type msg: bytes
|
:type msg: bytes
|
||||||
|
@ -217,18 +219,18 @@ class Serial(Escpos):
|
||||||
self.device.write(msg)
|
self.device.write(msg)
|
||||||
|
|
||||||
def _read(self):
|
def _read(self):
|
||||||
"""Reads a data buffer and returns it to the caller."""
|
"""Read the data buffer and return it to the caller."""
|
||||||
return self.device.read(16)
|
return self.device.read(16)
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
"""Close Serial interface"""
|
"""Close Serial interface."""
|
||||||
if self.device is not None and self.device.is_open:
|
if self.device is not None and self.device.is_open:
|
||||||
self.device.flush()
|
self.device.flush()
|
||||||
self.device.close()
|
self.device.close()
|
||||||
|
|
||||||
|
|
||||||
class Network(Escpos):
|
class Network(Escpos):
|
||||||
"""Network printer
|
"""Network printer.
|
||||||
|
|
||||||
This class is used to attach to a networked printer. You can also use this in order to attach to a printer that
|
This class is used to attach to a networked printer. You can also use this in order to attach to a printer that
|
||||||
is forwarded with ``socat``.
|
is forwarded with ``socat``.
|
||||||
|
@ -251,7 +253,7 @@ class Network(Escpos):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, host, port=9100, timeout=60, *args, **kwargs):
|
def __init__(self, host, port=9100, timeout=60, *args, **kwargs):
|
||||||
"""
|
"""Initialize network printer.
|
||||||
|
|
||||||
:param host: Printer's hostname or IP address
|
:param host: Printer's hostname or IP address
|
||||||
:param port: Port to write to
|
:param port: Port to write to
|
||||||
|
@ -264,7 +266,7 @@ class Network(Escpos):
|
||||||
self.open()
|
self.open()
|
||||||
|
|
||||||
def open(self):
|
def open(self):
|
||||||
"""Open TCP socket with ``socket``-library and set it as escpos device"""
|
"""Open TCP socket with ``socket``-library and set it as escpos device."""
|
||||||
self.device = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
self.device = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
self.device.settimeout(self.timeout)
|
self.device.settimeout(self.timeout)
|
||||||
self.device.connect((self.host, self.port))
|
self.device.connect((self.host, self.port))
|
||||||
|
@ -273,7 +275,7 @@ class Network(Escpos):
|
||||||
print("Could not open socket for {0}".format(self.host))
|
print("Could not open socket for {0}".format(self.host))
|
||||||
|
|
||||||
def _raw(self, msg):
|
def _raw(self, msg):
|
||||||
"""Print any command sent in raw format
|
"""Print any command sent in raw format.
|
||||||
|
|
||||||
:param msg: arbitrary code to be printed
|
:param msg: arbitrary code to be printed
|
||||||
:type msg: bytes
|
:type msg: bytes
|
||||||
|
@ -281,12 +283,11 @@ class Network(Escpos):
|
||||||
self.device.sendall(msg)
|
self.device.sendall(msg)
|
||||||
|
|
||||||
def _read(self):
|
def _read(self):
|
||||||
"""Read data from the TCP socket"""
|
"""Read data from the TCP socket."""
|
||||||
|
|
||||||
return self.device.recv(16)
|
return self.device.recv(16)
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
"""Close TCP connection"""
|
"""Close TCP connection."""
|
||||||
if self.device is not None:
|
if self.device is not None:
|
||||||
try:
|
try:
|
||||||
self.device.shutdown(socket.SHUT_RDWR)
|
self.device.shutdown(socket.SHUT_RDWR)
|
||||||
|
@ -296,7 +297,7 @@ class Network(Escpos):
|
||||||
|
|
||||||
|
|
||||||
class File(Escpos):
|
class File(Escpos):
|
||||||
"""Generic file printer
|
"""Generic file printer.
|
||||||
|
|
||||||
This class is used for parallel port printer or other printers that are directly attached to the filesystem.
|
This class is used for parallel port printer or other printers that are directly attached to the filesystem.
|
||||||
Note that you should stay away from using USB-to-Parallel-Adapter since they are unreliable
|
Note that you should stay away from using USB-to-Parallel-Adapter since they are unreliable
|
||||||
|
@ -310,7 +311,7 @@ class File(Escpos):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, devfile="/dev/usb/lp0", auto_flush=True, *args, **kwargs):
|
def __init__(self, devfile="/dev/usb/lp0", auto_flush=True, *args, **kwargs):
|
||||||
"""
|
"""Initialize file printer with device file.
|
||||||
|
|
||||||
:param devfile: Device file under dev filesystem
|
:param devfile: Device file under dev filesystem
|
||||||
:param auto_flush: automatically call flush after every call of _raw()
|
:param auto_flush: automatically call flush after every call of _raw()
|
||||||
|
@ -321,18 +322,18 @@ class File(Escpos):
|
||||||
self.open()
|
self.open()
|
||||||
|
|
||||||
def open(self):
|
def open(self):
|
||||||
"""Open system file"""
|
"""Open system file."""
|
||||||
self.device = open(self.devfile, "wb")
|
self.device = open(self.devfile, "wb")
|
||||||
|
|
||||||
if self.device is None:
|
if self.device is None:
|
||||||
print("Could not open the specified file {0}".format(self.devfile))
|
print("Could not open the specified file {0}".format(self.devfile))
|
||||||
|
|
||||||
def flush(self):
|
def flush(self):
|
||||||
"""Flush printing content"""
|
"""Flush printing content."""
|
||||||
self.device.flush()
|
self.device.flush()
|
||||||
|
|
||||||
def _raw(self, msg):
|
def _raw(self, msg):
|
||||||
"""Print any command sent in raw format
|
"""Print any command sent in raw format.
|
||||||
|
|
||||||
:param msg: arbitrary code to be printed
|
:param msg: arbitrary code to be printed
|
||||||
:type msg: bytes
|
:type msg: bytes
|
||||||
|
@ -342,14 +343,14 @@ class File(Escpos):
|
||||||
self.flush()
|
self.flush()
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
"""Close system file"""
|
"""Close system file."""
|
||||||
if self.device is not None:
|
if self.device is not None:
|
||||||
self.device.flush()
|
self.device.flush()
|
||||||
self.device.close()
|
self.device.close()
|
||||||
|
|
||||||
|
|
||||||
class Dummy(Escpos):
|
class Dummy(Escpos):
|
||||||
"""Dummy printer
|
"""Dummy printer.
|
||||||
|
|
||||||
This class is used for saving commands to a variable, for use in situations where
|
This class is used for saving commands to a variable, for use in situations where
|
||||||
there is no need to send commands to an actual printer. This includes
|
there is no need to send commands to an actual printer. This includes
|
||||||
|
@ -363,12 +364,12 @@ class Dummy(Escpos):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
""" """
|
"""Init with empty output list."""
|
||||||
Escpos.__init__(self, *args, **kwargs)
|
Escpos.__init__(self, *args, **kwargs)
|
||||||
self._output_list = []
|
self._output_list = []
|
||||||
|
|
||||||
def _raw(self, msg):
|
def _raw(self, msg):
|
||||||
"""Print any command sent in raw format
|
"""Print any command sent in raw format.
|
||||||
|
|
||||||
:param msg: arbitrary code to be printed
|
:param msg: arbitrary code to be printed
|
||||||
:type msg: bytes
|
:type msg: bytes
|
||||||
|
@ -377,11 +378,11 @@ class Dummy(Escpos):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def output(self):
|
def output(self):
|
||||||
"""Get the data that was sent to this printer"""
|
"""Get the data that was sent to this printer."""
|
||||||
return b"".join(self._output_list)
|
return b"".join(self._output_list)
|
||||||
|
|
||||||
def clear(self):
|
def clear(self):
|
||||||
"""Clear the buffer of the printer
|
"""Clear the buffer of the printer.
|
||||||
|
|
||||||
This method can be called if you send the contents to a physical printer
|
This method can be called if you send the contents to a physical printer
|
||||||
and want to use the Dummy printer for new output.
|
and want to use the Dummy printer for new output.
|
||||||
|
@ -389,13 +390,20 @@ class Dummy(Escpos):
|
||||||
del self._output_list[:]
|
del self._output_list[:]
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
|
"""Close not implemented for Dummy printer."""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
if _WIN32PRINT:
|
if _WIN32PRINT:
|
||||||
|
|
||||||
class Win32Raw(Escpos):
|
class Win32Raw(Escpos):
|
||||||
|
"""Printer binding for win32 API.
|
||||||
|
|
||||||
|
Uses the module pywin32 for printing.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, printer_name=None, *args, **kwargs):
|
def __init__(self, printer_name=None, *args, **kwargs):
|
||||||
|
"""Initialize default printer."""
|
||||||
Escpos.__init__(self, *args, **kwargs)
|
Escpos.__init__(self, *args, **kwargs)
|
||||||
if printer_name is not None:
|
if printer_name is not None:
|
||||||
self.printer_name = printer_name
|
self.printer_name = printer_name
|
||||||
|
@ -405,6 +413,7 @@ if _WIN32PRINT:
|
||||||
self.open()
|
self.open()
|
||||||
|
|
||||||
def open(self, job_name="python-escpos"):
|
def open(self, job_name="python-escpos"):
|
||||||
|
"""Open connection to default printer."""
|
||||||
if self.printer_name is None:
|
if self.printer_name is None:
|
||||||
raise Exception("Printer not found")
|
raise Exception("Printer not found")
|
||||||
self.hPrinter = win32print.OpenPrinter(self.printer_name)
|
self.hPrinter = win32print.OpenPrinter(self.printer_name)
|
||||||
|
@ -414,6 +423,7 @@ if _WIN32PRINT:
|
||||||
win32print.StartPagePrinter(self.hPrinter)
|
win32print.StartPagePrinter(self.hPrinter)
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
|
"""Close connection to default printer."""
|
||||||
if not self.hPrinter:
|
if not self.hPrinter:
|
||||||
return
|
return
|
||||||
win32print.EndPagePrinter(self.hPrinter)
|
win32print.EndPagePrinter(self.hPrinter)
|
||||||
|
@ -422,7 +432,7 @@ if _WIN32PRINT:
|
||||||
self.hPrinter = None
|
self.hPrinter = None
|
||||||
|
|
||||||
def _raw(self, msg):
|
def _raw(self, msg):
|
||||||
"""Print any command sent in raw format
|
"""Print any command sent in raw format.
|
||||||
|
|
||||||
:param msg: arbitrary code to be printed
|
:param msg: arbitrary code to be printed
|
||||||
:type msg: bytes
|
:type msg: bytes
|
||||||
|
@ -448,7 +458,7 @@ if _CUPSPRINT:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, printer_name=None, *args, **kwargs):
|
def __init__(self, printer_name=None, *args, **kwargs):
|
||||||
"""CupsPrinter class constructor.
|
"""Class constructor for CupsPrinter.
|
||||||
|
|
||||||
:param printer_name: CUPS printer name (Optional)
|
:param printer_name: CUPS printer name (Optional)
|
||||||
:type printer_name: str
|
:type printer_name: str
|
||||||
|
@ -477,7 +487,7 @@ if _CUPSPRINT:
|
||||||
return self.conn.getPrinters()
|
return self.conn.getPrinters()
|
||||||
|
|
||||||
def open(self, job_name="python-escpos"):
|
def open(self, job_name="python-escpos"):
|
||||||
"""Setup a new print job and target printer.
|
"""Set up a new print job and target the printer.
|
||||||
|
|
||||||
A call to this method is required to send new jobs to
|
A call to this method is required to send new jobs to
|
||||||
the same CUPS connection.
|
the same CUPS connection.
|
||||||
|
@ -491,7 +501,7 @@ if _CUPSPRINT:
|
||||||
self.tmpfile = tempfile.NamedTemporaryFile(delete=True)
|
self.tmpfile = tempfile.NamedTemporaryFile(delete=True)
|
||||||
|
|
||||||
def _raw(self, msg):
|
def _raw(self, msg):
|
||||||
"""Append any command sent in raw format to temporary file
|
"""Append any command sent in raw format to temporary file.
|
||||||
|
|
||||||
:param msg: arbitrary code to be printed
|
:param msg: arbitrary code to be printed
|
||||||
:type msg: bytes
|
:type msg: bytes
|
||||||
|
@ -582,7 +592,7 @@ if not sys.platform.startswith("win"):
|
||||||
self.lp.terminate()
|
self.lp.terminate()
|
||||||
|
|
||||||
def flush(self):
|
def flush(self):
|
||||||
"""End line and wait for new commands"""
|
"""End line and wait for new commands."""
|
||||||
if self.lp.stdin.writable():
|
if self.lp.stdin.writable():
|
||||||
self.lp.stdin.write(b"\n")
|
self.lp.stdin.write(b"\n")
|
||||||
if self.lp.stdin.closed is False:
|
if self.lp.stdin.closed is False:
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from escpos.printer import Dummy
|
from escpos.printer import Dummy
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,18 @@
|
||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
"""verifies that the metaclass abc is properly used by ESC/POS
|
"""verifies that the metaclass abc is properly used by ESC/POS
|
||||||
|
|
||||||
:author: `Patrick Kanzler <patrick.kanzler@fablab.fau.de>`_
|
:author: `Patrick Kanzler <dev@pkanzler.de>`_
|
||||||
:organization: `python-escpos <https://github.com/python-escpos>`_
|
:organization: `python-escpos <https://github.com/python-escpos>`_
|
||||||
:copyright: Copyright (c) 2016 Patrick Kanzler
|
:copyright: Copyright (c) 2016 Patrick Kanzler
|
||||||
:license: MIT
|
:license: MIT
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import pytest
|
|
||||||
import escpos.escpos as escpos
|
|
||||||
from abc import ABCMeta
|
from abc import ABCMeta
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
import escpos.escpos as escpos
|
||||||
|
|
||||||
|
|
||||||
def test_abstract_base_class_raises():
|
def test_abstract_base_class_raises():
|
||||||
"""test whether the abstract base class raises an exception for ESC/POS"""
|
"""test whether the abstract base class raises an exception for ESC/POS"""
|
||||||
|
|
|
@ -4,10 +4,12 @@
|
||||||
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import shutil
|
||||||
|
import tempfile
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from scripttest import TestFileEnvironment as TFE
|
from scripttest import TestFileEnvironment as TFE
|
||||||
import tempfile
|
|
||||||
import shutil
|
|
||||||
import escpos
|
import escpos
|
||||||
|
|
||||||
TEST_DIR = tempfile.mkdtemp() + "/cli-test"
|
TEST_DIR = tempfile.mkdtemp() + "/cli-test"
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
|
|
||||||
import escpos.printer as printer
|
|
||||||
from escpos.capabilities import Profile, BARCODE_B
|
|
||||||
from escpos.exceptions import BarcodeTypeError, BarcodeCodeError
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
import escpos.printer as printer
|
||||||
|
from escpos.capabilities import BARCODE_B, Profile
|
||||||
|
from escpos.exceptions import BarcodeCodeError, BarcodeTypeError
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"bctype,data,expected",
|
"bctype,data,expected",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import six
|
|
||||||
import pytest
|
import pytest
|
||||||
|
import six
|
||||||
|
|
||||||
from escpos import printer
|
from escpos import printer
|
||||||
from escpos.constants import BUZZER
|
from escpos.constants import BUZZER
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
import escpos.printer as printer
|
import escpos.printer as printer
|
||||||
from escpos.exceptions import CashDrawerError
|
from escpos.exceptions import CashDrawerError
|
||||||
import pytest
|
|
||||||
|
|
||||||
|
|
||||||
def test_raise_CashDrawerError():
|
def test_raise_CashDrawerError():
|
||||||
|
|
|
@ -2,9 +2,10 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
|
||||||
import escpos.printer as printer
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
import escpos.printer as printer
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"bctype,data",
|
"bctype,data",
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
import escpos.printer as printer
|
import escpos.printer as printer
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
"""tests for line display
|
"""tests for line display
|
||||||
|
|
||||||
:author: `Patrick Kanzler <patrick.kanzler@fablab.fau.de>`_
|
:author: `Patrick Kanzler <dev@pkanzler.de>`_
|
||||||
:organization: `python-escpos <https://github.com/python-escpos>`_
|
:organization: `python-escpos <https://github.com/python-escpos>`_
|
||||||
:copyright: Copyright (c) 2017 `python-escpos <https://github.com/python-escpos>`_
|
:copyright: Copyright (c) 2017 `python-escpos <https://github.com/python-escpos>`_
|
||||||
:license: MIT
|
:license: MIT
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
"""tests for panel button function
|
"""tests for panel button function
|
||||||
|
|
||||||
:author: `Patrick Kanzler <patrick.kanzler@fablab.fau.de>`_
|
:author: `Patrick Kanzler <dev@pkanzler.de>`_
|
||||||
:organization: `python-escpos <https://github.com/python-escpos>`_
|
:organization: `python-escpos <https://github.com/python-escpos>`_
|
||||||
:copyright: Copyright (c) 2016 `python-escpos <https://github.com/python-escpos>`_
|
:copyright: Copyright (c) 2016 `python-escpos <https://github.com/python-escpos>`_
|
||||||
:license: MIT
|
:license: MIT
|
||||||
|
|
|
@ -2,18 +2,18 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""tests for the non-native part of qr()
|
"""tests for the non-native part of qr()
|
||||||
|
|
||||||
:author: `Patrick Kanzler <patrick.kanzler@fablab.fau.de>`_
|
:author: `Patrick Kanzler <dev@pkanzler.de>`_
|
||||||
:organization: `python-escpos <https://github.com/python-escpos>`_
|
:organization: `python-escpos <https://github.com/python-escpos>`_
|
||||||
:copyright: Copyright (c) 2016 `python-escpos <https://github.com/python-escpos>`_
|
:copyright: Copyright (c) 2016 `python-escpos <https://github.com/python-escpos>`_
|
||||||
:license: MIT
|
:license: MIT
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
import pytest
|
|
||||||
import mock
|
import mock
|
||||||
|
import pytest
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
from escpos.printer import Dummy
|
from escpos.printer import Dummy
|
||||||
from PIL import Image
|
|
||||||
|
|
||||||
|
|
||||||
@mock.patch("escpos.printer.Dummy.image", spec=Dummy)
|
@mock.patch("escpos.printer.Dummy.image", spec=Dummy)
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
import six
|
import six
|
||||||
|
|
||||||
import escpos.printer as printer
|
import escpos.printer as printer
|
||||||
from escpos.constants import TXT_NORMAL, TXT_STYLE, SET_FONT
|
from escpos.constants import SET_FONT, TXT_NORMAL, TXT_SIZE, TXT_STYLE
|
||||||
from escpos.constants import TXT_SIZE
|
|
||||||
|
|
||||||
|
|
||||||
# Default test, please copy and paste this block to test set method calls
|
# Default test, please copy and paste this block to test set method calls
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
|
|
||||||
import escpos.printer as printer
|
|
||||||
import barcode.errors
|
import barcode.errors
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
import escpos.printer as printer
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def instance():
|
def instance():
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
"""tests for the text printing function
|
"""tests for the text printing function
|
||||||
|
|
||||||
:author: `Patrick Kanzler <patrick.kanzler@fablab.fau.de>`_
|
:author: `Patrick Kanzler <dev@pkanzler.de>`_
|
||||||
:organization: `python-escpos <https://github.com/python-escpos>`_
|
:organization: `python-escpos <https://github.com/python-escpos>`_
|
||||||
:copyright: Copyright (c) 2016 `python-escpos <https://github.com/python-escpos>`_
|
:copyright: Copyright (c) 2016 `python-escpos <https://github.com/python-escpos>`_
|
||||||
:license: MIT
|
:license: MIT
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
import pytest
|
|
||||||
import mock
|
|
||||||
from hypothesis import given, assume
|
|
||||||
import hypothesis.strategies as st
|
import hypothesis.strategies as st
|
||||||
|
import mock
|
||||||
|
import pytest
|
||||||
|
from hypothesis import assume, given
|
||||||
|
|
||||||
from escpos.printer import Dummy
|
from escpos.printer import Dummy
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from escpos.printer import Dummy
|
from escpos.printer import Dummy
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
"""very basic test cases that load the classes
|
"""very basic test cases that load the classes
|
||||||
|
|
||||||
:author: `Patrick Kanzler <patrick.kanzler@fablab.fau.de>`_
|
:author: `Patrick Kanzler <dev@pkanzler.de>`_
|
||||||
:organization: `python-escpos <https://github.com/python-escpos>`_
|
:organization: `python-escpos <https://github.com/python-escpos>`_
|
||||||
:copyright: Copyright (c) 2016 `python-escpos <https://github.com/python-escpos>`_
|
:copyright: Copyright (c) 2016 `python-escpos <https://github.com/python-escpos>`_
|
||||||
:license: MIT
|
:license: MIT
|
||||||
|
|
|
@ -2,19 +2,20 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""tests for the magic encode module
|
"""tests for the magic encode module
|
||||||
|
|
||||||
:author: `Patrick Kanzler <patrick.kanzler@fablab.fau.de>`_
|
:author: `Patrick Kanzler <dev@pkanzler.de>`_
|
||||||
:organization: `python-escpos <https://github.com/python-escpos>`_
|
:organization: `python-escpos <https://github.com/python-escpos>`_
|
||||||
:copyright: Copyright (c) 2016 `python-escpos <https://github.com/python-escpos>`_
|
:copyright: Copyright (c) 2016 `python-escpos <https://github.com/python-escpos>`_
|
||||||
:license: MIT
|
:license: MIT
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
import pytest
|
|
||||||
from hypothesis import given, example
|
|
||||||
import hypothesis.strategies as st
|
import hypothesis.strategies as st
|
||||||
from escpos.magicencode import MagicEncode, Encoder
|
import pytest
|
||||||
from escpos.katakana import encode_katakana
|
from hypothesis import example, given
|
||||||
|
|
||||||
from escpos.exceptions import CharCodeError, Error
|
from escpos.exceptions import CharCodeError, Error
|
||||||
|
from escpos.katakana import encode_katakana
|
||||||
|
from escpos.magicencode import Encoder, MagicEncode
|
||||||
|
|
||||||
|
|
||||||
class TestEncoder:
|
class TestEncoder:
|
||||||
|
|
|
@ -2,16 +2,15 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""tests for the File printer
|
"""tests for the File printer
|
||||||
|
|
||||||
:author: `Patrick Kanzler <patrick.kanzler@fablab.fau.de>`_
|
:author: `Patrick Kanzler <dev@pkanzler.de>`_
|
||||||
:organization: `python-escpos <https://github.com/python-escpos>`_
|
:organization: `python-escpos <https://github.com/python-escpos>`_
|
||||||
:copyright: Copyright (c) 2016 `python-escpos <https://github.com/python-escpos>`_
|
:copyright: Copyright (c) 2016 `python-escpos <https://github.com/python-escpos>`_
|
||||||
:license: MIT
|
:license: MIT
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
import six
|
||||||
from hypothesis import given, settings
|
from hypothesis import given, settings
|
||||||
from hypothesis.strategies import text
|
from hypothesis.strategies import text
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
|
|
||||||
import escpos.printer as printer
|
|
||||||
import pytest
|
|
||||||
import mock
|
|
||||||
import socket
|
import socket
|
||||||
|
|
||||||
|
import mock
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
import escpos.printer as printer
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def instance():
|
def instance():
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import pytest
|
import pytest
|
||||||
from escpos.capabilities import get_profile, NotSupported, BARCODE_B, Profile
|
|
||||||
|
from escpos.capabilities import BARCODE_B, NotSupported, Profile, get_profile
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
"""test the raising of errors with the error module
|
"""test the raising of errors with the error module
|
||||||
|
|
||||||
:author: `Patrick Kanzler <patrick.kanzler@fablab.fau.de>`_
|
:author: `Patrick Kanzler <dev@pkanzler.de>`_
|
||||||
:organization: `python-escpos <https://github.com/python-escpos>`_
|
:organization: `python-escpos <https://github.com/python-escpos>`_
|
||||||
:copyright: Copyright (c) 2017 `python-escpos <https://github.com/python-escpos>`_
|
:copyright: Copyright (c) 2017 `python-escpos <https://github.com/python-escpos>`_
|
||||||
:license: MIT
|
:license: MIT
|
||||||
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import escpos
|
import escpos
|
||||||
import escpos.exceptions
|
import escpos.exceptions
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,21 @@
|
||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
"""test the facility which enables usage of the with-statement
|
"""test the facility which enables usage of the with-statement
|
||||||
|
|
||||||
:author: `Patrick Kanzler <patrick.kanzler@fablab.fau.de>`_
|
:author: `Patrick Kanzler <dev@pkanzler.de>`_
|
||||||
:organization: `python-escpos <https://github.com/python-escpos>`_
|
:organization: `python-escpos <https://github.com/python-escpos>`_
|
||||||
:copyright: Copyright (c) 2016 `python-escpos <https://github.com/python-escpos>`_
|
:copyright: Copyright (c) 2016 `python-escpos <https://github.com/python-escpos>`_
|
||||||
:license: MIT
|
:license: MIT
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
import escpos.printer as printer
|
|
||||||
import escpos.escpos as escpos
|
import escpos.escpos as escpos
|
||||||
|
import escpos.printer as printer
|
||||||
|
|
||||||
|
|
||||||
def test_with_statement():
|
def test_with_statement():
|
||||||
"""Use with statement"""
|
"""Use with statement
|
||||||
|
|
||||||
|
.. todo:: Extend these tests as they don't really do anything at the moment"""
|
||||||
dummy_printer = printer.Dummy()
|
dummy_printer = printer.Dummy()
|
||||||
with escpos.EscposIO(dummy_printer) as p:
|
with escpos.EscposIO(dummy_printer) as p:
|
||||||
p.writelines("Some text.\n")
|
p.writelines("Some text.\n")
|
||||||
# TODO extend these tests as they don't really do anything at the moment
|
|
||||||
|
|
16
tox.ini
16
tox.ini
|
@ -22,8 +22,9 @@ deps = jaconv
|
||||||
pytest-mock
|
pytest-mock
|
||||||
hypothesis>4
|
hypothesis>4
|
||||||
python-barcode
|
python-barcode
|
||||||
commands = pytest --cov escpos --cov-report=xml
|
commands = pytest
|
||||||
passenv = ESCPOS_CAPABILITIES_PICKLE_DIR, ESCPOS_CAPABILITIES_FILE, CI, TRAVIS, TRAVIS_*, APPVEYOR, APPVEYOR_*, CODECOV_*
|
passenv = ESCPOS_CAPABILITIES_PICKLE_DIR, ESCPOS_CAPABILITIES_FILE, CI, TRAVIS, TRAVIS_*, APPVEYOR, APPVEYOR_*, CODECOV_*
|
||||||
|
setenv = PY_IGNORE_IMPORTMISMATCH=1
|
||||||
|
|
||||||
[testenv:docs]
|
[testenv:docs]
|
||||||
basepython = python
|
basepython = python
|
||||||
|
@ -39,7 +40,16 @@ commands = sphinx-build -W -b html -d {envtmpdir}/doctrees . {envtmpdir}/html
|
||||||
|
|
||||||
[testenv:flake8]
|
[testenv:flake8]
|
||||||
basepython = python
|
basepython = python
|
||||||
# TODO add flake8-future
|
|
||||||
# TODO add flake8-docstrings
|
|
||||||
deps = flake8
|
deps = flake8
|
||||||
|
flake8-docstrings
|
||||||
commands = flake8
|
commands = flake8
|
||||||
|
|
||||||
|
[testenv:mypy]
|
||||||
|
basepython = python
|
||||||
|
deps = mypy
|
||||||
|
types-six
|
||||||
|
types-PyYAML
|
||||||
|
types-appdirs
|
||||||
|
types-Pillow
|
||||||
|
jaconv
|
||||||
|
commands = mypy src
|
||||||
|
|
Loading…
Reference in New Issue