mypy-pylint-fixed #21

Open
aditya wants to merge 33 commits from mypy-pylint-fixed into master
Member

fixed mypy --strict and pylint errors and warnings of feat/multi-agent , only merge after merging pr #5

fixed mypy --strict and pylint errors and warnings of feat/multi-agent , only merge after merging pr #5
ISSUES FIXED: #4
requested review from brent.edwards 2025-10-27 09:57:16 +00:00
brent.edwards left a comment
Member

Five left for mypy --strict and pylint.

You can do it!

Five left for `mypy --strict` and `pylint`. You can do it!
@ -286,3 +283,3 @@
# Extract result
if hasattr(result, "messages") and result.messages:
return result.messages[-1].get("content", "")
content = result.messages[-1].get("content", "")
Member

In line 279 (I cannot leave a comment on code you didn't write) is

      result = await graph.execute(
         {"messages": [{"role": "user", "content": message}], "metadata": context}
     )

mypy --strict src reports:

src/cleveragents/agents/composite.py:279: error: Item "None" of "LangGraph | None" has no attribute "execute"  [union-attr]
In line 279 (I cannot leave a comment on code you didn't write) is > result = await graph.execute( > {"messages": [{"role": "user", "content": message}], "metadata": context} > ) `mypy --strict src` reports: ``` src/cleveragents/agents/composite.py:279: error: Item "None" of "LangGraph | None" has no attribute "execute" [union-attr] ```
@ -450,3 +482,1 @@
f"Registered {len(templates.get('agents', {}))} agent templates, "
f"{len(templates.get('graphs', {}))} graph templates, "
f"{len(templates.get('streams', {}))} stream templates"
"Registered %d agent templates, %d graph templates, %d stream templates",
Member

On line 478 (I cannot leave comments on lines you did not change) is the line

              self.template_registry.register_all_templates(self.config.templates)

mypy --strict src reports:

src/cleveragents/core/application.py:478: error: "object" has no attribute "register_all_templates"  [attr-defined]
On line 478 (I cannot leave comments on lines you did not change) is the line > self.template_registry.register_all_templates(self.config.templates) `mypy --strict src` reports: ``` src/cleveragents/core/application.py:478: error: "object" has no attribute "register_all_templates" [attr-defined] ```
@ -56,3 +57,3 @@
graph_def["name"] = self.name
return graph_def
return cast(Dict[str, Any], graph_def)
Member
    return cast(Dict[str, Any], graph_def)

According to mypy --strict src:

src/cleveragents/templates/graph_templates.py:59: error: Redundant cast to "dict[str, Any]"  [redundant-cast]
> return cast(Dict[str, Any], graph_def) According to `mypy --strict src`: ``` src/cleveragents/templates/graph_templates.py:59: error: Redundant cast to "dict[str, Any]" [redundant-cast] ```
@ -283,3 +280,3 @@
result = self._apply_templates_recursive(result, templates, context)
return result
return cast(Dict[str, Any], result)
Member
      return cast(Dict[str, Any], result)

According to mypy --strict src:

src/cleveragents/templates/inline_jinja_handler.py:282: error: Redundant cast to "dict[str, Any]"  [redundant-cast]
> return cast(Dict[str, Any], result) According to `mypy --strict src`: ``` src/cleveragents/templates/inline_jinja_handler.py:282: error: Redundant cast to "dict[str, Any]" [redundant-cast] ```
@ -52,3 +53,3 @@
stream_def["name"] = self.name
return stream_def
return cast(Dict[str, Any], stream_def)
Member
    return cast(Dict[str, Any], stream_def)

According to mypy --strict src:

src/cleveragents/templates/stream_templates.py:55: error: Redundant cast to "dict[str, Any]"  [redundant-cast]
> return cast(Dict[str, Any], stream_def) According to `mypy --strict src`: ``` src/cleveragents/templates/stream_templates.py:55: error: Redundant cast to "dict[str, Any]" [redundant-cast] ```
khird left a comment
Member

To achieve meaningful mypy compliance, the use of cast to subvert its warnings should be reduced, or at least there should be comments justifying why each usage is safe despite mypy's warning. The other issues are optional and won't block my approval of this MR.

To achieve meaningful mypy compliance, the use of cast to subvert its warnings should be reduced, or at least there should be comments justifying why each usage is safe despite mypy's warning. The other issues are optional and won't block my approval of this MR.
@ -100,3 +99,3 @@
kwargs["api_key"] = api_key
return ChatAnthropic(**kwargs)
elif self.provider.lower() == "google":
if self.provider.lower() == "google":
Member

These if/elif blocks would probably be more clearly expressed as one block of code that operates on a data structure like

{   "openai": {
        "renames": {},
        "class": ChatOpenAI},
    "anthropic": {
        "renames": {},
        "class": ChatAnthropic},
    "google": {
        "renames": {
            "max_tokens": "max_output_tokens",
            "api_key": "google_api_key"},
        "class": ChatGoogleGenerativeAPI}}

and decides what members of common_kwargs (if any) to mangle based on the renames field.

These if/elif blocks would probably be more clearly expressed as one block of code that operates on a data structure like ``` { "openai": { "renames": {}, "class": ChatOpenAI}, "anthropic": { "renames": {}, "class": ChatAnthropic}, "google": { "renames": { "max_tokens": "max_output_tokens", "api_key": "google_api_key"}, "class": ChatGoogleGenerativeAPI}} ``` and decides what members of `common_kwargs` (if any) to mangle based on the `renames` field.
@ -205,2 +228,3 @@
return {}
async def _execute_tool(self, state: GraphState) -> Dict[str, Any]:
async def _execute_tool(self, _state: GraphState) -> Dict[str, Any]:
Member

I assume this makes some automated tool shut up about you not using the argument state anywhere in the function body. Is there any reason not to simply remove it from the function definition? If there are places that rely on being able to call a function that might be self._execute_tool() or might be self._execute_conditional() and construct their argument list to include a GraphState, this change would cause it to break if they set it by keyword. If you absolutely can't remove it, using *args and **kwargs might be more forgiving.

I assume this makes some automated tool shut up about you not using the argument `state` anywhere in the function body. Is there any reason not to simply remove it from the function definition? If there are places that rely on being able to call a function that might be `self._execute_tool()` or might be `self._execute_conditional()` and construct their argument list to include a GraphState, this change would cause it to break if they set it by keyword. If you absolutely can't remove it, using `*args` and `**kwargs` might be more forgiving.
@ -156,2 +156,3 @@
if default_value.isdigit():
return default_value
elif default_value.replace(".", "").isdigit():
if default_value.replace(".", "").isdigit():
Member

What is the point of this test? If to match decimal numbers, should probably be replace(x, y, 1). If to match IP addresses, this doesn't work on IPv6. And in any case, if the condition isn't satisfied, we do the same thing (i.e. returning the default value) anyway when we fall through.

What is the point of this test? If to match decimal numbers, should probably be replace(x, y, 1). If to match IP addresses, this doesn't work on IPv6. And in any case, if the condition isn't satisfied, we do the same thing (i.e. returning the default value) anyway when we fall through.
@ -173,2 +171,3 @@
if config.isdigit():
return int(config)
elif config.replace(".", "").isdigit() and config.count(".") == 1:
if config.replace(".", "").isdigit() and config.count(".") == 1:
Member

So I guess the answer here is that it's a decimal number. I note that negatives aren't handled; may or may not be an issue.

So I guess the answer [here](https://git.cleverthis.com/cleveragents/cleveragents-core/pulls/21/files#issuecomment-30424) is that it's a decimal number. I note that negatives aren't handled; may or may not be an issue.
@ -332,2 +336,2 @@
import threading
import asyncio as async_io # pylint: disable=reimported,import-outside-toplevel
import threading # pylint: disable=import-outside-toplevel
Member

It's not clear why reimporting modules is necessary, or why they wouldn't be at the top level. Maybe comment to justify why do it this way that requires circumventing pylint + mypy?

It's not clear why reimporting modules is necessary, or why they wouldn't be at the top level. Maybe comment to justify why do it this way that requires circumventing pylint + mypy?
@ -6,3 +6,4 @@
from pathlib import Path
from typing import TYPE_CHECKING
from typing import Any
from typing import Dict
Member

typing.Dict is deprecated in favour of dict in recent versions of python, including all the versions CleverAgents claims to support.

typing.Dict is deprecated in favour of dict in recent versions of python, including all the versions CleverAgents claims to support.
@ -174,1 +173,3 @@
return template.instantiate(params, self, context or InstantiationContext())
return cast(
Dict[str, Any],
template.instantiate(params, self, context or InstantiationContext()),
Member

Please add a comment here explaining why fooling mypy with a cast() is necessary - if you know that template.instantiate() is going to return a dict[str, Any] then why not just annotate it as such in the base submodule? And if not, please explain why it's safe to proceed as if this were true, despite mypy's warning.

Please add a comment here explaining why fooling mypy with a `cast()` is necessary - if you know that `template.instantiate()` is going to return a `dict[str, Any]` then why not just annotate it as such in the base submodule? And if not, please explain why it's safe to proceed as if this were true, despite mypy's warning.
@ -84,3 +83,3 @@
# If no templates, just parse
if "{%" not in yaml_content and "{{" not in yaml_content:
return yaml.safe_load(yaml_content)
return cast(Dict[str, Any], yaml.safe_load(yaml_content))
Member

It's possible for yaml to represent a list rather than a dict. If there's a reason we know that can't be the case for the particular specimen in yaml_content, it would be good to document that reason. If there isn't such a reason, then mypy's correct here and you ought to handle or check that case. I'm not going to spam a bunch of identical comments about cast everywhere, but please give it a general look.

It's possible for yaml to represent a list rather than a dict. If there's a reason we know that can't be the case for the particular specimen in `yaml_content`, it would be good to document that reason. If there isn't such a reason, then mypy's correct here and you ought to handle or check that case. I'm not going to spam a bunch of identical comments about `cast` everywhere, but please give it a general look.
@ -53,2 +53,3 @@
if template_type == TemplateType.STREAM:
template = StreamTemplate(name, template_type, definition)
else:
if template_type not in [TemplateType.AGENT, TemplateType.GRAPH, TemplateType.STREAM]:
Member

I think the elif/else construction worked better here, because now anyone adding a new template type has to add an if block and an element to this list. If you'd just left it as elif blocks, there wouldn't be the possibility to forget the second part.

I think the elif/else construction worked better here, because now anyone adding a new template type has to add an if block *and* an element to this list. If you'd just left it as elif blocks, there wouldn't be the possibility to forget the second part.
This pull request can be merged automatically.
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin mypy-pylint-fixed:mypy-pylint-fixed
git switch mypy-pylint-fixed

Merge

Merge the changes and update on Forgejo.

Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.

git switch master
git merge --no-ff mypy-pylint-fixed
git switch mypy-pylint-fixed
git rebase master
git switch master
git merge --ff-only mypy-pylint-fixed
git switch mypy-pylint-fixed
git rebase master
git switch master
git merge --no-ff mypy-pylint-fixed
git switch master
git merge --squash mypy-pylint-fixed
git switch master
git merge --ff-only mypy-pylint-fixed
git switch master
git merge mypy-pylint-fixed
git push origin master
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
3 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: cleveragents/cleveragents-core#21
No description provided.