diff --git a/CHANGELOG b/CHANGELOG index 0264444..5dd4347 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,8 @@ +v 0.7.0 [-oct-2020] +--------------------- + - Update libraries + + v 0.6.0 [15-nov-2019] --------------------- - Call by code diff --git a/README.md b/README.md index d1e7d64..51892ef 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ Extension for insert barcode in LibreOffice documents, with Python, of course. Barcodes provided +* qrcode * code39 * code128 * ean @@ -19,7 +20,6 @@ Barcodes provided * pzn * upc * upca -* qrcode Requirements: @@ -45,6 +45,10 @@ BCH: `qztd3l00xle5tffdqvh2snvadkuau2ml0uqm4n875d` BTC: `3FhiXcXmAesmQzrNEngjHFnvaJRhU1AGWV` +ETH: `0x61a4f614a30ff686445751ed8328b82b77ecfc69` + +LTC: `MBcgQ3LQJA4W2wsXknTdm2fxRSysLaBJHS` + * [Look the wiki](https://gitlab.com/mauriciobaeza/zaz-barcode/wikis/home) * [Mira la wiki](https://gitlab.com/mauriciobaeza/zaz-barcode/wikis/home_es) diff --git a/VERSION b/VERSION index 009695b..bcaffe1 100644 --- a/VERSION +++ b/VERSION @@ -1,2 +1 @@ -0.6.0 - +0.7.0 \ No newline at end of file diff --git a/conf.py b/conf.py index 9a4b900..ff2f0fd 100644 --- a/conf.py +++ b/conf.py @@ -26,7 +26,7 @@ import logging TYPE_EXTENSION = 1 # ~ https://semver.org/ -VERSION = '0.6.0' +VERSION = '0.7.0' # ~ Your great extension name, not used spaces NAME = 'ZAZBarCode' @@ -41,8 +41,7 @@ ID = 'net.elmau.zaz.BarCode' USE_LOCALES = True DOMAIN = 'base' PATH_LOCALES = 'locales' -# ~ locate pygettext.py -PATH_PYGETTEXT = '/usr/lib/python3.7/Tools/i18n/pygettext.py' +PATH_PYGETTEXT = '/usr/lib/python3.8/Tools/i18n/pygettext.py' PATH_MSGMERGE = 'msgmerge' @@ -93,17 +92,6 @@ INFO = { } -CONTEXT = { - 'calc': 'com.sun.star.sheet.SpreadsheetDocument', - 'writer': 'com.sun.star.text.TextDocument', - 'impress': 'com.sun.star.presentation.PresentationDocument', - 'draw': 'com.sun.star.drawing.DrawingDocument', - 'base': 'com.sun.star.sdb.OfficeDatabaseDocument', - 'math': 'com.sun.star.formula.FormulaProperties', - 'basic': 'com.sun.star.script.BasicIDE', -} - - # ~ Menus, only for TYPE_EXTENSION = 1 # ~ Parent can be: AddonMenu or OfficeMenuBar # ~ For icons con name: NAME_16.bmp, used only NAME @@ -372,7 +360,7 @@ elif TYPE_EXTENSION == 3: METHODS = _methods() -FILE_PY = f"""import uno +DATA_PY = f"""import uno import unohelper {SRV_IMPORT} @@ -392,177 +380,6 @@ g_ImplementationHelper = unohelper.ImplementationHelper() g_ImplementationHelper.addImplementation({NAME}, ID_EXTENSION, SERVICE) """ - -tmp = ' {}' -node = [tmp.format(k, v['display_name']) for k, v in INFO.items()] -NODE_DISPLAY_NAME = '\n'.join(node) - -tmp = ' ' -node = [tmp.format(k) for k, v in INFO.items()] -NODE_EXTENSION_DESCRIPTION = '\n'.join(node) - -NODE_ICON = '' -if ICON: - NODE_ICON = f' ' - -NODE_PUBLISHER = '' -if PUBLISHER: - tmp = ' {}' - node = [tmp.format(v['link'], k, v['text']) for k, v in PUBLISHER.items()] - NODE_PUBLISHER = '\n'.join(node) - -NODE_DEPENDENCIES_MINIMAL = '' -if DEPENDENCIES_MINIMAL: - NODE_DEPENDENCIES_MINIMAL = f"""\n - - """ - -tmp = ' ' -node = [tmp.format(DIRS['registration'], k) for k in INFO.keys()] -NODE_LICENSE = '\n'.join(node) - -NODE_UPDATE = '' -if URL_XML_UPDATE: - NODE_UPDATE = f""" - - - """ - -FILE_DESCRIPTION = f""" - - - - -{NODE_DISPLAY_NAME} - - -{NODE_EXTENSION_DESCRIPTION} - - -{NODE_ICON} - - -{NODE_PUBLISHER} - - - -{NODE_LICENSE} - - {NODE_DEPENDENCIES_MINIMAL}{NODE_UPDATE} - -""" - -NODE_MENU = """ - -{titles} - - - service:{id}?{argument} - - - _self - - - {context} - - - %origin%/{folder}/{icon} - - """ - -opt = 'fuse' -if PARENT == 'OfficeMenuBar': - opt = 'replace' - - -def _get_context(args): - if not args: - return '' - c = [] - for v in args.split(','): - c.append(CONTEXT[v]) - return ','.join(c) - - -menus = [] -toolbar = [] -tmp = ' {}' -for i, m in enumerate(MENUS): - titles = [tmp.format(k, v) for k, v in m['title'].items()] - values = { - 'id': ID, - 'index': i+101, - 'opt': opt, - 'titles': '\n'.join(titles), - 'argument': m['argument'], - 'context': _get_context(m['context']), - 'folder': DIRS['images'], - 'icon': m['icon'], - } - menus.append(NODE_MENU.format(**values)) - if m['toolbar']: - values['index'] = f't{i+1}' - toolbar.append(NODE_MENU.format(**values)) - -NODE_TOOLBAR = '' -NODE_MENUS = '' -if TYPE_EXTENSION == 1: - if PARENT == 'AddonMenu': - NODE_MENUS = '\n'.join(menus) - elif PARENT == 'OfficeMenuBar': - tmp = ' {}' - titles = '\n'.join([tmp.format(k, v) for k, v in MENU_MAIN.items()]) - SUBMENUS = '\n ' + '\n'.join(menus) + '\n ' - NODE_MENUS = f""" - - {titles} - - - _self - - {SUBMENUS} - """ - - if toolbar: - node_toolbars = '\n'.join(toolbar) - NODE_TOOLBAR = f""" - - {node_toolbars} - - """ - -FILE_ADDONS = f""" - - - -{NODE_MENUS} - -{NODE_TOOLBAR} - - -""" - - -FILE_UPDATE = '' -if URL_XML_UPDATE: - FILE_UPDATE = f""" - - - - - - - - - - - -""" - - def _functions(): a = '[in] any {}' t = ' any {}({});' @@ -679,72 +496,42 @@ FILE_ADDIN = f""" """ -NODE_SHORTCUT = """ {0} - {0} - {0}service:{2}?{3} - {0} - {0} -""" - -NODE_SHORTCUTS = '' -if TYPE_EXTENSION == 1: - node_global = [] - node_module = {} - for m in MENUS: - if not m.get('shortcut', ''): - continue - if m['context']: - for c in m['context'].split(','): - if not c in node_module: - node_module[c] = [] - node = NODE_SHORTCUT.format(' ', m['shortcut'], ID, m['argument']) - node_module[c].append(node) - continue - node = NODE_SHORTCUT.format('', m['shortcut'], ID, m['argument']) - node_global.append(node) - if node_global: - NODE_SHORTCUTS = ' \n' - NODE_SHORTCUTS += '\n'.join(node_global) - NODE_SHORTCUTS += ' ' - if node_module: - NODE_SHORTCUTS += ' \n' - for c, n in node_module.items(): - NODE_SHORTCUTS += ' \n'.format(CONTEXT[c]) - NODE_SHORTCUTS += '\n'.join(n) - NODE_SHORTCUTS += ' \n' - NODE_SHORTCUTS += ' ' - -FILE_SHORTCUTS = f""" - - -{NODE_SHORTCUTS} - - -""" - - DATA_MANIFEST = [FILES['py'], f"Office/{FILES['shortcut']}", 'Addons.xcu'] if TYPE_EXTENSION > 1: DATA_MANIFEST.append(FILES['rdb']) if TYPE_EXTENSION == 3: DATA_MANIFEST.append('CalcAddIn.xcu') +DATA_DESCRIPTION = { + 'identifier': {'value': ID}, + 'version': {'value': VERSION}, + 'display-name': {k: v['display_name'] for k, v in INFO.items()}, + 'icon': ICON_EXT, + 'publisher': PUBLISHER, + 'update': URL_XML_UPDATE, +} + +DATA_ADDONS = { + 'parent': PARENT, + 'images': DIRS['images'], + 'main': MENU_MAIN, + 'menus': MENUS, +} DATA = { - 'py': FILE_PY, + 'py': DATA_PY, 'manifest': DATA_MANIFEST, - 'description': FILE_DESCRIPTION, - 'addons': FILE_ADDONS, - 'update': FILE_UPDATE, + 'description': DATA_DESCRIPTION, + 'addons': DATA_ADDONS, + 'update': URL_OXT, 'idl': FILE_IDL, 'addin': FILE_ADDIN, - 'shortcut': FILE_SHORTCUTS, } +with open('VERSION', 'w') as f: + f.write(VERSION) + + # ~ LICENSE_ACCEPT_BY = 'user' # or admin # ~ LICENSE_SUPPRESS_ON_UPDATE = True diff --git a/easymacro.py b/easymacro.py index 30e717e..5a75695 100644 --- a/easymacro.py +++ b/easymacro.py @@ -499,6 +499,11 @@ def dict_to_property(values, uno_any=False): return ps +def dict_to_named(values): + ps = tuple([NamedValue(n, v) for n, v in values.items()]) + return ps + + def property_to_dict(values): d = {i.Name: i.Value for i in values} return d @@ -1837,6 +1842,33 @@ class LOCellRange(object): self.sheet.obj.copyRange(self.address, source.range_address) return + def transpose(self, formula=False): + data = self.data + if formula: + data = self.formula + data = tuple(zip(*data)) + self.clear(1023) + self[0,0].copy_from(data, formula=formula) + return + + def transpose2(self): + # ~ 'Flags': 'A', + # ~ 'FormulaCommand': 0, + # ~ 'SkipEmptyCells': False, + # ~ 'AsLink': False, + # ~ 'MoveMode': 4, + args = { + 'Transpose': True, + } + args = dict_to_property(args) + self.select() + copy() + self.clear(1023) + self[0,0].select() + call_dispatch('.uno:InsertContents', args) + set_clipboard('') + return + def offset(self, row=1, col=0): ra = self.obj.getRangeAddress() col = ra.EndColumn + col @@ -1939,6 +1971,10 @@ class LOCellRange(object): def auto_format(self, value): self.obj.autoFormat(value) + def auto_width(self): + self.obj.Columns.OptimalWidth = True + return + def insert_image(self, path, **kwargs): s = self.obj.Size w = kwargs.get('width', s.Width) @@ -2060,6 +2096,22 @@ class LOCellRange(object): found = self.obj.replaceAll(descriptor) return found + @property + def validation(self): + return self.obj.Validation + @validation.setter + def validation(self, values): + is_list = False + current = self.validation + for k, v in values.items(): + if k == 'Type' and v == 6: + is_list = True + if k == 'Formula1' and is_list: + if isinstance(v, (tuple, list)): + v = ';'.join(['"{}"'.format(i) for i in v]) + setattr(current, k, v) + self.obj.Validation = current + class EventsListenerBase(unohelper.Base, XEventListener): @@ -2454,23 +2506,39 @@ class UnoBaseObject(object): return self._model.Width @width.setter def width(self, value): - if hasattr(self.model, 'Width'): - self.model.Width = value - elif hasattr(self.obj, 'PosSize'): - self._set_possize('Width', value) + self.model.Width = value + + @property + def ps_width(self): + return self._get_possize('Width') + @ps_width.setter + def ps_width(self, value): + self._set_possize('Width', value) @property def height(self): - if hasattr(self.model, 'Height'): - return self.model.Height - ps = self.obj.getPosSize() - return ps.Height + return self.model.Height @height.setter def height(self, value): - if hasattr(self.model, 'Height'): - self.model.Height = value - elif hasattr(self.obj, 'PosSize'): - self._set_possize('Height', value) + self.model.Height = value + + @property + def ps_height(self): + return self._get_possize('Height') + @ps_height.setter + def ps_height(self, value): + self._set_possize('Height', value) + + @property + def size(self): + ps = self.obj.getPosSize() + return (ps.Width, ps.Height) + @size.setter + def size(self, value): + ps = self.obj.getPosSize() + ps.Width = value[0] + ps.Height = value[1] + self.obj.setPosSize(ps.X, ps.Y, ps.Width, ps.Height, SIZE) @property def tag(self): @@ -4493,7 +4561,7 @@ def _zippwd(source, target, pwd): # ~ Export ok -def zip(source, target='', mode='w', pwd=''): +def zip_files(source, target='', mode='w', pwd=''): if pwd: return _zippwd(source, target, pwd) diff --git a/files/ZAZBarCode_v0.6.0.oxt b/files/ZAZBarCode_v0.7.0.oxt similarity index 77% rename from files/ZAZBarCode_v0.6.0.oxt rename to files/ZAZBarCode_v0.7.0.oxt index 3ca7495..36d10f2 100644 Binary files a/files/ZAZBarCode_v0.6.0.oxt and b/files/ZAZBarCode_v0.7.0.oxt differ diff --git a/files/zazbarcode.update.xml b/files/zazbarcode.update.xml index 0893f42..f68a62c 100644 --- a/files/zazbarcode.update.xml +++ b/files/zazbarcode.update.xml @@ -1,16 +1,9 @@ - - - - - - - - - - - - - \ No newline at end of file + + + + + + + + + diff --git a/source/Addons.xcu b/source/Addons.xcu index 5d68361..1208786 100644 --- a/source/Addons.xcu +++ b/source/Addons.xcu @@ -1,325 +1,324 @@ - - - + + + - - ZAZ BarCode + + ZAZ BarCode ZAZ BarCode + + + _self + + + + + Insert BarCode + Insertar Código + + + com.sun.star.sheet.SpreadsheetDocument,com.sun.star.text.TextDocument,com.sun.star.presentation.PresentationDocument,com.sun.star.drawing.DrawingDocument + + + service:net.elmau.zaz.BarCode?ask _self - - - - Insert BarCode - Insertar Código - - - service:net.elmau.zaz.BarCode?ask - - - _self - - - com.sun.star.sheet.SpreadsheetDocument,com.sun.star.text.TextDocument,com.sun.star.presentation.PresentationDocument,com.sun.star.drawing.DrawingDocument - - %origin%/images/barcode + %origin%/images/barcode - + - Insert CODE39 - Insertar CODE39 - - - service:net.elmau.zaz.BarCode?code39 - - - _self + Insert CODE39 + Insertar CODE39 - com.sun.star.sheet.SpreadsheetDocument,com.sun.star.text.TextDocument + com.sun.star.sheet.SpreadsheetDocument,com.sun.star.text.TextDocument + + + service:net.elmau.zaz.BarCode?code39 + + + _self - %origin%/images/barcode + %origin%/images/barcode - + - Insert CODE128 - Insertar CODE128 - - - service:net.elmau.zaz.BarCode?code128 - - - _self + Insert CODE128 + Insertar CODE128 - com.sun.star.sheet.SpreadsheetDocument,com.sun.star.text.TextDocument + com.sun.star.sheet.SpreadsheetDocument,com.sun.star.text.TextDocument + + + service:net.elmau.zaz.BarCode?code128 + + + _self - %origin%/images/barcode + %origin%/images/barcode - + - Insert EAN - Insertar EAN - - - service:net.elmau.zaz.BarCode?ean - - - _self + Insert EAN + Insertar EAN - com.sun.star.sheet.SpreadsheetDocument,com.sun.star.text.TextDocument + com.sun.star.sheet.SpreadsheetDocument,com.sun.star.text.TextDocument + + + service:net.elmau.zaz.BarCode?ean + + + _self - %origin%/images/barcode + %origin%/images/barcode - + - Insert EAN8 - Insertar EAN8 - - - service:net.elmau.zaz.BarCode?ean8 - - - _self + Insert EAN8 + Insertar EAN8 - com.sun.star.sheet.SpreadsheetDocument,com.sun.star.text.TextDocument + com.sun.star.sheet.SpreadsheetDocument,com.sun.star.text.TextDocument + + + service:net.elmau.zaz.BarCode?ean8 + + + _self - %origin%/images/barcode + %origin%/images/barcode - + - Insert EAN13 - Insertar EAN13 - - - service:net.elmau.zaz.BarCode?ean13 - - - _self + Insert EAN13 + Insertar EAN13 - com.sun.star.sheet.SpreadsheetDocument,com.sun.star.text.TextDocument + com.sun.star.sheet.SpreadsheetDocument,com.sun.star.text.TextDocument + + + service:net.elmau.zaz.BarCode?ean13 + + + _self - %origin%/images/barcode + %origin%/images/barcode - + - Insert GS1 - Insertar GS1 - - - service:net.elmau.zaz.BarCode?gs1 - - - _self + Insert GS1 + Insertar GS1 - com.sun.star.sheet.SpreadsheetDocument,com.sun.star.text.TextDocument + com.sun.star.sheet.SpreadsheetDocument,com.sun.star.text.TextDocument + + + service:net.elmau.zaz.BarCode?gs1 + + + _self - %origin%/images/barcode + %origin%/images/barcode - + - Insert GTIN - Insertar GTIN - - - service:net.elmau.zaz.BarCode?gtin - - - _self + Insert GTIN + Insertar GTIN - com.sun.star.sheet.SpreadsheetDocument,com.sun.star.text.TextDocument + com.sun.star.sheet.SpreadsheetDocument,com.sun.star.text.TextDocument + + + service:net.elmau.zaz.BarCode?gtin + + + _self - %origin%/images/barcode + %origin%/images/barcode - + - Insert ISBN - Insertar ISBN - - - service:net.elmau.zaz.BarCode?isbn - - - _self + Insert ISBN + Insertar ISBN - com.sun.star.sheet.SpreadsheetDocument,com.sun.star.text.TextDocument + com.sun.star.sheet.SpreadsheetDocument,com.sun.star.text.TextDocument + + + service:net.elmau.zaz.BarCode?isbn + + + _self - %origin%/images/barcode + %origin%/images/barcode - + - Insert ISBN10 - Insertar ISBN10 - - - service:net.elmau.zaz.BarCode?isbn10 - - - _self + Insert ISBN10 + Insertar ISBN10 - com.sun.star.sheet.SpreadsheetDocument,com.sun.star.text.TextDocument + com.sun.star.sheet.SpreadsheetDocument,com.sun.star.text.TextDocument + + + service:net.elmau.zaz.BarCode?isbn10 + + + _self - %origin%/images/barcode + %origin%/images/barcode - + - Insert ISBN13 - Insertar ISBN13 - - - service:net.elmau.zaz.BarCode?isbn13 - - - _self + Insert ISBN13 + Insertar ISBN13 - com.sun.star.sheet.SpreadsheetDocument,com.sun.star.text.TextDocument + com.sun.star.sheet.SpreadsheetDocument,com.sun.star.text.TextDocument + + + service:net.elmau.zaz.BarCode?isbn13 + + + _self - %origin%/images/barcode + %origin%/images/barcode - + - Insert ISSN - Insertar ISSN - - - service:net.elmau.zaz.BarCode?issn - - - _self + Insert ISSN + Insertar ISSN - com.sun.star.sheet.SpreadsheetDocument,com.sun.star.text.TextDocument + com.sun.star.sheet.SpreadsheetDocument,com.sun.star.text.TextDocument + + + service:net.elmau.zaz.BarCode?issn + + + _self - %origin%/images/barcode + %origin%/images/barcode - + - Insert JAN - Insertar JAN - - - service:net.elmau.zaz.BarCode?jan - - - _self + Insert JAN + Insertar JAN - com.sun.star.sheet.SpreadsheetDocument,com.sun.star.text.TextDocument + com.sun.star.sheet.SpreadsheetDocument,com.sun.star.text.TextDocument + + + service:net.elmau.zaz.BarCode?jan + + + _self - %origin%/images/barcode + %origin%/images/barcode - + - Insert PZN - Insertar PZN - - - service:net.elmau.zaz.BarCode?pzn - - - _self + Insert PZN + Insertar PZN - com.sun.star.sheet.SpreadsheetDocument,com.sun.star.text.TextDocument + com.sun.star.sheet.SpreadsheetDocument,com.sun.star.text.TextDocument + + + service:net.elmau.zaz.BarCode?pzn + + + _self - %origin%/images/barcode + %origin%/images/barcode - + - Insert UPC - Insertar UPC - - - service:net.elmau.zaz.BarCode?upc - - - _self + Insert UPC + Insertar UPC - com.sun.star.sheet.SpreadsheetDocument,com.sun.star.text.TextDocument + com.sun.star.sheet.SpreadsheetDocument,com.sun.star.text.TextDocument + + + service:net.elmau.zaz.BarCode?upc + + + _self - %origin%/images/barcode + %origin%/images/barcode - + - Insert UPCA - Insertar UPCA - - - service:net.elmau.zaz.BarCode?upca - - - _self + Insert UPCA + Insertar UPCA - com.sun.star.sheet.SpreadsheetDocument,com.sun.star.text.TextDocument + com.sun.star.sheet.SpreadsheetDocument,com.sun.star.text.TextDocument + + + service:net.elmau.zaz.BarCode?upca + + + _self - %origin%/images/barcode + %origin%/images/barcode - + - Insert QRCODE - Insertar QRCODE - - - service:net.elmau.zaz.BarCode?qrcode - - - _self + Insert QRCODE + Insertar QRCODE - com.sun.star.sheet.SpreadsheetDocument,com.sun.star.text.TextDocument + com.sun.star.sheet.SpreadsheetDocument,com.sun.star.text.TextDocument + + + service:net.elmau.zaz.BarCode?qrcode + + + _self - %origin%/images/barcode + %origin%/images/barcode - + - - + diff --git a/source/Office/Accelerators.xcu b/source/Office/Accelerators.xcu index d290b14..3db9b03 100644 --- a/source/Office/Accelerators.xcu +++ b/source/Office/Accelerators.xcu @@ -1,9 +1,5 @@ - - + + diff --git a/source/description.xml b/source/description.xml index 6d95b82..0195747 100644 --- a/source/description.xml +++ b/source/description.xml @@ -1,29 +1,29 @@ - + - - + + ZAZ Bar Code ZAZ Códigos de Barras - - + + - + El Mau El Mau - - - + + + - - - + + + diff --git a/source/pythonpath/barcode/__init__.py b/source/pythonpath/barcode/__init__.py old mode 100644 new mode 100755 index 427d094..571fdea --- a/source/pythonpath/barcode/__init__.py +++ b/source/pythonpath/barcode/__init__.py @@ -1,57 +1,73 @@ -# -*- coding: utf-8 -*- - -""" - -pyBarcode -========= - -This package provides a simple way to create standard barcodes. +"""This package provides a simple way to create standard barcodes. It needs no external packages to be installed, the barcodes are created as SVG objects. If Pillow is installed, the barcodes can also be rendered as images (all formats supported by Pillow). """ +import os +from typing import BinaryIO +from typing import Dict +from typing import Union +from barcode.codex import Code128 +from barcode.codex import Code39 +from barcode.codex import Gs1_128 +from barcode.codex import PZN +from barcode.ean import EAN13 +from barcode.ean import EAN14 +from barcode.ean import EAN8 +from barcode.ean import JAN from barcode.errors import BarcodeNotFoundError -from barcode.codex import Code39, PZN, Code128, Gs1_128 -from barcode.ean import EAN8, EAN13, EAN14, JAN -from barcode.isxn import ISBN10, ISBN13, ISSN -from barcode.upc import UPCA +from barcode.isxn import ISBN10 +from barcode.isxn import ISBN13 +from barcode.isxn import ISSN from barcode.itf import ITF +from barcode.upc import UPCA from barcode.version import version # noqa: F401 - -__BARCODE_MAP = dict( - ean8=EAN8, - ean13=EAN13, - ean=EAN13, - gtin=EAN14, - ean14=EAN14, - jan=JAN, - upc=UPCA, - upca=UPCA, - isbn=ISBN13, - isbn13=ISBN13, - gs1=ISBN13, - isbn10=ISBN10, - issn=ISSN, - code39=Code39, - pzn=PZN, - code128=Code128, - itf=ITF, - gs1_128=Gs1_128, -) +__BARCODE_MAP = { + "ean8": EAN8, + "ean13": EAN13, + "ean": EAN13, + "gtin": EAN14, + "ean14": EAN14, + "jan": JAN, + "upc": UPCA, + "upca": UPCA, + "isbn": ISBN13, + "isbn13": ISBN13, + "gs1": ISBN13, + "isbn10": ISBN10, + "issn": ISSN, + "code39": Code39, + "pzn": PZN, + "code128": Code128, + "itf": ITF, + "gs1_128": Gs1_128, +} PROVIDED_BARCODES = list(__BARCODE_MAP) PROVIDED_BARCODES.sort() def get(name, code=None, writer=None, options=None): + """Helper method for getting a generator or even a generated code. + + :param str name: The name of the type of barcode desired. + :param str code: The actual information to encode. If this parameter is + provided, a generated barcode is returned. Otherwise, the barcode class + is returned. + :param Writer writer: An alternative writer to use when generating the + barcode. + :param dict options: Additional options to be passed on to the barcode when + generating. + """ options = options or {} try: barcode = __BARCODE_MAP[name.lower()] except KeyError: - raise BarcodeNotFoundError('The barcode {0!r} you requested is not ' - 'known.'.format(name)) + raise BarcodeNotFoundError( + "The barcode {!r} you requested is not known.".format(name) + ) if code is not None: return barcode(code, writer, **options) else: @@ -62,17 +78,38 @@ def get_class(name): return get_barcode(name) -def generate(name, code, writer=None, output=None, writer_options=None, - text=None, pil=False): - options = writer_options or {} - barcode = get(name, code, writer, options) - if pil: - return barcode.render(writer_options, text) +def generate( + name: str, + code: str, + writer=None, + output: Union[str, os.PathLike, BinaryIO] = None, + writer_options: Dict = None, + text: str = None, +): + """Shortcut to generate a barcode in one line. + + :param name: Name of the type of barcode to use. + :param code: Data to encode into the barcode. + :param writer: A writer to use (e.g.: ImageWriter or SVGWriter). + :param output: Destination file-like or path-like where to save the generated + barcode. + :param writer_options: Options to pass on to the writer instance. + :param text: Text to render under the barcode. + """ + from barcode.base import Barcode + + writer = writer or Barcode.default_writer() + writer.set_options(writer_options or {}) + + barcode = get(name, code, writer) + if isinstance(output, str): - fullname = barcode.save(output, options, text) + fullname = barcode.save(output, writer_options, text) return fullname + elif output: + barcode.write(output, writer_options, text) else: - barcode.write(output, options, text) + raise TypeError("'output' cannot be None") get_barcode = get diff --git a/source/pythonpath/barcode/base.py b/source/pythonpath/barcode/base.py old mode 100644 new mode 100755 index 6a42bf5..7b7b0fe --- a/source/pythonpath/barcode/base.py +++ b/source/pythonpath/barcode/base.py @@ -1,43 +1,37 @@ -# -*- coding: utf-8 -*- - -from __future__ import unicode_literals - """barcode.base """ - from barcode.writer import SVGWriter -class Barcode(object): +class Barcode: - name = '' + name = "" digits = 0 default_writer = SVGWriter default_writer_options = { - 'module_width': 0.2, - 'module_height': 15.0, - 'quiet_zone': 6.5, - 'font_size': 10, - 'text_distance': 5.0, - 'background': 'white', - 'foreground': 'black', - 'write_text': True, - 'text': '', + "module_width": 0.2, + "module_height": 15.0, + "quiet_zone": 6.5, + "font_size": 10, + "text_distance": 5.0, + "background": "white", + "foreground": "black", + "write_text": True, + "text": "", } def to_ascii(self): code = self.build() for i, line in enumerate(code): - code[i] = line.replace('1', 'X').replace('0', ' ') - return '\n'.join(code) + code[i] = line.replace("1", "X").replace("0", " ") + return "\n".join(code) def __repr__(self): - return '<{0}({1!r})>'.format(self.__class__.__name__, - self.get_fullcode()) + return "<{}({!r})>".format(self.__class__.__name__, self.get_fullcode()) def build(self): raise NotImplementedError @@ -59,7 +53,7 @@ class Barcode(object): extension). options : Dict The same as in `self.render`. - text : str (unicode on Python 2) + text : str Text to render under the barcode. :returns: The full filename with extension. @@ -82,14 +76,11 @@ class Barcode(object): Object to write the raw data in. options : Dict The same as in `self.render`. - text : str (unicode on Python 2) + text : str Text to render under the barcode. """ output = self.render(options, text) - if hasattr(output, 'tostring'): - output.save(fp, format=self.writer.format) - else: - fp.write(output) + self.writer.write(output, fp) def render(self, writer_options=None, text=None): """Renders the barcode using `self.writer`. @@ -97,18 +88,18 @@ class Barcode(object): :parameters: writer_options : Dict Options for `self.writer`, see writer docs for details. - text : str (unicode on Python 2) + text : str Text to render under the barcode. :returns: Output of the writers render method. """ options = Barcode.default_writer_options.copy() options.update(writer_options or {}) - if options['write_text'] or text is not None: + if options["write_text"] or text is not None: if text is not None: - options['text'] = text + options["text"] = text else: - options['text'] = self.get_fullcode() + options["text"] = self.get_fullcode() self.writer.set_options(options) code = self.build() raw = self.writer.render(code) diff --git a/source/pythonpath/barcode/charsets/code128.py b/source/pythonpath/barcode/charsets/code128.py index 5132e29..4941aa2 100644 --- a/source/pythonpath/barcode/charsets/code128.py +++ b/source/pythonpath/barcode/charsets/code128.py @@ -1,64 +1,223 @@ -# -*- coding: utf-8 -*- - -from __future__ import unicode_literals - import string # Charsets for code 128 _common = ( - ' ', '!', '"', '#', '$', '%', '&', "'", '(', ')', '*', '+', ',', - '-', '.', '/', -) + tuple(string.digits) + ( - ':', ';', '<', '=', '>', '?', '@', -) + tuple(string.ascii_uppercase) + ( - '[', '\\', ']', '^', '_', + ( + " ", + "!", + '"', + "#", + "$", + "%", + "&", + "'", + "(", + ")", + "*", + "+", + ",", + "-", + ".", + "/", + ) + + tuple(string.digits) + + ( + ":", + ";", + "<", + "=", + ">", + "?", + "@", + ) + + tuple(string.ascii_uppercase) + + ( + "[", + "\\", + "]", + "^", + "_", + ) ) _charset_a = _common + ( - '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', '\x08', - '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f', '\x10', '\x11', - '\x12', '\x13', '\x14', '\x15', '\x16', '\x17', '\x18', '\x19', '\x1a', - '\x1b', '\x1c', '\x1d', '\x1e', '\x1f', '\xf3', '\xf2', 'SHIFT', 'TO_C', - 'TO_B', '\xf4', '\xf1', + "\x00", + "\x01", + "\x02", + "\x03", + "\x04", + "\x05", + "\x06", + "\x07", + "\x08", + "\x09", + "\x0a", + "\x0b", + "\x0c", + "\x0d", + "\x0e", + "\x0f", + "\x10", + "\x11", + "\x12", + "\x13", + "\x14", + "\x15", + "\x16", + "\x17", + "\x18", + "\x19", + "\x1a", + "\x1b", + "\x1c", + "\x1d", + "\x1e", + "\x1f", + "\xf3", + "\xf2", + "SHIFT", + "TO_C", + "TO_B", + "\xf4", + "\xf1", ) -_charset_b = _common + ('`',) + tuple(string.ascii_lowercase) + ( - '{', '|', '}', '~', '\x7f', '\xf3', '\xf2', 'SHIFT', 'TO_C', '\xf4', - 'TO_A', '\xf1', +_charset_b = ( + _common + + ("`",) + + tuple(string.ascii_lowercase) + + ( + "{", + "|", + "}", + "~", + "\x7f", + "\xf3", + "\xf2", + "SHIFT", + "TO_C", + "\xf4", + "TO_A", + "\xf1", + ) ) ALL = set(_common + _charset_a + _charset_b) -A = dict(((c, i) for i, c in enumerate(_charset_a))) -B = dict(((c, i) for i, c in enumerate(_charset_b))) -C = {'TO_B': 100, 'TO_A': 101, '\xf1': 102} +A = {c: i for i, c in enumerate(_charset_a)} +B = {c: i for i, c in enumerate(_charset_b)} +C = {"TO_B": 100, "TO_A": 101, "\xf1": 102} CODES = ( - '11011001100', '11001101100', '11001100110', '10010011000', '10010001100', - '10001001100', '10011001000', '10011000100', '10001100100', '11001001000', - '11001000100', '11000100100', '10110011100', '10011011100', '10011001110', - '10111001100', '10011101100', '10011100110', '11001110010', '11001011100', - '11001001110', '11011100100', '11001110100', '11101101110', '11101001100', - '11100101100', '11100100110', '11101100100', '11100110100', '11100110010', - '11011011000', '11011000110', '11000110110', '10100011000', '10001011000', - '10001000110', '10110001000', '10001101000', '10001100010', '11010001000', - '11000101000', '11000100010', '10110111000', '10110001110', '10001101110', - '10111011000', '10111000110', '10001110110', '11101110110', '11010001110', - '11000101110', '11011101000', '11011100010', '11011101110', '11101011000', - '11101000110', '11100010110', '11101101000', '11101100010', '11100011010', - '11101111010', '11001000010', '11110001010', '10100110000', '10100001100', - '10010110000', '10010000110', '10000101100', '10000100110', '10110010000', - '10110000100', '10011010000', '10011000010', '10000110100', '10000110010', - '11000010010', '11001010000', '11110111010', '11000010100', '10001111010', - '10100111100', '10010111100', '10010011110', '10111100100', '10011110100', - '10011110010', '11110100100', '11110010100', '11110010010', '11011011110', - '11011110110', '11110110110', '10101111000', '10100011110', '10001011110', - '10111101000', '10111100010', '11110101000', '11110100010', '10111011110', - '10111101110', '11101011110', '11110101110', '11010000100', '11010010000', - '11010011100', + "11011001100", + "11001101100", + "11001100110", + "10010011000", + "10010001100", + "10001001100", + "10011001000", + "10011000100", + "10001100100", + "11001001000", + "11001000100", + "11000100100", + "10110011100", + "10011011100", + "10011001110", + "10111001100", + "10011101100", + "10011100110", + "11001110010", + "11001011100", + "11001001110", + "11011100100", + "11001110100", + "11101101110", + "11101001100", + "11100101100", + "11100100110", + "11101100100", + "11100110100", + "11100110010", + "11011011000", + "11011000110", + "11000110110", + "10100011000", + "10001011000", + "10001000110", + "10110001000", + "10001101000", + "10001100010", + "11010001000", + "11000101000", + "11000100010", + "10110111000", + "10110001110", + "10001101110", + "10111011000", + "10111000110", + "10001110110", + "11101110110", + "11010001110", + "11000101110", + "11011101000", + "11011100010", + "11011101110", + "11101011000", + "11101000110", + "11100010110", + "11101101000", + "11101100010", + "11100011010", + "11101111010", + "11001000010", + "11110001010", + "10100110000", + "10100001100", + "10010110000", + "10010000110", + "10000101100", + "10000100110", + "10110010000", + "10110000100", + "10011010000", + "10011000010", + "10000110100", + "10000110010", + "11000010010", + "11001010000", + "11110111010", + "11000010100", + "10001111010", + "10100111100", + "10010111100", + "10010011110", + "10111100100", + "10011110100", + "10011110010", + "11110100100", + "11110010100", + "11110010010", + "11011011110", + "11011110110", + "11110110110", + "10101111000", + "10100011110", + "10001011110", + "10111101000", + "10111100010", + "11110101000", + "11110100010", + "10111011110", + "10111101110", + "11101011110", + "11110101110", + "11010000100", + "11010010000", + "11010011100", ) -STOP = '11000111010' +STOP = "11000111010" -START_CODES = {'A': 103, 'B': 104, 'C': 105} -TO = {101: START_CODES['A'], 100: START_CODES['B'], 99: START_CODES['C']} +START_CODES = {"A": 103, "B": 104, "C": 105} +TO = {101: START_CODES["A"], 100: START_CODES["B"], 99: START_CODES["C"]} diff --git a/source/pythonpath/barcode/charsets/code39.py b/source/pythonpath/barcode/charsets/code39.py index 4031f65..d9f679d 100644 --- a/source/pythonpath/barcode/charsets/code39.py +++ b/source/pythonpath/barcode/charsets/code39.py @@ -1,34 +1,61 @@ -# -*- coding: utf-8 -*- - -from __future__ import unicode_literals - import string # Charsets for code 39 -REF = (tuple(string.digits) + tuple(string.ascii_uppercase) + - ('-', '.', ' ', '$', '/', '+', '%')) -B = '1' -E = '0' +REF = ( + tuple(string.digits) + + tuple(string.ascii_uppercase) + + ("-", ".", " ", "$", "/", "+", "%") +) +B = "1" +E = "0" CODES = ( - '101000111011101', '111010001010111', '101110001010111', - '111011100010101', '101000111010111', '111010001110101', - '101110001110101', '101000101110111', '111010001011101', - '101110001011101', '111010100010111', '101110100010111', - '111011101000101', '101011100010111', '111010111000101', - '101110111000101', '101010001110111', '111010100011101', - '101110100011101', '101011100011101', '111010101000111', - '101110101000111', '111011101010001', '101011101000111', - '111010111010001', '101110111010001', '101010111000111', - '111010101110001', '101110101110001', '101011101110001', - '111000101010111', '100011101010111', '111000111010101', - '100010111010111', '111000101110101', '100011101110101', - '100010101110111', '111000101011101', '100011101011101', - '100010001000101', '100010001010001', '100010100010001', - '101000100010001', + "101000111011101", + "111010001010111", + "101110001010111", + "111011100010101", + "101000111010111", + "111010001110101", + "101110001110101", + "101000101110111", + "111010001011101", + "101110001011101", + "111010100010111", + "101110100010111", + "111011101000101", + "101011100010111", + "111010111000101", + "101110111000101", + "101010001110111", + "111010100011101", + "101110100011101", + "101011100011101", + "111010101000111", + "101110101000111", + "111011101010001", + "101011101000111", + "111010111010001", + "101110111010001", + "101010111000111", + "111010101110001", + "101110101110001", + "101011101110001", + "111000101010111", + "100011101010111", + "111000111010101", + "100010111010111", + "111000101110101", + "100011101110101", + "100010101110111", + "111000101011101", + "100011101011101", + "100010001000101", + "100010001010001", + "100010100010001", + "101000100010001", ) -EDGE = '100010111011101' -MIDDLE = '0' +EDGE = "100010111011101" +MIDDLE = "0" # MAP for assigning every symbol (REF) to (reference number, barcode) MAP = dict(zip(REF, enumerate(CODES))) diff --git a/source/pythonpath/barcode/charsets/ean.py b/source/pythonpath/barcode/charsets/ean.py index 951028a..199142d 100644 --- a/source/pythonpath/barcode/charsets/ean.py +++ b/source/pythonpath/barcode/charsets/ean.py @@ -1,17 +1,52 @@ -# -*- coding: utf-8 -*- - -from __future__ import unicode_literals - - -EDGE = '101' -MIDDLE = '01010' +EDGE = "101" +MIDDLE = "01010" CODES = { - 'A': ('0001101', '0011001', '0010011', '0111101', '0100011', - '0110001', '0101111', '0111011', '0110111', '0001011'), - 'B': ('0100111', '0110011', '0011011', '0100001', '0011101', - '0111001', '0000101', '0010001', '0001001', '0010111'), - 'C': ('1110010', '1100110', '1101100', '1000010', '1011100', - '1001110', '1010000', '1000100', '1001000', '1110100'), + "A": ( + "0001101", + "0011001", + "0010011", + "0111101", + "0100011", + "0110001", + "0101111", + "0111011", + "0110111", + "0001011", + ), + "B": ( + "0100111", + "0110011", + "0011011", + "0100001", + "0011101", + "0111001", + "0000101", + "0010001", + "0001001", + "0010111", + ), + "C": ( + "1110010", + "1100110", + "1101100", + "1000010", + "1011100", + "1001110", + "1010000", + "1000100", + "1001000", + "1110100", + ), } -LEFT_PATTERN = ('AAAAAA', 'AABABB', 'AABBAB', 'AABBBA', 'ABAABB', - 'ABBAAB', 'ABBBAA', 'ABABAB', 'ABABBA', 'ABBABA') +LEFT_PATTERN = ( + "AAAAAA", + "AABABB", + "AABBAB", + "AABBBA", + "ABAABB", + "ABBAAB", + "ABBBAA", + "ABABAB", + "ABABBA", + "ABBABA", +) diff --git a/source/pythonpath/barcode/charsets/itf.py b/source/pythonpath/barcode/charsets/itf.py index 988db00..24eb02f 100644 --- a/source/pythonpath/barcode/charsets/itf.py +++ b/source/pythonpath/barcode/charsets/itf.py @@ -1,12 +1,19 @@ -# -*- coding: utf-8 -*- - -from __future__ import unicode_literals - # W = Wide bar # w = wide space # N = Narrow bar # n = narrow space -START = 'NnNn' -STOP = 'WnN' -CODES = ('NNWWN', 'WNNNW', 'NWNNW', 'WWNNN', 'NNWNW', 'WNWNN', 'NWWNN', 'NNNWW', 'WNNWN', 'NWNWN') +START = "NnNn" +STOP = "WnN" +CODES = ( + "NNWWN", + "WNNNW", + "NWNNW", + "WWNNN", + "NNWNW", + "WNWNN", + "NWWNN", + "NNNWW", + "WNNWN", + "NWNWN", +) diff --git a/source/pythonpath/barcode/charsets/upc.py b/source/pythonpath/barcode/charsets/upc.py index 9b625c7..df90deb 100644 --- a/source/pythonpath/barcode/charsets/upc.py +++ b/source/pythonpath/barcode/charsets/upc.py @@ -1,13 +1,28 @@ -# -*- coding: utf-8 -*- - -from __future__ import unicode_literals - - -EDGE = '101' -MIDDLE = '01010' +EDGE = "101" +MIDDLE = "01010" CODES = { - 'L': ('0001101', '0011001', '0010011', '0111101', '0100011', - '0110001', '0101111', '0111011', '0110111', '0001011'), - 'R': ('1110010', '1100110', '1101100', '1000010', '1011100', - '1001110', '1010000', '1000100', '1001000', '1110100') + "L": ( + "0001101", + "0011001", + "0010011", + "0111101", + "0100011", + "0110001", + "0101111", + "0111011", + "0110111", + "0001011", + ), + "R": ( + "1110010", + "1100110", + "1101100", + "1000010", + "1011100", + "1001110", + "1010000", + "1000100", + "1001000", + "1110100", + ), } diff --git a/source/pythonpath/barcode/codex.py b/source/pythonpath/barcode/codex.py old mode 100644 new mode 100755 index c747175..870c8c2 --- a/source/pythonpath/barcode/codex.py +++ b/source/pythonpath/barcode/codex.py @@ -1,17 +1,15 @@ -# -*- coding: utf-8 -*- - -from __future__ import unicode_literals - -from barcode.base import Barcode -from barcode.charsets import code128, code39 -from barcode.errors import * - """Module: barcode.codex :Provided barcodes: Code 39, Code 128, PZN """ -__docformat__ = 'restructuredtext en' +from barcode.base import Barcode +from barcode.charsets import code128 +from barcode.charsets import code39 +from barcode.errors import BarcodeError +from barcode.errors import IllegalCharacterError +from barcode.errors import NumberOfDigitsError +__docformat__ = "restructuredtext en" # Sizes MIN_SIZE = 0.2 @@ -25,43 +23,40 @@ def check_code(code, name, allowed): wrong.append(char) if wrong: raise IllegalCharacterError( - 'The following characters are not valid for ' - '{name}: {wrong}'.format(name=name, wrong=', '.join(wrong)) + "The following characters are not valid for {name}: {wrong}".format( + name=name, wrong=", ".join(wrong) + ) ) class Code39(Barcode): - """Initializes a new Code39 instance. + """A Code39 barcode implementation""" - :parameters: - code : String - Code 39 string without \* and checksum (added automatically if - `add_checksum` is True). - writer : barcode.writer Instance - The writer to render the barcode (default: SVGWriter). - add_checksum : Boolean - Add the checksum to code or not (default: True). - """ + name = "Code 39" - name = 'Code 39' + def __init__(self, code: str, writer=None, add_checksum: bool = True): + r""" + :param code: Code 39 string without \* and without checksum. + :param writer: A ``barcode.writer`` instance used to render the barcode + (default: SVGWriter). + :param add_checksum: Add the checksum to code or not + """ - def __init__(self, code, writer=None, add_checksum=True): self.code = code.upper() if add_checksum: self.code += self.calculate_checksum() self.writer = writer or Barcode.default_writer() check_code(self.code, self.name, code39.REF) - def __unicode__(self): + def __str__(self): return self.code - __str__ = __unicode__ - - def get_fullcode(self): + def get_fullcode(self) -> str: + """:returns: The full code as it will be encoded.""" return self.code def calculate_checksum(self): - check = sum([code39.MAP[x][0] for x in self.code]) % 43 + check = sum(code39.MAP[x][0] for x in self.code) % 43 for k, v in code39.MAP.items(): if check == v[0]: return k @@ -74,7 +69,7 @@ class Code39(Barcode): return [code39.MIDDLE.join(chars)] def render(self, writer_options=None, text=None): - options = dict(module_width=MIN_SIZE, quiet_zone=MIN_QUIET_ZONE) + options = {"module_width": MIN_SIZE, "quiet_zone": MIN_QUIET_ZONE} options.update(writer_options or {}) return Barcode.render(self, options, text) @@ -89,30 +84,30 @@ class PZN7(Code39): The writer to render the barcode (default: SVGWriter). """ - name = 'Pharmazentralnummer' + name = "Pharmazentralnummer" digits = 6 def __init__(self, pzn, writer=None): - pzn = pzn[:self.digits] + pzn = pzn[: self.digits] if not pzn.isdigit(): - raise IllegalCharacterError('PZN can only contain numbers.') + raise IllegalCharacterError("PZN can only contain numbers.") if len(pzn) != self.digits: - raise NumberOfDigitsError('PZN must have {0} digits, not ' - '{1}.'.format(self.digits, len(pzn))) + raise NumberOfDigitsError( + "PZN must have {} digits, not {}.".format(self.digits, len(pzn)) + ) self.pzn = pzn - self.pzn = '{0}{1}'.format(pzn, self.calculate_checksum()) - Code39.__init__(self, 'PZN-{0}'.format(self.pzn), writer, - add_checksum=False) + self.pzn = "{}{}".format(pzn, self.calculate_checksum()) + Code39.__init__(self, "PZN-{}".format(self.pzn), writer, add_checksum=False) def get_fullcode(self): - return 'PZN-{0}'.format(self.pzn) + return "PZN-{}".format(self.pzn) def calculate_checksum(self): - sum_ = sum([int(x) * int(y) for x, y in enumerate(self.pzn, start=2)]) + sum_ = sum(int(x) * int(y) for x, y in enumerate(self.pzn, start=2)) checksum = sum_ % 11 if checksum == 10: - raise BarcodeError('Checksum can not be 10 for PZN.') + raise BarcodeError("Checksum can not be 10 for PZN.") else: return checksum @@ -134,20 +129,18 @@ class Code128(Barcode): The writer to render the barcode (default: SVGWriter). """ - name = 'Code 128' + name = "Code 128" def __init__(self, code, writer=None): self.code = code self.writer = writer or Barcode.default_writer() - self._charset = 'B' - self._buffer = '' + self._charset = "B" + self._buffer = "" check_code(self.code, self.name, code128.ALL) - def __unicode__(self): + def __str__(self): return self.code - __str__ = __unicode__ - @property def encoded(self): return self._build() @@ -156,18 +149,18 @@ class Code128(Barcode): return self.code def _new_charset(self, which): - if which == 'A': - code = self._convert('TO_A') - elif which == 'B': - code = self._convert('TO_B') - elif which == 'C': - code = self._convert('TO_C') + if which == "A": + code = self._convert("TO_A") + elif which == "B": + code = self._convert("TO_B") + elif which == "C": + code = self._convert("TO_C") self._charset = which return [code] def _maybe_switch_charset(self, pos): char = self.code[pos] - next_ = self.code[pos:pos + 10] + next_ = self.code[pos : pos + 10] def look_next(): digits = 0 @@ -176,44 +169,44 @@ class Code128(Barcode): digits += 1 else: break - return digits > 3 + return digits > 3 and (digits % 2) == 0 codes = [] - if self._charset == 'C' and not char.isdigit(): + if self._charset == "C" and not char.isdigit(): if char in code128.B: - codes = self._new_charset('B') + codes = self._new_charset("B") elif char in code128.A: - codes = self._new_charset('A') + codes = self._new_charset("A") if len(self._buffer) == 1: codes.append(self._convert(self._buffer[0])) - self._buffer = '' - elif self._charset == 'B': + self._buffer = "" + elif self._charset == "B": if look_next(): - codes = self._new_charset('C') + codes = self._new_charset("C") elif char not in code128.B: if char in code128.A: - codes = self._new_charset('A') - elif self._charset == 'A': + codes = self._new_charset("A") + elif self._charset == "A": if look_next(): - codes = self._new_charset('C') + codes = self._new_charset("C") elif char not in code128.A: if char in code128.B: - codes = self._new_charset('B') + codes = self._new_charset("B") return codes def _convert(self, char): - if self._charset == 'A': + if self._charset == "A": return code128.A[char] - elif self._charset == 'B': + elif self._charset == "B": return code128.B[char] - elif self._charset == 'C': + elif self._charset == "C": if char in code128.C: return code128.C[char] elif char.isdigit(): self._buffer += char if len(self._buffer) == 2: value = int(self._buffer) - self._buffer = '' + self._buffer = "" return value def _try_to_optimize(self, encoded): @@ -236,24 +229,24 @@ class Code128(Barcode): encoded.append(code_num) # Finally look in the buffer if len(self._buffer) == 1: - encoded.extend(self._new_charset('B')) + encoded.extend(self._new_charset("B")) encoded.append(self._convert(self._buffer[0])) - self._buffer = '' + self._buffer = "" encoded = self._try_to_optimize(encoded) return encoded def build(self): encoded = self._build() encoded.append(self._calculate_checksum(encoded)) - code = '' + code = "" for code_num in encoded: code += code128.CODES[code_num] code += code128.STOP - code += '11' + code += "11" return [code] def render(self, writer_options=None, text=None): - options = dict(module_width=MIN_SIZE, quiet_zone=MIN_QUIET_ZONE) + options = {"module_width": MIN_SIZE, "quiet_zone": MIN_QUIET_ZONE} options.update(writer_options or {}) return Barcode.render(self, options, text) @@ -266,16 +259,16 @@ class Gs1_128(Code128): https://www.gs1-128.info/ """ - name = 'GS1-128' + name = "GS1-128" - FNC1_CHAR = '\xf1' + FNC1_CHAR = "\xf1" def __init__(self, code, writer=None): code = self.FNC1_CHAR + code - super(Gs1_128, self).__init__(code, writer) + super().__init__(code, writer) def get_fullcode(self): - return super(Gs1_128, self).get_fullcode()[1:] + return super().get_fullcode()[1:] # For pre 0.8 compatibility diff --git a/source/pythonpath/barcode/ean.py b/source/pythonpath/barcode/ean.py old mode 100644 new mode 100755 index f3a447c..0b4ab5b --- a/source/pythonpath/barcode/ean.py +++ b/source/pythonpath/barcode/ean.py @@ -1,27 +1,32 @@ -# -*- coding: utf-8 -*- - -from __future__ import unicode_literals - -from barcode.base import Barcode -from barcode.charsets import ean as _ean -from barcode.errors import * - """Module: barcode.ean :Provided barcodes: EAN-14, EAN-13, EAN-8, JAN """ -__docformat__ = 'restructuredtext en' +__docformat__ = "restructuredtext en" -# Python 3 -try: - reduce -except NameError: - from functools import reduce +from functools import reduce +from barcode.base import Barcode +from barcode.charsets import ean as _ean +from barcode.errors import ( + IllegalCharacterError, + NumberOfDigitsError, + WrongCountryCodeError, +) # EAN13 Specs (all sizes in mm) -SIZES = dict(SC0=0.27, SC1=0.297, SC2=0.33, SC3=0.363, SC4=0.396, SC5=0.445, - SC6=0.495, SC7=0.544, SC8=0.61, SC9=0.66) +SIZES = { + "SC0": 0.27, + "SC1": 0.297, + "SC2": 0.33, + "SC3": 0.363, + "SC4": 0.396, + "SC5": 0.445, + "SC6": 0.495, + "SC7": 0.544, + "SC8": 0.61, + "SC9": 0.66, +} class EuropeanArticleNumber13(Barcode): @@ -34,37 +39,36 @@ class EuropeanArticleNumber13(Barcode): The writer to render the barcode (default: SVGWriter). """ - name = 'EAN-13' + name = "EAN-13" digits = 12 - def __init__(self, ean, writer=None, **kwargs): - no_checksum = False - if "no_checksum" in kwargs.keys(): - no_checksum = kwargs["no_checksum"] - ean = ean[:self.digits] + def __init__(self, ean, writer=None, no_checksum=False): + ean = ean[: self.digits] if not ean.isdigit(): - raise IllegalCharacterError('EAN code can only contain numbers.') + raise IllegalCharacterError("EAN code can only contain numbers.") if len(ean) != self.digits: - raise NumberOfDigitsError('EAN must have {0} digits, not ' - '{1}.'.format(self.digits, len(ean))) + raise NumberOfDigitsError( + "EAN must have {} digits, not {}.".format( + self.digits, + len(ean), + ) + ) self.ean = ean # If no checksum if no_checksum: # Add a thirteen char if given in parameter, # otherwise pad with zero - self.ean = '{0}{1}'.format( + self.ean = "{}{}".format( ean, ean[self.digits] if len(ean) > self.digits else 0 ) else: - self.ean = '{0}{1}'.format(ean, self.calculate_checksum()) + self.ean = "{}{}".format(ean, self.calculate_checksum()) self.writer = writer or Barcode.default_writer() - def __unicode__(self): + def __str__(self): return self.ean - __str__ = __unicode__ - def get_fullcode(self): return self.ean @@ -74,7 +78,10 @@ class EuropeanArticleNumber13(Barcode): :returns: The checksum for `self.ean`. :rtype: Integer """ - def sum_(x, y): return int(x) + int(y) + + def sum_(x, y): + return int(x) + int(y) + evensum = reduce(sum_, self.ean[-2::-2]) oddsum = reduce(sum_, self.ean[-1::-2]) return (10 - ((evensum + oddsum * 3) % 10)) % 10 @@ -91,7 +98,7 @@ class EuropeanArticleNumber13(Barcode): code += _ean.CODES[pattern[i]][int(number)] code += _ean.MIDDLE for number in self.ean[7:]: - code += _ean.CODES['C'][int(number)] + code += _ean.CODES["C"][int(number)] code += _ean.EDGE return [code] @@ -102,11 +109,11 @@ class EuropeanArticleNumber13(Barcode): """ code = self.build() for i, line in enumerate(code): - code[i] = line.replace('1', '|').replace('0', ' ') - return '\n'.join(code) + code[i] = line.replace("1", "|").replace("0", " ") + return "\n".join(code) def render(self, writer_options=None, text=None): - options = dict(module_width=SIZES['SC2']) + options = {"module_width": SIZES["SC2"]} options.update(writer_options or {}) return Barcode.render(self, options, text) @@ -121,14 +128,15 @@ class JapanArticleNumber(EuropeanArticleNumber13): The writer to render the barcode (default: SVGWriter). """ - name = 'JAN' + name = "JAN" valid_country_codes = list(range(450, 460)) + list(range(490, 500)) def __init__(self, jan, writer=None): if int(jan[:3]) not in JapanArticleNumber.valid_country_codes: - raise WrongCountryCodeError("Country code isn't between 450-460 " - "or 490-500.") + raise WrongCountryCodeError( + "Country code isn't between 450-460 or 490-500." + ) EuropeanArticleNumber13.__init__(self, jan, writer) @@ -142,7 +150,7 @@ class EuropeanArticleNumber8(EuropeanArticleNumber13): The writer to render the barcode (default: SVGWriter). """ - name = 'EAN-8' + name = "EAN-8" digits = 7 @@ -157,10 +165,10 @@ class EuropeanArticleNumber8(EuropeanArticleNumber13): """ code = _ean.EDGE[:] for number in self.ean[:4]: - code += _ean.CODES['A'][int(number)] + code += _ean.CODES["A"][int(number)] code += _ean.MIDDLE for number in self.ean[4:]: - code += _ean.CODES['C'][int(number)] + code += _ean.CODES["C"][int(number)] code += _ean.EDGE return [code] @@ -175,7 +183,7 @@ class EuropeanArticleNumber14(EuropeanArticleNumber13): The writer to render the barcode (default: SVGWriter). """ - name = 'EAN-14' + name = "EAN-14" digits = 13 def calculate_checksum(self): @@ -185,7 +193,8 @@ class EuropeanArticleNumber14(EuropeanArticleNumber13): :rtype: Integer """ - def sum_(x, y): return int(x) + int(y) + def sum_(x, y): + return int(x) + int(y) evensum = reduce(sum_, self.ean[::2]) oddsum = reduce(sum_, self.ean[1::2]) diff --git a/source/pythonpath/barcode/errors.py b/source/pythonpath/barcode/errors.py old mode 100644 new mode 100755 index 20f9459..7fb448f --- a/source/pythonpath/barcode/errors.py +++ b/source/pythonpath/barcode/errors.py @@ -1,10 +1,5 @@ -# -*- coding: utf-8 -*- - -from __future__ import unicode_literals - -"""barcode.errors -""" -__docformat__ = 'restructuredtext en' +"""barcode.errors""" +__docformat__ = "restructuredtext en" class BarcodeError(Exception): diff --git a/source/pythonpath/barcode/DejaVuSansMono.ttf b/source/pythonpath/barcode/fonts/DejaVuSansMono.ttf similarity index 100% rename from source/pythonpath/barcode/DejaVuSansMono.ttf rename to source/pythonpath/barcode/fonts/DejaVuSansMono.ttf diff --git a/source/pythonpath/barcode/isxn.py b/source/pythonpath/barcode/isxn.py old mode 100644 new mode 100755 index c5911ff..3d73ce1 --- a/source/pythonpath/barcode/isxn.py +++ b/source/pythonpath/barcode/isxn.py @@ -1,10 +1,3 @@ -# -*- coding: utf-8 -*- - -from __future__ import unicode_literals - -from barcode.ean import EuropeanArticleNumber13 -from barcode.errors import * - """Module: barcode.isxn :Provided barcodes: ISBN-13, ISBN-10, ISSN @@ -18,17 +11,21 @@ Example:: >>> from barcode import get_barcode >>> ISBN = get_barcode('isbn10') >>> isbn = ISBN('0132354187') - >>> unicode(isbn) + >>> isbn '0132354187' >>> isbn.get_fullcode() '9780132354189' >>> # Test with wrong checksum >>> isbn = ISBN('0132354180') - >>> unicode(isbn) + >>> isbn '0132354187' """ -__docformat__ = 'restructuredtext en' +from barcode.ean import EuropeanArticleNumber13 +from barcode.errors import BarcodeError +from barcode.errors import WrongCountryCodeError + +__docformat__ = "restructuredtext en" class InternationalStandardBookNumber13(EuropeanArticleNumber13): @@ -41,16 +38,16 @@ class InternationalStandardBookNumber13(EuropeanArticleNumber13): The writer to render the barcode (default: SVGWriter). """ - name = 'ISBN-13' + name = "ISBN-13" def __init__(self, isbn, writer=None): - isbn = isbn.replace('-', '') + isbn = isbn.replace("-", "") self.isbn13 = isbn - if isbn[:3] not in ('978', '979'): - raise WrongCountryCodeError('ISBN must start with 978 or 979.') - if isbn[:3] == '979': - if isbn[3:5] not in ('10', '11'): - raise BarcodeError('ISBN must start with 97910 or 97911.') + if isbn[:3] not in ("978", "979"): + raise WrongCountryCodeError("ISBN must start with 978 or 979.") + if isbn[:3] == "979": + if isbn[3:5] not in ("10", "11"): + raise BarcodeError("ISBN must start with 97910 or 97911.") EuropeanArticleNumber13.__init__(self, isbn, writer) @@ -65,30 +62,27 @@ class InternationalStandardBookNumber10(InternationalStandardBookNumber13): The writer to render the barcode (default: SVGWriter). """ - name = 'ISBN-10' + name = "ISBN-10" digits = 9 def __init__(self, isbn, writer=None): - isbn = isbn.replace('-', '') - isbn = isbn[:self.digits] + isbn = isbn.replace("-", "") + isbn = isbn[: self.digits] self.isbn10 = isbn - self.isbn10 = '{0}{1}'.format(isbn, self._calculate_checksum()) - InternationalStandardBookNumber13.__init__(self, '978' + isbn, writer) + self.isbn10 = "{}{}".format(isbn, self._calculate_checksum()) + InternationalStandardBookNumber13.__init__(self, "978" + isbn, writer) def _calculate_checksum(self): - tmp = sum([x * int(y) for x, y in enumerate(self.isbn10[:9], - start=1)]) % 11 + tmp = sum(x * int(y) for x, y in enumerate(self.isbn10[:9], start=1)) % 11 if tmp == 10: - return 'X' + return "X" else: return tmp - def __unicode__(self): + def __str__(self): return self.isbn10 - __str__ = __unicode__ - class InternationalStandardSerialNumber(EuropeanArticleNumber13): """Initializes new ISSN barcode. This code is rendered as EAN-13 @@ -101,33 +95,34 @@ class InternationalStandardSerialNumber(EuropeanArticleNumber13): The writer to render the barcode (default: SVGWriter). """ - name = 'ISSN' + name = "ISSN" digits = 7 def __init__(self, issn, writer=None): - issn = issn.replace('-', '') - issn = issn[:self.digits] + issn = issn.replace("-", "") + issn = issn[: self.digits] self.issn = issn - self.issn = '{0}{1}'.format(issn, self._calculate_checksum()) + self.issn = "{}{}".format(issn, self._calculate_checksum()) EuropeanArticleNumber13.__init__(self, self.make_ean(), writer) def _calculate_checksum(self): - tmp = 11 - sum([x * int(y) for x, y in - enumerate(reversed(self.issn[:7]), start=2)]) % 11 + tmp = ( + 11 + - sum(x * int(y) for x, y in enumerate(reversed(self.issn[:7]), start=2)) + % 11 + ) if tmp == 10: - return 'X' + return "X" else: return tmp def make_ean(self): - return '977{0}00{1}'.format(self.issn[:7], self._calculate_checksum()) + return "977{}00{}".format(self.issn[:7], self._calculate_checksum()) - def __unicode__(self): + def __str__(self): return self.issn - __str__ = __unicode__ - # Shortcuts ISBN13 = InternationalStandardBookNumber13 diff --git a/source/pythonpath/barcode/itf.py b/source/pythonpath/barcode/itf.py index c307255..4978dcd 100644 --- a/source/pythonpath/barcode/itf.py +++ b/source/pythonpath/barcode/itf.py @@ -1,17 +1,12 @@ -# -*- coding: utf-8 -*- - -from __future__ import unicode_literals - -from barcode.base import Barcode -from barcode.charsets import itf -from barcode.errors import * - """Module: barcode.itf :Provided barcodes: Interleaved 2 of 5 """ -__docformat__ = 'restructuredtext en' +__docformat__ = "restructuredtext en" +from barcode.base import Barcode +from barcode.charsets import itf +from barcode.errors import IllegalCharacterError MIN_SIZE = 0.2 MIN_QUIET_ZONE = 6.4 @@ -32,24 +27,22 @@ class ITF(Barcode): wide/narrow must be in the range 2..3 """ - name = 'ITF' + name = "ITF" def __init__(self, code, writer=None, narrow=2, wide=5): if not code.isdigit(): - raise IllegalCharacterError('ITF code can only contain numbers.') + raise IllegalCharacterError("ITF code can only contain numbers.") # Length must be even, prepend 0 if necessary if len(code) % 2 != 0: - code = '0' + code + code = "0" + code self.code = code self.writer = writer or Barcode.default_writer() self.narrow = narrow self.wide = wide - def __unicode__(self): + def __str__(self): return self.code - __str__ = __unicode__ - def get_fullcode(self): return self.code @@ -57,25 +50,27 @@ class ITF(Barcode): data = itf.START for i in range(0, len(self.code), 2): bars_digit = int(self.code[i]) - spaces_digit = int(self.code[i+1]) + spaces_digit = int(self.code[i + 1]) for j in range(5): data += itf.CODES[bars_digit][j].upper() data += itf.CODES[spaces_digit][j].lower() data += itf.STOP - raw = '' + raw = "" for e in data: - if e == 'W': - raw += '1' * self.wide - if e == 'w': - raw += '0' * self.wide - if e == 'N': - raw += '1' * self.narrow - if e == 'n': - raw += '0' * self.narrow + if e == "W": + raw += "1" * self.wide + if e == "w": + raw += "0" * self.wide + if e == "N": + raw += "1" * self.narrow + if e == "n": + raw += "0" * self.narrow return [raw] def render(self, writer_options, text=None): - options = dict(module_width=MIN_SIZE/self.narrow, - quiet_zone=MIN_QUIET_ZONE) + options = { + "module_width": MIN_SIZE / self.narrow, + "quiet_zone": MIN_QUIET_ZONE, + } options.update(writer_options or {}) return Barcode.render(self, options, text) diff --git a/source/pythonpath/barcode/pybarcode.py b/source/pythonpath/barcode/pybarcode.py index c1938fa..c44723c 100644 --- a/source/pythonpath/barcode/pybarcode.py +++ b/source/pythonpath/barcode/pybarcode.py @@ -1,115 +1,97 @@ -# -*- coding: utf-8 -*- - -from __future__ import print_function - import os - -import barcode - from argparse import ArgumentParser -from barcode.writer import ImageWriter, SVGWriter +import barcode from barcode.version import version +from barcode.writer import ImageWriter +from barcode.writer import SVGWriter -# Optional PyQt4 GUI -try: - from PyQt4 import QtCore -except ImportError: - QtCore = None # lint:ok - -# No GUI available yet -QtCore = None -IMG_FORMATS = ('BMP', 'GIF', 'JPEG', 'MSP', 'PCX', 'PNG', 'TIFF', 'XBM') - - -def open_gui(args, parser=None): - pass +IMG_FORMATS = ("BMP", "GIF", "JPEG", "MSP", "PCX", "PNG", "TIFF", "XBM") def list_types(args, parser=None): - print('\npyBarcode available barcode formats:') - print(', '.join(barcode.PROVIDED_BARCODES)) - print('\n') - print('Available image formats') - print('Standard: svg') + print("\npython-barcode available barcode formats:") + print(", ".join(barcode.PROVIDED_BARCODES)) + print("\n") + print("Available image formats") + print("Standard: svg") if ImageWriter is not None: - print('Pillow:', ', '.join(IMG_FORMATS)) + print("Pillow:", ", ".join(IMG_FORMATS)) else: - print('Pillow: disabled') - print('\n') + print("Pillow: disabled") + print("\n") def create_barcode(args, parser): args.type = args.type.upper() - if args.type != 'SVG' and args.type not in IMG_FORMATS: + if args.type != "SVG" and args.type not in IMG_FORMATS: parser.error( - 'Unknown type {type}. Try list action for available ' - 'types.'.format(type=args.type) + "Unknown type {type}. Try list action for available types.".format( + type=args.type + ) ) args.barcode = args.barcode.lower() if args.barcode not in barcode.PROVIDED_BARCODES: parser.error( - 'Unknown barcode {bc}. Try list action for available ' - 'barcodes.'.format(bc=args.barcode) + "Unknown barcode {bc}. Try list action for available barcodes.".format( + bc=args.barcode + ) ) - if args.type != 'SVG': - opts = dict(format=args.type) + if args.type != "SVG": + opts = {"format": args.type} writer = ImageWriter() else: - opts = dict(compress=args.compress) + opts = {"compress": args.compress} writer = SVGWriter() out = os.path.normpath(os.path.abspath(args.output)) - name = barcode.generate(args.barcode, args.code, writer, out, opts, - args.text) - print('New barcode saved as {0}.'.format(name)) + name = barcode.generate(args.barcode, args.code, writer, out, opts, args.text) + print("New barcode saved as {}.".format(name)) def main(): msg = [] if ImageWriter is None: - msg.append( - 'Image output disabled (Pillow not found), --type option disabled.' - ) + msg.append("Image output disabled (Pillow not found), --type option disabled.") else: msg.append( - 'Image output enabled, use --type option to give image ' - 'format (png, jpeg, ...).' + "Image output enabled, use --type option to give image " + "format (png, jpeg, ...)." ) - if QtCore is None: - msg.append('PyQt not found, gui action disabled.') - else: - msg.append('PyQt found. Use gui action to get a simple GUI.') parser = ArgumentParser( - description='Create standard barcodes via cli.', epilog=' '.join(msg) + description="Create standard barcodes via cli.", epilog=" ".join(msg) ) - parser.add_argument('-v', '--version', action='version', - version='%(prog)s ' + version) - subparsers = parser.add_subparsers(title='Actions') - create_parser = subparsers.add_parser('create', help='Create a barcode ' - 'with the given options.') - create_parser.add_argument('code', help='Code to render as barcode.') - create_parser.add_argument('output', help='Filename for output ' - 'without extension, e. g. mybarcode.') + parser.add_argument( + "-v", "--version", action="version", version="%(prog)s " + version + ) + subparsers = parser.add_subparsers(title="Actions") + create_parser = subparsers.add_parser( + "create", help="Create a barcode with the given options." + ) + create_parser.add_argument("code", help="Code to render as barcode.") create_parser.add_argument( - '-c', '--compress', action='store_true', - help='Compress output, only recognized if type is svg.' + "output", help="Filename for output without extension, e. g. mybarcode." ) - create_parser.add_argument('-b', '--barcode', help='Barcode to use ' - '[default: %(default)s].') - create_parser.add_argument('--text', help='Text to show under the ' - 'barcode.') + create_parser.add_argument( + "-c", + "--compress", + action="store_true", + help="Compress output, only recognized if type is svg.", + ) + create_parser.add_argument( + "-b", "--barcode", help="Barcode to use [default: %(default)s]." + ) + create_parser.add_argument("--text", help="Text to show under the barcode.") if ImageWriter is not None: - create_parser.add_argument('-t', '--type', help='Type of output ' - '[default: %(default)s].') - list_parser = subparsers.add_parser('list', help='List available ' - 'image and code types.') + create_parser.add_argument( + "-t", "--type", help="Type of output [default: %(default)s]." + ) + list_parser = subparsers.add_parser( + "list", help="List available image and code types." + ) list_parser.set_defaults(func=list_types) - if QtCore is not None: - gui_parser = subparsers.add_parser('gui', help='Opens a simple ' - 'PyQt GUI to create barcodes.') - gui_parser.set_defaults(func=open_gui) - create_parser.set_defaults(type='svg', compress=False, func=create_barcode, - barcode='code39', text=None) + create_parser.set_defaults( + type="svg", compress=False, func=create_barcode, barcode="code39", text=None + ) args = parser.parse_args() try: func = args.func @@ -119,5 +101,5 @@ def main(): func(args, parser) -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/source/pythonpath/barcode/upc.py b/source/pythonpath/barcode/upc.py old mode 100644 new mode 100755 index cd68259..c3ad3c8 --- a/source/pythonpath/barcode/upc.py +++ b/source/pythonpath/barcode/upc.py @@ -1,61 +1,57 @@ -# -*- coding: utf-8 -*- - -from __future__ import unicode_literals - -from barcode.base import Barcode -from barcode.charsets import upc as _upc -from barcode.errors import * - -try: - reduce -except NameError: - from functools import reduce - """Module: barcode.upc :Provided barcodes: UPC-A """ -__docformat__ = 'restructuredtext en' +__docformat__ = "restructuredtext en" + +from functools import reduce + +from barcode.base import Barcode +from barcode.charsets import upc as _upc +from barcode.errors import IllegalCharacterError, NumberOfDigitsError class UniversalProductCodeA(Barcode): - """Initializes new UPC-A barcode. + """Universal Product Code (UPC) barcode. - :parameters: - upc : String - The upc number as string. - writer : barcode.writer Instance - The writer to render the barcode (default: SVGWriter). - make_ean: boolean + UPC-A consists of 12 numeric digits. """ - name = 'UPC-A' + name = "UPC-A" digits = 11 def __init__(self, upc, writer=None, make_ean=False): + """Initializes new UPC-A barcode. + + :param str upc: The upc number as string. + :param writer: barcode.writer instance. The writer to render the + barcode (default: SVGWriter). + :param bool make_ean: Indicates if a leading zero should be added to + the barcode. This converts the UPC into a valid European Article + Number (EAN). + """ self.ean = make_ean - upc = upc[:self.digits] + upc = upc[: self.digits] if not upc.isdigit(): - raise IllegalCharacterError('UPC code can only contain numbers.') + raise IllegalCharacterError("UPC code can only contain numbers.") if len(upc) != self.digits: - raise NumberOfDigitsError('UPC must have {0} digits, not ' - '{1}.'.format(self.digits, len(upc))) + raise NumberOfDigitsError( + "UPC must have {} digits, not {}.".format(self.digits, len(upc)) + ) self.upc = upc - self.upc = '{}{}'.format(upc, self.calculate_checksum()) + self.upc = "{}{}".format(upc, self.calculate_checksum()) self.writer = writer or Barcode.default_writer() - def __unicode__(self): + def __str__(self): if self.ean: - return '0' + self.upc + return "0" + self.upc else: return self.upc - __str__ = __unicode__ - def get_fullcode(self): if self.ean: - return '0' + self.upc + return "0" + self.upc else: return self.upc @@ -63,10 +59,13 @@ class UniversalProductCodeA(Barcode): """Calculates the checksum for UPCA/UPC codes :return: The checksum for 'self.upc' - :rtype: Integer + :rtype: int """ - def sum_(x, y): return int(x) + int(y) - upc = self.upc[0:self.digits] + + def sum_(x, y): + return int(x) + int(y) + + upc = self.upc[0 : self.digits] oddsum = reduce(sum_, upc[::2]) evensum = reduce(sum_, upc[1::2]) check = (evensum + oddsum * 3) % 10 @@ -79,17 +78,17 @@ class UniversalProductCodeA(Barcode): """Builds the barcode pattern from 'self.upc' :return: The pattern as string - :rtype: String + :rtype: str """ code = _upc.EDGE[:] - for i, number in enumerate(self.upc[0:6]): - code += _upc.CODES['L'][int(number)] + for _i, number in enumerate(self.upc[0:6]): + code += _upc.CODES["L"][int(number)] code += _upc.MIDDLE for number in self.upc[6:]: - code += _upc.CODES['R'][int(number)] + code += _upc.CODES["R"][int(number)] code += _upc.EDGE @@ -98,17 +97,18 @@ class UniversalProductCodeA(Barcode): def to_ascii(self): """Returns an ascii representation of the barcode. - :rtype: String + :rtype: str """ code = self.build() for i, line in enumerate(code): - code[i] = line.replace('1', '|').replace('0', '_') - return '\n'.join(code) + code[i] = line.replace("1", "|").replace("0", "_") + return "\n".join(code) def render(self, writer_options=None, text=None): - options = dict(module_width=0.33) + options = {"module_width": 0.33} options.update(writer_options or {}) return Barcode.render(self, options, text) + UPCA = UniversalProductCodeA diff --git a/source/pythonpath/barcode/version.py b/source/pythonpath/barcode/version.py index f9f5476..8d5a1c7 100644 --- a/source/pythonpath/barcode/version.py +++ b/source/pythonpath/barcode/version.py @@ -1,4 +1,3 @@ -# coding: utf-8 -# file generated by setuptools_scm -# don't change, don't track in version control -version = '0.10.0' +#!/usr/bin/env python3 + +version = '0.0.0' diff --git a/source/pythonpath/barcode/writer.py b/source/pythonpath/barcode/writer.py old mode 100644 new mode 100755 index 415f26f..e3fbbff --- a/source/pythonpath/barcode/writer.py +++ b/source/pythonpath/barcode/writer.py @@ -1,10 +1,7 @@ -# -*- coding: utf-8 -*- - -from __future__ import unicode_literals - import gzip import os import xml.dom +from typing import BinaryIO from barcode.version import version @@ -17,8 +14,9 @@ except ImportError: from PIL import Image, ImageDraw, ImageFont # lint:ok except ImportError: import logging - log = logging.getLogger('pyBarcode') - log.info('Pillow not found. Image output disabled') + + log = logging.getLogger("pyBarcode") + log.info("Pillow not found. Image output disabled") Image = ImageDraw = ImageFont = None # lint:ok @@ -35,26 +33,26 @@ def _set_attributes(element, **attributes): element.setAttribute(key, value) -def create_svg_object(): +def create_svg_object(with_doctype=False): imp = xml.dom.getDOMImplementation() doctype = imp.createDocumentType( - 'svg', - '-//W3C//DTD SVG 1.1//EN', - 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd' + "svg", + "-//W3C//DTD SVG 1.1//EN", + "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd", + ) + document = imp.createDocument(None, "svg", doctype if with_doctype else None) + _set_attributes( + document.documentElement, version="1.1", xmlns="http://www.w3.org/2000/svg" ) - document = imp.createDocument(None, 'svg', doctype) - _set_attributes(document.documentElement, version='1.1', - xmlns='http://www.w3.org/2000/svg') return document -SIZE = '{0:.3f}mm' -COMMENT = 'Autogenerated with python-barcode {0}'.format(version) +SIZE = "{0:.3f}mm" +COMMENT = "Autogenerated with python-barcode {}".format(version) PATH = os.path.dirname(os.path.abspath(__file__)) -FONT = os.path.join(PATH, 'DejaVuSansMono.ttf') -class BaseWriter(object): +class BaseWriter: """Baseclass for all writers. Initializes the basic writer options. Childclasses can add more @@ -79,21 +77,26 @@ class BaseWriter(object): rendered output. """ - def __init__(self, initialize=None, paint_module=None, paint_text=None, - finish=None): - self._callbacks = dict( - initialize=initialize, paint_module=paint_module, - paint_text=paint_text, finish=finish - ) + def __init__( + self, initialize=None, paint_module=None, paint_text=None, finish=None + ): + self._callbacks = { + "initialize": initialize, + "paint_module": paint_module, + "paint_text": paint_text, + "finish": finish, + } self.module_width = 10 self.module_height = 10 + self.font_path = os.path.join(PATH, "fonts", "DejaVuSansMono.ttf") self.font_size = 10 self.quiet_zone = 6.5 - self.background = 'white' - self.foreground = 'black' - self.text = '' - self.human = '' # human readable text + self.background = "white" + self.foreground = "black" + self.text = "" + self.human = "" # human readable text self.text_distance = 5 + self.text_line_distance = 1 self.center_text = True def calculate_size(self, modules_per_line, number_of_lines, dpi=300): @@ -112,8 +115,12 @@ class BaseWriter(object): """ width = 2 * self.quiet_zone + modules_per_line * self.module_width height = 2.0 + self.module_height * number_of_lines + number_of_text_lines = len(self.text.splitlines()) if self.font_size and self.text: - height += pt2mm(self.font_size) / 2 + self.text_distance + height += ( + pt2mm(self.font_size) / 2 * number_of_text_lines + self.text_distance + ) + height += self.text_line_distance * (number_of_text_lines - 1) return int(mm2px(width, dpi)), int(mm2px(height, dpi)) def save(self, filename, output): @@ -154,7 +161,7 @@ class BaseWriter(object): :rtype: None """ for key, val in options.items(): - key = key.lstrip('_') + key = key.lstrip("_") if hasattr(self, key): setattr(self, key, val) @@ -167,8 +174,8 @@ class BaseWriter(object): List of strings matching the writer spec (only contain 0 or 1). """ - if self._callbacks['initialize'] is not None: - self._callbacks['initialize'](code) + if self._callbacks["initialize"] is not None: + self._callbacks["initialize"](code) ypos = 1.0 for cc, line in enumerate(code): """ @@ -176,11 +183,11 @@ class BaseWriter(object): result in aliasing gaps '11010111' -> [2, -1, 1, -1, 3] """ - line += ' ' + line += " " c = 1 mlist = [] for i in range(0, len(line) - 1): - if line[i] == line[i+1]: + if line[i] == line[i + 1]: c += 1 else: if line[i] == "1": @@ -197,141 +204,194 @@ class BaseWriter(object): else: color = self.foreground # remove painting for background colored tiles? - self._callbacks['paint_module']( + self._callbacks["paint_module"]( xpos, ypos, self.module_width * abs(mod), color ) xpos += self.module_width * abs(mod) bxe = xpos # Add right quiet zone to every line, except last line, # quiet zone already provided with background, - # should it be removed complety? + # should it be removed completely? if (cc + 1) != len(code): - self._callbacks['paint_module']( + self._callbacks["paint_module"]( xpos, ypos, self.quiet_zone, self.background ) ypos += self.module_height - if self.text and self._callbacks['paint_text'] is not None: + if self.text and self._callbacks["paint_text"] is not None: ypos += self.text_distance if self.center_text: # better center position for text xpos = bxs + ((bxe - bxs) / 2.0) else: xpos = bxs - self._callbacks['paint_text'](xpos, ypos) - return self._callbacks['finish']() + self._callbacks["paint_text"](xpos, ypos) + return self._callbacks["finish"]() class SVGWriter(BaseWriter): - def __init__(self): - BaseWriter.__init__(self, self._init, self._create_module, - self._create_text, self._finish) + BaseWriter.__init__( + self, self._init, self._create_module, self._create_text, self._finish + ) self.compress = False self.dpi = 25.4 + self.with_doctype = True self._document = None self._root = None self._group = None def _init(self, code): width, height = self.calculate_size(len(code[0]), len(code), self.dpi) - self._document = create_svg_object() + self._document = create_svg_object(self.with_doctype) self._root = self._document.documentElement - attributes = dict(width=SIZE.format(width), height=SIZE.format(height)) + attributes = { + "width": SIZE.format(width), + "height": SIZE.format(height), + } _set_attributes(self._root, **attributes) self._root.appendChild(self._document.createComment(COMMENT)) # create group for easier handling in 3rd party software # like corel draw, inkscape, ... - group = self._document.createElement('g') - attributes = dict(id='barcode_group') + group = self._document.createElement("g") + attributes = {"id": "barcode_group"} _set_attributes(group, **attributes) self._group = self._root.appendChild(group) - background = self._document.createElement('rect') - attributes = dict(width='100%', height='100%', - style='fill:{0}'.format(self.background)) + background = self._document.createElement("rect") + attributes = { + "width": "100%", + "height": "100%", + "style": "fill:{}".format(self.background), + } _set_attributes(background, **attributes) self._group.appendChild(background) def _create_module(self, xpos, ypos, width, color): - element = self._document.createElement('rect') - attributes = dict(x=SIZE.format(xpos), y=SIZE.format(ypos), - width=SIZE.format(width), - height=SIZE.format(self.module_height), - style='fill:{0};'.format(color)) + element = self._document.createElement("rect") + attributes = { + "x": SIZE.format(xpos), + "y": SIZE.format(ypos), + "width": SIZE.format(width), + "height": SIZE.format(self.module_height), + "style": "fill:{};".format(color), + } _set_attributes(element, **attributes) self._group.appendChild(element) def _create_text(self, xpos, ypos): - element = self._document.createElement('text') - attributes = dict(x=SIZE.format(xpos), y=SIZE.format(ypos), - style='fill:{0};font-size:{1}pt;text-anchor:' - 'middle;'.format(self.foreground, - self.font_size)) - _set_attributes(element, **attributes) # check option to override self.text with self.human (barcode as # human readable data, can be used to print own formats) - if self.human != '': + if self.human != "": barcodetext = self.human else: barcodetext = self.text - text_element = self._document.createTextNode(barcodetext) - element.appendChild(text_element) - self._group.appendChild(element) + for subtext in barcodetext.split("\n"): + element = self._document.createElement("text") + attributes = { + "x": SIZE.format(xpos), + "y": SIZE.format(ypos), + "style": "fill:{};font-size:{}pt;text-anchor:middle;".format( + self.foreground, + self.font_size, + ), + } + _set_attributes(element, **attributes) + text_element = self._document.createTextNode(subtext) + element.appendChild(text_element) + self._group.appendChild(element) + ypos += pt2mm(self.font_size) + self.text_line_distance def _finish(self): if self.compress: - return self._document.toxml(encoding='UTF-8') + return self._document.toxml(encoding="UTF-8") else: - return self._document.toprettyxml(indent=4 * ' ', newl=os.linesep, - encoding='UTF-8') + return self._document.toprettyxml( + indent=4 * " ", newl=os.linesep, encoding="UTF-8" + ) def save(self, filename, output): if self.compress: - _filename = '{0}.svgz'.format(filename) - f = gzip.open(_filename, 'wb') + _filename = "{}.svgz".format(filename) + f = gzip.open(_filename, "wb") f.write(output) f.close() else: - _filename = '{0}.svg'.format(filename) - with open(_filename, 'wb') as f: + _filename = "{}.svg".format(filename) + with open(_filename, "wb") as f: f.write(output) return _filename + def write(self, content, fp: BinaryIO): + """Write `content` into a file-like object. + + Content should be a barcode rendered by this writer. + """ + fp.write(content) + if Image is None: ImageWriter = None else: - class ImageWriter(BaseWriter): - def __init__(self): - BaseWriter.__init__(self, self._init, self._paint_module, - self._paint_text, self._finish) - self.format = 'PNG' + class ImageWriter(BaseWriter): # type: ignore + format: str + mode: str + dpi: int + + def __init__(self, format="PNG", mode="RGB"): + """Initialise a new write instance. + + :params format: The file format for the generated image. This parameter can + take any value that Pillow accepts. + :params mode: The colour-mode for the generated image. Set this to RGBA if + you wish to use colours with transparency. + """ + BaseWriter.__init__( + self, self._init, self._paint_module, self._paint_text, self._finish + ) + self.format = format + self.mode = mode self.dpi = 300 self._image = None self._draw = None def _init(self, code): size = self.calculate_size(len(code[0]), len(code), self.dpi) - self._image = Image.new('RGB', size, self.background) + self._image = Image.new(self.mode, size, self.background) self._draw = ImageDraw.Draw(self._image) def _paint_module(self, xpos, ypos, width, color): - size = [(mm2px(xpos, self.dpi), mm2px(ypos, self.dpi)), - (mm2px(xpos + width, self.dpi), - mm2px(ypos + self.module_height, self.dpi))] + size = [ + (mm2px(xpos, self.dpi), mm2px(ypos, self.dpi)), + ( + mm2px(xpos + width, self.dpi), + mm2px(ypos + self.module_height, self.dpi), + ), + ] self._draw.rectangle(size, outline=color, fill=color) def _paint_text(self, xpos, ypos): - font = ImageFont.truetype(FONT, self.font_size * 2) - width, height = font.getsize(self.text) - pos = (mm2px(xpos, self.dpi) - width // 2, - mm2px(ypos, self.dpi) - height // 4) - self._draw.text(pos, self.text, font=font, fill=self.foreground) + font = ImageFont.truetype(self.font_path, self.font_size * 2) + for subtext in self.text.split("\n"): + width, height = font.getsize(subtext) + # determine the maximum width of each line + pos = ( + mm2px(xpos, self.dpi) - width // 2, + mm2px(ypos, self.dpi) - height // 4, + ) + self._draw.text(pos, subtext, font=font, fill=self.foreground) + ypos += pt2mm(self.font_size) / 2 + self.text_line_distance def _finish(self): return self._image def save(self, filename, output): - filename = '{0}.{1}'.format(filename, self.format.lower()) + filename = "{}.{}".format(filename, self.format.lower()) output.save(filename, self.format.upper()) return filename + + def write(self, content, fp: BinaryIO): + """Write `content` into a file-like object. + + Content should be a barcode rendered by this writer. + """ + content.save(fp, format=self.format) diff --git a/source/pythonpath/easymacro.py b/source/pythonpath/easymacro.py index 30e717e..5a75695 100644 --- a/source/pythonpath/easymacro.py +++ b/source/pythonpath/easymacro.py @@ -499,6 +499,11 @@ def dict_to_property(values, uno_any=False): return ps +def dict_to_named(values): + ps = tuple([NamedValue(n, v) for n, v in values.items()]) + return ps + + def property_to_dict(values): d = {i.Name: i.Value for i in values} return d @@ -1837,6 +1842,33 @@ class LOCellRange(object): self.sheet.obj.copyRange(self.address, source.range_address) return + def transpose(self, formula=False): + data = self.data + if formula: + data = self.formula + data = tuple(zip(*data)) + self.clear(1023) + self[0,0].copy_from(data, formula=formula) + return + + def transpose2(self): + # ~ 'Flags': 'A', + # ~ 'FormulaCommand': 0, + # ~ 'SkipEmptyCells': False, + # ~ 'AsLink': False, + # ~ 'MoveMode': 4, + args = { + 'Transpose': True, + } + args = dict_to_property(args) + self.select() + copy() + self.clear(1023) + self[0,0].select() + call_dispatch('.uno:InsertContents', args) + set_clipboard('') + return + def offset(self, row=1, col=0): ra = self.obj.getRangeAddress() col = ra.EndColumn + col @@ -1939,6 +1971,10 @@ class LOCellRange(object): def auto_format(self, value): self.obj.autoFormat(value) + def auto_width(self): + self.obj.Columns.OptimalWidth = True + return + def insert_image(self, path, **kwargs): s = self.obj.Size w = kwargs.get('width', s.Width) @@ -2060,6 +2096,22 @@ class LOCellRange(object): found = self.obj.replaceAll(descriptor) return found + @property + def validation(self): + return self.obj.Validation + @validation.setter + def validation(self, values): + is_list = False + current = self.validation + for k, v in values.items(): + if k == 'Type' and v == 6: + is_list = True + if k == 'Formula1' and is_list: + if isinstance(v, (tuple, list)): + v = ';'.join(['"{}"'.format(i) for i in v]) + setattr(current, k, v) + self.obj.Validation = current + class EventsListenerBase(unohelper.Base, XEventListener): @@ -2454,23 +2506,39 @@ class UnoBaseObject(object): return self._model.Width @width.setter def width(self, value): - if hasattr(self.model, 'Width'): - self.model.Width = value - elif hasattr(self.obj, 'PosSize'): - self._set_possize('Width', value) + self.model.Width = value + + @property + def ps_width(self): + return self._get_possize('Width') + @ps_width.setter + def ps_width(self, value): + self._set_possize('Width', value) @property def height(self): - if hasattr(self.model, 'Height'): - return self.model.Height - ps = self.obj.getPosSize() - return ps.Height + return self.model.Height @height.setter def height(self, value): - if hasattr(self.model, 'Height'): - self.model.Height = value - elif hasattr(self.obj, 'PosSize'): - self._set_possize('Height', value) + self.model.Height = value + + @property + def ps_height(self): + return self._get_possize('Height') + @ps_height.setter + def ps_height(self, value): + self._set_possize('Height', value) + + @property + def size(self): + ps = self.obj.getPosSize() + return (ps.Width, ps.Height) + @size.setter + def size(self, value): + ps = self.obj.getPosSize() + ps.Width = value[0] + ps.Height = value[1] + self.obj.setPosSize(ps.X, ps.Y, ps.Width, ps.Height, SIZE) @property def tag(self): @@ -4493,7 +4561,7 @@ def _zippwd(source, target, pwd): # ~ Export ok -def zip(source, target='', mode='w', pwd=''): +def zip_files(source, target='', mode='w', pwd=''): if pwd: return _zippwd(source, target, pwd) diff --git a/source/pythonpath/qrcode/main.py b/source/pythonpath/qrcode/main.py index 5cbc2a8..55999e9 100644 --- a/source/pythonpath/qrcode/main.py +++ b/source/pythonpath/qrcode/main.py @@ -1,12 +1,8 @@ -import struct -from bisect import bisect_left - from qrcode import constants, exceptions, util from qrcode.image.base import BaseImage - -def int2byte(value): - return struct.Struct('>B').pack(value) +import six +from bisect import bisect_left def make(data=None, **kwargs): @@ -46,13 +42,21 @@ class QRCode(object): # Spec says border should be at least four boxes wide, but allow for # any (e.g. for producing printable QR codes). self.border = int(border) - _check_mask_pattern(mask_pattern) self.mask_pattern = mask_pattern self.image_factory = image_factory if image_factory is not None: assert issubclass(image_factory, BaseImage) self.clear() + @property + def mask_pattern(self): + return self._mask_pattern + + @mask_pattern.setter + def mask_pattern(self, pattern): + _check_mask_pattern(pattern) + self._mask_pattern = pattern + def clear(self): """ Reset the internal data. @@ -240,7 +244,7 @@ class QRCode(object): self.make() modcount = self.modules_count - codes = [int2byte(code).decode('cp437') + codes = [six.int2byte(code).decode('cp437') for code in (255, 223, 220, 219)] if tty: invert = True @@ -381,7 +385,7 @@ class QRCode(object): data_len = len(data) - for col in range(self.modules_count - 1, 0, -2): + for col in six.moves.xrange(self.modules_count - 1, 0, -2): if col <= 6: col -= 1 diff --git a/source/pythonpath/qrcode/util.py b/source/pythonpath/qrcode/util.py index 74ab39f..58f3d21 100644 --- a/source/pythonpath/qrcode/util.py +++ b/source/pythonpath/qrcode/util.py @@ -1,8 +1,8 @@ import re import math -# ~ import six -# ~ from six.moves import xrange +import six +from six.moves import xrange from qrcode import base, exceptions, LUT @@ -32,10 +32,8 @@ MODE_SIZE_LARGE = { MODE_KANJI: 12, } - -ALPHA_NUM = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:'.encode("latin-1") -RE_ALPHA_NUM = re.compile('^['.encode("latin-1") + re.escape(ALPHA_NUM) + r']*\Z'.encode("latin-1")) - +ALPHA_NUM = six.b('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:') +RE_ALPHA_NUM = re.compile(six.b('^[') + re.escape(ALPHA_NUM) + six.b(r']*\Z')) # The number of bits for numeric delimited data lengths. NUMBER_LENGTH = {3: 10, 2: 7, 1: 4} @@ -98,8 +96,8 @@ PAD1 = 0x11 _data_count = lambda block: block.data_count BIT_LIMIT_TABLE = [ [0] + [8*sum(map(_data_count, base.rs_blocks(version, error_correction))) - for version in range(1, 41)] - for error_correction in range(4) + for version in xrange(1, 41)] + for error_correction in xrange(4) ] @@ -194,7 +192,7 @@ def lost_point(modules): def _lost_point_level1(modules, modules_count): lost_point = 0 - modules_range = range(modules_count) + modules_range = xrange(modules_count) container = [0] * (modules_count + 1) for row in modules_range: @@ -227,7 +225,7 @@ def _lost_point_level1(modules, modules_count): container[length] += 1 lost_point += sum(container[each_length] * (each_length - 2) - for each_length in range(5, modules_count + 1)) + for each_length in xrange(5, modules_count + 1)) return lost_point @@ -235,7 +233,7 @@ def _lost_point_level1(modules, modules_count): def _lost_point_level2(modules, modules_count): lost_point = 0 - modules_range = range(modules_count - 1) + modules_range = xrange(modules_count - 1) for row in modules_range: this_row = modules[row] next_row = modules[row + 1] @@ -264,8 +262,8 @@ def _lost_point_level3(modules, modules_count): # row/column, preceded or followed by light area 4 modules wide. From ISOIEC. # pattern1: 10111010000 # pattern2: 00001011101 - modules_range = range(modules_count) - modules_range_short = range(modules_count-10) + modules_range = xrange(modules_count) + modules_range_short = xrange(modules_count-10) lost_point = 0 for row in modules_range: @@ -350,14 +348,14 @@ def optimal_data_chunks(data, minimum=4): :param minimum: The minimum number of bytes in a row to split as a chunk. """ data = to_bytestring(data) - num_pattern = r'\d'.encode("latin-1") - alpha_pattern = '['.encode("latin-1") + re.escape(ALPHA_NUM) + ']'.encode("latin-1") + num_pattern = six.b(r'\d') + alpha_pattern = six.b('[') + re.escape(ALPHA_NUM) + six.b(']') if len(data) <= minimum: - num_pattern = re.compile('^'.encode("latin-1") + num_pattern + '+$'.encode("latin-1")) - alpha_pattern = re.compile('^'.encode("latin-1") + alpha_pattern + '+$'.encode("latin-1")) + num_pattern = re.compile(six.b('^') + num_pattern + six.b('+$')) + alpha_pattern = re.compile(six.b('^') + alpha_pattern + six.b('+$')) else: re_repeat = ( - '{'.encode("latin-1") + str(minimum).encode('ascii') + ',}'.encode("latin-1")) + six.b('{') + six.text_type(minimum).encode('ascii') + six.b(',}')) num_pattern = re.compile(num_pattern + re_repeat) alpha_pattern = re.compile(alpha_pattern + re_repeat) num_bits = _optimal_split(data, num_pattern) @@ -392,8 +390,8 @@ def to_bytestring(data): Convert data to a (utf-8 encoded) byte-string if it isn't a byte-string already. """ - if not isinstance(data, bytes): - data = str(data).encode('utf-8') + if not isinstance(data, six.binary_type): + data = six.text_type(data).encode('utf-8') return data @@ -441,12 +439,12 @@ class QRData(object): def write(self, buffer): if self.mode == MODE_NUMBER: - for i in range(0, len(self.data), 3): + for i in xrange(0, len(self.data), 3): chars = self.data[i:i + 3] bit_length = NUMBER_LENGTH[len(chars)] buffer.put(int(chars), bit_length) elif self.mode == MODE_ALPHA_NUM: - for i in range(0, len(self.data), 2): + for i in xrange(0, len(self.data), 2): chars = self.data[i:i + 2] if len(chars) > 1: buffer.put( @@ -455,13 +453,12 @@ class QRData(object): else: buffer.put(ALPHA_NUM.find(chars), 6) else: - # ~ if six.PY3: + if six.PY3: # Iterating a bytestring in Python 3 returns an integer, # no need to ord(). - # ~ data = self.data - # ~ else: - # ~ data = [ord(c) for c in self.data] - data = self.data + data = self.data + else: + data = [ord(c) for c in self.data] for c in data: buffer.put(c, 8) diff --git a/zaz.py b/zaz.py index 9cad0c8..d08a269 100644 --- a/zaz.py +++ b/zaz.py @@ -19,6 +19,7 @@ import argparse import os +import py_compile import re import sys import zipfile @@ -44,8 +45,18 @@ from conf import ( class LiboXML(object): + CONTEXT = { + 'calc': 'com.sun.star.sheet.SpreadsheetDocument', + 'writer': 'com.sun.star.text.TextDocument', + 'impress': 'com.sun.star.presentation.PresentationDocument', + 'draw': 'com.sun.star.drawing.DrawingDocument', + 'base': 'com.sun.star.sdb.OfficeDatabaseDocument', + 'math': 'com.sun.star.formula.FormulaProperties', + 'basic': 'com.sun.star.script.BasicIDE', + } TYPES = { 'py': 'application/vnd.sun.star.uno-component;type=Python', + 'pyc': 'application/binary', 'zip': 'application/binary', 'xcu': 'application/vnd.sun.star.configuration-data', 'rdb': 'application/vnd.sun.star.uno-typelibrary;type=RDB', @@ -53,18 +64,34 @@ class LiboXML(object): 'help': 'application/vnd.sun.star.help', 'component': 'application/vnd.sun.star.uno-components', } - NAME_SPACES = { + NS_MANIFEST = { 'manifest_version': '1.2', 'manifest': 'urn:oasis:names:tc:opendocument:xmlns:manifest:1.0', 'xmlns:loext': 'urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0', } + NS_DESCRIPTION = { + 'xmlns': 'http://openoffice.org/extensions/description/2006', + 'xmlns:xlink': 'http://www.w3.org/1999/xlink', + 'xmlns:d': 'http://openoffice.org/extensions/description/2006', + } + NS_ADDONS = { + 'xmlns:xs': 'http://www.w3.org/2001/XMLSchema', + 'xmlns:oor': 'http://openoffice.org/2001/registry', + } + NS_UPDATE = { + 'xmlns': 'http://openoffice.org/extensions/update/2006', + 'xmlns:d': 'http://openoffice.org/extensions/description/2006', + 'xmlns:xlink': 'http://www.w3.org/1999/xlink', + } def __init__(self): self._manifest = None self._paths = [] + self._path_images = '' + self._toolbars = [] def _save_path(self, attr): - self._paths.append(attr['{{{}}}full-path'.format(self.NAME_SPACES['manifest'])]) + self._paths.append(attr['{{{}}}full-path'.format(self.NS_MANIFEST['manifest'])]) return def _clean(self, name, nodes): @@ -86,18 +113,18 @@ class LiboXML(object): def new_manifest(self, data): attr = { - 'manifest:version': self.NAME_SPACES['manifest_version'], - 'xmlns:manifest': self.NAME_SPACES['manifest'], - 'xmlns:loext': self.NAME_SPACES['xmlns:loext'], + 'manifest:version': self.NS_MANIFEST['manifest_version'], + 'xmlns:manifest': self.NS_MANIFEST['manifest'], + 'xmlns:loext': self.NS_MANIFEST['xmlns:loext'], } self._manifest = ET.Element('manifest:manifest', attr) return self.add_data_manifest(data) def parse_manifest(self, data): - ET.register_namespace('manifest', self.NAME_SPACES['manifest']) + ET.register_namespace('manifest', self.NS_MANIFEST['manifest']) self._manifest = ET.fromstring(data) - data = {'xmlns:loext': self.NAME_SPACES['xmlns:loext']} - self._manifest.attrib.update(**data) + attr = {'xmlns:loext': self.NS_MANIFEST['xmlns:loext']} + self._manifest.attrib.update(**attr) self._clean('manifest', self._manifest) return @@ -116,6 +143,217 @@ class LiboXML(object): ET.SubElement(self._manifest, node_name, attr) return self._get_xml(self._manifest) + def new_description(self, data): + doc = ET.Element('description', self.NS_DESCRIPTION) + + key = 'identifier' + ET.SubElement(doc, key, data[key]) + + key = 'version' + ET.SubElement(doc, key, data[key]) + + key = 'display-name' + node = ET.SubElement(doc, key) + for k, v in data[key].items(): + sn = ET.SubElement(node, 'name', {'lang': k}) + sn.text = v + + node = ET.SubElement(doc, 'extension-description') + for k in data[key].keys(): + attr = { + 'lang': k, + 'xlink:href': f'description/desc_{k}.txt', + } + ET.SubElement(node, 'src', attr) + + key = 'icon' + node = ET.SubElement(doc, key) + attr = {'xlink:href': f"images/{data[key]}"} + ET.SubElement(node, 'default', attr) + + key = 'publisher' + node = ET.SubElement(doc, key) + for k, v in data[key].items(): + attr = { + 'xlink:href': v['link'], + 'lang': k, + } + sn = ET.SubElement(node, 'name', attr) + sn.text = v['text'] + + key = 'display-name' + node = ET.SubElement(doc, 'registration') + attr = { + 'accept-by': 'user', + 'suppress-on-update': 'true', + } + node = ET.SubElement(node, 'simple-license', attr) + for k in data[key].keys(): + attr = { + 'xlink:href': f"{DIRS['registration']}/license_{k}.txt", + 'lang': k + } + ET.SubElement(node, 'license-text', attr) + + if data['update']: + node = ET.SubElement(doc, 'update-information') + ET.SubElement(node, 'src', {'xlink:href': data['update']}) + + return self._get_xml(doc) + + def _get_context(self, args): + if not args: + return '' + context = ','.join([self.CONTEXT[v] for v in args.split(',')]) + return context + + def _add_node_value(self, node, name, value='_self'): + attr = {'oor:name': name, 'oor:type': 'xs:string'} + sn = ET.SubElement(node, 'prop', attr) + sn = ET.SubElement(sn, 'value') + sn.text = value + return + + def _add_menu(self, id_extension, node, index, menu, in_menu_bar=True): + if in_menu_bar: + attr = { + 'oor:name': index, + 'oor:op': 'replace', + } + subnode = ET.SubElement(node, 'node', attr) + else: + subnode = node + + attr = {'oor:name': 'Title', 'oor:type': 'xs:string'} + sn1 = ET.SubElement(subnode, 'prop', attr) + for k, v in menu['title'].items(): + sn2 = ET.SubElement(sn1, 'value', {'xml:lang': k}) + sn2.text = v + value = self._get_context(menu['context']) + self._add_node_value(subnode, 'Context', value) + + if 'submenu' in menu: + sn = ET.SubElement(subnode, 'node', {'oor:name': 'Submenu'}) + for i, m in enumerate(menu['submenu']): + self._add_menu(id_extension, sn, f'{index}.s{i}', m) + if m.get('toolbar', False): + self._toolbars.append(m) + return + + value = f"service:{id_extension}?{menu['argument']}" + self._add_node_value(subnode, 'URL', value) + self._add_node_value(subnode, 'Target') + value = f"%origin%/{self._path_images}/{menu['icon']}" + self._add_node_value(subnode, 'ImageIdentifier', value) + return + + def new_addons(self, id_extension, data): + in_menu_bar = data['parent'] == 'OfficeMenuBar' + self._path_images = data['images'] + attr = { + 'oor:name': 'Addons', + 'oor:package': 'org.openoffice.Office', + } + attr.update(self.NS_ADDONS) + doc = ET.Element('oor:component-data', attr) + parent = ET.SubElement(doc, 'node', {'oor:name': 'AddonUI'}) + node = ET.SubElement(parent, 'node', {'oor:name': data['parent']}) + + op = 'fuse' + if in_menu_bar: + op = 'replace' + + attr = {'oor:name': id_extension, 'oor:op': op} + node = ET.SubElement(node, 'node', attr) + + if in_menu_bar: + attr = {'oor:name': 'Title', 'oor:type': 'xs:string'} + subnode = ET.SubElement(node, 'prop', attr) + for k, v in data['main'].items(): + sn = ET.SubElement(subnode, 'value', {'xml:lang': k}) + sn.text = v + + self._add_node_value(node, 'Target') + node = ET.SubElement(node, 'node', {'oor:name': 'Submenu'}) + + for i, menu in enumerate(data['menus']): + self._add_menu(id_extension, node, f'm{i}', menu, in_menu_bar) + if menu.get('toolbar', False): + self._toolbars.append(menu) + + if self._toolbars: + attr = {'oor:name': 'OfficeToolBar'} + toolbar = ET.SubElement(parent, 'node', attr) + attr = {'oor:name': id_extension, 'oor:op': 'replace'} + toolbar = ET.SubElement(toolbar, 'node', attr) + for t, menu in enumerate(self._toolbars): + self._add_menu(id_extension, toolbar, f't{t}', menu) + + return self._get_xml(doc) + + def _add_shortcut(self, node, key, id_extension, arg): + attr = {'oor:name': key, 'oor:op': 'fuse'} + subnode = ET.SubElement(node, 'node', attr) + subnode = ET.SubElement(subnode, 'prop', {'oor:name': 'Command'}) + subnode = ET.SubElement(subnode, 'value', {'xml:lang': 'en-US'}) + subnode.text = f"service:{id_extension}?{arg}" + return + + def _get_acceleartors(self, menu): + if 'submenu' in menu: + for m in menu['submenu']: + return self._get_acceleartors(m) + + if not menu.get('shortcut', ''): + return '' + + return menu + + def new_accelerators(self, id_extension, menus): + attr = { + 'oor:name': 'Accelerators', + 'oor:package': 'org.openoffice.Office', + } + attr.update(self.NS_ADDONS) + doc = ET.Element('oor:component-data', attr) + parent = ET.SubElement(doc, 'node', {'oor:name': 'PrimaryKeys'}) + + data = [] + for m in menus: + info = self._get_acceleartors(m) + if info: + data.append(info) + + node_global = None + node_modules = None + for m in data: + if m['context']: + if node_modules is None: + node_modules = ET.SubElement( + parent, 'node', {'oor:name': 'Modules'}) + for app in m['context'].split(','): + node = ET.SubElement( + node_modules, 'node', {'oor:name': self.CONTEXT[app]}) + self._add_shortcut( + node, m['shortcut'], id_extension, m['argument']) + else: + if node_global is None: + node_global = ET.SubElement( + parent, 'node', {'oor:name': 'Global'}) + self._add_shortcut( + node_global, m['shortcut'], id_extension, m['argument']) + + return self._get_xml(doc) + + def new_update(self, extension, url_oxt): + doc = ET.Element('description', self.NS_UPDATE) + ET.SubElement(doc, 'identifier', {'value': extension['id']}) + ET.SubElement(doc, 'version', {'value': extension['version']}) + node = ET.SubElement(doc, 'update-download') + ET.SubElement(node, 'src', {'xlink:href': url_oxt}) + node = ET.SubElement(doc, 'release-notes') + return self._get_xml(doc) + def _get_xml(self, doc): xml = parseString(ET.tostring(doc, encoding='utf-8')) return xml.toprettyxml(indent=' ', encoding='utf-8').decode('utf-8') @@ -155,11 +393,7 @@ def _get_files(path, filters=''): def _compress_oxt(): log.info('Compress OXT extension...') - path = DIRS['files'] - if not _exists(path): - _mkdir(path) - - path_oxt = _join(path, FILES['oxt']) + path_oxt = _join(DIRS['files'], FILES['oxt']) z = zipfile.ZipFile(path_oxt, 'w', compression=zipfile.ZIP_DEFLATED) root_len = len(os.path.abspath(DIRS['source'])) @@ -173,10 +407,6 @@ def _compress_oxt(): z.write(fullpath, file_name, zipfile.ZIP_DEFLATED) z.close() - if DATA['update']: - path_xml = _join(path, FILES['update']) - _save(path_xml, DATA['update']) - log.info('Extension OXT created sucesfully...') return @@ -294,6 +524,10 @@ def _compile_idl(): def _update_files(): + path_files = DIRS['files'] + if not _exists(path_files): + _mkdir(path_files) + path_source = DIRS['source'] for k, v in INFO.items(): @@ -325,16 +559,21 @@ def _update_files(): data = xml.new_manifest(DATA['manifest']) _save(path, data) - path = _join(path_source, DIRS['office']) - _mkdir(path) - path = _join(path_source, DIRS['office'], FILES['shortcut']) - _save(path, DATA['shortcut']) - - path = _join(path_source, FILES['addons']) - _save(path, DATA['addons']) - path = _join(path_source, FILES['description']) - _save(path, DATA['description']) + data = xml.new_description(DATA['description']) + _save(path, data) + + if TYPE_EXTENSION == 1: + path = _join(path_source, FILES['addons']) + data = xml.new_addons(EXTENSION['id'], DATA['addons']) + _save(path, data) + + path = _join(path_source, DIRS['office']) + _mkdir(path) + path = _join(path_source, DIRS['office'], FILES['shortcut']) + data = xml.new_accelerators(EXTENSION['id'], DATA['addons']['menus']) + _save(path, data) + if TYPE_EXTENSION == 3: path = _join(path_source, FILES['addin']) @@ -342,10 +581,15 @@ def _update_files(): if USE_LOCALES: msg = "Don't forget generate DOMAIN.pot for locales" - log.info(msg) for lang in EXTENSION['languages']: path = _join(path_source, DIRS['locales'], lang, 'LC_MESSAGES') Path(path).mkdir(parents=True, exist_ok=True) + log.info(msg) + + if DATA['update']: + path_xml = _join(path_files, FILES['update']) + data = xml.new_update(EXTENSION, DATA['update']) + _save(path_xml, data) _compile_idl() return @@ -373,7 +617,8 @@ def _get_info_path(path): def _zip_embed(source, files): PATH = 'Scripts/python/' - EASYMACRO = 'easymacro.' + EASYMACRO = 'easymacro2.py' + FILE_PYC = 'easymacro.pyc' p, f, name, e = _get_info_path(source) now = datetime.now().strftime('_%Y%m%d_%H%M%S') @@ -381,12 +626,10 @@ def _zip_embed(source, files): copyfile(source, path_source) target = source - with zipfile.PyZipFile(EASYMACRO + 'zip', mode='w') as zf: - zf.writepy(EASYMACRO + 'py') - + py_compile.compile(EASYMACRO, FILE_PYC) xml = LiboXML() - path_easymacro = PATH + EASYMACRO + 'zip' + path_easymacro = PATH + FILE_PYC names = [f[1] for f in files] + [path_easymacro] nodes = [] with zipfile.ZipFile(target, 'w', compression=zipfile.ZIP_DEFLATED) as zt: @@ -405,14 +648,14 @@ def _zip_embed(source, files): data.append(name) zt.write(path, name) - zt.write(EASYMACRO + 'zip', path_easymacro) + zt.write(FILE_PYC, path_easymacro) data.append(path_easymacro) xml.parse_manifest(xml_manifest) xml_manifest = xml.add_data_manifest(data) zt.writestr(path_manifest, xml_manifest) - os.unlink(EASYMACRO + 'zip') + os.unlink(FILE_PYC) return @@ -504,7 +747,9 @@ def main(args): if not _validate_update(): return - _update_files() + if not args.only_compress: + _update_files() + _compress_oxt() if args.install: @@ -529,6 +774,8 @@ def _process_command_line_arguments(): default=False, required=False) parser.add_argument('-u', '--update', dest='update', action='store_true', default=False, required=False) + parser.add_argument('-oc', '--only_compress', dest='only_compress', + action='store_true', default=False, required=False) return parser.parse_args()