Skip to content

Commit 1203a01

Browse files
Enable Strict Mypy Type Checking (#67)
* Refactor libs/oci to meet mypy stardard Removed unnecessary type: ignore comments, improved type annotations, and updated function signatures for better type safety across chat models, embeddings, and tests. Also enhanced mypy configuration for stricter type checking and plugin support. * Refactor libs/oracledb to meet mypy standard * Fix more lint in libs/oci * Remove unnecessary type ignore * Add type: ignore[call-arg] in /Users/panxia/Documents/GitHub/langchain-oracle/libs/oci/tests/unit_tests/chat_models/test_oci_data_science.py * Pass response to HTTPError in mock raise_for_status * Remove test dependencies not used in _lint.yml Removes 'test' and 'test_integration' groups from the Poetry install step in the lint workflow, ensuring only linting and typing dependencies are installed during lint jobs. * Revert "Remove test dependencies not used in _lint.yml" This reverts commit 3170d1d. * Add disk space cleanup to CI workflows Introduced steps to free disk space in both lint and test GitHub Actions workflows by removing unused Android and CodeQL directories and pruning Docker images. This helps prevent CI failures due to insufficient disk space.
1 parent cc2668e commit 1203a01

File tree

17 files changed

+104
-87
lines changed

17 files changed

+104
-87
lines changed

.github/workflows/_lint.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@ jobs:
3434
steps:
3535
- uses: actions/checkout@v4
3636

37+
- name: Free Disk Space
38+
run: |
39+
sudo rm -rf /usr/local/lib/android
40+
sudo rm -rf /opt/hostedtoolcache/CodeQL
41+
sudo docker image prune --all --force
42+
3743
- name: Set up Python ${{ matrix.python-version }} + Poetry ${{ env.POETRY_VERSION }}
3844
uses: "./.github/actions/poetry_setup"
3945
with:

.github/workflows/_test.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ jobs:
2626
steps:
2727
- uses: actions/checkout@v4
2828

29+
- name: Free Disk Space
30+
run: |
31+
sudo rm -rf /usr/local/lib/android
32+
sudo rm -rf /opt/hostedtoolcache/CodeQL
33+
sudo docker image prune --all --force
34+
2935
- name: Set up Python ${{ matrix.python-version }} + Poetry ${{ env.POETRY_VERSION }}
3036
uses: "./.github/actions/poetry_setup"
3137
with:

libs/oci/langchain_oci/chat_models/oci_data_science.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -598,7 +598,7 @@ def with_structured_output(
598598
if method == "json_mode":
599599
llm = self.bind(response_format={"type": "json_object"})
600600
output_parser = (
601-
PydanticOutputParser(pydantic_object=schema) # type: ignore[type-var, arg-type]
601+
PydanticOutputParser(pydantic_object=schema)
602602
if is_pydantic_schema
603603
else JsonOutputParser()
604604
)

libs/oci/langchain_oci/chat_models/oci_generative_ai.py

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
AIMessage,
3232
AIMessageChunk,
3333
BaseMessage,
34-
ChatMessage,
3534
HumanMessage,
3635
SystemMessage,
3736
ToolCall,
@@ -350,7 +349,7 @@ def get_role(self, message: BaseMessage) -> str:
350349
raise ValueError(f"Unknown message type: {type(message)}")
351350

352351
def messages_to_oci_params(
353-
self, messages: Sequence[ChatMessage], **kwargs: Any
352+
self, messages: Sequence[BaseMessage], **kwargs: Any
354353
) -> Dict[str, Any]:
355354
"""
356355
Convert LangChain messages to OCI parameters for Cohere.
@@ -417,7 +416,7 @@ def messages_to_oci_params(
417416
current_turn = list(reversed(current_turn))
418417

419418
# Process tool results from the current turn
420-
oci_tool_results: List[Any] = []
419+
oci_tool_results: Optional[List[Any]] = []
421420
for message in current_turn:
422421
if isinstance(message, ToolMessage):
423422
tool_msg = message
@@ -434,7 +433,7 @@ def messages_to_oci_params(
434433
parameters=lc_tool_call["args"],
435434
)
436435
tool_result.outputs = [{"output": tool_msg.content}]
437-
oci_tool_results.append(tool_result)
436+
oci_tool_results.append(tool_result) # type: ignore[union-attr]
438437
if not oci_tool_results:
439438
oci_tool_results = None
440439

@@ -552,7 +551,7 @@ def process_stream_tool_calls(
552551
Returns:
553552
List of ToolCallChunk objects
554553
"""
555-
tool_call_chunks = []
554+
tool_call_chunks: List[ToolCallChunk] = []
556555
tool_call_response = self.chat_stream_tool_calls(event_data)
557556

558557
if not tool_call_response:
@@ -813,7 +812,7 @@ def _should_allow_more_tool_calls(
813812
return False
814813

815814
# Detect infinite loop: same tool called with same arguments in succession
816-
recent_calls = []
815+
recent_calls: list = []
817816
for msg in reversed(messages):
818817
if hasattr(msg, "tool_calls") and msg.tool_calls:
819818
for tc in msg.tool_calls:
@@ -895,7 +894,7 @@ def _process_message_content(
895894

896895
def convert_to_oci_tool(
897896
self,
898-
tool: Union[Type[BaseModel], Callable, BaseTool],
897+
tool: Union[Dict[str, Any], Type[BaseModel], Callable, BaseTool],
899898
) -> Dict[str, Any]:
900899
"""Convert a BaseTool instance, TypedDict or BaseModel type
901900
to a OCI tool in Meta's format.
@@ -925,8 +924,8 @@ def convert_to_oci_tool(
925924
"required": parameters.get("required", []),
926925
},
927926
)
928-
elif isinstance(tool, BaseTool):
929-
return self.oci_function_definition(
927+
elif isinstance(tool, BaseTool): # type: ignore[unreachable]
928+
return self.oci_function_definition( # type: ignore[unreachable]
930929
name=tool.name,
931930
description=OCIUtils.remove_signature_from_tool_description(
932931
tool.name, tool.description
@@ -1016,7 +1015,7 @@ def process_stream_tool_calls(
10161015
Returns:
10171016
List of ToolCallChunk objects
10181017
"""
1019-
tool_call_chunks = []
1018+
tool_call_chunks: List[ToolCallChunk] = []
10201019
tool_call_response = self.chat_stream_tool_calls(event_data)
10211020

10221021
if not tool_call_response:
@@ -1142,7 +1141,7 @@ def _prepare_request(
11421141
stop: Optional[List[str]],
11431142
stream: bool,
11441143
**kwargs: Any,
1145-
) -> Dict[str, Any]:
1144+
) -> Any:
11461145
"""
11471146
Prepare the OCI chat request from LangChain messages.
11481147
@@ -1299,8 +1298,8 @@ def with_structured_output(
12991298
tool_name = getattr(self._provider.convert_to_oci_tool(schema), "name")
13001299
if is_pydantic_schema:
13011300
output_parser: OutputParserLike = PydanticToolsParser(
1302-
tools=[schema], # type: ignore[list-item]
1303-
first_tool_only=True, # type: ignore[list-item]
1301+
tools=[schema],
1302+
first_tool_only=True,
13041303
)
13051304
else:
13061305
output_parser = JsonOutputKeyToolsParser(
@@ -1309,15 +1308,15 @@ def with_structured_output(
13091308
elif method == "json_mode":
13101309
llm = self.bind(response_format={"type": "JSON_OBJECT"})
13111310
output_parser = (
1312-
PydanticOutputParser(pydantic_object=schema) # type: ignore[type-var, arg-type]
1311+
PydanticOutputParser(pydantic_object=schema)
13131312
if is_pydantic_schema
13141313
else JsonOutputParser()
13151314
)
13161315
elif method == "json_schema":
1317-
json_schema_dict = (
1316+
json_schema_dict: Dict[str, Any] = (
13181317
schema.model_json_schema() # type: ignore[union-attr]
13191318
if is_pydantic_schema
1320-
else schema
1319+
else schema # type: ignore[assignment]
13211320
)
13221321

13231322
response_json_schema = self._provider.oci_response_json_schema(

libs/oci/langchain_oci/embeddings/oci_data_science_model_deployment_endpoint.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -104,12 +104,9 @@ def _completion_with_retry(**kwargs: Any) -> Any:
104104
response.raise_for_status()
105105
return response
106106
except requests.exceptions.HTTPError as http_err:
107-
if response.status_code == 401 and self._refresh_signer():
108-
raise TokenExpiredError() from http_err
109-
else:
110-
raise ValueError(
111-
f"Server error: {str(http_err)}. Message: {response.text}"
112-
) from http_err
107+
raise ValueError(
108+
f"Server error: {str(http_err)}. Message: {response.text}"
109+
) from http_err
113110
except Exception as e:
114111
raise ValueError(f"Error occurs by inference endpoint: {str(e)}") from e
115112

libs/oci/langchain_oci/embeddings/oci_generative_ai.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ def validate_environment(cls, values: Dict) -> Dict: # pylint: disable=no-self-
125125
client_kwargs.pop("signer", None)
126126
elif values["auth_type"] == OCIAuthType(2).name:
127127

128-
def make_security_token_signer(oci_config): # type: ignore[no-untyped-def]
128+
def make_security_token_signer(oci_config):
129129
pk = oci.signer.load_private_key_from_file(
130130
oci_config.get("key_file"), None
131131
)

libs/oci/langchain_oci/llms/oci_generative_ai.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ def validate_environment(cls, values: Dict) -> Dict:
151151
client_kwargs.pop("signer", None)
152152
elif values["auth_type"] == OCIAuthType(2).name:
153153

154-
def make_security_token_signer(oci_config): # type: ignore[no-untyped-def]
154+
def make_security_token_signer(oci_config):
155155
pk = oci.signer.load_private_key_from_file(
156156
oci_config.get("key_file"), None
157157
)

libs/oci/pyproject.toml

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -77,20 +77,26 @@ ignore = [
7777
]
7878

7979
[tool.mypy]
80-
ignore_missing_imports = "True"
81-
82-
# Disable specific error codes that are causing issues
83-
disallow_untyped_defs = "False"
84-
disable_error_code = ["attr-defined", "assignment", "var-annotated", "override", "union-attr", "arg-type"]
85-
86-
# TODO: LangChain Google settings
87-
# plugins = ["pydantic.mypy"]
88-
# strict = true
89-
# disallow_untyped_defs = true
90-
91-
# # TODO: activate for 'strict' checking
92-
# disallow_any_generics = false
93-
# warn_return_any = false
80+
plugins = ["pydantic.mypy"]
81+
check_untyped_defs = true
82+
error_summary = false
83+
pretty = true
84+
show_column_numbers = true
85+
show_error_codes = true
86+
show_error_context = true
87+
warn_redundant_casts = true
88+
warn_unreachable = true
89+
warn_unused_configs = true
90+
warn_unused_ignores = true
91+
92+
# Ignore missing imports only for specific untyped packages
93+
[[tool.mypy.overrides]]
94+
module = [
95+
"oci.*",
96+
"ads.*",
97+
"langchain_openai.*",
98+
]
99+
ignore_missing_imports = true
94100

95101
[tool.coverage.run]
96102
omit = ["tests/*"]

libs/oci/tests/unit_tests/chat_models/test_oci_data_science.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ def __init__(self, json_data: Dict, status_code: int = 200):
8080
def raise_for_status(self) -> None:
8181
"""Mocked raise for status."""
8282
if 400 <= self.status_code < 600:
83-
raise HTTPError() # type: ignore[call-arg]
83+
raise HTTPError(response=self) # type: ignore[arg-type]
8484

8585
def json(self) -> Dict:
8686
"""Returns mocked json data."""
@@ -155,7 +155,7 @@ def test_stream_vllm(*args: Any) -> None:
155155
if output is None:
156156
output = chunk
157157
else:
158-
output += chunk
158+
output += chunk # type: ignore[assignment]
159159
count += 1
160160
assert count == 5
161161
assert output is not None

0 commit comments

Comments
 (0)