diff --git a/escpos/constants.py b/escpos/constants.py index e268edb..0e1ce82 100644 --- a/escpos/constants.py +++ b/escpos/constants.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- """ Set of ESC/POS Commands (Constants) This module contains constants that are described in the esc/pos-documentation. diff --git a/escpos/escpos.py b/escpos/escpos.py index 33cd6c9..9b6cb87 100644 --- a/escpos/escpos.py +++ b/escpos/escpos.py @@ -1,4 +1,5 @@ #!/usr/bin/python +# -*- coding: utf-8 -*- """ Main class This module contains the abstract base class :py:class:`Escpos`. @@ -38,6 +39,10 @@ class Escpos(object): :param columns: Text columns used by the printer. Defaults to 32.""" self.columns = columns + def __del__(self): + """ call self.close upon deletion """ + self.close() + @abstractmethod def _raw(self, msg): """ Sends raw data to the printer @@ -620,3 +625,89 @@ class Escpos(object): self._raw(PANEL_BUTTON_ON) else: 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() `. + For more information on the parameters see the :py:meth:`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() ` + """ + 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 ` is `True` (set by this class' constructor), + then :py:meth:`printer.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() diff --git a/escpos/exceptions.py b/escpos/exceptions.py index 0a51782..629b94f 100644 --- a/escpos/exceptions.py +++ b/escpos/exceptions.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- """ ESC/POS Exceptions classes Result/Exit codes: diff --git a/escpos/printer.py b/escpos/printer.py index ee9e227..654b995 100644 --- a/escpos/printer.py +++ b/escpos/printer.py @@ -1,5 +1,6 @@ #!/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 `_ and others :organization: Bashlinux and `python-escpos `_ @@ -82,7 +83,7 @@ class Usb(Escpos): """ self.device.write(self.out_ep, msg, self.interface) - def __del__(self): + def close(self): """ Release USB interface """ if self.device: usb.util.dispose_resources(self.device) @@ -147,7 +148,7 @@ class Serial(Escpos): """ self.device.write(msg) - def __del__(self): + def close(self): """ Close Serial interface """ if self.device is not None: self.device.flush() @@ -207,7 +208,7 @@ class Network(Escpos): """ self.device.sendall(msg) - def __del__(self): + def close(self): """ Close TCP connection """ self.device.shutdown(socket.SHUT_RDWR) self.device.close() @@ -255,7 +256,7 @@ class File(Escpos): """ self.device.write(msg) - def __del__(self): + def close(self): """ Close system file """ self.device.flush() self.device.close() @@ -294,3 +295,6 @@ class Dummy(Escpos): def output(self): """ Get the data that was sent to this printer """ return b''.join(self._output_list) + + def close(self): + pass diff --git a/test/test_with_statement.py b/test/test_with_statement.py new file mode 100644 index 0000000..a59a719 --- /dev/null +++ b/test/test_with_statement.py @@ -0,0 +1,24 @@ +#!/usr/bin/python +"""test the facility which enables usage of the with-statement + +:author: `Patrick Kanzler `_ +:organization: `python-escpos `_ +:copyright: Copyright (c) 2016 `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