Compare commits

...

6 Commits

Author SHA1 Message Date
Patrick Kanzler 4d479337d3
other minor problems 2018-05-16 02:15:52 +02:00
Patrick Kanzler 87b33367c0
add magic coding comment 2018-05-16 02:02:35 +02:00
Patrick Kanzler 594ab83fc3
cleanup imports, second part 2018-05-16 01:57:37 +02:00
Patrick Kanzler 9b8e56cd59
cleanup imports, first part 2018-05-16 01:23:04 +02:00
Patrick Kanzler c0af9aaaf4
remove bad quotes 2018-05-16 01:09:48 +02:00
Patrick Kanzler 18e4c1b0ac
add new flake8-plugins and revise config 2018-05-16 00:34:45 +02:00
21 changed files with 265 additions and 194 deletions

View File

@ -59,9 +59,9 @@ The basic usage is:
from escpos.printer import Usb
""" Seiko Epson Corp. Receipt Printer (EPSON TM-T88III) """
p = Usb(0x04b8, 0x0202, 0, profile="TM-T88III")
p.text("Hello World\n")
p.image("logo.gif")
p = Usb(0x04b8, 0x0202, 0, profile='TM-T88III')
p.text('Hello World\n')
p.image('logo.gif')
p.barcode('1324354657687', 'EAN13', 64, 2, '', '')
p.cut()

View File

@ -67,7 +67,7 @@ IP by DHCP or you set it manually.
::
Epson = printer.Network("192.168.1.99")
Epson = printer.Network('192.168.1.99')
Serial printer
^^^^^^^^^^^^^^
@ -81,7 +81,7 @@ to.
::
Epson = printer.Serial("/dev/tty0")
Epson = printer.Serial('/dev/tty0')
Other printers
^^^^^^^^^^^^^^
@ -93,7 +93,7 @@ passing the device node name.
::
Epson = printer.File("/dev/usb/lp1")
Epson = printer.File('/dev/usb/lp1')
The default is "/dev/usb/lp0", so if the printer is located on that
node, then you don't necessary need to pass the node name.
@ -110,11 +110,11 @@ on a USB interface.
""" Seiko Epson Corp. Receipt Printer M129 Definitions (EPSON TM-T88IV) """
Epson = printer.Usb(0x04b8,0x0202)
# Print text
Epson.text("Hello World\n")
Epson.text('Hello World\n')
# Print image
Epson.image("logo.gif")
Epson.image('logo.gif')
# Print QR Code
Epson.qr("You can readme from your smartphone")
Epson.qr('You can readme from your smartphone')
# Print barcode
Epson.barcode('1324354657687','EAN13',64,2,'','')
# Cut paper
@ -214,7 +214,7 @@ advantage of the fact that `_raw()` accepts binary strings.)
from escpos import printer
p = printer.Serial() # adapt this to your printer model
file = open("binary-blob.bin", "rb") # read in the file containing your commands in binary-mode
file = open('binary-blob.bin', 'rb') # read in the file containing your commands in binary-mode
data = file.read()
file.close()
@ -273,8 +273,8 @@ This is probably best explained by an example:
d = Dummy()
# create ESC/POS for the print job, this should go really fast
d.text("This is my image:\n")
d.image("funny_cat.png")
d.text('This is my image:\n')
d.image('funny_cat.png')
d.cut()
# send code to printer

View File

@ -1,8 +1,14 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from escpos.printer import Usb
# Adapt to your needs
p = Usb(0x0416, 0x5011, profile="POS-5890")
p = Usb(0x0416, 0x5011, profile='POS-5890')
# Print software and then hardware barcode with the same content
p.soft_barcode('code39', '123456')

View File

@ -1,13 +1,17 @@
# -*- coding: utf-8 -*-
"""Prints code page tables.
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import six
import sys
from escpos import printer
from escpos.constants import CODEPAGE_CHANGE, ESC, CTL_LF, CTL_FF, CTL_CR, CTL_HT, CTL_VT
from escpos.constants import CODEPAGE_CHANGE, CTL_CR, CTL_FF, CTL_HT, CTL_LF, CTL_VT, ESC
import six
def main():
@ -17,9 +21,9 @@ def main():
for codepage in sys.argv[1:] or ['USA']:
dummy.set(height=2, width=2)
dummy._raw(codepage + "\n\n\n")
dummy._raw(codepage + '\n\n\n')
print_codepage(dummy, codepage)
dummy._raw("\n\n")
dummy._raw('\n\n')
dummy.cut()
@ -30,22 +34,22 @@ def print_codepage(printer, codepage):
if codepage.isdigit():
codepage = int(codepage)
printer._raw(CODEPAGE_CHANGE + six.int2byte(codepage))
printer._raw("after")
printer._raw('after')
else:
printer.charcode(codepage)
sep = ""
sep = ''
# Table header
printer.set(font='b')
printer._raw(" {}\n".format(sep.join(map(lambda s: hex(s)[2:], range(0, 16)))))
printer._raw(' {}\n'.format(sep.join(map(lambda s: hex(s)[2:], range(0, 16)))))
printer.set()
# The table
for x in range(0, 16):
# First column
printer.set(font='b')
printer._raw("{} ".format(hex(x)[2:]))
printer._raw('{} '.format(hex(x)[2:]))
printer.set()
for y in range(0, 16):

View File

@ -1,10 +1,16 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import sys
from escpos.printer import Usb
def usage():
print("usage: qr_code.py <content>")
print('usage: qr_code.py <content>')
if __name__ == '__main__':
@ -15,5 +21,5 @@ if __name__ == '__main__':
content = sys.argv[1]
# Adapt to your needs
p = Usb(0x0416, 0x5011, profile="POS-5890")
p = Usb(0x0416, 0x5011, profile='POS-5890')
p.qr(content, center=True)

View File

@ -1,8 +1,14 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from escpos.printer import Usb
# Adapt to your needs
p = Usb(0x0416, 0x5011, profile="POS-5890")
p = Usb(0x0416, 0x5011, profile='POS-5890')
# Some software barcodes
p.soft_barcode('code128', 'Hello')

View File

@ -1,5 +1,5 @@
#!/usr/bin/python
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Adapted script from Adafruit
# Weather forecast for Raspberry Pi w/Adafruit Mini Thermal Printer.
@ -12,35 +12,38 @@
# Icons taken from http://adamwhitcroft.com/climacons/
# Check out his github: https://github.com/AdamWhitcroft/climacons
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from datetime import datetime
from __future__ import unicode_literals
import calendar
import urllib
import json
import time
import os
import time
import urllib
from datetime import datetime
from escpos.printer import Usb
""" Setting up the main pathing """
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/')
# Adapt to your needs
printer = Usb(0x0416, 0x5011, profile="POS-5890")
printer = Usb(0x0416, 0x5011, profile='POS-5890')
# You can get your API Key on www.darksky.net and register a dev account.
# Technically you can use any other weather service, of course :)
API_KEY = "YOUR API KEY"
API_KEY = 'YOUR API KEY'
LAT = "22.345490" # Your Location
LONG = "114.189945" # Your Location
LAT = '22.345490' # Your Location
LONG = '114.189945' # Your Location
def forecast_icon(idx):
icon = data['daily']['data'][idx]['icon']
image = GRAPHICS_PATH + icon + ".png"
image = GRAPHICS_PATH + icon + '.png'
return image
@ -80,23 +83,23 @@ def forecast(idx):
def icon():
icon = data['currently']['icon']
image = GRAPHICS_PATH + icon + ".png"
image = GRAPHICS_PATH + icon + '.png'
return image
deg = ' C' # Degree symbol on thermal printer, need to find a better way to use a proper degree symbol
# if you want Fahrenheit change units= to 'us'
url = "https://api.darksky.net/forecast/" + API_KEY + "/" + LAT + "," + LONG + \
"?exclude=[alerts,minutely,hourly,flags]&units=si" # change last bit to 'us' for Fahrenheit
url = 'https://api.darksky.net/forecast/' + API_KEY + '/' + LAT + ',' + LONG + \
'?exclude=[alerts,minutely,hourly,flags]&units=si' # change last bit to 'us' for Fahrenheit
response = urllib.urlopen(url)
data = json.loads(response.read())
printer.print_and_feed(n=1)
printer.control("LF")
printer.control('LF')
printer.set(font='a', height=2, align='center', bold=True, double_height=True)
printer.text("Weather Forecast")
printer.text("\n")
printer.text('Weather Forecast')
printer.text('\n')
printer.set(align='center')
@ -104,7 +107,7 @@ printer.set(align='center')
printer.set(font='a', height=2, align='center', bold=True, double_height=False)
printer.text('Current conditions: \n')
printer.image(icon())
printer.text("\n")
printer.text('\n')
printer.set(font='a', height=2, align='left', bold=False, double_height=False)
temp = data['currently']['temperature']
@ -124,4 +127,4 @@ printer.text('Forecast: \n')
forecast(0)
forecast(1)
printer.cut()
printer.control("LF")
printer.control('LF')

View File

@ -9,4 +9,13 @@ universal=1
[flake8]
exclude = .git,.tox,.github,.eggs,__pycache__,doc/conf.py,build,dist,capabilities-data,test,src/escpos/constants.py
max-line-length = 120
# future-imports = absolute_import, division, print_function, unicode_literals # we are not there yet
accept-encoding = utf-8, utf-16
require-code = True
# FI12 __future__ import "with_statement" missing
# FI15 __future__ import "generator_stop" missing
# FI16 __future__ import "nested_scopes" missing
# FI17 __future__ import "generators" missing
# FI5x __future__ import "xxx" present
# I101 Imported names are in the wrong order.
ignore = FI12,FI15,FI16,FI17,FI5, I101
copyright-check = True

View File

@ -1,12 +1,19 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
# from __future__ import unicode_literals
import os
import sys
from setuptools import find_packages, setup
base_dir = os.path.dirname(__file__)
src_dir = os.path.join(base_dir, "src")
src_dir = os.path.join(base_dir, 'src')
# When executing the setup.py, we need to be able to import ourselves, this
# means that we need to add the src/ directory to the sys.path.
@ -54,8 +61,8 @@ setup(
'receipt,',
],
platforms='any',
package_dir={"": "src"},
packages=find_packages(where="src", exclude=["tests", "tests.*"]),
package_dir={'': 'src'},
packages=find_packages(where='src', exclude=['tests', 'tests.*']),
package_data={'': ['COPYING', 'src/escpos/capabilities.json']},
include_package_data=True,
classifiers=[

View File

@ -7,7 +7,7 @@ from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
__all__ = ["constants", "escpos", "exceptions", "printer"]
__all__ = ['constants', 'escpos', 'exceptions', 'printer']
try:
from .version import version as __version__ # noqa

View File

@ -1,14 +1,22 @@
import re
from os import environ, path
import pickle
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import logging
import pickle
import platform
import re
import time
from os import environ, path
from tempfile import gettempdir
import six
import yaml
from tempfile import gettempdir
import platform
import yaml
logging.basicConfig()
logger = logging.getLogger(__name__)

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# PYTHON_ARGCOMPLETE_OK
""" CLI
@ -15,13 +16,15 @@ from __future__ import print_function
from __future__ import unicode_literals
import argparse
import sys
try:
import argcomplete
except ImportError:
# this CLI works nevertheless without argcomplete
pass # noqa
import sys
import six
from . import config
from . import version
@ -550,7 +553,7 @@ def main():
# print command with args
getattr(printer, target_command)(**command_arguments)
if target_command in REQUIRES_NEWLINE:
printer.text("\n")
printer.text('\n')
else:
command_arguments['printer'] = printer
globals()[target_command](**command_arguments)

View File

@ -1,3 +1,11 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from .capabilities import CAPABILITIES

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
""" ESC/POS configuration manager.
This module contains the implentations of abstract base class :py:class:`Config`.
@ -10,11 +11,13 @@ from __future__ import print_function
from __future__ import unicode_literals
import os
import appdirs
import yaml
from . import printer
from . import exceptions
from . import printer
class Config(object):

View File

@ -1,4 +1,4 @@
#!/usr/bin/python
#!/usr/bin/env python
# -*- coding: utf-8 -*-
""" Main class
@ -15,42 +15,41 @@ from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import qrcode
import os
import textwrap
import six
import time
from abc import ABCMeta, abstractmethod # abstract base class support
from re import match as re_match
import barcode
from barcode.writer import ImageWriter
import os
import qrcode
from .constants import ESC, GS, NUL, QR_ECLEVEL_L, QR_ECLEVEL_M, QR_ECLEVEL_H, QR_ECLEVEL_Q
from .constants import QR_MODEL_1, QR_MODEL_2, QR_MICRO, BARCODE_TYPES, BARCODE_HEIGHT, BARCODE_WIDTH
import six
from .capabilities import BARCODE_B, get_profile
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_BLW
from .constants import TXT_SIZE, TXT_NORMAL
from .constants import SET_FONT
from .constants import BARCODE_TYPES, BARCODE_HEIGHT, BARCODE_WIDTH
from .constants import CD_KICK_DEC_SEQUENCE, CD_KICK_5, CD_KICK_2, PAPER_FULL_CUT, PAPER_PART_CUT
from .constants import CTL_VT, CTL_CR, CTL_FF, CTL_LF, CTL_SET_HT, PANEL_BUTTON_OFF, PANEL_BUTTON_ON
from .constants import ESC, GS, NUL, QR_ECLEVEL_L, QR_ECLEVEL_M, QR_ECLEVEL_H, QR_ECLEVEL_Q
from .constants import HW_INIT, HW_RESET, HW_SELECT
from .constants import LINESPACING_FUNCS, LINESPACING_RESET
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
from .constants import HW_RESET, HW_SELECT, HW_INIT
from .constants import CTL_VT, CTL_CR, CTL_FF, CTL_LF, CTL_SET_HT, PANEL_BUTTON_OFF, PANEL_BUTTON_ON
from .constants import TXT_STYLE
from .constants import RT_STATUS_ONLINE, RT_MASK_ONLINE
from .constants import QR_MODEL_1, QR_MODEL_2, QR_MICRO
from .constants import RT_MASK_ONLINE, RT_STATUS_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 .constants import SET_FONT
from .constants import TXT_SIZE, TXT_NORMAL
from .constants import TXT_STYLE
from .exceptions import BarcodeCodeError, BarcodeSizeError, BarcodeTypeError
from .exceptions import CashDrawerError, ImageWidthError
from .exceptions import SetVariableError, TabPosError
from .image import EscposImage
from .magicencode import MagicEncode
from abc import ABCMeta, abstractmethod # abstract base class support
from escpos.image import EscposImage
from escpos.capabilities import get_profile, BARCODE_B
@six.add_metaclass(ABCMeta)
class Escpos(object):
@ -89,7 +88,7 @@ class Escpos(object):
"""
raise NotImplementedError()
def image(self, img_source, high_density_vertical=True, high_density_horizontal=True, impl="bitImageRaster",
def image(self, img_source, high_density_vertical=True, high_density_horizontal=True, impl='bitImageRaster',
fragment_height=960, center=False):
""" Print an image
@ -141,14 +140,14 @@ class Escpos(object):
fragment_height=fragment_height)
return
if impl == "bitImageRaster":
if impl == 'bitImageRaster':
# GS v 0, raster format bit image
density_byte = (0 if high_density_horizontal else 1) + (0 if high_density_vertical else 2)
header = GS + b"v0" + six.int2byte(density_byte) + self._int_low_high(im.width_bytes, 2) +\
header = GS + b'v0' + six.int2byte(density_byte) + self._int_low_high(im.width_bytes, 2) +\
self._int_low_high(im.height, 2)
self._raw(header + im.to_raster_format())
if impl == "graphics":
if impl == 'graphics':
# GS ( L raster format graphics
img_header = self._int_low_high(im.width, 2) + self._int_low_high(im.height, 2)
tone = b'0'
@ -160,14 +159,14 @@ class Escpos(object):
self._image_send_graphics_data(b'0', b'p', header + raster_data)
self._image_send_graphics_data(b'0', b'2', b'')
if impl == "bitImageColumn":
if impl == 'bitImageColumn':
# ESC *, column format bit image
density_byte = (1 if high_density_horizontal else 0) + (32 if high_density_vertical else 0)
header = ESC + b"*" + six.int2byte(density_byte) + self._int_low_high(im.width, 2)
outp = [ESC + b"3" + six.int2byte(16)] # Adjust line-feed size
header = ESC + b'*' + six.int2byte(density_byte) + self._int_low_high(im.width, 2)
outp = [ESC + b'3' + six.int2byte(16)] # Adjust line-feed size
for blob in im.to_column_format(high_density_vertical):
outp.append(header + blob + b"\n")
outp.append(ESC + b"2") # Reset line-feed size
outp.append(header + blob + b'\n')
outp.append(ESC + b'2') # Reset line-feed size
self._raw(b''.join(outp))
def _image_send_graphics_data(self, m, fn, data):
@ -182,7 +181,7 @@ class Escpos(object):
self._raw(GS + b'(L' + header + m + fn + data)
def qr(self, content, ec=QR_ECLEVEL_L, size=3, model=QR_MODEL_2,
native=False, center=False, impl="bitImageRaster"):
native=False, center=False, impl='bitImageRaster'):
""" Print QR Code for the provided string
:param content: The content of the code. Numeric data will be more efficiently compacted.
@ -198,18 +197,18 @@ class Escpos(object):
"""
# Basic validation
if ec not in [QR_ECLEVEL_L, QR_ECLEVEL_M, QR_ECLEVEL_H, QR_ECLEVEL_Q]:
raise ValueError("Invalid error correction level")
raise ValueError('Invalid error correction level')
if not 1 <= size <= 16:
raise ValueError("Invalid block size (must be 1-16)")
raise ValueError('Invalid block size (must be 1-16)')
if model not in [QR_MODEL_1, QR_MODEL_2, QR_MICRO]:
raise ValueError("Invalid QR model (must be one of QR_MODEL_1, QR_MODEL_2, QR_MICRO)")
if content == "":
raise ValueError('Invalid QR model (must be one of QR_MODEL_1, QR_MODEL_2, QR_MICRO)')
if content == '':
# Handle edge case by printing nothing.
return
if not native:
# Map ESC/POS error correction levels to python 'qrcode' library constant and render to an image
if model != QR_MODEL_2:
raise ValueError("Invalid QR model for qrlib rendering (must be QR_MODEL_2)")
raise ValueError('Invalid QR model for qrlib rendering (must be QR_MODEL_2)')
python_qr_ec = {
QR_ECLEVEL_H: qrcode.constants.ERROR_CORRECT_H,
QR_ECLEVEL_L: qrcode.constants.ERROR_CORRECT_L,
@ -220,7 +219,7 @@ class Escpos(object):
qr_code.add_data(content)
qr_code.make(fit=True)
qr_img = qr_code.make_image()
im = qr_img._img.convert("RGB")
im = qr_img._img.convert('RGB')
# Convert the RGB image in printable image
self.text('\n')
@ -230,7 +229,7 @@ class Escpos(object):
return
if center:
raise NotImplementedError("Centering not implemented for native QR rendering")
raise NotImplementedError('Centering not implemented for native QR rendering')
# Native 2D code printing
cn = b'1' # Code type for QR code
@ -253,7 +252,7 @@ class Escpos(object):
:param m: Modifier/variant for function. Often '0' where used.
"""
if len(m) > 1 or len(cn) != 1 or len(fn) != 1:
raise ValueError("cn and fn must be one byte each.")
raise ValueError('cn and fn must be one byte each.')
header = self._int_low_high(len(data) + len(m) + 2, 2)
self._raw(GS + b'(k' + header + cn + fn + m + data)
@ -266,16 +265,16 @@ class Escpos(object):
"""
max_input = (256 << (out_bytes * 8) - 1)
if not 1 <= out_bytes <= 4:
raise ValueError("Can only output 1-4 bytes")
raise ValueError('Can only output 1-4 bytes')
if not 0 <= inp_number <= max_input:
raise ValueError("Number too large. Can only output up to {0} in {1} bytes".format(max_input, out_bytes))
raise ValueError('Number too large. Can only output up to {0} in {1} bytes'.format(max_input, out_bytes))
outp = b''
for _ in range(0, out_bytes):
outp += six.int2byte(inp_number % 256)
inp_number //= 256
return outp
def charcode(self, code="AUTO"):
def charcode(self, code='AUTO'):
""" Set Character Code Table
Sets the control sequence from ``CHARCODE`` in :py:mod:`escpos.constants` as active. It will be sent with
@ -285,7 +284,7 @@ class Escpos(object):
:param code: Name of CharCode
:raises: :py:exc:`~escpos.exceptions.CharCodeError`
"""
if code.upper() == "AUTO":
if code.upper() == 'AUTO':
self.magic.force_encoding(False)
else:
self.magic.force_encoding(code)
@ -316,7 +315,7 @@ class Escpos(object):
bounds, regex = BARCODE_FORMATS[bc]
return any(bound[0] <= len(code) <= bound[1] for bound in bounds) and re_match(regex, code)
def barcode(self, code, bc, height=64, width=3, pos="BELOW", font="A",
def barcode(self, code, bc, height=64, width=3, pos='BELOW', font='A',
align_ct=True, function_type=None, check=True):
""" Print Barcode
@ -409,21 +408,21 @@ class Escpos(object):
if bc in BARCODE_TYPES['B']:
if not self.profile.supports(BARCODE_B):
raise BarcodeTypeError((
"Barcode type '{bc} not supported for "
"the current printer profile").format(bc=bc))
"Barcode type '{bc}' not supported for "
'the current printer profile').format(bc=bc))
function_type = 'B'
else:
raise BarcodeTypeError((
"Barcode type '{bc} is not valid").format(bc=bc))
"Barcode type '{bc}' is not valid").format(bc=bc))
bc_types = BARCODE_TYPES[function_type.upper()]
if bc.upper() not in bc_types.keys():
raise BarcodeTypeError((
"Barcode '{bc}' not valid for barcode function type "
"{function_type}").format(
'{function_type}').format(
bc=bc,
function_type=function_type,
))
function_type=function_type,)
)
if check and not self.check_barcode(bc, code):
raise BarcodeCodeError((
@ -439,30 +438,30 @@ class Escpos(object):
if 1 <= height <= 255:
self._raw(BARCODE_HEIGHT + six.int2byte(height))
else:
raise BarcodeSizeError("height = {height}".format(height=height))
raise BarcodeSizeError('height = {height}'.format(height=height))
# Width
if 2 <= width <= 6:
self._raw(BARCODE_WIDTH + six.int2byte(width))
else:
raise BarcodeSizeError("width = {width}".format(width=width))
raise BarcodeSizeError('width = {width}'.format(width=width))
# Font
if font.upper() == "B":
if font.upper() == 'B':
self._raw(BARCODE_FONT_B)
else: # DEFAULT FONT: A
self._raw(BARCODE_FONT_A)
# Position
if pos.upper() == "OFF":
if pos.upper() == 'OFF':
self._raw(BARCODE_TXT_OFF)
elif pos.upper() == "BOTH":
elif pos.upper() == 'BOTH':
self._raw(BARCODE_TXT_BTH)
elif pos.upper() == "ABOVE":
elif pos.upper() == 'ABOVE':
self._raw(BARCODE_TXT_ABV)
else: # DEFAULT POSITION: BELOW
self._raw(BARCODE_TXT_BLW)
self._raw(bc_types[bc.upper()])
if function_type.upper() == "B":
if function_type.upper() == 'B':
self._raw(six.int2byte(len(code)))
# Print Code
@ -471,7 +470,7 @@ class Escpos(object):
else:
raise BarcodeCodeError()
if function_type.upper() == "A":
if function_type.upper() == 'A':
self._raw(NUL)
def soft_barcode(self, barcode_type, data, impl='bitImageColumn',
@ -489,7 +488,7 @@ class Escpos(object):
barcode_class = barcode.get_barcode_class(barcode_type)
my_code = barcode_class(data, writer=image_writer)
with open(os.devnull, "wb") as nullfile:
with open(os.devnull, 'wb') as nullfile:
my_code.write(nullfile, {
'module_height': module_height,
'module_width': module_width,
@ -591,8 +590,7 @@ class Escpos(object):
"""
if custom_size:
if 1 <= width <= 8 and 1 <= height <= 8 and isinstance(width, int) and\
isinstance(height, int):
if 1 <= width <= 8 and 1 <= height <= 8 and isinstance(width, int) and isinstance(height, int):
size_byte = TXT_STYLE['width'][width] + TXT_STYLE['height'][height]
self._raw(TXT_SIZE + six.int2byte(size_byte))
else:
@ -640,12 +638,11 @@ class Escpos(object):
return
if divisor not in LINESPACING_FUNCS:
raise ValueError("divisor must be either 360, 180 or 60")
if (divisor in [360, 180]
and (not(0 <= spacing <= 255))):
raise ValueError("spacing must be a int between 0 and 255 when divisor is 360 or 180")
raise ValueError('divisor must be either 360, 180 or 60')
if (divisor in [360, 180] and (not(0 <= spacing <= 255))):
raise ValueError('spacing must be a int between 0 and 255 when divisor is 360 or 180')
if divisor == 60 and (not(0 <= spacing <= 85)):
raise ValueError("spacing must be a int between 0 and 85 when divisor is 60")
raise ValueError('spacing must be a int between 0 and 85 when divisor is 60')
self._raw(LINESPACING_FUNCS[divisor] + six.int2byte(spacing))
@ -673,12 +670,12 @@ class Escpos(object):
if mode not in ('FULL', 'PART'):
raise ValueError("Mode must be one of ('FULL', 'PART')")
if mode == "PART":
if mode == 'PART':
if self.profile.supports('paperPartCut'):
self._raw(PAPER_PART_CUT)
elif self.profile.supports('paperFullCut'):
self._raw(PAPER_FULL_CUT)
elif mode == "FULL":
elif mode == 'FULL':
if self.profile.supports('paperFullCut'):
self._raw(PAPER_FULL_CUT)
elif self.profile.supports('paperPartCut'):
@ -748,11 +745,11 @@ class Escpos(object):
* SELECT
* RESET
"""
if hw.upper() == "INIT":
if hw.upper() == 'INIT':
self._raw(HW_INIT)
elif hw.upper() == "SELECT":
elif hw.upper() == 'SELECT':
self._raw(HW_SELECT)
elif hw.upper() == "RESET":
elif hw.upper() == 'RESET':
self._raw(HW_RESET)
else: # DEFAULT: DOES NOTHING
pass
@ -767,9 +764,9 @@ class Escpos(object):
"""
if 0 <= n <= 255:
# ESC d n
self._raw(ESC + b"d" + six.int2byte(n))
self._raw(ESC + b'd' + six.int2byte(n))
else:
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):
""" Feed control sequences
@ -787,13 +784,13 @@ class Escpos(object):
:raises: :py:exc:`~escpos.exceptions.TabPosError`
"""
# Set position
if ctl.upper() == "LF":
if ctl.upper() == 'LF':
self._raw(CTL_LF)
elif ctl.upper() == "FF":
elif ctl.upper() == 'FF':
self._raw(CTL_FF)
elif ctl.upper() == "CR":
elif ctl.upper() == 'CR':
self._raw(CTL_CR)
elif ctl.upper() == "HT":
elif ctl.upper() == 'HT':
if not (0 <= count <= 32 and
1 <= tab_size <= 255 and
count * tab_size < 256):
@ -804,7 +801,7 @@ class Escpos(object):
for iterator in range(1, count):
self._raw(six.int2byte(iterator * tab_size))
self._raw(NUL)
elif ctl.upper() == "VT":
elif ctl.upper() == 'VT':
self._raw(CTL_VT)
def panel_buttons(self, enable=True):
@ -930,16 +927,16 @@ class EscposIO(object):
elif isinstance(text, list) or isinstance(text, tuple):
lines = text
else:
lines = ["{0}".format(text), ]
lines = ['{0}'.format(text), ]
# TODO check unicode handling
# TODO flush? or on print? (this should prob rather be handled by the _raw-method)
for line in lines:
self.printer.set(**params)
if isinstance(text, six.text_type):
self.printer.text(u"{0}\n".format(line))
self.printer.text(u'{0}\n'.format(line))
else:
self.printer.text("{0}\n".format(line))
self.printer.text('{0}\n'.format(line))
def close(self):
""" called upon closing the `with`-statement

View File

@ -51,13 +51,13 @@ class BarcodeTypeError(Error):
one of those specified in :py:meth:`escpos.escpos.Escpos.barcode`.
The returned error code is `10`.
"""
def __init__(self, msg=""):
def __init__(self, msg=''):
Error.__init__(self, msg)
self.msg = msg
self.resultcode = 10
def __str__(self):
return "No Barcode type is defined ({msg})".format(msg=self.msg)
return 'No Barcode type is defined ({msg})'.format(msg=self.msg)
class BarcodeSizeError(Error):
@ -67,13 +67,13 @@ class BarcodeSizeError(Error):
The size of the barcode has to be in the range that is specified in :py:meth:`escpos.escpos.Escpos.barcode`.
The resulting returncode is `20`.
"""
def __init__(self, msg=""):
def __init__(self, msg=''):
Error.__init__(self, msg)
self.msg = msg
self.resultcode = 20
def __str__(self):
return "Barcode size is out of range ({msg})".format(msg=self.msg)
return 'Barcode size is out of range ({msg})'.format(msg=self.msg)
class BarcodeCodeError(Error):
@ -83,13 +83,13 @@ class BarcodeCodeError(Error):
was True and the check failed.
The returncode for this exception is `30`.
"""
def __init__(self, msg=""):
def __init__(self, msg=''):
Error.__init__(self, msg)
self.msg = msg
self.resultcode = 30
def __str__(self):
return "No Barcode code was supplied ({msg})".format(msg=self.msg)
return 'No Barcode code was supplied ({msg})'.format(msg=self.msg)
class ImageSizeError(Error):
@ -97,7 +97,7 @@ class ImageSizeError(Error):
The returncode for this exception is `40`.
"""
def __init__(self, msg=""):
def __init__(self, msg=''):
Error.__init__(self, msg)
self.msg = msg
self.resultcode = 40
@ -111,13 +111,13 @@ class ImageWidthError(Error):
The return code for this exception is `41`.
"""
def __init__(self, msg=""):
def __init__(self, msg=''):
Error.__init__(self, msg)
self.msg = msg
self.resultcode = 41
def __str__(self):
return "Image width is too large ({msg})".format(msg=self.msg)
return 'Image width is too large ({msg})'.format(msg=self.msg)
class TextError(Error):
@ -126,13 +126,13 @@ class TextError(Error):
This exception is raised when an empty string is passed to :py:meth:`escpos.escpos.Escpos.text`.
The returncode for this exception is `50`.
"""
def __init__(self, msg=""):
def __init__(self, msg=''):
Error.__init__(self, msg)
self.msg = msg
self.resultcode = 50
def __str__(self):
return "Text string must be supplied to the text() method ({msg})".format(msg=self.msg)
return 'Text string must be supplied to the text() method ({msg})'.format(msg=self.msg)
class CashDrawerError(Error):
@ -141,13 +141,13 @@ class CashDrawerError(Error):
A valid pin number has to be passed onto the method :py:meth:`escpos.escpos.Escpos.cashdraw`.
The returncode for this exception is `60`.
"""
def __init__(self, msg=""):
def __init__(self, msg=''):
Error.__init__(self, msg)
self.msg = msg
self.resultcode = 60
def __str__(self):
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):
@ -157,13 +157,13 @@ class TabPosError(Error):
This exception is raised by :py:meth:`escpos.escpos.Escpos.control`.
The returncode for this exception is `70`.
"""
def __init__(self, msg=""):
def __init__(self, msg=''):
Error.__init__(self, msg)
self.msg = msg
self.resultcode = 70
def __str__(self):
return "Valid tab positions must be in the range 0 to 16 ({msg})".format(msg=self.msg)
return 'Valid tab positions must be in the range 0 to 16 ({msg})'.format(msg=self.msg)
class CharCodeError(Error):
@ -172,13 +172,13 @@ class CharCodeError(Error):
The supplied charcode-name in :py:meth:`escpos.escpos.Escpos.charcode` is unknown.
Ths returncode for this exception is `80`.
"""
def __init__(self, msg=""):
def __init__(self, msg=''):
Error.__init__(self, msg)
self.msg = msg
self.resultcode = 80
def __str__(self):
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):
@ -187,13 +187,13 @@ class USBNotFoundError(Error):
The USB device seems to be not plugged in.
Ths returncode for this exception is `90`.
"""
def __init__(self, msg=""):
def __init__(self, msg=''):
Error.__init__(self, msg)
self.msg = msg
self.resultcode = 90
def __str__(self):
return "USB device not found ({msg})".format(msg=self.msg)
return 'USB device not found ({msg})'.format(msg=self.msg)
class SetVariableError(Error):
@ -202,13 +202,13 @@ class SetVariableError(Error):
Check set variables against minimum and maximum values
Ths returncode for this exception is `100`.
"""
def __init__(self, msg=""):
def __init__(self, msg=''):
Error.__init__(self, msg)
self.msg = msg
self.resultcode = 100
def __str__(self):
return "Set variable out of range ({msg})".format(msg=self.msg)
return 'Set variable out of range ({msg})'.format(msg=self.msg)
# Configuration errors
@ -219,13 +219,13 @@ class ConfigNotFoundError(Error):
The default or passed configuration file could not be read
Ths returncode for this exception is `200`.
"""
def __init__(self, msg=""):
def __init__(self, msg=''):
Error.__init__(self, msg)
self.msg = msg
self.resultcode = 200
def __str__(self):
return "Configuration not found ({msg})".format(msg=self.msg)
return 'Configuration not found ({msg})'.format(msg=self.msg)
class ConfigSyntaxError(Error):
@ -234,13 +234,13 @@ class ConfigSyntaxError(Error):
The syntax is incorrect
Ths returncode for this exception is `210`.
"""
def __init__(self, msg=""):
def __init__(self, msg=''):
Error.__init__(self, msg)
self.msg = msg
self.resultcode = 210
def __str__(self):
return "Configuration syntax is invalid ({msg})".format(msg=self.msg)
return 'Configuration syntax is invalid ({msg})'.format(msg=self.msg)
class ConfigSectionMissingError(Error):
@ -249,10 +249,10 @@ class ConfigSectionMissingError(Error):
The part of the config asked for doesn't exist in the loaded configuration
Ths returncode for this exception is `220`.
"""
def __init__(self, msg=""):
def __init__(self, msg=''):
Error.__init__(self, msg)
self.msg = msg
self.resultcode = 220
def __str__(self):
return "Configuration section is missing ({msg})".format(msg=self.msg)
return 'Configuration section is missing ({msg})'.format(msg=self.msg)

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
""" Image format handling class
This module contains the image format handler :py:class:`EscposImage`.
@ -14,6 +15,7 @@ from __future__ import print_function
from __future__ import unicode_literals
import math
from PIL import Image, ImageOps
@ -42,14 +44,14 @@ class EscposImage(object):
# Convert to white RGB background, paste over white background
# to strip alpha.
img_original = img_original.convert('RGBA')
im = Image.new("RGB", img_original.size, (255, 255, 255))
im = Image.new('RGB', img_original.size, (255, 255, 255))
im.paste(img_original, mask=img_original.split()[3])
# Convert down to greyscale
im = im.convert("L")
im = im.convert('L')
# Invert: Only works on 'L' images
im = ImageOps.invert(im)
# Pure black and white
self._im = im.convert("1")
self._im = im.convert('1')
@property
def width(self):
@ -105,7 +107,7 @@ class EscposImage(object):
:param fragment_height: height of fragment
:return: list of PIL objects
"""
passes = int(math.ceil(self.height/fragment_height))
passes = int(math.ceil(self.height // fragment_height))
fragments = []
for n in range(0, passes):
left = 0
@ -125,7 +127,7 @@ class EscposImage(object):
old_width, height = self._im.size
new_size = (max_width, height)
new_im = Image.new("1", new_size)
new_im = Image.new('1', new_size)
paste_x = int((max_width - old_width) / 2)
new_im.paste(self._im, (paste_x, 0))

View File

@ -33,7 +33,7 @@ def encode_katakana(text):
# TODO doesn't this discard all that is not in the map? Can we be sure that the input does contain only
# encodable characters? We could at least throw an exception if encoding is not possible.
pass
return b"".join(encoded)
return b''.join(encoded)
TXT_ENC_KATAKANA_MAP = {

View File

@ -1,4 +1,4 @@
#!/usr/bin/python
#!/usr/bin/env python
# -*- coding: utf-8 -*-
""" Magic Encode
@ -18,10 +18,12 @@ from __future__ import print_function
from __future__ import unicode_literals
from builtins import bytes
import six
from .codepages import CodePages
from .constants import CODEPAGE_CHANGE
from .exceptions import Error
from .codepages import CodePages
import six
class Encoder(object):
@ -62,7 +64,7 @@ class Encoder(object):
raise ValueError((
'Encoding "{}" cannot be used for the current profile. '
'Valid encodings are: {}'
).format(encoding, ','.join(self.codepages.keys())))
).format(encoding, ','.join(self.codepages.keys())))
return encoding
@staticmethod
@ -75,11 +77,11 @@ class Encoder(object):
"""
codepage = CodePages.get_encoding(encoding)
if 'data' in codepage:
encodable_chars = list("".join(codepage['data']))
encodable_chars = list(''.join(codepage['data']))
assert(len(encodable_chars) == 128)
return encodable_chars
elif 'python_encode' in codepage:
encodable_chars = [u" "] * 128
encodable_chars = [u' '] * 128
for i in range(0, 128):
codepoint = i + 128
try:
@ -280,7 +282,7 @@ class MagicEncode(object):
def write_with_encoding(self, encoding, text):
if text is not None and type(text) is not six.text_type:
raise Error("The supplied text has to be unicode, but is of type {type}.".format(
raise Error('The supplied text has to be unicode, but is of type {type}.'.format(
type=type(text)
))

View File

@ -13,10 +13,12 @@ from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import socket
import serial
import usb.core
import usb.util
import serial
import socket
from .escpos import Escpos
from .exceptions import USBNotFoundError
@ -54,7 +56,7 @@ class Usb(Escpos):
""" Search device on USB tree and set it as escpos device """
self.device = usb.core.find(idVendor=self.idVendor, idProduct=self.idProduct)
if self.device is None:
raise USBNotFoundError("Device not found or cable not plugged in.")
raise USBNotFoundError('Device not found or cable not plugged in.')
check_driver = None
@ -68,13 +70,13 @@ class Usb(Escpos):
self.device.detach_kernel_driver(0)
except usb.core.USBError as e:
if check_driver is not None:
print("Could not detatch kernel driver: {0}".format(str(e)))
print('Could not detatch kernel driver: {0}'.format(str(e)))
try:
self.device.set_configuration()
self.device.reset()
except usb.core.USBError as e:
print("Could not set configuration: {0}".format(str(e)))
print('Could not set configuration: {0}'.format(str(e)))
def _raw(self, msg):
""" Print any command sent in raw format
@ -107,7 +109,7 @@ class Serial(Escpos):
"""
def __init__(self, devfile="/dev/ttyS0", baudrate=9600, bytesize=8, timeout=1,
def __init__(self, devfile='/dev/ttyS0', baudrate=9600, bytesize=8, timeout=1,
parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE,
xonxoff=False, dsrdtr=True, *args, **kwargs):
"""
@ -143,9 +145,9 @@ class Serial(Escpos):
xonxoff=self.xonxoff, dsrdtr=self.dsrdtr)
if self.device is not None:
print("Serial printer enabled")
print('Serial printer enabled')
else:
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):
""" Print any command sent in raw format
@ -209,7 +211,7 @@ class Network(Escpos):
self.device.connect((self.host, self.port))
if self.device is None:
print("Could not open socket for {0}".format(self.host))
print('Could not open socket for {0}'.format(self.host))
def _raw(self, msg):
""" Print any command sent in raw format
@ -240,7 +242,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):
"""
:param devfile: Device file under dev filesystem
@ -253,10 +255,10 @@ class File(Escpos):
def open(self):
""" Open system file """
self.device = open(self.devfile, "wb")
self.device = open(self.devfile, 'wb')
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):
""" Flush printing content """

View File

@ -25,7 +25,12 @@ commands = sphinx-build -W -b html -d {envtmpdir}/doctrees . {envtmpdir}/html
[testenv:flake8]
basepython = python
# TODO add flake8-future
# TODO add flake8-print after adding logging
# TODO add flake8-docstrings
deps = flake8
flake8-coding
flake8-copyright
flake8-future-import
flake8-quotes
flake8-import-order
commands = flake8