Lab7: Format and Lint
Tags: beginners, opensource, python
Published: 2022-11-05 02:50:20

## Linting and Formatting

This week we were told to add a linter and formatter to our projects for our respective language and a CONTRIBUTING.md to get people set up and ready to develop using the same tools. 

My language I am using for my project is Python so the two tools that I decided to implement were [**black**](https://pypi.org/project/black/) and [**pylint**](https://www.pylint.org)

## Problems early on

I have been using my computer for a long time, I have many versions of python on it. I have not ever used a pip dependency before and I found that they were installing but not working since they weren't on my path env variable. I realized after looking at the source of my version of python I was using that I was actually still using the one off of the Microsoft store I installed a long time ago. I figured this was a part of the problem so I uninstalled it and reinstalled the newest version of Python I could find 3.11 and am using that now. I installed black afterwards and it worked.

All I have to do is write `black <target file>` in cli and it formats it. In contributing mark down I also added a config to make it format on save for vscode/settings.json.

Before black:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7wcknjbyfxz9bmopscf9.png)


After black:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m59lod1px0q8mii3nfg0.png)



## Problems later on

I got pylint to work pretty quickly with a simple pip install, the problem was my code was evidently abysmal. This was my first result when running it:
```
************* Module main
src\main.py:40:0: C0301: Line too long (367/100) (line-too-long)
src\main.py:1:0: C0114: Missing module docstring (missing-module-docstring)
src\main.py:1:0: C0410: Multiple imports on one line (sys, getopt, os, shutil) (multiple-imports)
src\main.py:6:0: C0116: Missing function or method docstring (missing-function-docstring)
src\main.py:30:16: W0622: Redefining built-in 'input' (redefined-builtin)
src\main.py:18:4: C0103: Variable name "configExists" doesn't conform to snake_case naming style (invalid-name)
src\main.py:23:12: C0103: Variable name "configExists" doesn't conform to snake_case naming style (invalid-name)
src\main.py:28:12: C0103: Variable name "configOpts" doesn't conform to snake_case naming style (invalid-name)
src\main.py:48:8: C0103: Variable name "superSiteJen" doesn't conform to snake_case naming style (invalid-name)
src\main.py:50:8: C0103: Variable name "superSiteJen" doesn't conform to snake_case naming style (invalid-name)
src\main.py:6:0: R0912: Too many branches (19/12) (too-many-branches)
src\main.py:11:14: W0641: Possibly unused variable 'args' (possibly-unused-variable)
src\main.py:3:0: C0411: standard import "from os.path import isdir" should be placed before "from SSJ import SSJ" (wrong-import-order)  
************* Module SSJ
src\SSJ.py:16:33: W1401: Anomalous backslash in string: '\s'. String constant might be missing an r prefix. (anomalous-backslash-in-string)
src\SSJ.py:16:40: W1401: Anomalous backslash in string: '\s'. String constant might be missing an r prefix. (anomalous-backslash-in-string)
src\SSJ.py:210:38: W1401: Anomalous backslash in string: '\*'. String constant might be missing an r prefix. (anomalous-backslash-in-string)
src\SSJ.py:210:40: W1401: Anomalous backslash in string: '\*'. String constant might be missing an r prefix. (anomalous-backslash-in-string)
src\SSJ.py:210:47: W1401: Anomalous backslash in string: '\*'. String constant might be missing an r prefix. (anomalous-backslash-in-string)
src\SSJ.py:210:49: W1401: Anomalous backslash in string: '\*'. String constant might be missing an r prefix. (anomalous-backslash-in-string)
src\SSJ.py:213:38: W1401: Anomalous backslash in string: '\*'. String constant might be missing an r prefix. (anomalous-backslash-in-string)
src\SSJ.py:213:45: W1401: Anomalous backslash in string: '\*'. String constant might be missing an r prefix. (anomalous-backslash-in-string)
src\SSJ.py:216:38: W1401: Anomalous backslash in string: '\`'. String constant might be missing an r prefix. (anomalous-backslash-in-string)
src\SSJ.py:216:40: W1401: Anomalous backslash in string: '\`'. String constant might be missing an r prefix. (anomalous-backslash-in-string)
src\SSJ.py:216:42: W1401: Anomalous backslash in string: '\`'. String constant might be missing an r prefix. (anomalous-backslash-in-string)
src\SSJ.py:216:49: W1401: Anomalous backslash in string: '\`'. String constant might be missing an r prefix. (anomalous-backslash-in-string)
src\SSJ.py:216:51: W1401: Anomalous backslash in string: '\`'. String constant might be missing an r prefix. (anomalous-backslash-in-string)
src\SSJ.py:216:53: W1401: Anomalous backslash in string: '\`'. String constant might be missing an r prefix. (anomalous-backslash-in-string)
src\SSJ.py:217:38: W1401: Anomalous backslash in string: '\`'. String constant might be missing an r prefix. (anomalous-backslash-in-string)
src\SSJ.py:217:45: W1401: Anomalous backslash in string: '\`'. String constant might be missing an r prefix. (anomalous-backslash-in-string)
src\SSJ.py:219:38: W1401: Anomalous backslash in string: '\-'. String constant might be missing an r prefix. (anomalous-backslash-in-string)
src\SSJ.py:219:40: W1401: Anomalous backslash in string: '\-'. String constant might be missing an r prefix. (anomalous-backslash-in-string)
src\SSJ.py:219:42: W1401: Anomalous backslash in string: '\-'. String constant might be missing an r prefix. (anomalous-backslash-in-string)
src\SSJ.py:1:0: C0114: Missing module docstring (missing-module-docstring)
src\SSJ.py:1:0: C0103: Module name "SSJ" doesn't conform to snake_case naming style (invalid-name)
src\SSJ.py:4:0: C0410: Multiple imports on one line (re, json) (multiple-imports)
src\SSJ.py:7:0: C0115: Missing class docstring (missing-class-docstring)
src\SSJ.py:25:23: W0622: Redefining built-in 'input' (redefined-builtin)
src\SSJ.py:34:4: C0116: Missing function or method docstring (missing-function-docstring)
src\SSJ.py:34:4: C0103: Method name "parseFile" doesn't conform to snake_case naming style (invalid-name)
src\SSJ.py:34:24: C0103: Argument name "inputFile" doesn't conform to snake_case naming style (invalid-name)
src\SSJ.py:34:35: C0103: Argument name "inputFolder" doesn't conform to snake_case naming style (invalid-name)
src\SSJ.py:36:8: C0103: Variable name "titleStorage" doesn't conform to snake_case naming style (invalid-name)
src\SSJ.py:37:8: C0103: Variable name "titleQuestionMark" doesn't conform to snake_case naming style (invalid-name)
src\SSJ.py:46:12: C0103: Variable name "Lines" doesn't conform to snake_case naming style (invalid-name)
src\SSJ.py:50:20: C0103: Variable name "titleStorage" doesn't conform to snake_case naming style (invalid-name)
src\SSJ.py:53:24: C0103: Variable name "titleQuestionMark" doesn't conform to snake_case naming style (invalid-name)
src\SSJ.py:54:24: C0103: Variable name "newLine" doesn't conform to snake_case naming style (invalid-name)
src\SSJ.py:60:24: C0103: Variable name "newLine" doesn't conform to snake_case naming style (invalid-name)
src\SSJ.py:68:24: C0103: Variable name "titleQuestionMark" doesn't conform to snake_case naming style (invalid-name)
src\SSJ.py:69:24: C0103: Variable name "newLine" doesn't conform to snake_case naming style (invalid-name)
src\SSJ.py:75:24: C0103: Variable name "newLine" doesn't conform to snake_case naming style (invalid-name)
src\SSJ.py:82:23: C0121: Comparison 'titleQuestionMark == True' should be 'titleQuestionMark is True' if checking for the singleton value True, or 'titleQuestionMark' if testing for truthiness (singleton-comparison)
src\SSJ.py:83:24: C0103: Variable name "newLine" doesn't conform to snake_case naming style (invalid-name)
src\SSJ.py:89:24: C0103: Variable name "newLine" doesn't conform to snake_case naming style (invalid-name)
src\SSJ.py:97:24: C0103: Variable name "newLine" doesn't conform to snake_case naming style (invalid-name)
src\SSJ.py:104:24: C0103: Variable name "newLine" doesn't conform to snake_case naming style (invalid-name)
src\SSJ.py:111:12: C0103: Variable name "outputName" doesn't conform to snake_case naming style (invalid-name)
src\SSJ.py:116:8: C0103: Variable name "e" doesn't conform to snake_case naming style (invalid-name)
src\SSJ.py:44:23: R1732: Consider using 'with' for resource-allocating operations (consider-using-with)
src\SSJ.py:34:4: R0912: Too many branches (13/12) (too-many-branches)
src\SSJ.py:119:4: C0116: Missing function or method docstring (missing-function-docstring)
src\SSJ.py:119:4: C0103: Method name "writeOut" doesn't conform to snake_case naming style (invalid-name)
src\SSJ.py:122:16: C0103: Variable name "fileOut" doesn't conform to snake_case naming style (invalid-name)
src\SSJ.py:124:12: C0103: Variable name "tempTemp" doesn't conform to snake_case naming style (invalid-name)
src\SSJ.py:122:26: R1732: Consider using 'with' for resource-allocating operations (consider-using-with)
src\SSJ.py:140:4: C0116: Missing function or method docstring (missing-function-docstring)
src\SSJ.py:140:4: C0103: Method name "parseDir" doesn't conform to snake_case naming style (invalid-name)
src\SSJ.py:140:23: W0622: Redefining built-in 'input' (redefined-builtin)
src\SSJ.py:141:8: C0103: Variable name "inputFolder" doesn't conform to snake_case naming style (invalid-name)
src\SSJ.py:156:16: C0103: Variable name "outputName" doesn't conform to snake_case naming style (invalid-name)
src\SSJ.py:157:16: C0103: Variable name "hrefName" doesn't conform to snake_case naming style (invalid-name)
src\SSJ.py:163:22: C0209: Formatting a regular string which could be a f-string (consider-using-f-string)
src\SSJ.py:173:16: C0103: Variable name "fileOut" doesn't conform to snake_case naming style (invalid-name)
src\SSJ.py:173:26: R1732: Consider using 'with' for resource-allocating operations (consider-using-with)
src\SSJ.py:149:8: W0612: Unused variable 'temp' (unused-variable)
src\SSJ.py:180:4: C0116: Missing function or method docstring (missing-function-docstring)
src\SSJ.py:180:4: C0103: Method name "markdownSearch" doesn't conform to snake_case naming style (invalid-name)
src\SSJ.py:180:30: C0103: Argument name "indChars" doesn't conform to snake_case naming style (invalid-name)
src\SSJ.py:180:4: E0213: Method 'markdownSearch' should have "self" as first argument (no-self-argument)
src\SSJ.py:181:8: C0103: Variable name "newLine" doesn't conform to snake_case naming style (invalid-name)
src\SSJ.py:183:14: C0121: Comparison 'match != None' should be 'match is not None' (singleton-comparison)
src\SSJ.py:185:16: C0103: Variable name "newLine" doesn't conform to snake_case naming style (invalid-name)
src\SSJ.py:193:16: C0103: Variable name "newLine" doesn't conform to snake_case naming style (invalid-name)
src\SSJ.py:207:4: C0116: Missing function or method docstring (missing-function-docstring)
src\SSJ.py:207:4: C0103: Method name "convertMarkdown" doesn't conform to snake_case naming style (invalid-name)
src\SSJ.py:207:4: E0213: Method 'convertMarkdown' should have "self" as first argument (no-self-argument)
src\SSJ.py:208:8: C0103: Variable name "newLine" doesn't conform to snake_case naming style (invalid-name)
src\SSJ.py:210:8: C0103: Variable name "newLine" doesn't conform to snake_case naming style (invalid-name)
src\SSJ.py:211:8: C0103: Variable name "newLine" doesn't conform to snake_case naming style (invalid-name)
src\SSJ.py:213:8: C0103: Variable name "newLine" doesn't conform to snake_case naming style (invalid-name)
src\SSJ.py:214:8: C0103: Variable name "newLine" doesn't conform to snake_case naming style (invalid-name)
src\SSJ.py:216:8: C0103: Variable name "newLine" doesn't conform to snake_case naming style (invalid-name)
src\SSJ.py:217:8: C0103: Variable name "newLine" doesn't conform to snake_case naming style (invalid-name)
src\SSJ.py:219:8: C0103: Variable name "newLine" doesn't conform to snake_case naming style (invalid-name)
src\SSJ.py:223:4: C0116: Missing function or method docstring (missing-function-docstring)
src\SSJ.py:223:4: C0103: Method name "parseConfig" doesn't conform to snake_case naming style (invalid-name)
src\SSJ.py:223:26: C0103: Argument name "configFile" doesn't conform to snake_case naming style (invalid-name)
src\SSJ.py:224:13: W1514: Using open without explicitly specifying an encoding (unspecified-encoding)
src\SSJ.py:228:8: C0103: Variable name "arrOfStr" doesn't conform to snake_case naming style (invalid-name)

-----------------------------------
Your code has been rated at 3.99/10
```

After a few hours of replacing camel case with snake case this is what I get:

```
************* Module main
src\main.py:11:0: R0912: Too many branches (19/12) (too-many-branches)
src\main.py:17:14: W0641: Possibly unused variable 'args' (possibly-unused-variable)
************* Module ssj
src\ssj.py:38:4: R0912: Too many branches (13/12) (too-many-branches)

------------------------------------------------------------------
Your code has been rated at 9.84/10 (previous run: 9.78/10, +0.05)
```

I know it is not perfect but these issues are quite significantly more difficult for me to figure out, I will continue working on these and see if they are possible to fix in the future. Even so it is a big jump and a lot of changes already, for example I learned that when working with files the keyword 'with' and they keyword 'as' can make code neater in modern python. That's pretty cool. I also learned that in evaluating conditionals against Boolean values I should use the formulations `is` and `is not` instead of equality operators.


## Concluding

To round out this weeks work I added some instructions in the Contributing markdown to get the pylint to be integrated into vscode and I squashed and rebased my code then merged from my feature branch back to main and pushed it up to my remote origin.

Linting and Formatting commit: [9152894](https://github.com/sfrunza13/SiteGenerationTool/commit/9152894bdb59da1c0558062f76d678a85d2e62c3)