From dd9b0460ec95644f7682f67cc85df9e642801a2a Mon Sep 17 00:00:00 2001 From: JD <> Date: Tue, 22 Jul 2025 13:12:26 +0200 Subject: [PATCH 1/2] feat(src/resources/metadata): implement metadata endpoints --- LICENSE | 21 +++++++++ examples/metadata/get_datacenters.py | 18 +++++++ examples/metadata/get_workspace_base_image.py | 17 +++++++ examples/metadata/get_workspace_plans.py | 26 ++++++++++ src/codesphere/__init__.py | 2 + src/codesphere/resources/metadata/models.py | 47 +++++++++++++++++++ .../resources/metadata/resources.py | 28 +++++++++++ 7 files changed, 159 insertions(+) diff --git a/LICENSE b/LICENSE index e69de29..c7473a6 100644 --- a/LICENSE +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Jan-David Wiederstein + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/examples/metadata/get_datacenters.py b/examples/metadata/get_datacenters.py index e69de29..a1cc32a 100644 --- a/examples/metadata/get_datacenters.py +++ b/examples/metadata/get_datacenters.py @@ -0,0 +1,18 @@ +import asyncio +import pprint +from codesphere import CodesphereSDK + + +async def main(): + """Fetches datacenters.""" + async with CodesphereSDK() as sdk: + datacenters = await sdk.metadata.datacenters() + + for datacenter in datacenters: + pprint.pprint(datacenter.name) + pprint.pprint(datacenter.city) + pprint.pprint(datacenter.countryCode) + pprint.pprint(datacenter.id) + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/examples/metadata/get_workspace_base_image.py b/examples/metadata/get_workspace_base_image.py index e69de29..56cfa85 100644 --- a/examples/metadata/get_workspace_base_image.py +++ b/examples/metadata/get_workspace_base_image.py @@ -0,0 +1,17 @@ +import asyncio +import pprint +from codesphere import CodesphereSDK + + +async def main(): + """Fetches base images.""" + async with CodesphereSDK() as sdk: + images = await sdk.metadata.images() + + for image in images: + pprint.pprint(image.id) + pprint.pprint(image.name) + pprint.pprint(image.supportedUntil) + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/examples/metadata/get_workspace_plans.py b/examples/metadata/get_workspace_plans.py index e69de29..77fcd33 100644 --- a/examples/metadata/get_workspace_plans.py +++ b/examples/metadata/get_workspace_plans.py @@ -0,0 +1,26 @@ +import asyncio +import pprint +from codesphere import CodesphereSDK + + +async def main(): + """Fetches workspace plans.""" + async with CodesphereSDK() as sdk: + plans = await sdk.metadata.plans() + + for plan in plans: + pprint.pprint(plan.id) + pprint.pprint(plan.title) + pprint.pprint(plan.priceUsd) + pprint.pprint(plan.deprecated) + pprint.pprint(plan.characteristics.id) + pprint.pprint(plan.characteristics.CPU) + pprint.pprint(plan.characteristics.GPU) + pprint.pprint(plan.characteristics.RAM) + pprint.pprint(plan.characteristics.SSD) + pprint.pprint(plan.characteristics.TempStorage) + pprint.pprint(plan.characteristics.onDemand) + pprint.pprint(plan.maxReplicas) + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/src/codesphere/__init__.py b/src/codesphere/__init__.py index 0b3b9ab..5fa87e9 100644 --- a/src/codesphere/__init__.py +++ b/src/codesphere/__init__.py @@ -2,6 +2,7 @@ from .client import APIHttpClient from .resources.team.resources import TeamsResource from .resources.workspace.resources import WorkspacesResource +from .resources.metadata.resources import MetadataResource from .resources.workspace.models import ( Workspace, WorkspaceCreate, @@ -22,6 +23,7 @@ async def __aenter__(self): self.teams = TeamsResource(self._http_client) self.workspaces = WorkspacesResource(self._http_client) + self.metadata = MetadataResource(self._http_client) return self async def __aexit__(self, exc_type, exc_val, exc_tb): diff --git a/src/codesphere/resources/metadata/models.py b/src/codesphere/resources/metadata/models.py index e69de29..c101caf 100644 --- a/src/codesphere/resources/metadata/models.py +++ b/src/codesphere/resources/metadata/models.py @@ -0,0 +1,47 @@ +from __future__ import annotations +from pydantic import BaseModel +import datetime +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + pass + + +class Datacenters(BaseModel): + """Defines the request body for creating a team.""" + + id: int + name: str + city: str + countryCode: str + + +class Characteristics(BaseModel): + """Defines the hardware and service characteristics of a workspace plan.""" + + id: int + CPU: float + GPU: int + RAM: int + SSD: int + TempStorage: int + onDemand: bool + + +class WsPlans(BaseModel): + """Contains all fields that appear in a workspace-plans response.""" + + id: int + priceUsd: int + title: str + deprecated: bool + characteristics: Characteristics + maxReplicas: int + + +class Images(BaseModel): + """Represents a team as it appears in the list response.""" + + id: str + name: str + supportedUntil: datetime.datetime diff --git a/src/codesphere/resources/metadata/resources.py b/src/codesphere/resources/metadata/resources.py index e69de29..c56c98e 100644 --- a/src/codesphere/resources/metadata/resources.py +++ b/src/codesphere/resources/metadata/resources.py @@ -0,0 +1,28 @@ +from typing import List +from ..base import ResourceBase, APIOperation +from .models import Datacenters, WsPlans, Images + + +class MetadataResource(ResourceBase): + """Contains all API operations for team ressources.""" + + datacenters = APIOperation( + method="GET", + endpoint_template="/metadata/datacenters", + input_model=None, + response_model=List[Datacenters], + ) + + plans = APIOperation( + method="GET", + endpoint_template="/metadata/workspace-plans", + input_model=None, + response_model=List[WsPlans], + ) + + images = APIOperation( + method="GET", + endpoint_template="/metadata/workspace-base-images", + input_model=None, + response_model=List[Images], + ) From de0b711a18e3ff1bf7dac9ce7257999e44ba3e5a Mon Sep 17 00:00:00 2001 From: JD <> Date: Tue, 22 Jul 2025 13:12:27 +0200 Subject: [PATCH 2/2] =?UTF-8?q?bump:=20version=200.2.3=20=E2=86=92=200.3.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ pyproject.toml | 2 +- uv.lock | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 57d23bc..acb80ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## v0.3.0 (2025-07-22) + +### Feat + +- **src/resources/metadata**: implement metadata endpoints + ## v0.2.3 (2025-07-21) ### Fix diff --git a/pyproject.toml b/pyproject.toml index ace2192..9928baa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "codesphere" -version = "0.2.3" +version = "0.3.0" description = "Use Codesphere within python scripts." readme = "README.md" license = { file="LICENSE" } diff --git a/uv.lock b/uv.lock index 8b13482..cee40ec 100644 --- a/uv.lock +++ b/uv.lock @@ -182,7 +182,7 @@ wheels = [ [[package]] name = "codesphere" -version = "0.2.3" +version = "0.3.0" source = { editable = "." } dependencies = [ { name = "aiohttp" },