From 4cf49bd80a98e58ba42ec193c75fb01fb4faacda Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Thu, 13 Aug 2020 21:01:15 +0200 Subject: [PATCH 1/6] Updated flake8 settings --- .github/workflows/syntax.yml | 2 +- setup.cfg | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/syntax.yml b/.github/workflows/syntax.yml index f75369fe..2480e963 100644 --- a/.github/workflows/syntax.yml +++ b/.github/workflows/syntax.yml @@ -24,4 +24,4 @@ jobs: - name: Check for Syntax Error on Tests run: flake8 tests --count --select=E9,F63,F7,F82 --show-source --statistics - name: Check for Code Style on novelWriter - run: flake8 nw --count --max-line-length=99 --select E1,E231,E27,E4,E5,E7,E9,W,F --show-source --statistics + run: flake8 nw --count --max-line-length=99 --ignore E203,E221,E226,E241,E251,E261,E266,E302,E305 --show-source --statistics diff --git a/setup.cfg b/setup.cfg index 065ab174..d9410a61 100644 --- a/setup.cfg +++ b/setup.cfg @@ -3,3 +3,8 @@ license_files = LICENSE.md [bdist_wheel] universal = 0 + +[flake8] +ignore = E203,E221,E226,E241,E251,E261,E266,E302,E305 +max-line-length = 99 +exclude = docs/* From 832b5747df071852ead08dd33ee9a164eec199e4 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Thu, 13 Aug 2020 21:01:52 +0200 Subject: [PATCH 2/6] Fiexd more formatting errors --- nw/__init__.py | 1 + nw/core/project.py | 15 ++++++------ nw/core/tokenizer.py | 46 +++++++++++++++++------------------ nw/core/tree.py | 4 ++-- nw/gui/build.py | 1 - nw/gui/dochighlight.py | 16 ++++++------- nw/gui/outline.py | 10 ++++---- nw/gui/theme.py | 54 +++++++++++++++++++++--------------------- 8 files changed, 74 insertions(+), 73 deletions(-) diff --git a/nw/__init__.py b/nw/__init__.py index 603ded31..cb68d8c6 100644 --- a/nw/__init__.py +++ b/nw/__init__.py @@ -76,6 +76,7 @@ logging.addLevelName(VERBOSE, "VERBOSE") def logVerbose(self, message, *args, **kws): if self.isEnabledFor(VERBOSE): self._log(VERBOSE, message, args, **kws) + logging.Logger.verbose = logVerbose # Initiating logging diff --git a/nw/core/project.py b/nw/core/project.py index 1844c9cb..a2a670f5 100644 --- a/nw/core/project.py +++ b/nw/core/project.py @@ -206,14 +206,14 @@ class NWProject(): self.autoOutline = True self.statusItems = NWStatus() self.statusItems.addEntry("New", (100, 100, 100)) - self.statusItems.addEntry("Note", (200, 50, 0)) - self.statusItems.addEntry("Draft", (200, 150, 0)) - self.statusItems.addEntry("Finished", ( 50, 200, 0)) + self.statusItems.addEntry("Note", (200, 50, 0)) + self.statusItems.addEntry("Draft", (200, 150, 0)) + self.statusItems.addEntry("Finished", (50, 200, 0)) self.importItems = NWStatus() self.importItems.addEntry("New", (100, 100, 100)) - self.importItems.addEntry("Minor", (200, 50, 0)) - self.importItems.addEntry("Major", (200, 150, 0)) - self.importItems.addEntry("Main", ( 50, 200, 0)) + self.importItems.addEntry("Minor", (200, 50, 0)) + self.importItems.addEntry("Major", (200, 150, 0)) + self.importItems.addEntry("Main", (50, 200, 0)) self.lastEdited = None self.lastViewed = None self.lastWCount = 0 @@ -1402,7 +1402,8 @@ class NWProject(): try: rmdir(theData) logger.info("Removed folder: %s" % theFolder) - except Exception: + except Exception as e: + logger.error(str(e)) errList.append("Failed to remove: %s" % theFolder) return errList diff --git a/nw/core/tokenizer.py b/nw/core/tokenizer.py index 0314d9af..bf881f50 100644 --- a/nw/core/tokenizer.py +++ b/nw/core/tokenizer.py @@ -40,34 +40,34 @@ logger = logging.getLogger(__name__) class Tokenizer(): - FMT_B_B = 1 # Begin bold - FMT_B_E = 2 # End bold - FMT_I_B = 3 # Begin italics - FMT_I_E = 4 # End italics - FMT_D_B = 5 # Begin strikeout - FMT_D_E = 6 # End strikeout + FMT_B_B = 1 # Begin bold + FMT_B_E = 2 # End bold + FMT_I_B = 3 # Begin italics + FMT_I_E = 4 # End italics + FMT_D_B = 5 # Begin strikeout + FMT_D_E = 6 # End strikeout - T_EMPTY = 1 # Empty line (new paragraph) - T_SYNOPSIS = 2 # Synopsis comment - T_COMMENT = 3 # Comment line - T_KEYWORD = 4 # Command line - T_TITLE = 5 # Title - T_HEAD1 = 6 # Header 1 - T_HEAD2 = 7 # Header 2 - T_HEAD3 = 8 # Header 3 - T_HEAD4 = 9 # Header 4 + T_EMPTY = 1 # Empty line (new paragraph) + T_SYNOPSIS = 2 # Synopsis comment + T_COMMENT = 3 # Comment line + T_KEYWORD = 4 # Command line + T_TITLE = 5 # Title + T_HEAD1 = 6 # Header 1 + T_HEAD2 = 7 # Header 2 + T_HEAD3 = 8 # Header 3 + T_HEAD4 = 9 # Header 4 T_TEXT = 10 # Text line T_SEP = 11 # Scene separator T_SKIP = 12 # Paragraph break - A_NONE = 0 # No special style - A_LEFT = 1 # Left aligned - A_RIGHT = 2 # Right aligned - A_CENTRE = 4 # Centred - A_JUSTIFY = 8 # Justified - A_PBB = 16 # Page break before always - A_PBB_AV = 32 # Page break before avoid - A_PBB_NO = 64 # Page break before never + A_NONE = 0 # No special style + A_LEFT = 1 # Left aligned + A_RIGHT = 2 # Right aligned + A_CENTRE = 4 # Centred + A_JUSTIFY = 8 # Justified + A_PBB = 16 # Page break before always + A_PBB_AV = 32 # Page break before avoid + A_PBB_NO = 64 # Page break before never A_PBA = 128 # Page break after always A_PBA_AV = 256 # Page break after avoid A_PBA_NO = 512 # Page break after avoid diff --git a/nw/core/tree.py b/nw/core/tree.py index a9e77326..74080bd3 100644 --- a/nw/core/tree.py +++ b/nw/core/tree.py @@ -153,7 +153,7 @@ class NWTree(): outFile.write(" Table of Contents\n") outFile.write("===================\n") outFile.write("\n") - outFile.write(" %-25s %-9s %s\n" %("File Name", "Class", "Document Label")) + outFile.write(" %-25s %-9s %s\n" % ("File Name", "Class", "Document Label")) outFile.write("-"*80+"\n") for tHandle in sorted(self._treeOrder): tItem = self.__getitem__(tHandle) @@ -161,7 +161,7 @@ class NWTree(): continue tFile = tHandle+".nwd" if path.isfile(path.join(self.theProject.projContent, tFile)): - outFile.write(" %-25s %-9s %s\n" %( + outFile.write(" %-25s %-9s %s\n" % ( path.join("content", tFile), tItem.itemClass.name, tItem.itemName, diff --git a/nw/gui/build.py b/nw/gui/build.py index 336eb684..9bc09e61 100644 --- a/nw/gui/build.py +++ b/nw/gui/build.py @@ -1068,7 +1068,6 @@ class GuiBuildNovelDocView(QTextBrowser): strBuildTime = "Unknown" self.theTitle.setText("Build Time: %s" % strBuildTime) - def _updateDocMargins(self): """Automatically adjust the header to fill the top of the document within the viewport. diff --git a/nw/gui/dochighlight.py b/nw/gui/dochighlight.py index 4be70d5c..d743caa7 100644 --- a/nw/gui/dochighlight.py +++ b/nw/gui/dochighlight.py @@ -101,17 +101,17 @@ class GuiDocHighlighter(QSyntaxHighlighter): self.colEmph = None self.hStyles = { - "header1" : self._makeFormat(self.colHead, "bold", 1.8), - "header2" : self._makeFormat(self.colHead, "bold", 1.6), - "header3" : self._makeFormat(self.colHead, "bold", 1.4), - "header4" : self._makeFormat(self.colHead, "bold", 1.2), + "header1" : self._makeFormat(self.colHead, "bold", 1.8), + "header2" : self._makeFormat(self.colHead, "bold", 1.6), + "header3" : self._makeFormat(self.colHead, "bold", 1.4), + "header4" : self._makeFormat(self.colHead, "bold", 1.2), "header1h" : self._makeFormat(self.colHeadH, "bold", 1.8), "header2h" : self._makeFormat(self.colHeadH, "bold", 1.6), "header3h" : self._makeFormat(self.colHeadH, "bold", 1.4), "header4h" : self._makeFormat(self.colHeadH, "bold", 1.2), - "bold" : self._makeFormat(self.colEmph, "bold"), - "italic" : self._makeFormat(self.colEmph, "italic"), - "strike" : self._makeFormat(self.colEmph, "strike"), + "bold" : self._makeFormat(self.colEmph, "bold"), + "italic" : self._makeFormat(self.colEmph, "italic"), + "strike" : self._makeFormat(self.colEmph, "strike"), "trailing" : self._makeFormat(self.colTrail, "background"), "nobreak" : self._makeFormat(self.colTrail, "background"), "dialogue1" : self._makeFormat(self.colDialN), @@ -121,7 +121,7 @@ class GuiDocHighlighter(QSyntaxHighlighter): "hidden" : self._makeFormat(self.colComm), "keyword" : self._makeFormat(self.colKey), "modifier" : self._makeFormat(self.colMod), - "value" : self._makeFormat(self.colVal, "underline"), + "value" : self._makeFormat(self.colVal, "underline"), } self.hRules = [] diff --git a/nw/gui/outline.py b/nw/gui/outline.py index 039e2f3f..a359b06c 100644 --- a/nw/gui/outline.py +++ b/nw/gui/outline.py @@ -43,12 +43,12 @@ class GuiOutline(QTreeWidget): DEF_WIDTH = { nwOutline.TITLE : 200, - nwOutline.LEVEL : 40, + nwOutline.LEVEL : 40, nwOutline.LABEL : 150, - nwOutline.LINE : 40, - nwOutline.CCOUNT : 50, - nwOutline.WCOUNT : 50, - nwOutline.PCOUNT : 50, + nwOutline.LINE : 40, + nwOutline.CCOUNT : 50, + nwOutline.WCOUNT : 50, + nwOutline.PCOUNT : 50, nwOutline.POV : 100, nwOutline.CHAR : 100, nwOutline.PLOT : 100, diff --git a/nw/gui/theme.py b/nw/gui/theme.py index 3ec6d717..a368eaf6 100644 --- a/nw/gui/theme.py +++ b/nw/gui/theme.py @@ -77,11 +77,11 @@ class GuiTheme: self.themeLicenseUrl = "" ## GUI - self.treeWCount = [ 0, 0, 0] + self.treeWCount = [0, 0, 0] self.statNone = [120, 120, 120] - self.statUnsaved = [120, 120, 40] - self.statSaved = [ 40, 120, 0] - self.helpText = [ 0, 0, 0] + self.statUnsaved = [120, 120, 40] + self.statSaved = [40, 120, 0] + self.helpText = [0, 0, 0] # Loaded Syntax Settings @@ -96,21 +96,21 @@ class GuiTheme: ## Colours self.colBack = [255, 255, 255] - self.colText = [ 0, 0, 0] - self.colLink = [ 0, 0, 0] - self.colHead = [ 0, 0, 0] - self.colHeadH = [ 0, 0, 0] - self.colEmph = [ 0, 0, 0] - self.colDialN = [ 0, 0, 0] - self.colDialD = [ 0, 0, 0] - self.colDialS = [ 0, 0, 0] - self.colComm = [ 0, 0, 0] - self.colKey = [ 0, 0, 0] - self.colVal = [ 0, 0, 0] - self.colSpell = [ 0, 0, 0] - self.colTagErr = [ 0, 0, 0] - self.colRepTag = [ 0, 0, 0] - self.colMod = [ 0, 0, 0] + self.colText = [0, 0, 0] + self.colLink = [0, 0, 0] + self.colHead = [0, 0, 0] + self.colHeadH = [0, 0, 0] + self.colEmph = [0, 0, 0] + self.colDialN = [0, 0, 0] + self.colDialD = [0, 0, 0] + self.colDialS = [0, 0, 0] + self.colComm = [0, 0, 0] + self.colKey = [0, 0, 0] + self.colVal = [0, 0, 0] + self.colSpell = [0, 0, 0] + self.colTagErr = [0, 0, 0] + self.colRepTag = [0, 0, 0] + self.colMod = [0, 0, 0] # Changeable Settings self.guiTheme = None @@ -146,7 +146,7 @@ class GuiTheme: self.fontPixelSize = int(round(qMetric.height())) self.baseIconSize = int(round(qMetric.ascent())) self.textNHeight = qMetric.boundingRect("N").height() - self.textNWidth= qMetric.boundingRect("N").width() + self.textNWidth = qMetric.boundingRect("N").width() logger.verbose("GUI Font Family: %s" % self.guiFont.family()) logger.verbose("GUI Font Point Size: %.2f" % self.fontPointSize) @@ -276,13 +276,13 @@ class GuiTheme: ## Main cnfSec = "Main" if confParser.has_section(cnfSec): - self.themeName = self._parseLine( confParser, cnfSec, "name", "") - self.themeDescription = self._parseLine( confParser, cnfSec, "description", "") - self.themeAuthor = self._parseLine( confParser, cnfSec, "author", "") - self.themeCredit = self._parseLine( confParser, cnfSec, "credit", "") - self.themeUrl = self._parseLine( confParser, cnfSec, "url", "") - self.themeLicense = self._parseLine( confParser, cnfSec, "license", "") - self.themeLicenseUrl = self._parseLine( confParser, cnfSec, "licenseurl", "") + self.themeName = self._parseLine(confParser, cnfSec, "name", "") + self.themeDescription = self._parseLine(confParser, cnfSec, "description", "") + self.themeAuthor = self._parseLine(confParser, cnfSec, "author", "") + self.themeCredit = self._parseLine(confParser, cnfSec, "credit", "") + self.themeUrl = self._parseLine(confParser, cnfSec, "url", "") + self.themeLicense = self._parseLine(confParser, cnfSec, "license", "") + self.themeLicenseUrl = self._parseLine(confParser, cnfSec, "licenseurl", "") ## Palette cnfSec = "Palette" From 67ef5a89dd9d16f4d33af90829c6fd0be9921a34 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Thu, 13 Aug 2020 21:07:25 +0200 Subject: [PATCH 3/6] Removed additional spaces in enum file --- nw/constants/enum.py | 52 ++++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/nw/constants/enum.py b/nw/constants/enum.py index 68b8b173..ea40c9bf 100644 --- a/nw/constants/enum.py +++ b/nw/constants/enum.py @@ -68,32 +68,32 @@ class nwItemLayout(Enum): class nwDocAction(Enum): - NO_ACTION = 0 - UNDO = 1 - REDO = 2 - CUT = 3 - COPY = 4 - PASTE = 5 - EMPH = 6 - STRONG = 7 - STRIKE = 8 - S_QUOTE = 9 - D_QUOTE = 10 - SEL_ALL = 11 - SEL_PARA = 12 - FIND = 13 - REPLACE = 14 - GO_NEXT = 15 - GO_PREV = 16 - REPL_NEXT = 17 - BLOCK_H1 = 18 - BLOCK_H2 = 19 - BLOCK_H3 = 20 - BLOCK_H4 = 21 - BLOCK_COM = 22 - BLOCK_TXT = 23 - REPL_SNG = 24 - REPL_DBL = 25 + NO_ACTION = 0 + UNDO = 1 + REDO = 2 + CUT = 3 + COPY = 4 + PASTE = 5 + EMPH = 6 + STRONG = 7 + STRIKE = 8 + S_QUOTE = 9 + D_QUOTE = 10 + SEL_ALL = 11 + SEL_PARA = 12 + FIND = 13 + REPLACE = 14 + GO_NEXT = 15 + GO_PREV = 16 + REPL_NEXT = 17 + BLOCK_H1 = 18 + BLOCK_H2 = 19 + BLOCK_H3 = 20 + BLOCK_H4 = 21 + BLOCK_COM = 22 + BLOCK_TXT = 23 + REPL_SNG = 24 + REPL_DBL = 25 # END Enum nwDocAction From fcd2b732c36951bcb4afae9ef4e64d68169edaaa Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Thu, 13 Aug 2020 21:11:01 +0200 Subject: [PATCH 4/6] Renamed style.md file to CONTRIBUTING/md --- markdown/style.md => CONTRIBUTING.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename markdown/style.md => CONTRIBUTING.md (100%) diff --git a/markdown/style.md b/CONTRIBUTING.md similarity index 100% rename from markdown/style.md rename to CONTRIBUTING.md From 4ca2edd25fd5e0b40a6238d9953eb3b61c0ccce4 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Thu, 13 Aug 2020 21:40:02 +0200 Subject: [PATCH 5/6] Updated the contributing file --- CONTRIBUTING.md | 117 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 98 insertions(+), 19 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fd1a2d7b..283b31dd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,24 +1,103 @@ -# Code Style Guide +# Contributing -The source code of novelWriter broadly follows the style guide [PEP8](https://www.python.org/dev/peps/pep-0008/), but with a few modifications and exceptions. +When contributing to this repository, please first discuss the change you wish to make via the +issue tracker with the owner of this repository before making a change. If you just want to make a +minor correction, like fix a typo or similar, feel free to just make a pull request directly. -### Source Code Exceptions +There is a code of conduct. Please follow it in all your interactions with the project. -* Methods are camelCase, not underscore based. - The reason is partially because of the maintainers personal preference, and partially because that is what Qt5 and PyQt5 uses. - The maintainer generally, across multiple programming languages, uses underscores for defining namespaces. -* The maximum length of a code line is 99 characters, not 79. - The reason for this is that novelWriter is almost entirely made up of classes, meaning nearly all lines of code already have 8 leading spaces. - A 79 character limitation is too strict, and causes too many wrapped lines. - 99 characters is suitable for GitHub diff readability, and therefore the preferred limit. - It is also permitted under PEP8 as the maximum. - Comments and docstrings should comply with the 72 character limit. -* Aligning code with additional spaces is acceptable in those cases where it improves readability. - Otherwise, the PEP8 standard should be applied. +## Pull Request Process -### Documentation +1. Make sure your code passes all tests and conforms to the style guide. You can check that the code + conforms by running `flake8` from the root of the project folder. +2. Please provide a complete description of the changes in the pull request, and a summary that can + be copied into the [CHANGELOG](CHANGELOG.md). Remember to reference any issue related by + providing the issue number. +3. Do not change the version number unless asked to do so. Version numbers are bumped in separate + release pull requests by the maintainer. -The documentation does not adhere to the 80 character limit either. -The standard used in documentation is one line break after each sentence. -This is an alternative style that greatly improves readability of diffs as re-wrapping text is not needed when inserting new text in paragraphs. -Instead, the diff will show changes to each sentence. +## Code of Conduct + +### Our Pledge + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers +pledge to making participation in our project and our community a harassment-free experience for +everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level +of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. + +Please see the [CODE_OF_CONDUCT](CODE_OF_CONDUCT.md) file for the full text. + +## Code Style Guide + +The source code of novelWriter broadly follows the [PEP8](https://www.python.org/dev/peps/pep-0008/) +style guide , but with a few modifications and exceptions. + +### Linting with flake8 + +An excellent tool for checking Python code for errors and coding style is `flake8`. +The documentation is available [here](https://flake8.pycqa.org/en/latest/). + +The `setup.cfg` file in the root of this project has the following settings: +```conf +[flake8] +ignore = E203,E221,E226,E241,E251,E261,E266,E302,E305 +max-line-length = 99 +exclude = docs/* +``` + +The command line equivalent, with reporting, is: +```bash +flake8 . --count --ignore E203,E221,E226,E241,E251,E261,E266,E302,E305 --max-line-length=99 --show-source --statistics +``` + +Passing this check is required before contributuions are merged into the `main` branch. This is +checked automatically when you make a pull request. You can run the `flake8` command locally to +check beforehand. The full command will give you a detailed description of the code lines that do +not conform to the standard. + +## Ignored Errors + +Some errors are ignored in novelWriter, for various reasons. In addition, novelWriter sues camelCase +function and variable names due to this being the standard for the Qt libraries, and also because of +the author's personal preferences. + +The reason behind the other ignored error codes are listed below. Many of them are due to PEP8 not +permitting column alignment as opposed to many other coding styles. I find them useful in regions of +bulk value assignments. There's a reason why tables are more readable than lists. They should be +used sparingly though. + +The ignored errors are all `pycodestyle` errors, and they are documented +[here](https://pycodestyle.pycqa.org/en/latest/intro.html#error-codes). + +**E203:** whitespace before ‘:’ +**Reason:** Column alignment. It is natural to align dictionary columns along the `:` character, + +**E221:** multiple spaces before operator +**Reason:** Column alignment. + +**E226:** missing whitespace around arithmetic operator +**Reason:** This doesn't actually follow the PEP8 recommendation of grouping longer equations by +operator precedence like `2*a + 3*b` instead of `a * a + 3 * b`. Generally, don't use spaces around +`*`, `/` and `**`, but do use spaces around `+` and `-`. For appending strings, the spaces can be +dropped. Don't use the `+` operator for appending multiple strings. Use formatting instead. + +**E241:** multiple spaces after ‘,’ +**Reason:** Column alignment. + +**E251:** unexpected spaces around keyword / parameter equals +**Reason:** Column alignment. + +**E261:** at least two spaces before inline comment +**Reason:** With syntax highlighting, this one is meaningless and wastes an extra space. + +**E266:** too many leading ‘#’ for block comment +**Reason:** In the source multiple `#`s to indicate importance levels is sometimes used, like +markdown headers. + +**E302:** expected 2 blank lines, found 0 +**Reason:** Applies to classes. Instead, end classes with a comment like `# END Class ClassName` to +make it easier to se which class just ended. The double line break is then redundant. + +**E305:** expected 2 blank lines after end of function or class +**Reason:** Instead, _always_ end a function with a `return`, preferrably indented at function +level. The end of the function is then clear. From 00e321a6bffdce97e073ed8529e6dea187a7f2e9 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Thu, 13 Aug 2020 21:42:04 +0200 Subject: [PATCH 6/6] Added link to the contributing file in readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index b8a6fe5e..848bac0e 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,8 @@ is primarily saved in JSON files. The full documentation is available at [novelwriter.readthedocs.io](https://novelwriter.readthedocs.io/). +The contributing guide is available in [CONTRIBUTING](CONTRIBUTING.md). + ### Note on the Default Branch