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 from escpos.printer import Usb
""" Seiko Epson Corp. Receipt Printer (EPSON TM-T88III) """ """ Seiko Epson Corp. Receipt Printer (EPSON TM-T88III) """
p = Usb(0x04b8, 0x0202, 0, profile="TM-T88III") p = Usb(0x04b8, 0x0202, 0, profile='TM-T88III')
p.text("Hello World\n") p.text('Hello World\n')
p.image("logo.gif") p.image('logo.gif')
p.barcode('1324354657687', 'EAN13', 64, 2, '', '') p.barcode('1324354657687', 'EAN13', 64, 2, '', '')
p.cut() 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 Serial printer
^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^
@ -81,7 +81,7 @@ to.
:: ::
Epson = printer.Serial("/dev/tty0") Epson = printer.Serial('/dev/tty0')
Other printers 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 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. 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) """ """ Seiko Epson Corp. Receipt Printer M129 Definitions (EPSON TM-T88IV) """
Epson = printer.Usb(0x04b8,0x0202) Epson = printer.Usb(0x04b8,0x0202)
# Print text # Print text
Epson.text("Hello World\n") Epson.text('Hello World\n')
# Print image # Print image
Epson.image("logo.gif") Epson.image('logo.gif')
# Print QR Code # Print QR Code
Epson.qr("You can readme from your smartphone") Epson.qr('You can readme from your smartphone')
# Print barcode # Print barcode
Epson.barcode('1324354657687','EAN13',64,2,'','') Epson.barcode('1324354657687','EAN13',64,2,'','')
# Cut paper # Cut paper
@ -214,7 +214,7 @@ advantage of the fact that `_raw()` accepts binary strings.)
from escpos import printer from escpos import printer
p = printer.Serial() # adapt this to your printer model 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() data = file.read()
file.close() file.close()
@ -273,8 +273,8 @@ This is probably best explained by an example:
d = Dummy() d = Dummy()
# create ESC/POS for the print job, this should go really fast # create ESC/POS for the print job, this should go really fast
d.text("This is my image:\n") d.text('This is my image:\n')
d.image("funny_cat.png") d.image('funny_cat.png')
d.cut() d.cut()
# send code to printer # 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 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')
# Print software and then hardware barcode with the same content # Print software and then hardware barcode with the same content
p.soft_barcode('code39', '123456') p.soft_barcode('code39', '123456')

View File

@ -1,13 +1,17 @@
# -*- coding: utf-8 -*-
"""Prints code page tables. """Prints code page tables.
""" """
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function from __future__ import print_function
from __future__ import unicode_literals
import six
import sys import sys
from escpos import printer 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(): def main():
@ -17,9 +21,9 @@ def main():
for codepage in sys.argv[1:] or ['USA']: for codepage in sys.argv[1:] or ['USA']:
dummy.set(height=2, width=2) dummy.set(height=2, width=2)
dummy._raw(codepage + "\n\n\n") dummy._raw(codepage + '\n\n\n')
print_codepage(dummy, codepage) print_codepage(dummy, codepage)
dummy._raw("\n\n") dummy._raw('\n\n')
dummy.cut() dummy.cut()
@ -30,22 +34,22 @@ def print_codepage(printer, 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))
printer._raw("after") printer._raw('after')
else: else:
printer.charcode(codepage) printer.charcode(codepage)
sep = "" sep = ''
# Table header # Table header
printer.set(font='b') 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() printer.set()
# The table # The table
for x in range(0, 16): for x in range(0, 16):
# First column # First column
printer.set(font='b') printer.set(font='b')
printer._raw("{} ".format(hex(x)[2:])) printer._raw('{} '.format(hex(x)[2:]))
printer.set() printer.set()
for y in range(0, 16): 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 import sys
from escpos.printer import Usb from escpos.printer import Usb
def usage(): def usage():
print("usage: qr_code.py <content>") print('usage: qr_code.py <content>')
if __name__ == '__main__': if __name__ == '__main__':
@ -15,5 +21,5 @@ if __name__ == '__main__':
content = sys.argv[1] content = sys.argv[1]
# Adapt to your needs # Adapt to your needs
p = Usb(0x0416, 0x5011, profile="POS-5890") p = Usb(0x0416, 0x5011, profile='POS-5890')
p.qr(content, center=True) 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 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')
# Some software barcodes # Some software barcodes
p.soft_barcode('code128', 'Hello') 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 # Adapted script from Adafruit
# Weather forecast for Raspberry Pi w/Adafruit Mini Thermal Printer. # Weather forecast for Raspberry Pi w/Adafruit Mini Thermal Printer.
@ -12,35 +12,38 @@
# Icons taken from http://adamwhitcroft.com/climacons/ # Icons taken from http://adamwhitcroft.com/climacons/
# Check out his github: https://github.com/AdamWhitcroft/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 __future__ import print_function
from datetime import datetime from __future__ import unicode_literals
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 """ """ Setting 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/')
# Adapt to your needs # 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. # 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 :) # 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 LAT = '22.345490' # Your Location
LONG = "114.189945" # Your Location LONG = '114.189945' # Your Location
def forecast_icon(idx): def forecast_icon(idx):
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
@ -80,23 +83,23 @@ def forecast(idx):
def icon(): def icon():
icon = data['currently']['icon'] icon = data['currently']['icon']
image = GRAPHICS_PATH + icon + ".png" image = GRAPHICS_PATH + icon + '.png'
return image return image
deg = ' C' # Degree symbol on thermal printer, need to find a better way to use a proper degree symbol 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' # if you want Fahrenheit change units= to 'us'
url = "https://api.darksky.net/forecast/" + API_KEY + "/" + LAT + "," + LONG + \ url = 'https://api.darksky.net/forecast/' + API_KEY + '/' + LAT + ',' + LONG + \
"?exclude=[alerts,minutely,hourly,flags]&units=si" # change last bit to 'us' for Fahrenheit '?exclude=[alerts,minutely,hourly,flags]&units=si' # change last bit to 'us' for Fahrenheit
response = urllib.urlopen(url) response = urllib.urlopen(url)
data = json.loads(response.read()) data = json.loads(response.read())
printer.print_and_feed(n=1) 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.set(font='a', height=2, align='center', bold=True, double_height=True)
printer.text("Weather Forecast") printer.text('Weather Forecast')
printer.text("\n") printer.text('\n')
printer.set(align='center') 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.set(font='a', height=2, align='center', bold=True, double_height=False)
printer.text('Current conditions: \n') printer.text('Current conditions: \n')
printer.image(icon()) printer.image(icon())
printer.text("\n") printer.text('\n')
printer.set(font='a', height=2, align='left', bold=False, double_height=False) printer.set(font='a', height=2, align='left', bold=False, double_height=False)
temp = data['currently']['temperature'] temp = data['currently']['temperature']
@ -124,4 +127,4 @@ printer.text('Forecast: \n')
forecast(0) forecast(0)
forecast(1) forecast(1)
printer.cut() printer.cut()
printer.control("LF") printer.control('LF')

View File

@ -9,4 +9,13 @@ universal=1
[flake8] [flake8]
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
# 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 #!/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 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')
# When executing the setup.py, we need to be able to import ourselves, this # 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. # means that we need to add the src/ directory to the sys.path.
@ -54,8 +61,8 @@ setup(
'receipt,', 'receipt,',
], ],
platforms='any', platforms='any',
package_dir={"": "src"}, package_dir={'': 'src'},
packages=find_packages(where="src", exclude=["tests", "tests.*"]), packages=find_packages(where='src', exclude=['tests', 'tests.*']),
package_data={'': ['COPYING', 'src/escpos/capabilities.json']}, package_data={'': ['COPYING', 'src/escpos/capabilities.json']},
include_package_data=True, include_package_data=True,
classifiers=[ classifiers=[

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,4 @@
#!/usr/bin/python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" Main class """ Main class
@ -15,42 +15,41 @@ from __future__ import division
from __future__ import print_function from __future__ import print_function
from __future__ import unicode_literals from __future__ import unicode_literals
import qrcode import os
import textwrap import textwrap
import six
import time import time
from abc import ABCMeta, abstractmethod # abstract base class support
from re import match as re_match from re import match as re_match
import barcode import barcode
from barcode.writer import ImageWriter 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 import six
from .constants import QR_MODEL_1, QR_MODEL_2, QR_MICRO, BARCODE_TYPES, BARCODE_HEIGHT, BARCODE_WIDTH
from .capabilities import BARCODE_B, get_profile
from .constants import BARCODE_FONT_A, BARCODE_FONT_B, BARCODE_FORMATS 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 BARCODE_TXT_OFF, BARCODE_TXT_BTH, BARCODE_TXT_ABV, BARCODE_TXT_BLW
from .constants import TXT_SIZE, TXT_NORMAL from .constants import BARCODE_TYPES, BARCODE_HEIGHT, BARCODE_WIDTH
from .constants import SET_FONT 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 LINESPACING_FUNCS, LINESPACING_RESET
from .constants import LINE_DISPLAY_OPEN, LINE_DISPLAY_CLEAR, LINE_DISPLAY_CLOSE 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 QR_MODEL_1, QR_MODEL_2, QR_MICRO
from .constants import HW_RESET, HW_SELECT, HW_INIT from .constants import RT_MASK_ONLINE, RT_STATUS_ONLINE
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 RT_STATUS_PAPER, RT_MASK_PAPER, RT_MASK_LOWPAPER, RT_MASK_NOPAPER from .constants import RT_STATUS_PAPER, RT_MASK_PAPER, RT_MASK_LOWPAPER, RT_MASK_NOPAPER
from .constants import SET_FONT
from .exceptions import BarcodeTypeError, BarcodeSizeError, TabPosError from .constants import TXT_SIZE, TXT_NORMAL
from .exceptions import CashDrawerError, SetVariableError, BarcodeCodeError from .constants import TXT_STYLE
from .exceptions import ImageWidthError 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 .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) @six.add_metaclass(ABCMeta)
class Escpos(object): class Escpos(object):
@ -89,7 +88,7 @@ class Escpos(object):
""" """
raise NotImplementedError() 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): fragment_height=960, center=False):
""" Print an image """ Print an image
@ -141,14 +140,14 @@ class Escpos(object):
fragment_height=fragment_height) fragment_height=fragment_height)
return return
if impl == "bitImageRaster": if impl == 'bitImageRaster':
# GS v 0, raster format bit image # GS v 0, raster format bit image
density_byte = (0 if high_density_horizontal else 1) + (0 if high_density_vertical else 2) 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._int_low_high(im.height, 2)
self._raw(header + im.to_raster_format()) self._raw(header + im.to_raster_format())
if impl == "graphics": if impl == 'graphics':
# GS ( L raster format graphics # GS ( L raster format graphics
img_header = self._int_low_high(im.width, 2) + self._int_low_high(im.height, 2) img_header = self._int_low_high(im.width, 2) + self._int_low_high(im.height, 2)
tone = b'0' 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'p', header + raster_data)
self._image_send_graphics_data(b'0', b'2', b'') self._image_send_graphics_data(b'0', b'2', b'')
if impl == "bitImageColumn": if impl == 'bitImageColumn':
# ESC *, column format bit image # ESC *, column format bit image
density_byte = (1 if high_density_horizontal else 0) + (32 if high_density_vertical else 0) 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) 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 outp = [ESC + b'3' + six.int2byte(16)] # Adjust line-feed size
for blob in im.to_column_format(high_density_vertical): for blob in im.to_column_format(high_density_vertical):
outp.append(header + blob + b"\n") outp.append(header + blob + b'\n')
outp.append(ESC + b"2") # Reset line-feed size outp.append(ESC + b'2') # Reset line-feed size
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):
@ -182,7 +181,7 @@ class Escpos(object):
self._raw(GS + b'(L' + header + m + fn + data) self._raw(GS + b'(L' + header + m + fn + data)
def qr(self, content, ec=QR_ECLEVEL_L, size=3, model=QR_MODEL_2, 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 """ 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.
@ -198,18 +197,18 @@ class Escpos(object):
""" """
# Basic validation # Basic validation
if ec not in [QR_ECLEVEL_L, QR_ECLEVEL_M, QR_ECLEVEL_H, QR_ECLEVEL_Q]: 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: 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]: 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)") raise ValueError('Invalid QR model (must be one of QR_MODEL_1, QR_MODEL_2, QR_MICRO)')
if content == "": if content == '':
# Handle edge case by printing nothing. # Handle edge case by printing nothing.
return return
if not native: if not native:
# Map ESC/POS error correction levels to python 'qrcode' library constant and render to an image # Map ESC/POS error correction levels to python 'qrcode' library constant and render to an image
if model != QR_MODEL_2: 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 = { python_qr_ec = {
QR_ECLEVEL_H: qrcode.constants.ERROR_CORRECT_H, QR_ECLEVEL_H: qrcode.constants.ERROR_CORRECT_H,
QR_ECLEVEL_L: qrcode.constants.ERROR_CORRECT_L, QR_ECLEVEL_L: qrcode.constants.ERROR_CORRECT_L,
@ -220,7 +219,7 @@ class Escpos(object):
qr_code.add_data(content) qr_code.add_data(content)
qr_code.make(fit=True) qr_code.make(fit=True)
qr_img = qr_code.make_image() 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 # Convert the RGB image in printable image
self.text('\n') self.text('\n')
@ -230,7 +229,7 @@ class Escpos(object):
return return
if center: if center:
raise NotImplementedError("Centering not implemented for native QR rendering") raise NotImplementedError('Centering not implemented for native QR rendering')
# Native 2D code printing # Native 2D code printing
cn = b'1' # Code type for QR code 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. :param m: Modifier/variant for function. Often '0' where used.
""" """
if len(m) > 1 or len(cn) != 1 or len(fn) != 1: 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) header = self._int_low_high(len(data) + len(m) + 2, 2)
self._raw(GS + b'(k' + header + cn + fn + m + data) self._raw(GS + b'(k' + header + cn + fn + m + data)
@ -266,16 +265,16 @@ class Escpos(object):
""" """
max_input = (256 << (out_bytes * 8) - 1) max_input = (256 << (out_bytes * 8) - 1)
if not 1 <= out_bytes <= 4: 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: 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'' outp = b''
for _ in range(0, out_bytes): for _ in range(0, out_bytes):
outp += six.int2byte(inp_number % 256) outp += six.int2byte(inp_number % 256)
inp_number //= 256 inp_number //= 256
return outp return outp
def charcode(self, code="AUTO"): def charcode(self, code='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
@ -285,7 +284,7 @@ class Escpos(object):
:param code: Name of CharCode :param code: Name of CharCode
:raises: :py:exc:`~escpos.exceptions.CharCodeError` :raises: :py:exc:`~escpos.exceptions.CharCodeError`
""" """
if code.upper() == "AUTO": if code.upper() == 'AUTO':
self.magic.force_encoding(False) self.magic.force_encoding(False)
else: else:
self.magic.force_encoding(code) self.magic.force_encoding(code)
@ -316,7 +315,7 @@ class Escpos(object):
bounds, regex = BARCODE_FORMATS[bc] bounds, regex = BARCODE_FORMATS[bc]
return any(bound[0] <= len(code) <= bound[1] for bound in bounds) and re_match(regex, code) 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): align_ct=True, function_type=None, check=True):
""" Print Barcode """ Print Barcode
@ -409,21 +408,21 @@ class Escpos(object):
if bc in BARCODE_TYPES['B']: if bc in BARCODE_TYPES['B']:
if not self.profile.supports(BARCODE_B): if not self.profile.supports(BARCODE_B):
raise BarcodeTypeError(( raise BarcodeTypeError((
"Barcode type '{bc} not supported for " "Barcode type '{bc}' not supported for "
"the current printer profile").format(bc=bc)) 'the current printer profile').format(bc=bc))
function_type = 'B' function_type = 'B'
else: else:
raise BarcodeTypeError(( 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()] bc_types = BARCODE_TYPES[function_type.upper()]
if bc.upper() not in bc_types.keys(): if bc.upper() not in bc_types.keys():
raise BarcodeTypeError(( raise BarcodeTypeError((
"Barcode '{bc}' not valid for barcode function type " "Barcode '{bc}' not valid for barcode function type "
"{function_type}").format( '{function_type}').format(
bc=bc, bc=bc,
function_type=function_type, function_type=function_type,)
)) )
if check and not self.check_barcode(bc, code): if check and not self.check_barcode(bc, code):
raise BarcodeCodeError(( raise BarcodeCodeError((
@ -439,30 +438,30 @@ class Escpos(object):
if 1 <= height <= 255: if 1 <= height <= 255:
self._raw(BARCODE_HEIGHT + six.int2byte(height)) self._raw(BARCODE_HEIGHT + six.int2byte(height))
else: else:
raise BarcodeSizeError("height = {height}".format(height=height)) raise BarcodeSizeError('height = {height}'.format(height=height))
# Width # Width
if 2 <= width <= 6: if 2 <= width <= 6:
self._raw(BARCODE_WIDTH + six.int2byte(width)) self._raw(BARCODE_WIDTH + six.int2byte(width))
else: else:
raise BarcodeSizeError("width = {width}".format(width=width)) raise BarcodeSizeError('width = {width}'.format(width=width))
# Font # Font
if font.upper() == "B": if font.upper() == 'B':
self._raw(BARCODE_FONT_B) self._raw(BARCODE_FONT_B)
else: # DEFAULT FONT: A else: # DEFAULT FONT: A
self._raw(BARCODE_FONT_A) self._raw(BARCODE_FONT_A)
# Position # Position
if pos.upper() == "OFF": if pos.upper() == 'OFF':
self._raw(BARCODE_TXT_OFF) self._raw(BARCODE_TXT_OFF)
elif pos.upper() == "BOTH": elif pos.upper() == 'BOTH':
self._raw(BARCODE_TXT_BTH) self._raw(BARCODE_TXT_BTH)
elif pos.upper() == "ABOVE": elif pos.upper() == 'ABOVE':
self._raw(BARCODE_TXT_ABV) self._raw(BARCODE_TXT_ABV)
else: # DEFAULT POSITION: BELOW else: # DEFAULT POSITION: BELOW
self._raw(BARCODE_TXT_BLW) self._raw(BARCODE_TXT_BLW)
self._raw(bc_types[bc.upper()]) self._raw(bc_types[bc.upper()])
if function_type.upper() == "B": if function_type.upper() == 'B':
self._raw(six.int2byte(len(code))) self._raw(six.int2byte(len(code)))
# Print Code # Print Code
@ -471,7 +470,7 @@ class Escpos(object):
else: else:
raise BarcodeCodeError() raise BarcodeCodeError()
if function_type.upper() == "A": if function_type.upper() == 'A':
self._raw(NUL) self._raw(NUL)
def soft_barcode(self, barcode_type, data, impl='bitImageColumn', def soft_barcode(self, barcode_type, data, impl='bitImageColumn',
@ -489,7 +488,7 @@ class Escpos(object):
barcode_class = barcode.get_barcode_class(barcode_type) barcode_class = barcode.get_barcode_class(barcode_type)
my_code = barcode_class(data, writer=image_writer) 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, { my_code.write(nullfile, {
'module_height': module_height, 'module_height': module_height,
'module_width': module_width, 'module_width': module_width,
@ -591,8 +590,7 @@ class Escpos(object):
""" """
if custom_size: if custom_size:
if 1 <= width <= 8 and 1 <= height <= 8 and isinstance(width, int) and\ if 1 <= width <= 8 and 1 <= height <= 8 and isinstance(width, int) and isinstance(height, int):
isinstance(height, int):
size_byte = TXT_STYLE['width'][width] + TXT_STYLE['height'][height] size_byte = TXT_STYLE['width'][width] + TXT_STYLE['height'][height]
self._raw(TXT_SIZE + six.int2byte(size_byte)) self._raw(TXT_SIZE + six.int2byte(size_byte))
else: else:
@ -640,12 +638,11 @@ class Escpos(object):
return return
if divisor not in LINESPACING_FUNCS: if divisor not in LINESPACING_FUNCS:
raise ValueError("divisor must be either 360, 180 or 60") raise ValueError('divisor must be either 360, 180 or 60')
if (divisor in [360, 180] if (divisor in [360, 180] and (not(0 <= spacing <= 255))):
and (not(0 <= spacing <= 255))): raise ValueError('spacing must be a int between 0 and 255 when divisor is 360 or 180')
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)): 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)) self._raw(LINESPACING_FUNCS[divisor] + six.int2byte(spacing))
@ -673,12 +670,12 @@ class Escpos(object):
if mode not in ('FULL', 'PART'): if mode not in ('FULL', 'PART'):
raise ValueError("Mode must be one of ('FULL', 'PART')") raise ValueError("Mode must be one of ('FULL', 'PART')")
if mode == "PART": if mode == 'PART':
if self.profile.supports('paperPartCut'): if self.profile.supports('paperPartCut'):
self._raw(PAPER_PART_CUT) self._raw(PAPER_PART_CUT)
elif self.profile.supports('paperFullCut'): elif self.profile.supports('paperFullCut'):
self._raw(PAPER_FULL_CUT) self._raw(PAPER_FULL_CUT)
elif mode == "FULL": elif mode == 'FULL':
if self.profile.supports('paperFullCut'): if self.profile.supports('paperFullCut'):
self._raw(PAPER_FULL_CUT) self._raw(PAPER_FULL_CUT)
elif self.profile.supports('paperPartCut'): elif self.profile.supports('paperPartCut'):
@ -748,11 +745,11 @@ class Escpos(object):
* SELECT * SELECT
* RESET * RESET
""" """
if hw.upper() == "INIT": if hw.upper() == 'INIT':
self._raw(HW_INIT) self._raw(HW_INIT)
elif hw.upper() == "SELECT": elif hw.upper() == 'SELECT':
self._raw(HW_SELECT) self._raw(HW_SELECT)
elif hw.upper() == "RESET": elif hw.upper() == 'RESET':
self._raw(HW_RESET) self._raw(HW_RESET)
else: # DEFAULT: DOES NOTHING else: # DEFAULT: DOES NOTHING
pass pass
@ -767,9 +764,9 @@ class Escpos(object):
""" """
if 0 <= n <= 255: if 0 <= n <= 255:
# ESC d n # ESC d n
self._raw(ESC + b"d" + six.int2byte(n)) self._raw(ESC + b'd' + six.int2byte(n))
else: 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): def control(self, ctl, count=5, tab_size=8):
""" Feed control sequences """ Feed control sequences
@ -787,13 +784,13 @@ class Escpos(object):
:raises: :py:exc:`~escpos.exceptions.TabPosError` :raises: :py:exc:`~escpos.exceptions.TabPosError`
""" """
# Set position # Set position
if ctl.upper() == "LF": if ctl.upper() == 'LF':
self._raw(CTL_LF) self._raw(CTL_LF)
elif ctl.upper() == "FF": elif ctl.upper() == 'FF':
self._raw(CTL_FF) self._raw(CTL_FF)
elif ctl.upper() == "CR": elif ctl.upper() == 'CR':
self._raw(CTL_CR) self._raw(CTL_CR)
elif ctl.upper() == "HT": elif ctl.upper() == 'HT':
if not (0 <= count <= 32 and if not (0 <= count <= 32 and
1 <= tab_size <= 255 and 1 <= tab_size <= 255 and
count * tab_size < 256): count * tab_size < 256):
@ -804,7 +801,7 @@ class Escpos(object):
for iterator in range(1, count): for iterator in range(1, count):
self._raw(six.int2byte(iterator * tab_size)) self._raw(six.int2byte(iterator * tab_size))
self._raw(NUL) self._raw(NUL)
elif ctl.upper() == "VT": elif ctl.upper() == 'VT':
self._raw(CTL_VT) self._raw(CTL_VT)
def panel_buttons(self, enable=True): def panel_buttons(self, enable=True):
@ -930,16 +927,16 @@ class EscposIO(object):
elif isinstance(text, list) or isinstance(text, tuple): elif isinstance(text, list) or isinstance(text, tuple):
lines = text lines = text
else: else:
lines = ["{0}".format(text), ] lines = ['{0}'.format(text), ]
# TODO check unicode handling # TODO check unicode handling
# TODO flush? or on print? (this should prob rather be handled by the _raw-method) # TODO flush? or on print? (this should prob rather be handled by the _raw-method)
for line in lines: for line in lines:
self.printer.set(**params) self.printer.set(**params)
if isinstance(text, six.text_type): if isinstance(text, six.text_type):
self.printer.text(u"{0}\n".format(line)) self.printer.text(u'{0}\n'.format(line))
else: else:
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 """ 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`. one of those specified in :py:meth:`escpos.escpos.Escpos.barcode`.
The returned error code is `10`. The returned error code is `10`.
""" """
def __init__(self, msg=""): def __init__(self, msg=''):
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 "No Barcode type is defined ({msg})".format(msg=self.msg) return 'No Barcode type is defined ({msg})'.format(msg=self.msg)
class BarcodeSizeError(Error): 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 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`. The resulting returncode is `20`.
""" """
def __init__(self, msg=""): def __init__(self, msg=''):
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 "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): class BarcodeCodeError(Error):
@ -83,13 +83,13 @@ class BarcodeCodeError(Error):
was True and the check failed. was True and the check failed.
The returncode for this exception is `30`. The returncode for this exception is `30`.
""" """
def __init__(self, msg=""): def __init__(self, msg=''):
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 "No Barcode code was supplied ({msg})".format(msg=self.msg) return 'No Barcode code was supplied ({msg})'.format(msg=self.msg)
class ImageSizeError(Error): class ImageSizeError(Error):
@ -97,7 +97,7 @@ class ImageSizeError(Error):
The returncode for this exception is `40`. The returncode for this exception is `40`.
""" """
def __init__(self, msg=""): def __init__(self, msg=''):
Error.__init__(self, msg) Error.__init__(self, msg)
self.msg = msg self.msg = msg
self.resultcode = 40 self.resultcode = 40
@ -111,13 +111,13 @@ class ImageWidthError(Error):
The return code for this exception is `41`. The return code for this exception is `41`.
""" """
def __init__(self, msg=""): def __init__(self, msg=''):
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 "Image width is too large ({msg})".format(msg=self.msg) return 'Image width is too large ({msg})'.format(msg=self.msg)
class TextError(Error): 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`. This exception is raised when an empty string is passed to :py:meth:`escpos.escpos.Escpos.text`.
The returncode for this exception is `50`. The returncode for this exception is `50`.
""" """
def __init__(self, msg=""): def __init__(self, msg=''):
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 "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): 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`. A valid pin number has to be passed onto the method :py:meth:`escpos.escpos.Escpos.cashdraw`.
The returncode for this exception is `60`. The returncode for this exception is `60`.
""" """
def __init__(self, msg=""): def __init__(self, msg=''):
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 "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):
@ -157,13 +157,13 @@ class TabPosError(Error):
This exception is raised by :py:meth:`escpos.escpos.Escpos.control`. This exception is raised by :py:meth:`escpos.escpos.Escpos.control`.
The returncode for this exception is `70`. The returncode for this exception is `70`.
""" """
def __init__(self, msg=""): def __init__(self, msg=''):
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 "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): class CharCodeError(Error):
@ -172,13 +172,13 @@ class CharCodeError(Error):
The supplied charcode-name in :py:meth:`escpos.escpos.Escpos.charcode` is unknown. The supplied charcode-name in :py:meth:`escpos.escpos.Escpos.charcode` is unknown.
Ths returncode for this exception is `80`. Ths returncode for this exception is `80`.
""" """
def __init__(self, msg=""): def __init__(self, msg=''):
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 "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):
@ -187,13 +187,13 @@ class USBNotFoundError(Error):
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=''):
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 "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):
@ -202,13 +202,13 @@ class SetVariableError(Error):
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=''):
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 "Set variable out of range ({msg})".format(msg=self.msg) return 'Set variable out of range ({msg})'.format(msg=self.msg)
# Configuration errors # Configuration errors
@ -219,13 +219,13 @@ class ConfigNotFoundError(Error):
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=''):
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 "Configuration not found ({msg})".format(msg=self.msg) return 'Configuration not found ({msg})'.format(msg=self.msg)
class ConfigSyntaxError(Error): class ConfigSyntaxError(Error):
@ -234,13 +234,13 @@ class ConfigSyntaxError(Error):
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=''):
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 "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):
@ -249,10 +249,10 @@ class ConfigSectionMissingError(Error):
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=''):
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 "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 """ Image format handling class
This module contains the image format handler :py:class:`EscposImage`. This module contains the image format handler :py:class:`EscposImage`.
@ -14,6 +15,7 @@ from __future__ import print_function
from __future__ import unicode_literals from __future__ import unicode_literals
import math import math
from PIL import Image, ImageOps from PIL import Image, ImageOps
@ -42,14 +44,14 @@ class EscposImage(object):
# Convert to white RGB background, paste over white background # Convert to white RGB background, paste over white background
# to strip alpha. # to strip alpha.
img_original = img_original.convert('RGBA') 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]) im.paste(img_original, mask=img_original.split()[3])
# Convert down to greyscale # Convert down to greyscale
im = im.convert("L") im = im.convert('L')
# Invert: Only works on 'L' images # Invert: Only works on 'L' images
im = ImageOps.invert(im) im = ImageOps.invert(im)
# Pure black and white # Pure black and white
self._im = im.convert("1") self._im = im.convert('1')
@property @property
def width(self): def width(self):
@ -105,7 +107,7 @@ class EscposImage(object):
:param fragment_height: height of fragment :param fragment_height: height of fragment
:return: list of PIL objects :return: list of PIL objects
""" """
passes = int(math.ceil(self.height/fragment_height)) passes = int(math.ceil(self.height // fragment_height))
fragments = [] fragments = []
for n in range(0, passes): for n in range(0, passes):
left = 0 left = 0
@ -125,7 +127,7 @@ class EscposImage(object):
old_width, height = self._im.size old_width, height = self._im.size
new_size = (max_width, height) 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) paste_x = int((max_width - old_width) / 2)
new_im.paste(self._im, (paste_x, 0)) 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 # 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. # encodable characters? We could at least throw an exception if encoding is not possible.
pass pass
return b"".join(encoded) return b''.join(encoded)
TXT_ENC_KATAKANA_MAP = { TXT_ENC_KATAKANA_MAP = {

View File

@ -1,4 +1,4 @@
#!/usr/bin/python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" Magic Encode """ Magic Encode
@ -18,10 +18,12 @@ from __future__ import print_function
from __future__ import unicode_literals from __future__ import unicode_literals
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
class Encoder(object): class Encoder(object):
@ -62,7 +64,7 @@ class Encoder(object):
raise ValueError(( raise ValueError((
'Encoding "{}" cannot be used for the current profile. ' 'Encoding "{}" cannot be used for the current profile. '
'Valid encodings are: {}' 'Valid encodings are: {}'
).format(encoding, ','.join(self.codepages.keys()))) ).format(encoding, ','.join(self.codepages.keys())))
return encoding return encoding
@staticmethod @staticmethod
@ -75,11 +77,11 @@ class Encoder(object):
""" """
codepage = CodePages.get_encoding(encoding) codepage = CodePages.get_encoding(encoding)
if 'data' in codepage: if 'data' in codepage:
encodable_chars = list("".join(codepage['data'])) encodable_chars = list(''.join(codepage['data']))
assert(len(encodable_chars) == 128) assert(len(encodable_chars) == 128)
return encodable_chars return encodable_chars
elif 'python_encode' in codepage: elif 'python_encode' in codepage:
encodable_chars = [u" "] * 128 encodable_chars = [u' '] * 128
for i in range(0, 128): for i in range(0, 128):
codepoint = i + 128 codepoint = i + 128
try: try:
@ -280,7 +282,7 @@ class MagicEncode(object):
def write_with_encoding(self, encoding, text): def write_with_encoding(self, encoding, text):
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("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) type=type(text)
)) ))

View File

@ -13,10 +13,12 @@ from __future__ import division
from __future__ import print_function from __future__ import print_function
from __future__ import unicode_literals from __future__ import unicode_literals
import socket
import serial
import usb.core import usb.core
import usb.util import usb.util
import serial
import socket
from .escpos import Escpos from .escpos import Escpos
from .exceptions import USBNotFoundError from .exceptions import USBNotFoundError
@ -54,7 +56,7 @@ class Usb(Escpos):
""" Search device on USB tree and set it as escpos device """ """ Search device on USB tree and set it as escpos device """
self.device = usb.core.find(idVendor=self.idVendor, idProduct=self.idProduct) self.device = usb.core.find(idVendor=self.idVendor, idProduct=self.idProduct)
if self.device is None: 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 check_driver = None
@ -68,13 +70,13 @@ class Usb(Escpos):
self.device.detach_kernel_driver(0) self.device.detach_kernel_driver(0)
except usb.core.USBError as e: except usb.core.USBError as e:
if check_driver is not None: 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: try:
self.device.set_configuration() self.device.set_configuration()
self.device.reset() self.device.reset()
except usb.core.USBError as e: 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): def _raw(self, msg):
""" Print any command sent in raw format """ 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, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE,
xonxoff=False, dsrdtr=True, *args, **kwargs): xonxoff=False, dsrdtr=True, *args, **kwargs):
""" """
@ -143,9 +145,9 @@ class Serial(Escpos):
xonxoff=self.xonxoff, dsrdtr=self.dsrdtr) xonxoff=self.xonxoff, dsrdtr=self.dsrdtr)
if self.device is not None: if self.device is not None:
print("Serial printer enabled") print('Serial printer enabled')
else: 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): def _raw(self, msg):
""" Print any command sent in raw format """ Print any command sent in raw format
@ -209,7 +211,7 @@ class Network(Escpos):
self.device.connect((self.host, self.port)) self.device.connect((self.host, self.port))
if self.device is None: 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): def _raw(self, msg):
""" Print any command sent in raw format """ 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 :param devfile: Device file under dev filesystem
@ -253,10 +255,10 @@ class File(Escpos):
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 """

View File

@ -25,7 +25,12 @@ 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-print after adding logging
# TODO add flake8-docstrings # TODO add flake8-docstrings
deps = flake8 deps = flake8
flake8-coding
flake8-copyright
flake8-future-import
flake8-quotes
flake8-import-order
commands = flake8 commands = flake8