From b060028974cf9532e5647118bf9b11057f783b63 Mon Sep 17 00:00:00 2001
From: Shane <6071159+smashedr@users.noreply.github.com>
Date: Sat, 29 Nov 2025 14:15:27 -0800
Subject: [PATCH 01/24] Add Arbitrary Methods
---
README.md | 13 ++++++++++++-
build.ps1 | 48 ++++++++++++++++++++++++++++++++++++++++++++++
docs.ps1 | 38 ++++++++++++++++++++++++++++++++++++
docs/index.md | 11 +++++++++++
src/vultr/py.typed | 0
src/vultr/vultr.py | 26 ++++++++++++++++++-------
6 files changed, 128 insertions(+), 8 deletions(-)
create mode 100644 build.ps1
create mode 100644 docs.ps1
create mode 100644 src/vultr/py.typed
diff --git a/README.md b/README.md
index 06c1747..4a7493d 100644
--- a/README.md
+++ b/README.md
@@ -20,7 +20,7 @@
# Vultr Python
-
+
- [Install](#Install)
- [Usage](#Usage)
@@ -110,6 +110,17 @@ data = {
instance = vultr.create_instance(**data)
```
+Arbitrary Methods `get`, `post`, `patch`, `delete`
+
+```python
+# vultr.list_instances()
+instances = vultr.get('instances')
+# vultr.create_key()
+sshkey = vultr.post('ssh-keys', {"name": 'key-name', "ssh_key": 'ssh-rsa AAAA...'})
+# vultr.delete_instance()
+vultr.delete(f"instances/019ad1a8-2aa3-7650-83d1-8520d65ed6af")
+```
+
Full Documentation: [https://cssnr.github.io/vultr-python](https://cssnr.github.io/vultr-python)
Vultr API Reference: [https://www.vultr.com/api](https://www.vultr.com/api/?ref=6905748)
diff --git a/build.ps1 b/build.ps1
new file mode 100644
index 0000000..5db65bf
--- /dev/null
+++ b/build.ps1
@@ -0,0 +1,48 @@
+param (
+ [switch]$c,
+ [switch]$i,
+ [switch]$u
+)
+
+$ErrorActionPreference = "Stop"
+
+write-output "Clean: $c"
+write-output "Install: $i"
+write-output "Uninstall: $u"
+
+if ($u) {
+ Write-Host -ForegroundColor Red "Uninstalling..."
+ python -m pip uninstall -y vultr-python
+}
+
+$egg_dir = ".\src\*.egg-info"
+if (Test-Path $egg_dir) {
+ Write-Host -ForegroundColor Cyan "Removing: $egg_dir"
+ Remove-Item -Force -Recurse $egg_dir
+}
+$cache_dir = ".\src\*\__pycache__"
+if (Test-Path $cache_dir) {
+ Write-Host -ForegroundColor Cyan "Removing: $cache_dir"
+ Remove-Item -Force -Recurse $cache_dir
+}
+if (Test-Path ".\dist") {
+ Write-Host -ForegroundColor Cyan "Removing: .\dist"
+ Remove-Item -Force -Recurse ".\dist"
+}
+if (Test-Path ".\build") {
+ Write-Host -ForegroundColor Cyan "Removing: .\build"
+ Remove-Item -Force -Recurse ".\build"
+}
+if ($c) {
+ Write-Host -ForegroundColor Yellow "Clean Only. Not Building or Installing!"
+ exit
+}
+
+python -m build
+
+if ($args[0] -eq "i") {
+ Write-Host -ForegroundColor Green "Installing..."
+ python -m pip install .\dist\vultr_python-0.0.1-py3-none-any.whl
+}
+
+Write-Output "Success."
diff --git a/docs.ps1 b/docs.ps1
new file mode 100644
index 0000000..4d0d955
--- /dev/null
+++ b/docs.ps1
@@ -0,0 +1,38 @@
+param (
+ [switch]$c,
+ [switch]$b
+)
+
+$ErrorActionPreference = "Stop"
+
+write-output "Clean: $c"
+write-output "Build: $b"
+
+if ($c) {
+ Write-Host -ForegroundColor Yellow "Cleaning Docs..."
+ $site_dir = ".\site"
+ if (Test-Path $site_dir) {
+ Write-Host -ForegroundColor Cyan "Removing: $site_dir"
+ Remove-Item -Force -Recurse $site_dir
+ }
+ $cache_dir = ".\.cache"
+ if (Test-Path $cache_dir) {
+ Write-Host -ForegroundColor Cyan "Removing: $cache_dir"
+ Remove-Item -Force -Recurse $cache_dir
+ }
+}
+
+python -m pdoc -t .\docs\ -p 8008 `
+ --favicon "https://df.cssnr.com/raw/logo128.png" `
+ --logo "https://df.cssnr.com/raw/logo128.png" `
+ --logo-link "https://github.com/cssnr/vultr-python" `
+ vultr
+
+#-e "vultr=https://github.com/cssnr/vultr-python/blob/updates/src/vultr/" `
+
+#if ($b) {
+# Write-Host -ForegroundColor Green "Building Docs..."
+# zensical build
+#} else {
+# zensical serve
+#}
diff --git a/docs/index.md b/docs/index.md
index 2cab29c..886ed4f 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -88,6 +88,17 @@ data = {
instance = vultr.create_instance(**data)
```
+Arbitrary Methods `get`, `post`, `patch`, `delete`
+
+```python
+# vultr.list_instances()
+instances = vultr.get('instances')
+# vultr.create_key()
+sshkey = vultr.post('ssh-keys', {"name": 'key-name', "ssh_key": 'ssh-rsa AAAA...'})
+# vultr.delete_instance()
+vultr.delete(f"instances/019ad1a8-2aa3-7650-83d1-8520d65ed6af")
+```
+
Vultr API Reference: [https://www.vultr.com/api](https://www.vultr.com/api/?ref=6905748)
diff --git a/src/vultr/py.typed b/src/vultr/py.typed
new file mode 100644
index 0000000..e69de29
diff --git a/src/vultr/vultr.py b/src/vultr/vultr.py
index 96f0b50..f62675a 100644
--- a/src/vultr/vultr.py
+++ b/src/vultr/vultr.py
@@ -9,12 +9,24 @@ class Vultr(object):
def __init__(self, api_key: Optional[str] = None):
"""
- :param str api_key: Vultr API Key or VULTR_API_KEY environment variable
+ :param str api_key: Vultr API Key or VULTR_API_KEY Environment Variable
"""
self.api_key = api_key or os.getenv("VULTR_API_KEY")
- self.s = requests.session()
+ self._session = requests.session()
if self.api_key:
- self.s.headers.update({"Authorization": f"Bearer {self.api_key}"})
+ self._session.headers.update({"Authorization": f"Bearer {self.api_key}"})
+
+ def get(self, url: str):
+ return self._get(f"{self.url}/{url.lstrip('/')}")
+
+ def post(self, url: str, **kwargs):
+ return self._post(f"{self.url}/{url.lstrip('/')}", kwargs)
+
+ def patch(self, url: str, **kwargs):
+ return self._patch(f"{self.url}/{url.lstrip('/')}", kwargs)
+
+ def delete(self, url: str):
+ return self._delete(f"{self.url}/{url.lstrip('/')}")
def list_os(self):
url = f"{self.url}/os"
@@ -144,25 +156,25 @@ def filter_regions(regions: list, locations: list) -> list:
return [d for d in regions if d["id"] in locations]
def _get(self, url):
- r = self.s.get(url, timeout=10)
+ r = self._session.get(url, timeout=10)
if not r.ok:
r.raise_for_status()
return r.json()
def _post(self, url, data):
- r = self.s.post(url, json=data, timeout=10)
+ r = self._session.post(url, json=data, timeout=10)
if not r.ok:
r.raise_for_status()
return r.json()
def _patch(self, url, data):
- r = self.s.patch(url, json=data, timeout=10)
+ r = self._session.patch(url, json=data, timeout=10)
if not r.ok:
r.raise_for_status()
return r.json()
def _delete(self, url):
- r = self.s.delete(url, timeout=10)
+ r = self._session.delete(url, timeout=10)
if not r.ok:
r.raise_for_status()
return None
From 659abf3fed1bca3c4dd110c8250d6cf7a01a15f6 Mon Sep 17 00:00:00 2001
From: Shane <6071159+smashedr@users.noreply.github.com>
Date: Sat, 29 Nov 2025 14:26:06 -0800
Subject: [PATCH 02/24] Add Workflow Permissions
---
.github/workflows/build.yaml | 3 +++
.github/workflows/docs.yaml | 3 +++
.github/workflows/release.yaml | 6 ++++++
3 files changed, 12 insertions(+)
diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
index 0371331..0780dc7 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -18,6 +18,9 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 5
+ permissions:
+ contents: read
+
steps:
- name: "Checkout"
uses: actions/checkout@v6
diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml
index 21272c5..3e5aa85 100644
--- a/.github/workflows/docs.yaml
+++ b/.github/workflows/docs.yaml
@@ -22,6 +22,9 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 5
+ permissions:
+ contents: read
+
steps:
- name: "Checkout"
uses: actions/checkout@v5
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index 6c917d7..4b6e6b9 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -16,6 +16,9 @@ jobs:
with:
name: "release"
+ permissions:
+ contents: read
+
publish:
name: "Publish"
runs-on: ubuntu-latest
@@ -107,6 +110,9 @@ jobs:
timeout-minutes: 5
needs: [publish]
+ permissions:
+ contents: write
+
steps:
- name: "Debug"
continue-on-error: true
From 08371e82ccafd9dcd6945303be66585ce5a3e6f6 Mon Sep 17 00:00:00 2001
From: Shane <6071159+smashedr@users.noreply.github.com>
Date: Sat, 29 Nov 2025 14:38:53 -0800
Subject: [PATCH 03/24] Update Docs
---
README.md | 2 +-
docs/index.md | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 4a7493d..880e8cb 100644
--- a/README.md
+++ b/README.md
@@ -116,7 +116,7 @@ Arbitrary Methods `get`, `post`, `patch`, `delete`
# vultr.list_instances()
instances = vultr.get('instances')
# vultr.create_key()
-sshkey = vultr.post('ssh-keys', {"name": 'key-name', "ssh_key": 'ssh-rsa AAAA...'})
+sshkey = vultr.post('ssh-keys', name='key-name', ssh_key='ssh-rsa AAAA...')
# vultr.delete_instance()
vultr.delete(f"instances/019ad1a8-2aa3-7650-83d1-8520d65ed6af")
```
diff --git a/docs/index.md b/docs/index.md
index 886ed4f..0b12470 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -94,7 +94,7 @@ Arbitrary Methods `get`, `post`, `patch`, `delete`
# vultr.list_instances()
instances = vultr.get('instances')
# vultr.create_key()
-sshkey = vultr.post('ssh-keys', {"name": 'key-name', "ssh_key": 'ssh-rsa AAAA...'})
+sshkey = vultr.post('ssh-keys', name='key-name', ssh_key='ssh-rsa AAAA...')
# vultr.delete_instance()
vultr.delete(f"instances/019ad1a8-2aa3-7650-83d1-8520d65ed6af")
```
From a7779aff15a7a5fb46347319e8644a9488570e87 Mon Sep 17 00:00:00 2001
From: Shane <6071159+smashedr@users.noreply.github.com>
Date: Sat, 29 Nov 2025 15:29:28 -0800
Subject: [PATCH 04/24] Update Docs
---
README.md | 2 ++
docs/index.md | 2 ++
2 files changed, 4 insertions(+)
diff --git a/README.md b/README.md
index 880e8cb..ea67536 100644
--- a/README.md
+++ b/README.md
@@ -121,6 +121,8 @@ sshkey = vultr.post('ssh-keys', name='key-name', ssh_key='ssh-rsa AAAA...')
vultr.delete(f"instances/019ad1a8-2aa3-7650-83d1-8520d65ed6af")
```
+These methods take the URI as the first argument, and data kwargs as the second.
+
Full Documentation: [https://cssnr.github.io/vultr-python](https://cssnr.github.io/vultr-python)
Vultr API Reference: [https://www.vultr.com/api](https://www.vultr.com/api/?ref=6905748)
diff --git a/docs/index.md b/docs/index.md
index 0b12470..91b1dd9 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -99,6 +99,8 @@ sshkey = vultr.post('ssh-keys', name='key-name', ssh_key='ssh-rsa AAAA...')
vultr.delete(f"instances/019ad1a8-2aa3-7650-83d1-8520d65ed6af")
```
+These methods take the URI as the first argument, and data kwargs as the second.
+
Vultr API Reference: [https://www.vultr.com/api](https://www.vultr.com/api/?ref=6905748)
From 7b2b1a74ded3b650cb56110855fda03c0ec2db9e Mon Sep 17 00:00:00 2001
From: Shane <6071159+smashedr@users.noreply.github.com>
Date: Sat, 29 Nov 2025 17:08:29 -0800
Subject: [PATCH 05/24] Add Query Params and Basic Functionality Test
---
.github/workflows/test.yaml | 86 +++++++++++++++++++++++++++++++++++++
README.md | 21 ++++-----
docs/index.md | 21 ++++-----
src/vultr/vultr.py | 54 ++++++++++++-----------
tests/test_all.py | 10 +++++
5 files changed, 142 insertions(+), 50 deletions(-)
create mode 100644 .github/workflows/test.yaml
create mode 100644 tests/test_all.py
diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml
new file mode 100644
index 0000000..26b4f8e
--- /dev/null
+++ b/.github/workflows/test.yaml
@@ -0,0 +1,86 @@
+name: "Test"
+
+on:
+ workflow_dispatch:
+ push:
+ branches: [master]
+ #paths: &paths
+ paths:
+ - ".github/workflows/test.yaml"
+ - "src/**"
+ - "tests/**"
+ - "pyproject.toml"
+ #pull_request:
+ # paths: *paths
+
+jobs:
+ build:
+ name: "Build"
+ if: ${{ !contains(github.event.head_commit.message, '#notest') }}
+ uses: ./.github/workflows/build.yaml
+ with:
+ name: test
+
+ permissions:
+ contents: read
+
+ test:
+ runs-on: ubuntu-latest
+ timeout-minutes: 5
+ needs: [build]
+ strategy:
+ fail-fast: false
+ matrix:
+ version: ["3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
+ name: "Test ${{ matrix.version }}"
+
+ permissions:
+ contents: read
+
+ steps:
+ - name: "Checkout"
+ uses: actions/checkout@v6
+
+ - name: "Debug event.json"
+ if: ${{ !github.event.act }}
+ continue-on-error: true
+ run: cat "${GITHUB_EVENT_PATH}"
+
+ - name: "Debug CTX github"
+ if: ${{ !github.event.act }}
+ continue-on-error: true
+ env:
+ GITHUB_CTX: ${{ toJSON(github) }}
+ run: echo "$GITHUB_CTX"
+
+ - name: "Debug Environment"
+ if: ${{ !github.event.act }}
+ continue-on-error: true
+ run: env
+
+ - name: "Download Artifact"
+ uses: actions/download-artifact@v6
+ with:
+ name: test
+ path: dist
+
+ - name: "Setup Python ${{ matrix.version }}"
+ uses: actions/setup-python@v6
+ with:
+ python-version: ${{ matrix.version }}
+ cache: "pip"
+
+ - name: "Install ${{ matrix.version }}"
+ run: |
+ python -V
+ python -m pip install -U pip pytest
+ python -m pip install dist/*.whl
+
+ #- name: "Debug ${{ matrix.version }}"
+ # run: |
+ # ls -lAhR dist/
+
+ - name: "Test ${{ matrix.version }}"
+ #continue-on-error: ${{ contains('dev', matrix.version) }}
+ run: |
+ pytest -s
diff --git a/README.md b/README.md
index ea67536..945d0c8 100644
--- a/README.md
+++ b/README.md
@@ -76,8 +76,8 @@ vultr = Vultr('VULTR_API_KEY')
List plans and get available regions for that plan
```python
-plans = vultr.list_plans()
-plan = plans[0] # 0 seems to be the basic 5 dollar plan
+plans = vultr.list_plans({'type': 'vc2'}) # vc2 - Cloud Compute
+plan = plans[0] # 0 seems to be the base plan
regions = vultr.list_regions()
available = vultr.filter_regions(regions, plan['locations'])
```
@@ -98,26 +98,23 @@ sshkey = vultr.create_key('key-name', 'ssh-rsa AAAA...')
Create a new instance
```python
-hostname = 'my-new-host'
data = {
- 'region': available[0]['id'],
- 'plan': plan['id'],
'os_id': ubuntu_lts['id'],
'sshkey_id': [sshkey['id']],
- 'hostname': hostname,
- 'label': hostname,
+ 'hostname': 'my-new-host',
+ 'label': 'my-new-host',
}
-instance = vultr.create_instance(**data)
+instance = vultr.create_instance(available[0], plan, **data)
```
Arbitrary Methods `get`, `post`, `patch`, `delete`
```python
-# vultr.list_instances()
-instances = vultr.get('instances')
-# vultr.create_key()
+# vultr.get('url', params)
+instances = vultr.get('instances', {'type': 'vc2'})
+# vultr.post('url', **kwargs)
sshkey = vultr.post('ssh-keys', name='key-name', ssh_key='ssh-rsa AAAA...')
-# vultr.delete_instance()
+# vultr.delete('url')
vultr.delete(f"instances/019ad1a8-2aa3-7650-83d1-8520d65ed6af")
```
diff --git a/docs/index.md b/docs/index.md
index 91b1dd9..627a3c2 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -54,8 +54,8 @@ vultr = Vultr('VULTR_API_KEY')
List plans and get available regions for that plan
```python
-plans = vultr.list_plans()
-plan = plans[0] # 0 seems to be the basic 5 dollar plan
+plans = vultr.list_plans({'type': 'vc2'}) # vc2 - Cloud Compute
+plan = plans[0] # 0 seems to be the base plan
regions = vultr.list_regions()
available = vultr.filter_regions(regions, plan['locations'])
```
@@ -76,26 +76,23 @@ sshkey = vultr.create_key('key-name', 'ssh-rsa AAAA...')
Create a new instance
```python
-hostname = 'my-new-host'
data = {
- 'region': available[0]['id'],
- 'plan': plan['id'],
'os_id': ubuntu_lts['id'],
'sshkey_id': [sshkey['id']],
- 'hostname': hostname,
- 'label': hostname,
+ 'hostname': 'my-new-host',
+ 'label': 'my-new-host',
}
-instance = vultr.create_instance(**data)
+instance = vultr.create_instance(available[0], plan, **data)
```
Arbitrary Methods `get`, `post`, `patch`, `delete`
```python
-# vultr.list_instances()
-instances = vultr.get('instances')
-# vultr.create_key()
+# vultr.get('url', params)
+instances = vultr.get('instances', {'type': 'vc2'})
+# vultr.post('url', **kwargs)
sshkey = vultr.post('ssh-keys', name='key-name', ssh_key='ssh-rsa AAAA...')
-# vultr.delete_instance()
+# vultr.delete('url')
vultr.delete(f"instances/019ad1a8-2aa3-7650-83d1-8520d65ed6af")
```
diff --git a/src/vultr/vultr.py b/src/vultr/vultr.py
index f62675a..76bc79a 100644
--- a/src/vultr/vultr.py
+++ b/src/vultr/vultr.py
@@ -16,8 +16,8 @@ def __init__(self, api_key: Optional[str] = None):
if self.api_key:
self._session.headers.update({"Authorization": f"Bearer {self.api_key}"})
- def get(self, url: str):
- return self._get(f"{self.url}/{url.lstrip('/')}")
+ def get(self, url: str, params: Optional[dict] = None):
+ return self._get(f"{self.url}/{url.lstrip('/')}", params)
def post(self, url: str, **kwargs):
return self._post(f"{self.url}/{url.lstrip('/')}", kwargs)
@@ -28,29 +28,31 @@ def patch(self, url: str, **kwargs):
def delete(self, url: str):
return self._delete(f"{self.url}/{url.lstrip('/')}")
- def list_os(self):
+ def list_os(self, params: Optional[dict] = None):
url = f"{self.url}/os"
- return self._get(url)["os"]
+ return self._get(url, params)["os"]
- def list_plans(self):
+ def list_plans(self, params: Optional[dict] = None):
url = f"{self.url}/plans"
- return self._get(url)["plans"]
+ return self._get(url, params)["plans"]
- def list_regions(self):
+ def list_regions(self, params: Optional[dict] = None):
url = f"{self.url}/regions"
- return self._get(url)["regions"]
+ return self._get(url, params)["regions"]
- def list_instances(self):
+ def list_instances(self, params: Optional[dict] = None):
url = f"{self.url}/instances"
- return self._get(url)["instances"]
+ return self._get(url, params)["instances"]
- def get_instance(self, instance: Union[str, dict]):
+ def get_instance(self, instance: Union[str, dict], params: Optional[dict] = None):
instance_id = self._get_obj_key(instance)
url = f"{self.url}/instances/{instance_id}"
- return self._get(url)["instance"]
+ return self._get(url, params)["instance"]
- def create_instance(self, region: str, plan: str, **kwargs):
- data = {"region": region, "plan": plan}
+ def create_instance(
+ self, region: Union[str, dict], plan: Union[str, dict], **kwargs
+ ):
+ data = {"region": self._get_obj_key(region), "plan": self._get_obj_key(plan)}
data.update(kwargs)
url = f"{self.url}/instances"
return self._post(url, data)["instance"]
@@ -65,14 +67,14 @@ def delete_instance(self, instance: Union[str, dict]):
url = f"{self.url}/instances/{instance_id}"
return self._delete(url)
- def list_keys(self):
+ def list_keys(self, params: Optional[dict] = None):
url = f"{self.url}/ssh-keys"
- return self._get(url)["ssh_keys"]
+ return self._get(url, params)["ssh_keys"]
- def get_key(self, key: Union[str, dict]):
+ def get_key(self, key: Union[str, dict], params: Optional[dict] = None):
key_id = self._get_obj_key(key)
url = f"{self.url}/ssh-keys/{key_id}"
- return self._get(url)["ssh_key"]
+ return self._get(url, params)["ssh_key"]
def create_key(self, name: str, key: str, **kwargs):
data = {"name": name, "ssh_key": key}
@@ -90,14 +92,14 @@ def delete_key(self, key: Union[str, dict]):
url = f"{self.url}/ssh-keys/{key_id}"
return self._delete(url)
- def list_scripts(self):
+ def list_scripts(self, params: Optional[dict] = None):
url = f"{self.url}/startup-scripts"
- return self._get(url)["startup_scripts"]
+ return self._get(url, params)["startup_scripts"]
- def get_script(self, script: Union[str, dict]):
+ def get_script(self, script: Union[str, dict], params: Optional[dict] = None):
script_id = self._get_obj_key(script)
url = f"{self.url}/startup-scripts/{script_id}"
- return self._get(url)["startup_script"]
+ return self._get(url, params)["startup_script"]
def create_script(self, name: str, script: str, **kwargs):
data = {"name": name, "script": script}
@@ -115,10 +117,10 @@ def delete_script(self, script: Union[str, dict]):
url = f"{self.url}/startup-scripts/{script_id}"
return self._delete(url)
- def list_ipv4(self, instance: Union[str, dict]):
+ def list_ipv4(self, instance: Union[str, dict], params: Optional[dict] = None):
instance_id = self._get_obj_key(instance)
url = f"{self.url}/instances/{instance_id}/ipv4"
- return self._get(url)["ipv4s"]
+ return self._get(url, params)["ipv4s"]
def create_ipv4(self, instance: Union[str, dict], **kwargs):
instance_id = self._get_obj_key(instance)
@@ -155,8 +157,8 @@ def filter_scripts(scripts: list, name: str) -> dict:
def filter_regions(regions: list, locations: list) -> list:
return [d for d in regions if d["id"] in locations]
- def _get(self, url):
- r = self._session.get(url, timeout=10)
+ def _get(self, url, params: Optional[dict] = None):
+ r = self._session.get(url, params=params, timeout=10)
if not r.ok:
r.raise_for_status()
return r.json()
diff --git a/tests/test_all.py b/tests/test_all.py
new file mode 100644
index 0000000..a4ec506
--- /dev/null
+++ b/tests/test_all.py
@@ -0,0 +1,10 @@
+from vultr import Vultr
+
+
+vultr = Vultr()
+
+
+def test_free():
+ per_page = 100
+ plans = vultr.get("plans", {"type": "vc2", "per_page": per_page})
+ assert len(plans["plans"]) == min(plans["meta"]["total"], per_page)
From 4d40e332c6ce7cc7b03ebb2d69b33ba9466edaaf Mon Sep 17 00:00:00 2001
From: Shane <6071159+smashedr@users.noreply.github.com>
Date: Sat, 29 Nov 2025 17:12:40 -0800
Subject: [PATCH 06/24] Test
---
.github/workflows/test.yaml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml
index 26b4f8e..ac6ce3f 100644
--- a/.github/workflows/test.yaml
+++ b/.github/workflows/test.yaml
@@ -3,7 +3,7 @@ name: "Test"
on:
workflow_dispatch:
push:
- branches: [master]
+ #branches: [master]
#paths: &paths
paths:
- ".github/workflows/test.yaml"
From ee11706db8dc759f2be8fe4d6ab951918300f5e3 Mon Sep 17 00:00:00 2001
From: Shane <6071159+smashedr@users.noreply.github.com>
Date: Sat, 29 Nov 2025 17:43:27 -0800
Subject: [PATCH 07/24] Drop Support for 3.6
---
.github/workflows/test.yaml | 4 ++--
pyproject.toml | 2 +-
src/vultr/vultr.py | 4 +---
tests/test_all.py | 9 +++++++++
4 files changed, 13 insertions(+), 6 deletions(-)
diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml
index ac6ce3f..afd74f8 100644
--- a/.github/workflows/test.yaml
+++ b/.github/workflows/test.yaml
@@ -25,13 +25,13 @@ jobs:
contents: read
test:
- runs-on: ubuntu-latest
+ runs-on: ubuntu-22.04
timeout-minutes: 5
needs: [build]
strategy:
fail-fast: false
matrix:
- version: ["3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
+ version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
name: "Test ${{ matrix.version }}"
permissions:
diff --git a/pyproject.toml b/pyproject.toml
index 47d3620..f4ea224 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -5,7 +5,7 @@ description = "Python 3 wrapper for the Vultr API v2.0"
authors = [{ name="Shane" }]
readme = "README.md"
dynamic = ["version"]
-requires-python = ">=3.6"
+requires-python = ">=3.7"
classifiers = [
"Programming Language :: Python",
"Programming Language :: Python :: 3",
diff --git a/src/vultr/vultr.py b/src/vultr/vultr.py
index 76bc79a..879ddc9 100644
--- a/src/vultr/vultr.py
+++ b/src/vultr/vultr.py
@@ -49,9 +49,7 @@ def get_instance(self, instance: Union[str, dict], params: Optional[dict] = None
url = f"{self.url}/instances/{instance_id}"
return self._get(url, params)["instance"]
- def create_instance(
- self, region: Union[str, dict], plan: Union[str, dict], **kwargs
- ):
+ def create_instance(self, region: Union[str, dict], plan: Union[str, dict], **kwargs):
data = {"region": self._get_obj_key(region), "plan": self._get_obj_key(plan)}
data.update(kwargs)
url = f"{self.url}/instances"
diff --git a/tests/test_all.py b/tests/test_all.py
index a4ec506..f8c4a0f 100644
--- a/tests/test_all.py
+++ b/tests/test_all.py
@@ -7,4 +7,13 @@
def test_free():
per_page = 100
plans = vultr.get("plans", {"type": "vc2", "per_page": per_page})
+ print(f"plans: {len(plans['plans'])}")
assert len(plans["plans"]) == min(plans["meta"]["total"], per_page)
+
+ regions = vultr.list_regions({"per_page": per_page})
+ print(f"regions: {len(regions)}")
+ assert 0 < len(regions) <= per_page
+
+ available = vultr.filter_regions(regions, plans["plans"][0]["locations"])
+ print(f"available: {len(available)}")
+ assert 0 < len(available) <= per_page
From fe62469c59cf7b09b10fa1e408261be77a6b8594 Mon Sep 17 00:00:00 2001
From: Shane <6071159+smashedr@users.noreply.github.com>
Date: Sat, 29 Nov 2025 18:07:55 -0800
Subject: [PATCH 08/24] Add coverage
---
.github/workflows/lint.yaml | 26 +++++++++++++-------------
README.md | 10 ++++++----
2 files changed, 19 insertions(+), 17 deletions(-)
diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml
index 7dfc8cd..0e8b52f 100644
--- a/.github/workflows/lint.yaml
+++ b/.github/workflows/lint.yaml
@@ -137,19 +137,19 @@ jobs:
echo "::endgroup::"
"${RUNNER_TEMP}/actionlint" -color -verbose -shellcheck= -pyflakes=
- #- name: "pytest"
- # if: ${{ !cancelled() }}
- # id: coverage
- # run: |
- # coverage run -m pytest
- # coverage xml
- # coverage report -m
-
- #- name: "codecov"
- # if: ${{ !cancelled() && steps.coverage.outcome == 'success' }}
- # uses: codecov/codecov-action@v5
- # with:
- # token: ${{ secrets.CODECOV_TOKEN }}
+ - name: "pytest"
+ if: ${{ !cancelled() }}
+ id: coverage
+ run: |
+ coverage run -m pytest
+ coverage xml
+ coverage report -m
+
+ - name: "codecov"
+ if: ${{ !cancelled() && steps.coverage.outcome == 'success' }}
+ uses: codecov/codecov-action@v5
+ with:
+ token: ${{ secrets.CODECOV_TOKEN }}
#- name: "hadolint"
# if: ${{ !cancelled() }}
diff --git a/README.md b/README.md
index 945d0c8..33c73e4 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,9 @@
[](https://app.codacy.com/gh/cssnr/vultr-python/dashboard)
[](https://sonarcloud.io/summary/new_code?id=cssnr_vultr-python)
[](https://github.com/cssnr/vultr-python/actions/workflows/lint.yaml)
-[](https://cssnr.github.io/vultr-python)
+[](https://github.com/cssnr/vultr-python/actions/workflows/test.yaml)
+[](https://pypi.org/project/vultr-python/)
+[](https://cssnr.github.io/vultr-python/)
[](https://github.com/cssnr/vultr-python/graphs/commit-activity)
[](https://github.com/cssnr/vultr-python)
[](https://github.com/cssnr/vultr-python?tab=readme-ov-file#readme)
@@ -19,7 +21,7 @@
# Vultr Python
-
+
- [Install](#Install)
@@ -31,7 +33,7 @@ Python 3 wrapper for the Vultr API v2.
[](https://github.com/cssnr/vultr-python?tab=readme-ov-file#readme)
[](https://pypi.org/project/vultr-python)
-[](https://cssnr.github.io/vultr-python)
+[](https://cssnr.github.io/vultr-python/)
[](https://www.vultr.com/api/?ref=6905748)
Vultr API Reference: [https://www.vultr.com/api](https://www.vultr.com/api/?ref=6905748)
@@ -120,7 +122,7 @@ vultr.delete(f"instances/019ad1a8-2aa3-7650-83d1-8520d65ed6af")
These methods take the URI as the first argument, and data kwargs as the second.
-Full Documentation: [https://cssnr.github.io/vultr-python](https://cssnr.github.io/vultr-python)
+Full Documentation: [https://cssnr.github.io/vultr-python](https://cssnr.github.io/vultr-python/)
Vultr API Reference: [https://www.vultr.com/api](https://www.vultr.com/api/?ref=6905748)
From fd0bf2d118d1788b2a7f37385c5feec0f27ebf4d Mon Sep 17 00:00:00 2001
From: Shane <6071159+smashedr@users.noreply.github.com>
Date: Sat, 29 Nov 2025 18:10:28 -0800
Subject: [PATCH 09/24] Add pytest to dev
---
pyproject.toml | 1 +
1 file changed, 1 insertion(+)
diff --git a/pyproject.toml b/pyproject.toml
index f4ea224..6f3b1a4 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -36,6 +36,7 @@ dev = [
"coverage",
"isort",
"mypy",
+ "pytest",
"requests",
"ruff",
"setuptools",
From f1fccce0c1e0d755a282e318b013aef7c7a08080 Mon Sep 17 00:00:00 2001
From: Shane <6071159+smashedr@users.noreply.github.com>
Date: Sat, 29 Nov 2025 18:18:01 -0800
Subject: [PATCH 10/24] Update test on
---
.github/workflows/test.yaml | 9 ++++-----
README.md | 2 --
docs/index.md | 2 --
3 files changed, 4 insertions(+), 9 deletions(-)
diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml
index afd74f8..e61026f 100644
--- a/.github/workflows/test.yaml
+++ b/.github/workflows/test.yaml
@@ -3,15 +3,14 @@ name: "Test"
on:
workflow_dispatch:
push:
- #branches: [master]
- #paths: &paths
- paths:
+ branches: [master]
+ paths: &paths
- ".github/workflows/test.yaml"
- "src/**"
- "tests/**"
- "pyproject.toml"
- #pull_request:
- # paths: *paths
+ pull_request:
+ paths: *paths
jobs:
build:
diff --git a/README.md b/README.md
index 33c73e4..d68798f 100644
--- a/README.md
+++ b/README.md
@@ -120,8 +120,6 @@ sshkey = vultr.post('ssh-keys', name='key-name', ssh_key='ssh-rsa AAAA...')
vultr.delete(f"instances/019ad1a8-2aa3-7650-83d1-8520d65ed6af")
```
-These methods take the URI as the first argument, and data kwargs as the second.
-
Full Documentation: [https://cssnr.github.io/vultr-python](https://cssnr.github.io/vultr-python/)
Vultr API Reference: [https://www.vultr.com/api](https://www.vultr.com/api/?ref=6905748)
diff --git a/docs/index.md b/docs/index.md
index 627a3c2..ba77e8a 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -96,8 +96,6 @@ sshkey = vultr.post('ssh-keys', name='key-name', ssh_key='ssh-rsa AAAA...')
vultr.delete(f"instances/019ad1a8-2aa3-7650-83d1-8520d65ed6af")
```
-These methods take the URI as the first argument, and data kwargs as the second.
-
Vultr API Reference: [https://www.vultr.com/api](https://www.vultr.com/api/?ref=6905748)
From e2172c3b5b475a736eca5edd759e72d56bf4b27c Mon Sep 17 00:00:00 2001
From: Shane <6071159+smashedr@users.noreply.github.com>
Date: Sat, 29 Nov 2025 18:19:54 -0800
Subject: [PATCH 11/24] Add actionlint.yaml #notest
---
.github/actionlint.yaml | 4 ++++
1 file changed, 4 insertions(+)
create mode 100644 .github/actionlint.yaml
diff --git a/.github/actionlint.yaml b/.github/actionlint.yaml
new file mode 100644
index 0000000..97d70ba
--- /dev/null
+++ b/.github/actionlint.yaml
@@ -0,0 +1,4 @@
+paths:
+ .github/workflows/**/*.{yml,yaml}:
+ ignore:
+ - '"paths" section must be sequence node but got alias node with "" tag'
From 16193c35cc38c63ca1c7eaae080fb09a486c9827 Mon Sep 17 00:00:00 2001
From: Shane <6071159+smashedr@users.noreply.github.com>
Date: Sat, 29 Nov 2025 21:15:15 -0800
Subject: [PATCH 12/24] Add VultrException
---
README.md | 13 ++++++++++++-
docs/index.md | 12 ++++++++++++
src/vultr/__init__.py | 4 ++--
src/vultr/vultr.py | 21 +++++++++++++++++----
4 files changed, 43 insertions(+), 7 deletions(-)
diff --git a/README.md b/README.md
index d68798f..a104a16 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,6 @@
[](https://sonarcloud.io/summary/new_code?id=cssnr_vultr-python)
[](https://github.com/cssnr/vultr-python/actions/workflows/lint.yaml)
[](https://github.com/cssnr/vultr-python/actions/workflows/test.yaml)
-[](https://pypi.org/project/vultr-python/)
[](https://cssnr.github.io/vultr-python/)
[](https://github.com/cssnr/vultr-python/graphs/commit-activity)
[](https://github.com/cssnr/vultr-python)
@@ -120,6 +119,18 @@ sshkey = vultr.post('ssh-keys', name='key-name', ssh_key='ssh-rsa AAAA...')
vultr.delete(f"instances/019ad1a8-2aa3-7650-83d1-8520d65ed6af")
```
+Errors Handling
+
+```python
+from vultr import VultrException
+
+try:
+ instance = vultr.create_instance("atl", "vc2-1c-0.5gb-v6", os_id=2284)
+except VultrException as error:
+ print(error.error) # 'Server add failed: Ubuntu 24.04 LTS x64 requires a plan with at least 1000 MB memory.'
+ print(error.status) # 400
+```
+
Full Documentation: [https://cssnr.github.io/vultr-python](https://cssnr.github.io/vultr-python/)
Vultr API Reference: [https://www.vultr.com/api](https://www.vultr.com/api/?ref=6905748)
diff --git a/docs/index.md b/docs/index.md
index ba77e8a..bc10614 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -96,6 +96,18 @@ sshkey = vultr.post('ssh-keys', name='key-name', ssh_key='ssh-rsa AAAA...')
vultr.delete(f"instances/019ad1a8-2aa3-7650-83d1-8520d65ed6af")
```
+Errors Handling
+
+```python
+from vultr import VultrException
+
+try:
+ instance = vultr.create_instance("atl", "vc2-1c-0.5gb-v6", os_id=2284)
+except VultrException as error:
+ print(error.error) # 'Server add failed: Ubuntu 24.04 LTS x64 requires a plan with at least 1000 MB memory.'
+ print(error.status) # 400
+```
+
Vultr API Reference: [https://www.vultr.com/api](https://www.vultr.com/api/?ref=6905748)
diff --git a/src/vultr/__init__.py b/src/vultr/__init__.py
index 6cc4cfb..ab69aad 100644
--- a/src/vultr/__init__.py
+++ b/src/vultr/__init__.py
@@ -2,7 +2,7 @@
.. include:: ../../docs/index.md
"""
-from .vultr import Vultr
+from .vultr import Vultr, VultrException
-__all__ = ["Vultr"]
+__all__ = ["Vultr", "VultrException"]
diff --git a/src/vultr/vultr.py b/src/vultr/vultr.py
index 879ddc9..655bc0a 100644
--- a/src/vultr/vultr.py
+++ b/src/vultr/vultr.py
@@ -158,25 +158,25 @@ def filter_regions(regions: list, locations: list) -> list:
def _get(self, url, params: Optional[dict] = None):
r = self._session.get(url, params=params, timeout=10)
if not r.ok:
- r.raise_for_status()
+ raise VultrException(r)
return r.json()
def _post(self, url, data):
r = self._session.post(url, json=data, timeout=10)
if not r.ok:
- r.raise_for_status()
+ raise VultrException(r)
return r.json()
def _patch(self, url, data):
r = self._session.patch(url, json=data, timeout=10)
if not r.ok:
- r.raise_for_status()
+ raise VultrException(r)
return r.json()
def _delete(self, url):
r = self._session.delete(url, timeout=10)
if not r.ok:
- r.raise_for_status()
+ raise VultrException(r)
return None
@staticmethod
@@ -190,3 +190,16 @@ def _get_obj_key(obj, key="id"):
return obj[key]
else:
raise ValueError(f"Unable to parse object: {key}")
+
+
+class VultrException(Exception):
+ def __init__(self, response: requests.Response):
+ try:
+ data = response.json()
+ error = data.get("error", response.text)
+ except ValueError:
+ error = response.text
+ status = response.status_code
+ self.error = error
+ self.status = status
+ super().__init__(f"Error {self.status}: {self.error}")
From 92296aa74c88d9c4ac7c9e9c86cdf8a0f42f7e0e Mon Sep 17 00:00:00 2001
From: Shane <6071159+smashedr@users.noreply.github.com>
Date: Sat, 29 Nov 2025 21:46:20 -0800
Subject: [PATCH 13/24] Add Docstrings
---
README.md | 2 +-
docs/index.md | 2 +-
src/vultr/vultr.py | 33 ++++++++++++++++++++++++++++++---
3 files changed, 32 insertions(+), 5 deletions(-)
diff --git a/README.md b/README.md
index a104a16..bf04b0d 100644
--- a/README.md
+++ b/README.md
@@ -77,7 +77,7 @@ vultr = Vultr('VULTR_API_KEY')
List plans and get available regions for that plan
```python
-plans = vultr.list_plans({'type': 'vc2'}) # vc2 - Cloud Compute
+plans = vultr.list_plans({'type': 'vc2'}) # Filter by type
plan = plans[0] # 0 seems to be the base plan
regions = vultr.list_regions()
available = vultr.filter_regions(regions, plan['locations'])
diff --git a/docs/index.md b/docs/index.md
index bc10614..7c10ef2 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -54,7 +54,7 @@ vultr = Vultr('VULTR_API_KEY')
List plans and get available regions for that plan
```python
-plans = vultr.list_plans({'type': 'vc2'}) # vc2 - Cloud Compute
+plans = vultr.list_plans({'type': 'vc2'}) # Filter by type
plan = plans[0] # 0 seems to be the base plan
regions = vultr.list_regions()
available = vultr.filter_regions(regions, plan['locations'])
diff --git a/src/vultr/vultr.py b/src/vultr/vultr.py
index 655bc0a..2e28af0 100644
--- a/src/vultr/vultr.py
+++ b/src/vultr/vultr.py
@@ -9,23 +9,47 @@ class Vultr(object):
def __init__(self, api_key: Optional[str] = None):
"""
- :param str api_key: Vultr API Key or VULTR_API_KEY Environment Variable
+ :param api_key: Vultr API Key or `VULTR_API_KEY` Environment Variable
"""
self.api_key = api_key or os.getenv("VULTR_API_KEY")
+ """Provide the API key here or with the `VULTR_API_KEY` environment variable"""
self._session = requests.session()
if self.api_key:
self._session.headers.update({"Authorization": f"Bearer {self.api_key}"})
def get(self, url: str, params: Optional[dict] = None):
+ """
+ GET Data
+ :param url: Request URL. Example `/instances`
+ :param params: Query Parameters
+ :return: Response Data
+ """
return self._get(f"{self.url}/{url.lstrip('/')}", params)
def post(self, url: str, **kwargs):
+ """
+ POST Data
+ :param url: Request URL. Example `/instances`
+ :param kwargs: Request Data Keyword Arguments
+ :return: Response Data
+ """
return self._post(f"{self.url}/{url.lstrip('/')}", kwargs)
def patch(self, url: str, **kwargs):
+ """
+ PATCH Data
+ :param url: Request URL. Example `/instances/{resource_id}`
+ :param kwargs: Request Data Keyword Arguments
+ :return: Response Data
+ """
return self._patch(f"{self.url}/{url.lstrip('/')}", kwargs)
def delete(self, url: str):
+ """
+ DELETE a Resource
+ :param url: Request URL. Example `/instances/{resource_id}`
+ :return: None
+ """
return self._delete(f"{self.url}/{url.lstrip('/')}")
def list_os(self, params: Optional[dict] = None):
@@ -193,6 +217,7 @@ def _get_obj_key(obj, key="id"):
class VultrException(Exception):
+ """ Exception class for all Vultr error responses. """
def __init__(self, response: requests.Response):
try:
data = response.json()
@@ -200,6 +225,8 @@ def __init__(self, response: requests.Response):
except ValueError:
error = response.text
status = response.status_code
- self.error = error
- self.status = status
+ self.error: str = error
+ """Error Message returned from the API"""
+ self.status: int = status
+ """Response Status Code"""
super().__init__(f"Error {self.status}: {self.error}")
From 9e8ff86856af03818c6c296eb545c2e73f979e7b Mon Sep 17 00:00:00 2001
From: Shane <6071159+smashedr@users.noreply.github.com>
Date: Sat, 29 Nov 2025 22:04:08 -0800
Subject: [PATCH 14/24] Add MANIFEST.in
---
MANIFEST.in | 1 +
README.md | 9 ++++++---
docs/index.md | 8 +++++---
src/vultr/vultr.py | 5 +++--
4 files changed, 15 insertions(+), 8 deletions(-)
create mode 100644 MANIFEST.in
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..1eeef06
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1 @@
+prune tests
diff --git a/README.md b/README.md
index bf04b0d..bbf9817 100644
--- a/README.md
+++ b/README.md
@@ -6,6 +6,7 @@
[](https://sonarcloud.io/summary/new_code?id=cssnr_vultr-python)
[](https://github.com/cssnr/vultr-python/actions/workflows/lint.yaml)
[](https://github.com/cssnr/vultr-python/actions/workflows/test.yaml)
+[](https://pypi.org/project/vultr-python/)
[](https://cssnr.github.io/vultr-python/)
[](https://github.com/cssnr/vultr-python/graphs/commit-activity)
[](https://github.com/cssnr/vultr-python)
@@ -119,7 +120,7 @@ sshkey = vultr.post('ssh-keys', name='key-name', ssh_key='ssh-rsa AAAA...')
vultr.delete(f"instances/019ad1a8-2aa3-7650-83d1-8520d65ed6af")
```
-Errors Handling
+Error Handling
```python
from vultr import VultrException
@@ -127,8 +128,10 @@ from vultr import VultrException
try:
instance = vultr.create_instance("atl", "vc2-1c-0.5gb-v6", os_id=2284)
except VultrException as error:
- print(error.error) # 'Server add failed: Ubuntu 24.04 LTS x64 requires a plan with at least 1000 MB memory.'
- print(error.status) # 400
+ print(error.error)
+ # 'Server add failed: Ubuntu 24.04 LTS x64 requires a plan with at least 1000 MB memory.'
+ print(error.status)
+ # 400
```
Full Documentation: [https://cssnr.github.io/vultr-python](https://cssnr.github.io/vultr-python/)
diff --git a/docs/index.md b/docs/index.md
index 7c10ef2..9df3733 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -96,7 +96,7 @@ sshkey = vultr.post('ssh-keys', name='key-name', ssh_key='ssh-rsa AAAA...')
vultr.delete(f"instances/019ad1a8-2aa3-7650-83d1-8520d65ed6af")
```
-Errors Handling
+Error Handling
```python
from vultr import VultrException
@@ -104,8 +104,10 @@ from vultr import VultrException
try:
instance = vultr.create_instance("atl", "vc2-1c-0.5gb-v6", os_id=2284)
except VultrException as error:
- print(error.error) # 'Server add failed: Ubuntu 24.04 LTS x64 requires a plan with at least 1000 MB memory.'
- print(error.status) # 400
+ print(error.error)
+ # 'Server add failed: Ubuntu 24.04 LTS x64 requires a plan with at least 1000 MB memory.'
+ print(error.status)
+ # 400
```
diff --git a/src/vultr/vultr.py b/src/vultr/vultr.py
index 2e28af0..9ebc686 100644
--- a/src/vultr/vultr.py
+++ b/src/vultr/vultr.py
@@ -217,7 +217,8 @@ def _get_obj_key(obj, key="id"):
class VultrException(Exception):
- """ Exception class for all Vultr error responses. """
+ """Exception class for all Vultr error responses."""
+
def __init__(self, response: requests.Response):
try:
data = response.json()
@@ -226,7 +227,7 @@ def __init__(self, response: requests.Response):
error = response.text
status = response.status_code
self.error: str = error
- """Error Message returned from the API"""
+ """Error Message for 400 Codes"""
self.status: int = status
"""Response Status Code"""
super().__init__(f"Error {self.status}: {self.error}")
From a4f02fbc34e1c28ffdc6244fbf5ecd81709c4fe5 Mon Sep 17 00:00:00 2001
From: Shane <6071159+smashedr@users.noreply.github.com>
Date: Sun, 30 Nov 2025 00:10:34 -0800
Subject: [PATCH 15/24] Update Docs
---
.github/workflows/docs.yaml | 32 +++++++++++++++----------------
.github/workflows/lint.yaml | 2 +-
docs.ps1 | 22 +++++++++++----------
docs/index.md | 16 +++++++++++-----
docs/module.html.jinja2 | 38 +++++++++++++++++++++++++++++++++++++
5 files changed, 78 insertions(+), 32 deletions(-)
diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml
index 3e5aa85..3ec6a5e 100644
--- a/.github/workflows/docs.yaml
+++ b/.github/workflows/docs.yaml
@@ -13,7 +13,7 @@ on:
default: site
env:
- logo: "https://raw.githubusercontent.com/smashedr/repo-images/refs/heads/master/vultr-python/logo128.png"
+ logo: "https://raw.githubusercontent.com/cssnr/vultr-python/refs/heads/master/.github/assets/logo.svg"
link: ${{ github.event.repository.html_url }}
jobs:
@@ -27,7 +27,7 @@ jobs:
steps:
- name: "Checkout"
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
- name: "Debug CTX github"
continue-on-error: true
@@ -53,29 +53,29 @@ jobs:
python -m pip install -U pdoc
python -m pip install -e .
python -m pdoc -t docs -o "${{ inputs.path }}" \
- --favicon "${{ env.logo }}" \
--logo "${{ env.logo }}" \
--logo-link "${{ env.link }}" \
vultr
- - name: "Update Permissions"
+ - name: "Fix Docs"
+ working-directory: ${{ inputs.path }}
run: |
- chmod -c -R +rX "${{ inputs.path }}" | while read name; do
- echo "::notice::Fixed invalid file permissions: ${name}"
- done
+ mv -f vultr.html index.html
+
+ #- name: "Update Permissions"
+ # run: |
+ # chmod -c -R +rX "${{ inputs.path }}" | while read name; do
+ # echo "::notice::Fixed invalid file permissions: ${name}"
+ # done
- name: "List Artifacts"
- env:
- path: ${{ inputs.path }}
+ working-directory: ${{ inputs.path }}
run: |
- echo "::group::ls"
- ls -lAhR "${path}"
- echo "::endgroup::"
- echo "::group::tree"
- tree "${path}"
+ results="$(tree . || ls -lAhR .)"
+ echo "::group::results"
+ echo "${results}"
echo "::endgroup::"
- results="$(tree "${path}")"
- markdown='Artifacts:\n```text\n'"${results}"'\n```'
+ markdown='Artifacts: `${{ inputs.path }}`\n```text\n'"${results}"'\n```'
echo -e "${markdown}" >> $GITHUB_STEP_SUMMARY
- name: "Upload Pages Artifact"
diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml
index 0e8b52f..8268ad4 100644
--- a/.github/workflows/lint.yaml
+++ b/.github/workflows/lint.yaml
@@ -26,7 +26,7 @@ jobs:
steps:
- name: "Checkout"
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
- name: "Debug event.json"
continue-on-error: true
diff --git a/docs.ps1 b/docs.ps1
index 4d0d955..7fed3bc 100644
--- a/docs.ps1
+++ b/docs.ps1
@@ -22,17 +22,19 @@ if ($c) {
}
}
-python -m pdoc -t .\docs\ -p 8008 `
- --favicon "https://df.cssnr.com/raw/logo128.png" `
- --logo "https://df.cssnr.com/raw/logo128.png" `
+if ($b) {
+ Write-Host -ForegroundColor Yellow "Building Docs..."
+ python -m pdoc -t .\docs\ -o site `
+ --logo "https://raw.githubusercontent.com/cssnr/vultr-python/refs/heads/master/.github/assets/logo.svg" `
--logo-link "https://github.com/cssnr/vultr-python" `
vultr
+} else {
+ Write-Host -ForegroundColor Green "Serving Docs..."
+ python -m pdoc -t .\docs\ -p 8000 -h 0.0.0.0 `
+ --logo "https://raw.githubusercontent.com/cssnr/vultr-python/refs/heads/master/.github/assets/logo.svg" `
+ --logo-link "https://github.com/cssnr/vultr-python" `
+ vultr
+}
+#--favicon "https://df.cssnr.com/raw/logo128.png" `
#-e "vultr=https://github.com/cssnr/vultr-python/blob/updates/src/vultr/" `
-
-#if ($b) {
-# Write-Host -ForegroundColor Green "Building Docs..."
-# zensical build
-#} else {
-# zensical serve
-#}
diff --git a/docs/index.md b/docs/index.md
index 9df3733..175b178 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -39,11 +39,11 @@ python -m pip install vultr-python
## Usage
-You will need to create an api key and whitelist your IP address. Most functions do not work without an API Key.
+You will need to create an api key and whitelist your IP address for most functions.
- [https://my.vultr.com/settings/#settingsapi](https://my.vultr.com/settings/#settingsapi)
-Initialize the class with your API Key or with the `VULTR_API_KEY` environment variable.
+Initialize the `Vultr` class with your API Key or use the `VULTR_API_KEY` environment variable.
```python
from vultr import Vultr
@@ -88,16 +88,22 @@ instance = vultr.create_instance(available[0], plan, **data)
Arbitrary Methods `get`, `post`, `patch`, `delete`
```python
-# vultr.get('url', params)
instances = vultr.get('instances', {'type': 'vc2'})
-# vultr.post('url', **kwargs)
sshkey = vultr.post('ssh-keys', name='key-name', ssh_key='ssh-rsa AAAA...')
-# vultr.delete('url')
vultr.delete(f"instances/019ad1a8-2aa3-7650-83d1-8520d65ed6af")
```
Error Handling
+```python
+>>> instance = vultr.create_instance("atl", "vc2-1c-0.5gb-v6", **data)
+Traceback (most recent call last):
+ ...
+vultr.vultr.VultrException: Error 400: Server add failed: Ubuntu 24.04 LTS x64 requires a plan with at least 1000 MB memory.
+```
+
+Using the `VultrException` class
+
```python
from vultr import VultrException
diff --git a/docs/module.html.jinja2 b/docs/module.html.jinja2
index 229f2a8..82873b8 100644
--- a/docs/module.html.jinja2
+++ b/docs/module.html.jinja2
@@ -1,2 +1,40 @@
{% extends "default/module.html.jinja2" %}
{% block title %}Vultr Python{% endblock %}
+{% block head %}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{% endblock %}
From e2de5f3b1a315ba916384d97ea1eb411e2ab5d3d Mon Sep 17 00:00:00 2001
From: Shane <6071159+smashedr@users.noreply.github.com>
Date: Sun, 30 Nov 2025 00:41:07 -0800
Subject: [PATCH 16/24] Update Examples
---
.github/workflows/build.yaml | 14 +++++---------
README.md | 21 +++++++++++++--------
docs/index.md | 3 ++-
docs/module.html.jinja2 | 6 ++++++
4 files changed, 26 insertions(+), 18 deletions(-)
diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
index 0780dc7..681cad8 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -55,17 +55,13 @@ jobs:
python -m build
- name: "List Artifacts"
- env:
- path: ${{ inputs.path }}
+ working-directory: ${{ inputs.path }}
run: |
- echo "::group::ls"
- ls -lAhR "${path}"
- echo "::endgroup::"
- echo "::group::tree"
- tree "${path}"
+ results="$(tree . || ls -lAhR .)"
+ echo "::group::results"
+ echo "${results}"
echo "::endgroup::"
- results="$(tree "${path}")"
- markdown='Artifacts:\n```text\n'"${results}"'\n```'
+ markdown='Artifacts: `${{ inputs.path }}`\n```text\n'"${results}"'\n```'
echo -e "${markdown}" >> $GITHUB_STEP_SUMMARY
- name: "Upload to Actions"
diff --git a/README.md b/README.md
index bbf9817..97bc37a 100644
--- a/README.md
+++ b/README.md
@@ -39,7 +39,6 @@ Python 3 wrapper for the Vultr API v2.
Vultr API Reference: [https://www.vultr.com/api](https://www.vultr.com/api/?ref=6905748)
> [!TIP]
-> This project is not complete, but has many useful functions.
> Please submit a [Feature Request](https://github.com/cssnr/vultr-python/discussions/categories/feature-requests)
> or report any [Issues](https://github.com/cssnr/vultr-python/issues).
@@ -62,12 +61,11 @@ python -m pip install vultr-python
## Usage
-You will need to create an api key and whitelist your IP address.
-Most functions do not work without an API Key.
+You will need to create an api key and whitelist your IP address for most functions.
- [https://my.vultr.com/settings/#settingsapi](https://my.vultr.com/settings/#settingsapi)
-Initialize the class with your API Key or with the `VULTR_API_KEY` environment variable.
+Initialize the `Vultr` class with your API Key or use the `VULTR_API_KEY` environment variable.
```python
from vultr import Vultr
@@ -112,16 +110,23 @@ instance = vultr.create_instance(available[0], plan, **data)
Arbitrary Methods `get`, `post`, `patch`, `delete`
```python
-# vultr.get('url', params)
-instances = vultr.get('instances', {'type': 'vc2'})
-# vultr.post('url', **kwargs)
+plans = vultr.get('plans', {'type': 'vc2'})
sshkey = vultr.post('ssh-keys', name='key-name', ssh_key='ssh-rsa AAAA...')
-# vultr.delete('url')
+instance = vultr.patch('instances', plan=plans[1]['id'])
vultr.delete(f"instances/019ad1a8-2aa3-7650-83d1-8520d65ed6af")
```
Error Handling
+```python
+>>> instance = vultr.create_instance("atl", "vc2-1c-0.5gb-v6", **data)
+Traceback (most recent call last):
+ ...
+vultr.vultr.VultrException: Error 400: Server add failed: Ubuntu 24.04 LTS x64 requires a plan with at least 1000 MB memory.
+```
+
+Using the `VultrException` class
+
```python
from vultr import VultrException
diff --git a/docs/index.md b/docs/index.md
index 175b178..0f54e57 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -88,8 +88,9 @@ instance = vultr.create_instance(available[0], plan, **data)
Arbitrary Methods `get`, `post`, `patch`, `delete`
```python
-instances = vultr.get('instances', {'type': 'vc2'})
+plans = vultr.get('plans', {'type': 'vc2'})
sshkey = vultr.post('ssh-keys', name='key-name', ssh_key='ssh-rsa AAAA...')
+instance = vultr.patch('instances', plan=plans[1]['id'])
vultr.delete(f"instances/019ad1a8-2aa3-7650-83d1-8520d65ed6af")
```
diff --git a/docs/module.html.jinja2 b/docs/module.html.jinja2
index 82873b8..c3725a4 100644
--- a/docs/module.html.jinja2
+++ b/docs/module.html.jinja2
@@ -38,3 +38,9 @@
{% endblock %}
+
+{#{% block nav_footer %}#}
+{# #}
+{#{% endblock %}#}
+
+{#{% block attribution %}{% endblock %}#}
From c8803d4b24b23d5ab567d129525f40ec1e91dd06 Mon Sep 17 00:00:00 2001
From: Shane <6071159+smashedr@users.noreply.github.com>
Date: Sun, 30 Nov 2025 00:56:05 -0800
Subject: [PATCH 17/24] Cleanup
---
README.md | 1 -
docs/index.md | 3 ++-
docs/module.html.jinja2 | 2 --
3 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/README.md b/README.md
index 97bc37a..6d88b2c 100644
--- a/README.md
+++ b/README.md
@@ -121,7 +121,6 @@ Error Handling
```python
>>> instance = vultr.create_instance("atl", "vc2-1c-0.5gb-v6", **data)
Traceback (most recent call last):
- ...
vultr.vultr.VultrException: Error 400: Server add failed: Ubuntu 24.04 LTS x64 requires a plan with at least 1000 MB memory.
```
diff --git a/docs/index.md b/docs/index.md
index 0f54e57..58c6c4d 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -99,7 +99,6 @@ Error Handling
```python
>>> instance = vultr.create_instance("atl", "vc2-1c-0.5gb-v6", **data)
Traceback (most recent call last):
- ...
vultr.vultr.VultrException: Error 400: Server add failed: Ubuntu 24.04 LTS x64 requires a plan with at least 1000 MB memory.
```
@@ -122,3 +121,5 @@ except VultrException as error:
Vultr API Reference: [https://www.vultr.com/api](https://www.vultr.com/api/?ref=6905748)
---
+
+
API Documentation
diff --git a/docs/module.html.jinja2 b/docs/module.html.jinja2 index c3725a4..0948e60 100644 --- a/docs/module.html.jinja2 +++ b/docs/module.html.jinja2 @@ -26,10 +26,8 @@