From b09068ab99b3a600db21f8a7c70dee3d55981c80 Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Tue, 6 Jun 2023 22:12:56 +0200 Subject: [PATCH] Add annotations to odt class --- novelwriter/core/tohtml.py | 6 +- novelwriter/core/tokenizer.py | 16 +- novelwriter/core/tomd.py | 7 +- novelwriter/core/toodt.py | 516 +++++++++--------- tests/reference/coreToOdt_SaveFull_styles.xml | 12 +- tests/test_core/test_core_toodt.py | 98 ++-- 6 files changed, 322 insertions(+), 333 deletions(-) diff --git a/novelwriter/core/tohtml.py b/novelwriter/core/tohtml.py index 323b617c..f02daafb 100644 --- a/novelwriter/core/tohtml.py +++ b/novelwriter/core/tohtml.py @@ -1,7 +1,6 @@ """ novelWriter – HTML Text Converter ================================= -Extends the Tokenizer class to generate HTML output File History: Created: 2019-05-07 [0.0.1] @@ -37,6 +36,11 @@ logger = logging.getLogger(__name__) class ToHtml(Tokenizer): + """Core: HTML Document Writer + + Extend the Tokenizer class to writer HTML output. This class is + also used by the Document Viewer, and Manuscript Build Preview. + """ M_PREVIEW = 0 # Tweak output for the DocViewer M_EXPORT = 1 # Tweak output for saving to HTML or printing diff --git a/novelwriter/core/tokenizer.py b/novelwriter/core/tokenizer.py index 34307a93..62a6a71f 100644 --- a/novelwriter/core/tokenizer.py +++ b/novelwriter/core/tokenizer.py @@ -1,7 +1,6 @@ """ novelWriter – Text Tokenizer ============================ -Split novelWriter plain text into its elements File History: Created: 2019-05-05 [0.0.1] Tokenizer @@ -55,6 +54,13 @@ def stripEscape(text): class Tokenizer(ABC): + """Core: Text Tokenizer Abstract Base Class + + This is the base class for all document build classes. It parses the + novelWriter markup format and generates a registry of tokens and + text that can be further processed into other output formats by + subclasses. + """ # In-Text Format FMT_B_B = 1 # Begin bold @@ -309,6 +315,9 @@ class Tokenizer(ABC): """Add a heading at the start of a new root folder.""" if not self._project.tree.checkType(tHandle, nwItemType.ROOT): return False + theItem = self._project.tree[tHandle] + if not theItem: + return False if self._isFirst: textAlign = self.A_CENTRE @@ -316,7 +325,6 @@ class Tokenizer(ABC): else: textAlign = self.A_PBB | self.A_CENTRE - theItem = self._project.tree[tHandle] locNotes = self._localLookup("Notes") theTitle = f"{locNotes}: {theItem.itemName}" self._tokens = [] @@ -781,10 +789,10 @@ class HeadingFormatter: chWord = self._project.localLookup(self._chCount) hFormat = hFormat.replace(nwHeadFmt.CH_WORD, chWord) if nwHeadFmt.CH_ROML in hFormat: - chRom = numberToRoman(self._chCount, True) + chRom = numberToRoman(self._chCount, toLower=True) hFormat = hFormat.replace(nwHeadFmt.CH_ROML, chRom) if nwHeadFmt.CH_ROMU in hFormat: - chRom = numberToRoman(self._chCount, False) + chRom = numberToRoman(self._chCount, toLower=False) hFormat = hFormat.replace(nwHeadFmt.CH_ROMU, chRom) return hFormat diff --git a/novelwriter/core/tomd.py b/novelwriter/core/tomd.py index 67eaf9a4..8e05c40b 100644 --- a/novelwriter/core/tomd.py +++ b/novelwriter/core/tomd.py @@ -1,7 +1,6 @@ """ novelWriter – Markdown Text Converter ===================================== -Extends the Tokenizer class to generate Makrdown output File History: Created: 2021-02-06 [1.2b1] @@ -36,6 +35,12 @@ logger = logging.getLogger(__name__) class ToMarkdown(Tokenizer): + """Core: Markdown Document Writer + + Extend the Tokenizer class to writer Markdown output. It supports + both Standard Markdown and GitHub Flavour Markdown (Extended). The + class also supports concatenating novelWriter markup files. + """ M_STD = 0 # Standard Markdown M_GH = 1 # GitHub Markdown diff --git a/novelwriter/core/toodt.py b/novelwriter/core/toodt.py index b67d7a64..888e4e42 100644 --- a/novelwriter/core/toodt.py +++ b/novelwriter/core/toodt.py @@ -1,7 +1,6 @@ """ novelWriter – ODT Text Converter ================================ -Extends the Tokenizer class to generate ODT and FODT files File History: Created: 2021-01-26 [1.2b1] ToOdt @@ -25,8 +24,10 @@ General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . """ +from __future__ import annotations import logging +from pathlib import Path import xml.etree.ElementTree as ET from hashlib import sha256 @@ -36,6 +37,7 @@ from datetime import datetime from novelwriter import __version__ from novelwriter.common import xmlIndent from novelwriter.constants import nwKeyWords, nwLabels +from novelwriter.core.project import NWProject from novelwriter.core.tokenizer import Tokenizer, stripEscape logger = logging.getLogger(__name__) @@ -55,9 +57,8 @@ for ns, uri in XML_NS.items(): ET.register_namespace(ns, uri) -def _mkTag(ns, tag): - """Assemble namespace and tag name. - """ +def _mkTag(ns: str, tag: str) -> str: + """Assemble namespace and tag name.""" uri = XML_NS.get(ns, "") if uri: return f"{{{uri}}}{tag}" @@ -89,9 +90,16 @@ M_DEL = ~X_DEL class ToOdt(Tokenizer): + """Core: Open Document Writer - def __init__(self, theProject, isFlat): - super().__init__(theProject) + Extend the Tokenizer class to writer Open Document files. The output + should conform to the 1.3 Extended standard. + + Test with: https://odfvalidator.org/ + """ + + def __init__(self, project: NWProject, isFlat: bool): + super().__init__(project) self._isFlat = isFlat # Flat: .fodt, otherwise .odt @@ -178,36 +186,26 @@ class ToOdt(Tokenizer): # Setters ## - def setLanguage(self, theLang): - """Set language for the document. - """ - if theLang is None: - return False + def setLanguage(self, language: str): + """Set language for the document.""" + if language: + langBits = language.split("_") + self._dLanguage = langBits[0] + if len(langBits) > 1: + self._dCountry = langBits[1] + return - langBits = theLang.split("_") - self._dLanguage = langBits[0] - if len(langBits) > 1: - self._dCountry = langBits[1] - - return True - - def setColourHeaders(self, doColour): - """Enable/disable coloured headings and comments. - """ - self._colourHead = doColour + def setColourHeaders(self, state: bool): + """Enable/disable coloured headings and comments.""" + self._colourHead = state return ## # Class Methods ## - def getErrors(self): - """Return the list of errors.""" - return self._errData - def initDocument(self): - """Initialises a new open document XML tree. - """ + """Initialises a new open document XML tree.""" # Initialise Variables # ==================== @@ -369,8 +367,7 @@ class ToOdt(Tokenizer): return def doConvert(self): - """Convert the list of text tokens into XML elements. - """ + """Convert the list of text tokens into XML elements.""" self._result = "" # Not used, but cleared just in case odtTags = { @@ -421,12 +418,12 @@ class ToOdt(Tokenizer): if self._doJustify: parStyle.setTextAlign("left") - if len(thisPar) > 0: + if len(thisPar) > 0 and parStyle is not None: tTemp = "\n".join(thisPar) fTemp = " ".join(thisFmt) tTxt = tTemp.rstrip() tFmt = fTemp[:len(tTxt)] - self._addTextPar("Text_20_body", parStyle, tTxt, theFmt=tFmt) + self._addTextPar("Text_20_body", parStyle, tTxt, tFmt=tFmt) thisPar = [] thisFmt = [] @@ -477,41 +474,37 @@ class ToOdt(Tokenizer): elif tType == self.T_SYNOPSIS and self._doSynopsis: tTemp, fTemp = self._formatSynopsis(tText) - self._addTextPar("Text_20_Meta", oStyle, tTemp, theFmt=fTemp) + self._addTextPar("Text_20_Meta", oStyle, tTemp, tFmt=fTemp) elif tType == self.T_COMMENT and self._doComments: tTemp, fTemp = self._formatComments(tText) - self._addTextPar("Text_20_Meta", oStyle, tTemp, theFmt=fTemp) + self._addTextPar("Text_20_Meta", oStyle, tTemp, tFmt=fTemp) elif tType == self.T_KEYWORD and self._doKeywords: tTemp, fTemp = self._formatKeywords(tText) - self._addTextPar("Text_20_Meta", oStyle, tTemp, theFmt=fTemp) + self._addTextPar("Text_20_Meta", oStyle, tTemp, tFmt=fTemp) return def closeDocument(self): - """Return the serialised XML document - """ + """Return the serialised XML document""" # Build the auto-generated styles for styleName, styleObj in self._autoPara.values(): styleObj.packXML(self._xAuto, styleName) for styleName, styleObj in self._autoText.values(): styleObj.packXML(self._xAuto, styleName) - return - def saveFlatXML(self, savePath): - """Save the data to an .fodt file. - """ - with open(savePath, mode="wb") as outFile: + def saveFlatXML(self, path: str | Path): + """Save the data to an .fodt file.""" + with open(path, mode="wb") as fObj: xml = ET.ElementTree(self._dFlat) xmlIndent(xml) - xml.write(outFile, encoding="utf-8", xml_declaration=True) + xml.write(fObj, encoding="utf-8", xml_declaration=True) return - def saveOpenDocText(self, savePath): - """Save the data to an .odt file. - """ + def saveOpenDocText(self, path: str | Path): + """Save the data to an .odt file.""" mMani = _mkTag("manifest", "manifest") mVers = _mkTag("manifest", "version") mPath = _mkTag("manifest", "full-path") @@ -534,7 +527,7 @@ class ToOdt(Tokenizer): xml = ET.ElementTree(xObj) xml.write(fObj, encoding="utf-8", xml_declaration=True) - with ZipFile(savePath, mode="w") as outZip: + with ZipFile(path, mode="w") as outZip: outZip.writestr("mimetype", X_MIME) putInZip("META-INF/manifest.xml", xMani, outZip) putInZip("settings.xml", xSett, outZip) @@ -548,49 +541,48 @@ class ToOdt(Tokenizer): # Internal Functions ## - def _formatSynopsis(self, tText): - """Apply formatting to synopsis lines. - """ + def _formatSynopsis(self, text: str) -> tuple[str, str]: + """Apply formatting to synopsis lines.""" sSynop = self._localLookup("Synopsis") - rTxt = "**{0}:** {1}".format(sSynop, tText) - rFmt = "_B{0} b_ {1}".format(" "*len(sSynop), " "*len(tText)) + rTxt = "**{0}:** {1}".format(sSynop, text) + rFmt = "_B{0} b_ {1}".format(" "*len(sSynop), " "*len(text)) return rTxt, rFmt - def _formatComments(self, tText): - """Apply formatting to comments. - """ + def _formatComments(self, text: str) -> tuple[str, str]: + """Apply formatting to comments.""" sComm = self._localLookup("Comment") - rTxt = "**{0}:** {1}".format(sComm, tText) - rFmt = "_B{0} b_ {1}".format(" "*len(sComm), " "*len(tText)) + rTxt = "**{0}:** {1}".format(sComm, text) + rFmt = "_B{0} b_ {1}".format(" "*len(sComm), " "*len(text)) return rTxt, rFmt - def _formatKeywords(self, tText): - """Apply formatting to keywords. - """ - isValid, theBits, _ = self._project.index.scanThis("@"+tText) - if not isValid or not theBits: - return "" + def _formatKeywords(self, text: str) -> tuple[str, str]: + """Apply formatting to keywords.""" + valid, bits, _ = self._project.index.scanThis("@"+text) + if not valid or not bits: + return "", "" rTxt = "" rFmt = "" - if theBits[0] in nwLabels.KEY_NAME: - tText = nwLabels.KEY_NAME[theBits[0]] - rTxt += "**{0}:** ".format(tText) - rFmt += "_B{0} b_ ".format(" "*len(tText)) - if len(theBits) > 1: - if theBits[0] == nwKeyWords.TAG_KEY: - rTxt += theBits[1] - rFmt += " "*len(theBits[1]) + if bits[0] in nwLabels.KEY_NAME: + text = nwLabels.KEY_NAME[bits[0]] + rTxt += "**{0}:** ".format(text) + rFmt += "_B{0} b_ ".format(" "*len(text)) + if len(bits) > 1: + if bits[0] == nwKeyWords.TAG_KEY: + rTxt += bits[1] + rFmt += " "*len(bits[1]) else: - tTags = ", ".join(theBits[1:]) + tTags = ", ".join(bits[1:]) rTxt += tTags rFmt += (" "*len(tTags)) return rTxt, rFmt - def _addTextPar(self, styleName, oStyle, theText, theFmt="", isHead=False, oLevel=None): - """Add a text paragraph to the text XML element. - """ + def _addTextPar( + self, styleName: str, oStyle: ODTParagraphStyle, tText: str, tFmt: str = "", + isHead: bool = False, oLevel: str | None = None + ): + """Add a text paragraph to the text XML element.""" tAttr = {} tAttr[_mkTag("text", "style-name")] = self._paraStyle(styleName, oStyle) if oLevel is not None: @@ -603,16 +595,16 @@ class ToOdt(Tokenizer): # xmlIndent will add a line break if the first subelement is a span. xElem.text = "" - if not theText: + if not tText: return ## # Process Formatting ## - if len(theText) != len(theFmt): + if len(tText) != len(tFmt): # Generate an empty format if there isn't any or it doesn't match - theFmt = " "*len(theText) + tFmt = " "*len(tText) # The formatting loop tTemp = "" @@ -622,23 +614,23 @@ class ToOdt(Tokenizer): parProc = XMLParagraph(xElem) - for i, c in enumerate(theText): + for i, c in enumerate(tText): - if theFmt[i] == " ": + if tFmt[i] == " ": tTemp += c - elif theFmt[i] == "_": + elif tFmt[i] == "_": continue - elif theFmt[i] == "B": + elif tFmt[i] == "B": xFmt |= X_BLD - elif theFmt[i] == "b": + elif tFmt[i] == "b": xFmt &= M_BLD - elif theFmt[i] == "I": + elif tFmt[i] == "I": xFmt |= X_ITA - elif theFmt[i] == "i": + elif tFmt[i] == "i": xFmt &= M_ITA - elif theFmt[i] == "S": + elif tFmt[i] == "S": xFmt |= X_DEL - elif theFmt[i] == "s": + elif tFmt[i] == "s": xFmt &= M_DEL else: pErr += 1 @@ -669,9 +661,8 @@ class ToOdt(Tokenizer): return - def _paraStyle(self, parName, oStyle): - """Return a name for a style object. - """ + def _paraStyle(self, parName: str, oStyle: ODTParagraphStyle) -> str: + """Return a name for a style object.""" refStyle = self._mainPara.get(parName, None) if refStyle is None: logger.error("Unknown paragraph style '%s'", parName) @@ -690,29 +681,27 @@ class ToOdt(Tokenizer): return newName - def _textStyle(self, tFmt): - """Return a text style for a given style code. - """ - if tFmt in self._autoText: - return self._autoText[tFmt][0] + def _textStyle(self, hFmt: int) -> str: + """Return a text style for a given style code.""" + if hFmt in self._autoText: + return self._autoText[hFmt][0] newName = "T%d" % (len(self._autoText) + 1) newStyle = ODTTextStyle() - if tFmt & X_BLD: + if hFmt & X_BLD: newStyle.setFontWeight("bold") - if tFmt & X_ITA: + if hFmt & X_ITA: newStyle.setFontStyle("italic") - if tFmt & X_DEL: + if hFmt & X_DEL: newStyle.setStrikeStyle("solid") newStyle.setStrikeType("single") - self._autoText[tFmt] = (newName, newStyle) + self._autoText[hFmt] = (newName, newStyle) return newName - def _emToCm(self, emVal): - """Converts an em value to centimetres. - """ + def _emToCm(self, emVal: float) -> str: + """Converts an em value to centimetres.""" return f"{emVal*2.54/72*self._textSize:.3f}cm" ## @@ -720,110 +709,107 @@ class ToOdt(Tokenizer): ## def _pageStyles(self): - """Set the default page style. - """ - theAttr = {} - theAttr[_mkTag("style", "name")] = "PM1" + """Set the default page style.""" + tAttr = {} + tAttr[_mkTag("style", "name")] = "PM1" if self._isFlat: - xPage = ET.SubElement(self._xAuto, _mkTag("style", "page-layout"), attrib=theAttr) + xPage = ET.SubElement(self._xAuto, _mkTag("style", "page-layout"), attrib=tAttr) else: - xPage = ET.SubElement(self._xAut2, _mkTag("style", "page-layout"), attrib=theAttr) + xPage = ET.SubElement(self._xAut2, _mkTag("style", "page-layout"), attrib=tAttr) - theAttr = {} - theAttr[_mkTag("fo", "margin-top")] = self._mDocTop - theAttr[_mkTag("fo", "margin-bottom")] = self._mDocBtm - theAttr[_mkTag("fo", "margin-left")] = self._mDocLeft - theAttr[_mkTag("fo", "margin-right")] = self._mDocRight - ET.SubElement(xPage, _mkTag("style", "page-layout-properties"), attrib=theAttr) + tAttr = {} + tAttr[_mkTag("fo", "margin-top")] = self._mDocTop + tAttr[_mkTag("fo", "margin-bottom")] = self._mDocBtm + tAttr[_mkTag("fo", "margin-left")] = self._mDocLeft + tAttr[_mkTag("fo", "margin-right")] = self._mDocRight + ET.SubElement(xPage, _mkTag("style", "page-layout-properties"), attrib=tAttr) xHead = ET.SubElement(xPage, _mkTag("style", "header-style")) - theAttr = {} - theAttr[_mkTag("fo", "min-height")] = "0.600cm" - theAttr[_mkTag("fo", "margin-left")] = "0.000cm" - theAttr[_mkTag("fo", "margin-right")] = "0.000cm" - theAttr[_mkTag("fo", "margin-bottom")] = "0.500cm" - ET.SubElement(xHead, _mkTag("style", "header-footer-properties"), attrib=theAttr) + tAttr = {} + tAttr[_mkTag("fo", "min-height")] = "0.600cm" + tAttr[_mkTag("fo", "margin-left")] = "0.000cm" + tAttr[_mkTag("fo", "margin-right")] = "0.000cm" + tAttr[_mkTag("fo", "margin-bottom")] = "0.500cm" + ET.SubElement(xHead, _mkTag("style", "header-footer-properties"), attrib=tAttr) return def _defaultStyles(self): - """Set the default styles. - """ + """Set the default styles.""" # Add Paragraph Family Style # ========================== - theAttr = {} - theAttr[_mkTag("style", "family")] = "paragraph" - xStyl = ET.SubElement(self._xStyl, _mkTag("style", "default-style"), attrib=theAttr) + tAttr = {} + tAttr[_mkTag("style", "family")] = "paragraph" + xStyl = ET.SubElement(self._xStyl, _mkTag("style", "default-style"), attrib=tAttr) - theAttr = {} - theAttr[_mkTag("style", "line-break")] = "strict" - theAttr[_mkTag("style", "tab-stop-distance")] = "1.251cm" - theAttr[_mkTag("style", "writing-mode")] = "page" - ET.SubElement(xStyl, _mkTag("style", "paragraph-properties"), attrib=theAttr) + tAttr = {} + tAttr[_mkTag("style", "line-break")] = "strict" + tAttr[_mkTag("style", "tab-stop-distance")] = "1.251cm" + tAttr[_mkTag("style", "writing-mode")] = "page" + ET.SubElement(xStyl, _mkTag("style", "paragraph-properties"), attrib=tAttr) - theAttr = {} - theAttr[_mkTag("style", "font-name")] = self._textFont - theAttr[_mkTag("fo", "font-family")] = self._fontFamily - theAttr[_mkTag("fo", "font-size")] = self._fSizeText - theAttr[_mkTag("fo", "language")] = self._dLanguage - theAttr[_mkTag("fo", "country")] = self._dCountry - ET.SubElement(xStyl, _mkTag("style", "text-properties"), attrib=theAttr) + tAttr = {} + tAttr[_mkTag("style", "font-name")] = self._textFont + tAttr[_mkTag("fo", "font-family")] = self._fontFamily + tAttr[_mkTag("fo", "font-size")] = self._fSizeText + tAttr[_mkTag("fo", "language")] = self._dLanguage + tAttr[_mkTag("fo", "country")] = self._dCountry + ET.SubElement(xStyl, _mkTag("style", "text-properties"), attrib=tAttr) # Add Standard Paragraph Style # ============================ - theAttr = {} - theAttr[_mkTag("style", "name")] = "Standard" - theAttr[_mkTag("style", "family")] = "paragraph" - theAttr[_mkTag("style", "class")] = "text" - xStyl = ET.SubElement(self._xStyl, _mkTag("style", "style"), attrib=theAttr) + tAttr = {} + tAttr[_mkTag("style", "name")] = "Standard" + tAttr[_mkTag("style", "family")] = "paragraph" + tAttr[_mkTag("style", "class")] = "text" + xStyl = ET.SubElement(self._xStyl, _mkTag("style", "style"), attrib=tAttr) - theAttr = {} - theAttr[_mkTag("style", "font-name")] = self._textFont - theAttr[_mkTag("fo", "font-family")] = self._fontFamily - theAttr[_mkTag("fo", "font-size")] = self._fSizeText - ET.SubElement(xStyl, _mkTag("style", "text-properties"), attrib=theAttr) + tAttr = {} + tAttr[_mkTag("style", "font-name")] = self._textFont + tAttr[_mkTag("fo", "font-family")] = self._fontFamily + tAttr[_mkTag("fo", "font-size")] = self._fSizeText + ET.SubElement(xStyl, _mkTag("style", "text-properties"), attrib=tAttr) # Add Default Heading Style # ========================= - theAttr = {} - theAttr[_mkTag("style", "name")] = "Heading" - theAttr[_mkTag("style", "family")] = "paragraph" - theAttr[_mkTag("style", "parent-style-name")] = "Standard" - theAttr[_mkTag("style", "next-style-name")] = "Text_20_body" - theAttr[_mkTag("style", "class")] = "text" - xStyl = ET.SubElement(self._xStyl, _mkTag("style", "style"), attrib=theAttr) + tAttr = {} + tAttr[_mkTag("style", "name")] = "Heading" + tAttr[_mkTag("style", "family")] = "paragraph" + tAttr[_mkTag("style", "parent-style-name")] = "Standard" + tAttr[_mkTag("style", "next-style-name")] = "Text_20_body" + tAttr[_mkTag("style", "class")] = "text" + xStyl = ET.SubElement(self._xStyl, _mkTag("style", "style"), attrib=tAttr) - theAttr = {} - theAttr[_mkTag("fo", "margin-top")] = self._mTopHead - theAttr[_mkTag("fo", "margin-bottom")] = self._mBotHead - theAttr[_mkTag("fo", "keep-with-next")] = "always" - ET.SubElement(xStyl, _mkTag("style", "paragraph-properties"), attrib=theAttr) + tAttr = {} + tAttr[_mkTag("fo", "margin-top")] = self._mTopHead + tAttr[_mkTag("fo", "margin-bottom")] = self._mBotHead + tAttr[_mkTag("fo", "keep-with-next")] = "always" + ET.SubElement(xStyl, _mkTag("style", "paragraph-properties"), attrib=tAttr) - theAttr = {} - theAttr[_mkTag("style", "font-name")] = self._textFont - theAttr[_mkTag("fo", "font-family")] = self._fontFamily - theAttr[_mkTag("fo", "font-size")] = self._fSizeHead - ET.SubElement(xStyl, _mkTag("style", "text-properties"), attrib=theAttr) + tAttr = {} + tAttr[_mkTag("style", "font-name")] = self._textFont + tAttr[_mkTag("fo", "font-family")] = self._fontFamily + tAttr[_mkTag("fo", "font-size")] = self._fSizeHead + ET.SubElement(xStyl, _mkTag("style", "text-properties"), attrib=tAttr) # Add Header and Footer Styles # ============================ - theAttr = {} - theAttr[_mkTag("style", "name")] = "Header_20_and_20_Footer" - theAttr[_mkTag("style", "display-name")] = "Header and Footer" - theAttr[_mkTag("style", "family")] = "paragraph" - theAttr[_mkTag("style", "parent-style-name")] = "Standard" - theAttr[_mkTag("style", "class")] = "extra" - ET.SubElement(self._xStyl, _mkTag("style", "style"), attrib=theAttr) + tAttr = {} + tAttr[_mkTag("style", "name")] = "Header_20_and_20_Footer" + tAttr[_mkTag("style", "display-name")] = "Header and Footer" + tAttr[_mkTag("style", "family")] = "paragraph" + tAttr[_mkTag("style", "parent-style-name")] = "Standard" + tAttr[_mkTag("style", "class")] = "extra" + ET.SubElement(self._xStyl, _mkTag("style", "style"), attrib=tAttr) return def _useableStyles(self): - """Set the usable styles. - """ + """Set the usable styles.""" # Add Text Body Style # =================== @@ -977,12 +963,11 @@ class ToOdt(Tokenizer): return def _writeHeader(self): - """Write the header elements. - """ - theAttr = {} - theAttr[_mkTag("style", "name")] = "Standard" - theAttr[_mkTag("style", "page-layout-name")] = "PM1" - xPage = ET.SubElement(self._xMast, _mkTag("style", "master-page"), attrib=theAttr) + """Write the header elements.""" + tAttr = {} + tAttr[_mkTag("style", "name")] = "Standard" + tAttr[_mkTag("style", "page-layout-name")] = "PM1" + xPage = ET.SubElement(self._xMast, _mkTag("style", "master-page"), attrib=tAttr) # Standard Page Header xHead = ET.SubElement(xPage, _mkTag("style", "header")) @@ -1062,28 +1047,28 @@ class ODTParagraphStyle: # Attribute Setters ## - def setDisplayName(self, theValue): - self._mAttr["display-name"][1] = str(theValue) + def setDisplayName(self, value: str | None): + self._mAttr["display-name"][1] = value return - def setParentStyleName(self, theValue): - self._mAttr["parent-style-name"][1] = str(theValue) + def setParentStyleName(self, value: str | None): + self._mAttr["parent-style-name"][1] = value return - def setNextStyleName(self, theValue): - self._mAttr["next-style-name"][1] = str(theValue) + def setNextStyleName(self, value: str | None): + self._mAttr["next-style-name"][1] = value return - def setOutlineLevel(self, theValue): - if theValue in self.VALID_LEVEL: - self._mAttr["default-outline-level"][1] = str(theValue) + def setOutlineLevel(self, value: str | None): + if value in self.VALID_LEVEL: + self._mAttr["default-outline-level"][1] = value else: self._mAttr["default-outline-level"][1] = None return - def setClass(self, theValue): - if theValue in self.VALID_CLASS: - self._mAttr["class"][1] = str(theValue) + def setClass(self, value: str | None): + if value in self.VALID_CLASS: + self._mAttr["class"][1] = value else: self._mAttr["class"][1] = None return @@ -1092,43 +1077,43 @@ class ODTParagraphStyle: # Paragraph Setters ## - def setMarginTop(self, theValue): - self._pAttr["margin-top"][1] = str(theValue) + def setMarginTop(self, value: str | None): + self._pAttr["margin-top"][1] = value return - def setMarginBottom(self, theValue): - self._pAttr["margin-bottom"][1] = str(theValue) + def setMarginBottom(self, value: str | None): + self._pAttr["margin-bottom"][1] = value return - def setMarginLeft(self, theValue): - self._pAttr["margin-left"][1] = str(theValue) + def setMarginLeft(self, value: str | None): + self._pAttr["margin-left"][1] = value return - def setMarginRight(self, theValue): - self._pAttr["margin-right"][1] = str(theValue) + def setMarginRight(self, value: str | None): + self._pAttr["margin-right"][1] = value return - def setLineHeight(self, theValue): - self._pAttr["line-height"][1] = str(theValue) + def setLineHeight(self, value: str | None): + self._pAttr["line-height"][1] = value return - def setTextAlign(self, theValue): - if theValue in self.VALID_ALIGN: - self._pAttr["text-align"][1] = str(theValue) + def setTextAlign(self, value: str | None): + if value in self.VALID_ALIGN: + self._pAttr["text-align"][1] = value else: self._pAttr["text-align"][1] = None return - def setBreakBefore(self, theValue): - if theValue in self.VALID_BREAK: - self._pAttr["break-before"][1] = str(theValue) + def setBreakBefore(self, value: str | None): + if value in self.VALID_BREAK: + self._pAttr["break-before"][1] = value else: self._pAttr["break-before"][1] = None return - def setBreakAfter(self, theValue): - if theValue in self.VALID_BREAK: - self._pAttr["break-after"][1] = str(theValue) + def setBreakAfter(self, value: str | None): + if value in self.VALID_BREAK: + self._pAttr["break-after"][1] = value else: self._pAttr["break-after"][1] = None return @@ -1137,38 +1122,38 @@ class ODTParagraphStyle: # Text Setters ## - def setFontName(self, theValue): - self._tAttr["font-name"][1] = str(theValue) + def setFontName(self, value: str | None): + self._tAttr["font-name"][1] = value return - def setFontFamily(self, theValue): - self._tAttr["font-family"][1] = str(theValue) + def setFontFamily(self, value: str | None): + self._tAttr["font-family"][1] = value return - def setFontSize(self, theValue): - self._tAttr["font-size"][1] = str(theValue) + def setFontSize(self, value: str | None): + self._tAttr["font-size"][1] = value return - def setFontWeight(self, theValue): - if theValue in self.VALID_WEIGHT: - self._tAttr["font-weight"][1] = str(theValue) + def setFontWeight(self, value: str | None): + if value in self.VALID_WEIGHT: + self._tAttr["font-weight"][1] = value else: self._tAttr["font-weight"][1] = None return - def setColor(self, theValue): - self._tAttr["color"][1] = str(theValue) + def setColor(self, value: str | None): + self._tAttr["color"][1] = value return - def setOpacity(self, theValue): - self._tAttr["opacity"][1] = str(theValue) + def setOpacity(self, value: str | None): + self._tAttr["opacity"][1] = value return ## # Methods ## - def checkNew(self, refStyle): + def checkNew(self, refStyle: ODTParagraphStyle): """Check if there are new settings in refStyle that differ from those in the current object. """ @@ -1183,9 +1168,8 @@ class ODTParagraphStyle: return True return False - def getID(self): - """Generate a unique ID from the settings. - """ + def getID(self) -> str: + """Generate a unique ID from the settings.""" theString = ( f"Paragraph:Main:{str(self._mAttr)}:" f"Paragraph:Para:{str(self._pAttr)}:" @@ -1193,11 +1177,10 @@ class ODTParagraphStyle: ) return sha256(theString.encode()).hexdigest() - def packXML(self, xParent, xName): - """Pack the content into an xml element. - """ + def packXML(self, xParent: ET.Element, name: str): + """Pack the content into an xml element.""" theAttr = {} - theAttr[_mkTag("style", "name")] = xName + theAttr[_mkTag("style", "name")] = name theAttr[_mkTag("style", "family")] = "paragraph" for aName, (aNm, aVal) in self._mAttr.items(): if aVal is not None: @@ -1252,30 +1235,30 @@ class ODTTextStyle: # Setters ## - def setFontWeight(self, theValue): - if theValue in self.VALID_WEIGHT: - self._tAttr["font-weight"][1] = str(theValue) + def setFontWeight(self, value: str | None): + if value in self.VALID_WEIGHT: + self._tAttr["font-weight"][1] = value else: self._tAttr["font-weight"][1] = None return - def setFontStyle(self, theValue): - if theValue in self.VALID_STYLE: - self._tAttr["font-style"][1] = str(theValue) + def setFontStyle(self, value: str | None): + if value in self.VALID_STYLE: + self._tAttr["font-style"][1] = value else: self._tAttr["font-style"][1] = None return - def setStrikeStyle(self, theValue): - if theValue in self.VALID_LSTYLE: - self._tAttr["text-line-through-style"][1] = str(theValue) + def setStrikeStyle(self, value: str | None): + if value in self.VALID_LSTYLE: + self._tAttr["text-line-through-style"][1] = value else: self._tAttr["text-line-through-style"][1] = None return - def setStrikeType(self, theValue): - if theValue in self.VALID_LTYPE: - self._tAttr["text-line-through-type"][1] = str(theValue) + def setStrikeType(self, value: str | None): + if value in self.VALID_LTYPE: + self._tAttr["text-line-through-type"][1] = value else: self._tAttr["text-line-through-type"][1] = None return @@ -1284,11 +1267,10 @@ class ODTTextStyle: # Methods ## - def packXML(self, xParent, xName): - """Pack the content into an xml element. - """ + def packXML(self, xParent: ET.Element, name: str): + """Pack the content into an xml element.""" theAttr = {} - theAttr[_mkTag("style", "name")] = xName + theAttr[_mkTag("style", "name")] = name theAttr[_mkTag("style", "family")] = "text" xEntry = ET.SubElement(xParent, _mkTag("style", "style"), attrib=theAttr) @@ -1335,7 +1317,7 @@ class XMLParagraph: object and attribute is written to, """ - def __init__(self, xRoot): + def __init__(self, xRoot: ET.Element): self._xRoot = xRoot self._xTail = ET.Element("") @@ -1348,17 +1330,17 @@ class XMLParagraph: return - def appendText(self, text): + def appendText(self, tText: str): """Append text to the XML element. We do this one character at the time in order to be able to process line breaks, tabs and - spaces separately. Multiple spaces above one are concatenated - into a single tag, and must therefore be processed separately. + spaces separately. Multiple spaces are concatenated into a + single tag, and must therefore be processed separately. """ - text = stripEscape(text) + tText = stripEscape(tText) nSpaces = 0 - self._rawTxt += text + self._rawTxt += tText - for c in text: + for c in tText: if c == " ": nSpaces += 1 continue @@ -1395,38 +1377,36 @@ class XMLParagraph: else: if self._nState == X_ROOT_TEXT: - self._xRoot.text += c + self._xRoot.text = (self._xRoot.text or "") + c self._chrPos += 1 elif self._nState == X_ROOT_TAIL: - self._xTail.tail += c + self._xTail.tail = (self._xTail.tail or "") + c self._chrPos += 1 elif self._nState == X_SPAN_TEXT: - self._xTail.text += c + self._xTail.text = (self._xTail.text or "") + c self._chrPos += 1 elif self._nState == X_SPAN_SING: - self._xSing.tail += c + self._xSing.tail = (self._xSing.tail or "") + c self._chrPos += 1 if nSpaces > 0: + # Handle trailing spaces self._processSpaces(nSpaces) return - def appendSpan(self, tText, tFmt): + def appendSpan(self, tText: str, tFmt: str): """Append a text span to the XML element. The span is always closed since we do not allow nested spans (like Libre Office). Therefore we return to the root element level when we're done processing the text of the span. """ - self._xTail = ET.SubElement(self._xRoot, TAG_SPAN, attrib={ - TAG_STNM: tFmt - }) + self._xTail = ET.SubElement(self._xRoot, TAG_SPAN, attrib={TAG_STNM: tFmt}) self._xTail.text = "" # Defaults to None self._xTail.tail = "" # Defaults to None self._nState = X_SPAN_TEXT self.appendText(tText) self._nState = X_ROOT_TAIL - return def checkError(self): @@ -1443,7 +1423,7 @@ class XMLParagraph: # Internal Functions ## - def _processSpaces(self, nSpaces): + def _processSpaces(self, nSpaces: int): """Add spaces to paragraph. The first space is always written as-is (unless it's the first character of the paragraph). The second space uses the dedicated tag for spaces, and from the @@ -1455,16 +1435,16 @@ class XMLParagraph: if nSpaces > 0: if self._chrPos > 0: if self._nState == X_ROOT_TEXT: - self._xRoot.text += " " + self._xRoot.text = (self._xRoot.text or "") + " " self._chrPos += 1 elif self._nState == X_ROOT_TAIL: - self._xTail.tail += " " + self._xTail.tail = (self._xTail.tail or "") + " " self._chrPos += 1 elif self._nState == X_SPAN_TEXT: - self._xTail.text += " " + self._xTail.text = (self._xTail.text or "") + " " self._chrPos += 1 elif self._nState == X_SPAN_SING: - self._xSing.tail += " " + self._xSing.tail = (self._xSing.tail or "") + " " self._chrPos += 1 else: nSpaces += 1 diff --git a/tests/reference/coreToOdt_SaveFull_styles.xml b/tests/reference/coreToOdt_SaveFull_styles.xml index 6c5f9bd2..5f2d1db6 100644 --- a/tests/reference/coreToOdt_SaveFull_styles.xml +++ b/tests/reference/coreToOdt_SaveFull_styles.xml @@ -1,5 +1,5 @@ - + @@ -22,7 +22,7 @@ - + @@ -30,19 +30,19 @@ - + - + - + - + diff --git a/tests/test_core/test_core_toodt.py b/tests/test_core/test_core_toodt.py index 015e97b8..5ab6f276 100644 --- a/tests/test_core/test_core_toodt.py +++ b/tests/test_core/test_core_toodt.py @@ -43,8 +43,7 @@ XML_NS = [ def xmlToText(xElem): - """Get the text content of an XML element. - """ + """Get the text content of an XML element.""" rTxt = ET.tostring(xElem, encoding="utf-8", xml_declaration=False).decode() for nSpace in XML_NS: rTxt = rTxt.replace(nSpace, "") @@ -53,8 +52,7 @@ def xmlToText(xElem): @pytest.mark.core def testCoreToOdt_Init(mockGUI): - """Test initialisation of the ODT document. - """ + """Test initialisation of the ODT document.""" theProject = NWProject(mockGUI) # Flat Doc @@ -109,8 +107,7 @@ def testCoreToOdt_Init(mockGUI): @pytest.mark.core def testCoreToOdt_TextFormatting(mockGUI): - """Test formatting of paragraphs. - """ + """Test formatting of paragraphs.""" theProject = NWProject(mockGUI) theDoc = ToOdt(theProject, isFlat=True) @@ -156,7 +153,7 @@ def testCoreToOdt_TextFormatting(mockGUI): # No Format theDoc.initDocument() theDoc._addTextPar("Standard", oStyle, "Hello World") - assert theDoc.getErrors() == [] + assert theDoc.errData == [] assert xmlToText(theDoc._xText) == ( "" "Hello World" @@ -166,7 +163,7 @@ def testCoreToOdt_TextFormatting(mockGUI): # Heading Level None theDoc.initDocument() theDoc._addTextPar("Standard", oStyle, "Hello World", isHead=True) - assert theDoc.getErrors() == [] + assert theDoc.errData == [] assert xmlToText(theDoc._xText) == ( "" "Hello World" @@ -176,7 +173,7 @@ def testCoreToOdt_TextFormatting(mockGUI): # Heading Level 1 theDoc.initDocument() theDoc._addTextPar("Standard", oStyle, "Hello World", isHead=True, oLevel="1") - assert theDoc.getErrors() == [] + assert theDoc.errData == [] assert xmlToText(theDoc._xText) == ( "" "Hello World" @@ -187,8 +184,8 @@ def testCoreToOdt_TextFormatting(mockGUI): theDoc.initDocument() theTxt = "A **few** _words_ from ~~our~~ sponsor" theFmt = " _B b_ I i _S s_ " - theDoc._addTextPar("Standard", oStyle, theTxt, theFmt=theFmt) - assert theDoc.getErrors() == [] + theDoc._addTextPar("Standard", oStyle, theTxt, tFmt=theFmt) + assert theDoc.errData == [] assert xmlToText(theDoc._xText) == ( "" "A few " @@ -201,8 +198,8 @@ def testCoreToOdt_TextFormatting(mockGUI): theDoc.initDocument() theTxt = "A **few** _wordsXXX" theFmt = " _b b_ I XXX" - theDoc._addTextPar("Standard", oStyle, theTxt, theFmt=theFmt) - assert theDoc.getErrors() == ["Unknown format tag encountered"] + theDoc._addTextPar("Standard", oStyle, theTxt, tFmt=theFmt) + assert theDoc.errData == ["Unknown format tag encountered"] assert xmlToText(theDoc._xText) == ( "" "" @@ -215,8 +212,8 @@ def testCoreToOdt_TextFormatting(mockGUI): theDoc.initDocument() theTxt = "Hello\n\tWorld" theFmt = " " - theDoc._addTextPar("Standard", oStyle, theTxt, theFmt=theFmt) - assert theDoc.getErrors() == [] + theDoc._addTextPar("Standard", oStyle, theTxt, tFmt=theFmt) + assert theDoc.errData == [] assert xmlToText(theDoc._xText) == ( "" "HelloWorld" @@ -230,8 +227,8 @@ def testCoreToOdt_TextFormatting(mockGUI): theDoc.initDocument() theTxt = "Test text \\**_bold_** and more." theFmt = " I i " - theDoc._addTextPar("Standard", oStyle, theTxt, theFmt=theFmt) - assert theDoc.getErrors() == [] + theDoc._addTextPar("Standard", oStyle, theTxt, tFmt=theFmt) + assert theDoc.errData == [] assert xmlToText(theDoc._xText) == ( "" "Test text **" @@ -244,8 +241,7 @@ def testCoreToOdt_TextFormatting(mockGUI): @pytest.mark.core def testCoreToOdt_Convert(mockGUI): - """Test the converter of the ToOdt class. - """ + """Test the converter of the ToOdt class.""" theProject = NWProject(mockGUI) theDoc = ToOdt(theProject, isFlat=True) @@ -266,7 +262,7 @@ def testCoreToOdt_Convert(mockGUI): theDoc.initDocument() theDoc.doConvert() theDoc.closeDocument() - assert theDoc.getErrors() == [] + assert theDoc.errData == [] assert xmlToText(theDoc._xText) == ( '' 'Title' @@ -279,7 +275,7 @@ def testCoreToOdt_Convert(mockGUI): theDoc.initDocument() theDoc.doConvert() theDoc.closeDocument() - assert theDoc.getErrors() == [] + assert theDoc.errData == [] assert xmlToText(theDoc._xText) == ( '' 'Chapter' @@ -292,7 +288,7 @@ def testCoreToOdt_Convert(mockGUI): theDoc.initDocument() theDoc.doConvert() theDoc.closeDocument() - assert theDoc.getErrors() == [] + assert theDoc.errData == [] assert xmlToText(theDoc._xText) == ( '' 'Scene' @@ -305,7 +301,7 @@ def testCoreToOdt_Convert(mockGUI): theDoc.initDocument() theDoc.doConvert() theDoc.closeDocument() - assert theDoc.getErrors() == [] + assert theDoc.errData == [] assert xmlToText(theDoc._xText) == ( '' 'Section' @@ -318,7 +314,7 @@ def testCoreToOdt_Convert(mockGUI): theDoc.initDocument() theDoc.doConvert() theDoc.closeDocument() - assert theDoc.getErrors() == [] + assert theDoc.errData == [] assert xmlToText(theDoc._xText) == ( '' 'Title' @@ -331,7 +327,7 @@ def testCoreToOdt_Convert(mockGUI): theDoc.initDocument() theDoc.doConvert() theDoc.closeDocument() - assert theDoc.getErrors() == [] + assert theDoc.errData == [] assert xmlToText(theDoc._xText) == ( '' 'Prologue' @@ -347,7 +343,7 @@ def testCoreToOdt_Convert(mockGUI): theDoc.initDocument() theDoc.doConvert() theDoc.closeDocument() - assert theDoc.getErrors() == [] + assert theDoc.errData == [] assert xmlToText(theDoc._xText) == ( '' 'Some ' @@ -365,7 +361,7 @@ def testCoreToOdt_Convert(mockGUI): theDoc.initDocument() theDoc.doConvert() theDoc.closeDocument() - assert theDoc.getErrors() == [] + assert theDoc.errData == [] assert xmlToText(theDoc._xText) == ( '' 'Some text.Next line' @@ -378,7 +374,7 @@ def testCoreToOdt_Convert(mockGUI): theDoc.initDocument() theDoc.doConvert() theDoc.closeDocument() - assert theDoc.getErrors() == [] + assert theDoc.errData == [] assert xmlToText(theDoc._xText) == ( '' 'Item 1Item 2' @@ -391,7 +387,7 @@ def testCoreToOdt_Convert(mockGUI): theDoc.initDocument() theDoc.doConvert() theDoc.closeDocument() - assert theDoc.getErrors() == [] + assert theDoc.errData == [] assert xmlToText(theDoc._xText) == ( '' 'Some ' @@ -410,7 +406,7 @@ def testCoreToOdt_Convert(mockGUI): theDoc.initDocument() theDoc.doConvert() theDoc.closeDocument() - assert theDoc.getErrors() == [] + assert theDoc.errData == [] assert xmlToText(theDoc._xText) == ( '' 'Scene' @@ -434,7 +430,7 @@ def testCoreToOdt_Convert(mockGUI): theDoc.initDocument() theDoc.doConvert() theDoc.closeDocument() - assert theDoc.getErrors() == [] + assert theDoc.errData == [] assert xmlToText(theDoc._xText) == ( '' 'Scene' @@ -455,7 +451,7 @@ def testCoreToOdt_Convert(mockGUI): theDoc.initDocument() theDoc.doConvert() theDoc.closeDocument() - assert theDoc.getErrors() == [] + assert theDoc.errData == [] assert xmlToText(theDoc._xText) == ( '' '* * *' @@ -473,7 +469,7 @@ def testCoreToOdt_Convert(mockGUI): theDoc.initDocument() theDoc.doConvert() theDoc.closeDocument() - assert theDoc.getErrors() == [] + assert theDoc.errData == [] assert xmlToText(theDoc._xText) == ( '' '' @@ -500,7 +496,7 @@ def testCoreToOdt_Convert(mockGUI): theDoc.initDocument() theDoc.doConvert() theDoc.closeDocument() - assert theDoc.getErrors() == [] + assert theDoc.errData == [] assert xmlToText(theDoc._xText) == ( '' 'Scene' @@ -537,7 +533,7 @@ def testCoreToOdt_Convert(mockGUI): theDoc.initDocument() theDoc.doConvert() theDoc.closeDocument() - assert theDoc.getErrors() == [] + assert theDoc.errData == [] assert xmlToText(theDoc._xText) == ( '' 'Scene' @@ -559,7 +555,7 @@ def testCoreToOdt_Convert(mockGUI): theDoc.initDocument() theDoc.doConvert() theDoc.closeDocument() - assert theDoc.getErrors() == [] + assert theDoc.errData == [] assert xmlToText(theDoc._xText) == ( '' 'Chapter One' @@ -629,8 +625,7 @@ def testCoreToOdt_ConvertDirect(mockGUI): @pytest.mark.core def testCoreToOdt_SaveFlat(mockGUI, fncPath, tstPaths): - """Test the document save functions. - """ + """Test the document save functions.""" theProject = NWProject(mockGUI) theProject.data.setAuthor("Jane Smith") theProject.data.setName("Test Project") @@ -639,8 +634,11 @@ def testCoreToOdt_SaveFlat(mockGUI, fncPath, tstPaths): theDoc = ToOdt(theProject, isFlat=True) theDoc._isNovel = True - assert theDoc.setLanguage(None) is False - assert theDoc.setLanguage("nb_NO") is True + theDoc._dLanguage = "" + theDoc.setLanguage(None) + assert theDoc._dLanguage == "" + theDoc.setLanguage("nb_NO") + assert theDoc._dLanguage == "nb" theDoc.setColourHeaders(True) theDoc._text = ( @@ -669,8 +667,7 @@ def testCoreToOdt_SaveFlat(mockGUI, fncPath, tstPaths): @pytest.mark.core def testCoreToOdt_SaveFull(mockGUI, fncPath, tstPaths): - """Test the document save functions. - """ + """Test the document save functions.""" theProject = NWProject(mockGUI) theProject.data.setAuthor("Jane Smith") theProject.data.setName("Test Project") @@ -747,8 +744,7 @@ def testCoreToOdt_SaveFull(mockGUI, fncPath, tstPaths): @pytest.mark.core def testCoreToOdt_Format(mockGUI): - """Test the formatters for the ToOdt class. - """ + """Test the formatters for the ToOdt class.""" theProject = NWProject(mockGUI) theDoc = ToOdt(theProject, isFlat=True) @@ -761,7 +757,7 @@ def testCoreToOdt_Format(mockGUI): "_B b_ " ) - assert theDoc._formatKeywords("") == "" + assert theDoc._formatKeywords("") == ("", "") assert theDoc._formatKeywords("tag: Jane") == ( "**Tag:** Jane", "_B b_ " @@ -776,8 +772,7 @@ def testCoreToOdt_Format(mockGUI): @pytest.mark.core def testCoreToOdt_ODTParagraphStyle(): - """Test the ODTParagraphStyle class. - """ + """Test the ODTParagraphStyle class.""" parStyle = ODTParagraphStyle() # Set Attributes @@ -992,8 +987,7 @@ def testCoreToOdt_ODTParagraphStyle(): @pytest.mark.core def testCoreToOdt_ODTTextStyle(): - """Test the ODTTextStyle class. - """ + """Test the ODTTextStyle class.""" txtStyle = ODTTextStyle() # Font Weight @@ -1065,8 +1059,7 @@ def testCoreToOdt_ODTTextStyle(): @pytest.mark.core def testCoreToOdt_XMLParagraph(): - """Test XML encoding of paragraph. - """ + """Test XML encoding of paragraph.""" # Stage 1 : Text # ============== @@ -1257,8 +1250,7 @@ def testCoreToOdt_XMLParagraph(): @pytest.mark.core def testCoreToOdt_MkTag(): - """Test the tag maker function. - """ + """Test the tag maker function.""" assert _mkTag("office", "text") == "{urn:oasis:names:tc:opendocument:xmlns:office:1.0}text" assert _mkTag("style", "text") == "{urn:oasis:names:tc:opendocument:xmlns:style:1.0}text" assert _mkTag("blabla", "text") == "text"