Skip to content

Commit 7c7a589

Browse files
Merge pull request #111 from discord-modmail/scripts-wrapper
scripts: add wrapper to run scripts by invoking the scripts module
2 parents 92356fd + 5a2a2e3 commit 7c7a589

File tree

4 files changed

+75
-4
lines changed

4 files changed

+75
-4
lines changed

poetry.lock

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ pytest-xdist = { version = "^2.3.0", extras = ["psutil"] }
5656
mkdocs = ">=1.1.2,<2.0.0"
5757
mkdocs-material = ">=7.1.9,<8.0.0"
5858
mkdocs-markdownextradata-plugin = ">=0.1.7,<0.2.0"
59+
# Scripts
60+
click = "^8.0.3"
5961

6062
[build-system]
6163
requires = ["poetry-core>=1.0.0"]
@@ -88,5 +90,6 @@ flake8 = { cmd = "python -m flake8", help = "Lints code with flake8" }
8890
lint = { cmd = "pre-commit run --all-files", help = "Checks all files for CI errors" }
8991
precommit = { cmd = "pre-commit install --install-hooks", help = "Installs the precommit hook" }
9092
report = { cmd = "coverage report", help = "Show coverage report from previously run tests." }
93+
scripts = { cmd = 'python -m scripts', help = 'Run the scripts wrapper cli.' }
9194
test = { cmd = "pytest -n auto --dist loadfile", help = "Runs tests and save results to a coverage report" }
9295
test_mocks = { cmd = 'pytest tests/test_mocks.py', help = 'Runs the tests on the mock files. They are excluded from the main test suite.' }

scripts/__init__.py

Whitespace-only changes.

scripts/__main__.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
"""
2+
Script wrapper for scripts.
3+
4+
This allows scripts to be invoked through the scripts module.
5+
6+
The exposed interface is just running the internal files.
7+
Whatever interface they have, is what is shown.
8+
"""
9+
10+
import functools
11+
import runpy
12+
import sys
13+
14+
import click
15+
16+
17+
# key: alias
18+
# value: tuple of module name, help description
19+
commands: "dict[str, tuple[str, str | None]]" = {
20+
"export_req": ("scripts.export_requirements", "Export requirements to requirements.txt"),
21+
}
22+
23+
24+
def run_script(module_name: str, *args, **kwargs) -> None:
25+
"""
26+
Run the provided module, with the provided args and kwargs.
27+
28+
The provided defaults are what makes the environment nearly the same as if module was invoked directly.
29+
"""
30+
kwargs.setdefault("run_name", "__main__")
31+
kwargs.setdefault("alter_sys", True)
32+
runpy.run_module(module_name, **kwargs)
33+
34+
35+
@click.group()
36+
@click.help_option("-h", "--help")
37+
def cli() -> None:
38+
"""
39+
Custom scripts which help modmail development.
40+
41+
All custom scripts should be listed below as a command, with a description.
42+
In addition, some built in modules may be listed below as well.
43+
If a custom script is not shown below please open an issue.
44+
"""
45+
pass
46+
47+
48+
def main(cmd: str = None) -> None:
49+
"""Add the commands and run the cli."""
50+
if cmd is None:
51+
cmd = []
52+
for k, v in commands.items():
53+
func = functools.partial(run_script, v[0])
54+
cli.add_command(click.Command(k, help=v[1], callback=func))
55+
cli.main(cmd, standalone_mode=False)
56+
57+
58+
if __name__ == "__main__":
59+
try:
60+
cmd = [sys.argv[1]]
61+
sys.argv.pop(1) # pop the first arg out of sys.argv since its being used to get the name
62+
except IndexError:
63+
cmd = []
64+
try:
65+
main(cmd)
66+
except click.ClickException as e:
67+
e.show()
68+
sys.exit()

0 commit comments

Comments
 (0)