Skip to content

Commit 08f653c

Browse files
authored
fix: ruff errors (#40)
* fix: ruff errors long lines, optimize imports * fix: unit test caught error use formatted string to output statistics * fix: ruff errors in tests optimize imports remove unused vars add missing parameters * fix: ruff errors in examples improve logging and error handling in OpenTelemetry integration * fix: ruff error in examples update parameter name for clarity in test runner * fix: ruff error in examples long lines unbound reference * fix: run ruff linter and formatter on source tests and examples --------- Co-authored-by: Paul Zabelin <paulz@users.noreply.github.com>
1 parent 1ccd1b9 commit 08f653c

File tree

17 files changed

+136
-132
lines changed

17 files changed

+136
-132
lines changed

.github/workflows/python-tests.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,5 +41,10 @@ jobs:
4141
- name: Type check Python code
4242
run: uv run mypy src
4343

44+
- name: Run ruff linter and formatter
45+
run: |
46+
uv run ruff check src tests examples
47+
uv run ruff format src tests examples
48+
4449
- name: Check package build
4550
run: uv build --verbose

examples/team_recommender/src/logger_to_opentelemetry.py

Lines changed: 12 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
import logging
22
import sys
3-
from typing import Any, Dict, Optional
3+
from typing import Optional
44

5-
# OpenTelemetry imports
65
from opentelemetry import trace
7-
from opentelemetry.semconv.resource import ResourceAttributes
8-
from opentelemetry.trace import TracerProvider
96
from opentelemetry.trace.span import Span
107

118

@@ -26,6 +23,7 @@ def emit(self, record: logging.LogRecord) -> None:
2623
"""
2724
Convert a LogRecord to an OpenTelemetry span event.
2825
"""
26+
# noinspection PyBroadException
2927
try:
3028
# Get the current active span, if available
3129
current_span: Span = trace.get_current_span()
@@ -51,7 +49,7 @@ def emit(self, record: logging.LogRecord) -> None:
5149
attributes.update(record.otel_attributes)
5250

5351
# Format the message
54-
message = self.format(record)
52+
self.format(record)
5553

5654
# Add event to the current span
5755
current_span.add_event(name=f"log.{record.levelname.lower()}", attributes=attributes)
@@ -73,52 +71,31 @@ def emit(self, record: logging.LogRecord) -> None:
7371
self.handleError(record)
7472

7573

76-
def configure_opentelemetry(
77-
service_name: str, extra_resources: Optional[Dict[str, Any]] = None
78-
) -> None:
79-
"""Configure OpenTelemetry tracer with console exporter for demonstration."""
80-
# Create a resource with service info
81-
resource_attributes = {ResourceAttributes.SERVICE_NAME: service_name}
82-
83-
if extra_resources:
84-
resource_attributes.update(extra_resources)
85-
86-
# Create and set the TracerProvider
87-
resource = Resource.create(resource_attributes)
88-
trace.set_tracer_provider(TracerProvider(resource=resource))
89-
90-
# Add console exporter for demo purposes
91-
# In production, you'd use OTLP, Jaeger, Zipkin, etc.
92-
processor = BatchSpanProcessor(ConsoleSpanExporter())
93-
trace.get_tracer_provider().add_span_processor(processor)
94-
95-
9674
def configure_logger_for_opentelemetry(logger_name: Optional[str] = None) -> logging.Logger:
9775
"""Configure a logger to send events to OpenTelemetry."""
9876
# Get logger
99-
logger = logging.getLogger(logger_name)
77+
ot_logger = logging.getLogger(logger_name)
10078

10179
# Create and add OpenTelemetry handler
102-
otel_handler = OpenTelemetryLogHandler()
80+
ot_handler = OpenTelemetryLogHandler()
10381
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
104-
otel_handler.setFormatter(formatter)
105-
logger.addHandler(otel_handler)
82+
ot_handler.setFormatter(formatter)
83+
ot_logger.addHandler(ot_handler)
10684

10785
# You can keep console output for local development
10886
console_handler = logging.StreamHandler(sys.stdout)
10987
console_handler.setFormatter(formatter)
110-
logger.addHandler(console_handler)
88+
ot_logger.addHandler(console_handler)
11189

11290
# Set level
113-
logger.setLevel(logging.INFO)
91+
ot_logger.setLevel(logging.INFO)
11492

115-
return logger
93+
return ot_logger
11694

11795

11896
# Example usage
11997
if __name__ == "__main__":
12098
# Configure OpenTelemetry
121-
configure_opentelemetry("example-service")
12299

123100
# Configure logger
124101
logger = configure_logger_for_opentelemetry("example.app")
@@ -136,7 +113,7 @@ def configure_logger_for_opentelemetry(logger_name: Optional[str] = None) -> log
136113
try:
137114
# Simulate an error
138115
result = 1 / 0
139-
except Exception:
140-
logger.exception("Operation failed")
116+
except Exception as simulated_error:
117+
logger.exception(f"Operation failed: {simulated_error}")
141118

142119
logger.info("Operation completed")
Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,42 @@
1-
import time
21
import logging
2+
import time
33
from functools import wraps
4-
from typing import Any, Callable, TypeVar, Optional, Tuple, Type, Union, Dict, List
4+
from typing import Any, Callable, Optional, Tuple, Type, TypeVar
55

6-
T = TypeVar('T')
6+
T = TypeVar("T")
77
logger = logging.getLogger(__name__)
88

9+
910
def retry(
1011
max_attempts: int = 3,
1112
exceptions: Tuple[Type[Exception], ...] = (Exception,),
1213
initial_delay: float = 1.0,
1314
backoff_factor: float = 2.0,
14-
logger_name: Optional[str] = None
15+
logger_name: Optional[str] = None,
1516
) -> Callable:
1617
"""
1718
Retry decorator with exponential backoff for handling transient errors.
18-
19+
1920
Args:
2021
max_attempts: Maximum number of attempts (including first try)
2122
exceptions: Tuple of exception types to catch and retry
2223
initial_delay: Initial delay between retries in seconds
2324
backoff_factor: Multiplier for delay after each retry
2425
logger_name: Optional logger name for custom logging
25-
26+
2627
Returns:
2728
Decorated function with retry logic
2829
"""
2930
local_logger = logger
3031
if logger_name:
3132
local_logger = logging.getLogger(logger_name)
32-
33+
3334
def decorator(func: Callable[..., T]) -> Callable[..., T]:
3435
@wraps(func)
3536
def wrapper(*args: Any, **kwargs: Any) -> T:
3637
attempt = 1
3738
current_delay = initial_delay
38-
39+
3940
while True:
4041
try:
4142
return func(*args, **kwargs)
@@ -45,16 +46,16 @@ def wrapper(*args: Any, **kwargs: Any) -> T:
4546
f"Failed after {max_attempts} attempts: {e.__class__.__name__}: {str(e)}"
4647
)
4748
raise
48-
49+
4950
local_logger.warning(
5051
f"Attempt {attempt}/{max_attempts} failed with {e.__class__.__name__}: {str(e)}. "
5152
f"Retrying in {current_delay:.2f}s..."
5253
)
53-
54+
5455
time.sleep(current_delay)
5556
current_delay *= backoff_factor
5657
attempt += 1
57-
58+
5859
return wrapper
59-
60+
6061
return decorator

examples/team_recommender/tests/example_1_text_response/test_good_fit_for_project.py

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,18 @@ def test_response_shows_developer_names():
66
assert client is not None
77

88
system_prompt = """
9-
You will get a description of a project, and your task is to tell me the best developers from the given list for the project
10-
based on their skills.
9+
You will get a description of a project, and your task is
10+
to tell me the best developers from the given list for the project based on their skills.
1111
Today's date is April 15th, 2025.
12-
Pick only developers who are available after the project start date. Pick people with higher skill levels first.
12+
Pick only developers who are available after the project start date.
13+
Pick people with higher skill levels first.
1314
1415
Here is the skills data:
15-
Sam Thomas - Swift, Objective-C
16-
Drew Anderson - Swift, on vacation June 1st - June 10th
17-
Joe Smith - Android
18-
Robert Sanders - React Native
19-
"""
16+
Sam Thomas - Swift, Objective-C
17+
Drew Anderson - Swift, on vacation June 1st - June 10th
18+
Joe Smith - Android
19+
Robert Sanders - React Native
20+
"""
2021

2122
project_description = """
2223
This is a mobile iOS project for a telecom company. The project starts June 3rd.
@@ -35,19 +36,23 @@ def test_response_shows_developer_names():
3536
# For the iOS Native project starting on June 3rd, the best developers based on the given list would be:
3637
#
3738
# 1. Sam Thomas - Specializes in Swift and Objective-C, and is available for the project.
38-
# 2. Drew Anderson - Specializes in Swift but will be on vacation from June 1st to June 10th, so they are not available when the project starts.
39+
# 2. Drew Anderson - Specializes in Swift but will be on vacation from June 1st to June 10th,
40+
# so they are not available when the project starts.
3941
#
4042
# Therefore, Sam Thomas is the most suitable developer for this project.
4143
assert "Sam Thomas" in response
42-
assert "Drew Anderson" in response, "Surprisingly Drew Anderson is on vacation but still in the response"
44+
assert "Drew Anderson" in response, (
45+
"Surprisingly Drew Anderson is on vacation but still in the response"
46+
)
47+
4348

4449
def test_llm_will_hallucinate_given_no_data():
4550
client = OpenAI()
4651
assert client is not None
4752

4853
system_prompt = """
49-
You will get a description of a project, and your task is to tell me the best developers from the given list for the project
50-
based on their skills.
54+
You will get a description of a project, and your task is to tell me the best developers
55+
from the given list for the project based on their skills.
5156
Today's date is April 15th, 2025.
5257
Pick only developers who are available after the project start date. Pick people with higher skill levels first.
5358
@@ -83,7 +88,8 @@ def test_llm_will_hallucinate_given_no_data():
8388
# - Skills: iOS Native, Mobile UI Design
8489
# - Availability: Available starting May 20th
8590
#
86-
# Based on the project requirements and availability, the best developer for this mobile iOS project for the telecom company would be:
91+
# Based on the project requirements and availability, the best developer for this mobile iOS project
92+
# for the telecom company would be:
8793
#
8894
# 1. Sarah Johnson
8995
# - Skills: iOS Native, Mobile Development
@@ -92,6 +98,10 @@ def test_llm_will_hallucinate_given_no_data():
9298
# 2. Jamie Smith
9399
# - Skills: iOS Native, Mobile UI Design
94100
# - Availability: Available starting May 20th
95-
assert "Sam Thomas" not in response, "LLM obviously could not get our expected developer and will hallucinate"
101+
assert "Sam Thomas" not in response, (
102+
"LLM obviously could not get our expected developer and will hallucinate"
103+
)
96104
assert "Drew Anderson" not in response, "Response will contain made up names"
97-
assert len(response.split('\n')) > 5, "response contains list of made up developers in multiple lines"
105+
assert len(response.split("\n")) > 5, (
106+
"response contains list of made up developers in multiple lines"
107+
)

examples/team_recommender/tests/example_2_unit/test_allocations_unit.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,17 @@ def test_allocations():
1111
acceptable_people = ["Sam Thomas", "Drew Anderson", "Alex Wilson", "Alex Johnson"]
1212

1313
system_prompt = f"""
14-
You will get a description of a project, and your task is to tell me the best developers from the given list for the project
15-
based on their skills.
14+
You will get a description of a project, and your task is
15+
to tell me the best developers from the given list for the project based on their skills.
1616
Today's date is April 15th, 2025.
17-
Pick only developers who are available after the project start date. Pick people with higher skill levels first.
18-
respond in json with this structure:
17+
Pick only developers who are available after the project start date.
18+
Pick people with higher skill levels first.
19+
Respond in json with this structure:
1920
{example_output}
2021
2122
Here is the skills data:
2223
"""
24+
2325
system_prompt = system_prompt + str(skills_data)
2426

2527
project_description = """

examples/team_recommender/tests/example_3_loop/test_allocations_loop.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,17 @@ def test_allocations():
1313
skills_data = load_json_fixture("skills.json")
1414
example_output = load_json_fixture("example_output.json")
1515
system_prompt = f"""
16-
You will get a description of a project, and your task is to tell me the best developers from the given list for the project
17-
based on their skills.
16+
You will get a description of a project, and your task is
17+
to tell me the best developers from the given list for the project based on their skills.
1818
Today's date is April 15th, 2025.
19-
Pick only developers who are available after the project start date. Pick people with higher skill levels first.
20-
respond in json with this structure:
19+
Pick only developers who are available after the project start date.
20+
Pick people with higher skill levels first.
21+
Respond in json with this structure:
2122
{example_output}
2223
2324
Here is the skills data:
2425
"""
26+
2527
system_prompt = system_prompt + str(skills_data)
2628

2729
project_description = """

examples/team_recommender/tests/example_4_loop_no_hallucinating/test_allocations_hallucinating.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,20 @@ def get_all_developer_names(skills_data) -> set[str]:
1616
}
1717

1818

19-
def get_developer_names_from_response(response) -> set[str]:
19+
def get_developer_names_from_response(response: dict[str, dict[str, str]]) -> set[str]:
2020
return {developer["name"] for developer in response["developers"]}
2121

2222

2323
def test_allocations():
2424
skills_data = load_json_fixture("skills.json")
2525
example_output = load_json_fixture("example_output.json")
2626
system_prompt = f"""
27-
You will get a description of a project, and your task is to tell me the best developers from the given list for the project
28-
based on their skills.
27+
You will get a description of a project, and your task is
28+
to tell me the best developers from the given list for the project based on their skills.
2929
Today's date is April 15th, 2025.
30-
Pick only developers who are available after the project start date. Pick people with higher skill levels first.
31-
respond in json with this structure:
30+
Pick only developers who are available after the project start date.
31+
Pick people with higher skill levels first.
32+
Respond in json with this structure:
3233
{example_output}
3334
3435
Here is the skills data:
@@ -71,11 +72,11 @@ def run_allocation_test(reporter, skills_data) -> bool:
7172
response_format={"type": "json_object"},
7273
)
7374
response = completion.choices[0].message.content
74-
result = False
7575
json_load_success = False
7676
not_empty_response = True
7777
no_developer_name_is_hallucinated = True
7878
developer_is_appropriate = True
79+
json_object = {}
7980
try:
8081
json_object = json.loads(response)
8182
json_load_success = True

examples/team_recommender/tests/example_5_gate_on_success_threshold/test_allocations_threshold.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,17 @@ def test_allocations():
3636
skills_data = load_json_fixture("skills.json")
3737
example_output = load_json_fixture("example_output.json")
3838
system_prompt = f"""
39-
You will get a description of a project, and your task is to tell me the best developers from the given list for the project
40-
based on their skills.
39+
You will get a description of a project, and your task is
40+
to tell me the best developers from the given list for the project based on their skills.
4141
Today's date is April 15th, 2025.
42-
Pick only developers who are available after the project start date. Pick people with higher skill levels first.
43-
respond in json with this structure:
42+
Pick only developers who are available after the project start date.
43+
Pick people with higher skill levels first.
44+
Respond in json with this structure:
4445
{example_output}
4546
4647
Here is the skills data:
4748
"""
49+
4850
system_prompt = system_prompt + str(skills_data)
4951

5052
project_description = """

examples/team_recommender/tests/example_6_n_generations/test_faster_with_n_generations.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,17 @@ def test_fast_with_n_generations():
3636
skills_data = load_json_fixture("skills.json")
3737
example_output = load_json_fixture("example_output.json")
3838
system_prompt = f"""
39-
You will get a description of a project, and your task is to tell me the best developers from the given list for the project
40-
based on their skills.
39+
You will get a description of a project, and your task is
40+
to tell me the best developers from the given list for the project based on their skills.
4141
Today's date is April 15th, 2025.
42-
Pick only developers who are available after the project start date. Pick people with higher skill levels first.
43-
respond in json with this structure:
42+
Pick only developers who are available after the project start date.
43+
Pick people with higher skill levels first.
44+
Respond in json with this structure:
4445
{example_output}
4546
4647
Here is the skills data:
4748
"""
49+
4850
system_prompt = system_prompt + str(skills_data)
4951

5052
project_description = """
@@ -77,8 +79,8 @@ def test_fast_with_n_generations():
7779
output_dir=ROOT_DIR,
7880
)
7981
test_runner = Runner(
80-
lambda reporter: run_allocation_test(
81-
reporter, skills_data=skills_data, response=response
82+
lambda reporter, content=response: run_allocation_test(
83+
reporter, skills_data=skills_data, response=content
8284
),
8385
reporter=test_reporter,
8486
)

0 commit comments

Comments
 (0)