Skip to content

Commit b03a4f0

Browse files
committed
refactor(config): update configuration access across multiple services
- Refactored the import path for CONFIG to streamline access in various service files. - Updated SentryManager, Tracing, ActivityHandler, EventHandler, and GithubService to utilize the new CONFIG structure. - Enhanced error handling in GithubService for missing configuration values, ensuring better diagnostics. - Adjusted environment checks to rely on CONFIG.DEBUG for sampling rates and tracing behavior.
1 parent e920b4c commit b03a4f0

File tree

5 files changed

+76
-50
lines changed

5 files changed

+76
-50
lines changed

src/tux/services/handlers/activity.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from loguru import logger
88

99
from tux.core.types import Tux
10-
from tux.shared.config.settings import Config
10+
from tux.shared.config import CONFIG
1111
from tux.shared.substitutions import handle_substitution
1212

1313
# Map the string type to the discord.ActivityType enum.
@@ -37,14 +37,14 @@ def build_activity_list() -> list[discord.Activity | discord.Streaming]:
3737
A list of activity objects.
3838
"""
3939

40-
if not Config.ACTIVITIES or not Config.ACTIVITIES.strip():
41-
logger.warning("Config.ACTIVITIES is empty or None. Returning an empty list.")
40+
if not CONFIG.BOT_INFO.ACTIVITIES or not CONFIG.BOT_INFO.ACTIVITIES.strip():
41+
logger.warning("CONFIG.BOT_INFO.ACTIVITIES is empty or None. Returning an empty list.")
4242
return []
4343

4444
try:
45-
activity_data = json.loads(Config.ACTIVITIES) # Safely parse JSON
45+
activity_data = json.loads(CONFIG.BOT_INFO.ACTIVITIES) # Safely parse JSON
4646
except json.JSONDecodeError:
47-
logger.error(f"Failed to parse ACTIVITIES JSON: {Config.ACTIVITIES!r}")
47+
logger.error(f"Failed to parse ACTIVITIES JSON: {CONFIG.BOT_INFO.ACTIVITIES!r}")
4848
raise # Re-raise after logging
4949

5050
activities: list[discord.Activity | discord.Streaming] = []

src/tux/services/handlers/event.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
from tux.core.base_cog import BaseCog
55
from tux.core.types import Tux
6-
from tux.shared.config.settings import CONFIG
6+
from tux.shared.config import CONFIG
77
from tux.shared.functions import is_harmful, strip_formatting
88
from tux.ui.embeds import EmbedCreator, EmbedType
99

@@ -35,7 +35,7 @@ async def handle_harmful_message(message: discord.Message) -> None:
3535
None
3636
"""
3737

38-
if message.author.bot and message.webhook_id not in CONFIG.BRIDGE_WEBHOOK_IDS:
38+
if message.author.bot and message.webhook_id not in CONFIG.IRC_CONFIG.BRIDGE_WEBHOOK_IDS:
3939
return
4040

4141
stripped_content = strip_formatting(message.content)
@@ -69,9 +69,9 @@ async def on_message_edit(self, before: discord.Message, after: discord.Message)
6969
@commands.Cog.listener()
7070
async def on_message(self, message: discord.Message) -> None:
7171
# Allow the IRC bridge to use the snippet command only
72-
if message.webhook_id in CONFIG.BRIDGE_WEBHOOK_IDS and (
73-
message.content.startswith(f"{CONFIG.DEFAULT_PREFIX}s ")
74-
or message.content.startswith(f"{CONFIG.DEFAULT_PREFIX}snippet ")
72+
if message.webhook_id in CONFIG.IRC_CONFIG.BRIDGE_WEBHOOK_IDS and (
73+
message.content.startswith(f"{CONFIG.get_prefix()}s ")
74+
or message.content.startswith(f"{CONFIG.get_prefix()}snippet ")
7575
):
7676
ctx = await self.bot.get_context(message)
7777
await self.bot.invoke(ctx)

src/tux/services/sentry_manager.py

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,7 @@
3030
from sentry_sdk.types import Event, Hint
3131

3232
from tux.core.context import get_interaction_context
33-
from tux.shared.config.env import get_current_env
34-
from tux.shared.config.settings import CONFIG
33+
from tux.shared.config import CONFIG
3534

3635
# Type alias for Sentry's log level strings.
3736
LogLevelStr = Literal["fatal", "critical", "error", "warning", "info", "debug"]
@@ -276,7 +275,7 @@ def _traces_sampler(sampling_context: dict[str, Any]) -> float:
276275
transaction_name = sampling_context.get("transaction_context", {}).get("name", "")
277276

278277
# Full sampling in development for debugging
279-
if get_current_env() in ("dev", "development"):
278+
if CONFIG.DEBUG:
280279
return 1.0
281280

282281
# Production sampling rates using dictionary lookup
@@ -302,7 +301,7 @@ def setup() -> None:
302301
This method configures the release version, environment, tracing, and
303302
enables Sentry's logging integration.
304303
"""
305-
if not CONFIG.SENTRY_DSN:
304+
if not CONFIG.EXTERNAL_SERVICES.SENTRY_DSN:
306305
logger.warning("No Sentry DSN configured, skipping Sentry setup")
307306
return
308307

@@ -311,11 +310,11 @@ def setup() -> None:
311310
try:
312311
sentry_sdk.init(
313312
# https://docs.sentry.io/platforms/python/configuration/options/#dsn
314-
dsn=CONFIG.SENTRY_DSN,
313+
dsn=CONFIG.EXTERNAL_SERVICES.SENTRY_DSN,
315314
# https://docs.sentry.io/platforms/python/configuration/options/#release
316-
release=CONFIG.BOT_VERSION,
315+
release=CONFIG.BOT_INFO.BOT_VERSION,
317316
# https://docs.sentry.io/platforms/python/configuration/options/#environment
318-
environment=get_current_env(),
317+
environment="development" if CONFIG.DEBUG else "production",
319318
integrations=[
320319
AsyncioIntegration(),
321320
LoguruIntegration(),
@@ -327,10 +326,10 @@ def setup() -> None:
327326
send_default_pii=False,
328327
# https://docs.sentry.io/platforms/python/configuration/options/#traces_sample_rate
329328
# Adjust sampling based on environment - 100% for dev, lower for production
330-
traces_sample_rate=1.0 if get_current_env() in ("dev", "development") else 0.1,
329+
traces_sample_rate=1.0 if CONFIG.DEBUG else 0.1,
331330
# Set profiles_sample_rate to profile transactions.
332331
# We recommend adjusting this value in production.
333-
profiles_sample_rate=1.0 if get_current_env() in ("dev", "development") else 0.01,
332+
profiles_sample_rate=1.0 if CONFIG.DEBUG else 0.01,
334333
# https://docs.sentry.io/platforms/python/configuration/filtering/#using-before-send
335334
before_send=SentryManager._before_send,
336335
before_send_transaction=SentryManager._before_send_transaction,

src/tux/services/tracing.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
from discord.ext import commands
2727
from loguru import logger
2828

29+
from tux.shared.config import CONFIG
30+
2931
# Type variables for better type hints with generic functions
3032
P = ParamSpec("P")
3133
T = TypeVar("T")
@@ -574,10 +576,7 @@ def enhanced_span(op: str, name: str = "", **initial_data: Any) -> Generator[Dum
574576
return
575577

576578
# In production, skip tracing for certain frequent operations
577-
env = initial_data.get("environment", "development")
578-
if env not in ("dev", "development") and any(
579-
skip_term in name.lower() for skip_term in ["safe_get_attr", "connect_or_create"]
580-
):
579+
if not CONFIG.DEBUG and any(skip_term in name.lower() for skip_term in ["safe_get_attr", "connect_or_create"]):
581580
yield DummySpan()
582581
return
583582

src/tux/services/wrappers/github.py

Lines changed: 55 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
)
1010
from loguru import logger
1111

12-
from tux.shared.config.settings import CONFIG
12+
from tux.shared.config import CONFIG
1313
from tux.shared.exceptions import (
1414
APIConnectionError,
1515
APIPermissionError,
@@ -20,13 +20,41 @@
2020

2121
class GithubService:
2222
def __init__(self) -> None:
23+
# Check if GitHub configuration is available
24+
if not CONFIG.EXTERNAL_SERVICES.GITHUB_APP_ID:
25+
msg = "GitHub App ID is not configured. Please set EXTERNAL_SERVICES__GITHUB_APP_ID in your .env file."
26+
raise ValueError(
27+
msg,
28+
)
29+
30+
if not CONFIG.EXTERNAL_SERVICES.GITHUB_PRIVATE_KEY:
31+
msg = "GitHub private key is not configured. Please set EXTERNAL_SERVICES__GITHUB_PRIVATE_KEY in your .env file."
32+
raise ValueError(
33+
msg,
34+
)
35+
36+
if not CONFIG.EXTERNAL_SERVICES.GITHUB_INSTALLATION_ID:
37+
msg = "GitHub installation ID is not configured. Please set EXTERNAL_SERVICES__GITHUB_INSTALLATION_ID in your .env file."
38+
raise ValueError(
39+
msg,
40+
)
41+
42+
# Try to convert installation ID to int, with better error handling
43+
try:
44+
installation_id = int(CONFIG.EXTERNAL_SERVICES.GITHUB_INSTALLATION_ID)
45+
except ValueError as e:
46+
msg = "GitHub installation ID must be a valid integer. Please check EXTERNAL_SERVICES__GITHUB_INSTALLATION_ID in your .env file."
47+
raise ValueError(
48+
msg,
49+
) from e
50+
2351
self.github = GitHub(
2452
AppInstallationAuthStrategy(
25-
CONFIG.GITHUB_APP_ID,
26-
CONFIG.GITHUB_PRIVATE_KEY,
27-
int(CONFIG.GITHUB_INSTALLATION_ID),
28-
CONFIG.GITHUB_CLIENT_ID,
29-
CONFIG.GITHUB_CLIENT_SECRET,
53+
CONFIG.EXTERNAL_SERVICES.GITHUB_APP_ID,
54+
CONFIG.EXTERNAL_SERVICES.GITHUB_PRIVATE_KEY,
55+
installation_id,
56+
CONFIG.EXTERNAL_SERVICES.GITHUB_CLIENT_ID,
57+
CONFIG.EXTERNAL_SERVICES.GITHUB_CLIENT_SECRET,
3058
),
3159
)
3260

@@ -41,8 +69,8 @@ async def get_repo(self) -> FullRepository:
4169
"""
4270
try:
4371
response: Response[FullRepository] = await self.github.rest.repos.async_get(
44-
CONFIG.GITHUB_REPO_OWNER,
45-
CONFIG.GITHUB_REPO,
72+
CONFIG.EXTERNAL_SERVICES.GITHUB_REPO_OWNER,
73+
CONFIG.EXTERNAL_SERVICES.GITHUB_REPO,
4674
)
4775

4876
repo: FullRepository = response.parsed_data
@@ -53,7 +81,7 @@ async def get_repo(self) -> FullRepository:
5381
if e.response.status_code == 404:
5482
raise APIResourceNotFoundError(
5583
service_name="GitHub",
56-
resource_identifier=f"{CONFIG.GITHUB_REPO_OWNER}/{CONFIG.GITHUB_REPO}",
84+
resource_identifier=f"{CONFIG.EXTERNAL_SERVICES.GITHUB_REPO_OWNER}/{CONFIG.EXTERNAL_SERVICES.GITHUB_REPO}",
5785
) from e
5886
if e.response.status_code == 403:
5987
raise APIPermissionError(service_name="GitHub") from e
@@ -87,8 +115,8 @@ async def create_issue(self, title: str, body: str) -> Issue:
87115
"""
88116
try:
89117
response: Response[Issue] = await self.github.rest.issues.async_create(
90-
CONFIG.GITHUB_REPO_OWNER,
91-
CONFIG.GITHUB_REPO,
118+
CONFIG.EXTERNAL_SERVICES.GITHUB_REPO_OWNER,
119+
CONFIG.EXTERNAL_SERVICES.GITHUB_REPO,
92120
title=title,
93121
body=body,
94122
)
@@ -131,8 +159,8 @@ async def create_issue_comment(self, issue_number: int, body: str) -> IssueComme
131159
"""
132160
try:
133161
response: Response[IssueComment] = await self.github.rest.issues.async_create_comment(
134-
CONFIG.GITHUB_REPO_OWNER,
135-
CONFIG.GITHUB_REPO,
162+
CONFIG.EXTERNAL_SERVICES.GITHUB_REPO_OWNER,
163+
CONFIG.EXTERNAL_SERVICES.GITHUB_REPO,
136164
issue_number,
137165
body=body,
138166
)
@@ -177,8 +205,8 @@ async def close_issue(self, issue_number: int) -> Issue:
177205
"""
178206
try:
179207
response: Response[Issue] = await self.github.rest.issues.async_update(
180-
CONFIG.GITHUB_REPO_OWNER,
181-
CONFIG.GITHUB_REPO,
208+
CONFIG.EXTERNAL_SERVICES.GITHUB_REPO_OWNER,
209+
CONFIG.EXTERNAL_SERVICES.GITHUB_REPO,
182210
issue_number,
183211
state="closed",
184212
)
@@ -224,8 +252,8 @@ async def get_issue(self, issue_number: int) -> Issue:
224252

225253
try:
226254
response: Response[Issue] = await self.github.rest.issues.async_get(
227-
CONFIG.GITHUB_REPO_OWNER,
228-
CONFIG.GITHUB_REPO,
255+
CONFIG.EXTERNAL_SERVICES.GITHUB_REPO_OWNER,
256+
CONFIG.EXTERNAL_SERVICES.GITHUB_REPO,
229257
issue_number,
230258
)
231259

@@ -263,8 +291,8 @@ async def get_open_issues(self) -> list[Issue]:
263291

264292
try:
265293
response: Response[list[Issue]] = await self.github.rest.issues.async_list_for_repo(
266-
CONFIG.GITHUB_REPO_OWNER,
267-
CONFIG.GITHUB_REPO,
294+
CONFIG.EXTERNAL_SERVICES.GITHUB_REPO_OWNER,
295+
CONFIG.EXTERNAL_SERVICES.GITHUB_REPO,
268296
state="open",
269297
)
270298

@@ -297,8 +325,8 @@ async def get_closed_issues(self) -> list[Issue]:
297325

298326
try:
299327
response: Response[list[Issue]] = await self.github.rest.issues.async_list_for_repo(
300-
CONFIG.GITHUB_REPO_OWNER,
301-
CONFIG.GITHUB_REPO,
328+
CONFIG.EXTERNAL_SERVICES.GITHUB_REPO_OWNER,
329+
CONFIG.EXTERNAL_SERVICES.GITHUB_REPO,
302330
state="closed",
303331
)
304332

@@ -331,8 +359,8 @@ async def get_open_pulls(self) -> list[PullRequestSimple]:
331359

332360
try:
333361
response: Response[list[PullRequestSimple]] = await self.github.rest.pulls.async_list(
334-
CONFIG.GITHUB_REPO_OWNER,
335-
CONFIG.GITHUB_REPO,
362+
CONFIG.EXTERNAL_SERVICES.GITHUB_REPO_OWNER,
363+
CONFIG.EXTERNAL_SERVICES.GITHUB_REPO,
336364
state="open",
337365
)
338366

@@ -365,8 +393,8 @@ async def get_closed_pulls(self) -> list[PullRequestSimple]:
365393

366394
try:
367395
response: Response[list[PullRequestSimple]] = await self.github.rest.pulls.async_list(
368-
CONFIG.GITHUB_REPO_OWNER,
369-
CONFIG.GITHUB_REPO,
396+
CONFIG.EXTERNAL_SERVICES.GITHUB_REPO_OWNER,
397+
CONFIG.EXTERNAL_SERVICES.GITHUB_REPO,
370398
state="closed",
371399
)
372400

@@ -404,8 +432,8 @@ async def get_pull(self, pr_number: int) -> PullRequest:
404432

405433
try:
406434
response: Response[PullRequest] = await self.github.rest.pulls.async_get(
407-
CONFIG.GITHUB_REPO_OWNER,
408-
CONFIG.GITHUB_REPO,
435+
CONFIG.EXTERNAL_SERVICES.GITHUB_REPO_OWNER,
436+
CONFIG.EXTERNAL_SERVICES.GITHUB_REPO,
409437
pr_number,
410438
)
411439

0 commit comments

Comments
 (0)