Use Ruff for linting and fix a ton of issues
This commit is contained in:
@@ -23,11 +23,10 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
- name: Install Dependencies
|
||||
run: pip install -r requirements.txt -r requirements-dev.txt
|
||||
- name: Run Flake8
|
||||
- name: Run Ruff
|
||||
run: |
|
||||
flake8 --version
|
||||
flake8 novelwriter --count --show-source --statistics
|
||||
flake8 tests --count --show-source --statistics --extend-ignore ANN
|
||||
ruff --version
|
||||
ruff check
|
||||
- name: Run Pyright
|
||||
run: |
|
||||
pyright --version
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ import time
|
||||
# -- Project Information -----------------------------------------------------
|
||||
|
||||
project = "novelWriter"
|
||||
copyright = f"{datetime.date.today().year}"
|
||||
copyright = f"{datetime.date.today().year}" # noqa: A001
|
||||
|
||||
tmp_authors = ["Veronica Berglyd Olsen"]
|
||||
if additional := os.environ.get("SPHINX_I18N_AUTHORS"):
|
||||
|
||||
@@ -159,7 +159,7 @@ def main(sysArgs: list | None = None) -> GuiMain | None:
|
||||
print(helpMsg)
|
||||
sys.exit(0)
|
||||
elif inOpt in ("-v", "--version"):
|
||||
print("novelWriter Version %s [%s]" % (__version__, __date__))
|
||||
print(f"novelWriter Version {__version__} [{__date__}]")
|
||||
sys.exit(0)
|
||||
elif inOpt in ("-i", "--info"):
|
||||
logLevel = logging.INFO
|
||||
@@ -207,17 +207,17 @@ def main(sysArgs: list | None = None) -> GuiMain | None:
|
||||
errorCode = 0
|
||||
if sys.hexversion < 0x030a00f0:
|
||||
errorData.append(
|
||||
"At least Python 3.10 is required, found %s" % CONFIG.verPyString
|
||||
f"At least Python 3.10 is required, found {CONFIG.verPyString}"
|
||||
)
|
||||
errorCode |= 0x04
|
||||
if CONFIG.verQtValue < 0x060400:
|
||||
errorData.append(
|
||||
"At least Qt6 version 6.4 is required, found %s" % CONFIG.verQtString
|
||||
f"At least Qt6 version 6.4 is required, found {CONFIG.verQtString}"
|
||||
)
|
||||
errorCode |= 0x08
|
||||
if CONFIG.verPyQtValue < 0x060400:
|
||||
errorData.append(
|
||||
"At least PyQt6 version 6.4 is required, found %s" % CONFIG.verPyQtString
|
||||
f"At least PyQt6 version 6.4 is required, found {CONFIG.verPyQtString}"
|
||||
)
|
||||
errorCode |= 0x10
|
||||
|
||||
@@ -228,9 +228,9 @@ def main(sysArgs: list | None = None) -> GuiMain | None:
|
||||
errDlg.showMessage((
|
||||
"<h3>A critical error was encountered</h3>"
|
||||
"<p>novelWriter cannot start due to the following issues:<p>"
|
||||
"<p> - %s</p>"
|
||||
"<p> - {0}</p>"
|
||||
"<p>Shutting down ...</p>"
|
||||
) % (
|
||||
).format(
|
||||
"<br> - ".join(errorData)
|
||||
))
|
||||
for errLine in errorData:
|
||||
|
||||
@@ -490,7 +490,7 @@ def jsonEncode(data: dict | list | tuple, n: int = 0, nmax: int = 0) -> str:
|
||||
"""Encode a dictionary, list or tuple as a json object or array, and
|
||||
indent from level n up to a max level nmax if nmax is larger than 0.
|
||||
"""
|
||||
if not isinstance(data, (dict, list, tuple)):
|
||||
if not isinstance(data, dict | list | tuple):
|
||||
return "[]"
|
||||
|
||||
buffer = []
|
||||
|
||||
@@ -355,7 +355,7 @@ class Config:
|
||||
"""Set the last used path. Only the folder is saved, so if the
|
||||
path is not a folder, the parent of the path is used instead.
|
||||
"""
|
||||
if isinstance(path, (str, Path)):
|
||||
if isinstance(path, str | Path):
|
||||
path = checkPath(path, self._homePath)
|
||||
if not path.is_dir():
|
||||
path = path.parent
|
||||
@@ -504,10 +504,10 @@ class Config:
|
||||
and dataPath is mainly intended for the test suite.
|
||||
"""
|
||||
logger.debug("Initialising Config ...")
|
||||
if isinstance(confPath, (str, Path)):
|
||||
if isinstance(confPath, str | Path):
|
||||
logger.info("Setting alternative config path: %s", confPath)
|
||||
self._confPath = Path(confPath)
|
||||
if isinstance(dataPath, (str, Path)):
|
||||
if isinstance(dataPath, str | Path):
|
||||
logger.info("Setting alternative data path: %s", dataPath)
|
||||
self._dataPath = Path(dataPath)
|
||||
|
||||
@@ -555,7 +555,7 @@ class Config:
|
||||
for lngPath, lngBase in langList:
|
||||
for lngCode in self._qLocale.uiLanguages():
|
||||
qTrans = QTranslator()
|
||||
lngFile = "%s_%s" % (lngBase, lngCode.replace("-", "_"))
|
||||
lngFile = "{0}_{1}".format(lngBase, lngCode.replace("-", "_"))
|
||||
if lngFile not in self._qtTrans:
|
||||
if qTrans.load(lngFile, lngPath):
|
||||
logger.debug("Loaded: %s.qm", lngFile)
|
||||
|
||||
@@ -643,7 +643,7 @@ class nwUnicode:
|
||||
H_LTRIS = "◂"
|
||||
|
||||
|
||||
class nwHtmlUnicode():
|
||||
class nwHtmlUnicode:
|
||||
|
||||
U_TO_H = {
|
||||
# Quotes
|
||||
|
||||
@@ -294,12 +294,12 @@ class BuildSettings:
|
||||
def getInt(self, key: str) -> int:
|
||||
"""Type safe value access for integers."""
|
||||
value = self._settings.get(key, SETTINGS_TEMPLATE.get(key, (None, None))[1])
|
||||
return int(value) if isinstance(value, (int, float)) else 0
|
||||
return int(value) if isinstance(value, int | float) else 0
|
||||
|
||||
def getFloat(self, key: str) -> float:
|
||||
"""Type safe value access for floats."""
|
||||
value = self._settings.get(key, SETTINGS_TEMPLATE.get(key, (None, None))[1])
|
||||
return float(value) if isinstance(value, (int, float)) else 0.0
|
||||
return float(value) if isinstance(value, int | float) else 0.0
|
||||
|
||||
##
|
||||
# Setters
|
||||
|
||||
@@ -379,7 +379,7 @@ class ProjectBuilder:
|
||||
"""Build or copy a project from a data dictionary."""
|
||||
if isinstance(data, dict):
|
||||
path = data.get("path", None) or None
|
||||
if isinstance(path, (str, Path)):
|
||||
if isinstance(path, str | Path):
|
||||
self._path = Path(path).resolve()
|
||||
if data.get("sample", False):
|
||||
return self._extractSampleProject(self._path)
|
||||
@@ -509,7 +509,7 @@ class ProjectBuilder:
|
||||
|
||||
# Also add the archive and trash folders
|
||||
project.newRoot(nwItemClass.ARCHIVE)
|
||||
project.tree.trash # Triggers the creation of Trash
|
||||
_ = project.tree.trash # Triggers the creation of Trash
|
||||
|
||||
project.saveProject()
|
||||
project.closeProject()
|
||||
|
||||
@@ -316,13 +316,13 @@ class NWBuildDocument:
|
||||
bldObj.setStyles(self._build.getBool("html.addStyles"))
|
||||
bldObj.setReplaceUnicode(self._build.getBool("format.stripUnicode"))
|
||||
|
||||
if isinstance(bldObj, (ToOdt, ToDocX)):
|
||||
if isinstance(bldObj, ToOdt | ToDocX):
|
||||
bldObj.setHeaderFormat(
|
||||
self._build.getStr("doc.pageHeader"),
|
||||
self._build.getInt("doc.pageCountOffset"),
|
||||
)
|
||||
|
||||
if isinstance(bldObj, (ToOdt, ToDocX, ToQTextDocument)):
|
||||
if isinstance(bldObj, ToOdt | ToDocX | ToQTextDocument):
|
||||
scale = nwLabels.UNIT_SCALE.get(self._build.getStr("format.pageUnit"), 1.0)
|
||||
pW, pH = nwLabels.PAPER_SIZE.get(self._build.getStr("format.pageSize"), (-1.0, -1.0))
|
||||
bldObj.setPageLayout(
|
||||
|
||||
@@ -333,8 +333,9 @@ class ProjectModel(QAbstractItemModel):
|
||||
return self.createIndex(parent.row(), 0, parent)
|
||||
return QModelIndex()
|
||||
|
||||
def index(self, row: int, column: int, parent: QModelIndex = QModelIndex()) -> QModelIndex:
|
||||
def index(self, row: int, column: int, parent: QModelIndex | None = None) -> QModelIndex:
|
||||
"""Get the index of a child item of a parent."""
|
||||
parent = parent or QModelIndex()
|
||||
if self.hasIndex(row, column, parent):
|
||||
node: ProjectNode = parent.internalPointer() if parent.isValid() else self._root
|
||||
if child := node.child(row):
|
||||
|
||||
@@ -691,7 +691,7 @@ class _ReplacePage(NFixedPage):
|
||||
self.listBox.itemSelectionChanged.connect(self._onSelectionChanged)
|
||||
|
||||
for aKey, aVal in SHARED.project.data.autoReplace.items():
|
||||
newItem = QTreeWidgetItem(["<%s>" % aKey, aVal])
|
||||
newItem = QTreeWidgetItem([f"<{aKey}>", aVal])
|
||||
self.listBox.addTopLevelItem(newItem)
|
||||
|
||||
self.listBox.sortByColumn(self.C_KEY, Qt.SortOrder.AscendingOrder)
|
||||
|
||||
@@ -78,7 +78,7 @@ class GuiQuoteSelect(NDialog):
|
||||
|
||||
minSize = 100
|
||||
for sKey, sLabel in nwQuotes.SYMBOLS.items():
|
||||
text = "[ %s ] %s" % (sKey, trConst(sLabel))
|
||||
text = f"[ {sKey} ] {trConst(sLabel)}"
|
||||
minSize = max(minSize, metrics.boundingRect(text).width())
|
||||
qtItem = QListWidgetItem(text)
|
||||
qtItem.setData(self.D_KEY, sKey)
|
||||
|
||||
@@ -144,7 +144,7 @@ class NWErrorMessage(QDialog):
|
||||
|
||||
try:
|
||||
txtTrace = "\n".join(format_tb(exTrace))
|
||||
self.msgBody.setPlainText((
|
||||
self.msgBody.setPlainText(
|
||||
"Environment:\n"
|
||||
f"novelWriter Version: {__version__}\n"
|
||||
f"Host OS: {sys.platform} ({kernelVersion})\n"
|
||||
@@ -153,7 +153,7 @@ class NWErrorMessage(QDialog):
|
||||
f"enchant: {enchantVersion}\n\n"
|
||||
f"{exType.__name__}:\n{str(exValue)}\n\n"
|
||||
f"Traceback:\n{txtTrace}\n"
|
||||
))
|
||||
)
|
||||
except Exception:
|
||||
self.msgBody.setPlainText("Failed to generate error report ...")
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ class WheelEventFilter(QObject):
|
||||
self._locked = False
|
||||
return
|
||||
|
||||
def eventFilter(self, object: QObject, event: QEvent) -> bool:
|
||||
def eventFilter(self, obj: QObject, event: QEvent) -> bool:
|
||||
"""Filter events of type QWheelEvent and forward them to the
|
||||
parent widget's wheelEvent handler.
|
||||
"""
|
||||
|
||||
@@ -155,15 +155,15 @@ class NDoubleSpinBox(QDoubleSpinBox):
|
||||
self,
|
||||
parent: QWidget | None = None,
|
||||
*,
|
||||
min: float = 0.0,
|
||||
max: float = 15.0,
|
||||
minVal: float = 0.0,
|
||||
maxVal: float = 15.0,
|
||||
step: float = 0.1,
|
||||
prec: int = 2,
|
||||
) -> None:
|
||||
super().__init__(parent=parent)
|
||||
self.setFocusPolicy(Qt.FocusPolicy.StrongFocus)
|
||||
self.setMinimum(min)
|
||||
self.setMaximum(max)
|
||||
self.setMinimum(minVal)
|
||||
self.setMaximum(maxVal)
|
||||
self.setSingleStep(step)
|
||||
self.setDecimals(prec)
|
||||
return
|
||||
|
||||
@@ -212,9 +212,9 @@ class ToDocX(Tokenizer):
|
||||
self._pageMargins = QMargins(_mmToSz(left), _mmToSz(top), _mmToSz(right), _mmToSz(bottom))
|
||||
return
|
||||
|
||||
def setHeaderFormat(self, format: str, offset: int) -> None:
|
||||
def setHeaderFormat(self, value: str, offset: int) -> None:
|
||||
"""Set the document header format."""
|
||||
self._headerFormat = format.strip()
|
||||
self._headerFormat = value.strip()
|
||||
self._pageOffset = offset
|
||||
return
|
||||
|
||||
|
||||
@@ -203,9 +203,9 @@ class ToOdt(Tokenizer):
|
||||
self._mDocRight = f"{right/10.0:.3f}cm"
|
||||
return
|
||||
|
||||
def setHeaderFormat(self, format: str, offset: int) -> None:
|
||||
def setHeaderFormat(self, value: str, offset: int) -> None:
|
||||
"""Set the document header format."""
|
||||
self._headerFormat = format.strip()
|
||||
self._headerFormat = value.strip()
|
||||
self._pageOffset = offset
|
||||
return
|
||||
|
||||
@@ -1509,7 +1509,7 @@ class XMLParagraph:
|
||||
errMsg = ""
|
||||
nMissed = len(self._rawTxt) - self._chrPos
|
||||
if nMissed != 0:
|
||||
errMsg = "%d char(s) were not written: '%s'" % (nMissed, self._rawTxt)
|
||||
errMsg = f"{nMissed} char(s) were not written: '{self._rawTxt}'"
|
||||
return nMissed, errMsg
|
||||
|
||||
##
|
||||
|
||||
@@ -978,7 +978,7 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
super().dropEvent(event)
|
||||
return
|
||||
|
||||
def focusNextPrevChild(self, next: bool) -> bool:
|
||||
def focusNextPrevChild(self, _next: bool) -> bool:
|
||||
"""Capture the focus request from the tab key on the text
|
||||
editor. If the editor has focus, we do not change focus and
|
||||
allow the editor to insert a tab. If the search bar has focus,
|
||||
@@ -1037,7 +1037,7 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
logger.error("Invalid keyword '%s'", keyword)
|
||||
return False
|
||||
logger.debug("Inserting keyword '%s'", keyword)
|
||||
state = self.insertNewBlock("%s: " % keyword)
|
||||
state = self.insertNewBlock(f"{keyword}: ")
|
||||
return state
|
||||
|
||||
@pyqtSlot()
|
||||
@@ -1528,10 +1528,10 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
if fLen == min(numA, numB):
|
||||
cursor.beginEditBlock()
|
||||
cursor.setPosition(posS)
|
||||
for i in range(fLen):
|
||||
for _ in range(fLen):
|
||||
cursor.deletePreviousChar()
|
||||
cursor.setPosition(posE)
|
||||
for i in range(fLen):
|
||||
for _ in range(fLen):
|
||||
cursor.deletePreviousChar()
|
||||
cursor.endEditBlock()
|
||||
|
||||
@@ -1943,7 +1943,9 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
exist = False
|
||||
cPos = cursor.selectionStart() - block.position()
|
||||
tExist = SHARED.project.index.checkThese(tBits, self._docHandle)
|
||||
for sTag, sPos, sExist in zip(reversed(tBits), reversed(tPos), reversed(tExist)):
|
||||
for sTag, sPos, sExist in zip(
|
||||
reversed(tBits), reversed(tPos), reversed(tExist), strict=False
|
||||
):
|
||||
if cPos >= sPos:
|
||||
# The cursor is between the start of two tags
|
||||
if cPos <= sPos + len(sTag):
|
||||
|
||||
@@ -610,12 +610,9 @@ class GuiDocViewHistory:
|
||||
for loop, it is skipped entirely if log level isn't DEBUG.
|
||||
"""
|
||||
if CONFIG.isDebug: # pragma: no cover
|
||||
for i, (h, p) in enumerate(zip(self._navHistory, self._posHistory)):
|
||||
logger.debug(
|
||||
"History %02d: %s %13s [x:%d]" % (
|
||||
i + 1, ">" if i == self._currPos else " ", h, p
|
||||
)
|
||||
)
|
||||
for i, (h, p) in enumerate(zip(self._navHistory, self._posHistory, strict=False)):
|
||||
a = ">" if i == self._currPos else " "
|
||||
logger.debug(f"History {i + 1:02d}: {a} {h:13s} [x:{p}]")
|
||||
return
|
||||
|
||||
|
||||
|
||||
@@ -936,7 +936,7 @@ class GuiMainMenu(QMenuBar):
|
||||
# Search > Find in Project
|
||||
self.aFindProj = qtAddAction(self.srcMenu, self.tr("Find in Project"))
|
||||
self.aFindProj.setShortcut("Ctrl+Shift+F")
|
||||
self.aFindProj.triggered.connect(lambda: self.requestViewChange.emit(nwView.SEARCH))
|
||||
self.aFindProj.triggered.connect(qtLambda(self.requestViewChange.emit, nwView.SEARCH))
|
||||
|
||||
return
|
||||
|
||||
@@ -956,10 +956,10 @@ class GuiMainMenu(QMenuBar):
|
||||
self.mSelectLanguage = qtAddMenu(self.toolsMenu, self.tr("Spell Check Language"))
|
||||
languages = SHARED.spelling.listDictionaries()
|
||||
languages.insert(0, ("None", self.tr("Default")))
|
||||
for n, (tag, language) in enumerate(languages):
|
||||
for tag, language in languages:
|
||||
aSpell = QAction(self.mSelectLanguage)
|
||||
aSpell.setText(language)
|
||||
aSpell.triggered.connect(lambda n, tag=tag: self._changeSpelling(tag))
|
||||
aSpell.triggered.connect(qtLambda(self._changeSpelling, tag))
|
||||
self.mSelectLanguage.addAction(aSpell)
|
||||
|
||||
# Tools > Re-Run Spell Check
|
||||
|
||||
@@ -259,17 +259,17 @@ class GuiProjectToolBar(QWidget):
|
||||
self.mQuick = QMenu(self)
|
||||
|
||||
self.tbQuick = NIconToolButton(self, iSz)
|
||||
self.tbQuick.setToolTip("%s [Ctrl+L]" % self.tr("Quick Links"))
|
||||
self.tbQuick.setToolTip("{0} [Ctrl+L]".format(self.tr("Quick Links")))
|
||||
self.tbQuick.setShortcut("Ctrl+L")
|
||||
self.tbQuick.setMenu(self.mQuick)
|
||||
|
||||
# Move Buttons
|
||||
self.tbMoveU = NIconToolButton(self, iSz)
|
||||
self.tbMoveU.setToolTip("%s [Ctrl+Up]" % self.tr("Move Up"))
|
||||
self.tbMoveU.setToolTip("{0} [Ctrl+Up]".format(self.tr("Move Up")))
|
||||
self.tbMoveU.clicked.connect(self.projTree.moveItemUp)
|
||||
|
||||
self.tbMoveD = NIconToolButton(self, iSz)
|
||||
self.tbMoveD.setToolTip("%s [Ctrl+Down]" % self.tr("Move Down"))
|
||||
self.tbMoveD.setToolTip("{0} [Ctrl+Down]".format(self.tr("Move Down")))
|
||||
self.tbMoveD.clicked.connect(self.projTree.moveItemDown)
|
||||
|
||||
# Add Item Menu
|
||||
@@ -309,7 +309,7 @@ class GuiProjectToolBar(QWidget):
|
||||
self._buildRootMenu()
|
||||
|
||||
self.tbAdd = NIconToolButton(self, iSz)
|
||||
self.tbAdd.setToolTip("%s [Ctrl+N]" % self.tr("Add Item"))
|
||||
self.tbAdd.setToolTip("{0} [Ctrl+N]".format(self.tr("Add Item")))
|
||||
self.tbAdd.setShortcut("Ctrl+N")
|
||||
self.tbAdd.setMenu(self.mAdd)
|
||||
|
||||
|
||||
@@ -155,4 +155,4 @@ class _PopRightMenu(QMenu):
|
||||
if isinstance(parent := self.parent(), QWidget):
|
||||
offset = QPoint(parent.width(), parent.height() - self.height())
|
||||
self.move(parent.mapToGlobal(offset))
|
||||
return super(_PopRightMenu, self).event(event)
|
||||
return super().event(event)
|
||||
|
||||
@@ -370,7 +370,7 @@ class GuiMain(QMainWindow):
|
||||
return True
|
||||
|
||||
if not isYes:
|
||||
msgYes = SHARED.question("%s<br>%s" % (
|
||||
msgYes = SHARED.question("{0}<br>{1}".format(
|
||||
self.tr("Close the current project?"),
|
||||
self.tr("Changes are saved automatically.")
|
||||
))
|
||||
@@ -844,7 +844,7 @@ class GuiMain(QMainWindow):
|
||||
|
||||
def closeMain(self) -> bool:
|
||||
"""Save everything, and close novelWriter."""
|
||||
if SHARED.hasProject and CONFIG.askBeforeExit and not SHARED.question("%s<br>%s" % (
|
||||
if SHARED.hasProject and CONFIG.askBeforeExit and not SHARED.question("{0}<br>{1}".format(
|
||||
self.tr("Do you want to exit novelWriter?"),
|
||||
self.tr("Changes are saved automatically.")
|
||||
)):
|
||||
|
||||
@@ -101,28 +101,28 @@ class SharedData(QObject):
|
||||
def mainGui(self) -> GuiMain:
|
||||
"""Return the Main GUI instance."""
|
||||
if self._gui is None:
|
||||
raise Exception("SharedData class not fully initialised")
|
||||
raise RuntimeError("SharedData class not fully initialised")
|
||||
return self._gui
|
||||
|
||||
@property
|
||||
def theme(self) -> GuiTheme:
|
||||
"""Return the GUI Theme instance."""
|
||||
if self._theme is None:
|
||||
raise Exception("SharedData class not fully initialised")
|
||||
raise RuntimeError("SharedData class not fully initialised")
|
||||
return self._theme
|
||||
|
||||
@property
|
||||
def project(self) -> NWProject:
|
||||
"""Return the active NWProject instance."""
|
||||
if self._project is None:
|
||||
raise Exception("SharedData class not fully initialised")
|
||||
raise RuntimeError("SharedData class not fully initialised")
|
||||
return self._project
|
||||
|
||||
@property
|
||||
def spelling(self) -> NWSpellEnchant:
|
||||
"""Return the active NWProject instance."""
|
||||
if self._spelling is None:
|
||||
raise Exception("SharedData class not fully initialised")
|
||||
raise RuntimeError("SharedData class not fully initialised")
|
||||
return self._spelling
|
||||
|
||||
@property
|
||||
|
||||
@@ -333,7 +333,7 @@ class GuiManuscript(NToolDialog):
|
||||
def _deleteSelectedBuild(self) -> None:
|
||||
"""Delete the currently selected build settings entry."""
|
||||
if build := self._getSelectedBuild():
|
||||
if SHARED.question(self.tr("Delete build '{0}'?".format(build.name))):
|
||||
if SHARED.question(self.tr("Delete build '{0}'?").format(build.name)):
|
||||
if dialog := self._findSettingsDialog(build.buildID):
|
||||
dialog.close()
|
||||
self._builds.removeBuild(build.buildID)
|
||||
@@ -977,23 +977,23 @@ class _StatsWidget(QWidget):
|
||||
def updateStats(self, data: dict[str, int]) -> None:
|
||||
"""Update the stats values from a Tokenizer stats dict."""
|
||||
# Minimal
|
||||
self.minWordCount.setText("{0:n}".format(data.get(nwStats.WORDS, 0)))
|
||||
self.minCharCount.setText("{0:n}".format(data.get(nwStats.CHARS, 0)))
|
||||
self.minWordCount.setText(f"{data.get(nwStats.WORDS, 0):n}")
|
||||
self.minCharCount.setText(f"{data.get(nwStats.CHARS, 0):n}")
|
||||
|
||||
# Maximal
|
||||
self.maxTotalWords.setText("{0:n}".format(data.get(nwStats.WORDS, 0)))
|
||||
self.maxHeadWords.setText("{0:n}".format(data.get(nwStats.WORDS_TITLE, 0)))
|
||||
self.maxTextWords.setText("{0:n}".format(data.get(nwStats.WORDS_TEXT, 0)))
|
||||
self.maxTitleCount.setText("{0:n}".format(data.get(nwStats.TITLES, 0)))
|
||||
self.maxParCount.setText("{0:n}".format(data.get(nwStats.PARAGRAPHS, 0)))
|
||||
self.maxTotalWords.setText(f"{data.get(nwStats.WORDS, 0):n}")
|
||||
self.maxHeadWords.setText(f"{data.get(nwStats.WORDS_TITLE, 0):n}")
|
||||
self.maxTextWords.setText(f"{data.get(nwStats.WORDS_TEXT, 0):n}")
|
||||
self.maxTitleCount.setText(f"{data.get(nwStats.TITLES, 0):n}")
|
||||
self.maxParCount.setText(f"{data.get(nwStats.PARAGRAPHS, 0):n}")
|
||||
|
||||
self.maxTotalChars.setText("{0:n}".format(data.get(nwStats.CHARS, 0)))
|
||||
self.maxHeaderChars.setText("{0:n}".format(data.get(nwStats.CHARS_TITLE, 0)))
|
||||
self.maxTextChars.setText("{0:n}".format(data.get(nwStats.CHARS_TEXT, 0)))
|
||||
self.maxTotalChars.setText(f"{data.get(nwStats.CHARS, 0):n}")
|
||||
self.maxHeaderChars.setText(f"{data.get(nwStats.CHARS_TITLE, 0):n}")
|
||||
self.maxTextChars.setText(f"{data.get(nwStats.CHARS_TEXT, 0):n}")
|
||||
|
||||
self.maxTotalWordChars.setText("{0:n}".format(data.get(nwStats.WCHARS_ALL, 0)))
|
||||
self.maxHeadWordChars.setText("{0:n}".format(data.get(nwStats.WCHARS_TITLE, 0)))
|
||||
self.maxTextWordChars.setText("{0:n}".format(data.get(nwStats.WCHARS_TEXT, 0)))
|
||||
self.maxTotalWordChars.setText(f"{data.get(nwStats.WCHARS_ALL, 0):n}")
|
||||
self.maxHeadWordChars.setText(f"{data.get(nwStats.WCHARS_TITLE, 0):n}")
|
||||
self.maxTextWordChars.setText(f"{data.get(nwStats.WCHARS_TEXT, 0):n}")
|
||||
|
||||
return
|
||||
|
||||
|
||||
@@ -228,8 +228,8 @@ class GuiBuildSettings(NToolDialog):
|
||||
"""
|
||||
if self._build.changed:
|
||||
response = SHARED.question(self.tr(
|
||||
"Do you want to save your changes to '{0}'?".format(self._build.name)
|
||||
))
|
||||
"Do you want to save your changes to '{0}'?"
|
||||
).format(self._build.name))
|
||||
if response:
|
||||
self._emitBuildData()
|
||||
self._build.resetChangedState()
|
||||
@@ -1168,11 +1168,11 @@ class _FormattingTab(NScrollableForm):
|
||||
for key, name in nwLabels.PAPER_NAME.items():
|
||||
self.pageSize.addItem(trConst(name), key)
|
||||
|
||||
self.pageWidth = NDoubleSpinBox(self, max=500.0)
|
||||
self.pageWidth = NDoubleSpinBox(self, maxVal=500.0)
|
||||
self.pageWidth.setFixedWidth(dbW)
|
||||
self.pageWidth.valueChanged.connect(self._pageSizeValueChanged)
|
||||
|
||||
self.pageHeight = NDoubleSpinBox(self, max=500.0)
|
||||
self.pageHeight = NDoubleSpinBox(self, maxVal=500.0)
|
||||
self.pageHeight.setFixedWidth(dbW)
|
||||
self.pageHeight.valueChanged.connect(self._pageSizeValueChanged)
|
||||
|
||||
|
||||
@@ -447,7 +447,7 @@ class GuiWritingStats(NToolDialog):
|
||||
rType = record.get("type")
|
||||
if rType == "initial":
|
||||
self.wordOffset = checkInt(record.get("offset"), 0)
|
||||
logger.debug("Initial word count when log was started is %d" % self.wordOffset)
|
||||
logger.debug("Initial word count when log was started is %d", self.wordOffset)
|
||||
elif rType == "record":
|
||||
try:
|
||||
dStart = datetime.fromisoformat(str(record.get("start")))
|
||||
@@ -570,7 +570,7 @@ class GuiWritingStats(NToolDialog):
|
||||
idleEntry = formatTime(sIdle)
|
||||
else:
|
||||
sRatio = sIdle/sDiff if sDiff > 0.0 else 0.0
|
||||
idleEntry = "%d %%" % round(100.0 * sRatio)
|
||||
idleEntry = f"{round(100.0 * sRatio)} %"
|
||||
|
||||
newItem = QTreeWidgetItem()
|
||||
newItem.setText(self.C_TIME, sStart)
|
||||
|
||||
+3
-3
@@ -102,11 +102,11 @@ def cleanBuildDirs(args: argparse.Namespace) -> None:
|
||||
if folder.is_dir():
|
||||
try:
|
||||
shutil.rmtree(folder)
|
||||
print("Deleted: %s" % folder)
|
||||
print(f"Deleted: {folder}")
|
||||
except OSError:
|
||||
print("Failed: %s" % folder)
|
||||
print(f"Failed: {folder}")
|
||||
else:
|
||||
print("Missing: %s" % folder)
|
||||
print(f"Missing: {folder}")
|
||||
|
||||
print("")
|
||||
|
||||
|
||||
+32
-5
@@ -55,17 +55,44 @@ force_grid_wrap = 0
|
||||
lines_between_types = 1
|
||||
forced_separate = ["tests.*"]
|
||||
|
||||
[tool.flake8]
|
||||
max-line-length = 99
|
||||
ignore = ["E133", "E221", "E226", "E228", "E241", "W503", "ANN101", "ANN102", "ANN401"]
|
||||
per-file-ignores = ["tests/*:ANN"]
|
||||
exclude = ["docs/*"]
|
||||
[tool.ruff]
|
||||
line-length = 99
|
||||
|
||||
[tool.ruff.lint]
|
||||
select = [
|
||||
"A", # flake8-builtins (A)
|
||||
"B", # flake8-bugbear (B)
|
||||
"E", # pycodestyle (E)
|
||||
"F", # Pyflakes (F)
|
||||
"W", # pycodestyle (W)
|
||||
"UP",
|
||||
]
|
||||
ignore = [
|
||||
"E221", # multiple-spaces-before-operator
|
||||
"E226", # missing-whitespace-around-arithmetic-operator
|
||||
"E228", # missing-whitespace-around-modulo-operator
|
||||
"E241", # multiple-spaces-after-comma
|
||||
"ANN401",
|
||||
"UP015", # redundant-open-modes
|
||||
"UP030", # format-literals
|
||||
]
|
||||
|
||||
[tool.ruff.lint.per-file-ignores]
|
||||
"tests/*" = []
|
||||
|
||||
[tool.ruff.format]
|
||||
quote-style = "double"
|
||||
|
||||
[tool.pyright]
|
||||
include = ["novelwriter"]
|
||||
exclude = ["**/__pycache__"]
|
||||
|
||||
reportIncompatibleMethodOverride = false
|
||||
reportGeneralTypeIssues = "information"
|
||||
reportOptionalMemberAccess = "information"
|
||||
reportOptionalOperand = "information"
|
||||
reportOptionalSubscript = "information"
|
||||
reportUnboundVariable = "error"
|
||||
|
||||
pythonVersion = "3.10"
|
||||
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
flake8
|
||||
flake8-annotations
|
||||
flake8-pep585
|
||||
flake8-pyproject
|
||||
ruff
|
||||
isort
|
||||
pyright
|
||||
|
||||
+1
-2
@@ -195,8 +195,7 @@ def mockRnd(monkeypatch):
|
||||
self.reset()
|
||||
|
||||
def _rnd(self, n):
|
||||
for x in range(n):
|
||||
yield x
|
||||
yield from range(n)
|
||||
|
||||
def reset(self):
|
||||
gen = self._rnd(1000)
|
||||
|
||||
@@ -41,14 +41,14 @@ def testBaseSharedData_Init():
|
||||
shared = SharedData()
|
||||
|
||||
# When not initialised, it should raise exceptions
|
||||
with pytest.raises(Exception):
|
||||
shared.mainGui
|
||||
with pytest.raises(Exception):
|
||||
shared.theme
|
||||
with pytest.raises(Exception):
|
||||
shared.project
|
||||
with pytest.raises(Exception):
|
||||
shared.spelling
|
||||
with pytest.raises(RuntimeError):
|
||||
_ = shared.mainGui
|
||||
with pytest.raises(RuntimeError):
|
||||
_ = shared.theme
|
||||
with pytest.raises(RuntimeError):
|
||||
_ = shared.project
|
||||
with pytest.raises(RuntimeError):
|
||||
_ = shared.spelling
|
||||
|
||||
# Create some mock objects
|
||||
mockGui = MockGuiMain()
|
||||
|
||||
@@ -885,9 +885,9 @@ def testCoreIndex_ExtractData(nwGUI, fncPath, mockRnd):
|
||||
sHandle = project.newFile("Scene One", C.hNovelRoot)
|
||||
tHandle = project.newFile("Scene Two", C.hNovelRoot)
|
||||
|
||||
project.tree[hHandle].itemLayout == nwItemLayout.DOCUMENT # type: ignore
|
||||
project.tree[sHandle].itemLayout == nwItemLayout.DOCUMENT # type: ignore
|
||||
project.tree[tHandle].itemLayout == nwItemLayout.DOCUMENT # type: ignore
|
||||
assert project.tree[hHandle].itemLayout == nwItemLayout.DOCUMENT # type: ignore
|
||||
assert project.tree[sHandle].itemLayout == nwItemLayout.DOCUMENT # type: ignore
|
||||
assert project.tree[tHandle].itemLayout == nwItemLayout.DOCUMENT # type: ignore
|
||||
|
||||
assert index.scanText(hHandle, "## Chapter One\n\n") # type: ignore
|
||||
assert index.scanText(sHandle, "### Scene One\n\n") # type: ignore
|
||||
|
||||
@@ -74,7 +74,7 @@ def testGuiEditor_Init(qtbot, nwGUI, projPath, ipsumText, mockRnd):
|
||||
assert nwGUI.openDocument(C.hSceneDoc)
|
||||
docEditor = nwGUI.docEditor
|
||||
|
||||
docEditor.setPlainText("### Lorem Ipsum\n\n%s" % ipsumText[0])
|
||||
docEditor.setPlainText(f"### Lorem Ipsum\n\n{ipsumText[0]}")
|
||||
nwGUI.saveDocument()
|
||||
|
||||
# Check Defaults
|
||||
@@ -147,7 +147,7 @@ def testGuiEditor_LoadText(qtbot, nwGUI, projPath, ipsumText, mockRnd):
|
||||
assert nwGUI.openDocument(C.hSceneDoc) is True
|
||||
docEditor = nwGUI.docEditor
|
||||
|
||||
longText = "### Lorem Ipsum\n\n%s" % "\n\n".join(ipsumText*20)
|
||||
longText = "### Lorem Ipsum\n\n{0}".format("\n\n".join(ipsumText*20))
|
||||
docEditor.replaceText(longText)
|
||||
nwGUI.saveDocument()
|
||||
nwGUI.closeDocument()
|
||||
@@ -179,7 +179,7 @@ def testGuiEditor_SaveText(qtbot, monkeypatch, caplog, nwGUI, projPath, ipsumTex
|
||||
assert nwGUI.openDocument(C.hSceneDoc) is True
|
||||
docEditor = nwGUI.docEditor
|
||||
|
||||
longText = "### Lorem Ipsum\n\n%s" % "\n\n".join(ipsumText)
|
||||
longText = "### Lorem Ipsum\n\n{0}".format("\n\n".join(ipsumText))
|
||||
docEditor.replaceText(longText)
|
||||
|
||||
# Missing item
|
||||
@@ -483,7 +483,7 @@ def testGuiEditor_SpellChecking(qtbot, monkeypatch, nwGUI, projPath, ipsumText,
|
||||
assert nwGUI.openDocument(C.hSceneDoc) is True
|
||||
docEditor = nwGUI.docEditor
|
||||
|
||||
text = "### A Scene\n\n%s" % "\n\n".join(ipsumText)
|
||||
text = "### A Scene\n\n{0}".format("\n\n".join(ipsumText))
|
||||
docEditor.replaceText(text)
|
||||
|
||||
# Toggle State
|
||||
@@ -584,7 +584,7 @@ def testGuiEditor_Actions(qtbot, nwGUI, projPath, ipsumText, mockRnd):
|
||||
assert nwGUI.openDocument(C.hSceneDoc) is True
|
||||
docEditor = nwGUI.docEditor
|
||||
|
||||
text = "### A Scene\n\n%s" % "\n\n".join(ipsumText)
|
||||
text = "### A Scene\n\n{0}".format("\n\n".join(ipsumText))
|
||||
docEditor.replaceText(text)
|
||||
doc = docEditor.document()
|
||||
|
||||
@@ -650,7 +650,7 @@ def testGuiEditor_Actions(qtbot, nwGUI, projPath, ipsumText, mockRnd):
|
||||
# Emphasis/Undo/Redo
|
||||
# ==================
|
||||
|
||||
text = "### A Scene\n\n%s" % ipsumText[0]
|
||||
text = f"### A Scene\n\n{ipsumText[0]}"
|
||||
docEditor.replaceText(text)
|
||||
|
||||
# Emphasis
|
||||
@@ -683,7 +683,7 @@ def testGuiEditor_Actions(qtbot, nwGUI, projPath, ipsumText, mockRnd):
|
||||
# Shortcodes
|
||||
# ==========
|
||||
|
||||
text = "### A Scene\n\n%s" % ipsumText[0]
|
||||
text = f"### A Scene\n\n{ipsumText[0]}"
|
||||
docEditor.replaceText(text)
|
||||
|
||||
# Italic
|
||||
@@ -738,7 +738,7 @@ def testGuiEditor_Actions(qtbot, nwGUI, projPath, ipsumText, mockRnd):
|
||||
# Quotes
|
||||
# ======
|
||||
|
||||
text = "### A Scene\n\n%s" % ipsumText[0]
|
||||
text = f"### A Scene\n\n{ipsumText[0]}"
|
||||
docEditor.replaceText(text)
|
||||
|
||||
# Add Single Quotes
|
||||
@@ -772,7 +772,7 @@ def testGuiEditor_Actions(qtbot, nwGUI, projPath, ipsumText, mockRnd):
|
||||
# Remove Line Breaks
|
||||
# ==================
|
||||
|
||||
text = "### A Scene\n\n%s" % ipsumText[0]
|
||||
text = f"### A Scene\n\n{ipsumText[0]}"
|
||||
repText = text[:100] + text[100:].replace(" ", "\n", 3)
|
||||
docEditor.replaceText(repText)
|
||||
assert docEditor.docAction(nwDocAction.RM_BREAKS) is True
|
||||
@@ -974,7 +974,7 @@ def testGuiEditor_Insert(qtbot, monkeypatch, nwGUI, projPath, ipsumText, mockRnd
|
||||
buildTestProject(nwGUI, projPath)
|
||||
assert nwGUI.openDocument(C.hSceneDoc) is True
|
||||
docEditor = nwGUI.docEditor
|
||||
text = "### A Scene\n\n%s" % ipsumText[0]
|
||||
text = f"### A Scene\n\n{ipsumText[0]}"
|
||||
|
||||
# Insert Text
|
||||
# ===========
|
||||
@@ -1037,7 +1037,7 @@ def testGuiEditor_Insert(qtbot, monkeypatch, nwGUI, projPath, ipsumText, mockRnd
|
||||
# Insert KeyWords
|
||||
# ===============
|
||||
|
||||
text = "### A Scene\n\n\n%s" % ipsumText[0]
|
||||
text = f"### A Scene\n\n\n{ipsumText[0]}"
|
||||
docEditor.replaceText(text)
|
||||
docEditor.setCursorLine(3)
|
||||
|
||||
@@ -1076,13 +1076,13 @@ def testGuiEditor_TextManipulation(qtbot, nwGUI, projPath, ipsumText, mockRnd):
|
||||
assert nwGUI.openDocument(C.hSceneDoc) is True
|
||||
docEditor = nwGUI.docEditor
|
||||
|
||||
text = "### A Scene\n\n%s" % "\n\n".join(ipsumText)
|
||||
text = "### A Scene\n\n{0}".format("\n\n".join(ipsumText))
|
||||
docEditor.replaceText(text)
|
||||
|
||||
# Wrap Selection
|
||||
# ==============
|
||||
|
||||
text = "### A Scene\n\n%s" % "\n\n".join(ipsumText[0:2])
|
||||
text = "### A Scene\n\n{0}".format("\n\n".join(ipsumText[0:2]))
|
||||
docEditor.replaceText(text)
|
||||
docEditor.setCursorPosition(45)
|
||||
|
||||
@@ -1114,7 +1114,7 @@ def testGuiEditor_TextManipulation(qtbot, nwGUI, projPath, ipsumText, mockRnd):
|
||||
# Toggle Format
|
||||
# =============
|
||||
|
||||
text = "### A Scene\n\n%s" % "\n\n".join(ipsumText[0:2])
|
||||
text = "### A Scene\n\n{0}".format("\n\n".join(ipsumText[0:2]))
|
||||
|
||||
# Block format repetition
|
||||
docEditor.replaceText(text)
|
||||
@@ -1186,7 +1186,7 @@ def testGuiEditor_TextManipulation(qtbot, nwGUI, projPath, ipsumText, mockRnd):
|
||||
# ==============
|
||||
|
||||
# No Selection
|
||||
text = "### A Scene\n\n%s" % ipsumText[0].replace("consectetur", "=consectetur=")
|
||||
text = "### A Scene\n\n{0}".format(ipsumText[0].replace("consectetur", "=consectetur="))
|
||||
docEditor.replaceText(text)
|
||||
docEditor.setCursorPosition(45)
|
||||
docEditor._replaceQuotes("=", "<", ">")
|
||||
@@ -1194,7 +1194,7 @@ def testGuiEditor_TextManipulation(qtbot, nwGUI, projPath, ipsumText, mockRnd):
|
||||
|
||||
# First Paragraph Selected
|
||||
# This should not replace anything in second paragraph
|
||||
text = "### A Scene\n\n%s" % "\n\n".join(ipsumText[0:2]).replace("ipsum", "=ipsum=")
|
||||
text = "### A Scene\n\n{0}".format("\n\n".join(ipsumText[0:2]).replace("ipsum", "=ipsum="))
|
||||
docEditor.replaceText(text)
|
||||
docEditor.setCursorPosition(45)
|
||||
assert docEditor.docAction(nwDocAction.SEL_PARA)
|
||||
@@ -1222,7 +1222,7 @@ def testGuiEditor_TextManipulation(qtbot, nwGUI, projPath, ipsumText, mockRnd):
|
||||
# Check Blocks
|
||||
cursor = docEditor.textCursor()
|
||||
cursor.clearSelection()
|
||||
text = "### A Scene\n\n%s\n\n%s" % (parOne, parTwo)
|
||||
text = f"### A Scene\n\n{parOne}\n\n{parTwo}"
|
||||
docEditor.replaceText(text)
|
||||
docEditor.setCursorPosition(45)
|
||||
assert len(docEditor._selectedBlocks(cursor)) == 0
|
||||
@@ -1231,15 +1231,15 @@ def testGuiEditor_TextManipulation(qtbot, nwGUI, projPath, ipsumText, mockRnd):
|
||||
assert len(docEditor._selectedBlocks(cursor)) == 15
|
||||
|
||||
# Remove All
|
||||
text = "### A Scene\n\n%s\n\n%s" % (parOne, parTwo)
|
||||
text = f"### A Scene\n\n{parOne}\n\n{parTwo}"
|
||||
docEditor.replaceText(text)
|
||||
docEditor.setCursorPosition(45)
|
||||
docEditor._removeInParLineBreaks()
|
||||
assert docEditor.getText() == "### A Scene\n\n%s\n" % "\n\n".join(ipsumText[0:2])
|
||||
assert docEditor.getText() == "### A Scene\n\n{0}\n".format("\n\n".join(ipsumText[0:2]))
|
||||
|
||||
# Remove in First Paragraph
|
||||
# Second paragraphs should remain unchanged
|
||||
text = "### A Scene\n\n%s\n\n%s" % (parOne, parTwo)
|
||||
text = f"### A Scene\n\n{parOne}\n\n{parTwo}"
|
||||
docEditor.replaceText(text)
|
||||
cursor = docEditor.textCursor()
|
||||
cursor.setPosition(16, QtMoveAnchor)
|
||||
@@ -1260,7 +1260,7 @@ def testGuiEditor_TextManipulation(qtbot, nwGUI, projPath, ipsumText, mockRnd):
|
||||
|
||||
# Key Press Events
|
||||
# ================
|
||||
text = "### A Scene\n\n%s\n\n%s" % (parOne, parTwo)
|
||||
text = f"### A Scene\n\n{parOne}\n\n{parTwo}"
|
||||
docEditor.replaceText(text)
|
||||
assert docEditor.getText() == text
|
||||
|
||||
@@ -1290,7 +1290,7 @@ def testGuiEditor_BlockFormatting(qtbot, monkeypatch, nwGUI, projPath, ipsumText
|
||||
# Invalid and Generic
|
||||
# ===================
|
||||
|
||||
text = "### A Scene\n\n%s" % ipsumText[0]
|
||||
text = f"### A Scene\n\n{ipsumText[0]}"
|
||||
docEditor.replaceText(text)
|
||||
|
||||
# Invalid Block
|
||||
|
||||
@@ -276,11 +276,11 @@ def testGuiMainMenu_EditFormat(qtbot, monkeypatch, nwGUI, prjLipsum):
|
||||
# Other Checks
|
||||
|
||||
# Replace Quotes
|
||||
docEditor.setPlainText((
|
||||
docEditor.setPlainText(
|
||||
"### New Text\n\n"
|
||||
"Text with 'single' quotes and 'tricky stuff's'.\n\n"
|
||||
"Also text with \"double\" quotes which are \"less tricky\".\n\n"
|
||||
))
|
||||
)
|
||||
|
||||
mainMenu.aSelectAll.activate(QAction.ActionEvent.Trigger)
|
||||
mainMenu.aFmtReplSng.activate(QAction.ActionEvent.Trigger)
|
||||
@@ -299,14 +299,14 @@ def testGuiMainMenu_EditFormat(qtbot, monkeypatch, nwGUI, prjLipsum):
|
||||
)
|
||||
|
||||
# Remove in-paragraph line breaks
|
||||
docEditor.setPlainText((
|
||||
docEditor.setPlainText(
|
||||
"### New Text\n\n"
|
||||
"@char: Someone\n"
|
||||
"@location: Somewhere\n\n"
|
||||
"% Some comment ...\n\n"
|
||||
"Here is some text\non multiple\nlines.\n\n"
|
||||
"With another paragraph\nhere."
|
||||
))
|
||||
)
|
||||
mainMenu.aFmtRmBreaks.activate(QAction.ActionEvent.Trigger)
|
||||
assert docEditor.getText() == (
|
||||
"### New Text\n\n"
|
||||
@@ -317,14 +317,14 @@ def testGuiMainMenu_EditFormat(qtbot, monkeypatch, nwGUI, prjLipsum):
|
||||
"With another paragraph here.\n"
|
||||
)
|
||||
|
||||
docEditor.setPlainText((
|
||||
docEditor.setPlainText(
|
||||
"### New Text\n\n"
|
||||
"@char: Someone\n"
|
||||
"@location: Somewhere\n\n"
|
||||
"% Some comment ...\n\n"
|
||||
"Here is some text\non multiple\nlines.\n\n"
|
||||
"With another paragraph\nhere."
|
||||
))
|
||||
)
|
||||
cursor = docEditor.textCursor()
|
||||
cursor.setPosition(74)
|
||||
cursor.movePosition(QtMoveRight, QtKeepAnchor, 29)
|
||||
@@ -343,12 +343,12 @@ def testGuiMainMenu_EditFormat(qtbot, monkeypatch, nwGUI, prjLipsum):
|
||||
assert not docEditor.docAction(nwDocAction.NO_ACTION)
|
||||
|
||||
# Test Invalid Formats
|
||||
docEditor.setPlainText((
|
||||
docEditor.setPlainText(
|
||||
"### New Text\n\n"
|
||||
"@tag: Bod\n\n"
|
||||
"Text with 'single' quotes and 'tricky stuff's'.\n\n"
|
||||
"Also text with \"double\" quotes which are \"less tricky\".\n\n"
|
||||
))
|
||||
)
|
||||
|
||||
# Cannot Format Tag
|
||||
docEditor.setCursorPosition(17)
|
||||
@@ -489,7 +489,7 @@ def testGuiMainMenu_Insert(qtbot, monkeypatch, nwGUI, fncPath, projPath, mockRnd
|
||||
# Insert Keywords
|
||||
# ===============
|
||||
|
||||
for action, key in zip(mainMenu.mInsKeywords.actions(), nwKeyWords.ALL_KEYS):
|
||||
for action, key in zip(mainMenu.mInsKeywords.actions(), nwKeyWords.ALL_KEYS, strict=False):
|
||||
docEditor.setPlainText("Stuff")
|
||||
action.activate(QAction.ActionEvent.Trigger)
|
||||
assert docEditor.getText() == f"Stuff\n{key}: "
|
||||
@@ -503,7 +503,7 @@ def testGuiMainMenu_Insert(qtbot, monkeypatch, nwGUI, fncPath, projPath, mockRnd
|
||||
# Insert Fields
|
||||
# =============
|
||||
|
||||
for action, field in zip(mainMenu.mInsField.actions(), nwStats.ALL_FIELDS):
|
||||
for action, field in zip(mainMenu.mInsField.actions(), nwStats.ALL_FIELDS, strict=False):
|
||||
value = nwShortcode.FIELD_VALUE.format(field)
|
||||
docEditor.setPlainText("Stuff ")
|
||||
docEditor.setCursorPosition(6)
|
||||
|
||||
@@ -86,7 +86,7 @@ def testTextCounting_standardCounter():
|
||||
assert standardCounter(" <") == (0, 0, 0)
|
||||
|
||||
# General Text
|
||||
cC, wC, pC = standardCounter((
|
||||
cC, wC, pC = standardCounter(
|
||||
"#! Title\n\n"
|
||||
"##! Prologue\n\n"
|
||||
"# Heading One\n"
|
||||
@@ -100,47 +100,47 @@ def testTextCounting_standardCounter():
|
||||
"The second paragraph.\n\n\n"
|
||||
"The third paragraph.\n\n"
|
||||
"Dashes\u2013and even longer\u2014dashes."
|
||||
))
|
||||
)
|
||||
assert cC == 163
|
||||
assert wC == 26
|
||||
assert pC == 4
|
||||
|
||||
# Text Alignment
|
||||
cC, wC, pC = standardCounter((
|
||||
cC, wC, pC = standardCounter(
|
||||
"# Title\n\n"
|
||||
"Left aligned<<\n\n"
|
||||
"Left aligned <<\n\n"
|
||||
"Right indent<\n\n"
|
||||
"Right indent <\n\n"
|
||||
))
|
||||
)
|
||||
assert cC == 53
|
||||
assert wC == 9
|
||||
assert pC == 4
|
||||
|
||||
cC, wC, pC = standardCounter((
|
||||
cC, wC, pC = standardCounter(
|
||||
"# Title\n\n"
|
||||
">>Right aligned\n\n"
|
||||
">> Right aligned\n\n"
|
||||
">Left indent\n\n"
|
||||
"> Left indent\n\n"
|
||||
))
|
||||
)
|
||||
assert cC == 53
|
||||
assert wC == 9
|
||||
assert pC == 4
|
||||
|
||||
cC, wC, pC = standardCounter((
|
||||
cC, wC, pC = standardCounter(
|
||||
"# Title\n\n"
|
||||
">>Centre aligned<<\n\n"
|
||||
">> Centre aligned <<\n\n"
|
||||
">Double indent<\n\n"
|
||||
"> Double indent <\n\n"
|
||||
))
|
||||
)
|
||||
assert cC == 59
|
||||
assert wC == 9
|
||||
assert pC == 4
|
||||
|
||||
# Formatting Codes, Upper Case (Old Implementation)
|
||||
cC, wC, pC = standardCounter((
|
||||
cC, wC, pC = standardCounter(
|
||||
"Some text\n\n"
|
||||
"[NEWPAGE]\n\n"
|
||||
"more text\n\n"
|
||||
@@ -150,13 +150,13 @@ def testTextCounting_standardCounter():
|
||||
"and some final text\n\n"
|
||||
"[VSPACE:4]\n\n"
|
||||
"THE END\n\n"
|
||||
))
|
||||
)
|
||||
assert cC == 58
|
||||
assert wC == 13
|
||||
assert pC == 5
|
||||
|
||||
# Formatting Codes, Lower Case (Current Implementation)
|
||||
cC, wC, pC = standardCounter((
|
||||
cC, wC, pC = standardCounter(
|
||||
"Some text\n\n"
|
||||
"[newpage]\n\n"
|
||||
"more text\n\n"
|
||||
@@ -166,16 +166,16 @@ def testTextCounting_standardCounter():
|
||||
"and some final text\n\n"
|
||||
"[vspace:4]\n\n"
|
||||
"THE END\n\n"
|
||||
))
|
||||
)
|
||||
assert cC == 58
|
||||
assert wC == 13
|
||||
assert pC == 5
|
||||
|
||||
# Check ShortCodes
|
||||
cC, wC, pC = standardCounter((
|
||||
cC, wC, pC = standardCounter(
|
||||
"Text with [b]bold[/b] text and padded [b] bold [/b] text.\n\n"
|
||||
"Text with [b][i] nested [/i] emphasis [/b] in it.\n\n"
|
||||
))
|
||||
)
|
||||
assert cC == 78
|
||||
assert wC == 14
|
||||
assert pC == 2
|
||||
@@ -188,7 +188,7 @@ def testTextCounting_bodyTextCounter():
|
||||
assert bodyTextCounter(None) == (0, 0, 0) # type: ignore
|
||||
|
||||
# General Text
|
||||
wC, cC, sC = bodyTextCounter((
|
||||
wC, cC, sC = bodyTextCounter(
|
||||
"#! Title\n\n"
|
||||
"##! Prologue\n\n"
|
||||
"# Heading One\n"
|
||||
@@ -201,7 +201,7 @@ def testTextCounting_bodyTextCounter():
|
||||
"The second paragraph.\n\n\n"
|
||||
"The third paragraph.\n\n"
|
||||
"Dashes\u2013and even longer\u2014dashes."
|
||||
))
|
||||
)
|
||||
assert wC == 14
|
||||
assert cC == 91
|
||||
assert sC == 81
|
||||
|
||||
@@ -293,7 +293,7 @@ def testToolManuscript_Features(monkeypatch, qtbot, nwGUI, projPath, mockRnd):
|
||||
obj.close()
|
||||
break
|
||||
else:
|
||||
assert False
|
||||
raise AssertionError
|
||||
|
||||
# Finish
|
||||
manus.close()
|
||||
@@ -327,7 +327,7 @@ def testToolManuscript_Print(monkeypatch, qtbot, nwGUI, projPath):
|
||||
obj.close()
|
||||
break
|
||||
else:
|
||||
assert False
|
||||
raise AssertionError
|
||||
|
||||
# Finish
|
||||
manus.close()
|
||||
|
||||
@@ -121,41 +121,41 @@ def testToolWritingStats_Export(qtbot, monkeypatch, nwGUI, projPath, tstPaths):
|
||||
# Sort by time
|
||||
sessLog.listBox.sortByColumn(sessLog.C_TIME, Qt.SortOrder.AscendingOrder)
|
||||
|
||||
assert sessLog.novelWords.text() == "{:n}".format(600)
|
||||
assert sessLog.notesWords.text() == "{:n}".format(275)
|
||||
assert sessLog.totalWords.text() == "{:n}".format(875)
|
||||
assert sessLog.novelWords.text() == f"{600:n}"
|
||||
assert sessLog.notesWords.text() == f"{275:n}"
|
||||
assert sessLog.totalWords.text() == f"{875:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(0)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(1)
|
||||
assert item.text(sessLog.C_COUNT) == f"{1:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(1)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(-200)
|
||||
assert item.text(sessLog.C_COUNT) == f"{-200:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(2)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(300)
|
||||
assert item.text(sessLog.C_COUNT) == f"{300:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(3)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(-120)
|
||||
assert item.text(sessLog.C_COUNT) == f"{-120:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(4)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(-20)
|
||||
assert item.text(sessLog.C_COUNT) == f"{-20:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(5)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(40)
|
||||
assert item.text(sessLog.C_COUNT) == f"{40:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(6)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(-400)
|
||||
assert item.text(sessLog.C_COUNT) == f"{-400:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(7)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(200)
|
||||
assert item.text(sessLog.C_COUNT) == f"{200:n}"
|
||||
|
||||
assert sessLog._saveData(sessLog.FMT_CSV)
|
||||
assert sessLog._saveData(sessLog.FMT_JSON)
|
||||
@@ -230,35 +230,35 @@ def testToolWritingStats_Filters(qtbot, monkeypatch, nwGUI, projPath, tstPaths):
|
||||
|
||||
item = sessLog.listBox.topLevelItem(0)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(1)
|
||||
assert item.text(sessLog.C_COUNT) == f"{1:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(1)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(-200)
|
||||
assert item.text(sessLog.C_COUNT) == f"{-200:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(2)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(300)
|
||||
assert item.text(sessLog.C_COUNT) == f"{300:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(3)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(-120)
|
||||
assert item.text(sessLog.C_COUNT) == f"{-120:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(4)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(-20)
|
||||
assert item.text(sessLog.C_COUNT) == f"{-20:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(5)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(40)
|
||||
assert item.text(sessLog.C_COUNT) == f"{40:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(6)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(-400)
|
||||
assert item.text(sessLog.C_COUNT) == f"{-400:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(7)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(200)
|
||||
assert item.text(sessLog.C_COUNT) == f"{200:n}"
|
||||
|
||||
# No Novel Files
|
||||
qtbot.mouseClick(sessLog.incNovel, QtMouseLeft)
|
||||
@@ -270,35 +270,35 @@ def testToolWritingStats_Filters(qtbot, monkeypatch, nwGUI, projPath, tstPaths):
|
||||
|
||||
item = sessLog.listBox.topLevelItem(0)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(1)
|
||||
assert item.text(sessLog.C_COUNT) == f"{1:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(1)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(-100)
|
||||
assert item.text(sessLog.C_COUNT) == f"{-100:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(2)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(150)
|
||||
assert item.text(sessLog.C_COUNT) == f"{150:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(3)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(-60)
|
||||
assert item.text(sessLog.C_COUNT) == f"{-60:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(4)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(-10)
|
||||
assert item.text(sessLog.C_COUNT) == f"{-10:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(5)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(20)
|
||||
assert item.text(sessLog.C_COUNT) == f"{20:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(6)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(-200)
|
||||
assert item.text(sessLog.C_COUNT) == f"{-200:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(7)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(100)
|
||||
assert item.text(sessLog.C_COUNT) == f"{100:n}"
|
||||
|
||||
assert jsonData == [
|
||||
{
|
||||
@@ -339,35 +339,35 @@ def testToolWritingStats_Filters(qtbot, monkeypatch, nwGUI, projPath, tstPaths):
|
||||
|
||||
item = sessLog.listBox.topLevelItem(0)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(1)
|
||||
assert item.text(sessLog.C_COUNT) == f"{1:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(1)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(-100)
|
||||
assert item.text(sessLog.C_COUNT) == f"{-100:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(2)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(150)
|
||||
assert item.text(sessLog.C_COUNT) == f"{150:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(3)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(-60)
|
||||
assert item.text(sessLog.C_COUNT) == f"{-60:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(4)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(-10)
|
||||
assert item.text(sessLog.C_COUNT) == f"{-10:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(5)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(20)
|
||||
assert item.text(sessLog.C_COUNT) == f"{20:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(6)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(-200)
|
||||
assert item.text(sessLog.C_COUNT) == f"{-200:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(7)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(100)
|
||||
assert item.text(sessLog.C_COUNT) == f"{100:n}"
|
||||
|
||||
assert jsonData == [
|
||||
{
|
||||
@@ -408,19 +408,19 @@ def testToolWritingStats_Filters(qtbot, monkeypatch, nwGUI, projPath, tstPaths):
|
||||
|
||||
item = sessLog.listBox.topLevelItem(0)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(1)
|
||||
assert item.text(sessLog.C_COUNT) == f"{1:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(1)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(300)
|
||||
assert item.text(sessLog.C_COUNT) == f"{300:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(2)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(40)
|
||||
assert item.text(sessLog.C_COUNT) == f"{40:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(3)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(200)
|
||||
assert item.text(sessLog.C_COUNT) == f"{200:n}"
|
||||
|
||||
assert jsonData == [
|
||||
{
|
||||
@@ -449,43 +449,43 @@ def testToolWritingStats_Filters(qtbot, monkeypatch, nwGUI, projPath, tstPaths):
|
||||
|
||||
item = sessLog.listBox.topLevelItem(0)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(1)
|
||||
assert item.text(sessLog.C_COUNT) == f"{1:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(1)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(0)
|
||||
assert item.text(sessLog.C_COUNT) == f"{0:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(2)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(-200)
|
||||
assert item.text(sessLog.C_COUNT) == f"{-200:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(3)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(300)
|
||||
assert item.text(sessLog.C_COUNT) == f"{300:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(4)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(-120)
|
||||
assert item.text(sessLog.C_COUNT) == f"{-120:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(5)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(-20)
|
||||
assert item.text(sessLog.C_COUNT) == f"{-20:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(6)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(40)
|
||||
assert item.text(sessLog.C_COUNT) == f"{40:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(7)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(-400)
|
||||
assert item.text(sessLog.C_COUNT) == f"{-400:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(8)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(200)
|
||||
assert item.text(sessLog.C_COUNT) == f"{200:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(9)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(0)
|
||||
assert item.text(sessLog.C_COUNT) == f"{0:n}"
|
||||
|
||||
assert jsonData == [
|
||||
{
|
||||
@@ -542,35 +542,35 @@ def testToolWritingStats_Filters(qtbot, monkeypatch, nwGUI, projPath, tstPaths):
|
||||
|
||||
item = sessLog.listBox.topLevelItem(0)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(1)
|
||||
assert item.text(sessLog.C_COUNT) == f"{1:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(1)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(-200)
|
||||
assert item.text(sessLog.C_COUNT) == f"{-200:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(2)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(180)
|
||||
assert item.text(sessLog.C_COUNT) == f"{180:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(3)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(-20)
|
||||
assert item.text(sessLog.C_COUNT) == f"{-20:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(4)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(40)
|
||||
assert item.text(sessLog.C_COUNT) == f"{40:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(5)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(-400)
|
||||
assert item.text(sessLog.C_COUNT) == f"{-400:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(6)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(200)
|
||||
assert item.text(sessLog.C_COUNT) == f"{200:n}"
|
||||
|
||||
item = sessLog.listBox.topLevelItem(7)
|
||||
assert item is not None
|
||||
assert item.text(sessLog.C_COUNT) == "{:n}".format(0)
|
||||
assert item.text(sessLog.C_COUNT) == f"{0:n}"
|
||||
|
||||
assert jsonData == [
|
||||
{
|
||||
|
||||
+7
-7
@@ -97,18 +97,18 @@ def cmpFiles(
|
||||
lnTwo = txtTwo[n].strip()
|
||||
|
||||
if n+1 in ignoreLines:
|
||||
print("Ignoring line %d" % (n+1))
|
||||
print(f"Ignoring line {n+1}")
|
||||
continue
|
||||
|
||||
if ignoreStart is not None:
|
||||
if lnOne.startswith(ignoreStart):
|
||||
print("Ignoring line %d" % (n+1))
|
||||
print(f"Ignoring line {n+1}")
|
||||
continue
|
||||
|
||||
if lnOne != lnTwo:
|
||||
print("Diff on line %d:" % (n+1))
|
||||
print(" << '%s'" % lnOne)
|
||||
print(" >> '%s'" % lnTwo)
|
||||
print(f"Diff on line {n+1}:")
|
||||
print(f" << '{lnOne}'")
|
||||
print(f" >> '{lnTwo}'")
|
||||
diffFound = True
|
||||
|
||||
return not diffFound
|
||||
@@ -205,11 +205,11 @@ def buildTestProject(obj: object, projPath: Path) -> None:
|
||||
project.index.reIndexHandle(tdHandle)
|
||||
|
||||
aDoc = project.storage.getDocument(cdHandle)
|
||||
aDoc.writeDocument("## %s\n\n" % project.tr("New Chapter"))
|
||||
aDoc.writeDocument("## {0}\n\n".format(project.tr("New Chapter")))
|
||||
project.index.reIndexHandle(cdHandle)
|
||||
|
||||
aDoc = project.storage.getDocument(sdHandle)
|
||||
aDoc.writeDocument("### %s\n\n" % project.tr("New Scene"))
|
||||
aDoc.writeDocument("### {0}\n\n".format(project.tr("New Scene")))
|
||||
project.index.reIndexHandle(sdHandle)
|
||||
|
||||
project.session.startSession()
|
||||
|
||||
+2
-2
@@ -102,7 +102,7 @@ def buildSampleZip(args: argparse.Namespace | None = None) -> None:
|
||||
sys.exit(1)
|
||||
|
||||
print("")
|
||||
print("Built file: %s" % dstSample)
|
||||
print(f"Built file: {dstSample}")
|
||||
print("")
|
||||
|
||||
return
|
||||
@@ -242,7 +242,7 @@ def buildTranslationAssets(args: argparse.Namespace | None = None) -> None:
|
||||
for item in srcDir.iterdir():
|
||||
if item.is_file() and item.suffix == ".qm":
|
||||
item.rename(dstDir / item.name)
|
||||
print("Moved: %s -> %s" % (item.relative_to(ROOT_DIR), dstRel / item.name))
|
||||
print(f"Moved: {item.relative_to(ROOT_DIR)} -> {dstRel / item.name}")
|
||||
|
||||
print("")
|
||||
|
||||
|
||||
@@ -65,12 +65,12 @@ def embedPython(bldDir: Path, outDir: Path) -> None:
|
||||
"""Embed Python library."""
|
||||
print("Adding Python embeddable ...")
|
||||
|
||||
pyVers = "%d.%d.%d" % (sys.version_info[:3])
|
||||
pyVers = ".".join(str(v) for v in sys.version_info[:3])
|
||||
zipFile = f"python-{pyVers}-embed-amd64.zip"
|
||||
pyZip = bldDir / zipFile
|
||||
if not pyZip.is_file():
|
||||
pyUrl = f"https://www.python.org/ftp/python/{pyVers}/{zipFile}"
|
||||
print("Downloading: %s" % pyUrl)
|
||||
print(f"Downloading: {pyUrl}")
|
||||
urllib.request.urlretrieve(pyUrl, pyZip)
|
||||
|
||||
print("Extracting ...")
|
||||
@@ -192,7 +192,7 @@ def main(args: argparse.Namespace) -> None:
|
||||
print("")
|
||||
|
||||
numVers, _, _ = extractVersion()
|
||||
print("Version: %s" % numVers)
|
||||
print(f"Version: {numVers}")
|
||||
|
||||
bldDir = ROOT_DIR / "dist"
|
||||
outDir = bldDir / "novelWriter"
|
||||
|
||||
+6
-6
@@ -44,17 +44,17 @@ def extractVersion(beQuiet: bool = False) -> tuple[str, str, str]:
|
||||
try:
|
||||
for aLine in initFile.read_text(encoding="utf-8").splitlines():
|
||||
if aLine.startswith("__version__"):
|
||||
numVers = getValue((aLine))
|
||||
numVers = getValue(aLine)
|
||||
if aLine.startswith("__hexversion__"):
|
||||
hexVers = getValue((aLine))
|
||||
hexVers = getValue(aLine)
|
||||
if aLine.startswith("__date__"):
|
||||
relDate = getValue((aLine))
|
||||
relDate = getValue(aLine)
|
||||
except Exception as exc:
|
||||
print("Could not read file: %s" % initFile)
|
||||
print(f"Could not read file: {initFile}")
|
||||
print(str(exc))
|
||||
|
||||
if not beQuiet:
|
||||
print("novelWriter version: %s (%s) at %s" % (numVers, hexVers, relDate))
|
||||
print(f"novelWriter version: {numVers} ({hexVers}) at {relDate}")
|
||||
|
||||
return numVers, hexVers, relDate
|
||||
|
||||
@@ -95,7 +95,7 @@ def copyPackageFiles(dst: Path, setupPy: bool = False) -> None:
|
||||
copyFiles = ["LICENSE.md", "CREDITS.md", "pyproject.toml"]
|
||||
for copyFile in copyFiles:
|
||||
shutil.copyfile(copyFile, dst / copyFile)
|
||||
print("Copied: %s" % copyFile)
|
||||
print(f"Copied: {copyFile}")
|
||||
|
||||
writeFile(dst / "MANIFEST.in", (
|
||||
"include LICENSE.md\n"
|
||||
|
||||
@@ -165,7 +165,7 @@ def _fixXml(svg: ET.Element) -> str:
|
||||
|
||||
|
||||
def _writeThemeFile(
|
||||
path: Path, name: str, author: str, license: str, icons: dict[str, ET.Element]
|
||||
path: Path, name: str, author: str, license_: str, icons: dict[str, ET.Element]
|
||||
) -> None:
|
||||
"""Write an icon theme file."""
|
||||
with open(path.with_suffix(".icons"), mode="w", encoding="utf-8") as out:
|
||||
@@ -173,7 +173,7 @@ def _writeThemeFile(
|
||||
out.write("# Meta\n")
|
||||
out.write(f"meta:name = {name}\n")
|
||||
out.write(f"meta:author = {author}\n")
|
||||
out.write(f"meta:license = {license}\n")
|
||||
out.write(f"meta:license = {license_}\n")
|
||||
out.write("\n")
|
||||
out.write("# Icons\n")
|
||||
for key, svg in icons.items():
|
||||
|
||||
Reference in New Issue
Block a user