Repository: fredrikaverpil/creosote (language: python)

Issue:
Support configuration via pyproject.toml
## Why is the change needed?
Addresses #182 .  Allows for creosote configuration via `pyproject.toml` under the `[tool.creosote]` table.

## What was done in this PR?
* `ARGS_CAN_BE_SPECIFIED_MULTIPLE_TIMES` was made into default behavior, **this means that this should be part of a `v3.0.0` release.** If we want to target a non-major release, we can revert this without too much effort (but I think v3.0.0 is the way to go).
* Each `add_argument` default was turned into a field default for the new `Config` dataclass. The diff looks big, but for each `add_argument`, only the `default` was removed. Its all added back at the end of the `parse_args` function via `parser.set_defaults(**dataclasses.asdict(defaults))`.
* On execution, `pyproject.toml` is loaded and `[tool.creosote]` is searched for. Provided parameters are loaded as CLI defaults. `pyproject.toml` keys have the same name as the `dest` variable name provided in argparse. toml file is loaded into new `Config` dataclass.  For example, the following is the relevant pyproject.toml section in one of my projects:

```toml
[tool.creosote]
venvs=[".venv"]
paths=["belay"]
deps-file="pyproject.toml"
sections=["tool.poetry.dependencies"]
exclude-deps =[
  "importlib_resources",
  "pydantic",
]
```

## Are there any concerns, side-effects, additional notes?
* README/Documentation will need to be updated.
* The feature is implemented with a simple dataclass and keyword-unpacking. If a more complicated, nested data structure is needed into the future, we should use some library (`cattrs`, `pydantic`, or `msgspec`), but the scope here is simple enough that those seem like overkill and this is simple enough. The scope of creosote also implies that this will be unnecessary.
* I didn't add any tests, tests would probably be nice.

## Checklist, when applicable

- [no] Added test(s)
- [no] Updated README.md
- [yes] Is this a backwards-compatibility breaking change?
- [yes] Resolves: #182


Discussion / hints:
I *think* the remaining linting issues are related to python3.8 vs python3.7 features. I'd recommend dropping python 3.7 support since it reached EOL in June of 2023.

I can update CI in this PR if we want to take that route.

Fix patch:
diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml
index 578e4c4..6852f1c 100644
--- a/.github/workflows/check.yml
+++ b/.github/workflows/check.yml
@@ -12,7 +12,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12-dev"]
+        python-version: ["3.8", "3.9", "3.10", "3.11", "3.12-dev"]
         os: [ubuntu-latest]
     runs-on: ${{ matrix.os }}
     steps:
@@ -31,7 +31,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12-dev"]
+        python-version: ["3.8", "3.9", "3.10", "3.11", "3.12-dev"]
         os: [ubuntu-latest]
     runs-on: ${{ matrix.os }}
     steps:
diff --git a/.python-version b/.python-version
index 548d713..cc1923a 100644
--- a/.python-version
+++ b/.python-version
@@ -1,1 +1,1 @@
-3.7
\ No newline at end of file
+3.8
diff --git a/pyproject.toml b/pyproject.toml
index cbdc253..1d0a44e 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
 name = "creosote"
 description = 'Identify unused dependencies and avoid a bloated virtual environment.'
 readme = "README.md"
-requires-python = ">=3.7"
+requires-python = ">=3.8"
 license = "MIT"
 keywords = []
 authors = [{ name = "Fredrik Averpil", email = "fredrik.averpil@gmail.com" }]
@@ -14,11 +14,11 @@ classifiers = [
   # https://pypi.org/classifiers/
   "License :: OSI Approved :: MIT License",
   "Programming Language :: Python",
-  "Programming Language :: Python :: 3.7",
   "Programming Language :: Python :: 3.8",
   "Programming Language :: Python :: 3.9",
   "Programming Language :: Python :: 3.10",
   "Programming Language :: Python :: 3.11",
+  "Programming Language :: Python :: 3.12",
   "Programming Language :: Python :: Implementation :: CPython",
   "Programming Language :: Python :: Implementation :: PyPy",
 ]
@@ -95,7 +95,7 @@ ignore = []
 ]
 
 [tool.mypy]
-python_version = "3.7"
+python_version = "3.8"
 
 [[tool.mypy.overrides]]
 module = ["dotty_dict.*", "pip_requirements_parser.*"]


Test patch:
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index e81d825..7ed5827 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -12,7 +12,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12-dev"]
+        python-version: ["3.8", "3.9", "3.10", "3.11", "3.12-dev"]
         os: [ubuntu-latest, windows-latest, macos-latest]
     runs-on: ${{ matrix.os }}
     steps:
@@ -55,7 +55,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12-dev"]
+        python-version: ["3.8", "3.9", "3.10", "3.11", "3.12-dev"]
         os: [ubuntu-latest, windows-latest, macos-latest]
     runs-on: ${{ matrix.os }}
     steps:
diff --git a/tests/deps_files/Pipfile b/tests/deps_files/Pipfile
index b1057f3..a9d0f8a 100644
--- a/tests/deps_files/Pipfile
+++ b/tests/deps_files/Pipfile
@@ -12,4 +12,4 @@ toml = ">=0.10.2,<0.11"
 pytest = "*"
 
 [requires]
-python_version = "3.11"
+python_version = "3.8"
diff --git a/tests/deps_files/pyproject.pep621.toml b/tests/deps_files/pyproject.pep621.toml
index 17d1bfb..8623741 100644
--- a/tests/deps_files/pyproject.pep621.toml
+++ b/tests/deps_files/pyproject.pep621.toml
@@ -2,7 +2,7 @@
 name = "creosote"
 version = "0.0.1"
 description = 'This file is only used for testing with creosote.'
-requires-python = ">=3.7"
+requires-python = ">=3.8"
 license = "MIT"
 keywords = []
 authors = []
diff --git a/tests/deps_files/pyproject.poetry.toml b/tests/deps_files/pyproject.poetry.toml
index cc62dc8..5dad9fb 100644
--- a/tests/deps_files/pyproject.poetry.toml
+++ b/tests/deps_files/pyproject.poetry.toml
@@ -9,7 +9,7 @@ description = "This file is only used for testing with creosote."
 authors = []
 
 [tool.poetry.dependencies]
-python = ">=3.7, <3.12"
+python = ">=3.8, <3.12"
 dotty-dict = "^1.3.1"
 loguru = "^0.6.0"
 toml = "^0.10.2"
@@ -24,4 +24,3 @@ types-toml = "*"
 
 [tool.poetry.group.directrefs.dependencies]
 typing_extensions = { git = "https://github.com/python/typing_extensions.git", branch = "main" }
-
diff --git a/tests/fixtures/fast.py b/tests/fixtures/fast.py
index 3ee698d..9a0e05e 100644
--- a/tests/fixtures/fast.py
+++ b/tests/fixtures/fast.py
@@ -37,7 +37,7 @@ def _(dependency_names: List[str]):
 @pytest.fixture()
 def create_venv(tmp_path: Path) -> Generator[Tuple[Path, Path], None, None]:
     venv_path = tmp_path / "venv"
-    site_packages_path = venv_path / "lib" / "python3.7" / "site-packages"
+    site_packages_path = venv_path / "lib" / "python3.8" / "site-packages"
     site_packages_path.mkdir(parents=True)
     yield venv_path, site_packages_path