Skip to content

Commit 4f82c0f

Browse files
authored
feat(api): Added functions for fetching the connector version feeds. (#435)
* Added connector feed utility functions * Check ex code
1 parent f5e024c commit 4f82c0f

File tree

2 files changed

+102
-0
lines changed

2 files changed

+102
-0
lines changed
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
from datetime import datetime
2+
from typing import List
3+
4+
import httpx
5+
from pydantic import AliasGenerator, BaseModel, ConfigDict, HttpUrl
6+
from pydantic.alias_generators import to_pascal
7+
8+
9+
class ConnectorFeedBaseModel(BaseModel):
10+
"""
11+
Parent class for all Connector Feed Object Model classes
12+
Sets-up a pydantic config to serialize properties using a pascal case alias
13+
"""
14+
15+
model_config = ConfigDict(
16+
alias_generator=AliasGenerator(
17+
validation_alias=to_pascal,
18+
),
19+
populate_by_name=True,
20+
)
21+
22+
23+
class ConnectorVersion(ConnectorFeedBaseModel):
24+
number: str
25+
url: HttpUrl
26+
os: int # this is an enum, it's properly defined in the old v2 SDK (used by Speckle.Manager.Feed) # noqa: E501
27+
architecture: int # These are enums, they are properly defined in the old v2 SDK (used by Speckle.Manager.Feed) # noqa: E501
28+
date: datetime
29+
prerelease: bool
30+
31+
32+
class ConnectorVersions(ConnectorFeedBaseModel):
33+
versions: List[ConnectorVersion]
34+
35+
36+
def get_latest_version(host_app_slug: str, allow_pre_release: bool) -> ConnectorVersion:
37+
"""
38+
Fetches the JSON feed for the given connector slug and
39+
Returns the latest version by date - Note, it does not consider semvers!
40+
41+
Arguments:
42+
host_app_slug {str} -- the host app slug to query for
43+
allow_pre_release {bool} -- if false, only stable releases will be considered
44+
Raises:
45+
HTTPStatusError: if http request failed
46+
ValidationError: response was not valid json
47+
ValueError: The feed contained no connector versions
48+
"""
49+
connector_versions = get_connector_versions(host_app_slug).versions
50+
filtered_versions = [
51+
v for v in connector_versions if allow_pre_release or not v.prerelease
52+
]
53+
54+
return max(filtered_versions, key=lambda x: x.date)
55+
56+
57+
def get_connector_versions(host_app_slug: str) -> ConnectorVersions:
58+
"""
59+
Fetches the JSON feed for the given slug (v3 feeds only)
60+
Raises:
61+
HTTPStatusError: if http request failed
62+
ValidationError: response was not valid json
63+
"""
64+
url = f"https://releases.speckle.dev/manager2/feeds/{host_app_slug.lower()}-v3.json"
65+
66+
res = httpx.get(url).raise_for_status()
67+
68+
feed_data = ConnectorVersions.model_validate_json(res.text)
69+
70+
return feed_data
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import pytest
2+
from httpx import HTTPStatusError
3+
4+
from specklepy.core.api.connector_versions import (
5+
ConnectorVersion,
6+
ConnectorVersions,
7+
get_connector_versions,
8+
get_latest_version,
9+
)
10+
11+
# NOTE: the tests in this file are testing against the live releases.speckle.dev server
12+
# url defined in get_connector_versions.
13+
14+
15+
def test_connector_versions():
16+
res = get_connector_versions("blender")
17+
18+
assert isinstance(res, ConnectorVersions)
19+
assert res.versions # Assuming the feed is not empty
20+
21+
22+
def test_get_latest_version_throws_no_slug():
23+
with pytest.raises(HTTPStatusError) as ex:
24+
get_latest_version("non-existent-connector!", True)
25+
26+
assert "404" in str(ex.value)
27+
28+
29+
def test_get_latest_version():
30+
res = get_latest_version("blender", False)
31+
32+
assert isinstance(res, ConnectorVersion)

0 commit comments

Comments
 (0)