Skip to content

Commit ec0f2fe

Browse files
allissonCopilot
andauthored
feat: improve config validation (#21)
* feat: improve config validation * Update fastpubsub/config.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * test: add test for config validation * Update fastpubsub/config.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update fastpubsub/config.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * test: fix test --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 968393e commit ec0f2fe

File tree

2 files changed

+62
-11
lines changed

2 files changed

+62
-11
lines changed

fastpubsub/config.py

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,63 @@
1+
from enum import StrEnum
2+
3+
from pydantic import Field, field_validator, model_validator
4+
from pydantic.networks import IPvAnyAddress
15
from pydantic_settings import BaseSettings, SettingsConfigDict
26

37

8+
class LogLevel(StrEnum):
9+
debug = "debug"
10+
info = "info"
11+
warning = "warning"
12+
error = "error"
13+
critical = "critical"
14+
15+
416
class Settings(BaseSettings):
517
# database
618
database_url: str
719
database_echo: bool = False
8-
database_pool_size: int = 5
9-
database_max_overflow: int = 10
20+
database_pool_size: int = Field(default=5, ge=1)
21+
database_max_overflow: int = Field(default=10, ge=1)
1022
database_pool_pre_ping: bool = True
1123

1224
# log
1325
log_formatter: str = (
1426
"asctime=%(asctime)s level=%(levelname)s pathname=%(pathname)s line=%(lineno)s message=%(message)s"
1527
)
16-
log_level: str = "info"
28+
log_level: LogLevel = LogLevel.info
1729

1830
# subscription defaults
19-
subscription_max_attempts: int = 5
20-
subscription_backoff_min_seconds: int = 5
21-
subscription_backoff_max_seconds: int = 300
31+
subscription_max_attempts: int = Field(default=5, ge=1)
32+
subscription_backoff_min_seconds: int = Field(default=5, ge=1)
33+
subscription_backoff_max_seconds: int = Field(default=300, ge=1)
2234

2335
# api
2436
api_debug: bool = False
25-
api_host: str = "0.0.0.0"
26-
api_port: int = 8000
27-
api_num_workers: int = 1
37+
api_host: IPvAnyAddress = Field(default="0.0.0.0")
38+
api_port: int = Field(default=8000, ge=1)
39+
api_num_workers: int = Field(default=1, ge=1)
2840

2941
# workers
30-
cleanup_acked_messages_older_than_seconds: int = 3600
31-
cleanup_stuck_messages_lock_timeout_seconds: int = 60
42+
cleanup_acked_messages_older_than_seconds: int = Field(default=3600, ge=1)
43+
cleanup_stuck_messages_lock_timeout_seconds: int = Field(default=60, ge=1)
3244

3345
# load .env
3446
model_config = SettingsConfigDict(env_file=".env", env_prefix="fastpubsub_")
3547

48+
@field_validator("database_url")
49+
def validate_database_url_format(cls, v: str):
50+
if not v.startswith("postgresql+psycopg://"):
51+
raise ValueError("must start with 'postgresql+psycopg://'")
52+
return v
53+
54+
@model_validator(mode="after")
55+
def check_subscription_backoff_order(self) -> "Settings":
56+
if self.subscription_backoff_max_seconds < self.subscription_backoff_min_seconds:
57+
raise ValueError(
58+
"subscription_backoff_max_seconds must be greater than or equal to subscription_backoff_min_seconds"
59+
)
60+
return self
61+
3662

3763
settings = Settings()

tests/test_config.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import pytest
2+
from pydantic import ValidationError
3+
4+
from fastpubsub.config import Settings
5+
6+
7+
def test_settings_log_level():
8+
with pytest.raises(ValidationError) as excinfo:
9+
Settings(log_level="invalid")
10+
assert "Input should be 'debug', 'info', 'warning', 'error' or 'critical'" in str(excinfo.value)
11+
12+
13+
def test_settings_database_url_format():
14+
with pytest.raises(ValidationError) as excinfo:
15+
Settings(database_url="postgresql://fastpubsub:fastpubsub@localhost:5432/fastpubsub")
16+
assert "must start with 'postgresql+psycopg://'" in str(excinfo.value)
17+
18+
19+
def test_settings_subscription_backoff_order():
20+
with pytest.raises(ValidationError) as excinfo:
21+
Settings(subscription_backoff_min_seconds=5, subscription_backoff_max_seconds=4)
22+
assert (
23+
"subscription_backoff_max_seconds must be greater than or equal to subscription_backoff_min_seconds"
24+
in str(excinfo.value)
25+
)

0 commit comments

Comments
 (0)