Skip to content

Commit 2e938ec

Browse files
anfredetteclaude
andcommitted
Add ruff for code quality and linting
Add ruff 0.8.4 as development dependency with configuration in pyproject.toml. Auto-fix 170 code quality issues including import sorting, modern Python syntax, and redundant code patterns. Configure ruff with: - Line length: 100 characters - Python 3.11+ syntax enforcement - Import sorting (isort) - Common bug detection rules Update DEVELOPER_GUIDE.md with linting workflow and usage examples. Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Andre Fredette <afredette@redhat.com>
1 parent b234035 commit 2e938ec

File tree

18 files changed

+245
-137
lines changed

18 files changed

+245
-137
lines changed

backend/src/api/routes.py

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,18 @@
33
import logging
44
import os
55
from datetime import datetime
6-
from typing import List, Optional
6+
77
from fastapi import FastAPI, HTTPException
88
from fastapi.middleware.cors import CORSMiddleware
99
from pydantic import BaseModel
1010

11-
from ..context_intent.schema import DeploymentRecommendation, ConversationMessage
12-
from ..orchestration.workflow import RecommendationWorkflow
11+
from ..context_intent.schema import ConversationMessage, DeploymentRecommendation
12+
from ..deployment.cluster import KubernetesClusterManager, KubernetesDeploymentError
13+
from ..deployment.generator import DeploymentGenerator
14+
from ..deployment.validator import ValidationError, YAMLValidator
1315
from ..knowledge_base.model_catalog import ModelCatalog
1416
from ..knowledge_base.slo_templates import SLOTemplateRepository
15-
from ..deployment.generator import DeploymentGenerator
16-
from ..deployment.validator import YAMLValidator, ValidationError
17-
from ..deployment.cluster import KubernetesClusterManager, KubernetesDeploymentError
17+
from ..orchestration.workflow import RecommendationWorkflow
1818

1919
# Configure logging - check for DEBUG environment variable
2020
debug_mode = os.getenv("COMPASS_DEBUG", "false").lower() == "true"
@@ -64,7 +64,7 @@
6464
class RecommendationRequest(BaseModel):
6565
"""Request for deployment recommendation."""
6666
user_message: str
67-
conversation_history: Optional[List[ConversationMessage]] = None
67+
conversation_history: list[ConversationMessage] | None = None
6868

6969

7070
class SimpleRecommendationRequest(BaseModel):
@@ -76,14 +76,14 @@ class RecommendationResponse(BaseModel):
7676
"""Response with deployment recommendation."""
7777
recommendation: DeploymentRecommendation
7878
success: bool = True
79-
message: Optional[str] = None
79+
message: str | None = None
8080

8181

8282
class ErrorResponse(BaseModel):
8383
"""Error response."""
8484
success: bool = False
8585
error: str
86-
details: Optional[str] = None
86+
details: str | None = None
8787

8888

8989
class DeploymentRequest(BaseModel):
@@ -98,7 +98,7 @@ class DeploymentResponse(BaseModel):
9898
namespace: str
9999
files: dict
100100
success: bool = True
101-
message: Optional[str] = None
101+
message: str | None = None
102102

103103

104104
class DeploymentStatusResponse(BaseModel):
@@ -109,7 +109,7 @@ class DeploymentStatusResponse(BaseModel):
109109
resource_utilization: dict
110110
cost_analysis: dict
111111
traffic_patterns: dict
112-
recommendations: Optional[List[str]] = None
112+
recommendations: list[str] | None = None
113113

114114

115115
# Health check endpoint
@@ -619,15 +619,13 @@ async def get_deployment_yaml(deployment_id: str):
619619
"""
620620
try:
621621
# Get the output directory from deployment generator
622-
import os
623-
from pathlib import Path
624622

625623
output_dir = deployment_generator.output_dir
626624

627625
# Find all YAML files for this deployment
628626
yaml_files = {}
629627
for file_path in output_dir.glob(f"{deployment_id}*.yaml"):
630-
with open(file_path, 'r') as f:
628+
with open(file_path) as f:
631629
yaml_files[file_path.name] = f.read()
632630

633631
if not yaml_files:

backend/src/context_intent/extractor.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
"""Intent extraction from conversational input."""
22

33
import logging
4-
from typing import List, Dict, Optional
5-
from pathlib import Path
64
from datetime import datetime
5+
from pathlib import Path
76

8-
from .schema import DeploymentIntent, ConversationMessage
97
from ..llm.ollama_client import OllamaClient
10-
from ..llm.prompts import build_intent_extraction_prompt, INTENT_EXTRACTION_SCHEMA
8+
from ..llm.prompts import INTENT_EXTRACTION_SCHEMA, build_intent_extraction_prompt
9+
from .schema import ConversationMessage, DeploymentIntent
1110

1211
logger = logging.getLogger(__name__)
1312

@@ -19,7 +18,7 @@
1918
class IntentExtractor:
2019
"""Extract structured deployment intent from natural language conversation."""
2120

22-
def __init__(self, llm_client: Optional[OllamaClient] = None):
21+
def __init__(self, llm_client: OllamaClient | None = None):
2322
"""
2423
Initialize intent extractor.
2524
@@ -31,7 +30,7 @@ def __init__(self, llm_client: Optional[OllamaClient] = None):
3130
def extract_intent(
3231
self,
3332
user_message: str,
34-
conversation_history: Optional[List[ConversationMessage]] = None
33+
conversation_history: list[ConversationMessage] | None = None
3534
) -> DeploymentIntent:
3635
"""
3736
Extract deployment intent from user message.
@@ -106,7 +105,7 @@ def extract_intent(
106105
logger.error(f"Failed to extract intent: {e}")
107106
raise ValueError(f"Intent extraction failed: {e}")
108107

109-
def _parse_extracted_intent(self, raw_data: Dict) -> DeploymentIntent:
108+
def _parse_extracted_intent(self, raw_data: dict) -> DeploymentIntent:
110109
"""
111110
Parse and validate raw LLM output into DeploymentIntent.
112111
@@ -128,7 +127,7 @@ def _parse_extracted_intent(self, raw_data: Dict) -> DeploymentIntent:
128127
logger.error(f"Failed to parse intent from: {cleaned_data}")
129128
raise ValueError(f"Invalid intent data: {e}")
130129

131-
def _clean_llm_output(self, data: Dict) -> Dict:
130+
def _clean_llm_output(self, data: dict) -> dict:
132131
"""
133132
Clean common LLM output mistakes.
134133

backend/src/context_intent/schema.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
"""Data schemas for deployment intent and specifications."""
22

3-
from typing import Optional, List, Literal
3+
from typing import Literal
4+
45
from pydantic import BaseModel, Field
56

67

78
class TrafficProfile(BaseModel):
89
"""Traffic characteristics for the deployment."""
910

1011
prompt_tokens_mean: int = Field(..., description="Average prompt length in tokens")
11-
prompt_tokens_variance: Optional[int] = Field(None, description="Variance in prompt length")
12+
prompt_tokens_variance: int | None = Field(None, description="Variance in prompt length")
1213
generation_tokens_mean: int = Field(..., description="Average generation length in tokens")
13-
generation_tokens_variance: Optional[int] = Field(None, description="Variance in generation length")
14+
generation_tokens_variance: int | None = Field(None, description="Variance in generation length")
1415
expected_qps: float = Field(..., description="Expected queries per second")
15-
requests_per_user_per_day: Optional[int] = Field(None, description="User request frequency")
16+
requests_per_user_per_day: int | None = Field(None, description="User request frequency")
1617

1718

1819
class SLOTargets(BaseModel):
@@ -62,12 +63,12 @@ class DeploymentIntent(BaseModel):
6263
description="Cost sensitivity"
6364
)
6465

65-
domain_specialization: List[str] = Field(
66+
domain_specialization: list[str] = Field(
6667
default_factory=lambda: ["general"],
6768
description="Domain requirements (general, code, multilingual, enterprise)"
6869
)
6970

70-
additional_context: Optional[str] = Field(
71+
additional_context: str | None = Field(
7172
None,
7273
description="Any other relevant details from conversation"
7374
)
@@ -103,7 +104,7 @@ class DeploymentRecommendation(BaseModel):
103104
# Metadata
104105
meets_slo: bool = Field(..., description="Whether configuration meets SLO targets")
105106
reasoning: str = Field(..., description="Explanation of recommendation choice")
106-
alternative_options: Optional[List[dict]] = Field(
107+
alternative_options: list[dict] | None = Field(
107108
default=None,
108109
description="Alternative configurations with trade-offs"
109110
)
@@ -114,4 +115,4 @@ class ConversationMessage(BaseModel):
114115

115116
role: Literal["user", "assistant", "system"]
116117
content: str
117-
timestamp: Optional[str] = None
118+
timestamp: str | None = None

backend/src/deployment/cluster.py

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,11 @@
44
and the Kubernetes Python client.
55
"""
66

7-
import os
87
import logging
8+
import os
99
import subprocess
10-
from pathlib import Path
11-
from typing import Dict, Any, List, Optional
1210
from datetime import datetime
11+
from typing import Any
1312

1413
logger = logging.getLogger(__name__)
1514

@@ -87,7 +86,7 @@ def create_namespace_if_not_exists(self) -> bool:
8786
except subprocess.TimeoutExpired:
8887
raise KubernetesDeploymentError("Namespace operation timed out")
8988

90-
def apply_yaml(self, yaml_path: str) -> Dict[str, Any]:
89+
def apply_yaml(self, yaml_path: str) -> dict[str, Any]:
9190
"""
9291
Apply a YAML file to the cluster.
9392
@@ -124,7 +123,7 @@ def apply_yaml(self, yaml_path: str) -> Dict[str, Any]:
124123
except subprocess.TimeoutExpired:
125124
raise KubernetesDeploymentError(f"Timeout applying {yaml_path}")
126125

127-
def deploy_all(self, yaml_files: List[str]) -> Dict[str, Any]:
126+
def deploy_all(self, yaml_files: list[str]) -> dict[str, Any]:
128127
"""
129128
Deploy all YAML files to the cluster.
130129
@@ -164,7 +163,7 @@ def deploy_all(self, yaml_files: List[str]) -> Dict[str, Any]:
164163
"timestamp": datetime.now().isoformat()
165164
}
166165

167-
def get_inferenceservice_status(self, deployment_id: str) -> Dict[str, Any]:
166+
def get_inferenceservice_status(self, deployment_id: str) -> dict[str, Any]:
168167
"""
169168
Get status of an InferenceService.
170169
@@ -234,7 +233,7 @@ def get_inferenceservice_status(self, deployment_id: str) -> Dict[str, Any]:
234233
"error": str(e)
235234
}
236235

237-
def get_deployment_pods(self, deployment_id: str) -> List[Dict[str, Any]]:
236+
def get_deployment_pods(self, deployment_id: str) -> list[dict[str, Any]]:
238237
"""
239238
Get pods associated with a deployment.
240239
@@ -285,7 +284,7 @@ def get_deployment_pods(self, deployment_id: str) -> List[Dict[str, Any]]:
285284
logger.error(f"Error getting pods: {e}")
286285
return []
287286

288-
def delete_inferenceservice(self, deployment_id: str) -> Dict[str, Any]:
287+
def delete_inferenceservice(self, deployment_id: str) -> dict[str, Any]:
289288
"""
290289
Delete an InferenceService.
291290
@@ -328,7 +327,7 @@ def delete_inferenceservice(self, deployment_id: str) -> Dict[str, Any]:
328327
"error": str(e)
329328
}
330329

331-
def list_inferenceservices(self) -> List[str]:
330+
def list_inferenceservices(self) -> list[str]:
332331
"""
333332
List all InferenceServices in namespace.
334333

backend/src/deployment/generator.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44
LLM inference deployments using Jinja2 templates.
55
"""
66

7-
import os
87
import logging
98
from datetime import datetime
109
from pathlib import Path
11-
from typing import Dict, Any, List, Optional
12-
from jinja2 import Environment, FileSystemLoader, Template
10+
from typing import Any
11+
12+
from jinja2 import Environment, FileSystemLoader
1313

1414
from ..context_intent.schema import DeploymentRecommendation
1515

@@ -31,7 +31,7 @@ class DeploymentGenerator:
3131
# vLLM version to use
3232
VLLM_VERSION = "v0.6.2"
3333

34-
def __init__(self, output_dir: Optional[str] = None, simulator_mode: bool = False):
34+
def __init__(self, output_dir: str | None = None, simulator_mode: bool = False):
3535
"""
3636
Initialize the deployment generator.
3737
@@ -107,7 +107,7 @@ def _prepare_template_context(
107107
recommendation: DeploymentRecommendation,
108108
deployment_id: str,
109109
namespace: str = "default"
110-
) -> Dict[str, Any]:
110+
) -> dict[str, Any]:
111111
"""
112112
Prepare context dictionary for Jinja2 templates.
113113
@@ -237,7 +237,7 @@ def generate_all(
237237
self,
238238
recommendation: DeploymentRecommendation,
239239
namespace: str = "default"
240-
) -> Dict[str, str]:
240+
) -> dict[str, str]:
241241
"""
242242
Generate all deployment YAML files.
243243
@@ -299,7 +299,7 @@ def generate_all(
299299
def generate_kserve_yaml(
300300
self,
301301
recommendation: DeploymentRecommendation,
302-
deployment_id: Optional[str] = None,
302+
deployment_id: str | None = None,
303303
namespace: str = "default"
304304
) -> str:
305305
"""

0 commit comments

Comments
 (0)