Repository: NREL/hive (language: python)

Issue:
Experiment with pre-commit hooks to run black and ruff
It might be beneficial to run black automatically with a pre-commit hook to catch black errors.


Discussion / hints:
from @machallboyd:

- define what the project's sorting conventions, linting conventions etc in pyproject.toml
- Set up precommit hooks so git will run those tools before a commit to format the code for you
- Have the changes take place automatically whenever someone edits a file for a commit
I would advocate adding [ruff](https://github.com/charliermarsh/ruff) for our linting. 
Based on running ruff over the current codebase, we're touching almost all the files and so we should postpone doing this until we have a lull in PRs
I think it's actually a good reason to go ahead with it now. The beauty of doing this as a pre-commit hook will be that only files involved in people's PR will be changed by `ruff` and `black`, so the changes occur gradually.
To clarify, black and ruff as precommits wouldn't just be catching errors, they would be fixing the errors for you
Doing some experiments with this in `pyproject.toml`

```
[tool.black]
line-length = 100

[tool.ruff]
line-length = 100
```

Obnoxiously, `black` seems to consider this line to be 92 characters long and thus safe.

```
                    [len(v.vehicle_state.trip_plan) for v in veh_dispatch_pooling_in_fleet]  # type: ignore
```

Ruff, however, considers the inline comment `# type: ignore` to be part of the line, and yells about it, while black ignores comments. (This comment is there to tell `mypy` to ignore the line for type checking purposes)

```
nrel/hive/reporting/handler/time_step_stats_handler.py:321:101: E501 Line too long (107 > 100 characters)
```



Fix patch:
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
new file mode 100644
index 00000000..36ae71df
--- /dev/null
+++ b/.pre-commit-config.yaml
@@ -0,0 +1,16 @@
+repos:
+-   repo: https://github.com/pre-commit/pre-commit-hooks
+    rev: v2.3.0
+    hooks:
+    -   id: check-yaml
+    -   id: end-of-file-fixer
+    -   id: trailing-whitespace
+-   repo: https://github.com/psf/black
+    rev: 23.1.0
+    hooks:
+    -   id: black
+- repo: https://github.com/charliermarsh/ruff-pre-commit
+  # Ruff version.
+  rev: 'v0.0.263'
+  hooks:
+    - id: ruff
diff --git a/docs/source/developer/contributing.md b/docs/source/developer/contributing.md
index bf291ae6..2233acb8 100644
--- a/docs/source/developer/contributing.md
+++ b/docs/source/developer/contributing.md
@@ -27,6 +27,12 @@ This simple guide will walk you through the process of contributing to HIVE.
 1. Click on the "Fork" button in the upper right corner. This creates a copy of the repository under your GitHub account.
 1. Clone your forked repository to your local machine by clicking the "Code" button and copying the URL. Then, open your terminal or command prompt and run git clone [URL], replacing [URL] with the copied URL.
 
+## Installing the development environment
+
+1. Create and activate a new virtual environment with the tool of your choice (e.g. `venv`, `conda`, `pipenv`, etc.).
+1. Install the package and dependencies by running `pip install -e ".[dev]"`. This will install the package in editable mode, so you can make changes to the code and see them reflected in your environment.
+1. Install the pre-commit hook by running `pre-commit install`. This will run the pre-commit checks before each commit, and will prevent you from committing code that doesn't pass the checks.
+
 ## Opening a Pull Request
 
 1. Create a new branch in your local repository by running git checkout -b [branch-name], replacing [branch-name] with a descriptive name for your changes.
diff --git a/pyproject.toml b/pyproject.toml
index a9f333b2..37abdd74 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -50,6 +50,7 @@ dev = [
     "twine",
     "types-PyYAML",
     "types-setuptools",
+    "pre-commit",
 ]
 
 [project.urls]
@@ -62,10 +63,13 @@ hive-batch = "nrel.hive.app.run_batch:run"
 [tool.black]
 line-length = 100
 
+[tool.ruff]
+line-length = 100
+
 [tool.setuptools.packages.find]
 where = ["."]  # list of folders that contain the packages (["."] by default)
 include = ["nrel*"]  # package names should match these glob patterns (["*"] by default)
-exclude = ["rust*"] 
+exclude = ["rust*"]
 
 [tool.setuptools.package-data]
-"*" = ["py.typed"]
\ No newline at end of file
+"*" = ["py.typed"]


Test patch:
diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml
index dd4a4676..f6065ac9 100644
--- a/.github/workflows/tests.yaml
+++ b/.github/workflows/tests.yaml
@@ -1,4 +1,4 @@
-name: tests 
+name: tests
 
 on:
   push:
@@ -26,21 +26,25 @@ jobs:
         with:
           python-version: ${{ matrix.python-version }}
 
-      - name: Install package 
+      - name: Install package
         run: |
-          pip install ".[dev]" 
+          pip install ".[dev]"
 
       - name: Run mypy
-        run: mypy . --ignore-missing-imports 
+        run: mypy . --ignore-missing-imports
 
       - name: Run black
         run: |
           black nrel tests --check
 
-      - name: Python unit tests 
+      # Once all files have passed through pre-commit, the black check can be replaced by pre-commit:
+      # - name: Run pre-commit in CI
+      #   uses: pre-commit/action@v3.0.0
+
+      - name: Python unit tests
         run: |
-          pytest tests/ -v 
-      
+          pytest tests/ -v
+
       - name: HIVE Denver Demo test
         run: |
           hive denver_demo.yaml