mirror of
https://github.com/python-escpos/python-escpos
synced 2025-09-13 09:09:58 +00:00
Compare commits
69 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
8b3076871f | ||
![]() |
46429b1092 | ||
![]() |
99ca096f82 | ||
![]() |
2d97c0bbbd | ||
![]() |
6c6fe9bccf | ||
![]() |
c5e46a888d | ||
![]() |
46942820a5 | ||
![]() |
e50e295acc | ||
![]() |
2d7458fa49 | ||
![]() |
a6f635c0d5 | ||
![]() |
2d0f045457 | ||
![]() |
293b8632ff | ||
![]() |
5ff73595b6 | ||
![]() |
4ecab402b8 | ||
![]() |
c56e43da84 | ||
![]() |
88af26f46e | ||
![]() |
9dd966c2a3 | ||
![]() |
a7d959428f | ||
![]() |
8bf0e08659 | ||
![]() |
5ac5a24b50 | ||
![]() |
63252515b5 | ||
![]() |
29a546821b | ||
![]() |
4ddd18279f | ||
![]() |
de761e96e3 | ||
![]() |
ed7bce6932 | ||
![]() |
edd567785c | ||
![]() |
f1054876da | ||
![]() |
490e0657dd | ||
![]() |
b4c32b5a4a | ||
![]() |
40b30225d3 | ||
![]() |
19e3ec6895 | ||
![]() |
df539da854 | ||
![]() |
4534038b39 | ||
![]() |
adf85f7784 | ||
![]() |
aaa8162967 | ||
![]() |
0461adc212 | ||
![]() |
91ff83e506 | ||
![]() |
29ef88f591 | ||
![]() |
7c01a30d6c | ||
![]() |
035c425581 | ||
![]() |
d20646b2a9 | ||
![]() |
206822ac69 | ||
![]() |
dc08792e72 | ||
![]() |
2886075ce9 | ||
![]() |
73fff6291d | ||
![]() |
d5b9d99093 | ||
![]() |
18c51358aa | ||
![]() |
52719c0b7d | ||
![]() |
0051c876bf | ||
![]() |
854759d312 | ||
![]() |
a0343c66af | ||
![]() |
6c94f88c24 | ||
![]() |
6fb23d6826 | ||
![]() |
f649814091 | ||
![]() |
47b4d41b28 | ||
![]() |
599f4f3ca5 | ||
![]() |
d085e5c467 | ||
![]() |
b418302311 | ||
![]() |
f6acb72bbe | ||
![]() |
0c9856c1f6 | ||
![]() |
a748563395 | ||
![]() |
b84e280efb | ||
![]() |
4390dc4a9c | ||
![]() |
6e09fd1e97 | ||
![]() |
100c6b5e89 | ||
![]() |
26d72a69f0 | ||
![]() |
01e28bbcf6 | ||
![]() |
2a7e2a6a36 | ||
![]() |
3c3dab95f5 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -20,6 +20,7 @@ dist/
|
||||
.coverage
|
||||
src/escpos/version.py
|
||||
.hypothesis
|
||||
.pytest_cache/
|
||||
|
||||
# testing temporary directories
|
||||
test/test-cli-output/
|
||||
|
1
.gitmodules
vendored
1
.gitmodules
vendored
@@ -1,3 +1,4 @@
|
||||
[submodule "capabilities-data"]
|
||||
path = capabilities-data
|
||||
url = https://github.com/receipt-print-hq/escpos-printer-db.git
|
||||
branch = master
|
||||
|
3
.mailmap
3
.mailmap
@@ -8,5 +8,8 @@ Cody (Quantified Code Bot) <cody@quantifiedcode.com> Cody <cody@quantifiedcode.c
|
||||
Renato Lorenzi <renato.lorenzi@senior.com.br> Renato.Lorenzi <renato.lorenzi@senior.com.br>
|
||||
Ahmed Tahri <nyuubi.10@gmail.com> TAHRI Ahmed <nyuubi.10@gmail.com>
|
||||
Michael Elsdörfer <michael@elsdoerfer.com> Michael Elsdörfer <michael@elsdoerfer.info>
|
||||
Juanmi Taboada <juanmi@juanmitaboada.com> Juanmi Taboada <juanmi@juanmitaboada.com>
|
||||
csoft2k <csoft2k@hotmail.com>
|
||||
Sergio Pulgarin <sergio.pulgarin@gmail.com>
|
||||
reck31 <rakesh.gunduka@gmail.com>
|
||||
Alex Debiasio <alex.debiasio@thinkin.io> <alex.debiasio@studenti.unitn.it>
|
||||
|
43
.travis.yml
43
.travis.yml
@@ -1,18 +1,36 @@
|
||||
language: python
|
||||
sudo: false
|
||||
cache: pip
|
||||
dist: xenial
|
||||
git:
|
||||
depth: 100000
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- graphviz
|
||||
env:
|
||||
global:
|
||||
- ESCPOS_CAPABILITIES_FILE=/home/travis/build/python-escpos/python-escpos/capabilities-data/dist/capabilities.json
|
||||
matrix:
|
||||
fast_finish: true
|
||||
include:
|
||||
- name: "Python 3.7 on Windows"
|
||||
os: windows
|
||||
language: shell
|
||||
before_install:
|
||||
- choco install python
|
||||
- pip install tox codecov 'sphinx>=1.5.1'
|
||||
env:
|
||||
- TOXENV=py37
|
||||
- PATH=/c/Python37:/c/Python37/Scripts:$PATH
|
||||
- ESCPOS_CAPABILITIES_FILE=C:/Users/travis/build/python-escpos/python-escpos/capabilities-data/dist/capabilities.json
|
||||
- name: "Python 3.7 on macOS"
|
||||
os: osx
|
||||
osx_image: xcode10.2
|
||||
language: shell
|
||||
env: TOXENV=py37 ESCPOS_CAPABILITIES_FILE=/Users/travis/build/python-escpos/python-escpos/capabilities-data/dist/capabilities.json
|
||||
- python: 2.7
|
||||
env: TOXENV=py27
|
||||
- python: 3.3
|
||||
env: TOXENV=py33
|
||||
- python: 3.4
|
||||
env: TOXENV=py34
|
||||
- python: 3.5
|
||||
@@ -21,22 +39,31 @@ matrix:
|
||||
env: TOXENV=py36
|
||||
- python: 3.6-dev
|
||||
env: TOXENV=py36
|
||||
- python: nightly
|
||||
- python: 3.7
|
||||
env: TOXENV=py37
|
||||
- python: 3.7-dev
|
||||
env: TOXENV=py37
|
||||
- python: 3.8-dev
|
||||
env: TOXENV=py38
|
||||
- python: nightly
|
||||
env: TOXENV=py38
|
||||
- python: pypy
|
||||
env: TOXENV=pypy
|
||||
- python: pypy3
|
||||
env: TOXENV=pypy3
|
||||
- python: 2.7
|
||||
- python: 3.7
|
||||
env: TOXENV=docs
|
||||
- python: 2.7
|
||||
env: TOXENV=flake8
|
||||
- python: 3.6
|
||||
- python: 3.7
|
||||
env: TOXENV=flake8
|
||||
allow_failures:
|
||||
- python: 2.7
|
||||
- python: 3.6-dev
|
||||
- python: 3.7-dev
|
||||
- python: 3.8-dev
|
||||
- python: nightly
|
||||
- python: pypy3
|
||||
- os: windows
|
||||
- os: osx
|
||||
before_install:
|
||||
- pip install tox codecov 'sphinx>=1.5.1'
|
||||
- ./doc/generate_authors.sh --check
|
||||
@@ -59,4 +86,4 @@ deploy:
|
||||
tags: true
|
||||
repo: python-escpos/python-escpos
|
||||
branch: master
|
||||
condition: $TRAVIS_PYTHON_VERSION = "3.5"
|
||||
condition: $TRAVIS_PYTHON_VERSION = "3.7"
|
||||
|
9
AUTHORS
9
AUTHORS
@@ -1,4 +1,6 @@
|
||||
Ahmed Tahri
|
||||
akeonly
|
||||
Alex Debiasio
|
||||
Asuki Kono
|
||||
belono
|
||||
Christoph Heuel
|
||||
@@ -8,8 +10,11 @@ Curtis // mashedkeyboard
|
||||
Davis Goglin
|
||||
Dean Rispin
|
||||
Dmytro Katyukha
|
||||
Gerard Marull-Paretas
|
||||
Hark
|
||||
Joel Lehtonen
|
||||
Justin Vieira
|
||||
kennedy
|
||||
Kristi
|
||||
ldos
|
||||
Lucy Linder
|
||||
@@ -18,8 +23,12 @@ Michael Billington
|
||||
Michael Elsdörfer
|
||||
mrwunderbar666
|
||||
Nathan Bookham
|
||||
Omer Akram
|
||||
Patrick Kanzler
|
||||
primax79
|
||||
Qian Linfeng
|
||||
Ramon Poca
|
||||
reck31
|
||||
Renato Lorenzi
|
||||
Romain Porte
|
||||
Sam Cheng
|
||||
|
@@ -1,6 +1,69 @@
|
||||
*********
|
||||
Changelog
|
||||
*********
|
||||
2019-06-19 - Version 3.0a6 - "Mistake not..."
|
||||
---------------------------------------------
|
||||
This release is the seventh alpha release of the new version 3.0.
|
||||
Please be aware the the API is subject to change until v3.0 is
|
||||
released.
|
||||
|
||||
changes
|
||||
^^^^^^^
|
||||
- fix inclusion of the capabilities-file
|
||||
- execute CI jobs also on Windows and macOS-targets
|
||||
- improve documentation
|
||||
|
||||
contributors
|
||||
^^^^^^^^^^^^
|
||||
- Patrick Kanzler
|
||||
|
||||
2019-06-16 - Version 3.0a5 - "Lightly Seared On The Reality Grill"
|
||||
------------------------------------------------------------------
|
||||
This release is the sixth alpha release of the new version 3.0. Please
|
||||
be aware that the API is subject to change until v3.0 is released.
|
||||
|
||||
changes
|
||||
^^^^^^^
|
||||
- allow arbitrary USB arguments in USB-class
|
||||
- add Win32Raw-Printer on Windows-platforms
|
||||
- add and improve Windows support of USB-class
|
||||
- use pyyaml safe_load()
|
||||
- improve doc
|
||||
- implement _read method of Network printer class
|
||||
|
||||
contributors
|
||||
^^^^^^^^^^^^
|
||||
- Patrick Kanzler
|
||||
- Gerard Marull-Paretas
|
||||
- Ramon Poca
|
||||
- akeonly
|
||||
- Omer Akram
|
||||
- Justin Vieira
|
||||
|
||||
2018-05-15 - Version 3.0a4 - "Kakistocrat"
|
||||
------------------------------------------
|
||||
This release is the fifth alpha release of the new version 3.0. Please
|
||||
be aware that the API will still change until v3.0 is released.
|
||||
|
||||
changes
|
||||
^^^^^^^
|
||||
- raise exception when TypeError occurs in cashdraw (#268)
|
||||
- Feature/clear content in dummy printer (#271)
|
||||
- fix is_online() (#282)
|
||||
- improve documentation
|
||||
- Modified submodule to always pull from master branch (#283)
|
||||
- parameter for implementation of nonnative qrcode (#289)
|
||||
- improve platform independence (#296)
|
||||
|
||||
contributors
|
||||
^^^^^^^^^^^^
|
||||
- Christoph Heuel
|
||||
- Patrick Kanzler
|
||||
- kennedy
|
||||
- primax79
|
||||
- reck31
|
||||
- Thijs Triemstra
|
||||
|
||||
2017-10-08 - Version 3.0a3 - "Just Testing"
|
||||
-------------------------------------------
|
||||
This release is the fourth alpha release of the new version 3.0. Please
|
||||
|
@@ -1,6 +1,5 @@
|
||||
include *.rst
|
||||
include *.txt
|
||||
include COPYING
|
||||
include LICENSE
|
||||
include INSTALL
|
||||
include tox.ini
|
||||
|
13
README.rst
13
README.rst
@@ -65,6 +65,19 @@ The basic usage is:
|
||||
p.barcode('1324354657687', 'EAN13', 64, 2, '', '')
|
||||
p.cut()
|
||||
|
||||
|
||||
Another example based on the Network printer class:
|
||||
|
||||
.. code:: python
|
||||
|
||||
from escpos.printer import Network
|
||||
|
||||
kitchen = Network("192.168.1.100") #Printer IP Address
|
||||
kitchen.text("Hello World\n")
|
||||
kitchen.barcode('1324354657687', 'EAN13', 64, 2, '', '')
|
||||
kitchen.cut()
|
||||
|
||||
|
||||
The full project-documentation is available on `Read the Docs <https://python-escpos.readthedocs.io>`_.
|
||||
|
||||
Contributing
|
||||
|
Submodule capabilities-data updated: fd207aa9de...8885283d71
@@ -44,7 +44,7 @@ to have and the second yields the "Output Endpoint" address.
|
||||
|
||||
::
|
||||
|
||||
Epson = printer.Usb(0x04b8,0x0202)
|
||||
p = printer.Usb(0x04b8,0x0202)
|
||||
|
||||
By default the "Interface" number is "0" and the "Output Endpoint"
|
||||
address is "0x01". If you have other values then you can define them on
|
||||
@@ -55,7 +55,7 @@ on 0x81 and out\_ep=0x02, then the printer definition should look like:
|
||||
|
||||
::
|
||||
|
||||
Generic = printer.Usb(0x1a2b,0x1a2b,0,0x81,0x02)
|
||||
p = printer.Usb(0x1a2b,0x1a2b,0,0x81,0x02)
|
||||
|
||||
Network printer
|
||||
^^^^^^^^^^^^^^^
|
||||
@@ -67,7 +67,7 @@ IP by DHCP or you set it manually.
|
||||
|
||||
::
|
||||
|
||||
Epson = printer.Network("192.168.1.99")
|
||||
p = printer.Network("192.168.1.99")
|
||||
|
||||
Serial printer
|
||||
^^^^^^^^^^^^^^
|
||||
@@ -81,7 +81,10 @@ to.
|
||||
|
||||
::
|
||||
|
||||
Epson = printer.Serial("/dev/tty0")
|
||||
p = printer.Serial("/dev/tty0")
|
||||
|
||||
# on a Windows OS serial devices are typically accessible as COM
|
||||
p = printer.Serial("COM1")
|
||||
|
||||
Other printers
|
||||
^^^^^^^^^^^^^^
|
||||
@@ -93,7 +96,7 @@ passing the device node name.
|
||||
|
||||
::
|
||||
|
||||
Epson = printer.File("/dev/usb/lp1")
|
||||
p = printer.File("/dev/usb/lp1")
|
||||
|
||||
The default is "/dev/usb/lp0", so if the printer is located on that
|
||||
node, then you don't necessary need to pass the node name.
|
||||
@@ -108,17 +111,17 @@ on a USB interface.
|
||||
|
||||
from escpos import *
|
||||
""" Seiko Epson Corp. Receipt Printer M129 Definitions (EPSON TM-T88IV) """
|
||||
Epson = printer.Usb(0x04b8,0x0202)
|
||||
p = printer.Usb(0x04b8,0x0202)
|
||||
# Print text
|
||||
Epson.text("Hello World\n")
|
||||
p.text("Hello World\n")
|
||||
# Print image
|
||||
Epson.image("logo.gif")
|
||||
p.image("logo.gif")
|
||||
# Print QR Code
|
||||
Epson.qr("You can readme from your smartphone")
|
||||
p.qr("You can readme from your smartphone")
|
||||
# Print barcode
|
||||
Epson.barcode('1324354657687','EAN13',64,2,'','')
|
||||
p.barcode('1324354657687','EAN13',64,2,'','')
|
||||
# Cut paper
|
||||
Epson.cut()
|
||||
p.cut()
|
||||
|
||||
Configuration File
|
||||
------------------
|
||||
|
38
setup.py
38
setup.py
@@ -3,7 +3,6 @@
|
||||
import os
|
||||
import sys
|
||||
from setuptools import find_packages, setup
|
||||
from setuptools.command.test import test as test_command
|
||||
|
||||
|
||||
base_dir = os.path.dirname(__file__)
|
||||
@@ -19,33 +18,6 @@ def read(fname):
|
||||
return open(os.path.join(os.path.dirname(__file__), fname)).read()
|
||||
|
||||
|
||||
class Tox(test_command):
|
||||
"""proxy class that enables tox to be run with setup.py test"""
|
||||
user_options = [('tox-args=', 'a', "Arguments to pass to tox")]
|
||||
|
||||
def initialize_options(self):
|
||||
"""initialize the user-options"""
|
||||
test_command.initialize_options(self)
|
||||
self.tox_args = None
|
||||
|
||||
def finalize_options(self):
|
||||
"""finalize user-options"""
|
||||
test_command.finalize_options(self)
|
||||
self.test_args = []
|
||||
self.test_suite = True
|
||||
|
||||
def run_tests(self):
|
||||
"""run tox and pass on user-options"""
|
||||
# import here, cause outside the eggs aren't loaded
|
||||
import tox
|
||||
import shlex
|
||||
args = self.tox_args
|
||||
if args:
|
||||
args = shlex.split(self.tox_args)
|
||||
errno = tox.cmdline(args=args)
|
||||
sys.exit(errno)
|
||||
|
||||
|
||||
setuptools_scm_template = """\
|
||||
# coding: utf-8
|
||||
# file generated by setuptools_scm
|
||||
@@ -84,7 +56,7 @@ setup(
|
||||
platforms='any',
|
||||
package_dir={"": "src"},
|
||||
packages=find_packages(where="src", exclude=["tests", "tests.*"]),
|
||||
package_data={'': ['COPYING', 'src/escpos/capabilities.json']},
|
||||
package_data={'escpos': ['capabilities.json']},
|
||||
include_package_data=True,
|
||||
classifiers=[
|
||||
'Development Status :: 4 - Beta',
|
||||
@@ -93,10 +65,7 @@ setup(
|
||||
'License :: OSI Approved :: MIT License',
|
||||
'Operating System :: OS Independent',
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.3',
|
||||
'Programming Language :: Python :: 3.4',
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
@@ -125,16 +94,15 @@ setup(
|
||||
tests_require=[
|
||||
'jaconv',
|
||||
'tox',
|
||||
'pytest!=3.2.0',
|
||||
'pytest!=3.2.0,!=3.3.0',
|
||||
'pytest-cov',
|
||||
'pytest-mock',
|
||||
'nose',
|
||||
'scripttest',
|
||||
'mock',
|
||||
'hypothesis',
|
||||
'hypothesis!=3.56.9,<4',
|
||||
'flake8'
|
||||
],
|
||||
cmdclass={'test': Tox},
|
||||
entry_points={
|
||||
'console_scripts': [
|
||||
'python-escpos = escpos.cli:main'
|
||||
|
@@ -7,13 +7,14 @@ import time
|
||||
import six
|
||||
import yaml
|
||||
|
||||
from tempfile import gettempdir
|
||||
import platform
|
||||
|
||||
logging.basicConfig()
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
pickle_dir = environ.get('ESCPOS_CAPABILITIES_PICKLE_DIR', '/tmp/')
|
||||
pickle_path = path.join(pickle_dir, 'capabilities.pickle')
|
||||
pickle_dir = environ.get('ESCPOS_CAPABILITIES_PICKLE_DIR', gettempdir())
|
||||
pickle_path = path.join(pickle_dir, '{v}.capabilities.pickle'.format(v=platform.python_version()))
|
||||
capabilities_path = environ.get(
|
||||
'ESCPOS_CAPABILITIES_FILE',
|
||||
path.join(path.dirname(__file__), 'capabilities.json'))
|
||||
@@ -37,7 +38,7 @@ else:
|
||||
if full_load:
|
||||
logger.debug('Loading and pickling capabilities')
|
||||
with open(capabilities_path) as cp, open(pickle_path, 'wb') as pp:
|
||||
CAPABILITIES = yaml.load(cp)
|
||||
CAPABILITIES = yaml.safe_load(cp)
|
||||
pickle.dump(CAPABILITIES, pp, protocol=2)
|
||||
|
||||
logger.debug('Finished loading capabilities took %.2fs', time.time() - t0)
|
||||
@@ -47,7 +48,7 @@ PROFILES = CAPABILITIES['profiles']
|
||||
|
||||
|
||||
class NotSupported(Exception):
|
||||
"""Raised if a requested feature is not suppored by the
|
||||
"""Raised if a requested feature is not supported by the
|
||||
printer profile.
|
||||
"""
|
||||
pass
|
||||
@@ -90,7 +91,7 @@ class BaseProfile(object):
|
||||
return self.features.get(feature)
|
||||
|
||||
def get_code_pages(self):
|
||||
"""Return the support code pages as a {name: index} dict.
|
||||
"""Return the support code pages as a ``{name: index}`` dict.
|
||||
"""
|
||||
return {v: k for k, v in self.codePages.items()}
|
||||
|
||||
|
@@ -24,6 +24,8 @@ from re import match as re_match
|
||||
import barcode
|
||||
from barcode.writer import ImageWriter
|
||||
|
||||
import os
|
||||
|
||||
from .constants import ESC, GS, NUL, QR_ECLEVEL_L, QR_ECLEVEL_M, QR_ECLEVEL_H, QR_ECLEVEL_Q
|
||||
from .constants import QR_MODEL_1, QR_MODEL_2, QR_MICRO, BARCODE_TYPES, BARCODE_HEIGHT, BARCODE_WIDTH
|
||||
from .constants import BARCODE_FONT_A, BARCODE_FONT_B, BARCODE_FORMATS
|
||||
@@ -180,7 +182,7 @@ class Escpos(object):
|
||||
self._raw(GS + b'(L' + header + m + fn + data)
|
||||
|
||||
def qr(self, content, ec=QR_ECLEVEL_L, size=3, model=QR_MODEL_2,
|
||||
native=False, center=False):
|
||||
native=False, center=False, impl="bitImageRaster"):
|
||||
""" Print QR Code for the provided string
|
||||
|
||||
:param content: The content of the code. Numeric data will be more efficiently compacted.
|
||||
@@ -193,6 +195,7 @@ class Escpos(object):
|
||||
:param native: True to render the code on the printer, False to render the code as an image and send it to the
|
||||
printer (Default)
|
||||
:param center: Centers the code *default:* False
|
||||
:param impl: Image-printing-implementation, refer to :meth:`.image()` for details
|
||||
"""
|
||||
# Basic validation
|
||||
if ec not in [QR_ECLEVEL_L, QR_ECLEVEL_M, QR_ECLEVEL_H, QR_ECLEVEL_Q]:
|
||||
@@ -222,7 +225,7 @@ class Escpos(object):
|
||||
|
||||
# Convert the RGB image in printable image
|
||||
self.text('\n')
|
||||
self.image(im, center=center)
|
||||
self.image(im, center=center, impl=impl)
|
||||
self.text('\n')
|
||||
self.text('\n')
|
||||
return
|
||||
@@ -304,8 +307,8 @@ class Escpos(object):
|
||||
.. todo:: For fixed-length standards with mandatory checksum (EAN, UPC),
|
||||
compute and add the checksum automatically if missing.
|
||||
|
||||
:param bc: barcode format, see :py:func`~escpos.Escpos.barcode`
|
||||
:param code: alphanumeric data to be printed as bar code, see :py:func`~escpos.Escpos.barcode`
|
||||
:param bc: barcode format, see :py:meth:`.barcode()`
|
||||
:param code: alphanumeric data to be printed as bar code, see :py:meth:`.barcode()`
|
||||
:return: bool
|
||||
"""
|
||||
if bc not in BARCODE_FORMATS:
|
||||
@@ -392,7 +395,7 @@ class Escpos(object):
|
||||
*default*: A
|
||||
|
||||
:param check: If this parameter is True, the barcode format will be checked to ensure it meets the bc
|
||||
requirements as defigned in the esc/pos documentation. See py:func:`~escpos.Escpos.check_barcode`
|
||||
requirements as defigned in the esc/pos documentation. See :py:meth:`.check_barcode()`
|
||||
for more information. *default*: True.
|
||||
|
||||
:raises: :py:exc:`~escpos.exceptions.BarcodeSizeError`,
|
||||
@@ -487,11 +490,12 @@ class Escpos(object):
|
||||
barcode_class = barcode.get_barcode_class(barcode_type)
|
||||
my_code = barcode_class(data, writer=image_writer)
|
||||
|
||||
my_code.write("/dev/null", {
|
||||
'module_height': module_height,
|
||||
'module_width': module_width,
|
||||
'text_distance': text_distance
|
||||
})
|
||||
with open(os.devnull, "wb") as nullfile:
|
||||
my_code.write(nullfile, {
|
||||
'module_height': module_height,
|
||||
'module_width': module_width,
|
||||
'text_distance': text_distance
|
||||
})
|
||||
|
||||
# Retrieve the Pillow image and print it
|
||||
image = my_code.writer._image
|
||||
@@ -697,8 +701,8 @@ class Escpos(object):
|
||||
else:
|
||||
try:
|
||||
self._raw(CD_KICK_DEC_SEQUENCE(*pin))
|
||||
except:
|
||||
raise CashDrawerError()
|
||||
except TypeError as err:
|
||||
raise CashDrawerError(err)
|
||||
|
||||
def linedisplay_select(self, select_display=False):
|
||||
""" Selects the line display or the printer
|
||||
@@ -728,6 +732,7 @@ class Escpos(object):
|
||||
|
||||
You should connect a line display to your printer. You can do this by daisy-chaining
|
||||
the display between your computer and printer.
|
||||
|
||||
:param text: Text to display
|
||||
"""
|
||||
self.linedisplay_select(select_display=True)
|
||||
@@ -827,30 +832,41 @@ class Escpos(object):
|
||||
self._raw(PANEL_BUTTON_OFF)
|
||||
|
||||
def query_status(self, mode):
|
||||
""" Queries the printer for its status, and returns an array of integers containing it.
|
||||
"""
|
||||
Queries the printer for its status, and returns an array of integers containing it.
|
||||
|
||||
:param mode: Integer that sets the status mode queried to the printer.
|
||||
RT_STATUS_ONLINE: Printer status.
|
||||
RT_STATUS_PAPER: Paper sensor.
|
||||
:rtype: array(integer)"""
|
||||
- RT_STATUS_ONLINE: Printer status.
|
||||
- RT_STATUS_PAPER: Paper sensor.
|
||||
:rtype: array(integer)
|
||||
"""
|
||||
self._raw(mode)
|
||||
time.sleep(1)
|
||||
status = self._read()
|
||||
return status
|
||||
|
||||
def is_online(self):
|
||||
""" Queries the printer its online status.
|
||||
When online, returns True; False otherwise.
|
||||
:rtype: bool: True if online, False if offline."""
|
||||
"""
|
||||
Queries the online status of the printer.
|
||||
|
||||
:returns: When online, returns ``True``; ``False`` otherwise.
|
||||
:rtype: bool
|
||||
"""
|
||||
status = self.query_status(RT_STATUS_ONLINE)
|
||||
if len(status) == 0:
|
||||
return False
|
||||
return not (status & RT_MASK_ONLINE)
|
||||
return not (status[0] & RT_MASK_ONLINE)
|
||||
|
||||
def paper_status(self):
|
||||
""" Queries the printer its paper status.
|
||||
"""
|
||||
Queries the paper status of the printer.
|
||||
|
||||
Returns 2 if there is plenty of paper, 1 if the paper has arrived to
|
||||
the near-end sensor and 0 if there is no paper.
|
||||
:rtype: int: 2: Paper is adequate. 1: Paper ending. 0: No paper."""
|
||||
|
||||
:returns: 2: Paper is adequate. 1: Paper ending. 0: No paper.
|
||||
:rtype: int
|
||||
"""
|
||||
status = self.query_status(RT_STATUS_PAPER)
|
||||
if len(status) == 0:
|
||||
return 2
|
||||
@@ -866,7 +882,7 @@ 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.
|
||||
and assign it to the EscposIO class.
|
||||
This example explains the usage:
|
||||
|
||||
.. code-block:: Python
|
||||
|
@@ -34,41 +34,58 @@ class Usb(Escpos):
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, idVendor, idProduct, timeout=0, in_ep=0x82, out_ep=0x01, *args, **kwargs): # noqa: N803
|
||||
def __init__(self, idVendor, idProduct, usb_args=None, timeout=0, in_ep=0x82, out_ep=0x01,
|
||||
*args, **kwargs): # noqa: N803
|
||||
"""
|
||||
:param idVendor: Vendor ID
|
||||
:param idProduct: Product ID
|
||||
:param usb_args: Optional USB arguments (e.g. custom_match)
|
||||
: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.timeout = timeout
|
||||
self.in_ep = in_ep
|
||||
self.out_ep = out_ep
|
||||
self.open()
|
||||
|
||||
def open(self):
|
||||
""" Search device on USB tree and set it as escpos device """
|
||||
self.device = usb.core.find(idVendor=self.idVendor, idProduct=self.idProduct)
|
||||
usb_args = usb_args or {}
|
||||
if idVendor:
|
||||
usb_args['idVendor'] = idVendor
|
||||
if idProduct:
|
||||
usb_args['idProduct'] = idProduct
|
||||
self.open(usb_args)
|
||||
|
||||
def open(self, usb_args):
|
||||
""" Search device on USB tree and set it as escpos device.
|
||||
|
||||
:param usb_args: USB arguments
|
||||
"""
|
||||
self.device = usb.core.find(**usb_args)
|
||||
if self.device is None:
|
||||
raise USBNotFoundError("Device not found or cable not plugged in.")
|
||||
|
||||
check_driver = None
|
||||
self.idVendor = self.device.idVendor
|
||||
self.idProduct = self.device.idProduct
|
||||
|
||||
try:
|
||||
check_driver = self.device.is_kernel_driver_active(0)
|
||||
except NotImplementedError:
|
||||
pass
|
||||
# pyusb has three backends: libusb0, libusb1 and openusb but
|
||||
# only libusb1 backend implements the methods is_kernel_driver_active()
|
||||
# and detach_kernel_driver().
|
||||
# This helps enable this library to work on Windows.
|
||||
if self.device.backend.__module__.endswith("libusb1"):
|
||||
check_driver = None
|
||||
|
||||
if check_driver is None or check_driver:
|
||||
try:
|
||||
self.device.detach_kernel_driver(0)
|
||||
except usb.core.USBError as e:
|
||||
if check_driver is not None:
|
||||
print("Could not detatch kernel driver: {0}".format(str(e)))
|
||||
check_driver = self.device.is_kernel_driver_active(0)
|
||||
except NotImplementedError:
|
||||
pass
|
||||
|
||||
if check_driver is None or check_driver:
|
||||
try:
|
||||
self.device.detach_kernel_driver(0)
|
||||
except usb.core.USBError as e:
|
||||
if check_driver is not None:
|
||||
print("Could not detatch kernel driver: {0}".format(str(e)))
|
||||
|
||||
try:
|
||||
self.device.set_configuration()
|
||||
@@ -219,6 +236,11 @@ class Network(Escpos):
|
||||
"""
|
||||
self.device.sendall(msg)
|
||||
|
||||
def _read(self):
|
||||
""" Read data from the TCP socket """
|
||||
|
||||
return self.device.recv(16)
|
||||
|
||||
def close(self):
|
||||
""" Close TCP connection """
|
||||
if self.device is not None:
|
||||
@@ -312,5 +334,58 @@ class Dummy(Escpos):
|
||||
""" Get the data that was sent to this printer """
|
||||
return b''.join(self._output_list)
|
||||
|
||||
def clear(self):
|
||||
""" Clear the buffer of the printer
|
||||
|
||||
This method can be called if you send the contents to a physical printer
|
||||
and want to use the Dummy printer for new output.
|
||||
"""
|
||||
del self._output_list[:]
|
||||
|
||||
def close(self):
|
||||
pass
|
||||
|
||||
|
||||
_WIN32PRINT = False
|
||||
try:
|
||||
import win32print
|
||||
_WIN32PRINT = True
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
if _WIN32PRINT:
|
||||
class Win32Raw(Escpos):
|
||||
def __init__(self, printer_name=None, *args, **kwargs):
|
||||
Escpos.__init__(self, *args, **kwargs)
|
||||
if printer_name is not None:
|
||||
self.printer_name = printer_name
|
||||
else:
|
||||
self.printer_name = win32print.GetDefaultPrinter()
|
||||
self.hPrinter = None
|
||||
|
||||
def open(self, job_name="python-escpos"):
|
||||
if self.printer_name is None:
|
||||
raise Exception("Printer not found")
|
||||
self.hPrinter = win32print.OpenPrinter(self.printer_name)
|
||||
self.current_job = win32print.StartDocPrinter(self.hPrinter, 1, (job_name, None, "RAW"))
|
||||
win32print.StartPagePrinter(self.hPrinter)
|
||||
|
||||
def close(self):
|
||||
if not self.hPrinter:
|
||||
return
|
||||
win32print.EndPagePrinter(self.hPrinter)
|
||||
win32print.EndDocPrinter(self.hPrinter)
|
||||
win32print.ClosePrinter(self.hPrinter)
|
||||
self.hPrinter = None
|
||||
|
||||
def _raw(self, msg):
|
||||
""" Print any command sent in raw format
|
||||
|
||||
:param msg: arbitrary code to be printed
|
||||
:type msg: bytes
|
||||
"""
|
||||
if self.printer_name is None:
|
||||
raise Exception("Printer not found")
|
||||
if self.hPrinter is None:
|
||||
raise Exception("Printer job not opened")
|
||||
win32print.WritePrinter(self.hPrinter, msg)
|
||||
|
19
test/test_function_cashdraw.py
Normal file
19
test/test_function_cashdraw.py
Normal file
@@ -0,0 +1,19 @@
|
||||
#!/usr/bin/python
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import escpos.printer as printer
|
||||
from escpos.exceptions import CashDrawerError
|
||||
import pytest
|
||||
|
||||
|
||||
def test_raise_CashDrawerError():
|
||||
"""should raise an error if the sequence is invalid.
|
||||
"""
|
||||
instance = printer.Dummy()
|
||||
with pytest.raises(CashDrawerError):
|
||||
# call with sequence that is too long
|
||||
instance.cashdraw([1,1,1,1,1,1])
|
||||
|
8
test/test_function_dummy_clear.py
Normal file
8
test/test_function_dummy_clear.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from nose.tools import assert_raises
|
||||
from escpos.printer import Dummy
|
||||
|
||||
def test_printer_dummy_clear():
|
||||
printer = Dummy()
|
||||
printer.text("Hello")
|
||||
printer.clear()
|
||||
assert(printer.output == b'')
|
@@ -82,6 +82,7 @@ def test_invalid_model():
|
||||
instance.qr("1234", native=True, model="Hello")
|
||||
|
||||
|
||||
@pytest.mark.skip("this test has to be debugged")
|
||||
def test_image():
|
||||
"""Test QR as image"""
|
||||
instance = printer.Dummy()
|
||||
@@ -109,4 +110,4 @@ def instance():
|
||||
|
||||
def test_center_not_implementer(instance):
|
||||
with pytest.raises(NotImplementedError):
|
||||
instance.qr("test", center=True, native=True)
|
||||
instance.qr("test", center=True, native=True)
|
||||
|
16
test/test_function_softbarcode.py
Normal file
16
test/test_function_softbarcode.py
Normal file
@@ -0,0 +1,16 @@
|
||||
#!/usr/bin/python
|
||||
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 pytest
|
||||
|
||||
|
||||
def test_soft_barcode():
|
||||
"""just execute soft_barcode
|
||||
"""
|
||||
instance = printer.Dummy()
|
||||
instance.soft_barcode("ean8", "1234")
|
||||
|
@@ -27,6 +27,7 @@ else:
|
||||
mock_open_call = '__builtin__.open'
|
||||
|
||||
|
||||
@pytest.mark.skip("this test is broken and has to be fixed or discarded")
|
||||
@settings(use_coverage=False)
|
||||
@given(path=text())
|
||||
def test_load_file_printer(mocker, path):
|
||||
@@ -38,6 +39,7 @@ def test_load_file_printer(mocker, path):
|
||||
mock_open.assert_called_with(path, "wb")
|
||||
|
||||
|
||||
@pytest.mark.skip("this test is broken and has to be fixed or discarded")
|
||||
@settings(deadline=None, use_coverage=False)
|
||||
@given(txt=text())
|
||||
def test_auto_flush(mocker, txt):
|
||||
@@ -59,6 +61,7 @@ def test_auto_flush(mocker, txt):
|
||||
assert mock_device.flush.called
|
||||
|
||||
|
||||
@pytest.mark.skip("this test is broken and has to be fixed or discarded")
|
||||
@settings(deadline=None, use_coverage=False)
|
||||
@given(txt=text())
|
||||
def test_flush_on_close(mocker, txt):
|
||||
|
7
tox.ini
7
tox.ini
@@ -1,5 +1,5 @@
|
||||
[tox]
|
||||
envlist = py27, py34, py35, docs, flake8
|
||||
envlist = py27, py34, py35, py36, py37, docs, flake8
|
||||
|
||||
[testenv]
|
||||
deps = nose
|
||||
@@ -7,12 +7,13 @@ deps = nose
|
||||
coverage
|
||||
scripttest
|
||||
mock
|
||||
pytest!=3.2.0
|
||||
pytest!=3.2.0,!=3.3.0
|
||||
pytest-cov
|
||||
pytest-mock
|
||||
hypothesis
|
||||
hypothesis!=3.56.9,<4
|
||||
viivakoodi
|
||||
commands = py.test --cov escpos
|
||||
passenv = ESCPOS_CAPABILITIES_PICKLE_DIR ESCPOS_CAPABILITIES_FILE CI TRAVIS TRAVIS_* APPVEYOR APPVEYOR_* CODECOV_*
|
||||
|
||||
[testenv:docs]
|
||||
basepython = python
|
||||
|
Reference in New Issue
Block a user