Skip to content

Commit f9a586a

Browse files
authored
fix(traceloop-sdk): add type-checking support with mypy (#3463)
1 parent 88f61bc commit f9a586a

File tree

20 files changed

+366
-134
lines changed

20 files changed

+366
-134
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ jobs:
7474
run: npm cache clean --force || true
7575
- run: npx nx affected -t install --with dev
7676
- run: npx nx affected -t lint --parallel=3
77+
- run: npx nx affected -t type-check --parallel=3
7778

7879
build-packages:
7980
name: Build Packages

packages/traceloop-sdk/poetry.lock

Lines changed: 210 additions & 34 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/traceloop-sdk/project.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,14 @@
5050
"outputFile": "reports/packages/traceloop-sdk/pylint.txt"
5151
}
5252
},
53+
"type-check": {
54+
"executor": "@nxlv/python:run-commands",
55+
"outputs": [],
56+
"options": {
57+
"command": "poetry run mypy traceloop/sdk",
58+
"cwd": "packages/traceloop-sdk"
59+
}
60+
},
5361
"test": {
5462
"executor": "@nxlv/python:run-commands",
5563
"outputs": [

packages/traceloop-sdk/pyproject.toml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ autopep8 = "^2.2.0"
7979
flake8 = "7.0.0"
8080
pytest = "^8.2.2"
8181
pytest-sugar = "1.0.0"
82+
mypy = "^1.18.2"
83+
types-requests = "^2.31.0"
84+
types-colorama = "^0.4.15"
85+
pandas-stubs = "*"
8286

8387
[tool.poetry.group.test.dependencies]
8488
openai = "^1.31.1"
@@ -94,6 +98,44 @@ pandas = ">=1.0.0"
9498
[tool.poetry.extras]
9599
datasets = ["pandas"]
96100

101+
[tool.mypy]
102+
python_version = "3.10"
103+
warn_return_any = true
104+
warn_unused_configs = true
105+
disallow_untyped_defs = true
106+
disallow_any_unimported = false
107+
no_implicit_optional = true
108+
warn_redundant_casts = true
109+
warn_unused_ignores = true
110+
warn_no_return = true
111+
check_untyped_defs = true
112+
strict_equality = true
113+
namespace_packages = true
114+
explicit_package_bases = true
115+
plugins = ["pydantic.mypy"]
116+
117+
# Blacklist approach - all folders checked except those excluded below
118+
exclude = [
119+
"traceloop/sdk/decorators",
120+
"traceloop/sdk/prompts",
121+
"traceloop/sdk/tracing",
122+
"traceloop/sdk/utils",
123+
"traceloop/sdk/__init__.py",
124+
"tests/",
125+
]
126+
127+
[[tool.mypy.overrides]]
128+
module = [
129+
"cuid.*",
130+
"posthog.*",
131+
]
132+
ignore_missing_imports = true
133+
134+
[pydantic-mypy]
135+
init_forbid_extra = true
136+
init_typed = true
137+
warn_required_dynamic_aliases = true
138+
97139
[build-system]
98140
requires = ["poetry-core"]
99141
build-backend = "poetry.core.masonry.api"

packages/traceloop-sdk/tests/test_user_feedback.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def test_user_feedback_initialization(mock_http):
3535
assert feedback._app_name == "test-app"
3636

3737

38-
def test_create_basic_feedback(user_feedback, mock_http):
38+
def test_create_basic_feedback(user_feedback: UserFeedback, mock_http: Mock):
3939
"""Test creating basic user feedback"""
4040
user_feedback.create(
4141
annotation_task="task_123", entity_id="instance_456", tags={"sentiment": "positive"}
@@ -56,7 +56,7 @@ def test_create_basic_feedback(user_feedback, mock_http):
5656
)
5757

5858

59-
def test_create_feedback_complex_tags(user_feedback, mock_http):
59+
def test_create_feedback_complex_tags(user_feedback: UserFeedback, mock_http: Mock):
6060
"""Test creating user feedback with complex tags"""
6161
tags = {"sentiment": "positive", "relevance": 0.95, "tones": ["happy", "nice"]}
6262

@@ -77,7 +77,7 @@ def test_create_feedback_complex_tags(user_feedback, mock_http):
7777
)
7878

7979

80-
def test_create_feedback_parameter_validation(user_feedback):
80+
def test_create_feedback_parameter_validation(user_feedback: UserFeedback):
8181
"""Test parameter validation for feedback creation"""
8282
with pytest.raises(ValueError, match="annotation_task is required"):
8383
user_feedback.create(annotation_task="", entity_id="instance_456", tags={"sentiment": "positive"})

packages/traceloop-sdk/traceloop/sdk/annotation/base_annotation.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def create(
2929
Args:
3030
annotation_task (str): The ID/slug of the annotation task to report to.
3131
Can be found at app.traceloop.com/annotation_tasks/:annotation_task_id
32-
entity_id (str): The ID of the specific entity instance being annotated, should be reported
32+
entity_id (str): The ID of the specific entity being annotated, should be reported
3333
in the association properties
3434
tags (Dict[str, Any]): Dictionary containing the tags to be reported.
3535
Should match the tags defined in the annotation task
@@ -39,7 +39,7 @@ def create(
3939
client = Client(api_key="your-key")
4040
client.annotation.create(
4141
annotation_task="task_123",
42-
entity_id="instance_456",
42+
entity_id="456",
4343
tags={
4444
"sentiment": "positive",
4545
"relevance": 0.95,

packages/traceloop-sdk/traceloop/sdk/annotation/user_feedback.py

Lines changed: 32 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -8,36 +8,35 @@ class UserFeedback(BaseAnnotation):
88
def __init__(self, http: HTTPClient, app_name: str):
99
super().__init__(http, app_name, "user_feedback")
1010

11-
12-
def create(
13-
self,
14-
annotation_task: str,
15-
entity_instance_id: str,
16-
tags: Dict[str, Any],
17-
) -> None:
18-
"""Create an annotation for a specific task.
19-
20-
Args:
21-
annotation_task (str): The ID/slug of the annotation task to report to.
22-
Can be found at app.traceloop.com/annotation_tasks/:annotation_task_id
23-
entity_instance_id (str): The ID of the specific entity instance being annotated, should be reported
24-
in the association properties
25-
tags (Dict[str, Any]): Dictionary containing the tags to be reported.
26-
Should match the tags defined in the annotation task
27-
28-
Example:
29-
```python
30-
client = Client(api_key="your-key")
31-
client.annotation.create(
32-
annotation_task="task_123",
33-
entity_instance_id="instance_456",
34-
tags={
35-
"sentiment": "positive",
36-
"relevance": 0.95,
37-
"tones": ["happy", "nice"]
38-
},
39-
)
40-
```
41-
"""
42-
43-
return BaseAnnotation.create(self, annotation_task, entity_instance_id, tags)
11+
def create(
12+
self,
13+
annotation_task: str,
14+
entity_id: str,
15+
tags: Dict[str, Any],
16+
) -> None:
17+
"""Create an annotation for a specific task.
18+
19+
Args:
20+
annotation_task (str): The ID/slug of the annotation task to report to.
21+
Can be found at app.traceloop.com/annotation_tasks/:annotation_task_id
22+
entity_id (str): The ID of the specific entity being annotated, should be reported
23+
in the association properties
24+
tags (Dict[str, Any]): Dictionary containing the tags to be reported.
25+
Should match the tags defined in the annotation task
26+
27+
Example:
28+
```python
29+
client = Client(api_key="your-key")
30+
client.annotation.create(
31+
annotation_task="task_123",
32+
entity_id="instance_456",
33+
tags={
34+
"sentiment": "positive",
35+
"relevance": 0.95,
36+
"tones": ["happy", "nice"]
37+
},
38+
)
39+
```
40+
"""
41+
42+
return BaseAnnotation.create(self, annotation_task, entity_id, tags)

packages/traceloop-sdk/traceloop/sdk/client/client.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,5 @@ def __init__(
6363
self.user_feedback = UserFeedback(self._http, self.app_name)
6464
self.datasets = Datasets(self._http)
6565
experiment_slug = os.getenv("TRACELOOP_EXP_SLUG")
66-
self.experiment = Experiment(self._http, self._async_http, experiment_slug)
66+
# TODO: Fix type - Experiment constructor should accept Optional[str]
67+
self.experiment = Experiment(self._http, self._async_http, experiment_slug) # type: ignore[arg-type]

packages/traceloop-sdk/traceloop/sdk/client/http.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ def __init__(self, base_url: str, api_key: str, version: str):
1414
self.api_key = api_key
1515
self.version = version
1616

17-
def _headers(self):
17+
def _headers(self) -> Dict[str, str]:
1818
return {
1919
"Authorization": f"Bearer {self.api_key}",
2020
"X-Traceloop-SDK-Version": self.version,

packages/traceloop-sdk/traceloop/sdk/dataset/dataset.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ def add_column(self, slug: str, name: str, col_type: ColumnType) -> Column:
8686
self.columns.append(column)
8787
return column
8888

89-
def _create_columns(self, raw_columns: Dict[str, ColumnDefinition]):
89+
def _create_columns(self, raw_columns: Dict[str, ColumnDefinition]) -> None:
9090
"""Create Column objects from API response which includes column IDs"""
9191
for column_slug, column_def in raw_columns.items():
9292
column = Column(
@@ -98,7 +98,7 @@ def _create_columns(self, raw_columns: Dict[str, ColumnDefinition]):
9898
)
9999
self.columns.append(column)
100100

101-
def _create_rows(self, raw_rows: List[RowObject]):
101+
def _create_rows(self, raw_rows: List[RowObject]) -> None:
102102
for _, row_obj in enumerate(raw_rows):
103103
row = Row(
104104
http=self._http,

0 commit comments

Comments
 (0)