Skip to content

Commit

Permalink
sh: and python: YAML commands, refs #155
Browse files Browse the repository at this point in the history
  • Loading branch information
simonw committed Sep 26, 2024
1 parent bcab22e commit 99d1d69
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 9 deletions.
29 changes: 29 additions & 0 deletions docs/multi.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,35 @@ You can now take screenshots of `http://localhost:8000/` and any other URLs that
```
The server process will be automatically terminated when the `shot-scraper multi` command completes.

## Running custom code between steps

If you are taking screenshots of a single application, you may find it useful to run additional steps between shots that modify that application in some way.

You can do that using the `sh:` or `python:` keys. These can specify shell commands or Python code to run before taking the screenshot:

```yaml
- sh: echo "Hello from shell" > index.html
output: from-shell.png
url: http://localhost:8000/
```
You can also specify a list of shell arguments like this:
```yaml
- sh:
- curl
- -o
- index.html
- https://www.example.com/
output: example.png
url: http://localhost:8000/
```
If you specify these steps without a `url:` key they will still execute as individual task executions, without also taking a screenshot:
```yaml
- sh: echo "hello world" > index.html
- python: |
content = open("index.html").read()
open("index.html", "w").write(content.upper())
```

## `shot-scraper multi --help`

Full `--help` for this command:
Expand Down
16 changes: 14 additions & 2 deletions shot_scraper/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -540,8 +540,20 @@ def multi(
and pathlib.Path(shot["output"]).exists()
):
continue
if outputs and shot.get("output") not in outputs:
if outputs and shot.get("output") and shot.get("output") not in outputs:
continue
# Run "sh" key
if shot.get("sh"):
sh = shot["sh"]
if isinstance(sh, str):
subprocess.run(shot["sh"], shell=True)
elif isinstance(sh, list):
subprocess.run(sh)
else:
raise click.ClickException("- sh: must be a string or list")
# And "python" key
if shot.get("python"):
subprocess.run([sys.executable, "-c", shot["python"]])
if "server" in shot:
# Start that subprocess and remember the pid
server_processes.append(
Expand Down Expand Up @@ -1098,7 +1110,7 @@ def take_shot(

url = url_or_file_path(url, file_exists=_check_and_absolutize)

output = shot.get("output", "").strip()
output = (shot.get("output") or "").strip()
if not output and not return_bytes:
output = filename_for_url(url, ext="png", file_exists=os.path.exists)
quality = shot.get("quality")
Expand Down
37 changes: 30 additions & 7 deletions tests/test_shot_scraper.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from click.testing import CliRunner
import pathlib
import pytest
import textwrap
from shot_scraper.cli import cli
Expand All @@ -15,17 +16,39 @@ def test_version():
SERVER_YAML = """
- server: python -m http.server 9023
- url: http://localhost:9023/
output: {}
output: output.png
""".strip()

COMMANDS_YAML = """
- sh: echo "hello world" > index.html
- sh:
- touch
- touched.html
- python: |
content = open("index.html").read()
open("index.html", "w").write(content.upper())
"""


def test_multi_server(tmpdir):
yaml_file = tmpdir / "server.yaml"
yaml_file.write(SERVER_YAML.format(tmpdir / "output.png"))
def test_multi_server():
runner = CliRunner()
result = runner.invoke(cli, ["multi", str(yaml_file)])
assert result.exit_code == 0, result.output
assert (tmpdir / "output.png").exists()
with runner.isolated_filesystem():
open("server.yaml", "w").write(SERVER_YAML)
result = runner.invoke(cli, ["multi", "server.yaml"])
assert result.exit_code == 0, result.output
assert pathlib.Path("output.png").exists()


def test_multi_commands():
runner = CliRunner()
with runner.isolated_filesystem():
yaml_file = "commands.yaml"
open(yaml_file, "w").write(COMMANDS_YAML)
result = runner.invoke(cli, ["multi", yaml_file], catch_exceptions=False)
assert result.exit_code == 0, result.output
assert pathlib.Path("touched.html").exists()
assert pathlib.Path("index.html").exists()
assert open("index.html").read().strip() == "HELLO WORLD"


@pytest.mark.parametrize("input", ("key: value", "This is a string", "3.55"))
Expand Down

0 comments on commit 99d1d69

Please sign in to comment.