Picking out a Formatter and Linter for my Open Source Project
Tags: python, opensource, beginners, tutorial
Published: 2023-11-03 01:13:37

Hey everyone, I recently had the chance to install a linter and formatter for my [TXT to HTML Converter](https://github.com/Pasqua101/txt-to-HTML-converter) program. For formatting I went with [Black](https://pypi.org/project/black/) and for linting, I chose [Ruff](https://docs.astral.sh/ruff/). I'll talk about why I chose them, how they work, and what changes they made to my code below.

#### What is Black?
[Black](https://pypi.org/project/black/) is a Python code formatter that will format your code on the fly to match the code style set by the developers. For example, if a line of code is too long, Black will split it up into 2 or more lines for readability. If there are several arguments in a function, Black will also split that up into 2 or more lines. I chose Black, as I liked its code style and the way I can configure it. It was also a project I stumbled across during [Hacktoberfest](https://hacktoberfest.com/), but since I never used the formatter before I didn't really know how it works so I wouldn't be able to contribute to issues as easily. So I figured I should learn it now, and maybe contribute to it in the future.

#### What is Ruff?
[Ruff](https://docs.astral.sh/ruff/) is both a formatter and linter written in Rust that promises to be faster than alternative Python linters out there. Now, you may be thinking to yourself, why not chose Ruff for both linting and formatting? It would make things much easier. Well, I mainly chose for Ruff to be just a linter, as like I said above, I wanted to learn how Black works and try to contribute to it in the future. I can also do the same with Ruff, if I learn how their linter works, I can technically learn how two open source projects work and try to contribute to them both. Additionally, Ruff provides the same method for configuration as Black, which is another benefit I'll talk about later.

#### How was Black and Ruff set up?
Both Black and Ruff had very simple installation processes. I'll talk about how I set them up for Windows running PyCharm as my IDE.

##### Black:
To install Black, all I had to was type `pip install black` into my terminal. Black is designed to run on Python 3.8 or newer, and since I'm running my project with Python 3.11.4, it had no problem installing. What was nice about Black is that it worked straight after downloading, there was no setup involved. I could type `black  .` into my terminal and have it format all of my Python files immediately. However, there were some files I did not want it to format, specifically a Python file I'm using for reading a Dictionary from for a sidebar feature I'm developing. So while I could run `black file1.py file2.py file3.py`. I would rather configure it to ignore one file and format the rest with `black .` instead. Here's how I did it. To [configure Black](https://black.readthedocs.io/en/stable/usage_and_configuration/the_basics.html#configuration-via-a-file) you have to create a pyproject.toml file. From there you have to specify the tool that reads configuration, and then tell the tool what to exclude by using regex. Like the example I made below 
``` TOML
[tool.black]

extend-exclude = '^/sidebar.py'
```
Since I was using PyCharm as my IDE, Black added itself as a tool without me having to do anything. This gave me the option to configure my IDE to use Black when I save the file or reformat it, which I took advantage of. Since it saves me time from typing it into my terminal. To change the settings for Black on PyCharm, I had to go to `Preferences or Settings -> Tools -> Black`. That's pretty much it for the set up process, it was quick and easy and Ruff was about the same.


##### Ruff:
Setting up Ruff was roughly the same as Black. I had to paste this line of code `pip install ruff` into PowerShell. Then once it installed I could use it without having to configure anything, which is something I appreciated. Before I got to using it, I had to configure it. Just like Black, Ruff also uses a pyproject.toml file for configuration. So I was able to use the same configuration file for Black with Ruff. All I had to do was specify that Ruff will be reading the information after a certain line. With the configuration I was able to tell Ruff what kind of code style it should look for, what warnings it should ignore and what to exclude from linting. You can see the configuration I used for Ruff below, which I was able to put right under the configuration for Black.
```TOML
[tool.ruff.lint]
select = [
  # pycodestyle
  "E",
  # Pyflakes
  "F",
  # pyupgrade
  "UP",
  # flake8-bugbear
  "B",
  # flake8-simplify
  "SIM",
  # isort
  "I",
]
# Asking ruff to ignore the number of characters per line. PyCharm IDE already takes care of it.
ignore = ["E501"]
#Exclude certain files and folders from linting
exclude = [
    ".git",
    ".examples",
    ".app",
    "sidebar.py",
    "til",
    ".ruff_cache",
]
```
Originally, I did not have the ignore there, but I'll talk about why I used it later. Unlike Black, Ruff was not already added as a tool to PyCharm. There is a way to add it as an [external tool](https://docs.astral.sh/ruff/integrations/#pycharm-external-tool), but it didn't work for me. Thankfully, there on Ruff's website they mentioned a member in the community who created a [PyCharm plugin](https://plugins.jetbrains.com/plugin/20574-ruff) for Ruff and according to reviews they commonly updates it. So it was something I could rely on. Downloading the plugin was really simple, I just had to go to `Preferences or Settings -> Plugins` and search for Ruff on PyCharm. I found it and download it to my IDE. Then to configure it I had to go to `Preferences or Settings -> Tools -> Ruff`. Doing this greeted me to very similar option that Black had, I could run Ruff when I saved the file or reformatted it. Since I'm using Black for formatting, I made sure to configure the Ruff plugin to not be used when reformatting. If you did want to run Ruff on the terminal you could just type `ruff check .` to lint all the files in the current directory. If Ruff finds any issues, you could have it attempt to fix them by using `ruff check . --fix`. Ruff also has some [other linting options](https://docs.astral.sh/ruff/linter/) you can use to help out. That was pretty much it.

#### What did Black and Ruff Find and Change in my Code and How Did I Use Them?

Black:
When I used Black, I first tried it out from by using this line of code `black  .` on PowerShell, after I configured it to ignored one of my files. Black found out that a lot of my lines were too long for the Python standard. This is something that I kind of knew, since PyCharm makes highlights this issue for me. I mainly do on all my programming on a monitor that is connected to my laptop. So I tend to write longer lines of code. However, if I drag the IDE window to my laptop's display, it can be harder to read some of the lines of code. So, Black fixed that for me. I also noticed that with some lines where I do string concatenation Black split up each part of the string on separate lines. I didn't mind it, as it felt like my code looked a little neater and easier to read. The easy to read part is something I strive for with my code, so I was thankful for it. When I integrated Black into my IDE with the steps I mentioned above, I also tested it make sure it was working by handing it an unformatted line of code, which it fixed.

Ruff:
Just like Black, I used Ruff on PowerShell first with the command `ruff check .` to lint my files, I of course did this after I configured Ruff. Ruff seemed to think that some of line of code and comments were still to long, which was something that PyCharm was also suggesting to me. Before I tried fixing it myself I did try to use `ruff check . --fix`, and it was able to fix a handful of the 20+ problems it found. It was helpful, but I had to go fix some by hand, and thankfully my IDE provided me suggestions on how to change my lines of code, which I let it do for me. However, a lot of the lines seemed both fine to me and my IDE, which was when I configured Ruff to `ignore = ["E501"]` (it's a rule that states how many characters long my lines should be). PyCharm already seems to handle part of this for me, and if I did want to check with Ruff I can always uncomment the line. One other issue, Ruff picked up was that I was importing everything (*) from my helper.py file into my file_processors.py file. I didn't really see an issue with this until I realized I had a function from helpers.py that was not used in the file_processors.py, that function being the one that handles sidebar creation. Realizing that I did not need to import a function that would not be used in file_processors.py I changed up my import for the helper.py file to import only the functions I need, which I then formatted with Black. I also tried out the Ruff extension on my code and it worked just fine.


#### What did I learn?
Other than the fact that I got to learn how to use a very helpful formatter and linter, I also got to learn a little more about the proper way to style my code in Python since I feel like my code is now a look more easier to read and digest. Which should make future revisions easier not just for me, but anyone else modifying my code.

That concludes this post. Thank you all for reading, and I hope you found my little setup tutorial helpful! Catch you in the next post!