Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clean up some http code+tests, and add auth setup documentation #40

Merged
merged 1 commit into from
May 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,26 @@
### Getting Started

Create a file `~/.canvas/credentials.ini` and add the client_id and client_secret credentials for each of your Canvas instances. You can define your default host with `is_default=true`. If no default is explicitly defined, the Canvas CLI will use the first instance in the file as the default for each of the CLI commands.

**Example:**

```
[my-canvas-instance]
client_id=myclientid
client_secret=myclientsecret

[my-dev-canvas-instance]
client_id=devclientid
client_secret=devclientsecret
is_default=true

[localhost]
client_id=localclientid
client_secret=localclientsecret
```

Next, you're ready to install canvas.

`pip install canvas`

**Usage**:
Expand Down
26 changes: 23 additions & 3 deletions canvas_cli/apps/auth/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import keyring
import requests

from canvas_sdk.utils import Http

# Keyring namespace we'll use
KEYRING_SERVICE = __name__

Expand All @@ -32,7 +34,23 @@ def get_config() -> configparser.ConfigParser:
"""Reads the config file and returns a ConfigParser object."""
config = configparser.ConfigParser()
if not config.read(CONFIG_PATH):
raise Exception(f"Please add your configuration file at '{CONFIG_PATH}'")
raise Exception(
f"""Please add your configuration file at '{CONFIG_PATH}' with the following format:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rmagier1 , you'll appreciate this.


[my-canvas-instance]
client_id=myclientid
client_secret=myclientsecret

[my-dev-canvas-instance]
client_id=devclientid
client_secret=devclientsecret
is_default=true

[localhost]
client_id=localclientid
client_secret=localclientsecret
"""
)
return config


Expand Down Expand Up @@ -65,14 +83,16 @@ def get_default_host(host: str | None = None) -> str:
(host for host in hosts if config.getboolean(host, "is_default", fallback=False) is True),
hosts[0],
)
if first_default_host == 'localhost':
if first_default_host == "localhost":
Copy link
Collaborator

@aduane aduane May 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In ruby ' and " are slightly different. You only use " if you're going to do string interpolation. This is very ingrained into me, so I'm always using ' by default.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we using black and isort on this project?

I always type ' to avoid an extra keystroke (shift), and then let the autoformatter deal with it.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It appears we are and I just haven't installed the pre-commit hooks. My bad.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I appreciate your focus on developer efficiency, btw.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sometimes laziness and efficiency are the same thing

return "http://localhost:8000"

return f"https://{first_default_host}.canvasmedical.com"


def request_api_token(host: str, api_client_credentials: str) -> dict:
"""Request an api token using the provided client_id and client_secret."""
token_response = requests.post(
http = Http()
token_response = http.post(
f"{host}/auth/token/",
headers={"Content-Type": "application/x-www-form-urlencoded"},
data=f"grant_type=client_credentials&{api_client_credentials}",
Expand Down
1 change: 0 additions & 1 deletion canvas_sdk/utils/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ def measure_time(fn: F | None = None) -> Callable[[F], F] | F:
def _decorator(fn: F) -> F:
@wraps(fn)
def wrapper(self: "Http", *args: Any, **kwargs: Any) -> Any:
print(fn.__name__)
start_time = time.time()
result = fn(self, *args, **kwargs)
end_time = time.time()
Expand Down
25 changes: 21 additions & 4 deletions canvas_sdk/utils/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
def test_http_get(mock_get: MagicMock) -> None:
http = Http()
http.get("https://www.canvasmedical.com/", headers={"Authorization": "Bearer as;ldkfjdkj"})
mock_get.assert_called_once()
mock_get.assert_called_once_with(
"https://www.canvasmedical.com/", headers={"Authorization": "Bearer as;ldkfjdkj"}
)


@patch("requests.Session.post")
Expand All @@ -19,7 +21,12 @@ def test_http_post(mock_post: MagicMock) -> None:
data="grant-type=client_credentials",
headers={"Content-type": "application/json"},
)
mock_post.assert_called_once()
mock_post.assert_called_once_with(
"https://www.canvasmedical.com/",
json={"hey": "hi"},
data="grant-type=client_credentials",
headers={"Content-type": "application/json"},
)


@patch("requests.Session.put")
Expand All @@ -31,7 +38,12 @@ def test_http_put(mock_put: MagicMock) -> None:
data="grant-type=client_credentials",
headers={"Content-type": "application/json"},
)
mock_put.assert_called_once()
mock_put.assert_called_once_with(
"https://www.canvasmedical.com/",
json={"hey": "hi"},
data="grant-type=client_credentials",
headers={"Content-type": "application/json"},
)


@patch("requests.Session.patch")
Expand All @@ -43,4 +55,9 @@ def test_http_patch(mock_patch: MagicMock) -> None:
data="grant-type=client_credentials",
headers={"Content-type": "application/json"},
)
mock_patch.assert_called_once()
mock_patch.assert_called_once_with(
"https://www.canvasmedical.com/",
json={"hey": "hi"},
data="grant-type=client_credentials",
headers={"Content-type": "application/json"},
)
Loading