Skip to content

Commit 5e97a85

Browse files
bhirszmikeleppane
andauthored
feat: Add complete typing annotations (#1657)
Co-authored-by: Mikko Leppänen <[email protected]>
1 parent eced886 commit 5e97a85

File tree

122 files changed

+3837
-2975
lines changed

Some content is hidden

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

122 files changed

+3837
-2975
lines changed

.github/workflows/release-please.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
name: Release Please
22

3-
#on: # temporarily disable before 8.0
4-
# push:
3+
on:
4+
# push: temporarily disable before 8.0
55
# branches:
66
# - main
7+
workflow_dispatch:
78

89
permissions:
910
contents: write

noxfile.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
@nox.session(python=PYTHON_VERSIONS) # , reuse_venv=False
2424
@nox.parametrize("robot_ver", ROBOT_VERSIONS)
25-
def tests(session, robot_ver):
25+
def tests(session: nox.Session, robot_ver: str) -> None:
2626
"""
2727
Run tests with a given Python version and dependency version.
2828
@@ -48,13 +48,13 @@ def tests(session, robot_ver):
4848
session.run("pytest", "-v")
4949

5050

51-
def install_doc_deps(session, robot_version):
51+
def install_doc_deps(session: nox.Session, robot_version: str) -> None:
5252
session.install(f"robotframework=={robot_version}")
5353
session.run(*["uv", "sync", "--frozen", "--group", "doc"])
5454

5555

5656
@nox.session()
57-
def docs(session):
57+
def docs(session: nox.Session) -> None:
5858
install_doc_deps(session, "7.2.2")
5959
# session.run("sphinx-build", "-a", "-E", "-b", "html", "docs", "docs/_build/")
6060
command = ["sphinx-build", "-a", "-E", "--verbose", "-b", "html", "docs/source", "docs/_build/"]

pyproject.toml

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ robocop-mcp = "robocop.mcp.server:main"
5050

5151
[project.optional-dependencies]
5252
mcp = [
53-
"fastmcp>=2.13.0; python_version >= '3.10'",
53+
"fastmcp>=2.13.0"
5454
]
5555

5656
[project.urls]
@@ -74,13 +74,18 @@ default-groups = ["dev", "doc"]
7474

7575
[dependency-groups]
7676
dev = [
77+
"robotframework-robocop[mcp]",
7778
"coverage>=7.6.4",
7879
"pytest>=8.3.3",
7980
"pytest-xdist>=3.6.1",
8081
"ruff==0.14.8",
8182
"pysonar",
8283
"nox>=2025.11.12",
8384
"packaging>=25.0",
85+
"mypy>=1.19.1",
86+
"types-jinja2",
87+
"types-pytz",
88+
"msgpack-types"
8489
]
8590
doc = [
8691
"mkdocs",
@@ -132,7 +137,7 @@ lint.ignore = [
132137
"T201", # print in code
133138
#### Fix or decrease
134139
"ERA001", # commented-out code
135-
"ANN204", # missing type annotation for __init__
140+
#"ANN204", # missing type annotation for __init__
136141
"FIX002", # code with to do - check all of them later
137142
"PERF203", # try except in for loop - check all of them for possible refactors
138143
"C901", # code too complex (duplicate with other rules)
@@ -141,16 +146,16 @@ lint.ignore = [
141146
"FIX001", # line with fixme
142147
"TD001", # invalid todo tag fixme
143148
"TD004", # missing colon in TODO
144-
"ANN001", # annotations in method
145-
"ANN002", # annotations in return type
146-
"ANN201", # annotations in return type
147-
"ANN205", # annotations in return type
149+
#"ANN001", # annotations in method
150+
#"ANN002", # annotations in return type
151+
#"ANN201", # annotations in return type
152+
#"ANN205", # annotations in return type
148153
"RUF012", # mutable class attributes should be annotated with `typing.ClassVar`
149154
"PLR0913", # too many arguments in function definition
150155
"PLW2901", # for loop variable overwritten
151156
"INP001", # part of namespace package
152157
"PLR0912", # too many branches TODO
153-
"ANN003", # missing type kwargs
158+
#"ANN003", # missing type kwargs
154159
"SIM105", # contexlib.supress
155160
"ANN401", # typing.Any
156161
"B028", # no implicit stacklevel
@@ -188,6 +193,9 @@ extend-exclude = [
188193
# bug in typer where | None can't be used
189194
"src/robocop/run.py" = ["RUF013"]
190195

196+
[tool.ty.src]
197+
include = ["src"]
198+
191199
[tool.coverage.run]
192200
omit = ["*tests*"]
193201
source = ["robocop"]
@@ -199,3 +207,41 @@ exclude_lines = [
199207
"raise NotImplementedError"
200208
]
201209
fail_under = 5
210+
211+
[tool.mypy]
212+
python_version = "3.10"
213+
214+
strict = true
215+
216+
warn_return_any = true
217+
warn_unused_configs = true
218+
warn_redundant_casts = true
219+
warn_unused_ignores = true
220+
warn_unreachable = true
221+
222+
# Error output formatting
223+
show_error_codes = true
224+
show_column_numbers = true
225+
pretty = true
226+
color_output = true
227+
228+
# Module discovery
229+
mypy_path = "src"
230+
packages = ["robocop"]
231+
exclude = ["tests/", "docs/"]
232+
233+
# Robot Framework - no type stubs available for all supported versions
234+
[[tool.mypy.overrides]]
235+
module = "robot.*"
236+
ignore_missing_imports = true
237+
238+
# External libraries that may have incomplete stubs or no stubs at all
239+
[[tool.mypy.overrides]]
240+
module = ["typer.*", "click.*", "rich.*", "rich_click.*", "platformdirs.*", "tomli.*", "tomli_w.*", "jinja2.*"]
241+
ignore_missing_imports = true
242+
243+
# CLI module - intentionally passes None values to dataclasses which are handled by overwrite()
244+
# Also uses untyped decorators from typer/click and subclasses from Any-typed base classes
245+
[[tool.mypy.overrides]]
246+
module = "robocop.run"
247+
disable_error_code = ["arg-type", "attr-defined", "unused-ignore", "misc"]

src/robocop/cache.py

Lines changed: 8 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -418,28 +418,6 @@ def _get_entry(
418418

419419
return entry
420420

421-
def _set_entry(
422-
self,
423-
cache_dict: dict[str, LinterCacheEntry] | dict[str, FormatterCacheEntry],
424-
path: Path,
425-
entry: LinterCacheEntry | FormatterCacheEntry,
426-
) -> None:
427-
"""
428-
Store a cache entry.
429-
430-
Args:
431-
cache_dict: Dictionary to store cache entries (linter or formatter).
432-
path: Absolute path to the file.
433-
entry: Cache entry to store.
434-
435-
"""
436-
if not self.enabled:
437-
return
438-
439-
str_path = self._normalize_path(path)
440-
cache_dict[str_path] = entry
441-
self._dirty = True
442-
443421
# Linter cache methods
444422

445423
def get_linter_entry(self, path: Path, config_hash: str) -> LinterCacheEntry | None:
@@ -483,8 +461,9 @@ def set_linter_entry(
483461
config_hash=config_hash,
484462
diagnostics=tuple(CachedDiagnostic.from_diagnostic(d) for d in diagnostics),
485463
)
486-
487-
self._set_entry(self.data.linter, path, entry)
464+
str_path = self._normalize_path(path)
465+
self.data.linter[str_path] = entry
466+
self._dirty = True
488467

489468
# Formatter cache methods
490469

@@ -517,6 +496,8 @@ def set_formatter_entry(
517496
needs_formatting: Whether the file needed formatting.
518497
519498
"""
499+
if not self.enabled:
500+
return
520501
try:
521502
metadata = FileMetadata.from_path(path)
522503
except OSError:
@@ -527,8 +508,9 @@ def set_formatter_entry(
527508
config_hash=config_hash,
528509
needs_formatting=needs_formatting,
529510
)
530-
531-
self._set_entry(self.data.formatter, path, entry)
511+
str_path = self._normalize_path(path)
512+
self.data.formatter[str_path] = entry
513+
self._dirty = True
532514

533515

534516
def restore_diagnostics(

0 commit comments

Comments
 (0)