Skip to content

Commit a09623b

Browse files
authored
Expand ruff configurations to enforce comprehensive code quality standards (#23)
## Summary Enhances our `ruff` configurations to enforce comprehensive standards across various aspects of code quality, including style, formatting, structure, complexity, security, bug prevention, and documentation. ## Details ### Changes Implemented: 1. **Code Style and Formatting:** - Enforced PEP 8 conventions, including spacing, indentation, and line length. - Included `isort` for consistent import sorting. - Added rules for trailing commas, commented-out code, import conventions, naming conventions, and quote usage. 2. **Code Structure and Complexity:** - Simplified complex expressions and improved readability. - Applied best practices for list, set, and dict comprehensions. - Checked for overly complex code using cyclomatic complexity. 3. **Code Security and Bug Prevention:** - Detected unused function arguments, boolean traps, and implicit string concatenations. - Prevented common programming mistakes and potential bugs. - Enforced correct exception handling and detected security issues. 4. **Code Documentation:** - Ensured adherence to documentation standards. - Detected unresolved FIXMEs and other temporary comments. ### Files Modified: - `.pre-commit-config.yaml`: Updated configurations to include new ruff rules and standards. - `pyproject.toml`: Extended ruff linting rules to cover additional checks for various code quality aspects. - Source and test files: Applied necessary changes to comply with the new ruff configurations, including refactoring code, updating documentation, and adding comments. ### Test Plan: - **Automated Testing:** - Automated tests updated to run the latest changes - **Manual Testing:** - Manually reviewed changes to ensure they align with the updated linting standards. - Manually ran tests and checks
1 parent 8494b7a commit a09623b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+703
-616
lines changed

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ repos:
2020
datasets,
2121
loguru,
2222
numpy,
23+
openai,
2324
pydantic,
2425
pydantic_settings,
2526
pyyaml,
26-
openai,
2727
requests,
2828
transformers,
2929

docs/__init__.py

Whitespace-only changes.

pyproject.toml

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,80 @@ ignore_missing_imports=true
9999
[tool.ruff]
100100
line-length = 88
101101
exclude = ["build", "dist", "env", ".venv"]
102-
lint.select = ["E", "F", "W"]
102+
lint.ignore = [
103+
"PLR0913",
104+
"TCH001",
105+
"COM812",
106+
"ISC001",
107+
"TCH002",
108+
]
109+
lint.select = [
110+
# Rules reference: https://docs.astral.sh/ruff/rules/
111+
112+
# Code Style / Formatting
113+
"E", # pycodestyle: checks adherence to PEP 8 conventions including spacing, indentation, and line length
114+
"W", # pycodestyle: checks adherence to PEP 8 conventions including spacing, indentation, and line length
115+
"A", # flake8-builtins: prevents shadowing of Python built-in names
116+
"C", # Convention: ensures code adheres to specific style and formatting conventions
117+
"COM", # flake8-commas: enforces the correct use of trailing commas
118+
"ERA", # eradicate: detects commented-out code that should be removed
119+
"I", # isort: ensures imports are sorted in a consistent manner
120+
"ICN", # flake8-import-conventions: enforces import conventions for better readability
121+
"N", # pep8-naming: enforces PEP 8 naming conventions for classes, functions, and variables
122+
"NPY", # NumPy: enforces best practices for using the NumPy library
123+
"PD", # pandas-vet: enforces best practices for using the pandas library
124+
"PT", # flake8-pytest-style: enforces best practices and style conventions for pytest tests
125+
"PTH", # flake8-use-pathlib: encourages the use of pathlib over os.path for file system operations
126+
"Q", # flake8-quotes: enforces consistent use of single or double quotes
127+
"TCH", # flake8-type-checking: enforces type checking practices and standards
128+
"TID", # flake8-tidy-imports: enforces tidy and well-organized imports
129+
130+
# Code Structure / Complexity
131+
"C4", # flake8-comprehensions: improves readability and performance of list, set, and dict comprehensions
132+
"C90", # mccabe: checks for overly complex code using cyclomatic complexity
133+
"FBT", # flake8-boolean-trap: prevents the use of boolean traps in function arguments and calls
134+
"ISC", # flake8-implicit-str-concat: prevents implicit string concatenation
135+
"PIE", # flake8-pie: identifies and corrects common code inefficiencies and mistakes
136+
"R", # Refactor: suggests improvements to code structure and readability
137+
"SIM", # flake8-simplify: simplifies complex expressions and improves code readability
138+
139+
# Code Security / Bug Prevention
140+
"ARG", # flake8-unused-arguments: detects unused function and method arguments
141+
"ASYNC", # flake8-async: identifies incorrect or inefficient usage patterns in asynchronous code
142+
"B", # flake8-bugbear: detects common programming mistakes and potential bugs
143+
"BLE", # flake8-blind-except: prevents blind exceptions that catch all exceptions without handling
144+
"E", # Error: detects and reports errors in the code
145+
"F", # Pyflakes: detects unused imports, shadowed imports, undefined variables, and various formatting errors in string operations
146+
"INP", # flake8-no-pep420: prevents implicit namespace packages by requiring __init__.py
147+
"PGH", # pygrep-hooks: detects deprecated and dangerous code patterns
148+
"PL", # Pylint: comprehensive source code analyzer for enforcing coding standards and detecting errors
149+
"RSE", # flake8-raise: ensures exceptions are raised correctly
150+
"S", # flake8-bandit: detects security issues and vulnerabilities in the code
151+
"SLF", # flake8-self: prevents incorrect usage of the self argument in class methods
152+
"T10", # flake8-debugger: detects the presence of debugging tools such as pdb
153+
"T20", # flake8-print: detects print statements left in the code
154+
"UP", # pyupgrade: automatically upgrades syntax for newer versions of Python
155+
"W", # Warning: provides warnings about potential issues in the code
156+
"YTT", # flake8-2020: identifies code that will break with future Python releases
157+
158+
# Code Documentation
159+
"FIX", # flake8-fixme: detects FIXMEs and other temporary comments that should be resolved
160+
]
161+
162+
[tool.ruff.lint.extend-per-file-ignores]
163+
"tests/**/*.py" = [
164+
"S101", # asserts allowed in tests
165+
"ARG", # Unused function args allowed in tests
166+
"FBT", # Booleans as positional arguments in tests, e.g. via @pytest.mark.parametrize()
167+
"PLR2004", # Magic value used in comparison
168+
"TCH002", # No import only type checking in tests
169+
"SLF001", # enable private member access in tests
170+
"S105", # allow hardcoded passwords in tests
171+
"S311", # allow standard pseudo-random generators in tests
172+
"PT011", # allow generic exceptions in tests
173+
"N806", # allow uppercase variable names in tests
174+
"PGH003", # allow general ignores in tests
175+
]
103176

104177

105178
[tool.pytest.ini_options]

src/config/__init__.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ class LoggingSettings(BaseModel):
1515

1616

1717
class OpenAISettings(BaseModel):
18-
1918
# OpenAI API key.
2019
api_key: str = "invalid"
2120

src/guidellm/backend/base.py

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import functools
12
from abc import ABC, abstractmethod
23
from dataclasses import dataclass
34
from enum import Enum
@@ -79,6 +80,16 @@ def create(cls, backend_type: BackendEngine, **kwargs) -> "Backend":
7980

8081
return Backend._registry[backend_type](**kwargs)
8182

83+
@property
84+
def default_model(self) -> str:
85+
"""
86+
Get the default model for the backend.
87+
88+
:return: The default model.
89+
:rtype: str
90+
"""
91+
return _cachable_default_model(self)
92+
8293
def submit(self, request: TextGenerationRequest) -> TextGenerationResult:
8394
"""
8495
Submit a result request and populate the BenchmarkResult.
@@ -92,7 +103,7 @@ def submit(self, request: TextGenerationRequest) -> TextGenerationResult:
92103
logger.info(f"Submitting request with prompt: {request.prompt}")
93104

94105
result = TextGenerationResult(
95-
request=TextGenerationRequest(prompt=request.prompt)
106+
request=TextGenerationRequest(prompt=request.prompt),
96107
)
97108
result.start(request.prompt)
98109

@@ -111,7 +122,8 @@ def submit(self, request: TextGenerationRequest) -> TextGenerationResult:
111122

112123
@abstractmethod
113124
def make_request(
114-
self, request: TextGenerationRequest
125+
self,
126+
request: TextGenerationRequest,
115127
) -> Iterator[GenerativeResponse]:
116128
"""
117129
Abstract method to make a request to the backend.
@@ -121,8 +133,7 @@ def make_request(
121133
:return: An iterator over the generative responses.
122134
:rtype: Iterator[GenerativeResponse]
123135
"""
124-
125-
pass
136+
raise NotImplementedError
126137

127138
@abstractmethod
128139
def available_models(self) -> List[str]:
@@ -132,20 +143,7 @@ def available_models(self) -> List[str]:
132143
:return: A list of available models.
133144
:rtype: List[str]
134145
"""
135-
136-
pass
137-
138-
@property
139-
@abstractmethod
140-
def default_model(self) -> str:
141-
"""
142-
Abstract method to get the default model for the backend.
143-
144-
:return: The default model.
145-
:rtype: str
146-
"""
147-
148-
pass
146+
raise NotImplementedError
149147

150148
@abstractmethod
151149
def model_tokenizer(self, model: str) -> Optional[str]:
@@ -157,5 +155,14 @@ def model_tokenizer(self, model: str) -> Optional[str]:
157155
:return: The tokenizer for the model, or None if it cannot be created.
158156
:rtype: Optional[str]
159157
"""
158+
raise NotImplementedError
159+
160+
161+
@functools.lru_cache(maxsize=1)
162+
def _cachable_default_model(backend: Backend) -> str:
163+
if models := backend.available_models():
164+
logger.debug(f"Default model: {models[0]}")
165+
return models[0]
160166

161-
pass
167+
logger.error("No models available.")
168+
raise ValueError("No models available.")

src/guidellm/backend/openai.py

Lines changed: 8 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
from typing import Any, Dict, Generator, List, Optional
22

33
import openai
4+
from config import settings
45
from loguru import logger
56
from openai import OpenAI, Stream
67
from openai.types import Completion
78
from transformers import AutoTokenizer
89

9-
from config import settings
1010
from guidellm.backend import Backend, BackendEngine, GenerativeResponse
1111
from guidellm.core import TextGenerationRequest
1212

@@ -53,7 +53,7 @@ def __init__(
5353
raise ValueError(
5454
"`GUIDELLM__OPENAI__API_KEY` environment variable "
5555
"or --openai-api-key CLI parameter "
56-
"must be specify for the OpenAI backend"
56+
"must be specify for the OpenAI backend",
5757
)
5858

5959
if target is not None:
@@ -65,16 +65,17 @@ def __init__(
6565
else:
6666
raise ValueError(
6767
"`GUIDELLM__OPENAI__BASE_URL` environment variable "
68-
"or --target CLI parameter must be specify for the OpenAI backend."
68+
"or --target CLI parameter must be specified for the OpenAI backend."
6969
)
7070

7171
self.openai_client = OpenAI(api_key=_api_key, base_url=base_url)
7272
self.model = model or self.default_model
7373

74-
logger.info(f"OpenAI {self.model} Backend listening on {target}")
74+
logger.info("OpenAI {} Backend listening on {}", self.model, target)
7575

7676
def make_request(
77-
self, request: TextGenerationRequest
77+
self,
78+
request: TextGenerationRequest,
7879
) -> Generator[GenerativeResponse, None, None]:
7980
"""
8081
Make a request to the OpenAI backend.
@@ -143,22 +144,6 @@ def available_models(self) -> List[str]:
143144
logger.info(f"Available models: {models}")
144145
return models
145146

146-
@property
147-
def default_model(self) -> str:
148-
"""
149-
Get the default model for the backend.
150-
151-
:return: The default model.
152-
:rtype: str
153-
"""
154-
155-
if models := self.available_models():
156-
logger.info(f"Default model: {models[0]}")
157-
return models[0]
158-
159-
logger.error("No models available.")
160-
raise ValueError("No models available.")
161-
162147
def model_tokenizer(self, model: str) -> Optional[Any]:
163148
"""
164149
Get the tokenizer for a model.
@@ -172,8 +157,8 @@ def model_tokenizer(self, model: str) -> Optional[Any]:
172157
tokenizer = AutoTokenizer.from_pretrained(model)
173158
logger.info(f"Tokenizer created for model: {model}")
174159
return tokenizer
175-
except Exception as e:
176-
logger.warning(f"Could not create tokenizer for model {model}: {e}")
160+
except Exception as err: # noqa: BLE001
161+
logger.warning(f"Could not create tokenizer for model {model}: {err}")
177162
return None
178163

179164
def _token_count(self, text: str) -> int:

src/guidellm/core/distribution.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ class Distribution(Serializable):
1616
"""
1717

1818
data: Sequence[float] = Field(
19-
default_factory=list, description="The data points of the distribution."
19+
default_factory=list,
20+
description="The data points of the distribution.",
2021
)
2122

2223
def __str__(self):
@@ -160,7 +161,7 @@ def describe(self) -> dict:
160161
"std_deviation": self.std_deviation,
161162
"percentile_indices": [10, 20, 30, 40, 50, 60, 70, 80, 90, 95, 99],
162163
"percentile_values": self.percentiles(
163-
[10, 20, 30, 40, 50, 60, 70, 80, 90, 95, 99]
164+
[10, 20, 30, 40, 50, 60, 70, 80, 90, 95, 99],
164165
),
165166
"min": self.min,
166167
"max": self.max,

src/guidellm/core/request.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@ class TextGenerationRequest(Serializable):
1717
)
1818
prompt: str = Field(description="The input prompt for the text generation.")
1919
prompt_token_count: Optional[int] = Field(
20-
default=None, description="The number of tokens in the input prompt."
20+
default=None,
21+
description="The number of tokens in the input prompt.",
2122
)
2223
generate_token_count: Optional[int] = Field(
23-
default=None, description="The number of tokens to generate."
24+
default=None,
25+
description="The number of tokens to generate.",
2426
)
2527
params: Dict[str, Any] = Field(
2628
default_factory=dict,

0 commit comments

Comments
 (0)