{"id":28578180,"url":"https://github.com/digitalocean/pydo","last_synced_at":"2025-06-11T01:09:06.689Z","repository":{"id":62850471,"uuid":"362275050","full_name":"digitalocean/pydo","owner":"digitalocean","description":"Official DigitalOcean Python Client based on the DO OpenAPIv3 specification","archived":false,"fork":false,"pushed_at":"2025-06-04T17:55:55.000Z","size":8633,"stargazers_count":111,"open_issues_count":15,"forks_count":26,"subscribers_count":13,"default_branch":"main","last_synced_at":"2025-06-04T22:57:20.164Z","etag":null,"topics":["api","cloud","digitalocean","hacktoberfest","python"],"latest_commit_sha":null,"homepage":"https://pypi.org/project/pydo/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/digitalocean.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-04-27T23:04:08.000Z","updated_at":"2025-06-04T17:55:24.000Z","dependencies_parsed_at":"2024-03-28T16:29:09.037Z","dependency_job_id":"c45ef37c-97e6-436b-945c-c8ec5ed84352","html_url":"https://github.com/digitalocean/pydo","commit_stats":{"total_commits":146,"total_committers":13,"mean_commits":11.23076923076923,"dds":0.7465753424657534,"last_synced_commit":"d1ba95303dd6b6106ab0d5676b2f7cc8b5c0fa9f"},"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/digitalocean%2Fpydo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/digitalocean%2Fpydo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/digitalocean%2Fpydo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/digitalocean%2Fpydo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/digitalocean","download_url":"https://codeload.github.com/digitalocean/pydo/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/digitalocean%2Fpydo/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259178519,"owners_count":22817388,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","cloud","digitalocean","hacktoberfest","python"],"created_at":"2025-06-11T01:09:05.872Z","updated_at":"2025-06-11T01:09:06.658Z","avatar_url":"https://github.com/digitalocean.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# **PyDo**\n\n`pydo` is the official Python client library that allows\nPython developers to interact with and manage their DigitalOcean\nresources through a Python abstraction layer on top of the raw\n[DigitalOcean API HTTP Interface](https://developers.digitalocean.com/documentation/v2/).\n\nA top priority of this project is to ensure the client abides by the API\ncontract. Therefore, the client itself wraps a generated client based\non the [DigitalOcean OpenAPI Specification](https://github.com/digitalocean/openapi) to support all of DigitalOcean's HTTP APIs.\n\n# **Getting Started With the Client**\n\n## Prerequisites\n\n- Python version: \u003e= 3.7.2\n\n## Installation\n\nTo install from pip:\n\n```shell\n    pip install git+https://github.com/digitalocean/pydo.git\n```\n\nor, if repo is cloned locally:\n\n```shell\n    pip install /\u003cPATH\u003e/\u003cTO\u003e/pydo\n```\n\nTo install from source:\n\n```shell\nmake install\n```\n\n## **`pydo` Quickstart**\n\n\u003e A quick guide to getting started with the client.\n\n`pydo` must be initialized with `pydo.Client()`. A DigitalOcean API Token is required. The token can be passed explicitly to `pydo.Client()`, as such:\n\n```python\nimport os\nfrom pydo import Client\n\nclient = Client(token=os.getenv(\"DIGITALOCEAN_TOKEN\"))\n```\n\n#### Example of Using `pydo` to Access DO Resources\n\nFind 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.\n\n```python\nimport os\nfrom pydo import Client\n\nclient = Client(token=os.getenv(\"DIGITALOCEAN_TOKEN\"))\n\nssh_keys_resp = client.ssh_keys.list()\nfor k in ssh_keys_resp[\"ssh_keys\"]:\n    print(f\"ID: {k['id']}, NAME: {k['name']}, FINGERPRINT: {k['fingerprint']}\")\n```\n\nThe above code snippet should output the following:\n\n```shell\nID: 123456, NAME: my_test_ssh_key, FINGERPRINT: 5c:74:7e:60:28:69:34:ca:dd:74:67:c3:f3:00:7f:fe\nID: 123457, NAME: my_prod_ssh_key, FINGERPRINT: eb:76:c7:2a:d3:3e:80:5d:ef:2e:ca:86:d7:79:94:0d\n```\n\n**Consult the full list of supported DigitalOcean API endpoints in [PyDo's documentation](https://pydo.readthedocs.io/en/latest/).**\n\n**Note**: More working examples can be found [here](https://github.com/digitalocean/pydo/tree/main/examples).\n\n#### Pagination Example\n\nBelow is an example on handling pagination. One must parse the URL to find the\nnext page.\n\n```python\nimport os\nfrom pydo import Client\nfrom urllib.parse import urlparse, parse_qs\n\nclient = Client(token=os.getenv(\"DIGITALOCEAN_TOKEN\"))\n\npaginated = True\npage = 1\n\nwhile paginated:\n    resp = client.ssh_keys.list(per_page=50, page=page)\n\n    for k in resp[\"ssh_keys\"]:\n        print(f\"ID: {k['id']}, NAME: {k['name']}, FINGERPRINT: {k['fingerprint']}\")\n\n    pages = resp.get(\"links\", {}).get(\"pages\", {})\n    if \"next\" in pages:\n        parsed_url = urlparse(pages[\"next\"])\n        page = int(parse_qs(parsed_url.query)[\"page\"][0])\n    else:\n        paginated = False\n```\n\n#### Retries and Backoff\n\nBy default the client uses the same retry policy as the [Azure SDK for Python](https://learn.microsoft.com/en-us/python/api/azure-core/azure.core.pipeline.policies.retrypolicy?view=azure-python).\nretry policy. If you'd like to modify any of these values, you can pass them as keywords to your client initialization:\n\n```python\nclient = Client(token=os.getenv(\"DIGITALOCEAN_TOKEN\"), retry_total=3)\n```\n\nor\n\n```python\nclient = Client(token=os.getenv(\"DIGITALOCEAN_TOKEN\"), retry_policy=MyRetryPolicy())\n```\n\n# **Contributing**\n\n\u003eVisit our [Contribuing Guide](CONTRIBUTING.md) for more information on getting\ninvolved in developing this client.\n\n# **Tests**\n\n\u003eThe tests included in this repo are used to validate the generated client.\nWe use `pytest` to define and run the tests.\n\n**_Requirements_**\n\n- Python 3.7+\n  - Can be installed using something like\n    [pyenv](https://github.com/pyenv/pyenv)\n    - used to manage different installed versions of python.\n    - can also manage python virtual environments (with a plugin)\n  - [Poetry](https://python-poetry.org/docs/#installation).\n    - can also be configured to manage python virtual environments.\n\nThere are two types of test suites in the `tests/` directory.\n\n#### Mocked Tests: `tests/mocked/`\n\nTests in the `mocked` directory include:\n\n- tests that validate the generated client has all the expected classes and\n  methods for the respective API resources and operations.\n- tests that exercise individual operations against mocked responses.\n\nThese tests do not act against the real API so no real resources are created.\n\nTo run mocked tests, run:\n\n```shell\nmake test-mocked\n```\n\n#### Integration Tests: `tests/integration/`\n\nTests in the `integration` directory include tests that simulate specific\nscenarios a customer might use the client for to interact with the API.\n**_IMPORTANT:_** these tests require a valid API token and **_DO_** create real\nresources on the respective DigitalOcean account.\n\nTo run integration tests, run:\n\n```shell\nDIGITALOCEAN_TOKEN=... make test-integration\n```\n\n#### Test Customizations\n\nSome test values can be customized so integration tests can exercise different\nscenarios. For example, test use a default region to create resources. All the\ndefault values are managed in the\n[tests/integration/defaults.py](tests/integration/defaults.py) file. Any value\nthat has `environ.get()` can be overwritten by setting the respective environment\nvariable.\n\n#### Tests with Docker\n\nThe included Dockerfile is a developler convenience to test the package in\nisolation.\n\nTo use it, first build the image. Run:\n\n```shell\ndocker build -t pydo:dev .\n```\n\n##### Use the interactive python shell\n\nOpen the python shell:\n\n```shell\ndocker run -it --rm --name pydo pydo:dev python\n```\n\nThe above will launch an interactive python shell and display the following:\n\n```shell\nSkipping virtualenv creation, as specified in config file.\nPython 3.10.5 | packaged by conda-forge | (main, Jun 14 2022, 07:06:46) [GCC 10.3.0] on linux\nType \"help\", \"copyright\", \"credits\" or \"license\" for more information.\n\u003e\u003e\u003e\n```\n\nFrom here you can use the client interactively:\n\n```shell\n\u003e\u003e\u003e from pydo import Client\n\u003e\u003e\u003e c = Client(DIGITALOCEAN_TOKEN)\n\u003e\u003e\u003e c.droplets.list()\n```\n\nAlternatively, the tests can be run by attaching the tests as a volume and\nrunning pytest directly.\n\nRun:\n\n```shell\ndocker run -it --rm --name pydo -v $PWD/tests:/tests pydo:dev pytest tests/mocked\n```\n\n# **Known Issues**\n\n\u003eThis selection lists the known issues of the client generator.\n\n#### `kubernetes.get_kubeconfig` Does not serialize response content\n\nIn the generated python client, when calling client.kubernetes.get_kubeconfig(clust_id), the deserialization logic raises an error when the response content-type is applicaiton/yaml. We need to determine if the spec/schema can be configured such that the generator results in functions that properly handle the content. We will likely need to report the issue upstream to request support for the content-type.\n\n#### `invoices.get_pdf_by_uuid(invoice_uuid=invoice_uuid_param)` Does not return PDF\n\nIn the generated python client, when calling `invoices.get_pdf_by_uuid`, the response returns a Iterator[bytes] that does not format correctly into a PDF.\n\n#### Getting documentation via cli \"help(\u003cclient function\u003e)\"\n\nCurrently, calling the \"help(\u003cclient function\u003e)\" includes the API documentation for the respective operation which is substantial and can be confusing in the context of this client.\n\n#### projects.delete(project_id=project_id) expects a request body\n\nThis is a backend issue with the API endpoint. The API endpoint expects the header `content-type: application/json` to be set. If you do not set it you will receive a 415. Since the endpoint doesn't require a request or response body, it is an unnecessary header. For this to work in Pydo, ensure `application/json` header is passed in, as such:\n\n```python\n    custom_headers = {\"Content-Type\": \"application/json\"}\n    delete_resp = client.projects.delete(\n        headers=custom_headers, project_id=project_id\n    )\n```\n\n# **Roadmap**\n\n\u003eThis section lists short-term and long-term goals for the project.\n**Note**: These are goals, not necessarily commitments. The sections are not intended to represent exclusive focus during these terms.\n\nShort term:\n\n\u003e Usability, stability, and marketing.\n\nShort term, we are focused on improving usability and user productivity (part of this is getting the word out).\n\n- Documentation\n  - Support an automated process for creating comprehensive documentation that explains working of codes\n  - Support a clean cli `help(\u003cclient function\u003e)` documentation solution\n- Release stability\n  - define release strategy\n  - pip release\n\nLong term:\n\n\u003e Model support, expand on supporting functions\n\n- The client currently inputs and outputs JSON dictionaries. Adding models would unlock features such as typing and validation.\n- Add supporting functions to elevate customer experience (i.e. adding a funtion that surfaces IP address for a Droplet)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdigitalocean%2Fpydo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdigitalocean%2Fpydo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdigitalocean%2Fpydo/lists"}