Skip to content

Commit 492cff6

Browse files
committedOct 26, 2022
chore: Template upgrade
1 parent 9b9b3fc commit 492cff6

18 files changed

+335
-176
lines changed
 

‎.copier-answers.yml

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
# Changes here will be overwritten by Copier
2-
_commit: 0.4.4
2+
_commit: 0.10.2
33
_src_path: gh:pawamoy/copier-pdm
44
author_email: pawamoy@pm.me
5-
author_fullname: "Timoth\xE9e Mazzucotelli"
5+
author_fullname: Timothée Mazzucotelli
66
author_username: pawamoy
77
copyright_date: '2020'
8-
copyright_holder: "Timoth\xE9e Mazzucotelli"
8+
copyright_holder: Timothée Mazzucotelli
99
copyright_holder_email: pawamoy@pm.me
1010
copyright_license: ISC License
1111
project_description: Automatic Changelog generator using Jinja2 templates.
@@ -17,3 +17,4 @@ repository_name: git-changelog
1717
repository_namespace: pawamoy
1818
repository_provider: github.com
1919
use_precommit: false
20+

‎.github/FUNDING.yml

+2-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
11
github:
2-
- pawamoy
3-
ko_fi: pawamoy
4-
liberapay: pawamoy
5-
patreon: pawamoy
2+
- pawamoy
63
custom:
7-
- https://www.paypal.me/pawamoy
4+
- https://www.paypal.me/pawamoy

‎.github/workflows/ci.yml

+7-8
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ jobs:
2828
uses: actions/checkout@v2
2929

3030
- name: Set up PDM
31-
uses: pdm-project/setup-pdm@v2.5
31+
uses: pdm-project/setup-pdm@v2.6
3232
with:
3333
python-version: "3.8"
3434

@@ -50,15 +50,13 @@ jobs:
5050
run: pdm lock
5151

5252
- name: Install dependencies
53-
run: |
54-
pdm install -G duty -G docs -G quality -G typing
55-
pip install safety
53+
run: pdm install -G duty -G docs -G quality -G typing -G security
5654

5755
- name: Check if the documentation builds correctly
5856
run: pdm run duty check-docs
5957

6058
- name: Check the code quality
61-
run: pdm run duty check-code-quality
59+
run: pdm run duty check-quality
6260

6361
- name: Check if the code is correctly typed
6462
run: pdm run duty check-types
@@ -75,10 +73,11 @@ jobs:
7573
- macos-latest
7674
- windows-latest
7775
python-version:
78-
- "3.6"
7976
- "3.7"
8077
- "3.8"
8178
- "3.9"
79+
- "3.10"
80+
- "3.11-dev"
8281

8382
runs-on: ${{ matrix.os }}
8483

@@ -87,7 +86,7 @@ jobs:
8786
uses: actions/checkout@v2
8887

8988
- name: Set up PDM
90-
uses: pdm-project/setup-pdm@v2.5
89+
uses: pdm-project/setup-pdm@v2.6
9190
with:
9291
python-version: ${{ matrix.python-version }}
9392

@@ -106,7 +105,7 @@ jobs:
106105
key: tests-cache-${{ runner.os }}-${{ matrix.python-version }}
107106

108107
- name: Install dependencies
109-
run: pdm install -G duty -G tests
108+
run: pdm install --no-editable -G duty -G tests
110109

111110
- name: Run the test suite
112111
run: pdm run duty test

‎.gitpod.dockerfile

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
FROM gitpod/workspace-full
2+
USER gitpod
3+
ENV PIP_USER=no
4+
ENV PYTHON_VERSIONS=
5+
RUN pip3 install pipx; \
6+
pipx install pdm; \
7+
pipx ensurepath

‎.gitpod.yml

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
vscode:
2+
extensions:
3+
- ms-python.python
4+
5+
image:
6+
file: .gitpod.dockerfile
7+
8+
ports:
9+
- port: 8000
10+
onOpen: notify
11+
12+
tasks:
13+
- init: make setup

‎CONTRIBUTING.md

+18-21
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,21 @@ cd git-changelog
1414
make setup
1515
```
1616

17-
!!! note
18-
If it fails for some reason,
19-
you'll need to install
20-
[PDM](https://github.com/pdm-project/pdm)
21-
manually.
22-
23-
You can install it with:
24-
25-
```bash
26-
python3 -m pip install --user pipx
27-
pipx install pdm
28-
```
29-
30-
Now you can try running `make setup` again,
31-
or simply `pdm install`.
17+
> NOTE:
18+
> If it fails for some reason,
19+
> you'll need to install
20+
> [PDM](https://github.com/pdm-project/pdm)
21+
> manually.
22+
>
23+
> You can install it with:
24+
>
25+
> ```bash
26+
> python3 -m pip install --user pipx
27+
> pipx install pdm
28+
> ```
29+
>
30+
> Now you can try running `make setup` again,
31+
> or simply `pdm install`.
3232
3333
You now have the dependencies installed.
3434
@@ -57,17 +57,14 @@ As usual:
5757
1. create a new branch: `git checkout -b feature-or-bugfix-name`
5858
1. edit the code and/or the documentation
5959
60-
If you updated the documentation or the project dependencies:
61-
62-
1. run `make docs-regen`
63-
1. run `make docs-serve`,
64-
go to http://localhost:8000 and check that everything looks good
65-
6660
**Before committing:**
6761
6862
1. run `make format` to auto-format the code
6963
1. run `make check` to check everything (fix any warning)
7064
1. run `make test` to run the tests (fix any issue)
65+
1. if you updated the documentation or the project dependencies:
66+
1. run `make docs-serve`
67+
1. go to http://localhost:8000 and check that everything looks good
7168
1. follow our [commit message convention](#commit-message-convention)
7269
7370
If you are unsure about how to fix or ignore a warning,

‎Makefile

+12-4
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@ SHELL := bash
44
DUTY = $(shell [ -n "${VIRTUAL_ENV}" ] || echo pdm run) duty
55

66
args = $(foreach a,$($(subst -,_,$1)_args),$(if $(value $a),$a="$($a)"))
7-
check_code_quality_args = files
7+
check_quality_args = files
88
docs_serve_args = host port
99
release_args = version
1010
test_args = match
1111

1212
BASIC_DUTIES = \
1313
changelog \
14+
check-dependencies \
1415
clean \
1516
coverage \
1617
docs \
@@ -21,9 +22,7 @@ BASIC_DUTIES = \
2122
release
2223

2324
QUALITY_DUTIES = \
24-
check \
25-
check-code-quality \
26-
check-dependencies \
25+
check-quality \
2726
check-docs \
2827
check-types \
2928
test
@@ -32,10 +31,19 @@ QUALITY_DUTIES = \
3231
help:
3332
@$(DUTY) --list
3433

34+
.PHONY: lock
35+
lock:
36+
@pdm lock
37+
3538
.PHONY: setup
3639
setup:
3740
@bash scripts/setup.sh
3841

42+
.PHONY: check
43+
check:
44+
@bash scripts/multirun.sh duty check-quality check-types check-docs
45+
@$(DUTY) check-dependencies
46+
3947
.PHONY: $(BASIC_DUTIES)
4048
$(BASIC_DUTIES):
4149
@$(DUTY) $@ $(call args,$@)

‎README.md

+4-28
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
[![ci](https://github.com/pawamoy/git-changelog/workflows/ci/badge.svg)](https://github.com/pawamoy/git-changelog/actions?query=workflow%3Aci)
44
[![documentation](https://img.shields.io/badge/docs-mkdocs%20material-blue.svg?style=flat)](https://pawamoy.github.io/git-changelog/)
55
[![pypi version](https://img.shields.io/pypi/v/git-changelog.svg)](https://pypi.org/project/git-changelog/)
6+
[![gitpod](https://img.shields.io/badge/gitpod-workspace-blue.svg?style=flat)](https://gitpod.io/#https://github.com/pawamoy/git-changelog)
67
[![gitter](https://badges.gitter.im/join%20chat.svg)](https://gitter.im/git-changelog/community)
78

89
Automatic Changelog generator using Jinja2 templates. From git logs to change logs.
@@ -48,42 +49,17 @@ Automatic Changelog generator using Jinja2 templates. From git logs to change lo
4849
[issue-17]: https://github.com/pawamoy/git-changelog/issues/17
4950
[issue-19]: https://github.com/pawamoy/git-changelog/issues/19
5051

51-
## Requirements
52-
53-
git-changelog requires Python 3.6 or above.
54-
55-
<details>
56-
<summary>To install Python 3.6, I recommend using <a href="https://github.com/pyenv/pyenv"><code>pyenv</code></a>.</summary>
57-
58-
```bash
59-
# install pyenv
60-
git clone https://github.com/pyenv/pyenv ~/.pyenv
61-
62-
# setup pyenv (you should also put these three lines in .bashrc or similar)
63-
export PATH="${HOME}/.pyenv/bin:${PATH}"
64-
export PYENV_ROOT="${HOME}/.pyenv"
65-
eval "$(pyenv init -)"
66-
67-
# install Python 3.6
68-
pyenv install 3.6.12
69-
70-
# make it available globally
71-
pyenv global system 3.6.12
72-
```
73-
</details>
74-
7552
## Installation
7653

7754
With `pip`:
7855
```bash
79-
python3.6 -m pip install git-changelog
56+
pip install git-changelog
8057
```
8158

8259
With [`pipx`](https://github.com/pipxproject/pipx):
8360
```bash
84-
python3.6 -m pip install --user pipx
85-
86-
pipx install --python python3.6 git-changelog
61+
python3.7 -m pip install --user pipx
62+
pipx install git-changelog
8763
```
8864

8965
## Usage (command-line)

‎config/flake8.ini

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ ignore =
1010
D105
1111
# multi-line docstring summary should start at the first line
1212
D212
13+
# does not support Parameters sections
14+
D417
1315
# whitespace before ':' (incompatible with Black)
1416
E203
1517
# redundant with E0602 (undefined variable)

‎config/mypy.ini

+2-6
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
[mypy]
22
ignore_missing_imports = true
33
exclude = tests/fixtures/
4-
5-
[mypy-toml]
6-
ignore_missing_imports = true
7-
8-
[mypy-pkg_resources]
9-
ignore_missing_imports = true
4+
warn_unused_ignores = true
5+
show_error_codes = true

‎docs/credits.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```python exec="yes"
2+
--8<-- "scripts/gen_credits.py"
3+
```

‎docs/gen_ref_nav.py

100644100755
+14-7
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,25 @@
66

77
nav = mkdocs_gen_files.Nav()
88

9-
for path in sorted(Path("src").glob("**/*.py")):
9+
for path in sorted(Path("src").rglob("*.py")):
1010
module_path = path.relative_to("src").with_suffix("")
11-
doc_path = path.relative_to("src", "git_changelog").with_suffix(".md")
11+
doc_path = path.relative_to("src").with_suffix(".md")
1212
full_doc_path = Path("reference", doc_path)
1313

14-
parts = list(module_path.parts)
15-
parts[-1] = f"{parts[-1]}.py"
16-
nav[parts] = doc_path
14+
parts = tuple(module_path.parts)
15+
16+
if parts[-1] == "__init__":
17+
parts = parts[:-1]
18+
doc_path = doc_path.with_name("index.md")
19+
full_doc_path = full_doc_path.with_name("index.md")
20+
elif parts[-1] == "__main__":
21+
continue
22+
23+
nav[parts] = doc_path.as_posix()
1724

1825
with mkdocs_gen_files.open(full_doc_path, "w") as fd:
19-
ident = ".".join(module_path.parts)
20-
print("::: " + ident, file=fd)
26+
ident = ".".join(parts)
27+
fd.write(f"::: {ident}")
2128

2229
mkdocs_gen_files.set_edit_path(full_doc_path, path)
2330

‎duties.py

+50-52
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
"""Development tasks."""
22

3+
import importlib
34
import os
45
import re
56
import sys
6-
from functools import wraps
7+
from io import StringIO
78
from pathlib import Path
8-
from shutil import which
99
from typing import List, Optional, Pattern
1010
from urllib.request import urlopen
1111

@@ -43,7 +43,6 @@ def update_changelog(
4343
marker: str,
4444
version_regex: str,
4545
template_url: str,
46-
commit_style: str,
4746
) -> None:
4847
"""
4948
Update the given changelog file in place.
@@ -53,12 +52,16 @@ def update_changelog(
5352
marker: The line after which to insert new contents.
5453
version_regex: A regular expression to find currently documented versions in the file.
5554
template_url: The URL to the Jinja template used to render contents.
56-
commit_style: The style of commit messages to parse.
5755
"""
56+
from git_changelog.build import Changelog
57+
from git_changelog.commit import AngularStyle
58+
from jinja2.sandbox import SandboxedEnvironment
59+
60+
AngularStyle.DEFAULT_RENDER.insert(0, AngularStyle.TYPES["build"])
5861
env = SandboxedEnvironment(autoescape=False)
5962
template_text = urlopen(template_url).read().decode("utf8") # noqa: S310
6063
template = env.from_string(template_text)
61-
changelog = Changelog(".", style=commit_style)
64+
changelog = Changelog(".", style="angular")
6265

6366
if len(changelog.versions_list) == 1:
6467
last_version = changelog.versions_list[0]
@@ -98,14 +101,13 @@ def changelog(ctx):
98101
"marker": "<!-- insertion marker -->",
99102
"version_regex": r"^## \[v?(?P<version>[^\]]+)",
100103
"template_url": template_url,
101-
"commit_style": "angular",
102104
},
103105
title="Updating changelog",
104106
pty=PTY,
105107
)
106108

107109

108-
@duty(pre=["check_code_quality", "check_types", "check_docs", "check_dependencies"])
110+
@duty(pre=["check_quality", "check_types", "check_docs", "check_dependencies"])
109111
def check(ctx):
110112
"""
111113
Check it all!
@@ -116,7 +118,7 @@ def check(ctx):
116118

117119

118120
@duty
119-
def check_code_quality(ctx, files=PY_SRC):
121+
def check_quality(ctx, files=PY_SRC):
120122
"""
121123
Check the code quality.
122124
@@ -135,49 +137,48 @@ def check_dependencies(ctx):
135137
Arguments:
136138
ctx: The context instance (passed automatically).
137139
"""
138-
nofail = False
139-
safety = which("safety")
140-
if not safety:
141-
pipx = which("pipx")
142-
if pipx:
143-
safety = f"{pipx} run safety"
144-
else:
145-
safety = "safety"
146-
nofail = True
147-
ctx.run(
148-
f"pdm export -f requirements --without-hashes | {safety} check --stdin --full-report",
149-
title="Checking dependencies",
150-
pty=PTY,
151-
nofail=nofail,
140+
# undo possible patching
141+
# see https://github.com/pyupio/safety/issues/348
142+
for module in sys.modules: # noqa: WPS528
143+
if module.startswith("safety.") or module == "safety":
144+
del sys.modules[module] # noqa: WPS420
145+
146+
importlib.invalidate_caches()
147+
148+
# reload original, unpatched safety
149+
from safety.formatter import SafetyFormatter
150+
from safety.safety import calculate_remediations
151+
from safety.safety import check as safety_check
152+
from safety.util import read_requirements
153+
154+
# retrieve the list of dependencies
155+
requirements = ctx.run(
156+
["pdm", "export", "-f", "requirements", "--without-hashes"],
157+
title="Exporting dependencies as requirements",
158+
allow_overrides=False,
152159
)
153160

154-
155-
def no_docs_py36(nofail=True):
156-
"""
157-
Decorate a duty that builds docs to warn that it's not possible on Python 3.6.
158-
159-
Arguments:
160-
nofail: Whether to fail or not.
161-
162-
Returns:
163-
The decorated function.
164-
"""
165-
166-
def decorator(func):
167-
@wraps(func)
168-
def wrapper(ctx):
169-
if sys.version_info <= (3, 7, 0):
170-
ctx.run(["false"], title="Docs can't be built on Python 3.6", nofail=nofail, quiet=True)
171-
else:
172-
func(ctx)
173-
174-
return wrapper
175-
176-
return decorator
161+
# check using safety as a library
162+
def safety(): # noqa: WPS430
163+
packages = list(read_requirements(StringIO(requirements)))
164+
vulns, db_full = safety_check(packages=packages, ignore_vulns="")
165+
remediations = calculate_remediations(vulns, db_full)
166+
output_report = SafetyFormatter("text").render_vulnerabilities(
167+
announcements=[],
168+
vulnerabilities=vulns,
169+
remediations=remediations,
170+
full=True,
171+
packages=packages,
172+
)
173+
if vulns:
174+
print(output_report)
175+
return False
176+
return True
177+
178+
ctx.run(safety, title="Checking dependencies")
177179

178180

179181
@duty
180-
@no_docs_py36()
181182
def check_docs(ctx):
182183
"""
183184
Check if the documentation builds correctly.
@@ -190,8 +191,8 @@ def check_docs(ctx):
190191
ctx.run("mkdocs build -s", title="Building documentation", pty=PTY)
191192

192193

193-
@duty
194-
def check_types(ctx):
194+
@duty # noqa: WPS231
195+
def check_types(ctx): # noqa: WPS231
195196
"""
196197
Check that the code is correctly typed.
197198
@@ -223,7 +224,6 @@ def clean(ctx):
223224

224225

225226
@duty
226-
@no_docs_py36(nofail=False)
227227
def docs(ctx):
228228
"""
229229
Build the documentation locally.
@@ -235,7 +235,6 @@ def docs(ctx):
235235

236236

237237
@duty
238-
@no_docs_py36(nofail=False)
239238
def docs_serve(ctx, host="127.0.0.1", port=8000):
240239
"""
241240
Serve the documentation (localhost:8000).
@@ -249,7 +248,6 @@ def docs_serve(ctx, host="127.0.0.1", port=8000):
249248

250249

251250
@duty
252-
@no_docs_py36(nofail=False)
253251
def docs_deploy(ctx):
254252
"""
255253
Deploy the documentation on GitHub pages.
@@ -294,7 +292,7 @@ def release(ctx, version):
294292
ctx.run("git push --tags", title="Pushing tags", pty=False)
295293
ctx.run("pdm build", title="Building dist/wheel", pty=PTY)
296294
ctx.run("twine upload --skip-existing dist/*", title="Publishing version", pty=PTY)
297-
docs_deploy.run() # type: ignore
295+
docs_deploy.run()
298296

299297

300298
@duty(silent=True)

‎mkdocs.yml

+7-4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ site_url: "https://pawamoy.github.io/git-changelog"
44
repo_url: "https://github.com/pawamoy/git-changelog"
55
repo_name: "pawamoy/git-changelog"
66
site_dir: "site"
7+
watch: [README.md, CONTRIBUTING.md, CHANGELOG.md, src/git_changelog]
78

89
nav:
910
- Home:
@@ -25,6 +26,7 @@ theme:
2526
logo: material/currency-sign
2627
features:
2728
- navigation.tabs
29+
- navigation.tabs.sticky
2830
- navigation.top
2931
palette:
3032
- media: "(prefers-color-scheme: light)"
@@ -48,29 +50,30 @@ extra_css:
4850

4951
markdown_extensions:
5052
- admonition
53+
- callouts
5154
- pymdownx.emoji
5255
- pymdownx.magiclink
5356
- pymdownx.snippets:
5457
check_paths: true
5558
- pymdownx.superfences
56-
- pymdownx.tabbed
59+
- pymdownx.tabbed:
60+
alternate_style: true
5761
- pymdownx.tasklist
5862
- toc:
5963
permalink: "¤"
6064

6165
plugins:
6266
- search
67+
- markdown-exec
6368
- gen-files:
6469
scripts:
65-
- docs/gen_credits.py
6670
- docs/gen_ref_nav.py
6771
- literate-nav:
6872
nav_file: SUMMARY.md
6973
- coverage
74+
- section-index
7075
- mkdocstrings:
7176
custom_templates: docs/templates
72-
watch:
73-
- src/git_changelog
7477

7578
extra:
7679
social:

‎pyproject.toml

+58-35
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,34 @@ build-backend = "pdm.pep517.api"
44

55
[project]
66
name = "git-changelog"
7-
version = {use_scm = true}
87
description = "Automatic Changelog generator using Jinja2 templates."
98
authors = [{name = "Timothée Mazzucotelli", email = "pawamoy@pm.me"}]
10-
license = {file = "LICENSE"}
9+
license-expression = "ISC"
1110
readme = "README.md"
12-
requires-python = ">=3.6.2"
11+
requires-python = ">=3.7"
1312
keywords = [
1413
"git",
1514
"changelog",
1615
"changelog-generator",
1716
"commit-style",
1817
"commit-convention",
1918
]
20-
dynamic = ["version", "classifiers"]
19+
dynamic = ["version"]
2120
classifiers = [
2221
"Development Status :: 4 - Beta",
23-
"License :: OSI Approved :: ISC License (ISCL)",
22+
"Intended Audience :: Developers",
23+
"Programming Language :: Python",
24+
"Programming Language :: Python :: 3",
25+
"Programming Language :: Python :: 3 :: Only",
26+
"Programming Language :: Python :: 3.7",
27+
"Programming Language :: Python :: 3.8",
28+
"Programming Language :: Python :: 3.9",
29+
"Programming Language :: Python :: 3.10",
30+
"Programming Language :: Python :: 3.11",
31+
"Topic :: Documentation",
32+
"Topic :: Software Development",
33+
"Topic :: Software Development :: Documentation",
34+
"Topic :: Utilities",
2435
"Typing :: Typed",
2536
]
2637
dependencies = [
@@ -42,47 +53,59 @@ Funding = "https://github.com/sponsors/pawamoy"
4253
git-changelog = "git_changelog.cli:main"
4354

4455
[tool.pdm]
56+
version = {source = "scm"}
57+
58+
[tool.pdm.build]
4559
package-dir = "src"
60+
editable-backend = "editables"
4661

4762
[tool.pdm.dev-dependencies]
48-
duty = ["duty~=0.6"]
63+
duty = ["duty>=0.7"]
4964
docs = [
50-
"mkdocs~=1.1; python_version >= '3.7'",
51-
"mkdocs-coverage~=0.2; python_version >= '3.7'",
52-
"mkdocs-gen-files~=0.3; python_version >= '3.7'",
53-
"mkdocs-literate-nav~=0.4; python_version >= '3.7'",
54-
"mkdocs-material~=7.1; python_version >= '3.7'",
55-
"mkdocstrings~=0.15; python_version >= '3.7'",
56-
"toml~=0.10; python_version >= '3.7'",
65+
"mkdocs>=1.3",
66+
"mkdocs-coverage>=0.2",
67+
"mkdocs-gen-files>=0.3",
68+
"mkdocs-literate-nav>=0.4",
69+
"mkdocs-material>=7.3",
70+
"mkdocs-section-index>=0.3",
71+
"mkdocstrings[python]>=0.18",
72+
"markdown-callouts>=0.2",
73+
"markdown-exec>=0.5",
74+
"toml>=0.10",
5775
]
5876
format = [
59-
"autoflake~=1.4",
60-
"black~=21.10b0",
61-
"isort~=5.8",
77+
"autoflake>=1.4",
78+
"black>=21.10b0",
79+
"isort>=5.10",
6280
]
6381
quality = [
64-
"darglint~=1.7",
65-
"flake8-bandit~=2.1",
66-
"flake8-black~=0.2",
67-
"flake8-bugbear~=21.3",
68-
"flake8-builtins~=1.5",
69-
"flake8-comprehensions~=3.4",
70-
"flake8-docstrings~=1.6",
71-
"flake8-pytest-style~=1.4",
72-
"flake8-string-format~=0.3",
73-
"flake8-tidy-imports~=4.2",
74-
"flake8-variables-names~=0.0",
75-
"pep8-naming~=0.11",
76-
"wps-light~=0.15",
82+
"darglint>=1.8",
83+
"flake8<4", # TODO: remove once importlib-metadata version conflict is resolved
84+
"flake8-bandit>=2.1",
85+
"flake8-black>=0.2",
86+
"flake8-bugbear>=21.9",
87+
"flake8-builtins>=1.5",
88+
"flake8-comprehensions>=3.7",
89+
"flake8-docstrings>=1.6",
90+
"flake8-pytest-style>=1.5",
91+
"flake8-string-format>=0.3",
92+
"flake8-tidy-imports>=4.5",
93+
"flake8-variables-names>=0.0",
94+
"pep8-naming>=0.12",
95+
"wps-light>=0.15",
7796
]
7897
tests = [
79-
"pytest~=6.2",
80-
"pytest-cov~=2.11",
81-
"pytest-randomly~=3.6",
82-
"pytest-sugar~=0.9",
83-
"pytest-xdist~=2.2",
98+
"pytest>=6.2",
99+
"pytest-cov>=3.0",
100+
"pytest-randomly>=3.10",
101+
"pytest-xdist>=2.4",
102+
]
103+
typing = [
104+
"mypy>=0.910",
105+
"types-markdown>=3.3",
106+
"types-toml>=0.10",
84107
]
85-
typing = ["mypy~=0.812"]
108+
security = ["safety>=2"]
86109

87110
[tool.black]
88111
line-length = 120

‎scripts/gen_credits.py

+110
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
import re
2+
from itertools import chain
3+
from pathlib import Path
4+
from textwrap import dedent
5+
6+
import toml
7+
from jinja2 import StrictUndefined
8+
from jinja2.sandbox import SandboxedEnvironment
9+
10+
try:
11+
from importlib.metadata import metadata, PackageNotFoundError
12+
except ImportError:
13+
from importlib_metadata import metadata, PackageNotFoundError
14+
15+
project_dir = Path(".")
16+
pyproject = toml.load(project_dir / "pyproject.toml")
17+
project = pyproject["project"]
18+
pdm = pyproject["tool"]["pdm"]
19+
lock_data = toml.load(project_dir / "pdm.lock")
20+
lock_pkgs = {pkg["name"].lower(): pkg for pkg in lock_data["package"]}
21+
project_name = project["name"]
22+
regex = re.compile(r"(?P<dist>[\w.-]+)(?P<spec>.*)$")
23+
24+
def get_license(pkg_name):
25+
try:
26+
data = metadata(pkg_name)
27+
except PackageNotFoundError:
28+
return "?"
29+
license = data.get("License", "").strip()
30+
multiple_lines = bool(license.count("\n"))
31+
# TODO: remove author logic once all my packages licenses are fixed
32+
author = ""
33+
if multiple_lines or not license or license == "UNKNOWN":
34+
for header, value in data.items():
35+
if header == "Classifier" and value.startswith("License ::"):
36+
license = value.rsplit("::", 1)[1].strip()
37+
elif header == "Author-email":
38+
author = value
39+
if license == "Other/Proprietary License" and "pawamoy" in author:
40+
license = "ISC"
41+
return license or "?"
42+
43+
def get_deps(base_deps):
44+
deps = {}
45+
for dep in base_deps:
46+
parsed = regex.match(dep).groupdict()
47+
dep_name = parsed["dist"].lower()
48+
deps[dep_name] = {"license": get_license(dep_name), **parsed, **lock_pkgs[dep_name]}
49+
50+
again = True
51+
while again:
52+
again = False
53+
for pkg_name in lock_pkgs:
54+
if pkg_name in deps:
55+
for pkg_dependency in lock_pkgs[pkg_name].get("dependencies", []):
56+
parsed = regex.match(pkg_dependency).groupdict()
57+
dep_name = parsed["dist"].lower()
58+
if dep_name not in deps:
59+
deps[dep_name] = {"license": get_license(dep_name), **parsed, **lock_pkgs[dep_name]}
60+
again = True
61+
62+
return deps
63+
64+
dev_dependencies = get_deps(chain(*pdm.get("dev-dependencies", {}).values()))
65+
prod_dependencies = get_deps(
66+
chain(
67+
project.get("dependencies", []),
68+
chain(*project.get("optional-dependencies", {}).values()),
69+
)
70+
)
71+
72+
template_data = {
73+
"project_name": project_name,
74+
"prod_dependencies": sorted(prod_dependencies.values(), key=lambda dep: dep["name"]),
75+
"dev_dependencies": sorted(dev_dependencies.values(), key=lambda dep: dep["name"]),
76+
"more_credits": "http://pawamoy.github.io/credits/",
77+
}
78+
template_text = dedent(
79+
"""
80+
These projects were used to build `{{ project_name }}`. **Thank you!**
81+
82+
[`python`](https://www.python.org/) |
83+
[`pdm`](https://pdm.fming.dev/) |
84+
[`copier-pdm`](https://github.com/pawamoy/copier-pdm)
85+
86+
{% macro dep_line(dep) -%}
87+
[`{{ dep.name }}`](https://pypi.org/project/{{ dep.name }}/) | {{ dep.summary }} | {{ ("`" ~ dep.spec ~ "`") if dep.spec else "" }} | `{{ dep.version }}` | {{ dep.license }}
88+
{%- endmacro %}
89+
90+
### Runtime dependencies
91+
92+
Project | Summary | Version (accepted) | Version (last resolved) | License
93+
------- | ------- | ------------------ | ----------------------- | -------
94+
{% for dep in prod_dependencies -%}
95+
{{ dep_line(dep) }}
96+
{% endfor %}
97+
98+
### Development dependencies
99+
100+
Project | Summary | Version (accepted) | Version (last resolved) | License
101+
------- | ------- | ------------------ | ----------------------- | -------
102+
{% for dep in dev_dependencies -%}
103+
{{ dep_line(dep) }}
104+
{% endfor %}
105+
106+
{% if more_credits %}**[More credits from the author]({{ more_credits }})**{% endif %}
107+
"""
108+
)
109+
jinja_env = SandboxedEnvironment(undefined=StrictUndefined)
110+
print(jinja_env.from_string(template_text).render(**template_data))

‎scripts/multirun.sh

+11-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,21 @@
11
#!/usr/bin/env bash
22
set -e
33

4-
PYTHON_VERSIONS="${PYTHON_VERSIONS-3.6 3.7 3.8 3.9 3.10 3.11}"
4+
PYTHON_VERSIONS="${PYTHON_VERSIONS-3.7 3.8 3.9 3.10 3.11}"
5+
6+
restore_previous_python_version() {
7+
if pdm use -f "$1" &>/dev/null; then
8+
echo "> Restored previous Python version: ${1##*/}"
9+
fi
10+
}
511

612
if [ -n "${PYTHON_VERSIONS}" ]; then
13+
old_python_version="$(pdm config python.path)"
14+
echo "> Currently selected Python version: ${old_python_version##*/}"
15+
trap "restore_previous_python_version ${old_python_version}" EXIT
716
for python_version in ${PYTHON_VERSIONS}; do
817
if pdm use -f "python${python_version}" &>/dev/null; then
9-
echo "> pdm run $@ (Python ${python_version})"
18+
echo "> pdm run $@ (python${python_version})"
1019
pdm run "$@"
1120
else
1221
echo "> pdm use -f python${python_version}: Python interpreter not available?" >&2

‎scripts/setup.sh

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/usr/bin/env bash
22
set -e
33

4-
PYTHON_VERSIONS="${PYTHON_VERSIONS-3.6 3.7 3.8 3.9 3.10 3.11}"
4+
PYTHON_VERSIONS="${PYTHON_VERSIONS-3.7 3.8 3.9 3.10 3.11}"
55

66
install_with_pipx() {
77
if ! command -v "$1" &>/dev/null; then
@@ -14,7 +14,17 @@ install_with_pipx() {
1414

1515
install_with_pipx pdm
1616

17+
restore_previous_python_version() {
18+
if pdm use -f "$1" &>/dev/null; then
19+
echo "> Restored previous Python version: ${1##*/}"
20+
fi
21+
}
22+
1723
if [ -n "${PYTHON_VERSIONS}" ]; then
24+
if old_python_version="$(pdm config python.path 2>/dev/null)"; then
25+
echo "> Currently selected Python version: ${old_python_version##*/}"
26+
trap "restore_previous_python_version ${old_python_version}" EXIT
27+
fi
1828
for python_version in ${PYTHON_VERSIONS}; do
1929
if pdm use -f "python${python_version}" &>/dev/null; then
2030
echo "> Using Python ${python_version} interpreter"

0 commit comments

Comments
 (0)
Please sign in to comment.