Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file removed examples/domains/delete_domain.py
Empty file.
Empty file removed examples/domains/get_domain.py
Empty file.
Empty file removed examples/domains/list_domains.py
Empty file.
Empty file removed examples/domains/update_domain.py
Empty file.
Empty file.
18 changes: 18 additions & 0 deletions examples/teams/domains/create_domain.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import asyncio
import logging
from codesphere import CodesphereSDK

logging.basicConfig(level=logging.INFO)


async def main():
async with CodesphereSDK() as sdk:
team = await sdk.teams.get(team_id=35663)
domain = await team.domains.create(domain_name="test.com")

print(f"Domain created: {domain.name}")
print(domain.model_dump_json(indent=2))


if __name__ == "__main__":
asyncio.run(main())
18 changes: 18 additions & 0 deletions examples/teams/domains/delete_domain.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import asyncio
import logging
from codesphere import CodesphereSDK

logging.basicConfig(level=logging.INFO)


async def main():
async with CodesphereSDK() as sdk:
team = await sdk.teams.get(team_id=35663)
domain = await team.domains.delete(domain_name="test.com")

print(f"Domain created: {domain.name}")
print(domain.model_dump_json(indent=2))


if __name__ == "__main__":
asyncio.run(main())
18 changes: 18 additions & 0 deletions examples/teams/domains/get_domain.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import asyncio
import logging
from codesphere import CodesphereSDK

logging.basicConfig(level=logging.INFO)


async def main():
async with CodesphereSDK() as sdk:
team = await sdk.teams.get(team_id=35663)
logging.info(f"Working with team: {team.name}")
domain = await team.domains.get("test.com")

print(domain.model_dump_json(indent=2))


if __name__ == "__main__":
asyncio.run(main())
19 changes: 19 additions & 0 deletions examples/teams/domains/list_domains.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import asyncio
import logging
from codesphere import CodesphereSDK

logging.basicConfig(level=logging.INFO)


async def main():
async with CodesphereSDK() as sdk:
team = await sdk.teams.get(team_id=35663)
domains = await team.domains.list()

for domain in domains:
print(f"Domain: {domain.name}")
print(domain.model_dump_json(indent=2))


if __name__ == "__main__":
asyncio.run(main())
20 changes: 20 additions & 0 deletions examples/teams/domains/update_domain.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import asyncio
import logging
from codesphere import CodesphereSDK, CustomDomainConfig

logging.basicConfig(level=logging.INFO)


async def main():
async with CodesphereSDK() as sdk:
team = await sdk.teams.get(team_id=35663)
domain = await team.domains.get(domain_name="test.com")

new_config_data = CustomDomainConfig(
max_body_size_mb=24, max_connection_timeout_s=500, use_regex=False
)
await domain.update(new_config_data)


if __name__ == "__main__":
asyncio.run(main())
24 changes: 24 additions & 0 deletions examples/teams/domains/update_workspace_connections.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import asyncio
import logging
from codesphere import CodesphereSDK, DomainRouting

logging.basicConfig(level=logging.INFO)


async def main():
async with CodesphereSDK() as sdk:
team = await sdk.teams.get(team_id=35663)
domainBuilder = DomainRouting()

routing = (
domainBuilder.add("/", [74861]).add("/api", [74868]).add("/test", [74868])
)

domain = await team.domains.update_workspace_connections(
name="test.com", connections=routing
)
print(f"Current routing: {domain.workspaces}")


if __name__ == "__main__":
asyncio.run(main())
6 changes: 0 additions & 6 deletions examples/workspaces/execute_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,7 @@
import logging
from codesphere import CodesphereSDK

# --- Logging-Konfiguration ---
logging.basicConfig(level=logging.INFO)
# (Optionale Logger stummschalten)
logging.getLogger("codesphere.http_client").setLevel(logging.WARNING)
logging.getLogger("httpx").setLevel(logging.WARNING)

log = logging.getLogger(__name__)


async def main():
Expand Down
17 changes: 16 additions & 1 deletion src/codesphere/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,16 @@
from .client import CodesphereSDK

from .exceptions import CodesphereError, AuthenticationError
from .resources.team import Team, TeamCreate, TeamBase
from .resources.team import (
Team,
TeamCreate,
TeamBase,
Domain,
CustomDomainConfig,
DomainVerificationStatus,
DomainBase,
DomainRouting,
)
from .resources.workspace import (
Workspace,
WorkspaceCreate,
Expand Down Expand Up @@ -51,4 +60,10 @@
"Characteristic",
"WsPlan",
"Image",
"Domain",
"CustomDomainConfig",
"DomainVerificationStatus",
"DomainBase",
"DomainsResource",
"DomainRouting",
]
46 changes: 0 additions & 46 deletions src/codesphere/client.py
Original file line number Diff line number Diff line change
@@ -1,48 +1,13 @@
"""
Codesphere SDK Client

This module provides the main client class, CodesphereSDK.
"""

from .http_client import APIHttpClient
from .resources.metadata import MetadataResource
from .resources.team import TeamsResource
from .resources.workspace import WorkspacesResource


class CodesphereSDK:
"""The main entrypoint for interacting with the `Codesphere Public API <https://codesphere.com/api/swagger-ui/?ref=codesphere.ghost.io#/>`_.

This class manages the HTTP client, its lifecycle,
and provides access to the various API resources.

Primary usage is via an asynchronous context manager:

Usage:
>>> import asyncio
>>> from codesphere import CodesphereSDK
>>>
>>> async def main():
>>> async with CodesphereSDK() as sdk:
>>> teams = await sdk.teams.list()
>>> print(teams)
>>>
>>> asyncio.run(main())

Attributes:
teams (TeamsResource): Access to Team API operations.
workspaces (WorkspacesResource): Access to Workspace API operations.
metadata (MetadataResource): Access to Metadata API operations.
"""

teams: TeamsResource
"""Access to the Team API. (e.g., `sdk.teams.list()`)"""

workspaces: WorkspacesResource
"""Access to the Workspace API. (e.g., `sdk.workspaces.list()`)"""

metadata: MetadataResource
"""Access to the Metadata API. (e.g., `sdk.metadata.list_plans()`)"""

def __init__(self):
self._http_client = APIHttpClient()
Expand All @@ -51,20 +16,9 @@ def __init__(self):
self.metadata = MetadataResource(self._http_client)

async def open(self):
"""Manually opens the underlying HTTP client session.

Required for manual lifecycle control when not using `async with`.

Usage:
>>> sdk = CodesphereSDK()
>>> await sdk.open()
>>> # ... API calls ...
>>> await sdk.close()
"""
await self._http_client.open()

async def close(self):
"""Manually closes the underlying HTTP client session."""
await self._http_client.close()

async def __aenter__(self):
Expand Down
4 changes: 0 additions & 4 deletions src/codesphere/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,6 @@


class Settings(BaseSettings):
"""
API Client Settings
"""

model_config = SettingsConfigDict(
env_file=".env", env_file_encoding="utf-8", env_prefix="CS_"
)
Expand Down
26 changes: 26 additions & 0 deletions src/codesphere/core/base.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,33 @@
from typing import Generic, List, TypeVar
from pydantic import BaseModel, ConfigDict, RootModel
from pydantic.alias_generators import to_camel

from ..http_client import APIHttpClient
from .handler import _APIOperationExecutor

ModelT = TypeVar("ModelT")


class ResourceBase(_APIOperationExecutor):
def __init__(self, http_client: APIHttpClient):
self._http_client = http_client


class CamelModel(BaseModel):
model_config = ConfigDict(
alias_generator=to_camel,
populate_by_name=True,
)


class ResourceList(RootModel[List[ModelT]], Generic[ModelT]):
root: List[ModelT]

def __iter__(self):
return iter(self.root)

def __getitem__(self, item):
return self.root[item]

def __len__(self):
return len(self.root)
4 changes: 4 additions & 0 deletions src/codesphere/core/handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ def _prepare_request_args(self) -> tuple[str, dict]:
else:
payload = json_data_obj

if payload is not None:
log.info(f"PAYLOAD TYPE: {type(payload)}")
log.info(f"PAYLOAD CONTENT: {payload}")

request_kwargs = {"params": self.kwargs.get("params"), "json": payload}
return endpoint, {k: v for k, v in request_kwargs.items() if v is not None}

Expand Down
21 changes: 8 additions & 13 deletions src/codesphere/core/operations.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,17 @@
from typing import Callable, Awaitable, List, Optional, Type, TypeAlias, TypeVar
from typing import Callable, Awaitable, Generic, Optional, Type, TypeAlias, TypeVar

from pydantic import BaseModel


_T = TypeVar("_T")
ResponseT = TypeVar("ResponseT")
InputT = TypeVar("InputT")

AsyncCallable: TypeAlias = Callable[[], Awaitable[_T]]


class APIOperation:
def __init__(
self,
method: str,
endpoint_template: str,
response_model: Type[BaseModel] | Type[List[BaseModel]],
input_model: Optional[Type[BaseModel]] = None,
):
self.method = method
self.endpoint_template = endpoint_template
self.response_model = response_model
self.input_model = input_model
class APIOperation(BaseModel, Generic[ResponseT, InputT]):
method: str
endpoint_template: str
response_model: Type[ResponseT]
input_model: Optional[Type[InputT]] = None
Empty file.
Empty file.
2 changes: 1 addition & 1 deletion src/codesphere/resources/metadata/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Metadata Resource & Models"""

from .models import Datacenter, Characteristic, WsPlan, Image
from .schemas import Datacenter, Characteristic, WsPlan, Image
from .resources import MetadataResource

__all__ = ["Datacenter", "Characteristic", "WsPlan", "Image", "MetadataResource"]
24 changes: 24 additions & 0 deletions src/codesphere/resources/metadata/operations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from ...core.base import ResourceList
from ...core.operations import APIOperation
from .schemas import Datacenter, Image, WsPlan

_LIST_DC_OP = APIOperation(
method="GET",
endpoint_template="/metadata/datacenters",
input_model=type(None),
response_model=ResourceList[Datacenter],
)

_LIST_PLANS_OP = APIOperation(
method="GET",
endpoint_template="/metadata/workspace-plans",
input_model=type(None),
response_model=ResourceList[WsPlan],
)

_LIST_IMAGES_OP = APIOperation(
method="GET",
endpoint_template="/metadata/workspace-base-images",
input_model=type(None),
response_model=ResourceList[Image],
)
Loading
Loading