Skip to content

Commit dbe80cd

Browse files
committed
feat: basic requests
stdin is forwarded to the different endpoints
1 parent 21a9ab9 commit dbe80cd

5 files changed

Lines changed: 242 additions & 8 deletions

File tree

poetry.lock

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

pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,12 @@ classifiers = [
2727
[tool.poetry.dependencies]
2828
python = "^3.9"
2929
click = "^8.1.7"
30+
requests = "^2.32.2"
3031

3132
[tool.poetry.group.dev.dependencies]
3233
pytest = "^8.2.1"
3334
pytest-coverage = "^0.0"
35+
pytest-httpserver = "^1.0.10"
3436

3537
[tool.poetry.group.doc.dependencies]
3638
shibuya = "^2024.5.15"

scim_cli/__init__.py

Lines changed: 104 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,107 @@
1+
import json
2+
13
import click
4+
import requests
5+
6+
BASE_HEADERS = {
7+
"Accept": "application/scim+json",
8+
"Content-Type": "application/scim+json",
9+
}
10+
11+
12+
@click.group()
13+
@click.argument("url")
14+
@click.pass_context
15+
def cli(ctx, url):
16+
"""SCIM application development CLI."""
17+
ctx.ensure_object(dict)
18+
ctx.obj["URL"] = url
19+
20+
if not click.get_text_stream("stdin").isatty(): # pragma: no cover
21+
stdin = click.get_text_stream("stdin").read().strip()
22+
ctx.obj["STDIN"] = json.loads(stdin)
23+
24+
25+
@cli.command()
26+
@click.pass_context
27+
def get(ctx):
28+
"""Perform a SCIM GET request.
29+
30+
https://www.rfc-editor.org/rfc/rfc7644#section-3.4.1
31+
"""
32+
33+
response = requests.get(
34+
ctx.obj["URL"],
35+
params=ctx.obj.get("STDIN"),
36+
headers=BASE_HEADERS,
37+
allow_redirects=True,
38+
)
39+
click.echo(response.text)
40+
41+
42+
@cli.command()
43+
@click.pass_context
44+
def post(ctx):
45+
"""Perform a SCIM POST request.
46+
47+
https://www.rfc-editor.org/rfc/rfc7644#section-3.3
48+
"""
49+
50+
response = requests.post(
51+
ctx.obj["URL"],
52+
json=ctx.obj.get("STDIN"),
53+
headers=BASE_HEADERS,
54+
allow_redirects=True,
55+
)
56+
click.echo(response.text)
57+
58+
59+
@cli.command()
60+
@click.pass_context
61+
def put(ctx):
62+
"""Perform a SCIM PUT request.
63+
64+
https://www.rfc-editor.org/rfc/rfc7644#section-3.5.1
65+
"""
66+
67+
response = requests.put(
68+
ctx.obj["URL"],
69+
json=ctx.obj.get("STDIN"),
70+
headers=BASE_HEADERS,
71+
allow_redirects=True,
72+
)
73+
click.echo(response.text)
74+
75+
76+
@cli.command()
77+
@click.pass_context
78+
def patch(ctx):
79+
"""Perform a SCIM PATCH request.
80+
81+
https://www.rfc-editor.org/rfc/rfc7644#section-3.5.2
82+
"""
83+
84+
response = requests.patch(
85+
ctx.obj["URL"],
86+
json=ctx.obj.get("STDIN"),
87+
headers=BASE_HEADERS,
88+
allow_redirects=True,
89+
)
90+
click.echo(response.text)
91+
92+
93+
@cli.command()
94+
@click.pass_context
95+
def delete(ctx):
96+
"""Perform a SCIM DELETE request.
297
98+
https://www.rfc-editor.org/rfc/rfc7644#section-3.6
99+
"""
3100

4-
@click.command()
5-
def cli():
6-
"""Hello, world."""
7-
click.echo("Hello world!")
101+
response = requests.delete(
102+
ctx.obj["URL"],
103+
json=ctx.obj.get("STDIN"),
104+
headers=BASE_HEADERS,
105+
allow_redirects=True,
106+
)
107+
click.echo(response.text)

tests/conftest.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,28 @@
1+
import json
2+
13
import pytest
24
from click.testing import CliRunner
35

46

57
@pytest.fixture
68
def runner():
79
return CliRunner()
10+
11+
12+
@pytest.fixture
13+
def echoserver(httpserver):
14+
def echo_handler(request):
15+
payload = {
16+
"method": request.method,
17+
}
18+
19+
if request.args:
20+
payload["args"] = request.args
21+
22+
if request.data:
23+
payload["payload"] = request.json if request.is_json else request.data
24+
25+
return json.dumps(payload)
26+
27+
httpserver.expect_request("/").respond_with_handler(echo_handler)
28+
return httpserver

tests/test_cli.py

Lines changed: 83 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,87 @@
1+
import json
2+
13
from scim_cli import cli
24

35

4-
def test_hello_world(runner):
5-
result = runner.invoke(cli)
6+
def test_help(runner):
7+
result = runner.invoke(cli, ["--help"])
8+
assert result.exit_code == 0
9+
assert "SCIM application development CLI.\n" in result.output
10+
11+
12+
def test_get_stdin(runner, echoserver):
13+
"""Test that JSON stdin is passed in the GET request."""
14+
payload = {"foo": "bar"}
15+
result = runner.invoke(
16+
cli,
17+
[echoserver.url_for("/"), "get"],
18+
input=json.dumps(payload),
19+
catch_exceptions=False,
20+
)
21+
assert result.exit_code == 0
22+
expected_payload = {"method": "GET", "args": payload}
23+
json_output = json.loads(result.output)
24+
assert expected_payload == json_output
25+
26+
27+
def test_post_stdin(runner, echoserver):
28+
"""Test that JSON stdin is passed in the POST request."""
29+
30+
payload = {"foo": "bar"}
31+
result = runner.invoke(
32+
cli,
33+
[echoserver.url_for("/"), "post"],
34+
input=json.dumps(payload),
35+
catch_exceptions=False,
36+
)
37+
assert result.exit_code == 0
38+
expected_payload = {"method": "POST", "payload": payload}
39+
json_output = json.loads(result.output)
40+
assert expected_payload == json_output
41+
42+
43+
def test_put_stdin(runner, echoserver):
44+
"""Test that JSON stdin is passed in the PUT request."""
45+
46+
payload = {"foo": "bar"}
47+
result = runner.invoke(
48+
cli,
49+
[echoserver.url_for("/"), "put"],
50+
input=json.dumps(payload),
51+
catch_exceptions=False,
52+
)
53+
assert result.exit_code == 0
54+
expected_payload = {"method": "PUT", "payload": payload}
55+
json_output = json.loads(result.output)
56+
assert expected_payload == json_output
57+
58+
59+
def test_patch_stdin(runner, echoserver):
60+
"""Test that JSON stdin is passed in the POST request."""
61+
62+
payload = {"foo": "bar"}
63+
result = runner.invoke(
64+
cli,
65+
[echoserver.url_for("/"), "patch"],
66+
input=json.dumps(payload),
67+
catch_exceptions=False,
68+
)
69+
assert result.exit_code == 0
70+
expected_payload = {"method": "PATCH", "payload": payload}
71+
json_output = json.loads(result.output)
72+
assert expected_payload == json_output
73+
74+
75+
def test_delete_stdin(runner, echoserver):
76+
"""Test that JSON stdin is passed in the DELETE request."""
77+
payload = {"foo": "bar"}
78+
result = runner.invoke(
79+
cli,
80+
[echoserver.url_for("/"), "delete"],
81+
input=json.dumps(payload),
82+
catch_exceptions=False,
83+
)
684
assert result.exit_code == 0
7-
assert result.output == "Hello world!\n"
85+
expected_payload = {"method": "DELETE", "payload": payload}
86+
json_output = json.loads(result.output)
87+
assert expected_payload == json_output

0 commit comments

Comments
 (0)