Skip to content
Draft
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
28 changes: 28 additions & 0 deletions .github/workflows/schedule.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Scheduled tasks

on:
schedule:
- cron: '13 12 * * *'
workflow_dispatch:

jobs:
updatecli:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3

- run: pipx install poetry

- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.x'
cache: 'poetry'

- run: poetry install

- name: Run Updatecli in Apply mode
run: poetry run pytest
env:
PYTEST_ADDOPTS: ${{ secrets.PYTEST_ADDOPTS }}
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,26 @@ poetry install
poetry run pytest
```

## Testing

We run regular e2e acceptance tests on real data through pytest using our own ACRCloud account
as the data source.
These tests are scheduled to run at a regular interval in GitHub Actions with
[.github/workflows/schedule.yaml](./.github/workflows/schedule.yaml).

If you would like to run the acceptance test suite locally using your own key, you can supply
a bearer token on the command line:

```bash
poetry run pytest --acr-bearer-token="<bearer-token>"
```

To configure this in CI we use and recommend setting this via `PYTEST_ADDOPTS` env:

```bash
PYTEST_ADDOPTS='--acr-bearer-token="<bearer-token>"'
```

## Release Management

The CI/CD setup uses semantic commit messages following the [conventional commits standard](https://www.conventionalcommits.org/en/v1.0.0/).
Expand Down
129 changes: 106 additions & 23 deletions acrclient/client.py
Original file line number Diff line number Diff line change
@@ -1,37 +1,120 @@
import requests
from typing import Any, Optional

from requests import Session
from requests.adapters import HTTPAdapter, Retry
from requests.auth import AuthBase
from requests.models import PreparedRequest, Response

class Client:
"""ACRCloud client to fetch metadata.
from .models import (
GetBmCsProjectsResultsParams,
GetBmCsProjectsResultsResponse,
GetBmCsProjectsResultsResponseRecord,
ListBmCsProjectsParams,
ListBmCsProjectsResponse,
ListBmCsProjectsResponseRecord,
ListBmCsProjectsStreamsParams,
ListBmCsProjectsStreamsResponse,
ListBmCsProjectsStreamsResponseRecord,
)

Args:
bearer_token: The bearer token for ACRCloud.
"""

def __init__(self, bearer_token, base_url="https://eu-api-v2.acrcloud.com"):
self.base_url = base_url
class _Auth(AuthBase): # pylint: disable=too-few-public-methods
"""Bearer token style auth for ACRCloud."""

def __init__(self, bearer_token: str) -> None:
self.bearer_token = bearer_token

def request(self, path, headers=None, **kwargs):
"""Fetch JSON data from ACRCloud API with set Access Key param."""
def __call__(self, request: PreparedRequest) -> PreparedRequest:
request.headers["Authorization"] = f"Bearer {self.bearer_token}"
return request

url_params = {
**kwargs,
}
if not headers:
headers = {}
if self.bearer_token:
headers["Authorization"] = f"Bearer {self.bearer_token}"

response = requests.get(
url=f"{self.base_url}{path}", params=url_params, headers=headers, timeout=10

class Client:
"""ACRCloud client to fetch metadata."""
def __init__(
self,
bearer_token: str,
base_url: str = "https://api-v2.acrcloud.com",
retries: int = 5,
backoff_factor: float = 0.1,
):
"""
Parameters:
bearer_token: The bearer token for ACRCloud.
"""
self.base_url = base_url
self.auth = _Auth(bearer_token=bearer_token)
self._session = Session()
self._session.mount(
"https://",
HTTPAdapter(
max_retries=Retry(
total=retries,
backoff_factor=backoff_factor,
)
),
)

def get(
self,
path: str,
params: Any = None,
**kwargs,
) -> Response:
"""Fetch JSON data from ACRCloud API with set Access Key param."""
url = f"{self.base_url}{path}"
if not kwargs.get("timeout"):
kwargs["timeout"] = 60

# pylint: disable-next=missing-timeout
response = self._session.get(url=url, auth=self.auth, params=params, **kwargs)
response.raise_for_status()
return response

def json(
self,
path: str,
params: Any = None,
**kwargs,
) -> Any:
response = self.get(path, params=params, **kwargs)
return response.json()

def get_bm_cs_projects_results(self, project_id, stream_id, headers=None, **kwargs):
return self.request(
def list_bm_cs_projects(
self,
params: Optional[ListBmCsProjectsParams] = None,
**kwargs,
) -> ListBmCsProjectsResponse:
data = self.json(
path="/api/bm-cs-projects",
params=params,
**kwargs,
).get("data")
return [ListBmCsProjectsResponseRecord(**r) for r in data]

def list_bm_cs_projects_streams(
self,
project_id: int,
params: Optional[ListBmCsProjectsStreamsParams] = None,
**kwargs,
) -> ListBmCsProjectsStreamsResponse:
data = self.json(
path=f"/api/bm-cs-projects/{project_id}/streams",
params=params,
**kwargs,
).get("data")
return [ListBmCsProjectsStreamsResponseRecord(**r) for r in data]

def get_bm_cs_projects_results(
self,
project_id: int,
stream_id: str,
params: Optional[GetBmCsProjectsResultsParams] = None,
**kwargs,
) -> GetBmCsProjectsResultsResponse:
data = self.json(
path=f"/api/bm-cs-projects/{project_id}/streams/{stream_id}/results",
headers=headers,
params=params,
**kwargs,
).get("data")
return [GetBmCsProjectsResultsResponseRecord(**r) for r in data]
Loading