Skip to content

Commit 0eeacd5

Browse files
authored
pydantic を使わないような仕組みに切り替える (#174)
* Remove deprecated packages and update dependencies in uv.lock - Removed "annotated-types" version 0.7.0. - Removed "pydantic" version 2.11.7 and its dependencies. - Removed "pydantic-core" version 2.33.2 and its dependencies. - Removed "pydantic-settings" version 2.10.1 and its dependencies. - Removed "python-dotenv" version 1.1.1. - Removed "typing-inspection" version 0.4.1. - Updated development dependencies to reflect the removal of pydantic-settings. * disconnect_connection_api 関数の URL 型を HttpUrl から str に変更し、簡易バリデーションを追加する
1 parent a0e55c2 commit 0eeacd5

File tree

4 files changed

+71
-169
lines changed

4 files changed

+71
-169
lines changed

pyproject.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ dev-dependencies = [
3737
"pyjwt",
3838
"pytest-repeat",
3939
"ty",
40-
"pydantic-settings",
4140
]
4241

4342
[tool.ruff]

tests/api.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import httpx
2-
from pydantic import HttpUrl
32

43

5-
def disconnect_connection_api(url: HttpUrl, channel_id: str, connection_id: str) -> httpx.Response:
4+
def disconnect_connection_api(url: str, channel_id: str, connection_id: str) -> httpx.Response:
5+
# URL の簡易バリデーション
6+
if not url or not (url.startswith("http://") or url.startswith("https://")):
7+
raise ValueError(f"Invalid URL: {url}")
8+
69
headers = {
710
"Content-Type": "application/json",
811
"x-sora-target": "Sora_20151104.DisconnectConnection",
@@ -11,4 +14,4 @@ def disconnect_connection_api(url: HttpUrl, channel_id: str, connection_id: str)
1114
"channel_id": channel_id,
1215
"connection_id": connection_id,
1316
}
14-
return httpx.post(str(url), headers=headers, json=body, follow_redirects=True)
17+
return httpx.post(url, headers=headers, json=body, follow_redirects=True)

tests/conftest.py

Lines changed: 65 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,74 @@
11
import importlib.metadata
2+
import os
23
import time
34
import uuid
4-
from typing import Annotated
5+
from pathlib import Path
6+
from typing import Any
57

68
import jwt
79
import pytest
8-
from pydantic import Field, HttpUrl, SecretStr, computed_field, field_validator
9-
from pydantic_settings import BaseSettings, NoDecode, SettingsConfigDict
1010

1111
# sora_sdk から SoraLoggingSeverity をインポート
1212
from sora_sdk import SoraLoggingSeverity
1313

1414

15-
class Settings(BaseSettings):
16-
model_config = SettingsConfigDict(env_file=".env", env_prefix=".env", env_file_encoding="utf-8")
17-
18-
# TODO: list[WebsocketUrl] 型にする
19-
signaling_urls: Annotated[list[str], NoDecode] = Field(default=[], alias="TEST_SIGNALING_URLS")
20-
channel_id_prefix: str = Field(default="", alias="TEST_CHANNEL_ID_PREFIX")
21-
secret: SecretStr | None = Field(default=None, alias="TEST_SECRET_KEY")
22-
api_url: HttpUrl | None = Field(default=None, alias="TEST_API_URL")
23-
# TODO: openh264_path は FilePath 型にする
24-
openh264_path: str | None = Field(default=None, alias="OPENH264_PATH")
25-
libwebrtc_log: SoraLoggingSeverity | None = Field(default=None, alias="TEST_LIBWEBRTC_LOG")
26-
27-
channel_id_suffix: str = Field(default_factory=lambda: str(uuid.uuid4()))
28-
29-
@field_validator("signaling_urls", mode="before")
30-
@classmethod
31-
def validate_signaling_urls(cls, v: str) -> list[str]:
32-
"""
33-
TEST_SIGNALING_URLS が , で区切られている場合、それぞれの URL をリストに変換する
34-
"""
35-
return [x.strip() for x in v.split(",")]
36-
37-
@field_validator("libwebrtc_log", mode="before")
38-
@classmethod
39-
def validate_libwebrtc_log(cls, v: str | None) -> SoraLoggingSeverity | None:
40-
if v is None:
15+
class Settings:
16+
def __init__(self):
17+
# .env ファイルから環境変数を読み込む
18+
self._load_env_file(".env")
19+
20+
# 環境変数から設定を読み込む
21+
# TEST_SIGNALING_URL (単数形) と TEST_SIGNALING_URLS (複数形) の両方をサポート
22+
signaling_urls_env = os.getenv("TEST_SIGNALING_URLS", os.getenv("TEST_SIGNALING_URL", ""))
23+
self.signaling_urls = self._parse_signaling_urls(signaling_urls_env)
24+
self.channel_id_prefix = os.getenv("TEST_CHANNEL_ID_PREFIX", "")
25+
self.secret = os.getenv("TEST_SECRET_KEY")
26+
self.api_url = self._parse_api_url(os.getenv("TEST_API_URL"))
27+
self.openh264_path = os.getenv("OPENH264_PATH")
28+
self.libwebrtc_log = self._parse_libwebrtc_log(os.getenv("TEST_LIBWEBRTC_LOG"))
29+
self.channel_id_suffix = str(uuid.uuid4())
30+
31+
def _load_env_file(self, env_file: str) -> None:
32+
"""環境変数ファイルを読み込む"""
33+
env_path = Path(env_file)
34+
if not env_path.exists():
35+
return
36+
37+
with open(env_path, "r", encoding="utf-8") as f:
38+
for line in f:
39+
line = line.strip()
40+
if not line or line.startswith("#"):
41+
continue
42+
43+
if "=" in line:
44+
key, value = line.split("=", 1)
45+
key = key.strip()
46+
value = value.strip().strip('"').strip("'")
47+
# 環境変数が既に設定されていない場合のみ設定
48+
if key not in os.environ:
49+
os.environ[key] = value
50+
51+
def _parse_signaling_urls(self, value: str) -> list[str]:
52+
"""TEST_SIGNALING_URLS が , で区切られている場合、それぞれの URL をリストに変換する"""
53+
if not value:
54+
return []
55+
return [x.strip() for x in value.split(",") if x.strip()]
56+
57+
def _parse_api_url(self, value: str | None) -> str | None:
58+
"""API URLのバリデーション"""
59+
if not value:
4160
return None
42-
43-
match v.lower():
61+
# 簡易的なHTTP/HTTPS URLチェック
62+
if not (value.startswith("http://") or value.startswith("https://")):
63+
raise ValueError(f"Invalid API URL: {value}")
64+
return value
65+
66+
def _parse_libwebrtc_log(self, value: str | None) -> SoraLoggingSeverity | None:
67+
"""libwebrtc_logの値をSoraLoggingSeverityに変換"""
68+
if not value:
69+
return None
70+
71+
match value.lower():
4472
case "verbose":
4573
return SoraLoggingSeverity.VERBOSE
4674
case "info":
@@ -52,18 +80,15 @@ def validate_libwebrtc_log(cls, v: str | None) -> SoraLoggingSeverity | None:
5280
case "none":
5381
return SoraLoggingSeverity.NONE
5482
case _:
55-
# TODO: 道の値が設定されてたらエラーにした方がいい気がする
83+
# TODO: 未知の値が設定されてたらエラーにした方がいい気がする
5684
return None
57-
58-
@computed_field
85+
5986
@property
6087
def channel_id(self) -> str:
61-
"""
62-
TEST_CHANNEL_ID_PREFIX と TEST_CHANNEL_ID_SUFFIX を組み合わせて channel_id を生成する
63-
"""
88+
"""TEST_CHANNEL_ID_PREFIX と TEST_CHANNEL_ID_SUFFIX を組み合わせて channel_id を生成する"""
6489
return f"{self.channel_id_prefix}_{self.channel_id_suffix}"
6590

66-
def access_token(self, **kwargs) -> str | None:
91+
def access_token(self, **kwargs: Any) -> str | None:
6792
if self.secret is None:
6893
return None
6994

@@ -76,7 +101,7 @@ def access_token(self, **kwargs) -> str | None:
76101

77102
access_token = jwt.encode(
78103
payload,
79-
self.secret.get_secret_value(),
104+
self.secret,
80105
algorithm="HS256",
81106
)
82107

@@ -85,6 +110,7 @@ def access_token(self, **kwargs) -> str | None:
85110

86111
def pytest_report_header(config):
87112
"""pytest の実行時に特定のライブラリのバージョンを追加表示"""
113+
# config パラメータは pytest から渡されるが、この関数では使用しない
88114
try:
89115
version = importlib.metadata.version("sora_sdk")
90116
return f"sora_sdk: {version}"

0 commit comments

Comments
 (0)