1
0
mirror of https://github.com/python-escpos/python-escpos synced 2025-09-13 09:09:58 +00:00

29 Commits

Author SHA1 Message Date
Patrick Kanzler
11452034a3 Merge pull request #157 from python-escpos/development
v2.1.2
2016-08-02 16:32:19 +02:00
Patrick Kanzler
d2e2ea88a6 doc write changelog for version v2.1.2 2016-08-02 16:07:05 +02:00
Patrick Kanzler
2416303805 Merge pull request #156 from python-escpos/fix/code128-printing
fix printing of CODE128
2016-08-02 15:57:52 +02:00
Patrick Kanzler
38f9835931 fix printing of CODE128
The control sequence {A or {B or {C can't be part of the qr code.
For this the user has to supply this sequence.
2016-08-02 15:39:31 +02:00
Patrick Kanzler
7c732ee615 doc fix lists 2016-08-02 04:38:04 +02:00
Patrick Kanzler
3d98eb8b9c fix file-printer did not flush
The file-printer did not automatically flush and thus behaved
differently to the other printer-classes.
Now the default behaviour is to flush after every call of _raw(). This
can be disabled by calling the file-printer with auto_flush=False.

fixes #106
2016-08-02 04:25:54 +02:00
Patrick Kanzler
619d80a867 doc add changelog-stump for post-2.1.1 release 2016-08-02 00:45:36 +02:00
Patrick Kanzler
d3f74ced5d doc update changelog for release v2.1.1 2016-08-02 00:41:10 +02:00
Patrick Kanzler
0524b0576e Merge pull request #154 from python-escpos/development
release v2.1.1
2016-08-02 00:39:06 +02:00
Patrick Kanzler
c92d4463ae update changelog 2016-08-02 00:27:08 +02:00
Patrick Kanzler
6e74748773 Merge pull request #153 from python-escpos/improve/add-hypothesis-support
Improve/add hypothesis support
2016-08-02 00:25:00 +02:00
Patrick Kanzler
a2e188cecf move pypy3 to the allowed failures and add hypothesis
pypy3 is not compatible with hypothesis, which is needed for testing
2016-08-02 00:10:39 +02:00
Patrick Kanzler
c1a6da9aaa configure codecov.io
For $reasons codecov.io stopped working. Now with my account explicitly
set as "bot" it works again.
2016-08-02 00:10:39 +02:00
Patrick Kanzler
37baf5cd34 update changelog 2016-08-01 23:59:46 +02:00
Patrick Kanzler
5c209dd557 Merge pull request #151 from Renato-Lorenzi/improve/rename-interface-to-timeout
Change the interface param to timeout
2016-08-01 23:54:35 +02:00
Renato.Lorenzi
bef1a9cccf Change the interface param to timeout 2016-08-01 09:36:48 -03:00
Patrick Kanzler
042f945a09 doc added stump for next release 2016-07-23 14:57:24 +02:00
Patrick Kanzler
2cf30c7f05 Merge pull request #147 from python-escpos/development
v2.1.0
2016-07-23 14:42:33 +02:00
Patrick Kanzler
34d929806c doc update changelog 2016-07-23 11:44:34 +02:00
Patrick Kanzler
c5d34cc268 Merge pull request #148 from python-escpos/feature/tabcompletion
Feature/tabcompletion
2016-07-23 11:43:07 +02:00
Patrick Kanzler
fd3f1067fe DOC update documentation on installation and CLI 2016-07-23 11:34:18 +02:00
Patrick Kanzler
80b714fdae add basic argcomplete support 2016-07-23 10:39:40 +02:00
Patrick Kanzler
457c62cc7f Merge pull request #146 from python-escpos/add-version-to-module
add version-strings into the module
2016-07-23 08:54:03 +02:00
Patrick Kanzler
a5cae3adb7 fix inconsistent behaviour of argparse-code
this affected certain versions of argparse in python3
2016-07-17 19:39:51 +02:00
Patrick Kanzler
9f5eed0020 add version-strings into the module
The version string is in the module as __version__ available.
In the doc the version will be automatically parsed. The version comes
from the installed module if on read the docs or directly from
setuptools_scm if you are working locally.
The CLI will issue the version string if you call it with the option
'version'. The CLI does not accept commands like '--version', since this
would not be conform with the rest of the interface (and argparse).

The configuration for loading the version-string is adapted from
pimutils/vdirsyncer. It autogenerates a version string setuptools_scm at
install-time and then adds it to the __version__ member in __init__.py

I adapted the GitHub-template with a fitting comment and bumped the
changelog.

closes #141
2016-07-17 19:39:42 +02:00
Patrick Kanzler
57dd60c13f doc: add troubleshooting hint to network-interface
closes #142
2016-07-15 13:18:33 +02:00
Patrick Kanzler
0ec83387d5 improve github issues template 2016-07-15 13:05:59 +02:00
Patrick Kanzler
36e0a52e2d DOC added stump for new changelog-entry 2016-06-26 20:52:31 +02:00
Patrick Kanzler
214b4def14 configure codecov.io
fixes #134
2016-06-26 20:39:06 +02:00
20 changed files with 309 additions and 95 deletions

View File

@@ -17,6 +17,10 @@ I have:
<!-- Replace examples with your info -->
**Printer:** Manufacturer Model XVI
<!-- since version 2.0.1 you can type 'python-escpos version' in your shell.
Alternatively you could use '__version__' in module escpos. -->
**python-escpos version:** 0.0.0
**python version:** 0.0
**operating system:**

2
.gitignore vendored
View File

@@ -17,6 +17,8 @@ temp
build/
dist/
.coverage
src/escpos/version.py
.hypothesis
# testing temporary directories
test/test-cli-output/

View File

@@ -28,6 +28,7 @@ matrix:
allow_failures:
- python: 3.5-dev
- python: nightly
- python: pypy3
before_install:
- pip install tox codecov
script:

View File

@@ -1,6 +1,46 @@
*********
Changelog
*********
2016-08-02 - Version 2.1.2 - "Death and Gravity"
------------------------------------------------
changes
^^^^^^^
- fix File-printer: flush after every call of _raw()
- fix lists in documentation
- fix CODE128: by adding the control character to the barcode-selection-sequence the barcode became unusable
contributors
^^^^^^^^^^^^
- Patrick Kanzler
2016-08-02 - Version 2.1.1 - "Contents May Differ"
--------------------------------------------------
changes
^^^^^^^
- rename variable interface in USB-class to timeout
- add support for hypothesis and move pypy3 to the allowed failures (pypy3 is not supported by hypothesis)
contributors
^^^^^^^^^^^^
- Patrick Kanzler
- Renato Lorenzi
2016-07-23 - Version 2.1.0 - "But Who's Counting?"
--------------------------------------------------
changes
^^^^^^^
- packaging: configured the coverage-analysis codecov.io
- GitHub: improved issues-template
- documentation: add troubleshooting tip to network-interface
- the module, cli and documentation is now aware of the version of python-escpos
- the cli does now support basic tabcompletion
contributors
^^^^^^^^^^^^
- Patrick Kanzler
2016-06-24 - Version 2.0.0 - "Attitude Adjuster"
------------------------------------------------

17
codecov.yml Normal file
View File

@@ -0,0 +1,17 @@
codecov:
bot: patkan
coverage:
status:
project:
default: # status context
target: auto
threshold: "1%"
patch:
default:
target: auto
threshold: "1%"
range: "60...100"
comment: off

View File

@@ -15,7 +15,10 @@
import sys
import os
on_rtd = os.getenv('READTHEDOCS') == 'True'
from setuptools_scm import get_version
if on_rtd:
import escpos
else:
from setuptools_scm import get_version
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
@@ -70,10 +73,14 @@ copyright = u'2016, Manuel F Martinez and others'
# |version| and |release|, also used in various other places throughout the
# built documents.
#
if on_rtd:
# The full version, including alpha/beta/rc tags.
release = escpos.__version__
else:
# locally setuptools_scm should work
release = get_version(root=root)
# The short X.Y version.
version = get_version(root=root)
# The full version, including alpha/beta/rc tags.
release = version
version = '.'.join(release.split('.')[:2]) # The short X.Y version.
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.

View File

@@ -12,13 +12,13 @@ Content
:maxdepth: 1
:caption: User Documentation
user/dependencies
user/installation
user/methods
user/printers
user/raspi
user/todo
user/usage
user/barcode
.. toctree::
:maxdepth: 1

34
doc/user/barcode.rst Normal file
View File

@@ -0,0 +1,34 @@
Printing Barcodes
-----------------
:Last Reviewed: 2016-07-31
Most ESC/POS-printers implement barcode-printing.
The barcode-commandset is implemented in the barcode-method.
For a list of compatible barcodes you should check the manual of your printer.
As a rule of thumb: even older Epson-models support most 1D-barcodes.
To be sure just try some implementations and have a look at the notices below.
barcode-method
~~~~~~~~~~~~~~
The barcode-method is rather low-level and orients itself on the implementation of ESC/POS.
In the future this class could be supplemented by a high-level class that helps the user generating the payload.
.. py:currentmodule:: escpos.escpos
.. automethod:: Escpos.barcode
:noindex:
CODE128
~~~~~~~
Code128 barcodes need a certain format.
For now the user has to make sure that the payload is correct.
For alphanumeric CODE128 you have to preface your payload with `{B`.
.. code-block:: Python
from escpos.printer import Dummy, Serial
p = Serial()
# print CODE128 012ABCDabcd
p.barcode("{B012ABCDabcd", "CODE128", function_type="B")
A very good description on CODE128 is also on `Wikipedia <https://en.wikipedia.org/wiki/Code_128>`_.

View File

@@ -1,57 +0,0 @@
************
Dependencies
************
Fedora
------
Fortunately everything is on Fedora repositories.
::
# yum install python-imaging pyserial pyusb python-qrcode
Ubuntu
------
Ultimately, this instructions also apply to Raspbian, in case you are
interested to install python-escpos on your Raspberry with Raspbian.
Install the packages available on distro repositories.
::
# apt-get install python-imaging pyserial
The packages which are not available at Ubuntu repositories need to be
installed manually.
pyusb
^^^^^
This is the python binding to libusb-1.0
* Get the latest tarball from `sourceforge <http://sourceforge.net/projects/pyusb/files/PyUSB%201.0/>`__
* Build and install it
::
# tar zxvf pyusb-1.*.tar.gz
# cd pyusb-1.*
# python setup.py build
# sudo python setup.py install
python-qrcode
^^^^^^^^^^^^^
This is the python module to generate QR Codes
* Checkout the latest code from `github <https://github.com/lincolnloop/python-qrcode>`__
* Build and install it
::
# git clone https://github.com/lincolnloop/python-qrcode
# cd python-qrcode
# python setup.py build
# sudo python setup.py install

View File

@@ -2,16 +2,26 @@
Installation
************
System preparation
------------------
:Last Reviewed: 2016-07-23
1. Install the required
`dependencies <https://github.com/manpaz/python-escpos/wiki/Dependencies>`__
Installation with PIP
---------------------
Installation should be rather straight-forward. python-escpos is on PyPi, so you can simply enter:
2. Get the *Product ID* and *Vendor ID* from the lsusb command
::
pip install python-escpos
This should install all necessary dependencies. Apart from that python-escpos should also be
available as a Debian package. If you want to always benefit from the newest stable releases you should probably
install from PyPi.
Setup udev for USB-Printers
---------------------------
1. Get the *Product ID* and *Vendor ID* from the lsusb command
``# lsusb Bus 002 Device 001: ID 1a2b:1a2b Device name``
3. Create a udev rule to let users belonging to *dialout* group use the
2. Create a udev rule to let users belonging to *dialout* group use the
printer. You can create the file
``/etc/udev/rules.d/99-escpos.rules`` and add the following:
``SUBSYSTEM=="usb", ATTRS{idVendor}=="1a2b", ATTRS{idProduct}=="1a2b", MODE="0664", GROUP="dialout"``
@@ -20,21 +30,19 @@ System preparation
"dialout" group, or use another group you already belongs instead
"dialout" and set it in the ``GROUP`` parameter in the above rule.
4. Restart udev ``# sudo service udev restart`` In some new systems it
3. Restart udev ``# sudo service udev restart`` In some new systems it
is done with ``# sudo udevadm control --reload``
Install
-------
Enabling tab-completion in CLI
------------------------------
python-escpos has a CLI with tab-completion. This is realised with ``argcomplete``.
In order for this to work you have to enable tab-completion, which is described in
the `manual of argcomplete <https://argcomplete.readthedocs.io>`__.
* Clone python-escpos from github
* Change directory to python-escpos and install the package
If you only want to enable it for python-escpos, or global activation does not work, try this:
::
::
# cd python-escpos
# python setup.py build
# sudo python setup.py install
* Enjoy !!!
eval "$(register-python-argcomplete python-escpos)"

View File

@@ -88,6 +88,7 @@ set("align", "font", "type", width, height, invert, smooth, flip)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Set text properties.
* ``align`` set horizontal position for text, the possible values are:
* CENTER
@@ -106,6 +107,7 @@ cut("mode")
^^^^^^^^^^^
Cut paper.
* ``mode`` set a full or partial cut. *Default:* full
**Partial cut is not implemented in all printers.**
@@ -132,6 +134,7 @@ control("align")
^^^^^^^^^^^^^^^^
Carrier feed and tabs.
* ``align`` is a string which takes any of the following values:
* LF *for Line Feed*

View File

@@ -32,11 +32,25 @@ Network("host", port)
^^^^^^^^^^^^^^^^^^^^^
Based on socket
* ``host`` is an alphanumeric host name, could be either DNS host name or IP address.
* ``port`` to write to (default = 9100)
Troubleshooting:
Problems with a network-attached printer can have numerous causes. Make sure that your device has a proper IP address.
Often you can check the IP address by triggering the self-test of the device. As a next step try to send text
manually to the device. You could use for example:
.. ::
echo "OK\n" | nc IPADDRESS 9100
# the port number is often 9100
As a last resort try to reset the interface of the printer. This should be described in its manual.
File("file\_name")
^^^^^^^^^^^^^^^^^^
Printcap printers
* ``file_name`` is the full path to the device file name

View File

@@ -45,9 +45,24 @@ class Tox(test_command):
errno = tox.cmdline(args=args)
sys.exit(errno)
setuptools_scm_template = """\
# coding: utf-8
# file generated by setuptools_scm
# don't change, don't track in version control
from __future__ import unicode_literals
version = '{version}'
"""
setup(
name='python-escpos',
use_scm_version=True,
use_scm_version={
'write_to': 'src/escpos/version.py',
'write_to_template': setuptools_scm_template,
},
url='https://github.com/python-escpos/python-escpos',
download_url='https://github.com/python-escpos/python-escpos/archive/master.zip',
description='Python library to manipulate ESC/POS Printers',
@@ -95,11 +110,13 @@ setup(
'six',
'appdirs',
'pyyaml',
'argparse',
'argcomplete',
],
setup_requires=[
'setuptools_scm',
],
tests_require=['tox', 'nose', 'scripttest'],
tests_require=['tox', 'nose', 'scripttest', 'mock', 'hypothesis'],
cmdclass={'test': Tox},
entry_points={
'console_scripts': [

View File

@@ -1 +1,19 @@
# -*- coding: utf-8 -*-
"""
python-escpos enables you to manipulate escpos-printers
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
__all__ = ["constants", "escpos", "exceptions", "printer"]
try:
from .version import version as __version__ # noqa
except ImportError: # pragma: no cover
raise ImportError(
'Failed to find (autogenerated) version.py. '
'This might be because you are installing from GitHub\'s tarballs, '
'use the PyPI ones.'
)

View File

@@ -1,4 +1,5 @@
#!/usr/bin/env python
# PYTHON_ARGCOMPLETE_OK
""" CLI
This module acts as a command line interface for python-escpos. It mirrors
@@ -14,9 +15,15 @@ from __future__ import print_function
from __future__ import unicode_literals
import argparse
try:
import argcomplete
except ImportError:
# this CLI works nevertheless without argcomplete
pass # noqa
import sys
import six
from . import config
from . import version
# Must be defined before it's used in DEMO_FUNCTIONS
@@ -448,14 +455,17 @@ def main():
# Allow config file location to be passed
parser.add_argument(
'-c', '--config',
help='Altnerate path to the configuration file',
help='Alternate path to the configuration file',
)
# Everything interesting runs off of a subparser so we can use the format
# cli [subparser] -args
command_subparsers = parser.add_subparsers(
title='ESCPOS Command',
dest='parser',
)
# fix inconsistencies in the behaviour of some versions of argparse
command_subparsers.required = False # force 'required' testing
# Build the ESCPOS command arguments
for command in ESCPOS_COMMANDS:
@@ -491,6 +501,14 @@ def main():
action='store_true',
)
parser_command_version = command_subparsers.add_parser('version',
help='Print the version of python-escpos')
parser_command_version.set_defaults(version=True)
# hook in argcomplete
if 'argcomplete' in globals():
argcomplete.autocomplete(parser)
# Get only arguments actually passed
args_dict = vars(parser.parse_args())
if not args_dict:
@@ -498,6 +516,12 @@ def main():
sys.exit()
command_arguments = dict([k, v] for k, v in six.iteritems(args_dict) if v is not None)
# If version should be printed, do this, then exit
print_version = command_arguments.pop('version', None)
if print_version:
print(version.version)
sys.exit()
# If there was a config path passed, grab it
config_path = command_arguments.pop('config', None)
@@ -511,6 +535,9 @@ def main():
target_command = command_arguments.pop('func')
# remove helper-argument 'parser' from dict
command_arguments.pop('parser', None)
if hasattr(printer, target_command):
# print command with args
getattr(printer, target_command)(**command_arguments)

View File

@@ -168,10 +168,7 @@ BARCODE_TYPE_B = {
'NW7': _SET_BARCODE_TYPE(71),
'CODABAR': _SET_BARCODE_TYPE(71), # Same as NW7
'CODE93': _SET_BARCODE_TYPE(72),
# These are all the same barcode, but using different charcter sets
'CODE128A': _SET_BARCODE_TYPE(73) + b'{A', # CODE128 character set A
'CODE128B': _SET_BARCODE_TYPE(73) + b'{B', # CODE128 character set B
'CODE128C': _SET_BARCODE_TYPE(73) + b'{C', # CODE128 character set C
'CODE128': _SET_BARCODE_TYPE(73),
'GS1-128': _SET_BARCODE_TYPE(74),
'GS1 DATABAR OMNIDIRECTIONAL': _SET_BARCODE_TYPE(75),
'GS1 DATABAR TRUNCATED': _SET_BARCODE_TYPE(76),

View File

@@ -34,18 +34,18 @@ class Usb(Escpos):
"""
def __init__(self, idVendor, idProduct, interface=0, in_ep=0x82, out_ep=0x01, *args, **kwargs):
def __init__(self, idVendor, idProduct, timeout=0, in_ep=0x82, out_ep=0x01, *args, **kwargs):
"""
:param idVendor: Vendor ID
:param idProduct: Product ID
:param interface: USB device interface
:param timeout: Is the time limit of the USB operation. Default without timeout.
:param in_ep: Input end point
:param out_ep: Output end point
"""
Escpos.__init__(self, *args, **kwargs)
self.idVendor = idVendor
self.idProduct = idProduct
self.interface = interface
self.timeout = timeout
self.in_ep = in_ep
self.out_ep = out_ep
self.open()
@@ -82,7 +82,7 @@ class Usb(Escpos):
:param msg: arbitrary code to be printed
:type msg: bytes
"""
self.device.write(self.out_ep, msg, self.interface)
self.device.write(self.out_ep, msg, self.timeout)
def close(self):
""" Release USB interface """
@@ -229,13 +229,15 @@ class File(Escpos):
"""
def __init__(self, devfile="/dev/usb/lp0", *args, **kwargs):
def __init__(self, devfile="/dev/usb/lp0", auto_flush=True, *args, **kwargs):
"""
:param devfile : Device file under dev filesystem
:param auto_flush: automatically call flush after every call of _raw()
"""
Escpos.__init__(self, *args, **kwargs)
self.devfile = devfile
self.auto_flush = auto_flush
self.open()
def open(self):
@@ -256,6 +258,8 @@ class File(Escpos):
:type msg: bytes
"""
self.device.write(msg)
if self.auto_flush:
self.flush()
def close(self):
""" Close system file """

View File

@@ -11,6 +11,7 @@ import os
import sys
from scripttest import TestFileEnvironment
from nose.tools import assert_equals
import escpos
TEST_DIR = os.path.abspath('test/test-cli-output')
@@ -29,7 +30,7 @@ printer:
)
class TestCLI:
class TestCLI():
""" Contains setups, teardowns, and tests for CLI
"""
@@ -60,8 +61,7 @@ class TestCLI:
)
self.default_args = (
sys.executable,
'-mescpos.cli',
'python-escpos',
'-c',
CONFIGFILE,
)
@@ -79,10 +79,16 @@ class TestCLI:
def test_cli_help(self):
""" Test getting help from cli """
result = self.env.run(sys.executable, '-mescpos.cli', '-h')
result = self.env.run('python-escpos', '-h')
assert not result.stderr
assert 'usage' in result.stdout
def test_cli_version(self):
""" Test the version string """
result = self.env.run('python-escpos', 'version')
assert not result.stderr
assert_equals(escpos.__version__, result.stdout.strip())
def test_cli_text(self):
""" Make sure text returns what we sent it """
test_text = 'this is some text'

70
test/test_printer_file.py Normal file
View File

@@ -0,0 +1,70 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
"""tests for the File printer
: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 six
import mock
from hypothesis import given
from hypothesis.strategies import text
import escpos.printer as printer
if six.PY3:
mock_open_call = 'builtins.open'
else:
mock_open_call = '__builtin__.open'
@given(path=text())
@mock.patch(mock_open_call)
@mock.patch('escpos.escpos.Escpos.__init__')
def test_load_file_printer(mock_escpos, mock_open, path):
"""test the loading of the file-printer"""
printer.File(devfile=path)
assert mock_escpos.called
mock_open.assert_called_with(path, "wb")
@given(txt=text())
@mock.patch.object(printer.File, 'device')
@mock.patch(mock_open_call)
@mock.patch('escpos.escpos.Escpos.__init__')
def test_auto_flush(mock_escpos, mock_open, mock_device, txt):
"""test auto_flush in file-printer"""
p = printer.File(auto_flush=False)
# inject the mocked device-object
p.device = mock_device
p._raw(txt)
assert not mock_device.flush.called
mock_device.reset_mock()
p = printer.File(auto_flush=True)
# inject the mocked device-object
p.device = mock_device
p._raw(txt)
assert mock_device.flush.called
@given(txt=text())
@mock.patch.object(printer.File, 'device')
@mock.patch(mock_open_call)
def test_flush_on_close(mock_open, mock_device, txt):
"""test flush on close in file-printer"""
p = printer.File(auto_flush=False)
# inject the mocked device-object
p.device = mock_device
p._raw(txt)
assert not mock_device.flush.called
p.close()
assert mock_device.flush.called
assert mock_device.close.called

View File

@@ -5,6 +5,8 @@ envlist = py27, py34, py35, docs
deps = nose
coverage
scripttest
mock
hypothesis
commands = nosetests --with-coverage --cover-erase --cover-branches
[testenv:docs]