Merge pull request #136 from python-escpos/feature/mosquito-compatibility

Feature/mosquito compatibility
This commit is contained in:
Patrick Kanzler 2016-06-19 11:46:47 +02:00 committed by GitHub
commit adf73f3790
5 changed files with 157 additions and 8 deletions

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
""" Set of ESC/POS Commands (Constants) """ Set of ESC/POS Commands (Constants)
This module contains constants that are described in the esc/pos-documentation. This module contains constants that are described in the esc/pos-documentation.

View File

@ -1,4 +1,5 @@
#!/usr/bin/python #!/usr/bin/python
# -*- coding: utf-8 -*-
""" Main class """ Main class
This module contains the abstract base class :py:class:`Escpos`. This module contains the abstract base class :py:class:`Escpos`.
@ -31,6 +32,7 @@ class Escpos(object):
class. class.
""" """
device = None device = None
codepage = None
def __init__(self, columns=32): def __init__(self, columns=32):
""" Initialize ESCPOS Printer """ Initialize ESCPOS Printer
@ -38,6 +40,10 @@ class Escpos(object):
:param columns: Text columns used by the printer. Defaults to 32.""" :param columns: Text columns used by the printer. Defaults to 32."""
self.columns = columns self.columns = columns
def __del__(self):
""" call self.close upon deletion """
self.close()
@abstractmethod @abstractmethod
def _raw(self, msg): def _raw(self, msg):
""" Sends raw data to the printer """ Sends raw data to the printer
@ -202,48 +208,71 @@ 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`
""" """
# TODO improve this (rather unhandy code)
# TODO check the codepages
if code.upper() == "USA": if code.upper() == "USA":
self._raw(CHARCODE_PC437) self._raw(CHARCODE_PC437)
self.codepage = 'cp437'
elif code.upper() == "JIS": elif code.upper() == "JIS":
self._raw(CHARCODE_JIS) self._raw(CHARCODE_JIS)
self.codepage = 'cp932'
elif code.upper() == "MULTILINGUAL": elif code.upper() == "MULTILINGUAL":
self._raw(CHARCODE_PC850) self._raw(CHARCODE_PC850)
self.codepage = 'cp850'
elif code.upper() == "PORTUGUESE": elif code.upper() == "PORTUGUESE":
self._raw(CHARCODE_PC860) self._raw(CHARCODE_PC860)
self.codepage = 'cp860'
elif code.upper() == "CA_FRENCH": elif code.upper() == "CA_FRENCH":
self._raw(CHARCODE_PC863) self._raw(CHARCODE_PC863)
self.codepage = 'cp863'
elif code.upper() == "NORDIC": elif code.upper() == "NORDIC":
self._raw(CHARCODE_PC865) self._raw(CHARCODE_PC865)
self.codepage = 'cp865'
elif code.upper() == "WEST_EUROPE": elif code.upper() == "WEST_EUROPE":
self._raw(CHARCODE_WEU) self._raw(CHARCODE_WEU)
self.codepage = 'latin_1'
elif code.upper() == "GREEK": elif code.upper() == "GREEK":
self._raw(CHARCODE_GREEK) self._raw(CHARCODE_GREEK)
self.codepage = 'cp737'
elif code.upper() == "HEBREW": elif code.upper() == "HEBREW":
self._raw(CHARCODE_HEBREW) self._raw(CHARCODE_HEBREW)
self.codepage = 'cp862'
# elif code.upper() == "LATVIAN": # this is not listed in the constants # elif code.upper() == "LATVIAN": # this is not listed in the constants
# self._raw(CHARCODE_PC755) # self._raw(CHARCODE_PC755)
# self.codepage = 'cp'
elif code.upper() == "WPC1252": elif code.upper() == "WPC1252":
self._raw(CHARCODE_PC1252) self._raw(CHARCODE_PC1252)
self.codepage = 'cp1252'
elif code.upper() == "CIRILLIC2": elif code.upper() == "CIRILLIC2":
self._raw(CHARCODE_PC866) self._raw(CHARCODE_PC866)
self.codepage = 'cp866'
elif code.upper() == "LATIN2": elif code.upper() == "LATIN2":
self._raw(CHARCODE_PC852) self._raw(CHARCODE_PC852)
self.codepage = 'cp852'
elif code.upper() == "EURO": elif code.upper() == "EURO":
self._raw(CHARCODE_PC858) self._raw(CHARCODE_PC858)
self.codepage = 'cp858'
elif code.upper() == "THAI42": elif code.upper() == "THAI42":
self._raw(CHARCODE_THAI42) self._raw(CHARCODE_THAI42)
self.codepage = 'cp874'
elif code.upper() == "THAI11": elif code.upper() == "THAI11":
self._raw(CHARCODE_THAI11) self._raw(CHARCODE_THAI11)
self.codepage = 'cp874'
elif code.upper() == "THAI13": elif code.upper() == "THAI13":
self._raw(CHARCODE_THAI13) self._raw(CHARCODE_THAI13)
self.codepage = 'cp874'
elif code.upper() == "THAI14": elif code.upper() == "THAI14":
self._raw(CHARCODE_THAI14) self._raw(CHARCODE_THAI14)
self.codepage = 'cp874'
elif code.upper() == "THAI16": elif code.upper() == "THAI16":
self._raw(CHARCODE_THAI16) self._raw(CHARCODE_THAI16)
self.codepage = 'cp874'
elif code.upper() == "THAI17": elif code.upper() == "THAI17":
self._raw(CHARCODE_THAI17) self._raw(CHARCODE_THAI17)
self.codepage = 'cp874'
elif code.upper() == "THAI18": elif code.upper() == "THAI18":
self._raw(CHARCODE_THAI18) self._raw(CHARCODE_THAI18)
self.codepage = 'cp874'
else: else:
raise CharCodeError() raise CharCodeError()
@ -380,14 +409,16 @@ class Escpos(object):
""" Print alpha-numeric text """ Print alpha-numeric text
The text has to be encoded in the currently selected codepage. The text has to be encoded in the currently selected codepage.
The input text has to be encoded in unicode.
.. todo:: rework this in order to proberly handle encoding
:param txt: text to be printed :param txt: text to be printed
:raises: :py:exc:`~escpos.exceptions.TextError` :raises: :py:exc:`~escpos.exceptions.TextError`
""" """
if txt: if txt:
self._raw(txt.encode()) if self.codepage:
self._raw(txt.encode(self.codepage))
else:
self._raw(txt.encode())
else: else:
# TODO: why is it problematic to print an empty string? # TODO: why is it problematic to print an empty string?
raise TextError() raise TextError()
@ -395,6 +426,8 @@ class Escpos(object):
def block_text(self, txt, columns=None): def block_text(self, txt, columns=None):
""" Text is printed wrapped to specified columns """ Text is printed wrapped to specified columns
Text has to be encoded in unicode.
:param txt: text to be printed :param txt: text to be printed
:param columns: amount of columns :param columns: amount of columns
:return: None :return: None
@ -620,3 +653,89 @@ class Escpos(object):
self._raw(PANEL_BUTTON_ON) self._raw(PANEL_BUTTON_ON)
else: else:
self._raw(PANEL_BUTTON_OFF) self._raw(PANEL_BUTTON_OFF)
class EscposIO(object):
"""ESC/POS Printer IO object
Allows the class to be used together with the `with`-statement. You have to define a printer instance
and assign it to the EsposIO-class.
This example explains the usage:
.. code-block:: Python
with EscposIO(printer.Serial('/dev/ttyUSB0')) as p:
p.set(font='a', height=2, align='center', text_type='bold')
p.printer.set(align='left')
p.printer.image('logo.gif')
p.writelines('Big line\\n', font='b')
p.writelines('Привет')
p.writelines('BIG TEXT', width=2)
After the `with`-statement the printer automatically cuts the paper if `autocut` is `True`.
"""
def __init__(self, printer, autocut=True, autoclose=True, **kwargs):
"""
:param printer: An EscPos-printer object
:type printer: escpos.Escpos
:param autocut: If True, paper is automatically cut after the `with`-statement *default*: True
:param kwargs: These arguments will be passed to :py:meth:`escpos.Escpos.set()`
"""
self.printer = printer
self.params = kwargs
self.autocut = autocut
self.autoclose = autoclose
def set(self, **kwargs):
""" Set the printer-parameters
Controls which parameters will be passed to :py:meth:`Escpos.set() <escpos.escpos.Escpos.set()>`.
For more information on the parameters see the :py:meth:`set() <escpos.escpos.Escpos.set()>`-methods
documentation. These parameters can also be passed with this class' constructor or the
:py:meth:`~escpos.escpos.EscposIO.writelines()`-method.
:param kwargs: keyword-parameters that will be passed to :py:meth:`Escpos.set() <escpos.escpos.Escpos.set()>`
"""
self.params.update(kwargs)
def writelines(self, text, **kwargs):
params = dict(self.params)
params.update(kwargs)
if isinstance(text, six.text_type):
lines = text.split('\n')
elif isinstance(text, list) or isinstance(text, tuple):
lines = text
else:
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))
else:
self.printer.text("{0}\n".format(line))
def close(self):
""" called upon closing the `with`-statement
"""
self.printer.close()
def __enter__(self, **kwargs):
return self
def __exit__(self, type, value, traceback):
"""
If :py:attr:`autocut <escpos.escpos.EscposIO.autocut>` is `True` (set by this class' constructor),
then :py:meth:`printer.cut() <escpos.escpos.Escpos.cut()>` will be called here.
"""
if not (type is not None and issubclass(type, Exception)):
if self.autocut:
self.printer.cut()
if self.autoclose:
self.close()

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
""" ESC/POS Exceptions classes """ ESC/POS Exceptions classes
Result/Exit codes: Result/Exit codes:

View File

@ -1,5 +1,6 @@
#!/usr/bin/python #!/usr/bin/python
""" This module contains the implentations of abstract base class :py:class:`Escpos`. # -*- coding: utf-8 -*-
""" This module contains the implementations of abstract base class :py:class:`Escpos`.
:author: `Manuel F Martinez <manpaz@bashlinux.com>`_ and others :author: `Manuel F Martinez <manpaz@bashlinux.com>`_ and others
:organization: Bashlinux and `python-escpos <https://github.com/python-escpos>`_ :organization: Bashlinux and `python-escpos <https://github.com/python-escpos>`_
@ -82,7 +83,7 @@ class Usb(Escpos):
""" """
self.device.write(self.out_ep, msg, self.interface) self.device.write(self.out_ep, msg, self.interface)
def __del__(self): def close(self):
""" Release USB interface """ """ Release USB interface """
if self.device: if self.device:
usb.util.dispose_resources(self.device) usb.util.dispose_resources(self.device)
@ -147,7 +148,7 @@ class Serial(Escpos):
""" """
self.device.write(msg) self.device.write(msg)
def __del__(self): def close(self):
""" Close Serial interface """ """ Close Serial interface """
if self.device is not None: if self.device is not None:
self.device.flush() self.device.flush()
@ -207,7 +208,7 @@ class Network(Escpos):
""" """
self.device.sendall(msg) self.device.sendall(msg)
def __del__(self): def close(self):
""" Close TCP connection """ """ Close TCP connection """
self.device.shutdown(socket.SHUT_RDWR) self.device.shutdown(socket.SHUT_RDWR)
self.device.close() self.device.close()
@ -255,7 +256,7 @@ class File(Escpos):
""" """
self.device.write(msg) self.device.write(msg)
def __del__(self): def close(self):
""" Close system file """ """ Close system file """
self.device.flush() self.device.flush()
self.device.close() self.device.close()
@ -294,3 +295,6 @@ class Dummy(Escpos):
def output(self): def output(self):
""" Get the data that was sent to this printer """ """ Get the data that was sent to this printer """
return b''.join(self._output_list) return b''.join(self._output_list)
def close(self):
pass

View File

@ -0,0 +1,24 @@
#!/usr/bin/python
"""test the facility which enables usage of the with-statement
:author: `Patrick Kanzler <patrick.kanzler@fablab.fau.de>`_
:organization: `python-escpos <https://github.com/python-escpos>`_
:copyright: Copyright (c) 2016 `python-escpos <https://github.com/python-escpos>`_
:license: GNU GPL v3
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import escpos.printer as printer
import escpos.escpos as escpos
import os
def test_with_statement():
"""Use with statement"""
dummy_printer = printer.Dummy()
with escpos.EscposIO(dummy_printer) as p:
p.writelines('Some text.\n')
# TODO extend these tests as they don't really do anything at the moment