Skip to content

Commit 480270f

Browse files
committed
pythonize
1 parent 22c1d86 commit 480270f

6 files changed

Lines changed: 264 additions & 37 deletions

File tree

.github/workflows/check.yml

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,17 @@ jobs:
1010
runs-on: ubuntu-latest
1111
steps:
1212
- uses: actions/checkout@v4
13-
- uses: actions/setup-python@v5
13+
- name: Install uv
14+
uses: astral-sh/setup-uv@v4
1415
with:
15-
python-version: "3.12"
16-
# - name: Install
17-
# run: pip install -r requirements.txt
18-
# - name: Lint
19-
# run: pylint edgee
20-
# - name: Test
21-
# run: python -m unittest discover -s tests -p 'test_*.py'
16+
enable-cache: true
17+
- name: Set up Python
18+
run: uv python install 3.12
19+
- name: Install dependencies
20+
run: uv sync --all-extras
21+
- name: Ruff format check
22+
run: uv run ruff format --check .
23+
- name: Ruff lint
24+
run: uv run ruff check .
25+
- name: Run tests
26+
run: uv run pytest

edgee/__init__.py

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
11
"""Edgee Gateway SDK for Python"""
22

3-
import os
43
import json
5-
from typing import Optional, Union
4+
import os
65
from dataclasses import dataclass
7-
from urllib.request import Request, urlopen
86
from urllib.error import HTTPError
7+
from urllib.request import Request, urlopen
8+
9+
# API Configuration
10+
DEFAULT_BASE_URL = "https://api.edgee.ai"
11+
API_ENDPOINT = "/v1/chat/completions"
912

1013

1114
@dataclass
1215
class FunctionDefinition:
1316
name: str
14-
description: Optional[str] = None
15-
parameters: Optional[dict] = None
17+
description: str | None = None
18+
parameters: dict | None = None
1619

1720

1821
@dataclass
@@ -31,24 +34,24 @@ class ToolCall:
3134
@dataclass
3235
class Message:
3336
role: str # "system" | "user" | "assistant" | "tool"
34-
content: Optional[str] = None
35-
name: Optional[str] = None
36-
tool_calls: Optional[list[ToolCall]] = None
37-
tool_call_id: Optional[str] = None
37+
content: str | None = None
38+
name: str | None = None
39+
tool_calls: list[ToolCall] | None = None
40+
tool_call_id: str | None = None
3841

3942

4043
@dataclass
4144
class InputObject:
4245
messages: list[dict]
43-
tools: Optional[list[dict]] = None
44-
tool_choice: Optional[Union[str, dict]] = None
46+
tools: list[dict] | None = None
47+
tool_choice: str | dict | None = None
4548

4649

4750
@dataclass
4851
class Choice:
4952
index: int
5053
message: dict
51-
finish_reason: Optional[str]
54+
finish_reason: str | None
5255

5356

5457
@dataclass
@@ -61,43 +64,44 @@ class Usage:
6164
@dataclass
6265
class SendResponse:
6366
choices: list[Choice]
64-
usage: Optional[Usage] = None
67+
usage: Usage | None = None
6568

6669

6770
@dataclass
6871
class EdgeeConfig:
69-
api_key: Optional[str] = None
70-
base_url: Optional[str] = None
72+
api_key: str | None = None
73+
base_url: str | None = None
7174

7275

7376
class Edgee:
7477
def __init__(
7578
self,
76-
config: Optional[Union[str, EdgeeConfig, dict]] = None,
79+
config: str | EdgeeConfig | dict | None = None,
7780
):
78-
api_key: Optional[str] = None
79-
base_url: Optional[str] = None
80-
8181
if isinstance(config, str):
8282
# Backward compatibility: accept api_key as string
8383
api_key = config
84+
base_url = None
8485
elif isinstance(config, EdgeeConfig):
8586
api_key = config.api_key
8687
base_url = config.base_url
8788
elif isinstance(config, dict):
8889
api_key = config.get("api_key")
8990
base_url = config.get("base_url")
91+
else:
92+
api_key = None
93+
base_url = None
9094

9195
self.api_key = api_key or os.environ.get("EDGEE_API_KEY", "")
9296
if not self.api_key:
9397
raise ValueError("EDGEE_API_KEY is not set")
9498

95-
self.base_url = base_url or os.environ.get("EDGEE_BASE_URL", "https://api.edgee.ai")
99+
self.base_url = base_url or os.environ.get("EDGEE_BASE_URL", DEFAULT_BASE_URL)
96100

97101
def send(
98102
self,
99103
model: str,
100-
input: Union[str, InputObject, dict],
104+
input: str | InputObject | dict,
101105
) -> SendResponse:
102106
"""Send a completion request to the Edgee AI Gateway."""
103107

@@ -121,7 +125,7 @@ def send(
121125
body["tool_choice"] = tool_choice
122126

123127
request = Request(
124-
f"{self.base_url}/v1/chat/completions",
128+
f"{self.base_url}{API_ENDPOINT}",
125129
data=json.dumps(body).encode("utf-8"),
126130
headers={
127131
"Content-Type": "application/json",

example/test.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,3 @@
6161
)
6262
print(f"Content: {response3.choices[0].message.get('content')}")
6363
print(f"Tool calls: {response3.choices[0].message.get('tool_calls')}")
64-

pyproject.toml

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,39 @@ Homepage = "https://github.com/edgee-cloud/python-sdk"
2626
Repository = "https://github.com/edgee-cloud/python-sdk"
2727

2828
[project.optional-dependencies]
29-
dev = ["pytest>=8.0.0"]
29+
dev = ["pytest>=8.0.0", "ruff>=0.8.0"]
3030

3131
[build-system]
3232
requires = ["hatchling"]
3333
build-backend = "hatchling.build"
3434

3535
[tool.pytest.ini_options]
3636
testpaths = ["tests"]
37+
38+
[tool.ruff]
39+
target-version = "py310"
40+
line-length = 100
41+
42+
[tool.ruff.lint]
43+
select = [
44+
"E", # pycodestyle errors
45+
"W", # pycodestyle warnings
46+
"F", # pyflakes
47+
"I", # isort
48+
"B", # flake8-bugbear
49+
"C4", # flake8-comprehensions
50+
"UP", # pyupgrade
51+
]
52+
ignore = [
53+
"E501", # line too long (handled by formatter)
54+
]
55+
56+
[tool.ruff.format]
57+
quote-style = "double"
58+
indent-style = "space"
59+
60+
[dependency-groups]
61+
dev = [
62+
"pytest>=8.0.0",
63+
"ruff>=0.8.0",
64+
]

tests/test_edgee.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22

33
import json
44
import os
5+
from unittest.mock import MagicMock, patch
6+
57
import pytest
6-
from unittest.mock import patch, MagicMock
7-
from io import BytesIO
88

9-
from edgee import Edgee, EdgeeConfig, SendResponse, Choice, Usage
9+
from edgee import Edgee, EdgeeConfig
1010

1111

1212
class TestEdgeeConstructor:
@@ -122,7 +122,7 @@ def test_send_with_input_object(self, mock_urlopen):
122122
mock_urlopen.return_value = self._mock_response(mock_response_data)
123123

124124
client = Edgee("test-api-key")
125-
result = client.send(
125+
client.send(
126126
model="gpt-4",
127127
input={
128128
"messages": [
@@ -306,4 +306,3 @@ def test_config_base_url_overrides_env(self, mock_urlopen):
306306

307307
call_args = mock_urlopen.call_args[0][0]
308308
assert call_args.full_url == f"{config_base_url}/v1/chat/completions"
309-

0 commit comments

Comments
 (0)