Skip to content

Commit f04f480

Browse files
committed
Automate screenshot generation in README.rst
The current screenshot is outdated. It is running on an older version of Django Debug Toolbar and an end-of-life Django 1.6. Some newer panels, such as the history panel, are missing. The new script example/screenshot.py uses Selenium to generate a screenshot using the latest version of Django and Django Debug Toolbar. Unlike the previous screenshot which displayed macOS window decorations, this one is OS-agnostic. The script generates the image with an exact resolution, so README.rst no longer needs to re-specify dimensions. The generated image is optimized using the optipng command line utility. The contributing docs have been updated to include running this script when making a new release so the screenshot will continue to remain up to date.
1 parent b0ba227 commit f04f480

File tree

5 files changed

+97
-2
lines changed

5 files changed

+97
-2
lines changed

Makefile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,8 @@ translatable_strings:
4747
update_translations:
4848
tx pull -a --minimum-perc=10
4949
cd debug_toolbar && python -m django compilemessages
50+
51+
.PHONY: example/django-debug-toolbar.png
52+
example/django-debug-toolbar.png: example/screenshot.py
53+
python $< --browser firefox --headless -o $@
54+
optipng $@

README.rst

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@ more details about the panel's content.
2525
Here's a screenshot of the toolbar in action:
2626

2727
.. image:: https://raw.github.com/jazzband/django-debug-toolbar/master/example/django-debug-toolbar.png
28-
:width: 908
29-
:height: 557
28+
:alt: Django Debug Toolbar screenshot
3029

3130
In addition to the built-in panels, a number of third-party panels are
3231
contributed by the community.

docs/contributing.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,14 @@ The release itself requires the following steps:
132132

133133
Commit.
134134

135+
#. Update the screenshot in ``README.rst``.
136+
137+
.. code-block:: console
138+
139+
$ make example/django-debug-toolbar.png
140+
141+
Commit.
142+
135143
#. Bump version numbers in ``docs/changes.rst``, ``docs/conf.py``,
136144
``README.rst`` and ``setup.py``. Add the release date to
137145
``docs/changes.rst``. Commit.

example/django-debug-toolbar.png

-88.8 KB
Loading

example/screenshot.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import argparse
2+
import importlib
3+
import os
4+
import signal
5+
import subprocess
6+
7+
from selenium.webdriver.common.keys import Keys
8+
from selenium.webdriver.support import expected_conditions as EC
9+
from selenium.webdriver.support.wait import WebDriverWait
10+
11+
12+
def parse_args():
13+
parser = argparse.ArgumentParser()
14+
parser.add_argument("--browser", required=True)
15+
parser.add_argument("--headless", action="store_true")
16+
parser.add_argument("--outfile", "-o", required=True)
17+
parser.add_argument("--width", type=int, default=900)
18+
parser.add_argument("--height", type=int, default=700)
19+
return parser.parse_args()
20+
21+
22+
def create_webdriver_options(browser, headless):
23+
mod = importlib.import_module(f"selenium.webdriver.{browser}.options")
24+
options = mod.Options()
25+
if headless:
26+
options.headless = True
27+
return options
28+
29+
30+
def create_webdriver(browser, headless):
31+
mod = importlib.import_module(f"selenium.webdriver.{browser}.webdriver")
32+
return mod.WebDriver(options=create_webdriver_options(browser, headless))
33+
34+
35+
def example_server():
36+
return subprocess.Popen(["make", "example"])
37+
38+
39+
def set_viewport_size(selenium, width, height):
40+
script = """
41+
return [
42+
window.outerWidth - window.innerWidth + arguments[0],
43+
window.outerHeight - window.innerHeight + arguments[1],
44+
];
45+
"""
46+
window_width, window_height = selenium.execute_script(script, width, height)
47+
selenium.set_window_size(window_width, window_height)
48+
49+
50+
def submit_form(selenium, data):
51+
url = selenium.current_url
52+
for name, value in data.items():
53+
el = selenium.find_element_by_name(name)
54+
el.send_keys(value)
55+
el.send_keys(Keys.RETURN)
56+
WebDriverWait(selenium, timeout=5).until(EC.url_changes(url))
57+
58+
59+
def main():
60+
args = parse_args()
61+
with example_server() as p:
62+
try:
63+
with create_webdriver(args.browser, args.headless) as selenium:
64+
set_viewport_size(selenium, args.width, args.height)
65+
66+
selenium.get("http://localhost:8000/admin/login/")
67+
submit_form(selenium, {"username": os.environ["USER"], "password": "p"})
68+
69+
selenium.get("http://localhost:8000/admin/auth/user/")
70+
# Close the admin sidebar.
71+
el = selenium.find_element_by_id("toggle-nav-sidebar")
72+
el.click()
73+
# Open the SQL panel.
74+
el = selenium.find_element_by_id("djdt-SQLPanel")
75+
el.click()
76+
77+
selenium.save_screenshot(args.outfile)
78+
finally:
79+
p.send_signal(signal.SIGTERM)
80+
81+
82+
if __name__ == "__main__":
83+
main()

0 commit comments

Comments
 (0)