mirror of
				https://github.com/python-escpos/python-escpos
				synced 2025-10-23 09:30:00 +00:00 
			
		
		
		
	reformat codebase
This commit is contained in:
		
							
								
								
									
										88
									
								
								doc/conf.py
									
									
									
									
									
								
							
							
						
						
									
										88
									
								
								doc/conf.py
									
									
									
									
									
								
							| @@ -14,7 +14,8 @@ | |||||||
|  |  | ||||||
| import sys | import sys | ||||||
| import os | import os | ||||||
| on_rtd = os.getenv('READTHEDOCS') == 'True' |  | ||||||
|  | on_rtd = os.getenv("READTHEDOCS") == "True" | ||||||
| if on_rtd: | if on_rtd: | ||||||
|     import escpos |     import escpos | ||||||
| else: | else: | ||||||
| @@ -23,8 +24,8 @@ else: | |||||||
| # If extensions (or modules to document with autodoc) are in another directory, | # 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 | # add these directories to sys.path here. If the directory is relative to the | ||||||
| # documentation root, use os.path.abspath to make it absolute, like shown here. | # documentation root, use os.path.abspath to make it absolute, like shown here. | ||||||
| sys.path.insert(0, os.path.abspath('../src')) | sys.path.insert(0, os.path.abspath("../src")) | ||||||
| root = os.path.relpath(os.path.join(os.path.dirname(__file__), '..')) | root = os.path.relpath(os.path.join(os.path.dirname(__file__), "..")) | ||||||
|  |  | ||||||
| # -- General configuration ------------------------------------------------ | # -- General configuration ------------------------------------------------ | ||||||
|  |  | ||||||
| @@ -35,40 +36,40 @@ root = os.path.relpath(os.path.join(os.path.dirname(__file__), '..')) | |||||||
| # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom | ||||||
| # ones. | # ones. | ||||||
| extensions = [ | extensions = [ | ||||||
|     'sphinx.ext.autodoc', |     "sphinx.ext.autodoc", | ||||||
|     'sphinx.ext.doctest', |     "sphinx.ext.doctest", | ||||||
|     'sphinx.ext.todo', |     "sphinx.ext.todo", | ||||||
|     'sphinx.ext.coverage', |     "sphinx.ext.coverage", | ||||||
|     'sphinx.ext.viewcode', |     "sphinx.ext.viewcode", | ||||||
|     'sphinx.ext.todo', |     "sphinx.ext.todo", | ||||||
|     'sphinx.ext.graphviz', |     "sphinx.ext.graphviz", | ||||||
|     'sphinx.ext.inheritance_diagram', |     "sphinx.ext.inheritance_diagram", | ||||||
|     'sphinxcontrib.spelling', |     "sphinxcontrib.spelling", | ||||||
| ] | ] | ||||||
|  |  | ||||||
| # supress warnings for external images | # supress warnings for external images | ||||||
| suppress_warnings = [ | suppress_warnings = [ | ||||||
|     'image.nonlocal_uri', |     "image.nonlocal_uri", | ||||||
| ] | ] | ||||||
|  |  | ||||||
| # enable todos | # enable todos | ||||||
| todo_include_todos = True | todo_include_todos = True | ||||||
|  |  | ||||||
| # Add any paths that contain templates here, relative to this directory. | # Add any paths that contain templates here, relative to this directory. | ||||||
| templates_path = ['_templates'] | templates_path = ["_templates"] | ||||||
|  |  | ||||||
| # The suffix of source filenames. | # The suffix of source filenames. | ||||||
| source_suffix = '.rst' | source_suffix = ".rst" | ||||||
|  |  | ||||||
| # The encoding of source files. | # The encoding of source files. | ||||||
| # source_encoding = 'utf-8-sig' | # source_encoding = 'utf-8-sig' | ||||||
|  |  | ||||||
| # The master toctree document. | # The master toctree document. | ||||||
| master_doc = 'index' | master_doc = "index" | ||||||
|  |  | ||||||
| # General information about the project. | # General information about the project. | ||||||
| project = u'python-escpos' | project = u"python-escpos" | ||||||
| copyright = u'2016, Manuel F Martinez and others' | copyright = u"2016, Manuel F Martinez and others" | ||||||
|  |  | ||||||
| # The version info for the project you're documenting, acts as replacement for | # The version info for the project you're documenting, acts as replacement for | ||||||
| # |version| and |release|, also used in various other places throughout the | # |version| and |release|, also used in various other places throughout the | ||||||
| @@ -81,7 +82,7 @@ else: | |||||||
|     # locally setuptools_scm should work |     # locally setuptools_scm should work | ||||||
|     release = get_version(root=root) |     release = get_version(root=root) | ||||||
| # The short X.Y version. | # The short X.Y version. | ||||||
| version = '.'.join(release.split('.')[:2])  # The short X.Y version. | version = ".".join(release.split(".")[:2])  # The short X.Y version. | ||||||
|  |  | ||||||
| # The language for content autogenerated by Sphinx. Refer to documentation | # The language for content autogenerated by Sphinx. Refer to documentation | ||||||
| # for a list of supported languages. | # for a list of supported languages. | ||||||
| @@ -95,7 +96,7 @@ version = '.'.join(release.split('.')[:2])  # The short X.Y version. | |||||||
|  |  | ||||||
| # List of patterns, relative to source directory, that match files and | # List of patterns, relative to source directory, that match files and | ||||||
| # directories to ignore when looking for source files. | # directories to ignore when looking for source files. | ||||||
| exclude_patterns = ['_build'] | exclude_patterns = ["_build"] | ||||||
|  |  | ||||||
| # The reST default role (used for this markup: `text`) to use for all | # The reST default role (used for this markup: `text`) to use for all | ||||||
| # documents. | # documents. | ||||||
| @@ -113,7 +114,7 @@ exclude_patterns = ['_build'] | |||||||
| # show_authors = False | # show_authors = False | ||||||
|  |  | ||||||
| # The name of the Pygments (syntax highlighting) style to use. | # The name of the Pygments (syntax highlighting) style to use. | ||||||
| pygments_style = 'sphinx' | pygments_style = "sphinx" | ||||||
|  |  | ||||||
| # A list of ignored prefixes for module index sorting. | # A list of ignored prefixes for module index sorting. | ||||||
| # modindex_common_prefix = [] | # modindex_common_prefix = [] | ||||||
| @@ -127,15 +128,16 @@ pygments_style = 'sphinx' | |||||||
| # The theme to use for HTML and HTML Help pages.  See the documentation for | # The theme to use for HTML and HTML Help pages.  See the documentation for | ||||||
| # a list of builtin themes. | # a list of builtin themes. | ||||||
| if on_rtd: | if on_rtd: | ||||||
|     html_theme = 'default' |     html_theme = "default" | ||||||
| else: | else: | ||||||
|     try: |     try: | ||||||
|         import sphinx_rtd_theme |         import sphinx_rtd_theme | ||||||
|         html_theme = 'sphinx_rtd_theme' |  | ||||||
|  |         html_theme = "sphinx_rtd_theme" | ||||||
|         html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] |         html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] | ||||||
|     except ImportError: |     except ImportError: | ||||||
|         print("no sphinx_rtd_theme found, switching to nature") |         print("no sphinx_rtd_theme found, switching to nature") | ||||||
|         html_theme = 'default' |         html_theme = "default" | ||||||
|  |  | ||||||
| # Theme options are theme-specific and customize the look and feel of a theme | # Theme options are theme-specific and customize the look and feel of a theme | ||||||
| # further.  For a list of options available for each theme, see the | # further.  For a list of options available for each theme, see the | ||||||
| @@ -159,12 +161,12 @@ else: | |||||||
| # The name of an image file (within the static path) to use as favicon of the | # The name of an image file (within the static path) to use as favicon of the | ||||||
| # docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32 | # docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32 | ||||||
| # pixels large. | # pixels large. | ||||||
| html_favicon = 'pyescpos.ico' | html_favicon = "pyescpos.ico" | ||||||
|  |  | ||||||
| # Add any paths that contain custom static files (such as style sheets) here, | # Add any paths that contain custom static files (such as style sheets) here, | ||||||
| # relative to this directory. They are copied after the builtin static files, | # relative to this directory. They are copied after the builtin static files, | ||||||
| # so a file named "default.css" will overwrite the builtin "default.css". | # so a file named "default.css" will overwrite the builtin "default.css". | ||||||
| html_static_path = ['_static'] | html_static_path = ["_static"] | ||||||
|  |  | ||||||
| # Add any extra paths that contain custom files (such as robots.txt or | # Add any extra paths that contain custom files (such as robots.txt or | ||||||
| # .htaccess) here, relative to this directory. These files are copied | # .htaccess) here, relative to this directory. These files are copied | ||||||
| @@ -213,7 +215,7 @@ html_static_path = ['_static'] | |||||||
| # html_file_suffix = None | # html_file_suffix = None | ||||||
|  |  | ||||||
| # Output file base name for HTML help builder. | # Output file base name for HTML help builder. | ||||||
| htmlhelp_basename = 'python-escposdoc' | htmlhelp_basename = "python-escposdoc" | ||||||
|  |  | ||||||
|  |  | ||||||
| # -- Options for LaTeX output --------------------------------------------- | # -- Options for LaTeX output --------------------------------------------- | ||||||
| @@ -221,10 +223,8 @@ htmlhelp_basename = 'python-escposdoc' | |||||||
| latex_elements = { | latex_elements = { | ||||||
|     # The paper size ('letterpaper' or 'a4paper'). |     # The paper size ('letterpaper' or 'a4paper'). | ||||||
|     #'papersize': 'letterpaper', |     #'papersize': 'letterpaper', | ||||||
|  |  | ||||||
|     # The font size ('10pt', '11pt' or '12pt'). |     # The font size ('10pt', '11pt' or '12pt'). | ||||||
|     #'pointsize': '10pt', |     #'pointsize': '10pt', | ||||||
|  |  | ||||||
|     # Additional stuff for the LaTeX preamble. |     # Additional stuff for the LaTeX preamble. | ||||||
|     #'preamble': '', |     #'preamble': '', | ||||||
| } | } | ||||||
| @@ -233,8 +233,13 @@ latex_elements = { | |||||||
| # (source start file, target name, title, | # (source start file, target name, title, | ||||||
| #  author, documentclass [howto, manual, or own class]). | #  author, documentclass [howto, manual, or own class]). | ||||||
| latex_documents = [ | latex_documents = [ | ||||||
|   ('index', 'python-escpos.tex', u'python-escpos Documentation', |     ( | ||||||
|    u'Manuel F Martinez and others', 'manual'), |         "index", | ||||||
|  |         "python-escpos.tex", | ||||||
|  |         u"python-escpos Documentation", | ||||||
|  |         u"Manuel F Martinez and others", | ||||||
|  |         "manual", | ||||||
|  |     ), | ||||||
| ] | ] | ||||||
|  |  | ||||||
| # The name of an image file (relative to this directory) to place at the top of | # The name of an image file (relative to this directory) to place at the top of | ||||||
| @@ -263,8 +268,13 @@ latex_documents = [ | |||||||
| # One entry per manual page. List of tuples | # One entry per manual page. List of tuples | ||||||
| # (source start file, name, description, authors, manual section). | # (source start file, name, description, authors, manual section). | ||||||
| man_pages = [ | man_pages = [ | ||||||
|     ('index', 'python-escpos', u'python-escpos Documentation', |     ( | ||||||
|      [u'Manuel F Martinez and others'], 1) |         "index", | ||||||
|  |         "python-escpos", | ||||||
|  |         u"python-escpos Documentation", | ||||||
|  |         [u"Manuel F Martinez and others"], | ||||||
|  |         1, | ||||||
|  |     ) | ||||||
| ] | ] | ||||||
|  |  | ||||||
| # If true, show URL addresses after external links. | # If true, show URL addresses after external links. | ||||||
| @@ -277,9 +287,15 @@ man_pages = [ | |||||||
| # (source start file, target name, title, author, | # (source start file, target name, title, author, | ||||||
| #  dir menu entry, description, category) | #  dir menu entry, description, category) | ||||||
| texinfo_documents = [ | texinfo_documents = [ | ||||||
|   ('index', 'python-escpos', u'python-escpos Documentation', |     ( | ||||||
|    u'Manuel F Martinez and others', 'python-escpos', 'One line description of project.', |         "index", | ||||||
|    'Miscellaneous'), |         "python-escpos", | ||||||
|  |         u"python-escpos Documentation", | ||||||
|  |         u"Manuel F Martinez and others", | ||||||
|  |         "python-escpos", | ||||||
|  |         "One line description of project.", | ||||||
|  |         "Miscellaneous", | ||||||
|  |     ), | ||||||
| ] | ] | ||||||
|  |  | ||||||
| # Documents to append as an appendix to all manuals. | # Documents to append as an appendix to all manuals. | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ from escpos.printer import Usb | |||||||
| 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") | ||||||
| p.text('\n') | p.text("\n") | ||||||
| p.text('\n') | p.text("\n") | ||||||
| p.barcode('123456', 'CODE39') | p.barcode("123456", "CODE39") | ||||||
|   | |||||||
| @@ -6,15 +6,23 @@ 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, | ||||||
|  |     ESC, | ||||||
|  |     CTL_LF, | ||||||
|  |     CTL_FF, | ||||||
|  |     CTL_CR, | ||||||
|  |     CTL_HT, | ||||||
|  |     CTL_VT, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
| def main(): | def main(): | ||||||
|     dummy = printer.Dummy() |     dummy = printer.Dummy() | ||||||
|  |  | ||||||
|     dummy.hw('init') |     dummy.hw("init") | ||||||
|  |  | ||||||
|     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) | ||||||
| @@ -36,14 +44,14 @@ def print_codepage(printer, 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() | ||||||
|  |  | ||||||
| @@ -51,12 +59,12 @@ def print_codepage(printer, codepage): | |||||||
|             byte = six.int2byte(x * 16 + y) |             byte = six.int2byte(x * 16 + y) | ||||||
|  |  | ||||||
|             if byte in (ESC, CTL_LF, CTL_FF, CTL_CR, CTL_HT, CTL_VT): |             if byte in (ESC, CTL_LF, CTL_FF, CTL_CR, CTL_HT, CTL_VT): | ||||||
|                 byte = ' ' |                 byte = " " | ||||||
|  |  | ||||||
|             printer._raw(byte) |             printer._raw(byte) | ||||||
|             printer._raw(sep) |             printer._raw(sep) | ||||||
|         printer._raw('\n') |         printer._raw("\n") | ||||||
|  |  | ||||||
|  |  | ||||||
| if __name__ == '__main__': | if __name__ == "__main__": | ||||||
|     main() |     main() | ||||||
|   | |||||||
| @@ -7,7 +7,7 @@ def usage(): | |||||||
|     print("usage: qr_code.py <content>") |     print("usage: qr_code.py <content>") | ||||||
|  |  | ||||||
|  |  | ||||||
| if __name__ == '__main__': | if __name__ == "__main__": | ||||||
|     if len(sys.argv) != 2: |     if len(sys.argv) != 2: | ||||||
|         usage() |         usage() | ||||||
|         sys.exit(1) |         sys.exit(1) | ||||||
|   | |||||||
| @@ -5,5 +5,5 @@ from escpos.printer import Usb | |||||||
| 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") | ||||||
| p.soft_barcode('code39', '1234') | p.soft_barcode("code39", "1234") | ||||||
|   | |||||||
| @@ -38,88 +38,90 @@ 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 | ||||||
|  |  | ||||||
|  |  | ||||||
| # Dumps one forecast line to the printer | # Dumps one forecast line to the printer | ||||||
| def forecast(idx): | def forecast(idx): | ||||||
|     date = datetime.fromtimestamp(int(data['daily']['data'][idx]['time'])) |     date = datetime.fromtimestamp(int(data["daily"]["data"][idx]["time"])) | ||||||
|     day = calendar.day_name[date.weekday()] |     day = calendar.day_name[date.weekday()] | ||||||
|     lo = data['daily']['data'][idx]['temperatureMin'] |     lo = data["daily"]["data"][idx]["temperatureMin"] | ||||||
|     hi = data['daily']['data'][idx]['temperatureMax'] |     hi = data["daily"]["data"][idx]["temperatureMax"] | ||||||
|     cond = data['daily']['data'][idx]['summary'] |     cond = data["daily"]["data"][idx]["summary"] | ||||||
|     print(date) |     print(date) | ||||||
|     print(day) |     print(day) | ||||||
|     print(lo) |     print(lo) | ||||||
|     print(hi) |     print(hi) | ||||||
|     print(cond) |     print(cond) | ||||||
|     time.sleep(1) |     time.sleep(1) | ||||||
|     printer.set( |     printer.set(font="a", height=2, align="left", bold=False, double_height=False) | ||||||
|         font='a', |     printer.text(day + " \n ") | ||||||
|         height=2, |  | ||||||
|         align='left', |  | ||||||
|         bold=False, |  | ||||||
|         double_height=False) |  | ||||||
|     printer.text(day + ' \n ') |  | ||||||
|     time.sleep(5)  # Sleep to prevent printer buffer overflow |     time.sleep(5)  # Sleep to prevent printer buffer overflow | ||||||
|     printer.text('\n') |     printer.text("\n") | ||||||
|     printer.image(forecast_icon(idx)) |     printer.image(forecast_icon(idx)) | ||||||
|     printer.text('low ' + str(lo)) |     printer.text("low " + str(lo)) | ||||||
|     printer.text(deg) |     printer.text(deg) | ||||||
|     printer.text('\n') |     printer.text("\n") | ||||||
|     printer.text(' high ' + str(hi)) |     printer.text(" high " + str(hi)) | ||||||
|     printer.text(deg) |     printer.text(deg) | ||||||
|     printer.text('\n') |     printer.text("\n") | ||||||
|     # take care of pesky unicode dash |     # take care of pesky unicode dash | ||||||
|     printer.text(cond.replace(u'\u2013', '-').encode('utf-8')) |     printer.text(cond.replace(u"\u2013", "-").encode("utf-8")) | ||||||
|     printer.text('\n \n') |     printer.text("\n \n") | ||||||
|  |  | ||||||
|  |  | ||||||
| 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 = ( | ||||||
|     "?exclude=[alerts,minutely,hourly,flags]&units=si"  # change last bit to 'us' for Fahrenheit |     "https://api.darksky.net/forecast/" | ||||||
|  |     + API_KEY | ||||||
|  |     + "/" | ||||||
|  |     + LAT | ||||||
|  |     + "," | ||||||
|  |     + LONG | ||||||
|  |     + "?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") | ||||||
|  |  | ||||||
|  |  | ||||||
| # Print current conditions | # Print current conditions | ||||||
| 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"] | ||||||
| cond = data['currently']['summary'] | cond = data["currently"]["summary"] | ||||||
| printer.text(temp) | printer.text(temp) | ||||||
| printer.text(' ') | printer.text(" ") | ||||||
| printer.text(deg) | printer.text(deg) | ||||||
| printer.text(' ') | printer.text(" ") | ||||||
| printer.text('\n') | printer.text("\n") | ||||||
| printer.text('Sky: ' + cond) | printer.text("Sky: " + cond) | ||||||
| printer.text('\n') | printer.text("\n") | ||||||
| printer.text('\n') | printer.text("\n") | ||||||
|  |  | ||||||
| # Print forecast | # Print forecast | ||||||
| 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('Forecast: \n') | printer.text("Forecast: \n") | ||||||
| forecast(0) | forecast(0) | ||||||
| forecast(1) | forecast(1) | ||||||
| printer.cut() | printer.cut() | ||||||
|   | |||||||
| @@ -9,7 +9,7 @@ try: | |||||||
|     from .version import version as __version__  # noqa |     from .version import version as __version__  # noqa | ||||||
| except ImportError:  # pragma: no cover | except ImportError:  # pragma: no cover | ||||||
|     raise ImportError( |     raise ImportError( | ||||||
|         'Failed to find (autogenerated) version.py. ' |         "Failed to find (autogenerated) version.py. " | ||||||
|         'This might be because you are installing from GitHub\'s tarballs, ' |         "This might be because you are installing from GitHub's tarballs, " | ||||||
|         'use the PyPI ones.' |         "use the PyPI ones." | ||||||
|     ) |     ) | ||||||
|   | |||||||
| @@ -16,48 +16,53 @@ from typing import Any, Dict | |||||||
| logging.basicConfig() | logging.basicConfig() | ||||||
| logger = logging.getLogger(__name__) | logger = logging.getLogger(__name__) | ||||||
|  |  | ||||||
| pickle_dir = environ.get('ESCPOS_CAPABILITIES_PICKLE_DIR', gettempdir()) | pickle_dir = environ.get("ESCPOS_CAPABILITIES_PICKLE_DIR", gettempdir()) | ||||||
| pickle_path = path.join(pickle_dir, '{v}.capabilities.pickle'.format(v=platform.python_version())) | pickle_path = path.join( | ||||||
|  |     pickle_dir, "{v}.capabilities.pickle".format(v=platform.python_version()) | ||||||
|  | ) | ||||||
| # get a temporary file from pkg_resources if no file is specified in env | # get a temporary file from pkg_resources if no file is specified in env | ||||||
| capabilities_path = environ.get('ESCPOS_CAPABILITIES_FILE', | capabilities_path = environ.get( | ||||||
|                                 pkg_resources.resource_filename(__name__, 'capabilities.json')) |     "ESCPOS_CAPABILITIES_FILE", | ||||||
|  |     pkg_resources.resource_filename(__name__, "capabilities.json"), | ||||||
|  | ) | ||||||
|  |  | ||||||
| # Load external printer database | # Load external printer database | ||||||
| t0 = time.time() | t0 = time.time() | ||||||
| logger.debug('Using capabilities from file: %s', capabilities_path) | logger.debug("Using capabilities from file: %s", capabilities_path) | ||||||
| if path.exists(pickle_path): | if path.exists(pickle_path): | ||||||
|     if path.getmtime(capabilities_path) > path.getmtime(pickle_path): |     if path.getmtime(capabilities_path) > path.getmtime(pickle_path): | ||||||
|         logger.debug('Found a more recent capabilities file') |         logger.debug("Found a more recent capabilities file") | ||||||
|         full_load = True |         full_load = True | ||||||
|     else: |     else: | ||||||
|         full_load = False |         full_load = False | ||||||
|         logger.debug('Loading capabilities from pickle in %s', pickle_path) |         logger.debug("Loading capabilities from pickle in %s", pickle_path) | ||||||
|         with open(pickle_path, 'rb') as cf: |         with open(pickle_path, "rb") as cf: | ||||||
|             CAPABILITIES = pickle.load(cf) |             CAPABILITIES = pickle.load(cf) | ||||||
| else: | else: | ||||||
|     logger.debug('Capabilities pickle file not found: %s', pickle_path) |     logger.debug("Capabilities pickle file not found: %s", pickle_path) | ||||||
|     full_load = True |     full_load = True | ||||||
|  |  | ||||||
| if full_load: | if full_load: | ||||||
|     logger.debug('Loading and pickling capabilities') |     logger.debug("Loading and pickling capabilities") | ||||||
|     with open(capabilities_path) as cp, open(pickle_path, 'wb') as pp: |     with open(capabilities_path) as cp, open(pickle_path, "wb") as pp: | ||||||
|         CAPABILITIES = yaml.safe_load(cp) |         CAPABILITIES = yaml.safe_load(cp) | ||||||
|         pickle.dump(CAPABILITIES, pp, protocol=2) |         pickle.dump(CAPABILITIES, pp, protocol=2) | ||||||
|  |  | ||||||
| logger.debug('Finished loading capabilities took %.2fs', time.time() - t0) | logger.debug("Finished loading capabilities took %.2fs", time.time() - t0) | ||||||
|  |  | ||||||
|  |  | ||||||
| PROFILES: Dict[str, Any] = CAPABILITIES['profiles'] | PROFILES: Dict[str, Any] = CAPABILITIES["profiles"] | ||||||
|  |  | ||||||
|  |  | ||||||
| class NotSupported(Exception): | class NotSupported(Exception): | ||||||
|     """Raised if a requested feature is not supported by the |     """Raised if a requested feature is not supported by the | ||||||
|     printer profile. |     printer profile. | ||||||
|     """ |     """ | ||||||
|  |  | ||||||
|     pass |     pass | ||||||
|  |  | ||||||
|  |  | ||||||
| BARCODE_B = 'barcodeB' | BARCODE_B = "barcodeB" | ||||||
|  |  | ||||||
|  |  | ||||||
| class BaseProfile(object): | class BaseProfile(object): | ||||||
| @@ -76,26 +81,24 @@ class BaseProfile(object): | |||||||
|         """Return the escpos index for `font`. Makes sure that |         """Return the escpos index for `font`. Makes sure that | ||||||
|         the requested `font` is valid. |         the requested `font` is valid. | ||||||
|         """ |         """ | ||||||
|         font = {'a': 0, 'b': 1}.get(font, font) |         font = {"a": 0, "b": 1}.get(font, font) | ||||||
|         if not six.text_type(font) in self.fonts: |         if not six.text_type(font) in self.fonts: | ||||||
|             raise NotSupported( |             raise NotSupported( | ||||||
|                 '"{}" is not a valid font in the current profile'.format(font)) |                 '"{}" is not a valid font in the current profile'.format(font) | ||||||
|  |             ) | ||||||
|         return font |         return font | ||||||
|  |  | ||||||
|     def get_columns(self, font): |     def get_columns(self, font): | ||||||
|         """ Return the number of columns for the given font. |         """Return the number of columns for the given font.""" | ||||||
|         """ |  | ||||||
|         font = self.get_font(font) |         font = self.get_font(font) | ||||||
|         return self.fonts[six.text_type(font)]['columns'] |         return self.fonts[six.text_type(font)]["columns"] | ||||||
|  |  | ||||||
|     def supports(self, feature): |     def supports(self, feature): | ||||||
|         """Return true/false for the given feature. |         """Return true/false for the given feature.""" | ||||||
|         """ |  | ||||||
|         return self.features.get(feature) |         return self.features.get(feature) | ||||||
|  |  | ||||||
|     def get_code_pages(self): |     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()} |         return {v: k for k, v in self.codePages.items()} | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -106,7 +109,7 @@ def get_profile(name: str=None, **kwargs): | |||||||
|     if isinstance(name, Profile): |     if isinstance(name, Profile): | ||||||
|         return name |         return name | ||||||
|  |  | ||||||
|     clazz = get_profile_class(name or 'default') |     clazz = get_profile_class(name or "default") | ||||||
|     return clazz(**kwargs) |     return clazz(**kwargs) | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -120,9 +123,8 @@ def get_profile_class(name: str): | |||||||
|     if name not in CLASS_CACHE: |     if name not in CLASS_CACHE: | ||||||
|         profile_data = PROFILES[name] |         profile_data = PROFILES[name] | ||||||
|         profile_name = clean(name) |         profile_name = clean(name) | ||||||
|         class_name = '{}{}Profile'.format( |         class_name = "{}{}Profile".format(profile_name[0].upper(), profile_name[1:]) | ||||||
|             profile_name[0].upper(), profile_name[1:]) |         new_class = type(class_name, (BaseProfile,), {"profile_data": profile_data}) | ||||||
|         new_class = type(class_name, (BaseProfile,), {'profile_data': profile_data}) |  | ||||||
|         CLASS_CACHE[name] = new_class |         CLASS_CACHE[name] = new_class | ||||||
|  |  | ||||||
|     return CLASS_CACHE[name] |     return CLASS_CACHE[name] | ||||||
| @@ -130,13 +132,13 @@ def get_profile_class(name: str): | |||||||
|  |  | ||||||
| def clean(s): | def clean(s): | ||||||
|     # Remove invalid characters |     # Remove invalid characters | ||||||
|     s = re.sub('[^0-9a-zA-Z_]', '', s) |     s = re.sub("[^0-9a-zA-Z_]", "", s) | ||||||
|     # Remove leading characters until we find a letter or underscore |     # Remove leading characters until we find a letter or underscore | ||||||
|     s = re.sub('^[^a-zA-Z_]+', '', s) |     s = re.sub("^[^a-zA-Z_]+", "", s) | ||||||
|     return str(s) |     return str(s) | ||||||
|  |  | ||||||
|  |  | ||||||
| class Profile(get_profile_class('default')): | class Profile(get_profile_class("default")): | ||||||
|     """ |     """ | ||||||
|     For users, who want to provide their profile |     For users, who want to provide their profile | ||||||
|     """ |     """ | ||||||
|   | |||||||
| @@ -11,6 +11,7 @@ It requires you to have a configuration file. See documentation for details. | |||||||
|  |  | ||||||
|  |  | ||||||
| import argparse | import argparse | ||||||
|  |  | ||||||
| try: | try: | ||||||
|     import argcomplete |     import argcomplete | ||||||
| except ImportError: | except ImportError: | ||||||
| @@ -27,11 +28,11 @@ def str_to_bool(string): | |||||||
|     """Used as a type in argparse so that we get back a proper |     """Used as a type in argparse so that we get back a proper | ||||||
|     bool instead of always True |     bool instead of always True | ||||||
|     """ |     """ | ||||||
|     return string.lower() in ('y', 'yes', '1', 'true') |     return string.lower() in ("y", "yes", "1", "true") | ||||||
|  |  | ||||||
|  |  | ||||||
| # A list of functions that work better with a newline to be sent after them. | # A list of functions that work better with a newline to be sent after them. | ||||||
| REQUIRES_NEWLINE = ('qr', 'barcode', 'text', 'block_text') | REQUIRES_NEWLINE = ("qr", "barcode", "text", "block_text") | ||||||
|  |  | ||||||
|  |  | ||||||
| # Used in demo method | # Used in demo method | ||||||
| @@ -39,40 +40,46 @@ REQUIRES_NEWLINE = ('qr', 'barcode', 'text', 'block_text') | |||||||
| #   manual translation is done in the case of barcodes_a -> barcode. | #   manual translation is done in the case of barcodes_a -> barcode. | ||||||
| # Value: A list of dictionaries to pass to the escpos function as arguments. | # Value: A list of dictionaries to pass to the escpos function as arguments. | ||||||
| DEMO_FUNCTIONS = { | DEMO_FUNCTIONS = { | ||||||
|     'text': [ |     "text": [ | ||||||
|         {'txt': 'Hello, World!\n', } |         { | ||||||
|  |             "txt": "Hello, World!\n", | ||||||
|  |         } | ||||||
|     ], |     ], | ||||||
|     'qr': [ |     "qr": [ | ||||||
|         {'content': 'This tests a QR code'}, |         {"content": "This tests a QR code"}, | ||||||
|         {'content': 'https://en.wikipedia.org/'} |         {"content": "https://en.wikipedia.org/"}, | ||||||
|     ], |     ], | ||||||
|     'barcodes_a': [ |     "barcodes_a": [ | ||||||
|         {'bc': 'UPC-A', 'code': '13243546576'}, |         {"bc": "UPC-A", "code": "13243546576"}, | ||||||
|         {'bc': 'UPC-E', 'code': '132435'}, |         {"bc": "UPC-E", "code": "132435"}, | ||||||
|         {'bc': 'EAN13', 'code': '1324354657687'}, |         {"bc": "EAN13", "code": "1324354657687"}, | ||||||
|         {'bc': 'EAN8', 'code': '1324354'}, |         {"bc": "EAN8", "code": "1324354"}, | ||||||
|         {'bc': 'CODE39', 'code': 'TEST'}, |         {"bc": "CODE39", "code": "TEST"}, | ||||||
|         {'bc': 'ITF', 'code': '55867492279103'}, |         {"bc": "ITF", "code": "55867492279103"}, | ||||||
|         {'bc': 'NW7', 'code': 'A00000000A'}, |         {"bc": "NW7", "code": "A00000000A"}, | ||||||
|     ], |     ], | ||||||
|     'barcodes_b': [ |     "barcodes_b": [ | ||||||
|         {'bc': 'UPC-A', 'code': '13243546576', 'function_type': 'B'}, |         {"bc": "UPC-A", "code": "13243546576", "function_type": "B"}, | ||||||
|         {'bc': 'UPC-E', 'code': '132435', 'function_type': 'B'}, |         {"bc": "UPC-E", "code": "132435", "function_type": "B"}, | ||||||
|         {'bc': 'EAN13', 'code': '1324354657687', 'function_type': 'B'}, |         {"bc": "EAN13", "code": "1324354657687", "function_type": "B"}, | ||||||
|         {'bc': 'EAN8', 'code': '1324354', 'function_type': 'B'}, |         {"bc": "EAN8", "code": "1324354", "function_type": "B"}, | ||||||
|         {'bc': 'CODE39', 'code': 'TEST', 'function_type': 'B'}, |         {"bc": "CODE39", "code": "TEST", "function_type": "B"}, | ||||||
|         {'bc': 'ITF', 'code': '55867492279103', 'function_type': 'B'}, |         {"bc": "ITF", "code": "55867492279103", "function_type": "B"}, | ||||||
|         {'bc': 'NW7', 'code': 'A00000000A', 'function_type': 'B'}, |         {"bc": "NW7", "code": "A00000000A", "function_type": "B"}, | ||||||
|         {'bc': 'CODE93', 'code': 'A00000000A', 'function_type': 'B'}, |         {"bc": "CODE93", "code": "A00000000A", "function_type": "B"}, | ||||||
|         {'bc': 'CODE93', 'code': '1324354657687', 'function_type': 'B'}, |         {"bc": "CODE93", "code": "1324354657687", "function_type": "B"}, | ||||||
|         {'bc': 'CODE128A', 'code': 'TEST', 'function_type': 'B'}, |         {"bc": "CODE128A", "code": "TEST", "function_type": "B"}, | ||||||
|         {'bc': 'CODE128B', 'code': 'TEST', 'function_type': 'B'}, |         {"bc": "CODE128B", "code": "TEST", "function_type": "B"}, | ||||||
|         {'bc': 'CODE128C', 'code': 'TEST', 'function_type': 'B'}, |         {"bc": "CODE128C", "code": "TEST", "function_type": "B"}, | ||||||
|         {'bc': 'GS1-128', 'code': '00123456780000000001', 'function_type': 'B'}, |         {"bc": "GS1-128", "code": "00123456780000000001", "function_type": "B"}, | ||||||
|         {'bc': 'GS1 DataBar Omnidirectional', 'code': '0000000000000', 'function_type': 'B'}, |         { | ||||||
|         {'bc': 'GS1 DataBar Truncated', 'code': '0000000000000', 'function_type': 'B'}, |             "bc": "GS1 DataBar Omnidirectional", | ||||||
|         {'bc': 'GS1 DataBar Limited', 'code': '0000000000000', 'function_type': 'B'}, |             "code": "0000000000000", | ||||||
|         {'bc': 'GS1 DataBar Expanded', 'code': '00AAAAAAA', 'function_type': 'B'}, |             "function_type": "B", | ||||||
|  |         }, | ||||||
|  |         {"bc": "GS1 DataBar Truncated", "code": "0000000000000", "function_type": "B"}, | ||||||
|  |         {"bc": "GS1 DataBar Limited", "code": "0000000000000", "function_type": "B"}, | ||||||
|  |         {"bc": "GS1 DataBar Expanded", "code": "00AAAAAAA", "function_type": "B"}, | ||||||
|     ], |     ], | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -84,356 +91,355 @@ DEMO_FUNCTIONS = { | |||||||
| # arguments: A list of dicts of args for subparser.add_argument | # arguments: A list of dicts of args for subparser.add_argument | ||||||
| ESCPOS_COMMANDS = [ | ESCPOS_COMMANDS = [ | ||||||
|     { |     { | ||||||
|         'parser': { |         "parser": { | ||||||
|             'name': 'qr', |             "name": "qr", | ||||||
|             'help': 'Print a QR code', |             "help": "Print a QR code", | ||||||
|         }, |         }, | ||||||
|         'defaults': { |         "defaults": { | ||||||
|             'func': 'qr', |             "func": "qr", | ||||||
|         }, |         }, | ||||||
|         'arguments': [ |         "arguments": [ | ||||||
|             { |             { | ||||||
|                 'option_strings': ('--content',), |                 "option_strings": ("--content",), | ||||||
|                 'help': 'Text to print as a qr code', |                 "help": "Text to print as a qr code", | ||||||
|                 'required': True, |                 "required": True, | ||||||
|             }, |             }, | ||||||
|             { |             { | ||||||
|                 'option_strings': ('--size',), |                 "option_strings": ("--size",), | ||||||
|                 'help': 'QR code size (1-16) [default:3]', |                 "help": "QR code size (1-16) [default:3]", | ||||||
|                 'required': False, |                 "required": False, | ||||||
|                 'type': int, |                 "type": int, | ||||||
|  |             }, | ||||||
|  |         ], | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         "parser": { | ||||||
|  |             "name": "barcode", | ||||||
|  |             "help": "Print a barcode", | ||||||
|  |         }, | ||||||
|  |         "defaults": { | ||||||
|  |             "func": "barcode", | ||||||
|  |         }, | ||||||
|  |         "arguments": [ | ||||||
|  |             { | ||||||
|  |                 "option_strings": ("--code",), | ||||||
|  |                 "help": "Barcode data to print", | ||||||
|  |                 "required": True, | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "option_strings": ("--bc",), | ||||||
|  |                 "help": "Barcode format", | ||||||
|  |                 "required": True, | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "option_strings": ("--height",), | ||||||
|  |                 "help": "Barcode height in px", | ||||||
|  |                 "type": int, | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "option_strings": ("--width",), | ||||||
|  |                 "help": "Barcode width", | ||||||
|  |                 "type": int, | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "option_strings": ("--pos",), | ||||||
|  |                 "help": "Label position", | ||||||
|  |                 "choices": ["BELOW", "ABOVE", "BOTH", "OFF"], | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "option_strings": ("--font",), | ||||||
|  |                 "help": "Label font", | ||||||
|  |                 "choices": ["A", "B"], | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "option_strings": ("--align_ct",), | ||||||
|  |                 "help": "Align barcode center", | ||||||
|  |                 "type": str_to_bool, | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "option_strings": ("--function_type",), | ||||||
|  |                 "help": "ESCPOS function type", | ||||||
|  |                 "choices": ["A", "B"], | ||||||
|  |             }, | ||||||
|  |         ], | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         "parser": { | ||||||
|  |             "name": "text", | ||||||
|  |             "help": "Print plain text", | ||||||
|  |         }, | ||||||
|  |         "defaults": { | ||||||
|  |             "func": "text", | ||||||
|  |         }, | ||||||
|  |         "arguments": [ | ||||||
|  |             { | ||||||
|  |                 "option_strings": ("--txt",), | ||||||
|  |                 "help": "Plain text to print", | ||||||
|  |                 "required": True, | ||||||
|             } |             } | ||||||
|         ], |         ], | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|         'parser': { |         "parser": { | ||||||
|             'name': 'barcode', |             "name": "block_text", | ||||||
|             'help': 'Print a barcode', |             "help": "Print wrapped text", | ||||||
|         }, |         }, | ||||||
|         'defaults': { |         "defaults": { | ||||||
|             'func': 'barcode', |             "func": "block_text", | ||||||
|         }, |         }, | ||||||
|         'arguments': [ |         "arguments": [ | ||||||
|             { |             { | ||||||
|                 'option_strings': ('--code',), |                 "option_strings": ("--txt",), | ||||||
|                 'help': 'Barcode data to print', |                 "help": "block_text to print", | ||||||
|                 'required': True, |                 "required": True, | ||||||
|             }, |             }, | ||||||
|             { |             { | ||||||
|                 'option_strings': ('--bc',), |                 "option_strings": ("--columns",), | ||||||
|                 'help': 'Barcode format', |                 "help": "Number of columns", | ||||||
|                 'required': True, |                 "type": int, | ||||||
|             }, |  | ||||||
|             { |  | ||||||
|                 'option_strings': ('--height',), |  | ||||||
|                 'help': 'Barcode height in px', |  | ||||||
|                 'type': int, |  | ||||||
|             }, |  | ||||||
|             { |  | ||||||
|                 'option_strings': ('--width',), |  | ||||||
|                 'help': 'Barcode width', |  | ||||||
|                 'type': int, |  | ||||||
|             }, |  | ||||||
|             { |  | ||||||
|                 'option_strings': ('--pos',), |  | ||||||
|                 'help': 'Label position', |  | ||||||
|                 'choices': ['BELOW', 'ABOVE', 'BOTH', 'OFF'], |  | ||||||
|             }, |  | ||||||
|             { |  | ||||||
|                 'option_strings': ('--font',), |  | ||||||
|                 'help': 'Label font', |  | ||||||
|                 'choices': ['A', 'B'], |  | ||||||
|             }, |  | ||||||
|             { |  | ||||||
|                 'option_strings': ('--align_ct',), |  | ||||||
|                 'help': 'Align barcode center', |  | ||||||
|                 'type': str_to_bool, |  | ||||||
|             }, |  | ||||||
|             { |  | ||||||
|                 'option_strings': ('--function_type',), |  | ||||||
|                 'help': 'ESCPOS function type', |  | ||||||
|                 'choices': ['A', 'B'], |  | ||||||
|             }, |             }, | ||||||
|         ], |         ], | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|         'parser': { |         "parser": { | ||||||
|             'name': 'text', |             "name": "cut", | ||||||
|             'help': 'Print plain text', |             "help": "Cut the paper", | ||||||
|         }, |         }, | ||||||
|         'defaults': { |         "defaults": { | ||||||
|             'func': 'text', |             "func": "cut", | ||||||
|         }, |         }, | ||||||
|         'arguments': [ |         "arguments": [ | ||||||
|             { |             { | ||||||
|                 'option_strings': ('--txt',), |                 "option_strings": ("--mode",), | ||||||
|                 'help': 'Plain text to print', |                 "help": "Type of cut", | ||||||
|                 'required': True, |                 "choices": ["FULL", "PART"], | ||||||
|             } |  | ||||||
|         ], |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|         'parser': { |  | ||||||
|             'name': 'block_text', |  | ||||||
|             'help': 'Print wrapped text', |  | ||||||
|         }, |  | ||||||
|         'defaults': { |  | ||||||
|             'func': 'block_text', |  | ||||||
|         }, |  | ||||||
|         'arguments': [ |  | ||||||
|             { |  | ||||||
|                 'option_strings': ('--txt',), |  | ||||||
|                 'help': 'block_text to print', |  | ||||||
|                 'required': True, |  | ||||||
|             }, |  | ||||||
|             { |  | ||||||
|                 'option_strings': ('--columns',), |  | ||||||
|                 'help': 'Number of columns', |  | ||||||
|                 'type': int, |  | ||||||
|             }, |             }, | ||||||
|         ], |         ], | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|         'parser': { |         "parser": { | ||||||
|             'name': 'cut', |             "name": "cashdraw", | ||||||
|             'help': 'Cut the paper', |             "help": "Kick the cash drawer", | ||||||
|         }, |         }, | ||||||
|         'defaults': { |         "defaults": { | ||||||
|             'func': 'cut', |             "func": "cashdraw", | ||||||
|         }, |         }, | ||||||
|         'arguments': [ |         "arguments": [ | ||||||
|             { |             { | ||||||
|                 'option_strings': ('--mode',), |                 "option_strings": ("--pin",), | ||||||
|                 'help': 'Type of cut', |                 "help": "Which PIN to kick", | ||||||
|                 'choices': ['FULL', 'PART'], |                 "choices": [2, 5], | ||||||
|             }, |             }, | ||||||
|         ], |         ], | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|         'parser': { |         "parser": { | ||||||
|             'name': 'cashdraw', |             "name": "image", | ||||||
|             'help': 'Kick the cash drawer', |             "help": "Print an image", | ||||||
|         }, |         }, | ||||||
|         'defaults': { |         "defaults": { | ||||||
|             'func': 'cashdraw', |             "func": "image", | ||||||
|         }, |         }, | ||||||
|         'arguments': [ |         "arguments": [ | ||||||
|             { |             { | ||||||
|                 'option_strings': ('--pin',), |                 "option_strings": ("--img_source",), | ||||||
|                 'help': 'Which PIN to kick', |                 "help": "Path to image", | ||||||
|                 'choices': [2, 5], |                 "required": True, | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "option_strings": ("--impl",), | ||||||
|  |                 "help": "Implementation to use", | ||||||
|  |                 "choices": ["bitImageRaster", "bitImageColumn", "graphics"], | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "option_strings": ("--high_density_horizontal",), | ||||||
|  |                 "help": "Image density (horizontal)", | ||||||
|  |                 "type": str_to_bool, | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "option_strings": ("--high_density_vertical",), | ||||||
|  |                 "help": "Image density (vertical)", | ||||||
|  |                 "type": str_to_bool, | ||||||
|             }, |             }, | ||||||
|         ], |         ], | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|         'parser': { |         "parser": { | ||||||
|             'name': 'image', |             "name": "fullimage", | ||||||
|             'help': 'Print an image', |             "help": "Print a fullimage", | ||||||
|         }, |         }, | ||||||
|         'defaults': { |         "defaults": { | ||||||
|             'func': 'image', |             "func": "fullimage", | ||||||
|         }, |         }, | ||||||
|         'arguments': [ |         "arguments": [ | ||||||
|             { |             { | ||||||
|                 'option_strings': ('--img_source',), |                 "option_strings": ("--img",), | ||||||
|                 'help': 'Path to image', |                 "help": "Path to img", | ||||||
|                 'required': True, |                 "required": True, | ||||||
|             }, |             }, | ||||||
|             { |             { | ||||||
|                 'option_strings': ('--impl',), |                 "option_strings": ("--max_height",), | ||||||
|                 'help': 'Implementation to use', |                 "help": "Max height of image in px", | ||||||
|                 'choices': ['bitImageRaster', 'bitImageColumn', 'graphics'], |                 "type": int, | ||||||
|             }, |             }, | ||||||
|             { |             { | ||||||
|                 'option_strings': ('--high_density_horizontal',), |                 "option_strings": ("--width",), | ||||||
|                 'help': 'Image density (horizontal)', |                 "help": "Max width of image in px", | ||||||
|                 'type': str_to_bool, |                 "type": int, | ||||||
|             }, |             }, | ||||||
|             { |             { | ||||||
|                 'option_strings': ('--high_density_vertical',), |                 "option_strings": ("--histeq",), | ||||||
|                 'help': 'Image density (vertical)', |                 "help": "Equalize the histrogram", | ||||||
|                 'type': str_to_bool, |                 "type": str_to_bool, | ||||||
|             }, |  | ||||||
|  |  | ||||||
|         ], |  | ||||||
|             }, |             }, | ||||||
|             { |             { | ||||||
|         'parser': { |                 "option_strings": ("--bandsize",), | ||||||
|             'name': 'fullimage', |                 "help": "Size of bands to divide into when printing", | ||||||
|             'help': 'Print a fullimage', |                 "type": int, | ||||||
|         }, |  | ||||||
|         'defaults': { |  | ||||||
|             'func': 'fullimage', |  | ||||||
|         }, |  | ||||||
|         'arguments': [ |  | ||||||
|             { |  | ||||||
|                 'option_strings': ('--img',), |  | ||||||
|                 'help': 'Path to img', |  | ||||||
|                 'required': True, |  | ||||||
|             }, |  | ||||||
|             { |  | ||||||
|                 'option_strings': ('--max_height',), |  | ||||||
|                 'help': 'Max height of image in px', |  | ||||||
|                 'type': int, |  | ||||||
|             }, |  | ||||||
|             { |  | ||||||
|                 'option_strings': ('--width',), |  | ||||||
|                 'help': 'Max width of image in px', |  | ||||||
|                 'type': int, |  | ||||||
|             }, |  | ||||||
|             { |  | ||||||
|                 'option_strings': ('--histeq',), |  | ||||||
|                 'help': 'Equalize the histrogram', |  | ||||||
|                 'type': str_to_bool, |  | ||||||
|             }, |  | ||||||
|             { |  | ||||||
|                 'option_strings': ('--bandsize',), |  | ||||||
|                 'help': 'Size of bands to divide into when printing', |  | ||||||
|                 'type': int, |  | ||||||
|             }, |             }, | ||||||
|         ], |         ], | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|         'parser': { |         "parser": { | ||||||
|             'name': 'charcode', |             "name": "charcode", | ||||||
|             'help': 'Set character code table', |             "help": "Set character code table", | ||||||
|         }, |         }, | ||||||
|         'defaults': { |         "defaults": { | ||||||
|             'func': 'charcode', |             "func": "charcode", | ||||||
|         }, |         }, | ||||||
|         'arguments': [ |         "arguments": [ | ||||||
|             { |             { | ||||||
|                 'option_strings': ('--code',), |                 "option_strings": ("--code",), | ||||||
|                 'help': 'Character code', |                 "help": "Character code", | ||||||
|                 'required': True, |                 "required": True, | ||||||
|             }, |             }, | ||||||
|         ], |         ], | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|         'parser': { |         "parser": { | ||||||
|             'name': 'set', |             "name": "set", | ||||||
|             'help': 'Set text properties', |             "help": "Set text properties", | ||||||
|         }, |         }, | ||||||
|         'defaults': { |         "defaults": { | ||||||
|             'func': 'set', |             "func": "set", | ||||||
|         }, |         }, | ||||||
|         'arguments': [ |         "arguments": [ | ||||||
|             { |             { | ||||||
|                 'option_strings': ('--align',), |                 "option_strings": ("--align",), | ||||||
|                 'help': 'Horizontal alignment', |                 "help": "Horizontal alignment", | ||||||
|                 'choices': ['left', 'center', 'right'], |                 "choices": ["left", "center", "right"], | ||||||
|             }, |             }, | ||||||
|             { |             { | ||||||
|                 'option_strings': ('--font',), |                 "option_strings": ("--font",), | ||||||
|                 'help': 'Font choice', |                 "help": "Font choice", | ||||||
|                 'choices': ['left', 'center', 'right'], |                 "choices": ["left", "center", "right"], | ||||||
|             }, |             }, | ||||||
|             { |             { | ||||||
|                 'option_strings': ('--text_type',), |                 "option_strings": ("--text_type",), | ||||||
|                 'help': 'Text properties', |                 "help": "Text properties", | ||||||
|                 'choices': ['B', 'U', 'U2', 'BU', 'BU2', 'NORMAL'], |                 "choices": ["B", "U", "U2", "BU", "BU2", "NORMAL"], | ||||||
|             }, |             }, | ||||||
|             { |             { | ||||||
|                 'option_strings': ('--width',), |                 "option_strings": ("--width",), | ||||||
|                 'help': 'Width multiplier', |                 "help": "Width multiplier", | ||||||
|                 'type': int, |                 "type": int, | ||||||
|             }, |             }, | ||||||
|             { |             { | ||||||
|                 'option_strings': ('--height',), |                 "option_strings": ("--height",), | ||||||
|                 'help': 'Height multiplier', |                 "help": "Height multiplier", | ||||||
|                 'type': int, |                 "type": int, | ||||||
|             }, |             }, | ||||||
|             { |             { | ||||||
|                 'option_strings': ('--density',), |                 "option_strings": ("--density",), | ||||||
|                 'help': 'Print density', |                 "help": "Print density", | ||||||
|                 'type': int, |                 "type": int, | ||||||
|             }, |             }, | ||||||
|             { |             { | ||||||
|                 'option_strings': ('--invert',), |                 "option_strings": ("--invert",), | ||||||
|                 'help': 'White on black printing', |                 "help": "White on black printing", | ||||||
|                 'type': str_to_bool, |                 "type": str_to_bool, | ||||||
|             }, |             }, | ||||||
|             { |             { | ||||||
|                 'option_strings': ('--smooth',), |                 "option_strings": ("--smooth",), | ||||||
|                 'help': 'Text smoothing. Effective on >:  4x4 text', |                 "help": "Text smoothing. Effective on >:  4x4 text", | ||||||
|                 'type': str_to_bool, |                 "type": str_to_bool, | ||||||
|             }, |             }, | ||||||
|             { |             { | ||||||
|                 'option_strings': ('--flip',), |                 "option_strings": ("--flip",), | ||||||
|                 'help': 'Text smoothing. Effective on >:  4x4 text', |                 "help": "Text smoothing. Effective on >:  4x4 text", | ||||||
|                 'type': str_to_bool, |                 "type": str_to_bool, | ||||||
|             }, |             }, | ||||||
|         ], |         ], | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|         'parser': { |         "parser": { | ||||||
|             'name': 'hw', |             "name": "hw", | ||||||
|             'help': 'Hardware operations', |             "help": "Hardware operations", | ||||||
|         }, |         }, | ||||||
|         'defaults': { |         "defaults": { | ||||||
|             'func': 'hw', |             "func": "hw", | ||||||
|         }, |         }, | ||||||
|         'arguments': [ |         "arguments": [ | ||||||
|             { |             { | ||||||
|                 'option_strings': ('--hw',), |                 "option_strings": ("--hw",), | ||||||
|                 'help': 'Operation', |                 "help": "Operation", | ||||||
|                 'choices': ['INIT', 'SELECT', 'RESET'], |                 "choices": ["INIT", "SELECT", "RESET"], | ||||||
|                 'required': True, |                 "required": True, | ||||||
|             }, |             }, | ||||||
|         ], |         ], | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|         'parser': { |         "parser": { | ||||||
|             'name': 'control', |             "name": "control", | ||||||
|             'help': 'Control sequences', |             "help": "Control sequences", | ||||||
|         }, |         }, | ||||||
|         'defaults': { |         "defaults": { | ||||||
|             'func': 'control', |             "func": "control", | ||||||
|         }, |         }, | ||||||
|         'arguments': [ |         "arguments": [ | ||||||
|             { |             { | ||||||
|                 'option_strings': ('--ctl',), |                 "option_strings": ("--ctl",), | ||||||
|                 'help': 'Control sequence', |                 "help": "Control sequence", | ||||||
|                 'choices': ['LF', 'FF', 'CR', 'HT', 'VT'], |                 "choices": ["LF", "FF", "CR", "HT", "VT"], | ||||||
|                 'required': True, |                 "required": True, | ||||||
|             }, |             }, | ||||||
|             { |             { | ||||||
|                 'option_strings': ('--pos',), |                 "option_strings": ("--pos",), | ||||||
|                 'help': 'Horizontal tab position (1-4)', |                 "help": "Horizontal tab position (1-4)", | ||||||
|                 'type': int, |                 "type": int, | ||||||
|             }, |             }, | ||||||
|         ], |         ], | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|         'parser': { |         "parser": { | ||||||
|             'name': 'panel_buttons', |             "name": "panel_buttons", | ||||||
|             'help': 'Controls panel buttons', |             "help": "Controls panel buttons", | ||||||
|         }, |         }, | ||||||
|         'defaults': { |         "defaults": { | ||||||
|             'func': 'panel_buttons', |             "func": "panel_buttons", | ||||||
|         }, |         }, | ||||||
|         'arguments': [ |         "arguments": [ | ||||||
|             { |             { | ||||||
|                 'option_strings': ('--enable',), |                 "option_strings": ("--enable",), | ||||||
|                 'help': 'Feed button enabled', |                 "help": "Feed button enabled", | ||||||
|                 'type': str_to_bool, |                 "type": str_to_bool, | ||||||
|                 'required': True, |                 "required": True, | ||||||
|             }, |             }, | ||||||
|         ], |         ], | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|         'parser': { |         "parser": { | ||||||
|             'name': 'raw', |             "name": "raw", | ||||||
|             'help': 'Raw data', |             "help": "Raw data", | ||||||
|         }, |         }, | ||||||
|         'defaults': { |         "defaults": { | ||||||
|             'func': '_raw', |             "func": "_raw", | ||||||
|         }, |         }, | ||||||
|         'arguments': [ |         "arguments": [ | ||||||
|             { |             { | ||||||
|                 'option_strings': ('--msg',), |                 "option_strings": ("--msg",), | ||||||
|                 'help': 'Raw data to send', |                 "help": "Raw data to send", | ||||||
|                 'required': True, |                 "required": True, | ||||||
|             }, |             }, | ||||||
|         ], |         ], | ||||||
|     }, |     }, | ||||||
| @@ -449,68 +455,71 @@ def main(): | |||||||
|     """ |     """ | ||||||
|  |  | ||||||
|     parser = argparse.ArgumentParser( |     parser = argparse.ArgumentParser( | ||||||
|         description='CLI for python-escpos', |         description="CLI for python-escpos", | ||||||
|         epilog='Printer configuration is defined in the python-escpos config' |         epilog="Printer configuration is defined in the python-escpos config" | ||||||
|         'file. See documentation for details.', |         "file. See documentation for details.", | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|     parser.register('type', 'bool', str_to_bool) |     parser.register("type", "bool", str_to_bool) | ||||||
|  |  | ||||||
|     # Allow config file location to be passed |     # Allow config file location to be passed | ||||||
|     parser.add_argument( |     parser.add_argument( | ||||||
|         '-c', '--config', |         "-c", | ||||||
|         help='Alternate path to the configuration file', |         "--config", | ||||||
|  |         help="Alternate path to the configuration file", | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|     # Everything interesting runs off of a subparser so we can use the format |     # Everything interesting runs off of a subparser so we can use the format | ||||||
|     # cli [subparser] -args |     # cli [subparser] -args | ||||||
|     command_subparsers = parser.add_subparsers( |     command_subparsers = parser.add_subparsers( | ||||||
|         title='ESCPOS Command', |         title="ESCPOS Command", | ||||||
|         dest='parser', |         dest="parser", | ||||||
|     ) |     ) | ||||||
|     # fix inconsistencies in the behaviour of some versions of argparse |     # fix inconsistencies in the behaviour of some versions of argparse | ||||||
|     command_subparsers.required = False  # force 'required' testing |     command_subparsers.required = False  # force 'required' testing | ||||||
|  |  | ||||||
|     # Build the ESCPOS command arguments |     # Build the ESCPOS command arguments | ||||||
|     for command in ESCPOS_COMMANDS: |     for command in ESCPOS_COMMANDS: | ||||||
|         parser_command = command_subparsers.add_parser(**command['parser']) |         parser_command = command_subparsers.add_parser(**command["parser"]) | ||||||
|         parser_command.set_defaults(**command['defaults']) |         parser_command.set_defaults(**command["defaults"]) | ||||||
|         for argument in command['arguments']: |         for argument in command["arguments"]: | ||||||
|             option_strings = argument.pop('option_strings') |             option_strings = argument.pop("option_strings") | ||||||
|             parser_command.add_argument(*option_strings, **argument) |             parser_command.add_argument(*option_strings, **argument) | ||||||
|  |  | ||||||
|     # Build any custom arguments |     # Build any custom arguments | ||||||
|     parser_command_demo = command_subparsers.add_parser('demo', |     parser_command_demo = command_subparsers.add_parser( | ||||||
|                                                         help='Demonstrates various functions') |         "demo", help="Demonstrates various functions" | ||||||
|     parser_command_demo.set_defaults(func='demo') |     ) | ||||||
|  |     parser_command_demo.set_defaults(func="demo") | ||||||
|     demo_group = parser_command_demo.add_mutually_exclusive_group() |     demo_group = parser_command_demo.add_mutually_exclusive_group() | ||||||
|     demo_group.add_argument( |     demo_group.add_argument( | ||||||
|         '--barcodes-a', |         "--barcodes-a", | ||||||
|         help='Print demo barcodes for function type A', |         help="Print demo barcodes for function type A", | ||||||
|         action='store_true', |         action="store_true", | ||||||
|     ) |     ) | ||||||
|     demo_group.add_argument( |     demo_group.add_argument( | ||||||
|         '--barcodes-b', |         "--barcodes-b", | ||||||
|         help='Print demo barcodes for function type B', |         help="Print demo barcodes for function type B", | ||||||
|         action='store_true', |         action="store_true", | ||||||
|     ) |     ) | ||||||
|     demo_group.add_argument( |     demo_group.add_argument( | ||||||
|         '--qr', |         "--qr", | ||||||
|         help='Print some demo QR codes', |         help="Print some demo QR codes", | ||||||
|         action='store_true', |         action="store_true", | ||||||
|     ) |     ) | ||||||
|     demo_group.add_argument( |     demo_group.add_argument( | ||||||
|         '--text', |         "--text", | ||||||
|         help='Print some demo text', |         help="Print some demo text", | ||||||
|         action='store_true', |         action="store_true", | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|     parser_command_version = command_subparsers.add_parser('version', |     parser_command_version = command_subparsers.add_parser( | ||||||
|                                                            help='Print the version of python-escpos') |         "version", help="Print the version of python-escpos" | ||||||
|  |     ) | ||||||
|     parser_command_version.set_defaults(version=True) |     parser_command_version.set_defaults(version=True) | ||||||
|  |  | ||||||
|     # hook in argcomplete |     # hook in argcomplete | ||||||
|     if 'argcomplete' in globals(): |     if "argcomplete" in globals(): | ||||||
|         argcomplete.autocomplete(parser) |         argcomplete.autocomplete(parser) | ||||||
|  |  | ||||||
|     # Get only arguments actually passed |     # Get only arguments actually passed | ||||||
| @@ -518,16 +527,18 @@ def main(): | |||||||
|     if not args_dict: |     if not args_dict: | ||||||
|         parser.print_help() |         parser.print_help() | ||||||
|         sys.exit() |         sys.exit() | ||||||
|     command_arguments = dict([k, v] for k, v in six.iteritems(args_dict) if v is not None) |     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 |     # If version should be printed, do this, then exit | ||||||
|     print_version = command_arguments.pop('version', None) |     print_version = command_arguments.pop("version", None) | ||||||
|     if print_version: |     if print_version: | ||||||
|         print(version.version) |         print(version.version) | ||||||
|         sys.exit() |         sys.exit() | ||||||
|  |  | ||||||
|     # If there was a config path passed, grab it |     # If there was a config path passed, grab it | ||||||
|     config_path = command_arguments.pop('config', None) |     config_path = command_arguments.pop("config", None) | ||||||
|  |  | ||||||
|     # Load the configuration and defined printer |     # Load the configuration and defined printer | ||||||
|     saved_config = config.Config() |     saved_config = config.Config() | ||||||
| @@ -535,12 +546,12 @@ def main(): | |||||||
|     printer = saved_config.printer() |     printer = saved_config.printer() | ||||||
|  |  | ||||||
|     if not printer: |     if not printer: | ||||||
|         raise Exception('No printers loaded from config') |         raise Exception("No printers loaded from config") | ||||||
|  |  | ||||||
|     target_command = command_arguments.pop('func') |     target_command = command_arguments.pop("func") | ||||||
|  |  | ||||||
|     # remove helper-argument 'parser' from dict |     # remove helper-argument 'parser' from dict | ||||||
|     command_arguments.pop('parser', None) |     command_arguments.pop("parser", None) | ||||||
|  |  | ||||||
|     if hasattr(printer, target_command): |     if hasattr(printer, target_command): | ||||||
|         # print command with args |         # print command with args | ||||||
| @@ -548,7 +559,7 @@ def main(): | |||||||
|         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) | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -564,14 +575,14 @@ def demo(printer, **kwargs): | |||||||
|     for demo_choice in kwargs.keys(): |     for demo_choice in kwargs.keys(): | ||||||
|         command = getattr( |         command = getattr( | ||||||
|             printer, |             printer, | ||||||
|             demo_choice |             demo_choice.replace("barcodes_a", "barcode").replace( | ||||||
|             .replace('barcodes_a', 'barcode') |                 "barcodes_b", "barcode" | ||||||
|             .replace('barcodes_b', 'barcode') |             ), | ||||||
|         ) |         ) | ||||||
|         for params in DEMO_FUNCTIONS[demo_choice]: |         for params in DEMO_FUNCTIONS[demo_choice]: | ||||||
|             command(**params) |             command(**params) | ||||||
|         printer.cut() |         printer.cut() | ||||||
|  |  | ||||||
|  |  | ||||||
| if __name__ == '__main__': | if __name__ == "__main__": | ||||||
|     main() |     main() | ||||||
|   | |||||||
| @@ -21,4 +21,4 @@ class CodePageManager: | |||||||
|         return self.data[encoding] |         return self.data[encoding] | ||||||
|  |  | ||||||
|  |  | ||||||
| CodePages = CodePageManager(CAPABILITIES['encodings']) | CodePages = CodePageManager(CAPABILITIES["encodings"]) | ||||||
|   | |||||||
| @@ -19,8 +19,9 @@ class Config(object): | |||||||
|     This class loads configuration from a default or specificed directory. It |     This class loads configuration from a default or specificed directory. It | ||||||
|     can create your defined printer and return it to you. |     can create your defined printer and return it to you. | ||||||
|     """ |     """ | ||||||
|     _app_name = 'python-escpos' |  | ||||||
|     _config_file = 'config.yaml' |     _app_name = "python-escpos" | ||||||
|  |     _config_file = "config.yaml" | ||||||
|  |  | ||||||
|     def __init__(self): |     def __init__(self): | ||||||
|         """Initialize configuration. |         """Initialize configuration. | ||||||
| @@ -58,31 +59,32 @@ class Config(object): | |||||||
|  |  | ||||||
|         if not config_path: |         if not config_path: | ||||||
|             config_path = os.path.join( |             config_path = os.path.join( | ||||||
|                 appdirs.user_config_dir(self._app_name), |                 appdirs.user_config_dir(self._app_name), self._config_file | ||||||
|                 self._config_file |  | ||||||
|             ) |             ) | ||||||
|  |  | ||||||
|         try: |         try: | ||||||
|             # First check if it's file like. If it is, pyyaml can load it. |             # First check if it's file like. If it is, pyyaml can load it. | ||||||
|             # I'm checking type instead of catching exceptions to keep the |             # I'm checking type instead of catching exceptions to keep the | ||||||
|             # exception handling simple |             # exception handling simple | ||||||
|             if hasattr(config_path, 'read'): |             if hasattr(config_path, "read"): | ||||||
|                 config = yaml.safe_load(config_path) |                 config = yaml.safe_load(config_path) | ||||||
|             else: |             else: | ||||||
|                 # If it isn't, it's a path. We have to open it first, otherwise |                 # If it isn't, it's a path. We have to open it first, otherwise | ||||||
|                 # pyyaml will try to read it as yaml |                 # pyyaml will try to read it as yaml | ||||||
|                 with open(config_path, 'rb') as config_file: |                 with open(config_path, "rb") as config_file: | ||||||
|                     config = yaml.safe_load(config_file) |                     config = yaml.safe_load(config_file) | ||||||
|         except EnvironmentError: |         except EnvironmentError: | ||||||
|             raise exceptions.ConfigNotFoundError('Couldn\'t read config at {config_path}'.format( |             raise exceptions.ConfigNotFoundError( | ||||||
|  |                 "Couldn't read config at {config_path}".format( | ||||||
|                     config_path=str(config_path), |                     config_path=str(config_path), | ||||||
|             )) |                 ) | ||||||
|  |             ) | ||||||
|         except yaml.YAMLError: |         except yaml.YAMLError: | ||||||
|             raise exceptions.ConfigSyntaxError('Error parsing YAML') |             raise exceptions.ConfigSyntaxError("Error parsing YAML") | ||||||
|  |  | ||||||
|         if 'printer' in config: |         if "printer" in config: | ||||||
|             self._printer_config = config['printer'] |             self._printer_config = config["printer"] | ||||||
|             self._printer_name = self._printer_config.pop('type').title() |             self._printer_name = self._printer_config.pop("type").title() | ||||||
|  |  | ||||||
|             if not self._printer_name or not hasattr(printer, self._printer_name): |             if not self._printer_name or not hasattr(printer, self._printer_name): | ||||||
|                 raise exceptions.ConfigSyntaxError( |                 raise exceptions.ConfigSyntaxError( | ||||||
| @@ -104,7 +106,7 @@ class Config(object): | |||||||
|             self.load() |             self.load() | ||||||
|  |  | ||||||
|         if not self._printer_name: |         if not self._printer_name: | ||||||
|             raise exceptions.ConfigSectionMissingError('printer') |             raise exceptions.ConfigSectionMissingError("printer") | ||||||
|  |  | ||||||
|         if not self._printer: |         if not self._printer: | ||||||
|             # We could catch init errors and make them a ConfigSyntaxError, |             # We could catch init errors and make them a ConfigSyntaxError, | ||||||
|   | |||||||
| @@ -16,120 +16,125 @@ import six | |||||||
|  |  | ||||||
| # Control characters | # Control characters | ||||||
| # as labelled in https://www.novopos.ch/client/EPSON/TM-T20/TM-T20_eng_qr.pdf | # as labelled in https://www.novopos.ch/client/EPSON/TM-T20/TM-T20_eng_qr.pdf | ||||||
| NUL = b'\x00' | NUL = b"\x00" | ||||||
| EOT = b'\x04' | EOT = b"\x04" | ||||||
| ENQ = b'\x05' | ENQ = b"\x05" | ||||||
| DLE = b'\x10' | DLE = b"\x10" | ||||||
| DC4 = b'\x14' | DC4 = b"\x14" | ||||||
| CAN = b'\x18' | CAN = b"\x18" | ||||||
| ESC = b'\x1b' | ESC = b"\x1b" | ||||||
| FS  = b'\x1c' | FS = b"\x1c" | ||||||
| GS  = b'\x1d' | GS = b"\x1d" | ||||||
|  |  | ||||||
| # Feed control sequences | # Feed control sequences | ||||||
| CTL_LF = b'\n'              # Print and line feed | CTL_LF = b"\n"  # Print and line feed | ||||||
| CTL_FF = b'\f'              # Form feed | CTL_FF = b"\f"  # Form feed | ||||||
| CTL_CR = b'\r'              # Carriage return | CTL_CR = b"\r"  # Carriage return | ||||||
| CTL_HT = b'\t'              # Horizontal tab | CTL_HT = b"\t"  # Horizontal tab | ||||||
| CTL_SET_HT = ESC + b'\x44'  # Set horizontal tab positions | CTL_SET_HT = ESC + b"\x44"  # Set horizontal tab positions | ||||||
| CTL_VT = b'\v'              # Vertical tab | CTL_VT = b"\v"  # Vertical tab | ||||||
|  |  | ||||||
| # Printer hardware | # Printer hardware | ||||||
| HW_INIT   = ESC + b'@'             # Clear data in buffer and reset modes | HW_INIT = ESC + b"@"  # Clear data in buffer and reset modes | ||||||
| HW_SELECT = ESC + b'=\x01'         # Printer select | HW_SELECT = ESC + b"=\x01"  # Printer select | ||||||
|  |  | ||||||
| HW_RESET  = ESC + b'\x3f\x0a\x00'   # Reset printer hardware | HW_RESET = ESC + b"\x3f\x0a\x00"  # Reset printer hardware | ||||||
| # (TODO: Where is this specified?) | # (TODO: Where is this specified?) | ||||||
|  |  | ||||||
| # Cash Drawer (ESC p <pin> <on time: 2*ms> <off time: 2*ms>) | # Cash Drawer (ESC p <pin> <on time: 2*ms> <off time: 2*ms>) | ||||||
| _CASH_DRAWER = lambda m, t1='', t2='': ESC + b'p' + m + six.int2byte(t1) + six.int2byte(t2) | _CASH_DRAWER = ( | ||||||
| CD_KICK_DEC_SEQUENCE = lambda esc, p, m, t1=50, t2=50: six.int2byte(esc) + six.int2byte(p) + six.int2byte(m) + six.int2byte(t1) + six.int2byte(t2) |     lambda m, t1="", t2="": ESC + b"p" + m + six.int2byte(t1) + six.int2byte(t2) | ||||||
| CD_KICK_2 = _CASH_DRAWER(b'\x00', 50, 50)  # Sends a pulse to pin 2 [] | ) | ||||||
| CD_KICK_5 = _CASH_DRAWER(b'\x01', 50, 50)  # Sends a pulse to pin 5 [] | CD_KICK_DEC_SEQUENCE = ( | ||||||
|  |     lambda esc, p, m, t1=50, t2=50: six.int2byte(esc) | ||||||
|  |     + six.int2byte(p) | ||||||
|  |     + six.int2byte(m) | ||||||
|  |     + six.int2byte(t1) | ||||||
|  |     + six.int2byte(t2) | ||||||
|  | ) | ||||||
|  | CD_KICK_2 = _CASH_DRAWER(b"\x00", 50, 50)  # Sends a pulse to pin 2 [] | ||||||
|  | CD_KICK_5 = _CASH_DRAWER(b"\x01", 50, 50)  # Sends a pulse to pin 5 [] | ||||||
|  |  | ||||||
| # Paper Cutter | # Paper Cutter | ||||||
| _CUT_PAPER = lambda m: GS + b'V' + m | _CUT_PAPER = lambda m: GS + b"V" + m | ||||||
| PAPER_FULL_CUT = _CUT_PAPER(b'\x00')  # Full cut paper | PAPER_FULL_CUT = _CUT_PAPER(b"\x00")  # Full cut paper | ||||||
| PAPER_PART_CUT = _CUT_PAPER(b'\x01')  # Partial cut paper | PAPER_PART_CUT = _CUT_PAPER(b"\x01")  # Partial cut paper | ||||||
|  |  | ||||||
| # Beep (please note that the actual beep sequence may differ between devices) | # Beep (please note that the actual beep sequence may differ between devices) | ||||||
| BEEP = b'\x07' | BEEP = b"\x07" | ||||||
|  |  | ||||||
| # Panel buttons (e.g. the FEED button) | # Panel buttons (e.g. the FEED button) | ||||||
| _PANEL_BUTTON = lambda n: ESC + b'c5' + six.int2byte(n) | _PANEL_BUTTON = lambda n: ESC + b"c5" + six.int2byte(n) | ||||||
| PANEL_BUTTON_ON = _PANEL_BUTTON(0)  # enable all panel buttons | PANEL_BUTTON_ON = _PANEL_BUTTON(0)  # enable all panel buttons | ||||||
| PANEL_BUTTON_OFF = _PANEL_BUTTON(1)  # disable all panel buttons | PANEL_BUTTON_OFF = _PANEL_BUTTON(1)  # disable all panel buttons | ||||||
|  |  | ||||||
| # Line display printing | # Line display printing | ||||||
| LINE_DISPLAY_OPEN = ESC + b'\x3d\x02' | LINE_DISPLAY_OPEN = ESC + b"\x3d\x02" | ||||||
| LINE_DISPLAY_CLEAR = ESC + b'\x40' | LINE_DISPLAY_CLEAR = ESC + b"\x40" | ||||||
| LINE_DISPLAY_CLOSE = ESC + b'\x3d\x01' | LINE_DISPLAY_CLOSE = ESC + b"\x3d\x01" | ||||||
|  |  | ||||||
| # Sheet modes | # Sheet modes | ||||||
| SHEET_SLIP_MODE = ESC + b'\x63\x30\x04'  # slip paper | SHEET_SLIP_MODE = ESC + b"\x63\x30\x04"  # slip paper | ||||||
| SHEET_ROLL_MODE = ESC + b'\x63\x30\x01'  # paper roll | SHEET_ROLL_MODE = ESC + b"\x63\x30\x01"  # paper roll | ||||||
|  |  | ||||||
| # Text format | # Text format | ||||||
| # TODO: Acquire the "ESC/POS Application Programming Guide for Paper Roll | # TODO: Acquire the "ESC/POS Application Programming Guide for Paper Roll | ||||||
| #       Printers" and tidy up this stuff too. | #       Printers" and tidy up this stuff too. | ||||||
| TXT_SIZE       = GS + b'!' | TXT_SIZE = GS + b"!" | ||||||
|  |  | ||||||
| TXT_NORMAL     = ESC + b'!\x00'     # Normal text | TXT_NORMAL = ESC + b"!\x00"  # Normal text | ||||||
|  |  | ||||||
|  |  | ||||||
| TXT_STYLE = { | TXT_STYLE = { | ||||||
|     'bold': { |     "bold": { | ||||||
|         False: ESC + b'\x45\x00',               # Bold font OFF |         False: ESC + b"\x45\x00",  # Bold font OFF | ||||||
|         True: ESC + b'\x45\x01'                 # Bold font ON |         True: ESC + b"\x45\x01",  # Bold font ON | ||||||
|     }, |     }, | ||||||
|     'underline': { |     "underline": { | ||||||
|         0: ESC + b'\x2d\x00',                   # Underline font OFF |         0: ESC + b"\x2d\x00",  # Underline font OFF | ||||||
|         1: ESC + b'\x2d\x01',                   # Underline font 1-dot ON |         1: ESC + b"\x2d\x01",  # Underline font 1-dot ON | ||||||
|         2: ESC + b'\x2d\x02'                    # Underline font 2-dot ON |         2: ESC + b"\x2d\x02",  # Underline font 2-dot ON | ||||||
|     }, |     }, | ||||||
|     'size': { |     "size": { | ||||||
|         'normal': TXT_NORMAL + ESC + b'!\x00',  # Normal text |         "normal": TXT_NORMAL + ESC + b"!\x00",  # Normal text | ||||||
|         '2h': TXT_NORMAL + ESC + b'!\x10',      # Double height text |         "2h": TXT_NORMAL + ESC + b"!\x10",  # Double height text | ||||||
|         '2w': TXT_NORMAL + ESC + b'!\x20',      # Double width text |         "2w": TXT_NORMAL + ESC + b"!\x20",  # Double width text | ||||||
|         '2x': TXT_NORMAL + ESC + b'!\x30'       # Quad area text |         "2x": TXT_NORMAL + ESC + b"!\x30",  # Quad area text | ||||||
|     }, |     }, | ||||||
|     'font': { |     "font": { | ||||||
|         'a': ESC + b'\x4d\x00',                 # Font type A |         "a": ESC + b"\x4d\x00",  # Font type A | ||||||
|         'b': ESC + b'\x4d\x00'                  # Font type B |         "b": ESC + b"\x4d\x00",  # Font type B | ||||||
|     }, |     }, | ||||||
|     'align': { |     "align": { | ||||||
|         'left': ESC + b'\x61\x00',              # Left justification |         "left": ESC + b"\x61\x00",  # Left justification | ||||||
|         'center': ESC + b'\x61\x01',            # Centering |         "center": ESC + b"\x61\x01",  # Centering | ||||||
|         'right': ESC + b'\x61\x02'              # Right justification |         "right": ESC + b"\x61\x02",  # Right justification | ||||||
|     }, |     }, | ||||||
|     'invert': { |     "invert": { | ||||||
|         True: GS  + b'\x42\x01',                # Inverse Printing ON |         True: GS + b"\x42\x01",  # Inverse Printing ON | ||||||
|         False: GS  + b'\x42\x00'                # Inverse Printing OFF |         False: GS + b"\x42\x00",  # Inverse Printing OFF | ||||||
|     }, |     }, | ||||||
|     'color': { |     "color": { | ||||||
|         'black': ESC + b'\x72\x00',             # Default Color |         "black": ESC + b"\x72\x00",  # Default Color | ||||||
|         'red': ESC + b'\x72\x01'                # Alternative Color, Usually Red |         "red": ESC + b"\x72\x01",  # Alternative Color, Usually Red | ||||||
|     }, |     }, | ||||||
|     'flip': { |     "flip": {True: ESC + b"\x7b\x01", False: ESC + b"\x7b\x00"},  # Flip ON  # Flip OFF | ||||||
|         True: ESC + b'\x7b\x01',                # Flip ON |     "density": { | ||||||
|         False: ESC + b'\x7b\x00'                # Flip OFF |         0: GS + b"\x7c\x00",  # Printing Density -50% | ||||||
|  |         1: GS + b"\x7c\x01",  # Printing Density -37.5% | ||||||
|  |         2: GS + b"\x7c\x02",  # Printing Density -25% | ||||||
|  |         3: GS + b"\x7c\x03",  # Printing Density -12.5% | ||||||
|  |         4: GS + b"\x7c\x04",  # Printing Density  0% | ||||||
|  |         5: GS + b"\x7c\x08",  # Printing Density +50% | ||||||
|  |         6: GS + b"\x7c\x07",  # Printing Density +37.5% | ||||||
|  |         7: GS + b"\x7c\x06",  # Printing Density +25% | ||||||
|  |         8: GS + b"\x7c\x05",  # Printing Density +12.5% | ||||||
|     }, |     }, | ||||||
|     'density': { |     "smooth": { | ||||||
|         0: GS + b'\x7c\x00',                    # Printing Density -50% |         True: GS + b"\x62\x01",  # Smooth ON | ||||||
|         1: GS + b'\x7c\x01',                    # Printing Density -37.5% |         False: GS + b"\x62\x00",  # Smooth OFF | ||||||
|         2: GS + b'\x7c\x02',                    # Printing Density -25% |  | ||||||
|         3: GS + b'\x7c\x03',                    # Printing Density -12.5% |  | ||||||
|         4: GS + b'\x7c\x04',                    # Printing Density  0% |  | ||||||
|         5: GS + b'\x7c\x08',                    # Printing Density +50% |  | ||||||
|         6: GS + b'\x7c\x07',                    # Printing Density +37.5% |  | ||||||
|         7: GS + b'\x7c\x06',                    # Printing Density +25% |  | ||||||
|         8: GS + b'\x7c\x05'                     # Printing Density +12.5% |  | ||||||
|     }, |     }, | ||||||
|     'smooth': { |     "height": {  # Custom text height | ||||||
|         True: GS + b'\x62\x01',                 # Smooth ON |  | ||||||
|         False: GS + b'\x62\x00'                 # Smooth OFF |  | ||||||
|     }, |  | ||||||
|     'height': {                                 # Custom text height |  | ||||||
|         1: 0x00, |         1: 0x00, | ||||||
|         2: 0x01, |         2: 0x01, | ||||||
|         3: 0x02, |         3: 0x02, | ||||||
| @@ -137,9 +142,9 @@ TXT_STYLE = { | |||||||
|         5: 0x04, |         5: 0x04, | ||||||
|         6: 0x05, |         6: 0x05, | ||||||
|         7: 0x06, |         7: 0x06, | ||||||
|         8: 0x07 |         8: 0x07, | ||||||
|     }, |     }, | ||||||
|     'width': {                                  # Custom text width |     "width": {  # Custom text width | ||||||
|         1: 0x00, |         1: 0x00, | ||||||
|         2: 0x10, |         2: 0x10, | ||||||
|         3: 0x20, |         3: 0x20, | ||||||
| @@ -147,101 +152,104 @@ TXT_STYLE = { | |||||||
|         5: 0x40, |         5: 0x40, | ||||||
|         6: 0x50, |         6: 0x50, | ||||||
|         7: 0x60, |         7: 0x60, | ||||||
|         8: 0x70 |         8: 0x70, | ||||||
|     } |     }, | ||||||
| } | } | ||||||
|  |  | ||||||
| # Fonts | # Fonts | ||||||
| SET_FONT = lambda n: ESC + b'\x4d' + n | SET_FONT = lambda n: ESC + b"\x4d" + n | ||||||
| TXT_FONT_A     = SET_FONT(b'\x00')  # Font type A | TXT_FONT_A = SET_FONT(b"\x00")  # Font type A | ||||||
| TXT_FONT_B     = SET_FONT(b'\x01')  # Font type B | TXT_FONT_B = SET_FONT(b"\x01")  # Font type B | ||||||
|  |  | ||||||
| # Spacing | # Spacing | ||||||
| LINESPACING_RESET = ESC + b'2' | LINESPACING_RESET = ESC + b"2" | ||||||
| LINESPACING_FUNCS = { | LINESPACING_FUNCS = { | ||||||
|   60: ESC + b'A',  # line_spacing/60 of an inch, 0 <= line_spacing <= 85 |     60: ESC + b"A",  # line_spacing/60 of an inch, 0 <= line_spacing <= 85 | ||||||
|   360: ESC + b'+', # line_spacing/360 of an inch, 0 <= line_spacing <= 255 |     360: ESC + b"+",  # line_spacing/360 of an inch, 0 <= line_spacing <= 255 | ||||||
|   180: ESC + b'3', # line_spacing/180 of an inch, 0 <= line_spacing <= 255 |     180: ESC + b"3",  # line_spacing/180 of an inch, 0 <= line_spacing <= 255 | ||||||
| } | } | ||||||
|  |  | ||||||
| # Prefix to change the codepage. You need to attach a byte to indicate | # Prefix to change the codepage. You need to attach a byte to indicate | ||||||
| # the codepage to use. We use escpos-printer-db as the data source. | # the codepage to use. We use escpos-printer-db as the data source. | ||||||
| CODEPAGE_CHANGE = ESC + b'\x74' | CODEPAGE_CHANGE = ESC + b"\x74" | ||||||
|  |  | ||||||
| # Barcode format | # Barcode format | ||||||
| _SET_BARCODE_TXT_POS = lambda n: GS + b'H' + n | _SET_BARCODE_TXT_POS = lambda n: GS + b"H" + n | ||||||
| BARCODE_TXT_OFF = _SET_BARCODE_TXT_POS(b'\x00')  # HRI barcode chars OFF | BARCODE_TXT_OFF = _SET_BARCODE_TXT_POS(b"\x00")  # HRI barcode chars OFF | ||||||
| BARCODE_TXT_ABV = _SET_BARCODE_TXT_POS(b'\x01')  # HRI barcode chars above | BARCODE_TXT_ABV = _SET_BARCODE_TXT_POS(b"\x01")  # HRI barcode chars above | ||||||
| BARCODE_TXT_BLW = _SET_BARCODE_TXT_POS(b'\x02')  # HRI barcode chars below | BARCODE_TXT_BLW = _SET_BARCODE_TXT_POS(b"\x02")  # HRI barcode chars below | ||||||
| BARCODE_TXT_BTH = _SET_BARCODE_TXT_POS(b'\x03')  # HRI both above and below | BARCODE_TXT_BTH = _SET_BARCODE_TXT_POS(b"\x03")  # HRI both above and below | ||||||
|  |  | ||||||
| _SET_HRI_FONT = lambda n: GS + b'f' + n | _SET_HRI_FONT = lambda n: GS + b"f" + n | ||||||
| BARCODE_FONT_A = _SET_HRI_FONT(b'\x00')  # Font type A for HRI barcode chars | BARCODE_FONT_A = _SET_HRI_FONT(b"\x00")  # Font type A for HRI barcode chars | ||||||
| BARCODE_FONT_B = _SET_HRI_FONT(b'\x01')  # Font type B for HRI barcode chars | BARCODE_FONT_B = _SET_HRI_FONT(b"\x01")  # Font type B for HRI barcode chars | ||||||
|  |  | ||||||
| BARCODE_HEIGHT = GS + b'h'  # Barcode Height [1-255] | BARCODE_HEIGHT = GS + b"h"  # Barcode Height [1-255] | ||||||
| BARCODE_WIDTH  = GS + b'w'  # Barcode Width  [2-6] | BARCODE_WIDTH = GS + b"w"  # Barcode Width  [2-6] | ||||||
|  |  | ||||||
| # NOTE: This isn't actually an ESC/POS command. It's the common prefix to the | # NOTE: This isn't actually an ESC/POS command. It's the common prefix to the | ||||||
| #      two "print bar code" commands: | #      two "print bar code" commands: | ||||||
| #      -  Type A: "GS k <type as integer> <data> NUL" | #      -  Type A: "GS k <type as integer> <data> NUL" | ||||||
| #      -  TYPE B: "GS k <type as letter> <data length> <data>" | #      -  TYPE B: "GS k <type as letter> <data length> <data>" | ||||||
| #      The latter command supports more barcode types | #      The latter command supports more barcode types | ||||||
| _SET_BARCODE_TYPE = lambda m: GS + b'k' + six.int2byte(m) | _SET_BARCODE_TYPE = lambda m: GS + b"k" + six.int2byte(m) | ||||||
|  |  | ||||||
| # Barcodes for printing function type A | # Barcodes for printing function type A | ||||||
| BARCODE_TYPE_A = { | BARCODE_TYPE_A = { | ||||||
|     'UPC-A':   _SET_BARCODE_TYPE(0), |     "UPC-A": _SET_BARCODE_TYPE(0), | ||||||
|     'UPC-E':   _SET_BARCODE_TYPE(1), |     "UPC-E": _SET_BARCODE_TYPE(1), | ||||||
|     'EAN13':   _SET_BARCODE_TYPE(2), |     "EAN13": _SET_BARCODE_TYPE(2), | ||||||
|     'EAN8':    _SET_BARCODE_TYPE(3), |     "EAN8": _SET_BARCODE_TYPE(3), | ||||||
|     'CODE39':  _SET_BARCODE_TYPE(4), |     "CODE39": _SET_BARCODE_TYPE(4), | ||||||
|     'ITF':     _SET_BARCODE_TYPE(5), |     "ITF": _SET_BARCODE_TYPE(5), | ||||||
|     'NW7':     _SET_BARCODE_TYPE(6), |     "NW7": _SET_BARCODE_TYPE(6), | ||||||
|     'CODABAR': _SET_BARCODE_TYPE(6),  # Same as NW7 |     "CODABAR": _SET_BARCODE_TYPE(6),  # Same as NW7 | ||||||
| } | } | ||||||
|  |  | ||||||
| # Barcodes for printing function type B | # Barcodes for printing function type B | ||||||
| # The first 8 are the same barcodes as type A | # The first 8 are the same barcodes as type A | ||||||
| BARCODE_TYPE_B = { | BARCODE_TYPE_B = { | ||||||
|     'UPC-A':                       _SET_BARCODE_TYPE(65), |     "UPC-A": _SET_BARCODE_TYPE(65), | ||||||
|     'UPC-E':                       _SET_BARCODE_TYPE(66), |     "UPC-E": _SET_BARCODE_TYPE(66), | ||||||
|     'EAN13':                       _SET_BARCODE_TYPE(67), |     "EAN13": _SET_BARCODE_TYPE(67), | ||||||
|     'EAN8':                        _SET_BARCODE_TYPE(68), |     "EAN8": _SET_BARCODE_TYPE(68), | ||||||
|     'CODE39':                      _SET_BARCODE_TYPE(69), |     "CODE39": _SET_BARCODE_TYPE(69), | ||||||
|     'ITF':                         _SET_BARCODE_TYPE(70), |     "ITF": _SET_BARCODE_TYPE(70), | ||||||
|     'NW7':                         _SET_BARCODE_TYPE(71), |     "NW7": _SET_BARCODE_TYPE(71), | ||||||
|     'CODABAR':                     _SET_BARCODE_TYPE(71),  # Same as NW7 |     "CODABAR": _SET_BARCODE_TYPE(71),  # Same as NW7 | ||||||
|     'CODE93':                      _SET_BARCODE_TYPE(72), |     "CODE93": _SET_BARCODE_TYPE(72), | ||||||
|     'CODE128':                     _SET_BARCODE_TYPE(73), |     "CODE128": _SET_BARCODE_TYPE(73), | ||||||
|     'GS1-128':                     _SET_BARCODE_TYPE(74), |     "GS1-128": _SET_BARCODE_TYPE(74), | ||||||
|     'GS1 DATABAR OMNIDIRECTIONAL': _SET_BARCODE_TYPE(75), |     "GS1 DATABAR OMNIDIRECTIONAL": _SET_BARCODE_TYPE(75), | ||||||
|     'GS1 DATABAR TRUNCATED':       _SET_BARCODE_TYPE(76), |     "GS1 DATABAR TRUNCATED": _SET_BARCODE_TYPE(76), | ||||||
|     'GS1 DATABAR LIMITED':         _SET_BARCODE_TYPE(77), |     "GS1 DATABAR LIMITED": _SET_BARCODE_TYPE(77), | ||||||
|     'GS1 DATABAR EXPANDED':        _SET_BARCODE_TYPE(78), |     "GS1 DATABAR EXPANDED": _SET_BARCODE_TYPE(78), | ||||||
| } | } | ||||||
|  |  | ||||||
| BARCODE_FORMATS = { | BARCODE_FORMATS = { | ||||||
|     'UPC-A':                       ([(11, 12)], "^[0-9]{11,12}$"), |     "UPC-A": ([(11, 12)], "^[0-9]{11,12}$"), | ||||||
|     'UPC-E':                       ([(7, 8), (11, 12)], "^([0-9]{7,8}|[0-9]{11,12})$"), |     "UPC-E": ([(7, 8), (11, 12)], "^([0-9]{7,8}|[0-9]{11,12})$"), | ||||||
|     'EAN13':                       ([(12, 13)], "^[0-9]{12,13}$"), |     "EAN13": ([(12, 13)], "^[0-9]{12,13}$"), | ||||||
|     'EAN8':                        ([(7, 8)], "^[0-9]{7,8}$"), |     "EAN8": ([(7, 8)], "^[0-9]{7,8}$"), | ||||||
|     'CODE39':                      ([(1, 255)], "^([0-9A-Z \$\%\+\-\.\/]+|\*[0-9A-Z \$\%\+\-\.\/]+\*)$"), |     "CODE39": ([(1, 255)], "^([0-9A-Z \$\%\+\-\.\/]+|\*[0-9A-Z \$\%\+\-\.\/]+\*)$"), | ||||||
|     'ITF':                         ([(2, 255)], "^([0-9]{2})+$"), |     "ITF": ([(2, 255)], "^([0-9]{2})+$"), | ||||||
|     'NW7':                         ([(1, 255)], "^[A-Da-d][0-9\$\+\-\.\/\:]+[A-Da-d]$"), |     "NW7": ([(1, 255)], "^[A-Da-d][0-9\$\+\-\.\/\:]+[A-Da-d]$"), | ||||||
|     'CODABAR':                     ([(1, 255)], "^[A-Da-d][0-9\$\+\-\.\/\:]+[A-Da-d]$"),  # Same as NW7 |     "CODABAR": ([(1, 255)], "^[A-Da-d][0-9\$\+\-\.\/\:]+[A-Da-d]$"),  # Same as NW7 | ||||||
|     'CODE93':                      ([(1, 255)], "^[\\x00-\\x7F]+$"), |     "CODE93": ([(1, 255)], "^[\\x00-\\x7F]+$"), | ||||||
|     'CODE128':                     ([(2, 255)], "^\{[A-C][\\x00-\\x7F]+$"), |     "CODE128": ([(2, 255)], "^\{[A-C][\\x00-\\x7F]+$"), | ||||||
|     'GS1-128':                     ([(2, 255)], "^\{[A-C][\\x00-\\x7F]+$"), # same as CODE128 |     "GS1-128": ([(2, 255)], "^\{[A-C][\\x00-\\x7F]+$"),  # same as CODE128 | ||||||
|     'GS1 DATABAR OMNIDIRECTIONAL': ([(13,13)], "^[0-9]{13}$"), |     "GS1 DATABAR OMNIDIRECTIONAL": ([(13, 13)], "^[0-9]{13}$"), | ||||||
|     'GS1 DATABAR TRUNCATED':       ([(13,13)], "^[0-9]{13}$"), # same as GS1 omnidirectional |     "GS1 DATABAR TRUNCATED": ([(13, 13)], "^[0-9]{13}$"),  # same as GS1 omnidirectional | ||||||
|     'GS1 DATABAR LIMITED':         ([(13,13)], "^[01][0-9]{12}$"), |     "GS1 DATABAR LIMITED": ([(13, 13)], "^[01][0-9]{12}$"), | ||||||
|     'GS1 DATABAR EXPANDED':        ([(2,255)], "^\([0-9][A-Za-z0-9 \!\"\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\_\{]+$"), |     "GS1 DATABAR EXPANDED": ( | ||||||
|  |         [(2, 255)], | ||||||
|  |         "^\([0-9][A-Za-z0-9 \!\"\%\&'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\_\{]+$", | ||||||
|  |     ), | ||||||
| } | } | ||||||
|  |  | ||||||
| BARCODE_TYPES = { | BARCODE_TYPES = { | ||||||
|     'A': BARCODE_TYPE_A, |     "A": BARCODE_TYPE_A, | ||||||
|     'B': BARCODE_TYPE_B, |     "B": BARCODE_TYPE_B, | ||||||
| } | } | ||||||
|  |  | ||||||
| # QRCode error correction levels | # QRCode error correction levels | ||||||
| @@ -258,16 +266,16 @@ QR_MICRO = 3 | |||||||
| # Image format | # Image format | ||||||
| # NOTE: _PRINT_RASTER_IMG is the obsolete ESC/POS "print raster bit image" | # NOTE: _PRINT_RASTER_IMG is the obsolete ESC/POS "print raster bit image" | ||||||
| #       command. The constants include a fragment of the data's header. | #       command. The constants include a fragment of the data's header. | ||||||
| _PRINT_RASTER_IMG = lambda data: GS + b'v0' + data | _PRINT_RASTER_IMG = lambda data: GS + b"v0" + data | ||||||
| S_RASTER_N  = _PRINT_RASTER_IMG(b'\x00')  # Set raster image normal size | S_RASTER_N = _PRINT_RASTER_IMG(b"\x00")  # Set raster image normal size | ||||||
| S_RASTER_2W = _PRINT_RASTER_IMG(b'\x01')  # Set raster image double width | S_RASTER_2W = _PRINT_RASTER_IMG(b"\x01")  # Set raster image double width | ||||||
| S_RASTER_2H = _PRINT_RASTER_IMG(b'\x02')  # Set raster image double height | S_RASTER_2H = _PRINT_RASTER_IMG(b"\x02")  # Set raster image double height | ||||||
| S_RASTER_Q  = _PRINT_RASTER_IMG(b'\x03')  # Set raster image quadruple | S_RASTER_Q = _PRINT_RASTER_IMG(b"\x03")  # Set raster image quadruple | ||||||
|  |  | ||||||
| # Status Command | # Status Command | ||||||
| RT_STATUS = DLE + EOT | RT_STATUS = DLE + EOT | ||||||
| RT_STATUS_ONLINE = RT_STATUS +  b'\x01' | RT_STATUS_ONLINE = RT_STATUS + b"\x01" | ||||||
| RT_STATUS_PAPER = RT_STATUS +  b'\x04' | RT_STATUS_PAPER = RT_STATUS + b"\x04" | ||||||
| RT_MASK_ONLINE = 8 | RT_MASK_ONLINE = 8 | ||||||
| RT_MASK_PAPER = 18 | RT_MASK_PAPER = 18 | ||||||
| RT_MASK_LOWPAPER = 30 | RT_MASK_LOWPAPER = 30 | ||||||
|   | |||||||
| @@ -22,17 +22,51 @@ from barcode.writer import ImageWriter | |||||||
|  |  | ||||||
| import os | import os | ||||||
|  |  | ||||||
| from .constants import ESC, GS, NUL, QR_ECLEVEL_L, QR_ECLEVEL_M, QR_ECLEVEL_H, QR_ECLEVEL_Q | from .constants import ( | ||||||
| from .constants import QR_MODEL_1, QR_MODEL_2, QR_MICRO, BARCODE_TYPES, BARCODE_HEIGHT, BARCODE_WIDTH |     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 | 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 TXT_SIZE, TXT_NORMAL | ||||||
| from .constants import SET_FONT | from .constants import SET_FONT | ||||||
| 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 ( | ||||||
|  |     CD_KICK_DEC_SEQUENCE, | ||||||
|  |     CD_KICK_5, | ||||||
|  |     CD_KICK_2, | ||||||
|  |     PAPER_FULL_CUT, | ||||||
|  |     PAPER_PART_CUT, | ||||||
|  | ) | ||||||
| from .constants import HW_RESET, HW_SELECT, HW_INIT | from .constants import HW_RESET, HW_SELECT, HW_INIT | ||||||
| from .constants import CTL_VT, CTL_CR, CTL_FF, CTL_LF, CTL_SET_HT, PANEL_BUTTON_OFF, PANEL_BUTTON_ON | 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 TXT_STYLE | ||||||
| from .constants import RT_STATUS_ONLINE, RT_MASK_ONLINE | 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 | ||||||
| @@ -55,6 +89,7 @@ class Escpos(object): | |||||||
|     This class is the abstract base class for an esc/pos-printer. The printer implementations are children of this |     This class is the abstract base class for an esc/pos-printer. The printer implementations are children of this | ||||||
|     class. |     class. | ||||||
|     """ |     """ | ||||||
|  |  | ||||||
|     device = None |     device = None | ||||||
|  |  | ||||||
|     def __init__(self, profile=None, magic_encode_args=None, **kwargs): |     def __init__(self, profile=None, magic_encode_args=None, **kwargs): | ||||||
| @@ -85,8 +120,15 @@ class Escpos(object): | |||||||
|         """ |         """ | ||||||
|         raise NotImplementedError() |         raise NotImplementedError() | ||||||
|  |  | ||||||
|     def image(self, img_source, high_density_vertical=True, high_density_horizontal=True, impl="bitImageRaster", |     def image( | ||||||
|               fragment_height=960, center=False): |         self, | ||||||
|  |         img_source, | ||||||
|  |         high_density_vertical=True, | ||||||
|  |         high_density_horizontal=True, | ||||||
|  |         impl="bitImageRaster", | ||||||
|  |         fragment_height=960, | ||||||
|  |         center=False, | ||||||
|  |     ): | ||||||
|         """Print an image |         """Print an image | ||||||
|  |  | ||||||
|         You can select whether the printer should print in high density or not. The default value is high density. |         You can select whether the printer should print in high density or not. The default value is high density. | ||||||
| @@ -116,14 +158,16 @@ class Escpos(object): | |||||||
|         im = EscposImage(img_source) |         im = EscposImage(img_source) | ||||||
|  |  | ||||||
|         try: |         try: | ||||||
|             if self.profile.profile_data['media']['width']['pixels'] == "Unknown": |             if self.profile.profile_data["media"]["width"]["pixels"] == "Unknown": | ||||||
|                 print("The media.width.pixel field of the printer profile is not set. " + |                 print( | ||||||
|                       "The center flag will have no effect.") |                     "The media.width.pixel field of the printer profile is not set. " | ||||||
|  |                     + "The center flag will have no effect." | ||||||
|  |                 ) | ||||||
|  |  | ||||||
|             max_width = int(self.profile.profile_data['media']['width']['pixels']) |             max_width = int(self.profile.profile_data["media"]["width"]["pixels"]) | ||||||
|  |  | ||||||
|             if im.width > max_width: |             if im.width > max_width: | ||||||
|                 raise ImageWidthError('{} > {}'.format(im.width, max_width)) |                 raise ImageWidthError("{} > {}".format(im.width, max_width)) | ||||||
|  |  | ||||||
|             if center: |             if center: | ||||||
|                 im.center(max_width) |                 im.center(max_width) | ||||||
| @@ -137,41 +181,59 @@ class Escpos(object): | |||||||
|         if im.height > fragment_height: |         if im.height > fragment_height: | ||||||
|             fragments = im.split(fragment_height) |             fragments = im.split(fragment_height) | ||||||
|             for fragment in fragments: |             for fragment in fragments: | ||||||
|                 self.image(fragment, |                 self.image( | ||||||
|  |                     fragment, | ||||||
|                     high_density_vertical=high_density_vertical, |                     high_density_vertical=high_density_vertical, | ||||||
|                     high_density_horizontal=high_density_horizontal, |                     high_density_horizontal=high_density_horizontal, | ||||||
|                     impl=impl, |                     impl=impl, | ||||||
|                            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) + ( | ||||||
|             header = GS + b"v0" + six.int2byte(density_byte) + self._int_low_high(im.width_bytes, 2) +\ |                 0 if high_density_vertical else 2 | ||||||
|                 self._int_low_high(im.height, 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._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( | ||||||
|             tone = b'0' |                 im.height, 2 | ||||||
|             colors = b'1' |             ) | ||||||
|  |             tone = b"0" | ||||||
|  |             colors = b"1" | ||||||
|             ym = six.int2byte(1 if high_density_vertical else 2) |             ym = six.int2byte(1 if high_density_vertical else 2) | ||||||
|             xm = six.int2byte(1 if high_density_horizontal else 2) |             xm = six.int2byte(1 if high_density_horizontal else 2) | ||||||
|             header = tone + xm + ym + colors + img_header |             header = tone + xm + ym + colors + img_header | ||||||
|             raster_data = im.to_raster_format() |             raster_data = im.to_raster_format() | ||||||
|             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) + ( | ||||||
|             header = ESC + b"*" + six.int2byte(density_byte) + self._int_low_high(im.width, 2) |                 32 if high_density_vertical else 0 | ||||||
|  |             ) | ||||||
|  |             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,10 +244,18 @@ class Escpos(object): | |||||||
|         :param data: Data to send |         :param data: Data to send | ||||||
|         """ |         """ | ||||||
|         header = self._int_low_high(len(data) + 2, 2) |         header = self._int_low_high(len(data) + 2, 2) | ||||||
|         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( | ||||||
|            native=False, center=False, impl="bitImageRaster"): |         self, | ||||||
|  |         content, | ||||||
|  |         ec=QR_ECLEVEL_L, | ||||||
|  |         size=3, | ||||||
|  |         model=QR_MODEL_2, | ||||||
|  |         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. | ||||||
| @@ -206,49 +276,59 @@ class Escpos(object): | |||||||
|         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, | ||||||
|                 QR_ECLEVEL_M: qrcode.constants.ERROR_CORRECT_M, |                 QR_ECLEVEL_M: qrcode.constants.ERROR_CORRECT_M, | ||||||
|                 QR_ECLEVEL_Q: qrcode.constants.ERROR_CORRECT_Q |                 QR_ECLEVEL_Q: qrcode.constants.ERROR_CORRECT_Q, | ||||||
|             } |             } | ||||||
|             qr_code = qrcode.QRCode(version=None, box_size=size, border=1, error_correction=python_qr_ec[ec]) |             qr_code = qrcode.QRCode( | ||||||
|  |                 version=None, box_size=size, border=1, error_correction=python_qr_ec[ec] | ||||||
|  |             ) | ||||||
|             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") | ||||||
|             self.image(im, center=center, impl=impl) |             self.image(im, center=center, impl=impl) | ||||||
|             self.text('\n') |             self.text("\n") | ||||||
|             self.text('\n') |             self.text("\n") | ||||||
|             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 | ||||||
|         # Select model: 1, 2 or micro. |         # Select model: 1, 2 or micro. | ||||||
|         self._send_2d_code_data(six.int2byte(65), cn, six.int2byte(48 + model) + six.int2byte(0)) |         self._send_2d_code_data( | ||||||
|  |             six.int2byte(65), cn, six.int2byte(48 + model) + six.int2byte(0) | ||||||
|  |         ) | ||||||
|         # Set dot size. |         # Set dot size. | ||||||
|         self._send_2d_code_data(six.int2byte(67), cn, six.int2byte(size)) |         self._send_2d_code_data(six.int2byte(67), cn, six.int2byte(size)) | ||||||
|         # Set error correction level: L, M, Q, or H |         # Set error correction level: L, M, Q, or H | ||||||
|         self._send_2d_code_data(six.int2byte(69), cn, six.int2byte(48 + ec)) |         self._send_2d_code_data(six.int2byte(69), cn, six.int2byte(48 + ec)) | ||||||
|         # Send content & print |         # Send content & print | ||||||
|         self._send_2d_code_data(six.int2byte(80), cn, content.encode('utf-8'), b'0') |         self._send_2d_code_data(six.int2byte(80), cn, content.encode("utf-8"), b"0") | ||||||
|         self._send_2d_code_data(six.int2byte(81), cn, b'', b'0') |         self._send_2d_code_data(six.int2byte(81), cn, b"", b"0") | ||||||
|  |  | ||||||
|     def _send_2d_code_data(self, fn, cn, data, m=b''): |     def _send_2d_code_data(self, fn, cn, data, m=b""): | ||||||
|         """Wrapper for GS ( k, to calculate and send correct data length. |         """Wrapper for GS ( k, to calculate and send correct data length. | ||||||
|  |  | ||||||
|         :param fn: Function to use. |         :param fn: Function to use. | ||||||
| @@ -259,7 +339,7 @@ class Escpos(object): | |||||||
|         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) | ||||||
|  |  | ||||||
|     @staticmethod |     @staticmethod | ||||||
|     def _int_low_high(inp_number, out_bytes): |     def _int_low_high(inp_number, out_bytes): | ||||||
| @@ -268,12 +348,16 @@ class Escpos(object): | |||||||
|         :param inp_number: Input number |         :param inp_number: Input number | ||||||
|         :param out_bytes: The number of bytes to output (1 - 4). |         :param out_bytes: The number of bytes to output (1 - 4). | ||||||
|         """ |         """ | ||||||
|         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( | ||||||
|         outp = b'' |                 "Number too large. Can only output up to {0} in {1} bytes".format( | ||||||
|  |                     max_input, out_bytes | ||||||
|  |                 ) | ||||||
|  |             ) | ||||||
|  |         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 | ||||||
| @@ -318,10 +402,22 @@ class Escpos(object): | |||||||
|             return False |             return False | ||||||
|  |  | ||||||
|         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( | ||||||
|                 align_ct=True, function_type=None, check=True): |         self, | ||||||
|  |         code, | ||||||
|  |         bc, | ||||||
|  |         height=64, | ||||||
|  |         width=3, | ||||||
|  |         pos="BELOW", | ||||||
|  |         font="A", | ||||||
|  |         align_ct=True, | ||||||
|  |         function_type=None, | ||||||
|  |         check=True, | ||||||
|  |     ): | ||||||
|         """Print Barcode |         """Print Barcode | ||||||
|  |  | ||||||
|         This method allows to print barcodes. The rendering of the barcode is done by the printer and therefore has to |         This method allows to print barcodes. The rendering of the barcode is done by the printer and therefore has to | ||||||
| @@ -407,38 +503,46 @@ class Escpos(object): | |||||||
|         """ |         """ | ||||||
|         if function_type is None: |         if function_type is None: | ||||||
|             # Choose the function type automatically. |             # Choose the function type automatically. | ||||||
|             if bc in BARCODE_TYPES['A']: |             if bc in BARCODE_TYPES["A"]: | ||||||
|                 function_type = 'A' |                 function_type = "A" | ||||||
|             else: |             else: | ||||||
|                 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" | ||||||
|                     function_type = 'B' |                             ).format(bc=bc) | ||||||
|  |                         ) | ||||||
|  |                     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( | ||||||
|                 "Barcode '{code}' not in a valid format for type '{bc}'").format( |                 ("Barcode '{code}' not in a valid format for type '{bc}'").format( | ||||||
|                     code=code, |                     code=code, | ||||||
|                     bc=bc, |                     bc=bc, | ||||||
|             )) |                 ) | ||||||
|  |             ) | ||||||
|  |  | ||||||
|         # Align Bar Code() |         # Align Bar Code() | ||||||
|         if align_ct: |         if align_ct: | ||||||
|             self._raw(TXT_STYLE['align']['center']) |             self._raw(TXT_STYLE["align"]["center"]) | ||||||
|         # Height |         # Height | ||||||
|         if 1 <= height <= 255: |         if 1 <= height <= 255: | ||||||
|             self._raw(BARCODE_HEIGHT + six.int2byte(height)) |             self._raw(BARCODE_HEIGHT + six.int2byte(height)) | ||||||
| @@ -478,28 +582,40 @@ class Escpos(object): | |||||||
|         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( | ||||||
|                      module_height=5, module_width=0.2, text_distance=1, |         self, | ||||||
|                      center=True): |         barcode_type, | ||||||
|  |         data, | ||||||
|  |         impl="bitImageColumn", | ||||||
|  |         module_height=5, | ||||||
|  |         module_width=0.2, | ||||||
|  |         text_distance=1, | ||||||
|  |         center=True, | ||||||
|  |     ): | ||||||
|  |  | ||||||
|         image_writer = ImageWriter() |         image_writer = ImageWriter() | ||||||
|  |  | ||||||
|         # Check if barcode type exists |         # Check if barcode type exists | ||||||
|         if barcode_type not in barcode.PROVIDED_BARCODES: |         if barcode_type not in barcode.PROVIDED_BARCODES: | ||||||
|             raise BarcodeTypeError( |             raise BarcodeTypeError( | ||||||
|                 'Barcode type {} not supported by software barcode renderer' |                 "Barcode type {} not supported by software barcode renderer".format( | ||||||
|                 .format(barcode_type)) |                     barcode_type | ||||||
|  |                 ) | ||||||
|  |             ) | ||||||
|  |  | ||||||
|         # Render the barcode to a fake file |         # Render the barcode to a fake file | ||||||
|         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( | ||||||
|                 'module_height': module_height, |                 nullfile, | ||||||
|                 'module_width': module_width, |                 { | ||||||
|                 'text_distance': text_distance |                     "module_height": module_height, | ||||||
|             }) |                     "module_width": module_width, | ||||||
|  |                     "text_distance": text_distance, | ||||||
|  |                 }, | ||||||
|  |             ) | ||||||
|  |  | ||||||
|         # Retrieve the Pillow image and print it |         # Retrieve the Pillow image and print it | ||||||
|         image = my_code.writer._image |         image = my_code.writer._image | ||||||
| @@ -517,7 +633,7 @@ class Escpos(object): | |||||||
|         txt = six.text_type(txt) |         txt = six.text_type(txt) | ||||||
|         self.magic.write(txt) |         self.magic.write(txt) | ||||||
|  |  | ||||||
|     def textln(self, txt=''): |     def textln(self, txt=""): | ||||||
|         """Print alpha-numeric text with a newline |         """Print alpha-numeric text with a newline | ||||||
|  |  | ||||||
|         The text has to be encoded in the currently selected codepage. |         The text has to be encoded in the currently selected codepage. | ||||||
| @@ -526,7 +642,7 @@ class Escpos(object): | |||||||
|         :param txt: text to be printed with a newline |         :param txt: text to be printed with a newline | ||||||
|         :raises: :py:exc:`~escpos.exceptions.TextError` |         :raises: :py:exc:`~escpos.exceptions.TextError` | ||||||
|         """ |         """ | ||||||
|         self.text('{}\n'.format(txt)) |         self.text("{}\n".format(txt)) | ||||||
|  |  | ||||||
|     def ln(self, count=1): |     def ln(self, count=1): | ||||||
|         """Print a newline or more |         """Print a newline or more | ||||||
| @@ -535,9 +651,9 @@ class Escpos(object): | |||||||
|         :raises: :py:exc:`ValueError` if count < 0 |         :raises: :py:exc:`ValueError` if count < 0 | ||||||
|         """ |         """ | ||||||
|         if count < 0: |         if count < 0: | ||||||
|             raise ValueError('Count cannot be lesser than 0') |             raise ValueError("Count cannot be lesser than 0") | ||||||
|         if count > 0: |         if count > 0: | ||||||
|             self.text('\n' * count) |             self.text("\n" * count) | ||||||
|  |  | ||||||
|     def block_text(self, txt, font="0", columns=None): |     def block_text(self, txt, font="0", columns=None): | ||||||
|         """Text is printed wrapped to specified columns |         """Text is printed wrapped to specified columns | ||||||
| @@ -552,9 +668,22 @@ class Escpos(object): | |||||||
|         col_count = self.profile.get_columns(font) if columns is None else columns |         col_count = self.profile.get_columns(font) if columns is None else columns | ||||||
|         self.text(textwrap.fill(txt, col_count)) |         self.text(textwrap.fill(txt, col_count)) | ||||||
|  |  | ||||||
|     def set(self, align='left', font='a', bold=False, underline=0, width=1, |     def set( | ||||||
|             height=1, density=9, invert=False, smooth=False, flip=False, |         self, | ||||||
|             double_width=False, double_height=False, custom_size=False): |         align="left", | ||||||
|  |         font="a", | ||||||
|  |         bold=False, | ||||||
|  |         underline=0, | ||||||
|  |         width=1, | ||||||
|  |         height=1, | ||||||
|  |         density=9, | ||||||
|  |         invert=False, | ||||||
|  |         smooth=False, | ||||||
|  |         flip=False, | ||||||
|  |         double_width=False, | ||||||
|  |         double_height=False, | ||||||
|  |         custom_size=False, | ||||||
|  |     ): | ||||||
|         """Set text properties by sending them to the printer |         """Set text properties by sending them to the printer | ||||||
|  |  | ||||||
|         :param align: horizontal position for text, possible values are: |         :param align: horizontal position for text, possible values are: | ||||||
| @@ -596,34 +725,38 @@ class Escpos(object): | |||||||
|         """ |         """ | ||||||
|  |  | ||||||
|         if custom_size: |         if custom_size: | ||||||
|             if 1 <= width <= 8 and 1 <= height <= 8 and isinstance(width, int) and\ |             if ( | ||||||
|               isinstance(height, int): |                 1 <= width <= 8 | ||||||
|                 size_byte = TXT_STYLE['width'][width] + TXT_STYLE['height'][height] |                 and 1 <= height <= 8 | ||||||
|  |                 and isinstance(width, int) | ||||||
|  |                 and isinstance(height, int) | ||||||
|  |             ): | ||||||
|  |                 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: | ||||||
|                 raise SetVariableError() |                 raise SetVariableError() | ||||||
|         else: |         else: | ||||||
|             self._raw(TXT_NORMAL) |             self._raw(TXT_NORMAL) | ||||||
|             if double_width and double_height: |             if double_width and double_height: | ||||||
|                 self._raw(TXT_STYLE['size']['2x']) |                 self._raw(TXT_STYLE["size"]["2x"]) | ||||||
|             elif double_width: |             elif double_width: | ||||||
|                 self._raw(TXT_STYLE['size']['2w']) |                 self._raw(TXT_STYLE["size"]["2w"]) | ||||||
|             elif double_height: |             elif double_height: | ||||||
|                 self._raw(TXT_STYLE['size']['2h']) |                 self._raw(TXT_STYLE["size"]["2h"]) | ||||||
|             else: |             else: | ||||||
|                 self._raw(TXT_STYLE['size']['normal']) |                 self._raw(TXT_STYLE["size"]["normal"]) | ||||||
|  |  | ||||||
|         self._raw(TXT_STYLE['flip'][flip]) |         self._raw(TXT_STYLE["flip"][flip]) | ||||||
|         self._raw(TXT_STYLE['smooth'][smooth]) |         self._raw(TXT_STYLE["smooth"][smooth]) | ||||||
|         self._raw(TXT_STYLE['bold'][bold]) |         self._raw(TXT_STYLE["bold"][bold]) | ||||||
|         self._raw(TXT_STYLE['underline'][underline]) |         self._raw(TXT_STYLE["underline"][underline]) | ||||||
|         self._raw(SET_FONT(six.int2byte(self.profile.get_font(font)))) |         self._raw(SET_FONT(six.int2byte(self.profile.get_font(font)))) | ||||||
|         self._raw(TXT_STYLE['align'][align]) |         self._raw(TXT_STYLE["align"][align]) | ||||||
|  |  | ||||||
|         if density != 9: |         if density != 9: | ||||||
|             self._raw(TXT_STYLE['density'][density]) |             self._raw(TXT_STYLE["density"][density]) | ||||||
|  |  | ||||||
|         self._raw(TXT_STYLE['invert'][invert]) |         self._raw(TXT_STYLE["invert"][invert]) | ||||||
|  |  | ||||||
|     def line_spacing(self, spacing=None, divisor=180): |     def line_spacing(self, spacing=None, divisor=180): | ||||||
|         """Set line character spacing. |         """Set line character spacing. | ||||||
| @@ -646,15 +779,18 @@ class Escpos(object): | |||||||
|  |  | ||||||
|         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( | ||||||
|             raise ValueError("spacing must be a int between 0 and 255 when divisor is 360 or 180") |                 "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)) | ||||||
|  |  | ||||||
|     def cut(self, mode='FULL', feed=True): |     def cut(self, mode="FULL", feed=True): | ||||||
|         """Cut paper. |         """Cut paper. | ||||||
|  |  | ||||||
|         Without any arguments the paper will be cut completely. With 'mode=PART' a partial cut will |         Without any arguments the paper will be cut completely. With 'mode=PART' a partial cut will | ||||||
| @@ -667,24 +803,24 @@ class Escpos(object): | |||||||
|         """ |         """ | ||||||
|  |  | ||||||
|         if not feed: |         if not feed: | ||||||
|             self._raw(GS + b'V' + six.int2byte(66) + b'\x00') |             self._raw(GS + b"V" + six.int2byte(66) + b"\x00") | ||||||
|             return |             return | ||||||
|  |  | ||||||
|         self.print_and_feed(6) |         self.print_and_feed(6) | ||||||
|  |  | ||||||
|         mode = mode.upper() |         mode = mode.upper() | ||||||
|         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"): | ||||||
|                 self._raw(PAPER_PART_CUT) |                 self._raw(PAPER_PART_CUT) | ||||||
|  |  | ||||||
|     def cashdraw(self, pin): |     def cashdraw(self, pin): | ||||||
| @@ -797,9 +933,9 @@ class Escpos(object): | |||||||
|         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 ( | ||||||
|                     1 <= tab_size <= 255 and |                 0 <= count <= 32 and 1 <= tab_size <= 255 and count * tab_size < 256 | ||||||
|                     count * tab_size < 256): |             ): | ||||||
|                 raise TabPosError() |                 raise TabPosError() | ||||||
|             else: |             else: | ||||||
|                 # Set tab positions |                 # Set tab positions | ||||||
| @@ -872,11 +1008,11 @@ class Escpos(object): | |||||||
|         status = self.query_status(RT_STATUS_PAPER) |         status = self.query_status(RT_STATUS_PAPER) | ||||||
|         if len(status) == 0: |         if len(status) == 0: | ||||||
|             return 2 |             return 2 | ||||||
|         if (status[0] & RT_MASK_NOPAPER == RT_MASK_NOPAPER): |         if status[0] & RT_MASK_NOPAPER == RT_MASK_NOPAPER: | ||||||
|             return 0 |             return 0 | ||||||
|         if (status[0] & RT_MASK_LOWPAPER == RT_MASK_LOWPAPER): |         if status[0] & RT_MASK_LOWPAPER == RT_MASK_LOWPAPER: | ||||||
|             return 1 |             return 1 | ||||||
|         if (status[0] & RT_MASK_PAPER == RT_MASK_PAPER): |         if status[0] & RT_MASK_PAPER == RT_MASK_PAPER: | ||||||
|             return 2 |             return 2 | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -929,11 +1065,13 @@ class EscposIO(object): | |||||||
|         params.update(kwargs) |         params.update(kwargs) | ||||||
|  |  | ||||||
|         if isinstance(text, six.text_type): |         if isinstance(text, six.text_type): | ||||||
|             lines = text.split('\n') |             lines = text.split("\n") | ||||||
|         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) | ||||||
| @@ -945,8 +1083,7 @@ class EscposIO(object): | |||||||
|                 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""" | ||||||
|         """ |  | ||||||
|         self.printer.close() |         self.printer.close() | ||||||
|  |  | ||||||
|     def __enter__(self, **kwargs): |     def __enter__(self, **kwargs): | ||||||
|   | |||||||
| @@ -28,6 +28,7 @@ Result/Exit codes: | |||||||
|  |  | ||||||
| class Error(Exception): | class Error(Exception): | ||||||
|     """Base class for ESC/POS errors""" |     """Base class for ESC/POS errors""" | ||||||
|  |  | ||||||
|     def __init__(self, msg, status=None): |     def __init__(self, msg, status=None): | ||||||
|         Exception.__init__(self) |         Exception.__init__(self) | ||||||
|         self.msg = msg |         self.msg = msg | ||||||
| @@ -46,6 +47,7 @@ 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 | ||||||
| @@ -62,6 +64,7 @@ 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 | ||||||
| @@ -78,6 +81,7 @@ 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 | ||||||
| @@ -92,13 +96,16 @@ 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 | ||||||
|  |  | ||||||
|     def __str__(self): |     def __str__(self): | ||||||
|         return "Image height is longer than 255px and can't be printed ({msg})".format(msg=self.msg) |         return "Image height is longer than 255px and can't be printed ({msg})".format( | ||||||
|  |             msg=self.msg | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |  | ||||||
| class ImageWidthError(Error): | class ImageWidthError(Error): | ||||||
| @@ -106,6 +113,7 @@ 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 | ||||||
| @@ -121,13 +129,16 @@ 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): | ||||||
| @@ -136,6 +147,7 @@ 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 | ||||||
| @@ -152,13 +164,16 @@ 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): | ||||||
| @@ -167,6 +182,7 @@ 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 | ||||||
| @@ -182,6 +198,7 @@ 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 | ||||||
| @@ -197,6 +214,7 @@ 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 | ||||||
| @@ -208,12 +226,14 @@ class SetVariableError(Error): | |||||||
|  |  | ||||||
| # Configuration errors | # Configuration errors | ||||||
|  |  | ||||||
|  |  | ||||||
| class ConfigNotFoundError(Error): | class ConfigNotFoundError(Error): | ||||||
|     """The configuration file was not found |     """The configuration file was not found | ||||||
|  |  | ||||||
|     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 | ||||||
| @@ -229,6 +249,7 @@ 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 | ||||||
| @@ -244,6 +265,7 @@ 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 | ||||||
|   | |||||||
| @@ -37,7 +37,7 @@ 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 | ||||||
|   | |||||||
| @@ -34,69 +34,68 @@ def encode_katakana(text): | |||||||
| TXT_ENC_KATAKANA_MAP = { | TXT_ENC_KATAKANA_MAP = { | ||||||
|     # Maps UTF-8 Katakana symbols to KATAKANA Page Codes |     # Maps UTF-8 Katakana symbols to KATAKANA Page Codes | ||||||
|     # TODO: has this really to be hardcoded? |     # TODO: has this really to be hardcoded? | ||||||
|  |  | ||||||
|     # Half-Width Katakanas |     # Half-Width Katakanas | ||||||
|     '。': b'\xa1', |     "。": b"\xa1", | ||||||
|     '「': b'\xa2', |     "「": b"\xa2", | ||||||
|     '」': b'\xa3', |     "」": b"\xa3", | ||||||
|     '、': b'\xa4', |     "、": b"\xa4", | ||||||
|     '・': b'\xa5', |     "・": b"\xa5", | ||||||
|     'ヲ': b'\xa6', |     "ヲ": b"\xa6", | ||||||
|     'ァ': b'\xa7', |     "ァ": b"\xa7", | ||||||
|     'ィ': b'\xa8', |     "ィ": b"\xa8", | ||||||
|     'ゥ': b'\xa9', |     "ゥ": b"\xa9", | ||||||
|     'ェ': b'\xaa', |     "ェ": b"\xaa", | ||||||
|     'ォ': b'\xab', |     "ォ": b"\xab", | ||||||
|     'ャ': b'\xac', |     "ャ": b"\xac", | ||||||
|     'ュ': b'\xad', |     "ュ": b"\xad", | ||||||
|     'ョ': b'\xae', |     "ョ": b"\xae", | ||||||
|     'ッ': b'\xaf', |     "ッ": b"\xaf", | ||||||
|     'ー': b'\xb0', |     "ー": b"\xb0", | ||||||
|     'ア': b'\xb1', |     "ア": b"\xb1", | ||||||
|     'イ': b'\xb2', |     "イ": b"\xb2", | ||||||
|     'ウ': b'\xb3', |     "ウ": b"\xb3", | ||||||
|     'エ': b'\xb4', |     "エ": b"\xb4", | ||||||
|     'オ': b'\xb5', |     "オ": b"\xb5", | ||||||
|     'カ': b'\xb6', |     "カ": b"\xb6", | ||||||
|     'キ': b'\xb7', |     "キ": b"\xb7", | ||||||
|     'ク': b'\xb8', |     "ク": b"\xb8", | ||||||
|     'ケ': b'\xb9', |     "ケ": b"\xb9", | ||||||
|     'コ': b'\xba', |     "コ": b"\xba", | ||||||
|     'サ': b'\xbb', |     "サ": b"\xbb", | ||||||
|     'シ': b'\xbc', |     "シ": b"\xbc", | ||||||
|     'ス': b'\xbd', |     "ス": b"\xbd", | ||||||
|     'セ': b'\xbe', |     "セ": b"\xbe", | ||||||
|     'ソ': b'\xbf', |     "ソ": b"\xbf", | ||||||
|     'タ': b'\xc0', |     "タ": b"\xc0", | ||||||
|     'チ': b'\xc1', |     "チ": b"\xc1", | ||||||
|     'ツ': b'\xc2', |     "ツ": b"\xc2", | ||||||
|     'テ': b'\xc3', |     "テ": b"\xc3", | ||||||
|     'ト': b'\xc4', |     "ト": b"\xc4", | ||||||
|     'ナ': b'\xc5', |     "ナ": b"\xc5", | ||||||
|     'ニ': b'\xc6', |     "ニ": b"\xc6", | ||||||
|     'ヌ': b'\xc7', |     "ヌ": b"\xc7", | ||||||
|     'ネ': b'\xc8', |     "ネ": b"\xc8", | ||||||
|     'ノ': b'\xc9', |     "ノ": b"\xc9", | ||||||
|     'ハ': b'\xca', |     "ハ": b"\xca", | ||||||
|     'ヒ': b'\xcb', |     "ヒ": b"\xcb", | ||||||
|     'フ': b'\xcc', |     "フ": b"\xcc", | ||||||
|     'ヘ': b'\xcd', |     "ヘ": b"\xcd", | ||||||
|     'ホ': b'\xce', |     "ホ": b"\xce", | ||||||
|     'マ': b'\xcf', |     "マ": b"\xcf", | ||||||
|     'ミ': b'\xd0', |     "ミ": b"\xd0", | ||||||
|     'ム': b'\xd1', |     "ム": b"\xd1", | ||||||
|     'メ': b'\xd2', |     "メ": b"\xd2", | ||||||
|     'モ': b'\xd3', |     "モ": b"\xd3", | ||||||
|     'ヤ': b'\xd4', |     "ヤ": b"\xd4", | ||||||
|     'ユ': b'\xd5', |     "ユ": b"\xd5", | ||||||
|     'ヨ': b'\xd6', |     "ヨ": b"\xd6", | ||||||
|     'ラ': b'\xd7', |     "ラ": b"\xd7", | ||||||
|     'リ': b'\xd8', |     "リ": b"\xd8", | ||||||
|     'ル': b'\xd9', |     "ル": b"\xd9", | ||||||
|     'レ': b'\xda', |     "レ": b"\xda", | ||||||
|     'ロ': b'\xdb', |     "ロ": b"\xdb", | ||||||
|     'ワ': b'\xdc', |     "ワ": b"\xdc", | ||||||
|     'ン': b'\xdd', |     "ン": b"\xdd", | ||||||
|     '゙': b'\xde', |     "゙": b"\xde", | ||||||
|     '゚': b'\xdf', |     "゚": b"\xdf", | ||||||
| } | } | ||||||
|   | |||||||
| @@ -55,10 +55,12 @@ class Encoder(object): | |||||||
|         """ |         """ | ||||||
|         encoding = CodePages.get_encoding_name(encoding) |         encoding = CodePages.get_encoding_name(encoding) | ||||||
|         if encoding not in self.codepages: |         if encoding not in self.codepages: | ||||||
|             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 | ||||||
| @@ -70,16 +72,18 @@ class Encoder(object): | |||||||
|         :param encoding: The name of the encoding. This must appear in the CodePage list |         :param encoding: The name of the encoding. This must appear in the CodePage list | ||||||
|         """ |         """ | ||||||
|         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: | ||||||
|                     encodable_chars[i] = bytes([codepoint]).decode(codepage['python_encode']) |                     encodable_chars[i] = bytes([codepoint]).decode( | ||||||
|  |                         codepage["python_encode"] | ||||||
|  |                     ) | ||||||
|                 except UnicodeDecodeError: |                 except UnicodeDecodeError: | ||||||
|                     # Non-encodable character, just skip it |                     # Non-encodable character, just skip it | ||||||
|                     pass |                     pass | ||||||
| @@ -100,7 +104,9 @@ class Encoder(object): | |||||||
|         if encoding in self.available_characters: |         if encoding in self.available_characters: | ||||||
|             return self.available_characters[encoding] |             return self.available_characters[encoding] | ||||||
|         codepage_char_list = self._get_codepage_char_list(encoding) |         codepage_char_list = self._get_codepage_char_list(encoding) | ||||||
|         codepage_char_map = dict((utf8, i + 128) for (i, utf8) in enumerate(codepage_char_list)) |         codepage_char_map = dict( | ||||||
|  |             (utf8, i + 128) for (i, utf8) in enumerate(codepage_char_list) | ||||||
|  |         ) | ||||||
|         self.available_characters[encoding] = codepage_char_map |         self.available_characters[encoding] = codepage_char_map | ||||||
|         return codepage_char_map |         return codepage_char_map | ||||||
|  |  | ||||||
| @@ -134,7 +140,7 @@ class Encoder(object): | |||||||
|             return charmap[char] |             return charmap[char] | ||||||
|         return ord(defaultchar) |         return ord(defaultchar) | ||||||
|  |  | ||||||
|     def encode(self, text, encoding, defaultchar='?'): |     def encode(self, text, encoding, defaultchar="?"): | ||||||
|         """Encode text under the given encoding |         """Encode text under the given encoding | ||||||
|  |  | ||||||
|         :param text: Text to encode |         :param text: Text to encode | ||||||
| @@ -142,15 +148,14 @@ class Encoder(object): | |||||||
|         :param defaultchar: Fallback for non-encodable characters |         :param defaultchar: Fallback for non-encodable characters | ||||||
|         """ |         """ | ||||||
|         codepage_char_map = self._get_codepage_char_map(encoding) |         codepage_char_map = self._get_codepage_char_map(encoding) | ||||||
|         output_bytes = bytes([self._encode_char(char, codepage_char_map, defaultchar) for char in text]) |         output_bytes = bytes( | ||||||
|  |             [self._encode_char(char, codepage_char_map, defaultchar) for char in text] | ||||||
|  |         ) | ||||||
|         return output_bytes |         return output_bytes | ||||||
|  |  | ||||||
|     def __encoding_sort_func(self, item): |     def __encoding_sort_func(self, item): | ||||||
|         key, index = item |         key, index = item | ||||||
|         return ( |         return (key in self.used_encodings, index) | ||||||
|             key in self.used_encodings, |  | ||||||
|             index |  | ||||||
|         ) |  | ||||||
|  |  | ||||||
|     def find_suitable_encoding(self, char): |     def find_suitable_encoding(self, char): | ||||||
|         """The order of our search is a specific one: |         """The order of our search is a specific one: | ||||||
| @@ -168,9 +173,7 @@ class Encoder(object): | |||||||
|            that the code page we pick for this character is actually |            that the code page we pick for this character is actually | ||||||
|            supported. |            supported. | ||||||
|         """ |         """ | ||||||
|         sorted_encodings = sorted( |         sorted_encodings = sorted(self.codepages.items(), key=self.__encoding_sort_func) | ||||||
|             self.codepages.items(), |  | ||||||
|             key=self.__encoding_sort_func) |  | ||||||
|  |  | ||||||
|         for encoding, _ in sorted_encodings: |         for encoding, _ in sorted_encodings: | ||||||
|             if self.can_encode(encoding, char): |             if self.can_encode(encoding, char): | ||||||
| @@ -205,8 +208,10 @@ class MagicEncode(object): | |||||||
|     If the printer does not support a suitable code page, it can |     If the printer does not support a suitable code page, it can | ||||||
|     insert an error character. |     insert an error character. | ||||||
|     """ |     """ | ||||||
|     def __init__(self, driver, encoding=None, disabled=False, |  | ||||||
|                  defaultsymbol='?', encoder=None): |     def __init__( | ||||||
|  |         self, driver, encoding=None, disabled=False, defaultsymbol="?", encoder=None | ||||||
|  |     ): | ||||||
|         """ |         """ | ||||||
|  |  | ||||||
|         :param driver: |         :param driver: | ||||||
| @@ -219,7 +224,7 @@ class MagicEncode(object): | |||||||
|         :param encoder: |         :param encoder: | ||||||
|         """ |         """ | ||||||
|         if disabled and not encoding: |         if disabled and not encoding: | ||||||
|             raise Error('If you disable magic encode, you need to define an encoding!') |             raise Error("If you disable magic encode, you need to define an encoding!") | ||||||
|  |  | ||||||
|         self.driver = driver |         self.driver = driver | ||||||
|         self.encoder = encoder or Encoder(driver.profile.get_code_pages()) |         self.encoder = encoder or Encoder(driver.profile.get_code_pages()) | ||||||
| @@ -241,8 +246,7 @@ class MagicEncode(object): | |||||||
|             self.disabled = True |             self.disabled = True | ||||||
|  |  | ||||||
|     def write(self, text): |     def write(self, text): | ||||||
|         """Write the text, automatically switching encodings. |         """Write the text, automatically switching encodings.""" | ||||||
|         """ |  | ||||||
|  |  | ||||||
|         if self.disabled: |         if self.disabled: | ||||||
|             self.write_with_encoding(self.encoding, text) |             self.write_with_encoding(self.encoding, text) | ||||||
| @@ -268,25 +272,26 @@ class MagicEncode(object): | |||||||
|                 self.write_with_encoding(encoding, to_write) |                 self.write_with_encoding(encoding, to_write) | ||||||
|  |  | ||||||
|     def _handle_character_failed(self, char): |     def _handle_character_failed(self, char): | ||||||
|         """Called when no codepage was found to render a character. |         """Called when no codepage was found to render a character.""" | ||||||
|         """ |  | ||||||
|         # Writing the default symbol via write() allows us to avoid |         # Writing the default symbol via write() allows us to avoid | ||||||
|         # unnecesary codepage switches. |         # unnecesary codepage switches. | ||||||
|         self.write(self.defaultsymbol) |         self.write(self.defaultsymbol) | ||||||
|  |  | ||||||
|     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) | ||||||
|             )) |                 ) | ||||||
|  |             ) | ||||||
|  |  | ||||||
|         # We always know the current code page; if the new codepage |         # We always know the current code page; if the new codepage | ||||||
|         # is different, emit a change command. |         # is different, emit a change command. | ||||||
|         if encoding != self.encoding: |         if encoding != self.encoding: | ||||||
|             self.encoding = encoding |             self.encoding = encoding | ||||||
|             self.driver._raw( |             self.driver._raw( | ||||||
|                 CODEPAGE_CHANGE + |                 CODEPAGE_CHANGE + six.int2byte(self.encoder.get_sequence(encoding)) | ||||||
|                 six.int2byte(self.encoder.get_sequence(encoding))) |             ) | ||||||
|  |  | ||||||
|         if text: |         if text: | ||||||
|             self.driver._raw(self.encoder.encode(text, encoding)) |             self.driver._raw(self.encoder.encode(text, encoding)) | ||||||
|   | |||||||
| @@ -30,8 +30,17 @@ class Usb(Escpos): | |||||||
|  |  | ||||||
|     """ |     """ | ||||||
|  |  | ||||||
|     def __init__(self, idVendor, idProduct, usb_args=None, timeout=0, in_ep=0x82, out_ep=0x01, |     def __init__( | ||||||
|                  *args, **kwargs):  # noqa: N803 |         self, | ||||||
|  |         idVendor, | ||||||
|  |         idProduct, | ||||||
|  |         usb_args=None, | ||||||
|  |         timeout=0, | ||||||
|  |         in_ep=0x82, | ||||||
|  |         out_ep=0x01, | ||||||
|  |         *args, | ||||||
|  |         **kwargs | ||||||
|  |     ):  # noqa: N803 | ||||||
|         """ |         """ | ||||||
|         :param idVendor: Vendor ID |         :param idVendor: Vendor ID | ||||||
|         :param idProduct: Product ID |         :param idProduct: Product ID | ||||||
| @@ -47,9 +56,9 @@ class Usb(Escpos): | |||||||
|  |  | ||||||
|         usb_args = usb_args or {} |         usb_args = usb_args or {} | ||||||
|         if idVendor: |         if idVendor: | ||||||
|             usb_args['idVendor'] = idVendor |             usb_args["idVendor"] = idVendor | ||||||
|         if idProduct: |         if idProduct: | ||||||
|             usb_args['idProduct'] = idProduct |             usb_args["idProduct"] = idProduct | ||||||
|         self.open(usb_args) |         self.open(usb_args) | ||||||
|  |  | ||||||
|     def open(self, usb_args): |     def open(self, usb_args): | ||||||
| @@ -122,9 +131,19 @@ class Serial(Escpos): | |||||||
|  |  | ||||||
|     """ |     """ | ||||||
|  |  | ||||||
|     def __init__(self, devfile="/dev/ttyS0", baudrate=9600, bytesize=8, timeout=1, |     def __init__( | ||||||
|                  parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, |         self, | ||||||
|                  xonxoff=False, dsrdtr=True, *args, **kwargs): |         devfile="/dev/ttyS0", | ||||||
|  |         baudrate=9600, | ||||||
|  |         bytesize=8, | ||||||
|  |         timeout=1, | ||||||
|  |         parity=serial.PARITY_NONE, | ||||||
|  |         stopbits=serial.STOPBITS_ONE, | ||||||
|  |         xonxoff=False, | ||||||
|  |         dsrdtr=True, | ||||||
|  |         *args, | ||||||
|  |         **kwargs | ||||||
|  |     ): | ||||||
|         """ |         """ | ||||||
|  |  | ||||||
|         :param devfile:  Device file under dev filesystem |         :param devfile:  Device file under dev filesystem | ||||||
| @@ -152,10 +171,16 @@ class Serial(Escpos): | |||||||
|         """Setup serial port and set is as escpos device""" |         """Setup serial port and set is as escpos device""" | ||||||
|         if self.device is not None and self.device.is_open: |         if self.device is not None and self.device.is_open: | ||||||
|             self.close() |             self.close() | ||||||
|         self.device = serial.Serial(port=self.devfile, baudrate=self.baudrate, |         self.device = serial.Serial( | ||||||
|                                     bytesize=self.bytesize, parity=self.parity, |             port=self.devfile, | ||||||
|                                     stopbits=self.stopbits, timeout=self.timeout, |             baudrate=self.baudrate, | ||||||
|                                     xonxoff=self.xonxoff, dsrdtr=self.dsrdtr) |             bytesize=self.bytesize, | ||||||
|  |             parity=self.parity, | ||||||
|  |             stopbits=self.stopbits, | ||||||
|  |             timeout=self.timeout, | ||||||
|  |             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") | ||||||
| @@ -317,8 +342,7 @@ class Dummy(Escpos): | |||||||
|     """ |     """ | ||||||
|  |  | ||||||
|     def __init__(self, *args, **kwargs): |     def __init__(self, *args, **kwargs): | ||||||
|         """ |         """ """ | ||||||
|         """ |  | ||||||
|         Escpos.__init__(self, *args, **kwargs) |         Escpos.__init__(self, *args, **kwargs) | ||||||
|         self._output_list = [] |         self._output_list = [] | ||||||
|  |  | ||||||
| @@ -333,7 +357,7 @@ class Dummy(Escpos): | |||||||
|     @property |     @property | ||||||
|     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 clear(self): |     def clear(self): | ||||||
|         """Clear the buffer of the printer |         """Clear the buffer of the printer | ||||||
| @@ -356,6 +380,7 @@ except ImportError: | |||||||
|     pass |     pass | ||||||
|  |  | ||||||
| if _WIN32PRINT: | if _WIN32PRINT: | ||||||
|  |  | ||||||
|     class Win32Raw(Escpos): |     class Win32Raw(Escpos): | ||||||
|         def __init__(self, printer_name=None, *args, **kwargs): |         def __init__(self, printer_name=None, *args, **kwargs): | ||||||
|             Escpos.__init__(self, *args, **kwargs) |             Escpos.__init__(self, *args, **kwargs) | ||||||
| @@ -370,7 +395,9 @@ if _WIN32PRINT: | |||||||
|             if self.printer_name is None: |             if self.printer_name is None: | ||||||
|                 raise Exception("Printer not found") |                 raise Exception("Printer not found") | ||||||
|             self.hPrinter = win32print.OpenPrinter(self.printer_name) |             self.hPrinter = win32print.OpenPrinter(self.printer_name) | ||||||
|             self.current_job = win32print.StartDocPrinter(self.hPrinter, 1, (job_name, None, "RAW")) |             self.current_job = win32print.StartDocPrinter( | ||||||
|  |                 self.hPrinter, 1, (job_name, None, "RAW") | ||||||
|  |             ) | ||||||
|             win32print.StartPagePrinter(self.hPrinter) |             win32print.StartPagePrinter(self.hPrinter) | ||||||
|  |  | ||||||
|         def close(self): |         def close(self): | ||||||
|   | |||||||
| @@ -9,31 +9,30 @@ from scripttest import TestFileEnvironment | |||||||
| from nose.tools import assert_equal, nottest | from nose.tools import assert_equal, nottest | ||||||
| import escpos | import escpos | ||||||
|  |  | ||||||
| TEST_DIR = os.path.abspath('test/test-cli-output') | TEST_DIR = os.path.abspath("test/test-cli-output") | ||||||
|  |  | ||||||
| DEVFILE_NAME = 'testfile' | DEVFILE_NAME = "testfile" | ||||||
|  |  | ||||||
| DEVFILE = os.path.join(TEST_DIR, DEVFILE_NAME) | DEVFILE = os.path.join(TEST_DIR, DEVFILE_NAME) | ||||||
| CONFIGFILE = 'testconfig.yaml' | CONFIGFILE = "testconfig.yaml" | ||||||
| CONFIG_YAML = ''' | CONFIG_YAML = """ | ||||||
| --- | --- | ||||||
|  |  | ||||||
| printer: | printer: | ||||||
|     type: file |     type: file | ||||||
|     devfile: {testfile} |     devfile: {testfile} | ||||||
| '''.format( | """.format( | ||||||
|     testfile=DEVFILE, |     testfile=DEVFILE, | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  |  | ||||||
| class TestCLI: | class TestCLI: | ||||||
|     """ Contains setups, teardowns, and tests for CLI |     """Contains setups, teardowns, and tests for CLI""" | ||||||
|     """ |  | ||||||
|  |  | ||||||
|     @classmethod |     @classmethod | ||||||
|     def setup_class(cls): |     def setup_class(cls): | ||||||
|         """Create a config file to read from""" |         """Create a config file to read from""" | ||||||
|         with open(CONFIGFILE, 'w') as config: |         with open(CONFIGFILE, "w") as config: | ||||||
|             config.write(CONFIG_YAML) |             config.write(CONFIG_YAML) | ||||||
|  |  | ||||||
|     @classmethod |     @classmethod | ||||||
| @@ -52,12 +51,12 @@ class TestCLI: | |||||||
|         ) |         ) | ||||||
|  |  | ||||||
|         self.default_args = ( |         self.default_args = ( | ||||||
|             'python-escpos', |             "python-escpos", | ||||||
|             '-c', |             "-c", | ||||||
|             CONFIGFILE, |             CONFIGFILE, | ||||||
|         ) |         ) | ||||||
|  |  | ||||||
|         fhandle = open(DEVFILE, 'a') |         fhandle = open(DEVFILE, "a") | ||||||
|         try: |         try: | ||||||
|             os.utime(DEVFILE, None) |             os.utime(DEVFILE, None) | ||||||
|         finally: |         finally: | ||||||
| @@ -70,45 +69,41 @@ class TestCLI: | |||||||
|  |  | ||||||
|     def test_cli_help(self): |     def test_cli_help(self): | ||||||
|         """Test getting help from cli""" |         """Test getting help from cli""" | ||||||
|         result = self.env.run('python-escpos', '-h') |         result = self.env.run("python-escpos", "-h") | ||||||
|         assert not result.stderr |         assert not result.stderr | ||||||
|         assert 'usage' in result.stdout |         assert "usage" in result.stdout | ||||||
|  |  | ||||||
|     def test_cli_version(self): |     def test_cli_version(self): | ||||||
|         """Test the version string""" |         """Test the version string""" | ||||||
|         result = self.env.run('python-escpos', 'version') |         result = self.env.run("python-escpos", "version") | ||||||
|         assert not result.stderr |         assert not result.stderr | ||||||
|         assert_equal(escpos.__version__, result.stdout.strip()) |         assert_equal(escpos.__version__, result.stdout.strip()) | ||||||
|  |  | ||||||
|     @nottest  # disable this test as it is not that easy anymore to predict the outcome of this call |     @nottest  # disable this test as it is not that easy anymore to predict the outcome of this call | ||||||
|     def test_cli_text(self): |     def test_cli_text(self): | ||||||
|         """Make sure text returns what we sent it""" |         """Make sure text returns what we sent it""" | ||||||
|         test_text = 'this is some text' |         test_text = "this is some text" | ||||||
|         result = self.env.run( |         result = self.env.run( | ||||||
|             *(self.default_args + ( |             *( | ||||||
|                 'text', |                 self.default_args | ||||||
|                 '--txt', |                 + ( | ||||||
|  |                     "text", | ||||||
|  |                     "--txt", | ||||||
|                     test_text, |                     test_text, | ||||||
|             )) |                 ) | ||||||
|  |             ) | ||||||
|         ) |         ) | ||||||
|         assert not result.stderr |         assert not result.stderr | ||||||
|         assert DEVFILE_NAME in result.files_updated.keys() |         assert DEVFILE_NAME in result.files_updated.keys() | ||||||
|         assert_equals( |         assert_equals(result.files_updated[DEVFILE_NAME].bytes, test_text + "\n") | ||||||
|             result.files_updated[DEVFILE_NAME].bytes, |  | ||||||
|             test_text + '\n' |  | ||||||
|         ) |  | ||||||
|  |  | ||||||
|     def test_cli_text_inavlid_args(self): |     def test_cli_text_inavlid_args(self): | ||||||
|         """Test a failure to send valid arguments""" |         """Test a failure to send valid arguments""" | ||||||
|         result = self.env.run( |         result = self.env.run( | ||||||
|             *(self.default_args + ( |             *(self.default_args + ("text", "--invalid-param", "some data")), | ||||||
|                 'text', |  | ||||||
|                 '--invalid-param', |  | ||||||
|                 'some data' |  | ||||||
|             )), |  | ||||||
|             expect_error=True, |             expect_error=True, | ||||||
|             expect_stderr=True |             expect_stderr=True | ||||||
|         ) |         ) | ||||||
|         assert_equal(result.returncode, 2) |         assert_equal(result.returncode, 2) | ||||||
|         assert 'error:' in result.stderr |         assert "error:" in result.stderr | ||||||
|         assert not result.files_updated |         assert not result.files_updated | ||||||
|   | |||||||
| @@ -6,42 +6,51 @@ from escpos.exceptions import BarcodeTypeError, BarcodeCodeError | |||||||
| import pytest | import pytest | ||||||
|  |  | ||||||
|  |  | ||||||
| @pytest.mark.parametrize("bctype,data,expected", [ | @pytest.mark.parametrize( | ||||||
|     ('EAN13', '4006381333931', |     "bctype,data,expected", | ||||||
|         b'\x1ba\x01\x1dh@\x1dw\x03\x1df\x00\x1dH\x02\x1dk\x024006381333931\x00') |     [ | ||||||
| ]) |         ( | ||||||
|  |             "EAN13", | ||||||
|  |             "4006381333931", | ||||||
|  |             b"\x1ba\x01\x1dh@\x1dw\x03\x1df\x00\x1dH\x02\x1dk\x024006381333931\x00", | ||||||
|  |         ) | ||||||
|  |     ], | ||||||
|  | ) | ||||||
| def test_barcode(bctype, data, expected): | def test_barcode(bctype, data, expected): | ||||||
|     """should generate different barcode types correctly. |     """should generate different barcode types correctly.""" | ||||||
|     """ |  | ||||||
|     instance = printer.Dummy() |     instance = printer.Dummy() | ||||||
|     instance.barcode(data, bctype) |     instance.barcode(data, bctype) | ||||||
|     assert instance.output == expected |     assert instance.output == expected | ||||||
|  |  | ||||||
|  |  | ||||||
| @pytest.mark.parametrize("bctype,supports_b", [ | @pytest.mark.parametrize( | ||||||
|     ('invalid', True), |     "bctype,supports_b", | ||||||
|     ('CODE128', False), |     [ | ||||||
| ]) |         ("invalid", True), | ||||||
|  |         ("CODE128", False), | ||||||
|  |     ], | ||||||
|  | ) | ||||||
| def test_lacks_support(bctype, supports_b): | def test_lacks_support(bctype, supports_b): | ||||||
|     """should raise an error if the barcode type is not supported. |     """should raise an error if the barcode type is not supported.""" | ||||||
|     """ |  | ||||||
|     profile = Profile(features={BARCODE_B: supports_b}) |     profile = Profile(features={BARCODE_B: supports_b}) | ||||||
|     instance = printer.Dummy(profile=profile) |     instance = printer.Dummy(profile=profile) | ||||||
|     with pytest.raises(BarcodeTypeError): |     with pytest.raises(BarcodeTypeError): | ||||||
|         instance.barcode('test', bctype) |         instance.barcode("test", bctype) | ||||||
|  |  | ||||||
|     assert instance.output == b'' |     assert instance.output == b"" | ||||||
|  |  | ||||||
|  |  | ||||||
| @pytest.mark.parametrize("bctype,data", [ | @pytest.mark.parametrize( | ||||||
|     ('EAN13', 'AA'), |     "bctype,data", | ||||||
|     ('CODE128', '{D2354AA'), |     [ | ||||||
| ]) |         ("EAN13", "AA"), | ||||||
|  |         ("CODE128", "{D2354AA"), | ||||||
|  |     ], | ||||||
|  | ) | ||||||
| def test_code_check(bctype, data): | def test_code_check(bctype, data): | ||||||
|     """should raise an error if the barcode code is invalid. |     """should raise an error if the barcode code is invalid.""" | ||||||
|     """ |  | ||||||
|     instance = printer.Dummy() |     instance = printer.Dummy() | ||||||
|     with pytest.raises(BarcodeCodeError): |     with pytest.raises(BarcodeCodeError): | ||||||
|         instance.barcode(data, bctype) |         instance.barcode(data, bctype) | ||||||
|  |  | ||||||
|     assert instance.output == b'' |     assert instance.output == b"" | ||||||
|   | |||||||
| @@ -6,10 +6,8 @@ import pytest | |||||||
|  |  | ||||||
|  |  | ||||||
| def test_raise_CashDrawerError(): | def test_raise_CashDrawerError(): | ||||||
|     """should raise an error if the sequence is invalid. |     """should raise an error if the sequence is invalid.""" | ||||||
|     """ |  | ||||||
|     instance = printer.Dummy() |     instance = printer.Dummy() | ||||||
|     with pytest.raises(CashDrawerError): |     with pytest.raises(CashDrawerError): | ||||||
|         # call with sequence that is too long |         # call with sequence that is too long | ||||||
|         instance.cashdraw([1, 1, 1, 1, 1, 1]) |         instance.cashdraw([1, 1, 1, 1, 1, 1]) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -6,95 +6,101 @@ import escpos.printer as printer | |||||||
| import pytest | import pytest | ||||||
|  |  | ||||||
|  |  | ||||||
| @pytest.mark.parametrize("bctype,data", [ | @pytest.mark.parametrize( | ||||||
|     ('UPC-A', '01234567890'), |     "bctype,data", | ||||||
|     ('UPC-A', '012345678905'), |     [ | ||||||
|     ('UPC-E', '01234567'), |         ("UPC-A", "01234567890"), | ||||||
|     ('UPC-E', '0123456'), |         ("UPC-A", "012345678905"), | ||||||
|     ('UPC-E', '012345678905'), |         ("UPC-E", "01234567"), | ||||||
|     ('EAN13', '0123456789012'), |         ("UPC-E", "0123456"), | ||||||
|     ('EAN13', '012345678901'), |         ("UPC-E", "012345678905"), | ||||||
|     ('EAN8', '01234567'), |         ("EAN13", "0123456789012"), | ||||||
|     ('EAN8', '0123456'), |         ("EAN13", "012345678901"), | ||||||
|     ('CODE39', 'ABC-1234'), |         ("EAN8", "01234567"), | ||||||
|     ('CODE39', 'ABC-1234-$$-+A'), |         ("EAN8", "0123456"), | ||||||
|     ('CODE39', '*WIKIPEDIA*'), |         ("CODE39", "ABC-1234"), | ||||||
|     ('ITF', '010203040506070809'), |         ("CODE39", "ABC-1234-$$-+A"), | ||||||
|     ('ITF', '11221133113344556677889900'), |         ("CODE39", "*WIKIPEDIA*"), | ||||||
|     ('CODABAR', 'A2030405060B'), |         ("ITF", "010203040506070809"), | ||||||
|     ('CODABAR', 'C11221133113344556677889900D'), |         ("ITF", "11221133113344556677889900"), | ||||||
|     ('CODABAR', 'D0D'), |         ("CODABAR", "A2030405060B"), | ||||||
|     ('NW7', 'A2030405060B'), |         ("CODABAR", "C11221133113344556677889900D"), | ||||||
|     ('NW7', 'C11221133113344556677889900D'), |         ("CODABAR", "D0D"), | ||||||
|     ('NW7', 'D0D'), |         ("NW7", "A2030405060B"), | ||||||
|     ('CODE93', 'A2030405060B'), |         ("NW7", "C11221133113344556677889900D"), | ||||||
|     ('CODE93', '+:$&23-7@$'), |         ("NW7", "D0D"), | ||||||
|     ('CODE93', 'D0D'), |         ("CODE93", "A2030405060B"), | ||||||
|     ('CODE128', '{A2030405060B'), |         ("CODE93", "+:$&23-7@$"), | ||||||
|     ('CODE128', '{C+:$&23-7@$'), |         ("CODE93", "D0D"), | ||||||
|     ('CODE128', '{B0D'), |         ("CODE128", "{A2030405060B"), | ||||||
|     ('GS1-128', '{A2030405060B'), |         ("CODE128", "{C+:$&23-7@$"), | ||||||
|     ('GS1-128', '{C+:$&23-7@$'), |         ("CODE128", "{B0D"), | ||||||
|     ('GS1-128', '{B0D'), |         ("GS1-128", "{A2030405060B"), | ||||||
|     ('GS1 DATABAR OMNIDIRECTIONAL', '0123456789123'), |         ("GS1-128", "{C+:$&23-7@$"), | ||||||
|     ('GS1 DATABAR TRUNCATED', '0123456789123'), |         ("GS1-128", "{B0D"), | ||||||
|     ('GS1 DATABAR LIMITED', '0123456789123'), |         ("GS1 DATABAR OMNIDIRECTIONAL", "0123456789123"), | ||||||
|     ('GS1 DATABAR EXPANDED', '(9A{A20304+-%&06a0B'), |         ("GS1 DATABAR TRUNCATED", "0123456789123"), | ||||||
|     ('GS1 DATABAR EXPANDED', '(1 {C+:&23-7%'), |         ("GS1 DATABAR LIMITED", "0123456789123"), | ||||||
|     ('GS1 DATABAR EXPANDED', '(00000001234567678'), |         ("GS1 DATABAR EXPANDED", "(9A{A20304+-%&06a0B"), | ||||||
| ]) |         ("GS1 DATABAR EXPANDED", "(1 {C+:&23-7%"), | ||||||
|  |         ("GS1 DATABAR EXPANDED", "(00000001234567678"), | ||||||
|  |     ], | ||||||
|  | ) | ||||||
| def test_check_valid_barcode(bctype, data): | def test_check_valid_barcode(bctype, data): | ||||||
|     assert (printer.Escpos.check_barcode(bctype, data)) |     assert printer.Escpos.check_barcode(bctype, data) | ||||||
|  |  | ||||||
|  |  | ||||||
| @pytest.mark.parametrize("bctype,data", [ | @pytest.mark.parametrize( | ||||||
|     ('UPC-A', '01234567890123'),  # too long |     "bctype,data", | ||||||
|     ('UPC-A', '0123456789'),  # too short |     [ | ||||||
|     ('UPC-A', '72527273-711'),  # invalid '-' |         ("UPC-A", "01234567890123"),  # too long | ||||||
|     ('UPC-A', 'A12345678901'),  # invalid 'A' |         ("UPC-A", "0123456789"),  # too short | ||||||
|     ('UPC-E', '01234567890123'),  # too long |         ("UPC-A", "72527273-711"),  # invalid '-' | ||||||
|     ('UPC-E', '012345'),  # too short |         ("UPC-A", "A12345678901"),  # invalid 'A' | ||||||
|     ('UPC-E', '72527-2'),  # invalid '-' |         ("UPC-E", "01234567890123"),  # too long | ||||||
|     ('UPC-E', 'A123456'),  # invalid 'A' |         ("UPC-E", "012345"),  # too short | ||||||
|     ('EAN13', '0123456789'),  # too short |         ("UPC-E", "72527-2"),  # invalid '-' | ||||||
|     ('EAN13', 'A123456789012'),  # invalid 'A' |         ("UPC-E", "A123456"),  # invalid 'A' | ||||||
|     ('EAN13', '012345678901234'),  # too long |         ("EAN13", "0123456789"),  # too short | ||||||
|     ('EAN8', '012345'),  # too short |         ("EAN13", "A123456789012"),  # invalid 'A' | ||||||
|     ('EAN8', 'A123456789012'),  # invalid 'A' |         ("EAN13", "012345678901234"),  # too long | ||||||
|     ('EAN8', '012345678901234'),  # too long |         ("EAN8", "012345"),  # too short | ||||||
|     ('CODE39', 'ALKJ_34'),  # invalid '_' |         ("EAN8", "A123456789012"),  # invalid 'A' | ||||||
|     ('CODE39', 'A' * 256),  # too long |         ("EAN8", "012345678901234"),  # too long | ||||||
|     ('ITF', '010203040'),  # odd length |         ("CODE39", "ALKJ_34"),  # invalid '_' | ||||||
|     ('ITF', '0' * 256),  # too long |         ("CODE39", "A" * 256),  # too long | ||||||
|     ('ITF', 'AB01'),  # invalid 'A' |         ("ITF", "010203040"),  # odd length | ||||||
|     ('CODABAR', '010203040'),  # no start/stop |         ("ITF", "0" * 256),  # too long | ||||||
|     ('CODABAR', '0' * 256),  # too long |         ("ITF", "AB01"),  # invalid 'A' | ||||||
|     ('CODABAR', 'AB-01F'),  # invalid 'B' |         ("CODABAR", "010203040"),  # no start/stop | ||||||
|     ('NW7', '010203040'),  # no start/stop |         ("CODABAR", "0" * 256),  # too long | ||||||
|     ('NW7', '0' * 256),  # too long |         ("CODABAR", "AB-01F"),  # invalid 'B' | ||||||
|     ('NW7', 'AB-01F'),  # invalid 'B' |         ("NW7", "010203040"),  # no start/stop | ||||||
|     ('CODE93', 'é010203040'),  # invalid 'é' |         ("NW7", "0" * 256),  # too long | ||||||
|     ('CODE93', '0' * 256),  # too long |         ("NW7", "AB-01F"),  # invalid 'B' | ||||||
|     ('CODE128', '010203040'),  # missing leading { |         ("CODE93", "é010203040"),  # invalid 'é' | ||||||
|     ('CODE128', '{D2354AA'),  # second char not between A-C |         ("CODE93", "0" * 256),  # too long | ||||||
|     ('CODE128', '0' * 256),  # too long |         ("CODE128", "010203040"),  # missing leading { | ||||||
|     ('GS1-128', '010203040'),  # missing leading { |         ("CODE128", "{D2354AA"),  # second char not between A-C | ||||||
|     ('GS1-128', '{D2354AA'),  # second char not between A-C |         ("CODE128", "0" * 256),  # too long | ||||||
|     ('GS1-128', '0' * 256),  # too long |         ("GS1-128", "010203040"),  # missing leading { | ||||||
|     ('GS1 DATABAR OMNIDIRECTIONAL', '01234567891234'),  # too long |         ("GS1-128", "{D2354AA"),  # second char not between A-C | ||||||
|     ('GS1 DATABAR OMNIDIRECTIONAL', '012345678912'),  # too short |         ("GS1-128", "0" * 256),  # too long | ||||||
|     ('GS1 DATABAR OMNIDIRECTIONAL', '012345678A1234'),  # invalid 'A' |         ("GS1 DATABAR OMNIDIRECTIONAL", "01234567891234"),  # too long | ||||||
|     ('GS1 DATABAR TRUNCATED', '01234567891234'),  # too long |         ("GS1 DATABAR OMNIDIRECTIONAL", "012345678912"),  # too short | ||||||
|     ('GS1 DATABAR TRUNCATED', '012345678912'),  # too short |         ("GS1 DATABAR OMNIDIRECTIONAL", "012345678A1234"),  # invalid 'A' | ||||||
|     ('GS1 DATABAR TRUNCATED', '012345678A1234'),  # invalid 'A' |         ("GS1 DATABAR TRUNCATED", "01234567891234"),  # too long | ||||||
|     ('GS1 DATABAR LIMITED', '01234567891234'),  # too long |         ("GS1 DATABAR TRUNCATED", "012345678912"),  # too short | ||||||
|     ('GS1 DATABAR LIMITED', '012345678912'),  # too short |         ("GS1 DATABAR TRUNCATED", "012345678A1234"),  # invalid 'A' | ||||||
|     ('GS1 DATABAR LIMITED', '012345678A1234'),  # invalid 'A' |         ("GS1 DATABAR LIMITED", "01234567891234"),  # too long | ||||||
|     ('GS1 DATABAR LIMITED', '02345678912341'),  # invalid start (should be 01) |         ("GS1 DATABAR LIMITED", "012345678912"),  # too short | ||||||
|     ('GS1 DATABAR EXPANDED', '010203040'),  # missing leading ( |         ("GS1 DATABAR LIMITED", "012345678A1234"),  # invalid 'A' | ||||||
|     ('GS1-128', '(' + ('0' * 256)),  # too long |         ("GS1 DATABAR LIMITED", "02345678912341"),  # invalid start (should be 01) | ||||||
|     ('GS1 DATABAR EXPANDED', '(a{D2354AA'),  # second char not between 0-9 |         ("GS1 DATABAR EXPANDED", "010203040"),  # missing leading ( | ||||||
|     ('GS1 DATABAR EXPANDED', 'IT will fail'),  # first char not '(' |         ("GS1-128", "(" + ("0" * 256)),  # too long | ||||||
| ]) |         ("GS1 DATABAR EXPANDED", "(a{D2354AA"),  # second char not between 0-9 | ||||||
|  |         ("GS1 DATABAR EXPANDED", "IT will fail"),  # first char not '(' | ||||||
|  |     ], | ||||||
|  | ) | ||||||
| def test_check_invalid_barcode(bctype, data): | def test_check_invalid_barcode(bctype, data): | ||||||
|     assert (not printer.Escpos.check_barcode(bctype, data)) |     assert not printer.Escpos.check_barcode(bctype, data) | ||||||
|   | |||||||
| @@ -1,4 +1,3 @@ | |||||||
|  |  | ||||||
| import six | import six | ||||||
|  |  | ||||||
| import escpos.printer as printer | import escpos.printer as printer | ||||||
| @@ -9,5 +8,5 @@ def test_cut_without_feed(): | |||||||
|     """Test cut without feeding paper""" |     """Test cut without feeding paper""" | ||||||
|     instance = printer.Dummy() |     instance = printer.Dummy() | ||||||
|     instance.cut(feed=False) |     instance.cut(feed=False) | ||||||
|     expected = GS + b'V' + six.int2byte(66) + b'\x00' |     expected = GS + b"V" + six.int2byte(66) + b"\x00" | ||||||
|     assert(instance.output == expected) |     assert instance.output == expected | ||||||
|   | |||||||
| @@ -1,8 +1,9 @@ | |||||||
| from nose.tools import assert_raises | from nose.tools import assert_raises | ||||||
| from escpos.printer import Dummy | from escpos.printer import Dummy | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_printer_dummy_clear(): | def test_printer_dummy_clear(): | ||||||
|     printer = Dummy() |     printer = Dummy() | ||||||
|     printer.text("Hello") |     printer.text("Hello") | ||||||
|     printer.clear() |     printer.clear() | ||||||
|     assert(printer.output == b'') |     assert printer.output == b"" | ||||||
|   | |||||||
| @@ -22,13 +22,13 @@ def test_bit_image_black(): | |||||||
|     Test printing solid black bit image (raster) |     Test printing solid black bit image (raster) | ||||||
|     """ |     """ | ||||||
|     instance = printer.Dummy() |     instance = printer.Dummy() | ||||||
|     instance.image('test/resources/canvas_black.png', impl="bitImageRaster") |     instance.image("test/resources/canvas_black.png", impl="bitImageRaster") | ||||||
|     assert(instance.output == b'\x1dv0\x00\x01\x00\x01\x00\x80') |     assert instance.output == b"\x1dv0\x00\x01\x00\x01\x00\x80" | ||||||
|     # Same thing w/ object created on the fly, rather than a filename |     # Same thing w/ object created on the fly, rather than a filename | ||||||
|     instance = printer.Dummy() |     instance = printer.Dummy() | ||||||
|     im = Image.new("RGB", (1, 1), (0, 0, 0)) |     im = Image.new("RGB", (1, 1), (0, 0, 0)) | ||||||
|     instance.image(im, impl="bitImageRaster") |     instance.image(im, impl="bitImageRaster") | ||||||
|     assert(instance.output == b'\x1dv0\x00\x01\x00\x01\x00\x80') |     assert instance.output == b"\x1dv0\x00\x01\x00\x01\x00\x80" | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_bit_image_white(): | def test_bit_image_white(): | ||||||
| @@ -36,8 +36,8 @@ def test_bit_image_white(): | |||||||
|     Test printing solid white bit image (raster) |     Test printing solid white bit image (raster) | ||||||
|     """ |     """ | ||||||
|     instance = printer.Dummy() |     instance = printer.Dummy() | ||||||
|     instance.image('test/resources/canvas_white.png', impl="bitImageRaster") |     instance.image("test/resources/canvas_white.png", impl="bitImageRaster") | ||||||
|     assert(instance.output == b'\x1dv0\x00\x01\x00\x01\x00\x00') |     assert instance.output == b"\x1dv0\x00\x01\x00\x01\x00\x00" | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_bit_image_both(): | def test_bit_image_both(): | ||||||
| @@ -45,8 +45,8 @@ def test_bit_image_both(): | |||||||
|     Test printing black/white bit image (raster) |     Test printing black/white bit image (raster) | ||||||
|     """ |     """ | ||||||
|     instance = printer.Dummy() |     instance = printer.Dummy() | ||||||
|     instance.image('test/resources/black_white.png', impl="bitImageRaster") |     instance.image("test/resources/black_white.png", impl="bitImageRaster") | ||||||
|     assert(instance.output == b'\x1dv0\x00\x01\x00\x02\x00\xc0\x00') |     assert instance.output == b"\x1dv0\x00\x01\x00\x02\x00\xc0\x00" | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_bit_image_transparent(): | def test_bit_image_transparent(): | ||||||
| @@ -54,8 +54,8 @@ def test_bit_image_transparent(): | |||||||
|     Test printing black/transparent bit image (raster) |     Test printing black/transparent bit image (raster) | ||||||
|     """ |     """ | ||||||
|     instance = printer.Dummy() |     instance = printer.Dummy() | ||||||
|     instance.image('test/resources/black_transparent.png', impl="bitImageRaster") |     instance.image("test/resources/black_transparent.png", impl="bitImageRaster") | ||||||
|     assert(instance.output == b'\x1dv0\x00\x01\x00\x02\x00\xc0\x00') |     assert instance.output == b"\x1dv0\x00\x01\x00\x02\x00\xc0\x00" | ||||||
|  |  | ||||||
|  |  | ||||||
| # Column format print | # Column format print | ||||||
| @@ -64,8 +64,8 @@ def test_bit_image_colfmt_black(): | |||||||
|     Test printing solid black bit image (column format) |     Test printing solid black bit image (column format) | ||||||
|     """ |     """ | ||||||
|     instance = printer.Dummy() |     instance = printer.Dummy() | ||||||
|     instance.image('test/resources/canvas_black.png', impl="bitImageColumn") |     instance.image("test/resources/canvas_black.png", impl="bitImageColumn") | ||||||
|     assert(instance.output == b'\x1b3\x10\x1b*!\x01\x00\x80\x00\x00\x0a\x1b2') |     assert instance.output == b"\x1b3\x10\x1b*!\x01\x00\x80\x00\x00\x0a\x1b2" | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_bit_image_colfmt_white(): | def test_bit_image_colfmt_white(): | ||||||
| @@ -73,8 +73,8 @@ def test_bit_image_colfmt_white(): | |||||||
|     Test printing solid white bit image (column format) |     Test printing solid white bit image (column format) | ||||||
|     """ |     """ | ||||||
|     instance = printer.Dummy() |     instance = printer.Dummy() | ||||||
|     instance.image('test/resources/canvas_white.png', impl="bitImageColumn") |     instance.image("test/resources/canvas_white.png", impl="bitImageColumn") | ||||||
|     assert(instance.output == b'\x1b3\x10\x1b*!\x01\x00\x00\x00\x00\x0a\x1b2') |     assert instance.output == b"\x1b3\x10\x1b*!\x01\x00\x00\x00\x00\x0a\x1b2" | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_bit_image_colfmt_both(): | def test_bit_image_colfmt_both(): | ||||||
| @@ -82,8 +82,10 @@ def test_bit_image_colfmt_both(): | |||||||
|     Test printing black/white bit image (column format) |     Test printing black/white bit image (column format) | ||||||
|     """ |     """ | ||||||
|     instance = printer.Dummy() |     instance = printer.Dummy() | ||||||
|     instance.image('test/resources/black_white.png', impl="bitImageColumn") |     instance.image("test/resources/black_white.png", impl="bitImageColumn") | ||||||
|     assert(instance.output == b'\x1b3\x10\x1b*!\x02\x00\x80\x00\x00\x80\x00\x00\x0a\x1b2') |     assert ( | ||||||
|  |         instance.output == b"\x1b3\x10\x1b*!\x02\x00\x80\x00\x00\x80\x00\x00\x0a\x1b2" | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_bit_image_colfmt_transparent(): | def test_bit_image_colfmt_transparent(): | ||||||
| @@ -91,8 +93,10 @@ def test_bit_image_colfmt_transparent(): | |||||||
|     Test printing black/transparent bit image (column format) |     Test printing black/transparent bit image (column format) | ||||||
|     """ |     """ | ||||||
|     instance = printer.Dummy() |     instance = printer.Dummy() | ||||||
|     instance.image('test/resources/black_transparent.png', impl="bitImageColumn") |     instance.image("test/resources/black_transparent.png", impl="bitImageColumn") | ||||||
|     assert(instance.output == b'\x1b3\x10\x1b*!\x02\x00\x80\x00\x00\x80\x00\x00\x0a\x1b2') |     assert ( | ||||||
|  |         instance.output == b"\x1b3\x10\x1b*!\x02\x00\x80\x00\x00\x80\x00\x00\x0a\x1b2" | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |  | ||||||
| # Graphics print | # Graphics print | ||||||
| @@ -101,8 +105,11 @@ def test_graphics_black(): | |||||||
|     Test printing solid black graphics |     Test printing solid black graphics | ||||||
|     """ |     """ | ||||||
|     instance = printer.Dummy() |     instance = printer.Dummy() | ||||||
|     instance.image('test/resources/canvas_black.png', impl="graphics") |     instance.image("test/resources/canvas_black.png", impl="graphics") | ||||||
|     assert(instance.output == b'\x1d(L\x0b\x000p0\x01\x011\x01\x00\x01\x00\x80\x1d(L\x02\x0002') |     assert ( | ||||||
|  |         instance.output | ||||||
|  |         == b"\x1d(L\x0b\x000p0\x01\x011\x01\x00\x01\x00\x80\x1d(L\x02\x0002" | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_graphics_white(): | def test_graphics_white(): | ||||||
| @@ -110,8 +117,11 @@ def test_graphics_white(): | |||||||
|     Test printing solid white graphics |     Test printing solid white graphics | ||||||
|     """ |     """ | ||||||
|     instance = printer.Dummy() |     instance = printer.Dummy() | ||||||
|     instance.image('test/resources/canvas_white.png', impl="graphics") |     instance.image("test/resources/canvas_white.png", impl="graphics") | ||||||
|     assert(instance.output == b'\x1d(L\x0b\x000p0\x01\x011\x01\x00\x01\x00\x00\x1d(L\x02\x0002') |     assert ( | ||||||
|  |         instance.output | ||||||
|  |         == b"\x1d(L\x0b\x000p0\x01\x011\x01\x00\x01\x00\x00\x1d(L\x02\x0002" | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_graphics_both(): | def test_graphics_both(): | ||||||
| @@ -119,8 +129,11 @@ def test_graphics_both(): | |||||||
|     Test printing black/white graphics |     Test printing black/white graphics | ||||||
|     """ |     """ | ||||||
|     instance = printer.Dummy() |     instance = printer.Dummy() | ||||||
|     instance.image('test/resources/black_white.png', impl="graphics") |     instance.image("test/resources/black_white.png", impl="graphics") | ||||||
|     assert(instance.output == b'\x1d(L\x0c\x000p0\x01\x011\x02\x00\x02\x00\xc0\x00\x1d(L\x02\x0002') |     assert ( | ||||||
|  |         instance.output | ||||||
|  |         == b"\x1d(L\x0c\x000p0\x01\x011\x02\x00\x02\x00\xc0\x00\x1d(L\x02\x0002" | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_graphics_transparent(): | def test_graphics_transparent(): | ||||||
| @@ -128,8 +141,11 @@ def test_graphics_transparent(): | |||||||
|     Test printing black/transparent graphics |     Test printing black/transparent graphics | ||||||
|     """ |     """ | ||||||
|     instance = printer.Dummy() |     instance = printer.Dummy() | ||||||
|     instance.image('test/resources/black_transparent.png', impl="graphics") |     instance.image("test/resources/black_transparent.png", impl="graphics") | ||||||
|     assert(instance.output == b'\x1d(L\x0c\x000p0\x01\x011\x02\x00\x02\x00\xc0\x00\x1d(L\x02\x0002') |     assert ( | ||||||
|  |         instance.output | ||||||
|  |         == b"\x1d(L\x0c\x000p0\x01\x011\x02\x00\x02\x00\xc0\x00\x1d(L\x02\x0002" | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_large_graphics(): | def test_large_graphics(): | ||||||
| @@ -137,20 +153,19 @@ def test_large_graphics(): | |||||||
|     Test whether 'large' graphics that induce a fragmentation are handled correctly. |     Test whether 'large' graphics that induce a fragmentation are handled correctly. | ||||||
|     """ |     """ | ||||||
|     instance = printer.Dummy() |     instance = printer.Dummy() | ||||||
|     instance.image('test/resources/black_white.png', impl="bitImageRaster", fragment_height=1) |     instance.image( | ||||||
|     assert(instance.output == b'\x1dv0\x00\x01\x00\x01\x00\xc0\x1dv0\x00\x01\x00\x01\x00\x00') |         "test/resources/black_white.png", impl="bitImageRaster", fragment_height=1 | ||||||
|  |     ) | ||||||
|  |     assert ( | ||||||
|  |         instance.output | ||||||
|  |         == b"\x1dv0\x00\x01\x00\x01\x00\xc0\x1dv0\x00\x01\x00\x01\x00\x00" | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |  | ||||||
| @pytest.fixture | @pytest.fixture | ||||||
| def dummy_with_width(): | def dummy_with_width(): | ||||||
|     instance = printer.Dummy() |     instance = printer.Dummy() | ||||||
|     instance.profile.profile_data = { |     instance.profile.profile_data = {"media": {"width": {"pixels": 384}}} | ||||||
|         'media': { |  | ||||||
|             'width': { |  | ||||||
|                 'pixels': 384 |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     return instance |     return instance | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -15,17 +15,18 @@ def test_function_linedisplay_select_on(): | |||||||
|     """test the linedisplay_select function (activate)""" |     """test the linedisplay_select function (activate)""" | ||||||
|     instance = printer.Dummy() |     instance = printer.Dummy() | ||||||
|     instance.linedisplay_select(select_display=True) |     instance.linedisplay_select(select_display=True) | ||||||
|     assert(instance.output == b'\x1B\x3D\x02') |     assert instance.output == b"\x1B\x3D\x02" | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_function_linedisplay_select_off(): | def test_function_linedisplay_select_off(): | ||||||
|     """test the linedisplay_select function (deactivate)""" |     """test the linedisplay_select function (deactivate)""" | ||||||
|     instance = printer.Dummy() |     instance = printer.Dummy() | ||||||
|     instance.linedisplay_select(select_display=False) |     instance.linedisplay_select(select_display=False) | ||||||
|     assert(instance.output == b'\x1B\x3D\x01') |     assert instance.output == b"\x1B\x3D\x01" | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_function_linedisplay_clear(): | def test_function_linedisplay_clear(): | ||||||
|     """test the linedisplay_clear function""" |     """test the linedisplay_clear function""" | ||||||
|     instance = printer.Dummy() |     instance = printer.Dummy() | ||||||
|     instance.linedisplay_clear() |     instance.linedisplay_clear() | ||||||
|     assert(instance.output == b'\x1B\x40') |     assert instance.output == b"\x1B\x40" | ||||||
|  |  | ||||||
|   | |||||||
| @@ -15,11 +15,11 @@ def test_function_panel_button_on(): | |||||||
|     """test the panel button function (enabling) by comparing output""" |     """test the panel button function (enabling) by comparing output""" | ||||||
|     instance = printer.Dummy() |     instance = printer.Dummy() | ||||||
|     instance.panel_buttons() |     instance.panel_buttons() | ||||||
|     assert(instance.output == b'\x1B\x63\x35\x00') |     assert instance.output == b"\x1B\x63\x35\x00" | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_function_panel_button_off(): | def test_function_panel_button_off(): | ||||||
|     """test the panel button function (disabling) by comparing output""" |     """test the panel button function (disabling) by comparing output""" | ||||||
|     instance = printer.Dummy() |     instance = printer.Dummy() | ||||||
|     instance.panel_buttons(False) |     instance.panel_buttons(False) | ||||||
|     assert(instance.output == b'\x1B\x63\x35\x01') |     assert instance.output == b"\x1B\x63\x35\x01" | ||||||
|   | |||||||
| @@ -19,42 +19,51 @@ def test_defaults(): | |||||||
|     """Test QR code with defaults""" |     """Test QR code with defaults""" | ||||||
|     instance = printer.Dummy() |     instance = printer.Dummy() | ||||||
|     instance.qr("1234", native=True) |     instance.qr("1234", native=True) | ||||||
|     expected = b'\x1d(k\x04\x001A2\x00\x1d(k\x03\x001C\x03\x1d(k\x03\x001E0\x1d' \ |     expected = ( | ||||||
|         b'(k\x07\x001P01234\x1d(k\x03\x001Q0' |         b"\x1d(k\x04\x001A2\x00\x1d(k\x03\x001C\x03\x1d(k\x03\x001E0\x1d" | ||||||
|     assert(instance.output == expected) |         b"(k\x07\x001P01234\x1d(k\x03\x001Q0" | ||||||
|  |     ) | ||||||
|  |     assert instance.output == expected | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_empty(): | def test_empty(): | ||||||
|     """Test QR printing blank code""" |     """Test QR printing blank code""" | ||||||
|     instance = printer.Dummy() |     instance = printer.Dummy() | ||||||
|     instance.qr("", native=True) |     instance.qr("", native=True) | ||||||
|     assert(instance.output == b'') |     assert instance.output == b"" | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_ec(): | def test_ec(): | ||||||
|     """Test QR error correction setting""" |     """Test QR error correction setting""" | ||||||
|     instance = printer.Dummy() |     instance = printer.Dummy() | ||||||
|     instance.qr("1234", native=True, ec=QR_ECLEVEL_H) |     instance.qr("1234", native=True, ec=QR_ECLEVEL_H) | ||||||
|     expected = b'\x1d(k\x04\x001A2\x00\x1d(k\x03\x001C\x03\x1d(k\x03\x001E3\x1d' \ |     expected = ( | ||||||
|         b'(k\x07\x001P01234\x1d(k\x03\x001Q0' |         b"\x1d(k\x04\x001A2\x00\x1d(k\x03\x001C\x03\x1d(k\x03\x001E3\x1d" | ||||||
|     assert(instance.output == expected) |         b"(k\x07\x001P01234\x1d(k\x03\x001Q0" | ||||||
|  |     ) | ||||||
|  |     assert instance.output == expected | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_size(): | def test_size(): | ||||||
|     """Test QR box size""" |     """Test QR box size""" | ||||||
|     instance = printer.Dummy() |     instance = printer.Dummy() | ||||||
|     instance.qr("1234", native=True, size=7) |     instance.qr("1234", native=True, size=7) | ||||||
|     expected = b'\x1d(k\x04\x001A2\x00\x1d(k\x03\x001C\x07\x1d(k\x03\x001E0\x1d' \ |     expected = ( | ||||||
|         b'(k\x07\x001P01234\x1d(k\x03\x001Q0' |         b"\x1d(k\x04\x001A2\x00\x1d(k\x03\x001C\x07\x1d(k\x03\x001E0\x1d" | ||||||
|     assert(instance.output == expected) |         b"(k\x07\x001P01234\x1d(k\x03\x001Q0" | ||||||
|  |     ) | ||||||
|  |     assert instance.output == expected | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_model(): | def test_model(): | ||||||
|     """Test QR model""" |     """Test QR model""" | ||||||
|     instance = printer.Dummy() |     instance = printer.Dummy() | ||||||
|     instance.qr("1234", native=True, model=QR_MODEL_1) |     instance.qr("1234", native=True, model=QR_MODEL_1) | ||||||
|     expected = b'\x1d(k\x04\x001A1\x00\x1d(k\x03\x001C\x03\x1d(k\x03\x001E0\x1d' \ |     expected = ( | ||||||
|         b'(k\x07\x001P01234\x1d(k\x03\x001Q0' |         b"\x1d(k\x04\x001A1\x00\x1d(k\x03\x001C\x03\x1d(k\x03\x001E0\x1d" | ||||||
|     assert(instance.output == expected) |         b"(k\x07\x001P01234\x1d(k\x03\x001Q0" | ||||||
|  |     ) | ||||||
|  |     assert instance.output == expected | ||||||
|  |  | ||||||
|  |  | ||||||
| @raises(ValueError) | @raises(ValueError) | ||||||
| @@ -84,12 +93,14 @@ def test_image(): | |||||||
|     instance = printer.Dummy() |     instance = printer.Dummy() | ||||||
|     instance.qr("1", native=False, size=1) |     instance.qr("1", native=False, size=1) | ||||||
|     print(instance.output) |     print(instance.output) | ||||||
|     expected = b'\x1bt\x00\n' \ |     expected = ( | ||||||
|         b'\x1dv0\x00\x03\x00\x17\x00\x00\x00\x00\x7f]\xfcA\x19\x04]it]et' \ |         b"\x1bt\x00\n" | ||||||
|         b']ItA=\x04\x7fU\xfc\x00\x0c\x00y~t4\x7f =\xa84j\xd9\xf0\x05\xd4\x90\x00' \ |         b"\x1dv0\x00\x03\x00\x17\x00\x00\x00\x00\x7f]\xfcA\x19\x04]it]et" | ||||||
|         b'i(\x7f<\xa8A \xd8]\'\xc4]y\xf8]E\x80Ar\x94\x7fR@\x00\x00\x00' \ |         b"]ItA=\x04\x7fU\xfc\x00\x0c\x00y~t4\x7f =\xa84j\xd9\xf0\x05\xd4\x90\x00" | ||||||
|         b'\n\n' |         b"i(\x7f<\xa8A \xd8]'\xc4]y\xf8]E\x80Ar\x94\x7fR@\x00\x00\x00" | ||||||
|     assert(instance.output == expected) |         b"\n\n" | ||||||
|  |     ) | ||||||
|  |     assert instance.output == expected | ||||||
|  |  | ||||||
|  |  | ||||||
| @raises(ValueError) | @raises(ValueError) | ||||||
|   | |||||||
| @@ -16,7 +16,7 @@ from escpos.printer import Dummy | |||||||
| from PIL import Image | from PIL import Image | ||||||
|  |  | ||||||
|  |  | ||||||
| @mock.patch('escpos.printer.Dummy.image', spec=Dummy) | @mock.patch("escpos.printer.Dummy.image", spec=Dummy) | ||||||
| def test_type_of_object_passed_to_image_function(img_function): | def test_type_of_object_passed_to_image_function(img_function): | ||||||
|     """ |     """ | ||||||
|     Test the type of object that is passed to the image function during non-native qr-printing. |     Test the type of object that is passed to the image function during non-native qr-printing. | ||||||
|   | |||||||
| @@ -1,4 +1,3 @@ | |||||||
|  |  | ||||||
| import six | import six | ||||||
|  |  | ||||||
| import escpos.printer as printer | import escpos.printer as printer | ||||||
| @@ -8,41 +7,46 @@ from escpos.constants import TXT_SIZE | |||||||
|  |  | ||||||
| # Default test, please copy and paste this block to test set method calls | # Default test, please copy and paste this block to test set method calls | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_default_values(): | def test_default_values(): | ||||||
|     instance = printer.Dummy() |     instance = printer.Dummy() | ||||||
|     instance.set() |     instance.set() | ||||||
|  |  | ||||||
|     expected_sequence = ( |     expected_sequence = ( | ||||||
|         TXT_NORMAL, TXT_STYLE['size']['normal'],  # Normal text size |         TXT_NORMAL, | ||||||
|         TXT_STYLE['flip'][False],  # Flip OFF |         TXT_STYLE["size"]["normal"],  # Normal text size | ||||||
|         TXT_STYLE['smooth'][False],  # Smooth OFF |         TXT_STYLE["flip"][False],  # Flip OFF | ||||||
|         TXT_STYLE['bold'][False],  # Bold OFF |         TXT_STYLE["smooth"][False],  # Smooth OFF | ||||||
|         TXT_STYLE['underline'][0],  # Underline OFF |         TXT_STYLE["bold"][False],  # Bold OFF | ||||||
|         SET_FONT(b'\x00'),  # Default font |         TXT_STYLE["underline"][0],  # Underline OFF | ||||||
|         TXT_STYLE['align']['left'],  # Align left |         SET_FONT(b"\x00"),  # Default font | ||||||
|         TXT_STYLE['invert'][False]  # Inverted OFF |         TXT_STYLE["align"]["left"],  # Align left | ||||||
|  |         TXT_STYLE["invert"][False],  # Inverted OFF | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|     assert(instance.output == b''.join(expected_sequence)) |     assert instance.output == b"".join(expected_sequence) | ||||||
|  |  | ||||||
|  |  | ||||||
| # Size tests | # Size tests | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_set_size_2h(): | def test_set_size_2h(): | ||||||
|     instance = printer.Dummy() |     instance = printer.Dummy() | ||||||
|     instance.set(double_height=True) |     instance.set(double_height=True) | ||||||
|  |  | ||||||
|     expected_sequence = ( |     expected_sequence = ( | ||||||
|         TXT_NORMAL, TXT_STYLE['size']['2h'],  # Double height text size |         TXT_NORMAL, | ||||||
|         TXT_STYLE['flip'][False],  # Flip OFF |         TXT_STYLE["size"]["2h"],  # Double height text size | ||||||
|         TXT_STYLE['smooth'][False],  # Smooth OFF |         TXT_STYLE["flip"][False],  # Flip OFF | ||||||
|         TXT_STYLE['bold'][False],  # Bold OFF |         TXT_STYLE["smooth"][False],  # Smooth OFF | ||||||
|         TXT_STYLE['underline'][0],  # Underline OFF |         TXT_STYLE["bold"][False],  # Bold OFF | ||||||
|         SET_FONT(b'\x00'),  # Default font |         TXT_STYLE["underline"][0],  # Underline OFF | ||||||
|         TXT_STYLE['align']['left'],  # Align left |         SET_FONT(b"\x00"),  # Default font | ||||||
|         TXT_STYLE['invert'][False]  # Inverted OFF |         TXT_STYLE["align"]["left"],  # Align left | ||||||
|  |         TXT_STYLE["invert"][False],  # Inverted OFF | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|     assert (instance.output == b''.join(expected_sequence)) |     assert instance.output == b"".join(expected_sequence) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_set_size_2w(): | def test_set_size_2w(): | ||||||
| @@ -50,17 +54,18 @@ def test_set_size_2w(): | |||||||
|     instance.set(double_width=True) |     instance.set(double_width=True) | ||||||
|  |  | ||||||
|     expected_sequence = ( |     expected_sequence = ( | ||||||
|         TXT_NORMAL, TXT_STYLE['size']['2w'],  # Double width text size |         TXT_NORMAL, | ||||||
|         TXT_STYLE['flip'][False],  # Flip OFF |         TXT_STYLE["size"]["2w"],  # Double width text size | ||||||
|         TXT_STYLE['smooth'][False],  # Smooth OFF |         TXT_STYLE["flip"][False],  # Flip OFF | ||||||
|         TXT_STYLE['bold'][False],  # Bold OFF |         TXT_STYLE["smooth"][False],  # Smooth OFF | ||||||
|         TXT_STYLE['underline'][0],  # Underline OFF |         TXT_STYLE["bold"][False],  # Bold OFF | ||||||
|         SET_FONT(b'\x00'),  # Default font |         TXT_STYLE["underline"][0],  # Underline OFF | ||||||
|         TXT_STYLE['align']['left'],  # Align left |         SET_FONT(b"\x00"),  # Default font | ||||||
|         TXT_STYLE['invert'][False]  # Inverted OFF |         TXT_STYLE["align"]["left"],  # Align left | ||||||
|  |         TXT_STYLE["invert"][False],  # Inverted OFF | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|     assert (instance.output == b''.join(expected_sequence)) |     assert instance.output == b"".join(expected_sequence) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_set_size_2x(): | def test_set_size_2x(): | ||||||
| @@ -68,17 +73,18 @@ def test_set_size_2x(): | |||||||
|     instance.set(double_height=True, double_width=True) |     instance.set(double_height=True, double_width=True) | ||||||
|  |  | ||||||
|     expected_sequence = ( |     expected_sequence = ( | ||||||
|         TXT_NORMAL, TXT_STYLE['size']['2x'],  # Double text size |         TXT_NORMAL, | ||||||
|         TXT_STYLE['flip'][False],  # Flip OFF |         TXT_STYLE["size"]["2x"],  # Double text size | ||||||
|         TXT_STYLE['smooth'][False],  # Smooth OFF |         TXT_STYLE["flip"][False],  # Flip OFF | ||||||
|         TXT_STYLE['bold'][False],  # Bold OFF |         TXT_STYLE["smooth"][False],  # Smooth OFF | ||||||
|         TXT_STYLE['underline'][0],  # Underline OFF |         TXT_STYLE["bold"][False],  # Bold OFF | ||||||
|         SET_FONT(b'\x00'),  # Default font |         TXT_STYLE["underline"][0],  # Underline OFF | ||||||
|         TXT_STYLE['align']['left'],  # Align left |         SET_FONT(b"\x00"),  # Default font | ||||||
|         TXT_STYLE['invert'][False]  # Inverted OFF |         TXT_STYLE["align"]["left"],  # Align left | ||||||
|  |         TXT_STYLE["invert"][False],  # Inverted OFF | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|     assert (instance.output == b''.join(expected_sequence)) |     assert instance.output == b"".join(expected_sequence) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_set_size_custom(): | def test_set_size_custom(): | ||||||
| @@ -87,55 +93,61 @@ def test_set_size_custom(): | |||||||
|  |  | ||||||
|     expected_sequence = ( |     expected_sequence = ( | ||||||
|         TXT_SIZE,  # Custom text size, no normal reset |         TXT_SIZE,  # Custom text size, no normal reset | ||||||
|         six.int2byte(TXT_STYLE['width'][8] + TXT_STYLE['height'][7]), |         six.int2byte(TXT_STYLE["width"][8] + TXT_STYLE["height"][7]), | ||||||
|         TXT_STYLE['flip'][False],  # Flip OFF |         TXT_STYLE["flip"][False],  # Flip OFF | ||||||
|         TXT_STYLE['smooth'][False],  # Smooth OFF |         TXT_STYLE["smooth"][False],  # Smooth OFF | ||||||
|         TXT_STYLE['bold'][False],  # Bold OFF |         TXT_STYLE["bold"][False],  # Bold OFF | ||||||
|         TXT_STYLE['underline'][0],  # Underline OFF |         TXT_STYLE["underline"][0],  # Underline OFF | ||||||
|         SET_FONT(b'\x00'),  # Default font |         SET_FONT(b"\x00"),  # Default font | ||||||
|         TXT_STYLE['align']['left'],  # Align left |         TXT_STYLE["align"]["left"],  # Align left | ||||||
|         TXT_STYLE['invert'][False]  # Inverted OFF |         TXT_STYLE["invert"][False],  # Inverted OFF | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|     assert (instance.output == b''.join(expected_sequence)) |     assert instance.output == b"".join(expected_sequence) | ||||||
|  |  | ||||||
|  |  | ||||||
| # Flip | # Flip | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_set_flip(): | def test_set_flip(): | ||||||
|     instance = printer.Dummy() |     instance = printer.Dummy() | ||||||
|     instance.set(flip=True) |     instance.set(flip=True) | ||||||
|  |  | ||||||
|     expected_sequence = ( |     expected_sequence = ( | ||||||
|         TXT_NORMAL, TXT_STYLE['size']['normal'],  # Normal text size |         TXT_NORMAL, | ||||||
|         TXT_STYLE['flip'][True],  # Flip ON |         TXT_STYLE["size"]["normal"],  # Normal text size | ||||||
|         TXT_STYLE['smooth'][False],  # Smooth OFF |         TXT_STYLE["flip"][True],  # Flip ON | ||||||
|         TXT_STYLE['bold'][False],  # Bold OFF |         TXT_STYLE["smooth"][False],  # Smooth OFF | ||||||
|         TXT_STYLE['underline'][0],  # Underline OFF |         TXT_STYLE["bold"][False],  # Bold OFF | ||||||
|         SET_FONT(b'\x00'),  # Default font |         TXT_STYLE["underline"][0],  # Underline OFF | ||||||
|         TXT_STYLE['align']['left'],  # Align left |         SET_FONT(b"\x00"),  # Default font | ||||||
|         TXT_STYLE['invert'][False]  # Inverted OFF |         TXT_STYLE["align"]["left"],  # Align left | ||||||
|  |         TXT_STYLE["invert"][False],  # Inverted OFF | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|     assert (instance.output == b''.join(expected_sequence)) |     assert instance.output == b"".join(expected_sequence) | ||||||
|  |  | ||||||
|  |  | ||||||
| # Smooth | # Smooth | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_smooth(): | def test_smooth(): | ||||||
|     instance = printer.Dummy() |     instance = printer.Dummy() | ||||||
|     instance.set(smooth=True) |     instance.set(smooth=True) | ||||||
|  |  | ||||||
|     expected_sequence = ( |     expected_sequence = ( | ||||||
|         TXT_NORMAL, TXT_STYLE['size']['normal'],  # Normal text size |         TXT_NORMAL, | ||||||
|         TXT_STYLE['flip'][False],  # Flip OFF |         TXT_STYLE["size"]["normal"],  # Normal text size | ||||||
|         TXT_STYLE['smooth'][True],  # Smooth ON |         TXT_STYLE["flip"][False],  # Flip OFF | ||||||
|         TXT_STYLE['bold'][False],  # Bold OFF |         TXT_STYLE["smooth"][True],  # Smooth ON | ||||||
|         TXT_STYLE['underline'][0],  # Underline OFF |         TXT_STYLE["bold"][False],  # Bold OFF | ||||||
|         SET_FONT(b'\x00'),  # Default font |         TXT_STYLE["underline"][0],  # Underline OFF | ||||||
|         TXT_STYLE['align']['left'],  # Align left |         SET_FONT(b"\x00"),  # Default font | ||||||
|         TXT_STYLE['invert'][False]  # Inverted OFF |         TXT_STYLE["align"]["left"],  # Align left | ||||||
|  |         TXT_STYLE["invert"][False],  # Inverted OFF | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|     assert(instance.output == b''.join(expected_sequence)) |     assert instance.output == b"".join(expected_sequence) | ||||||
|  |  | ||||||
|  |  | ||||||
| # Type | # Type | ||||||
| @@ -146,17 +158,18 @@ def test_set_bold(): | |||||||
|     instance.set(bold=True) |     instance.set(bold=True) | ||||||
|  |  | ||||||
|     expected_sequence = ( |     expected_sequence = ( | ||||||
|         TXT_NORMAL, TXT_STYLE['size']['normal'],  # Normal text size |         TXT_NORMAL, | ||||||
|         TXT_STYLE['flip'][False],  # Flip OFF |         TXT_STYLE["size"]["normal"],  # Normal text size | ||||||
|         TXT_STYLE['smooth'][False],  # Smooth OFF |         TXT_STYLE["flip"][False],  # Flip OFF | ||||||
|         TXT_STYLE['bold'][True],  # Bold ON |         TXT_STYLE["smooth"][False],  # Smooth OFF | ||||||
|         TXT_STYLE['underline'][0],  # Underline OFF |         TXT_STYLE["bold"][True],  # Bold ON | ||||||
|         SET_FONT(b'\x00'),  # Default font |         TXT_STYLE["underline"][0],  # Underline OFF | ||||||
|         TXT_STYLE['align']['left'],  # Align left |         SET_FONT(b"\x00"),  # Default font | ||||||
|         TXT_STYLE['invert'][False]  # Inverted OFF |         TXT_STYLE["align"]["left"],  # Align left | ||||||
|  |         TXT_STYLE["invert"][False],  # Inverted OFF | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|     assert (instance.output == b''.join(expected_sequence)) |     assert instance.output == b"".join(expected_sequence) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_set_underline(): | def test_set_underline(): | ||||||
| @@ -164,17 +177,18 @@ def test_set_underline(): | |||||||
|     instance.set(underline=1) |     instance.set(underline=1) | ||||||
|  |  | ||||||
|     expected_sequence = ( |     expected_sequence = ( | ||||||
|         TXT_NORMAL, TXT_STYLE['size']['normal'],  # Normal text size |         TXT_NORMAL, | ||||||
|         TXT_STYLE['flip'][False],  # Flip OFF |         TXT_STYLE["size"]["normal"],  # Normal text size | ||||||
|         TXT_STYLE['smooth'][False],  # Smooth OFF |         TXT_STYLE["flip"][False],  # Flip OFF | ||||||
|         TXT_STYLE['bold'][False],  # Bold OFF |         TXT_STYLE["smooth"][False],  # Smooth OFF | ||||||
|         TXT_STYLE['underline'][1],  # Underline ON, type 1 |         TXT_STYLE["bold"][False],  # Bold OFF | ||||||
|         SET_FONT(b'\x00'),  # Default font |         TXT_STYLE["underline"][1],  # Underline ON, type 1 | ||||||
|         TXT_STYLE['align']['left'],  # Align left |         SET_FONT(b"\x00"),  # Default font | ||||||
|         TXT_STYLE['invert'][False]  # Inverted OFF |         TXT_STYLE["align"]["left"],  # Align left | ||||||
|  |         TXT_STYLE["invert"][False],  # Inverted OFF | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|     assert (instance.output == b''.join(expected_sequence)) |     assert instance.output == b"".join(expected_sequence) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_set_underline2(): | def test_set_underline2(): | ||||||
| @@ -182,59 +196,64 @@ def test_set_underline2(): | |||||||
|     instance.set(underline=2) |     instance.set(underline=2) | ||||||
|  |  | ||||||
|     expected_sequence = ( |     expected_sequence = ( | ||||||
|         TXT_NORMAL, TXT_STYLE['size']['normal'],  # Normal text size |         TXT_NORMAL, | ||||||
|         TXT_STYLE['flip'][False],  # Flip OFF |         TXT_STYLE["size"]["normal"],  # Normal text size | ||||||
|         TXT_STYLE['smooth'][False],  # Smooth OFF |         TXT_STYLE["flip"][False],  # Flip OFF | ||||||
|         TXT_STYLE['bold'][False],  # Bold OFF |         TXT_STYLE["smooth"][False],  # Smooth OFF | ||||||
|         TXT_STYLE['underline'][2],  # Underline ON, type 2 |         TXT_STYLE["bold"][False],  # Bold OFF | ||||||
|         SET_FONT(b'\x00'),  # Default font |         TXT_STYLE["underline"][2],  # Underline ON, type 2 | ||||||
|         TXT_STYLE['align']['left'],  # Align left |         SET_FONT(b"\x00"),  # Default font | ||||||
|         TXT_STYLE['invert'][False]  # Inverted OFF |         TXT_STYLE["align"]["left"],  # Align left | ||||||
|  |         TXT_STYLE["invert"][False],  # Inverted OFF | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|     assert (instance.output == b''.join(expected_sequence)) |     assert instance.output == b"".join(expected_sequence) | ||||||
|  |  | ||||||
|  |  | ||||||
| # Align | # Align | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_align_center(): | def test_align_center(): | ||||||
|     instance = printer.Dummy() |     instance = printer.Dummy() | ||||||
|     instance.set(align='center') |     instance.set(align="center") | ||||||
|  |  | ||||||
|     expected_sequence = ( |     expected_sequence = ( | ||||||
|         TXT_NORMAL, TXT_STYLE['size']['normal'],  # Normal text size |         TXT_NORMAL, | ||||||
|         TXT_STYLE['flip'][False],  # Flip OFF |         TXT_STYLE["size"]["normal"],  # Normal text size | ||||||
|         TXT_STYLE['smooth'][False],  # Smooth OFF |         TXT_STYLE["flip"][False],  # Flip OFF | ||||||
|         TXT_STYLE['bold'][False],  # Bold OFF |         TXT_STYLE["smooth"][False],  # Smooth OFF | ||||||
|         TXT_STYLE['underline'][0],  # Underline OFF |         TXT_STYLE["bold"][False],  # Bold OFF | ||||||
|         SET_FONT(b'\x00'),  # Default font |         TXT_STYLE["underline"][0],  # Underline OFF | ||||||
|         TXT_STYLE['align']['center'],  # Align center |         SET_FONT(b"\x00"),  # Default font | ||||||
|         TXT_STYLE['invert'][False]  # Inverted OFF |         TXT_STYLE["align"]["center"],  # Align center | ||||||
|  |         TXT_STYLE["invert"][False],  # Inverted OFF | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|     assert(instance.output == b''.join(expected_sequence)) |     assert instance.output == b"".join(expected_sequence) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_align_right(): | def test_align_right(): | ||||||
|     instance = printer.Dummy() |     instance = printer.Dummy() | ||||||
|     instance.set(align='right') |     instance.set(align="right") | ||||||
|  |  | ||||||
|     expected_sequence = ( |     expected_sequence = ( | ||||||
|         TXT_NORMAL, TXT_STYLE['size']['normal'],  # Normal text size |         TXT_NORMAL, | ||||||
|         TXT_STYLE['flip'][False],  # Flip OFF |         TXT_STYLE["size"]["normal"],  # Normal text size | ||||||
|         TXT_STYLE['smooth'][False],  # Smooth OFF |         TXT_STYLE["flip"][False],  # Flip OFF | ||||||
|         TXT_STYLE['bold'][False],  # Bold OFF |         TXT_STYLE["smooth"][False],  # Smooth OFF | ||||||
|         TXT_STYLE['underline'][0],  # Underline OFF |         TXT_STYLE["bold"][False],  # Bold OFF | ||||||
|         SET_FONT(b'\x00'),  # Default font |         TXT_STYLE["underline"][0],  # Underline OFF | ||||||
|         TXT_STYLE['align']['right'],  # Align right |         SET_FONT(b"\x00"),  # Default font | ||||||
|         TXT_STYLE['invert'][False]  # Inverted OFF |         TXT_STYLE["align"]["right"],  # Align right | ||||||
|  |         TXT_STYLE["invert"][False],  # Inverted OFF | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|     assert(instance.output == b''.join(expected_sequence)) |     assert instance.output == b"".join(expected_sequence) | ||||||
|  |  | ||||||
|  |  | ||||||
| # Densities | # Densities | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_densities(): | def test_densities(): | ||||||
|  |  | ||||||
|     for density in range(8): |     for density in range(8): | ||||||
| @@ -242,35 +261,38 @@ def test_densities(): | |||||||
|         instance.set(density=density) |         instance.set(density=density) | ||||||
|  |  | ||||||
|         expected_sequence = ( |         expected_sequence = ( | ||||||
|             TXT_NORMAL, TXT_STYLE['size']['normal'],  # Normal text size |             TXT_NORMAL, | ||||||
|             TXT_STYLE['flip'][False],  # Flip OFF |             TXT_STYLE["size"]["normal"],  # Normal text size | ||||||
|             TXT_STYLE['smooth'][False],  # Smooth OFF |             TXT_STYLE["flip"][False],  # Flip OFF | ||||||
|             TXT_STYLE['bold'][False],  # Bold OFF |             TXT_STYLE["smooth"][False],  # Smooth OFF | ||||||
|             TXT_STYLE['underline'][0],  # Underline OFF |             TXT_STYLE["bold"][False],  # Bold OFF | ||||||
|             SET_FONT(b'\x00'),  # Default font |             TXT_STYLE["underline"][0],  # Underline OFF | ||||||
|             TXT_STYLE['align']['left'],  # Align left |             SET_FONT(b"\x00"),  # Default font | ||||||
|             TXT_STYLE['density'][density],  # Custom density from 0 to 8 |             TXT_STYLE["align"]["left"],  # Align left | ||||||
|             TXT_STYLE['invert'][False]  # Inverted OFF |             TXT_STYLE["density"][density],  # Custom density from 0 to 8 | ||||||
|  |             TXT_STYLE["invert"][False],  # Inverted OFF | ||||||
|         ) |         ) | ||||||
|  |  | ||||||
|         assert(instance.output == b''.join(expected_sequence)) |         assert instance.output == b"".join(expected_sequence) | ||||||
|  |  | ||||||
|  |  | ||||||
| # Invert | # Invert | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_invert(): | def test_invert(): | ||||||
|     instance = printer.Dummy() |     instance = printer.Dummy() | ||||||
|     instance.set(invert=True) |     instance.set(invert=True) | ||||||
|  |  | ||||||
|     expected_sequence = ( |     expected_sequence = ( | ||||||
|         TXT_NORMAL, TXT_STYLE['size']['normal'],  # Normal text size |         TXT_NORMAL, | ||||||
|         TXT_STYLE['flip'][False],  # Flip OFF |         TXT_STYLE["size"]["normal"],  # Normal text size | ||||||
|         TXT_STYLE['smooth'][False],  # Smooth OFF |         TXT_STYLE["flip"][False],  # Flip OFF | ||||||
|         TXT_STYLE['bold'][False],  # Bold OFF |         TXT_STYLE["smooth"][False],  # Smooth OFF | ||||||
|         TXT_STYLE['underline'][0],  # Underline OFF |         TXT_STYLE["bold"][False],  # Bold OFF | ||||||
|         SET_FONT(b'\x00'),  # Default font |         TXT_STYLE["underline"][0],  # Underline OFF | ||||||
|         TXT_STYLE['align']['left'],  # Align left |         SET_FONT(b"\x00"),  # Default font | ||||||
|         TXT_STYLE['invert'][True]  # Inverted ON |         TXT_STYLE["align"]["left"],  # Align left | ||||||
|  |         TXT_STYLE["invert"][True],  # Inverted ON | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|     assert(instance.output == b''.join(expected_sequence)) |     assert instance.output == b"".join(expected_sequence) | ||||||
|   | |||||||
| @@ -9,11 +9,13 @@ import pytest | |||||||
| def instance(): | def instance(): | ||||||
|     return printer.Dummy() |     return printer.Dummy() | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_soft_barcode_ean8_invalid(instance): | def test_soft_barcode_ean8_invalid(instance): | ||||||
|     """test with an invalid barcode""" |     """test with an invalid barcode""" | ||||||
|     with pytest.raises(barcode.errors.BarcodeError): |     with pytest.raises(barcode.errors.BarcodeError): | ||||||
|         instance.soft_barcode("ean8", "1234") |         instance.soft_barcode("ean8", "1234") | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_soft_barcode_ean8(instance): | def test_soft_barcode_ean8(instance): | ||||||
|     """test with a valid ean8 barcode""" |     """test with a valid ean8 barcode""" | ||||||
|     instance.soft_barcode("ean8", "1234567") |     instance.soft_barcode("ean8", "1234567") | ||||||
|   | |||||||
| @@ -16,13 +16,12 @@ from escpos.printer import Dummy | |||||||
|  |  | ||||||
|  |  | ||||||
| def get_printer(): | def get_printer(): | ||||||
|     return Dummy(magic_encode_args={'disabled': True, 'encoding': 'CP437'}) |     return Dummy(magic_encode_args={"disabled": True, "encoding": "CP437"}) | ||||||
|  |  | ||||||
|  |  | ||||||
| @given(text=st.text()) | @given(text=st.text()) | ||||||
| def test_text(text): | def test_text(text): | ||||||
|     """Test that text() calls the MagicEncode object. |     """Test that text() calls the MagicEncode object.""" | ||||||
|     """ |  | ||||||
|     instance = get_printer() |     instance = get_printer() | ||||||
|     instance.magic.write = mock.Mock() |     instance.magic.write = mock.Mock() | ||||||
|     instance.text(text) |     instance.text(text) | ||||||
| @@ -32,30 +31,32 @@ def test_text(text): | |||||||
| def test_block_text(): | def test_block_text(): | ||||||
|     printer = get_printer() |     printer = get_printer() | ||||||
|     printer.block_text( |     printer.block_text( | ||||||
|         "All the presidents men were eating falafel for breakfast.", font='a') |         "All the presidents men were eating falafel for breakfast.", font="a" | ||||||
|     assert printer.output == \ |     ) | ||||||
|         b'All the presidents men were eating falafel\nfor breakfast.' |     assert ( | ||||||
|  |         printer.output == b"All the presidents men were eating falafel\nfor breakfast." | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_textln(): | def test_textln(): | ||||||
|     printer = get_printer() |     printer = get_printer() | ||||||
|     printer.textln('hello, world') |     printer.textln("hello, world") | ||||||
|     assert printer.output == b'hello, world\n' |     assert printer.output == b"hello, world\n" | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_textln_empty(): | def test_textln_empty(): | ||||||
|     printer = get_printer() |     printer = get_printer() | ||||||
|     printer.textln() |     printer.textln() | ||||||
|     assert printer.output == b'\n' |     assert printer.output == b"\n" | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_ln(): | def test_ln(): | ||||||
|     printer = get_printer() |     printer = get_printer() | ||||||
|     printer.ln() |     printer.ln() | ||||||
|     assert printer.output == b'\n' |     assert printer.output == b"\n" | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_multiple_ln(): | def test_multiple_ln(): | ||||||
|     printer = get_printer() |     printer = get_printer() | ||||||
|     printer.ln(3) |     printer.ln(3) | ||||||
|     assert printer.output == b'\n\n\n' |     assert printer.output == b"\n\n\n" | ||||||
|   | |||||||
| @@ -5,13 +5,13 @@ from escpos.printer import Dummy | |||||||
| def test_line_spacing_code_gen(): | def test_line_spacing_code_gen(): | ||||||
|     printer = Dummy() |     printer = Dummy() | ||||||
|     printer.line_spacing(10) |     printer.line_spacing(10) | ||||||
|     assert printer.output == b'\x1b3\n' |     assert printer.output == b"\x1b3\n" | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_line_spacing_rest(): | def test_line_spacing_rest(): | ||||||
|     printer = Dummy() |     printer = Dummy() | ||||||
|     printer.line_spacing() |     printer.line_spacing() | ||||||
|     assert printer.output == b'\x1b2' |     assert printer.output == b"\x1b2" | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_line_spacing_error_handling(): | def test_line_spacing_error_handling(): | ||||||
|   | |||||||
| @@ -15,57 +15,67 @@ def test_image_black(): | |||||||
|     """ |     """ | ||||||
|     Test rendering solid black image |     Test rendering solid black image | ||||||
|     """ |     """ | ||||||
|     for img_format in ['png', 'jpg', 'gif']: |     for img_format in ["png", "jpg", "gif"]: | ||||||
|         _load_and_check_img('canvas_black.' + img_format, 1, 1, b'\x80', [b'\x80']) |         _load_and_check_img("canvas_black." + img_format, 1, 1, b"\x80", [b"\x80"]) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_image_black_transparent(): | def test_image_black_transparent(): | ||||||
|     """ |     """ | ||||||
|     Test rendering black/transparent image |     Test rendering black/transparent image | ||||||
|     """ |     """ | ||||||
|     for img_format in ['png', 'gif']: |     for img_format in ["png", "gif"]: | ||||||
|         _load_and_check_img('black_transparent.' + img_format, 2, 2, b'\xc0\x00', [b'\x80\x80']) |         _load_and_check_img( | ||||||
|  |             "black_transparent." + img_format, 2, 2, b"\xc0\x00", [b"\x80\x80"] | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_image_black_white(): | def test_image_black_white(): | ||||||
|     """ |     """ | ||||||
|     Test rendering black/white image |     Test rendering black/white image | ||||||
|     """ |     """ | ||||||
|     for img_format in ['png', 'jpg', 'gif']: |     for img_format in ["png", "jpg", "gif"]: | ||||||
|         _load_and_check_img('black_white.' + img_format, 2, 2, b'\xc0\x00', [b'\x80\x80']) |         _load_and_check_img( | ||||||
|  |             "black_white." + img_format, 2, 2, b"\xc0\x00", [b"\x80\x80"] | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_image_white(): | def test_image_white(): | ||||||
|     """ |     """ | ||||||
|     Test rendering solid white image |     Test rendering solid white image | ||||||
|     """ |     """ | ||||||
|     for img_format in ['png', 'jpg', 'gif']: |     for img_format in ["png", "jpg", "gif"]: | ||||||
|         _load_and_check_img('canvas_white.' + img_format, 1, 1, b'\x00', [b'\x00']) |         _load_and_check_img("canvas_white." + img_format, 1, 1, b"\x00", [b"\x00"]) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_split(): | def test_split(): | ||||||
|     """ |     """ | ||||||
|     test whether the split-function works as expected |     test whether the split-function works as expected | ||||||
|     """ |     """ | ||||||
|     im = EscposImage('test/resources/black_white.png') |     im = EscposImage("test/resources/black_white.png") | ||||||
|     (upper_part, lower_part) = im.split(1) |     (upper_part, lower_part) = im.split(1) | ||||||
|     upper_part = EscposImage(upper_part) |     upper_part = EscposImage(upper_part) | ||||||
|     lower_part = EscposImage(lower_part) |     lower_part = EscposImage(lower_part) | ||||||
|     assert(upper_part.width == lower_part.width == 2) |     assert upper_part.width == lower_part.width == 2 | ||||||
|     assert(upper_part.height == lower_part.height == 1) |     assert upper_part.height == lower_part.height == 1 | ||||||
|     assert(upper_part.to_raster_format() == b'\xc0') |     assert upper_part.to_raster_format() == b"\xc0" | ||||||
|     assert(lower_part.to_raster_format() == b'\x00') |     assert lower_part.to_raster_format() == b"\x00" | ||||||
|  |  | ||||||
|  |  | ||||||
| def _load_and_check_img(filename, width_expected, height_expected, raster_format_expected, column_format_expected): | def _load_and_check_img( | ||||||
|  |     filename, | ||||||
|  |     width_expected, | ||||||
|  |     height_expected, | ||||||
|  |     raster_format_expected, | ||||||
|  |     column_format_expected, | ||||||
|  | ): | ||||||
|     """ |     """ | ||||||
|     Load an image, and test whether raster & column formatted output, sizes, etc match expectations. |     Load an image, and test whether raster & column formatted output, sizes, etc match expectations. | ||||||
|     """ |     """ | ||||||
|     im = EscposImage('test/resources/' + filename) |     im = EscposImage("test/resources/" + filename) | ||||||
|     assert(im.width == width_expected) |     assert im.width == width_expected | ||||||
|     assert(im.height == height_expected) |     assert im.height == height_expected | ||||||
|     assert(im.to_raster_format() == raster_format_expected) |     assert im.to_raster_format() == raster_format_expected | ||||||
|     i = 0 |     i = 0 | ||||||
|     for row in im.to_column_format(False): |     for row in im.to_column_format(False): | ||||||
|         assert(row == column_format_expected[i]) |         assert row == column_format_expected[i] | ||||||
|         i += 1 |         i += 1 | ||||||
|   | |||||||
| @@ -14,4 +14,4 @@ import escpos.printer as printer | |||||||
| def test_instantiation(): | def test_instantiation(): | ||||||
|     """test the instantiation of a escpos-printer class and basic printing""" |     """test the instantiation of a escpos-printer class and basic printing""" | ||||||
|     instance = printer.Dummy() |     instance = printer.Dummy() | ||||||
|     instance.text('This is a test\n') |     instance.text("This is a test\n") | ||||||
|   | |||||||
| @@ -24,17 +24,17 @@ class TestEncoder: | |||||||
|     """ |     """ | ||||||
|  |  | ||||||
|     def test_can_encode(self): |     def test_can_encode(self): | ||||||
|         assert not Encoder({'CP437': 1}).can_encode('CP437', u'€') |         assert not Encoder({"CP437": 1}).can_encode("CP437", u"€") | ||||||
|         assert Encoder({'CP437': 1}).can_encode('CP437', u'á') |         assert Encoder({"CP437": 1}).can_encode("CP437", u"á") | ||||||
|         assert not Encoder({'foobar': 1}).can_encode('foobar', 'a') |         assert not Encoder({"foobar": 1}).can_encode("foobar", "a") | ||||||
|  |  | ||||||
|     def test_find_suitable_encoding(self): |     def test_find_suitable_encoding(self): | ||||||
|         assert not Encoder({'CP437': 1}).find_suitable_encoding(u'€') |         assert not Encoder({"CP437": 1}).find_suitable_encoding(u"€") | ||||||
|         assert Encoder({'CP858': 1}).find_suitable_encoding(u'€') == 'CP858' |         assert Encoder({"CP858": 1}).find_suitable_encoding(u"€") == "CP858" | ||||||
|  |  | ||||||
|     @raises(ValueError) |     @raises(ValueError) | ||||||
|     def test_get_encoding(self): |     def test_get_encoding(self): | ||||||
|         Encoder({}).get_encoding_name('latin1') |         Encoder({}).get_encoding_name("latin1") | ||||||
|  |  | ||||||
|  |  | ||||||
| class TestMagicEncode: | class TestMagicEncode: | ||||||
| @@ -57,50 +57,50 @@ class TestMagicEncode: | |||||||
|                 MagicEncode(driver, disabled=True) |                 MagicEncode(driver, disabled=True) | ||||||
|  |  | ||||||
|     class TestWriteWithEncoding: |     class TestWriteWithEncoding: | ||||||
|  |  | ||||||
|         def test_init_from_none(self, driver): |         def test_init_from_none(self, driver): | ||||||
|             encode = MagicEncode(driver, encoding=None) |             encode = MagicEncode(driver, encoding=None) | ||||||
|             encode.write_with_encoding('CP858', '€ ist teuro.') |             encode.write_with_encoding("CP858", "€ ist teuro.") | ||||||
|             assert driver.output == b'\x1bt\x13\xd5 ist teuro.' |             assert driver.output == b"\x1bt\x13\xd5 ist teuro." | ||||||
|  |  | ||||||
|         def test_change_from_another(self, driver): |         def test_change_from_another(self, driver): | ||||||
|             encode = MagicEncode(driver, encoding='CP437') |             encode = MagicEncode(driver, encoding="CP437") | ||||||
|             encode.write_with_encoding('CP858', '€ ist teuro.') |             encode.write_with_encoding("CP858", "€ ist teuro.") | ||||||
|             assert driver.output == b'\x1bt\x13\xd5 ist teuro.' |             assert driver.output == b"\x1bt\x13\xd5 ist teuro." | ||||||
|  |  | ||||||
|         def test_no_change(self, driver): |         def test_no_change(self, driver): | ||||||
|             encode = MagicEncode(driver, encoding='CP858') |             encode = MagicEncode(driver, encoding="CP858") | ||||||
|             encode.write_with_encoding('CP858', '€ ist teuro.') |             encode.write_with_encoding("CP858", "€ ist teuro.") | ||||||
|             assert driver.output == b'\xd5 ist teuro.' |             assert driver.output == b"\xd5 ist teuro." | ||||||
|  |  | ||||||
|     class TestWrite: |     class TestWrite: | ||||||
|  |  | ||||||
|         def test_write(self, driver): |         def test_write(self, driver): | ||||||
|             encode = MagicEncode(driver) |             encode = MagicEncode(driver) | ||||||
|             encode.write('€ ist teuro.') |             encode.write("€ ist teuro.") | ||||||
|             assert driver.output == b'\x1bt\x0f\xa4 ist teuro.' |             assert driver.output == b"\x1bt\x0f\xa4 ist teuro." | ||||||
|  |  | ||||||
|         def test_write_disabled(self, driver): |         def test_write_disabled(self, driver): | ||||||
|             encode = MagicEncode(driver, encoding='CP437', disabled=True) |             encode = MagicEncode(driver, encoding="CP437", disabled=True) | ||||||
|             encode.write('€ ist teuro.') |             encode.write("€ ist teuro.") | ||||||
|             assert driver.output == b'? ist teuro.' |             assert driver.output == b"? ist teuro." | ||||||
|  |  | ||||||
|         def test_write_no_codepage(self, driver): |         def test_write_no_codepage(self, driver): | ||||||
|             encode = MagicEncode( |             encode = MagicEncode( | ||||||
|                 driver, defaultsymbol="_", encoder=Encoder({'CP437': 1}), |                 driver, | ||||||
|                 encoding='CP437') |                 defaultsymbol="_", | ||||||
|             encode.write(u'€ ist teuro.') |                 encoder=Encoder({"CP437": 1}), | ||||||
|             assert driver.output == b'_ ist teuro.' |                 encoding="CP437", | ||||||
|  |             ) | ||||||
|  |             encode.write(u"€ ist teuro.") | ||||||
|  |             assert driver.output == b"_ ist teuro." | ||||||
|  |  | ||||||
|     class TestForceEncoding: |     class TestForceEncoding: | ||||||
|  |  | ||||||
|         def test(self, driver): |         def test(self, driver): | ||||||
|             encode = MagicEncode(driver) |             encode = MagicEncode(driver) | ||||||
|             encode.force_encoding('CP437') |             encode.force_encoding("CP437") | ||||||
|             assert driver.output == b'\x1bt\x00' |             assert driver.output == b"\x1bt\x00" | ||||||
|  |  | ||||||
|             encode.write('€ ist teuro.') |             encode.write("€ ist teuro.") | ||||||
|             assert driver.output == b'\x1bt\x00? ist teuro.' |             assert driver.output == b"\x1bt\x00? ist teuro." | ||||||
|  |  | ||||||
|  |  | ||||||
| try: | try: | ||||||
| @@ -119,5 +119,5 @@ class TestKatakana: | |||||||
|         encode_katakana(text) |         encode_katakana(text) | ||||||
|  |  | ||||||
|     def test_result(self): |     def test_result(self): | ||||||
|         assert encode_katakana('カタカナ') == b'\xb6\xc0\xb6\xc5' |         assert encode_katakana("カタカナ") == b"\xb6\xc0\xb6\xc5" | ||||||
|         assert encode_katakana("あいうえお") == b'\xb1\xb2\xb3\xb4\xb5' |         assert encode_katakana("あいうえお") == b"\xb1\xb2\xb3\xb4\xb5" | ||||||
|   | |||||||
| @@ -18,16 +18,16 @@ from hypothesis.strategies import text | |||||||
| import escpos.printer as printer | import escpos.printer as printer | ||||||
|  |  | ||||||
| if six.PY3: | if six.PY3: | ||||||
|     mock_open_call = 'builtins.open' |     mock_open_call = "builtins.open" | ||||||
| else: | else: | ||||||
|     mock_open_call = '__builtin__.open' |     mock_open_call = "__builtin__.open" | ||||||
|  |  | ||||||
|  |  | ||||||
| @pytest.mark.skip("this test is broken and has to be fixed or discarded") | @pytest.mark.skip("this test is broken and has to be fixed or discarded") | ||||||
| @given(path=text()) | @given(path=text()) | ||||||
| def test_load_file_printer(mocker, path): | def test_load_file_printer(mocker, path): | ||||||
|     """test the loading of the file-printer""" |     """test the loading of the file-printer""" | ||||||
|     mock_escpos = mocker.patch('escpos.escpos.Escpos.__init__') |     mock_escpos = mocker.patch("escpos.escpos.Escpos.__init__") | ||||||
|     mock_open = mocker.patch(mock_open_call) |     mock_open = mocker.patch(mock_open_call) | ||||||
|     printer.File(devfile=path) |     printer.File(devfile=path) | ||||||
|     assert mock_escpos.called |     assert mock_escpos.called | ||||||
| @@ -38,9 +38,9 @@ def test_load_file_printer(mocker, path): | |||||||
| @given(txt=text()) | @given(txt=text()) | ||||||
| def test_auto_flush(mocker, txt): | def test_auto_flush(mocker, txt): | ||||||
|     """test auto_flush in file-printer""" |     """test auto_flush in file-printer""" | ||||||
|     mock_escpos = mocker.patch('escpos.escpos.Escpos.__init__') |     mock_escpos = mocker.patch("escpos.escpos.Escpos.__init__") | ||||||
|     mock_open = mocker.patch(mock_open_call) |     mock_open = mocker.patch(mock_open_call) | ||||||
|     mock_device = mocker.patch.object(printer.File, 'device') |     mock_device = mocker.patch.object(printer.File, "device") | ||||||
|  |  | ||||||
|     p = printer.File(auto_flush=False) |     p = printer.File(auto_flush=False) | ||||||
|     # inject the mocked device-object |     # inject the mocked device-object | ||||||
| @@ -60,7 +60,7 @@ def test_auto_flush(mocker, txt): | |||||||
| def test_flush_on_close(mocker, txt): | def test_flush_on_close(mocker, txt): | ||||||
|     """test flush on close in file-printer""" |     """test flush on close in file-printer""" | ||||||
|     mock_open = mocker.patch(mock_open_call) |     mock_open = mocker.patch(mock_open_call) | ||||||
|     mock_device = mocker.patch.object(printer.File, 'device') |     mock_device = mocker.patch.object(printer.File, "device") | ||||||
|  |  | ||||||
|     p = printer.File(auto_flush=False) |     p = printer.File(auto_flush=False) | ||||||
|     # inject the mocked device-object |     # inject the mocked device-object | ||||||
|   | |||||||
| @@ -11,6 +11,7 @@ def instance(): | |||||||
|     socket.socket.connect = mock.Mock() |     socket.socket.connect = mock.Mock() | ||||||
|     return printer.Network("localhost") |     return printer.Network("localhost") | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_close_without_open(instance): | def test_close_without_open(instance): | ||||||
|     """try to close without opening (should fail gracefully) |     """try to close without opening (should fail gracefully) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -4,35 +4,33 @@ from escpos.capabilities import get_profile, NotSupported, BARCODE_B, Profile | |||||||
|  |  | ||||||
| @pytest.fixture | @pytest.fixture | ||||||
| def profile(): | def profile(): | ||||||
|     return get_profile('default') |     return get_profile("default") | ||||||
|  |  | ||||||
|  |  | ||||||
| class TestBaseProfile: | class TestBaseProfile: | ||||||
|     """Test the `BaseProfile` class. |     """Test the `BaseProfile` class.""" | ||||||
|     """ |  | ||||||
|  |  | ||||||
|     def test_get_font(self, profile): |     def test_get_font(self, profile): | ||||||
|         with pytest.raises(NotSupported): |         with pytest.raises(NotSupported): | ||||||
|             assert profile.get_font('3') |             assert profile.get_font("3") | ||||||
|         assert profile.get_font(1) == 1 |         assert profile.get_font(1) == 1 | ||||||
|         assert profile.get_font('a') == 0 |         assert profile.get_font("a") == 0 | ||||||
|  |  | ||||||
|     def test_supports(self, profile): |     def test_supports(self, profile): | ||||||
|         assert not profile.supports('asdf asdf') |         assert not profile.supports("asdf asdf") | ||||||
|         assert profile.supports(BARCODE_B) |         assert profile.supports(BARCODE_B) | ||||||
|  |  | ||||||
|     def test_get_columns(self, profile): |     def test_get_columns(self, profile): | ||||||
|         assert profile.get_columns('a') > 5 |         assert profile.get_columns("a") > 5 | ||||||
|         with pytest.raises(NotSupported): |         with pytest.raises(NotSupported): | ||||||
|             assert profile.get_columns('asdfasdf') |             assert profile.get_columns("asdfasdf") | ||||||
|  |  | ||||||
|  |  | ||||||
| class TestCustomProfile: | class TestCustomProfile: | ||||||
|     """Test custom profile options with the `Profile` class. |     """Test custom profile options with the `Profile` class.""" | ||||||
|     """ |  | ||||||
|  |  | ||||||
|     def test_columns(self): |     def test_columns(self): | ||||||
|         assert Profile(columns=10).get_columns('sdfasdf') == 10 |         assert Profile(columns=10).get_columns("sdfasdf") == 10 | ||||||
|  |  | ||||||
|     def test_features(self): |     def test_features(self): | ||||||
|         assert Profile(features={'foo': True}).supports('foo') |         assert Profile(features={"foo": True}).supports("foo") | ||||||
|   | |||||||
| @@ -16,5 +16,5 @@ def test_with_statement(): | |||||||
|     """Use with statement""" |     """Use with statement""" | ||||||
|     dummy_printer = printer.Dummy() |     dummy_printer = printer.Dummy() | ||||||
|     with escpos.EscposIO(dummy_printer) as p: |     with escpos.EscposIO(dummy_printer) as p: | ||||||
|             p.writelines('Some text.\n') |         p.writelines("Some text.\n") | ||||||
|     # TODO extend these tests as they don't really do anything at the moment |     # TODO extend these tests as they don't really do anything at the moment | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Patrick Kanzler
					Patrick Kanzler