Skip to content

Commit 27161d7

Browse files
new: Support region availability endpoints (#349)
* Add availability object * Add filter assertion * Avail docs
1 parent 0e46856 commit 27161d7

8 files changed

Lines changed: 742 additions & 4 deletions

File tree

linode_api4/groups/region.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from linode_api4.groups import Group
22
from linode_api4.objects import Region
3+
from linode_api4.objects.region import RegionAvailabilityEntry
34

45

56
class RegionGroup(Group):
@@ -23,3 +24,22 @@ def __call__(self, *filters):
2324
"""
2425

2526
return self.client._get_and_filter(Region, *filters)
27+
28+
def availability(self, *filters):
29+
"""
30+
Returns the availability of Linode plans within a Region.
31+
32+
33+
API Documentation: https://www.linode.com/docs/api/regions/#regions-availability-list
34+
35+
:param filters: Any number of filters to apply to this query.
36+
See :doc:`Filtering Collections</linode_api4/objects/filtering>`
37+
for more details on filtering.
38+
39+
:returns: A list of entries describing the availability of a plan in a region.
40+
:rtype: PaginatedList of RegionAvailabilityEntry
41+
"""
42+
43+
return self.client._get_and_filter(
44+
RegionAvailabilityEntry, *filters, endpoint="/regions/availability"
45+
)

linode_api4/objects/region.py

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
from linode_api4.objects import Base, Property
1+
from dataclasses import dataclass
2+
from typing import List
3+
4+
from linode_api4.errors import UnexpectedResponseError
5+
from linode_api4.objects.base import Base, JSONObject, Property
6+
from linode_api4.objects.filtering import FilterableAttribute
7+
from linode_api4.objects.serializable import JSONFilterableMetaclass
28

39

410
class Region(Base):
@@ -17,3 +23,29 @@ class Region(Base):
1723
"resolvers": Property(),
1824
"label": Property(),
1925
}
26+
27+
@property
28+
def availability(self) -> List["RegionAvailabilityEntry"]:
29+
result = self._client.get(
30+
f"{self.api_endpoint}/availability", model=self
31+
)
32+
33+
if result is None:
34+
raise UnexpectedResponseError(
35+
"Expected availability data, got None."
36+
)
37+
38+
return [RegionAvailabilityEntry.from_json(v) for v in result]
39+
40+
41+
@dataclass
42+
class RegionAvailabilityEntry(JSONObject):
43+
"""
44+
Represents the availability of a Linode type within a region.
45+
46+
API Documentation: https://www.linode.com/docs/api/regions/#region-availability-view
47+
"""
48+
49+
region: str = None
50+
plan: str = None
51+
available: bool = False

linode_api4/objects/serializable.py

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,41 @@
11
import inspect
22
from dataclasses import asdict, dataclass
3-
from typing import Any, Dict, Optional, get_args, get_origin, get_type_hints
3+
from types import SimpleNamespace
4+
from typing import (
5+
Any,
6+
ClassVar,
7+
Dict,
8+
Optional,
9+
get_args,
10+
get_origin,
11+
get_type_hints,
12+
)
13+
14+
from linode_api4.objects.filtering import FilterableAttribute
15+
16+
# Wraps the SimpleNamespace class and allows for
17+
# SQLAlchemy-style filter generation on JSONObjects.
18+
JSONFilterGroup = SimpleNamespace
19+
20+
21+
class JSONFilterableMetaclass(type):
22+
def __init__(cls, name, bases, dct):
23+
setattr(
24+
cls,
25+
"filters",
26+
JSONFilterGroup(
27+
**{
28+
k: FilterableAttribute(k)
29+
for k in cls.__annotations__.keys()
30+
}
31+
),
32+
)
33+
34+
super().__init__(name, bases, dct)
435

536

637
@dataclass
7-
class JSONObject:
38+
class JSONObject(metaclass=JSONFilterableMetaclass):
839
"""
940
A simple helper class for serializable API objects.
1041
This is typically used for nested object values.
@@ -13,6 +44,16 @@ class JSONObject:
1344
fields and static typing.
1445
"""
1546

47+
filters: ClassVar[JSONFilterGroup] = None
48+
"""
49+
A group containing FilterableAttributes used to create SQLAlchemy-style filters.
50+
51+
Example usage::
52+
self.client.regions.availability(
53+
RegionAvailabilityEntry.filters.plan == "premium4096.7"
54+
)
55+
"""
56+
1657
def __init__(self):
1758
raise NotImplementedError(
1859
"JSONObject is not intended to be constructed directly"

linode_api4/paginated_list.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import math
22

3+
from linode_api4.objects.serializable import JSONObject
4+
35

46
class PaginatedList(object):
57
"""
@@ -205,6 +207,10 @@ def make_list(json_arr, client, cls, parent_id=None):
205207

206208
for obj in json_arr:
207209
id_val = None
210+
# Special handling for JSON objects
211+
if issubclass(cls, JSONObject):
212+
result.append(cls.from_json(obj))
213+
continue
208214

209215
if "id" in obj:
210216
id_val = obj["id"]

0 commit comments

Comments
 (0)