diff --git a/README.md b/README.md index 22049d46..59b5808c 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,12 @@ To install from pip: pip install pydo ``` +For async support, install with the `aio` extra: + +```shell + pip install pydo[aio] +``` + ## **`pydo` Quickstart** > A quick guide to getting started with the client. @@ -36,6 +42,22 @@ from pydo import Client client = Client(token=os.getenv("DIGITALOCEAN_TOKEN")) ``` +For asynchronous operations, use the `AsyncClient`: + +```python +import os +import asyncio +from pydo import AsyncClient + +async def main(): + client = AsyncClient(token=os.getenv("DIGITALOCEAN_TOKEN")) + # Use await for async operations + result = await client.ssh_keys.list() + print(result) + +asyncio.run(main()) +``` + #### Example of Using `pydo` to Access DO Resources Find below a working example for GETting a ssh_key ([per this http request](https://docs.digitalocean.com/reference/api/api-reference/#operation/sshKeys_list)) and printing the ID associated with the ssh key. If you'd like to try out this quick example, you can follow [these instructions](https://docs.digitalocean.com/products/droplets/how-to/add-ssh-keys/) to add ssh keys to your DO account. diff --git a/src/pydo/_patch.py b/src/pydo/_patch.py index 350d70fd..51296534 100644 --- a/src/pydo/_patch.py +++ b/src/pydo/_patch.py @@ -12,6 +12,7 @@ from pydo.custom_policies import CustomHttpLoggingPolicy from pydo import GeneratedClient, _version +from pydo.aio import AsyncClient if TYPE_CHECKING: # pylint: disable=unused-import,ungrouped-imports @@ -49,7 +50,7 @@ def __init__(self, token: str, *, timeout: int = 120, **kwargs): ) -__all__ = ["Client"] +__all__ = ["Client", "AsyncClient"] def patch_sdk(): diff --git a/src/pydo/aio/__init__.py b/src/pydo/aio/__init__.py index d3564a0d..ebf52ad7 100644 --- a/src/pydo/aio/__init__.py +++ b/src/pydo/aio/__init__.py @@ -13,8 +13,12 @@ _patch_all = [] from ._patch import patch_sdk as _patch_sdk +# Alias Client as AsyncClient for easier access +AsyncClient = Client + __all__ = [ "GeneratedClient", + "AsyncClient", ] __all__.extend([p for p in _patch_all if p not in __all__]) diff --git a/src/pydo/operations/_patch.py b/src/pydo/operations/_patch.py index 8a843f7c..2e1b836b 100644 --- a/src/pydo/operations/_patch.py +++ b/src/pydo/operations/_patch.py @@ -9,6 +9,8 @@ from typing import TYPE_CHECKING from ._operations import DropletsOperations as Droplets +from ._operations import KubernetesOperations as Kubernetes +from ._operations import InvoicesOperations as Invoices if TYPE_CHECKING: # pylint: disable=unused-import,ungrouped-imports @@ -25,3 +27,27 @@ def patch_sdk(): you can't accomplish using the techniques described in https://aka.ms/azsdk/python/dpcodegen/python/customize """ + + # Fix kubernetes.get_kubeconfig to return raw YAML content instead of trying to parse as JSON + def _get_kubeconfig(self, cluster_id, **kwargs): + """Get a Kubernetes config file for the specified cluster.""" + # Call the original method but with raw response + response = self._client.get( + f"/v2/kubernetes/clusters/{cluster_id}/kubeconfig", + **kwargs + ) + return response.content + + Kubernetes.get_kubeconfig = _get_kubeconfig + + # Fix invoices.get_pdf_by_uuid to return raw PDF content instead of trying to parse as JSON + def _get_pdf_by_uuid(self, invoice_uuid, **kwargs): + """Get a PDF invoice by UUID.""" + # Call the original method but with raw response + response = self._client.get( + f"/v2/customers/my/invoices/{invoice_uuid}/pdf", + **kwargs + ) + return response.content + + Invoices.get_pdf_by_uuid = _get_pdf_by_uuid diff --git a/tests/mocked/test_billing.py b/tests/mocked/test_billing.py index b787d502..b1576ed0 100644 --- a/tests/mocked/test_billing.py +++ b/tests/mocked/test_billing.py @@ -203,12 +203,11 @@ def test_get_invoice_pdf_by_uuid(mock_client: Client, mock_client_url): responses.add( responses.GET, f"{mock_client_url}/v2/customers/my/invoices/1/pdf", - json=expected, + body=expected, ) invoices = mock_client.invoices.get_pdf_by_uuid(invoice_uuid=1) - list_in = list(invoices) - assert "group_description" in str(list_in) + assert "group_description" in str(invoices) @responses.activate diff --git a/tests/mocked/test_kubernetes.py b/tests/mocked/test_kubernetes.py index 703ebb7c..7e785d0e 100644 --- a/tests/mocked/test_kubernetes.py +++ b/tests/mocked/test_kubernetes.py @@ -211,9 +211,6 @@ def test_kubernetes_get_kubeconfig(mock_client: Client, mock_client_url): ) config_resp = mock_client.kubernetes.get_kubeconfig(cluster_id) - pytest.skip("The operation currently fails to return content.") - # TODO: investigate why the generated client doesn't return the response content - # It seems to be something to do with the yaml content type. assert config_resp.decode("utf-8") == expected