mirror of
https://github.com/tiennm99/serena.git
synced 2026-10-17 00:14:56 +00:00
Replace mypy by ty (#1619)
This commit is contained in:
1 parent
0d8d5add9d
commit
7333a0c868
53 files changed
+221
-210
No files matched your search
@@ -13,11 +13,9 @@
|
||||
- `ruff format` runs on `src scripts test`; same set for `ruff check`.
|
||||
- mccabe complexity cap: 20.
|
||||
|
||||
## Typing (mypy strict)
|
||||
- `disallow_untyped_defs = true`, `disallow_incomplete_defs = true`, `strict_equality`, `strict_optional`, `warn_unreachable`, `no_implicit_optional`.
|
||||
- Excluded paths: `^build/`, `^docs/`, `^test/resources/`.
|
||||
- Test files relax `disallow_untyped_defs` (still type-checked otherwise).
|
||||
|
||||
## Typing (ty)
|
||||
- Type checker is **ty** (Astral), configured under `[tool.ty]` in `pyproject.toml`.
|
||||
|
||||
## Tests
|
||||
- Language-server tests are pytest-marker-gated (one marker per language; see `pyproject.toml` `[tool.pytest.ini_options].markers`). Default `poe test` runs unmarked tests + whatever `PYTEST_MARKERS` selects.
|
||||
- Snapshot tests use **syrupy** with custom `--snapshot-patch-pycharm-diff` plugin (auto-added via `addopts`).
|
||||
|
||||
@@ -104,7 +104,7 @@ The project uses modern Python tooling:
|
||||
- **uv** for fast dependency resolution and virtual environments
|
||||
- **pytest** for testing with language-specific markers (`@pytest.mark.csharp`)
|
||||
- **ruff** for linting and formatting
|
||||
- **mypy** for type checking
|
||||
- **ty** (Astral) for type checking
|
||||
|
||||
## Build and Development
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ Run via `uv run poe <task>` (or `poe <task>` inside the activated venv). Poe exe
|
||||
- `poe test` — pytest on `test/` (per-language tests are marker-gated; pass `-m <marker>` to enable).
|
||||
- `poe lint` — ruff format-check + ruff check (no fixes).
|
||||
- `poe format` — ruff `--fix` then `ruff format` (mutates files).
|
||||
- `poe type-check` — mypy on `src/serena`, `src/solidlsp`, and `test/` (test pass disables `no-untyped-def`).
|
||||
- `poe type-check` — ty on `src/serena`, `src/solidlsp`, and `test/` (test pass relaxes pytest/mock-noisy rules via `[[tool.ty.overrides]]`).
|
||||
- Single test file: `uv run pytest test/path/to/test_x.py -vv`. Language-gated: add `-m python` etc.
|
||||
|
||||
## Docs
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
After any code change in `src/` or `test/`, run:
|
||||
|
||||
1. `uv run poe format` — applies ruff fixes + formatting (mutates files).
|
||||
2. `uv run poe type-check` — mypy strict on `src/serena`, `src/solidlsp`, `test/`.
|
||||
2. `uv run poe type-check` — ty on `src/serena`, `src/solidlsp`, `test/`.
|
||||
3. `uv run poe test` — pytest on affected files or affected languages, using `-m` markers.
|
||||
|
||||
If prompt templates changed: `uv run python scripts/gen_prompt_factory.py` (regenerates `src/serena/generated/generated_prompt_factory.py`; use `uv run poe format` and commit the result).
|
||||
|
||||
@@ -5,6 +5,6 @@
|
||||
- Build backend: `hatchling`. Packages: `src/serena`, `src/interprompt`, `src/solidlsp`.
|
||||
- Task runner: **poethepoet** (`poe <task>`). Poe executor is `simple` (does NOT shell out via uv) — avoids env recreation while MCP server is running.
|
||||
- Key runtime deps: `mcp`, `flask` (dashboard), `pydantic`, `pygls` + `lsprotocol` (LSP), `anthropic`, `jinja2`, `ruamel.yaml`, `pywebview`/`pystray` (GUI), `pythonnet` (Windows only).
|
||||
- Dev deps: `ruff` (lint+format), `mypy` (strict), `pytest` (+ `pytest-xdist`, `pytest-timeout`, `syrupy` snapshots), `sphinx`/`jupyter-book` for docs.
|
||||
- Dev deps: `ruff` (lint+format), `ty` (Astral type checker; replaced mypy), `pytest` (+ `pytest-xdist`, `pytest-timeout`, `syrupy` snapshots), `sphinx`/`jupyter-book` for docs.
|
||||
- Optional extras: `agno` (Agno agent integration), `google` (gemini).
|
||||
- LSP client core lives under `src/solidlsp/`; one subdir per supported language server under `language_servers/`.
|
||||
+44
-26
@@ -73,7 +73,7 @@ text = "MIT"
|
||||
dev = [
|
||||
"jinja2==3.1.6",
|
||||
# In version 1.0.4 we get a NoneType error related to some config conversion (yml_analytics is None and should be a list)
|
||||
"mypy==1.17.0",
|
||||
"ty==0.0.24",
|
||||
"poethepoet==0.36.0",
|
||||
"pytest==8.4.1",
|
||||
"pytest-xdist==3.8.0",
|
||||
@@ -109,29 +109,47 @@ packages = ["src/serena", "src/interprompt", "src/solidlsp"]
|
||||
[tool.doc8]
|
||||
max-line-length = 1000
|
||||
|
||||
[tool.mypy]
|
||||
allow_redefinition = true
|
||||
check_untyped_defs = true
|
||||
disallow_incomplete_defs = true
|
||||
disallow_untyped_defs = true
|
||||
ignore_missing_imports = true
|
||||
no_implicit_optional = true
|
||||
pretty = true
|
||||
show_error_codes = true
|
||||
show_error_context = true
|
||||
show_traceback = true
|
||||
strict_equality = true
|
||||
strict_optional = true
|
||||
warn_no_return = true
|
||||
warn_redundant_casts = true
|
||||
warn_unreachable = true
|
||||
warn_unused_configs = true
|
||||
warn_unused_ignores = false
|
||||
exclude = "^build/|^docs/|^test/resources/"
|
||||
[tool.ty.environment]
|
||||
python-version = "3.11"
|
||||
# Analyze for all platforms rather than defaulting to the OS ty happens to run on. This keeps the
|
||||
# check deterministic across the CI matrix (Linux/Windows/macOS) and lets platform-conditional stdlib
|
||||
# members (e.g. subprocess.CREATE_NO_WINDOW, ctypes.windll, pwd) resolve without per-OS type-ignores.
|
||||
python-platform = "all"
|
||||
|
||||
[[tool.mypy.overrides]]
|
||||
module = "test.*"
|
||||
disallow_untyped_defs = false # untyped defs are OK in tests
|
||||
[tool.ty.rules]
|
||||
# Mirror mypy's ignore_missing_imports=true: optional extras (e.g. agno, google-genai) and
|
||||
# platform-specific modules (e.g. AppKit on macOS) are not installed in the default dev environment,
|
||||
# so we do not want unresolvable imports to fail the type check.
|
||||
unresolved-import = "ignore"
|
||||
possibly-missing-submodule = "ignore"
|
||||
|
||||
[tool.ty.src]
|
||||
# NOTE: test/resources is intentionally NOT excluded here. This config is also discovered by the ty
|
||||
# language server (used by the PYTHON_TY diagnostics provider) when it analyzes the sample fixture
|
||||
# repos under test/resources; excluding them here would suppress the diagnostics those tests rely on.
|
||||
# test/resources is instead excluded from the `ty check test` CLI task via its --exclude flag.
|
||||
exclude = ["build/", "docs/"]
|
||||
|
||||
[[tool.ty.overrides]]
|
||||
# Test code is heavily dynamic (pytest fixtures, MagicMock, intentionally loose Optionals). ty models
|
||||
# pytest's fail/skip helpers and MagicMock far more strictly than mypy did (mypy inferred `Any` for
|
||||
# these), which produces hundreds of diagnostics that are not real bugs. We therefore relax these
|
||||
# specific type rules for tests only, while still catching genuinely broken test code (undefined
|
||||
# names, syntax errors, unused type-ignore comments, etc.). The sample fixture repos under
|
||||
# test/resources are excluded so the ty language server still reports real diagnostics on them.
|
||||
include = ["test/**"]
|
||||
exclude = ["test/resources/"]
|
||||
|
||||
[tool.ty.overrides.rules]
|
||||
invalid-argument-type = "ignore"
|
||||
invalid-key = "ignore"
|
||||
invalid-return-type = "ignore"
|
||||
no-matching-overload = "ignore"
|
||||
not-subscriptable = "ignore"
|
||||
parameter-already-assigned = "ignore"
|
||||
too-many-positional-arguments = "ignore"
|
||||
unresolved-attribute = "ignore"
|
||||
unsupported-operator = "ignore"
|
||||
|
||||
[tool.poe.env]
|
||||
PYDEVD_DISABLE_FILE_VALIDATION = "1"
|
||||
@@ -152,9 +170,9 @@ _ruff_fix = "ruff check --fix src scripts test"
|
||||
_ruff_format = "ruff format src scripts test"
|
||||
lint = ["_ruff_format_check", "_ruff_check"]
|
||||
format = ["_ruff_fix", "_ruff_format"]
|
||||
_mypy_core = "mypy src/serena src/solidlsp"
|
||||
_mypy_test = "mypy --disable-error-code no-untyped-def test"
|
||||
type-check = ["_mypy_core", "_mypy_test"]
|
||||
_ty_core = "ty check src/serena src/solidlsp"
|
||||
_ty_test = "ty check test --exclude test/resources"
|
||||
type-check = ["_ty_core", "_ty_test"]
|
||||
# docs
|
||||
_autogen_docs = "python docs/autogen_docs.py"
|
||||
_sphinx_build = "sphinx-build -b html docs docs/_build -W --keep-going"
|
||||
|
||||
+1
-1
@@ -1363,7 +1363,7 @@ class SerenaAgent:
|
||||
self.issue_task(lambda: self.get_active_project_or_raise().remove_language(language), name=f"RemoveLanguage:{language.value}")
|
||||
|
||||
def get_tool(self, tool_class: type[TTool]) -> TTool:
|
||||
return self._all_tools[tool_class] # type: ignore
|
||||
return self._all_tools[tool_class]
|
||||
|
||||
def print_tool_overview(self) -> None:
|
||||
ToolRegistry().print_tool_overview(self._active_tools.tools)
|
||||
|
||||
@@ -789,7 +789,9 @@ class SerenaDashboardAPI:
|
||||
# patch flask.cli.show_server to avoid printing the server info
|
||||
from flask import cli
|
||||
|
||||
cli.show_server_banner = lambda *args, **kwargs: None
|
||||
# ty cannot model reassigning a third-party module's function attribute (it rejects any
|
||||
# replacement, even one with an identical signature), so the monkeypatch is suppressed here
|
||||
cli.show_server_banner = lambda *args, **kwargs: None # ty: ignore[invalid-assignment]
|
||||
self._app.run(host=self._host, port=port, debug=False, use_reloader=False, threaded=True)
|
||||
return port
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# mypy: ignore-errors
|
||||
import logging
|
||||
import queue
|
||||
import sys
|
||||
@@ -109,7 +108,7 @@ class GuiLogViewer:
|
||||
|
||||
if self.menubar is not None:
|
||||
dashboard_menu = tk.Menu(self.menubar, tearoff=0)
|
||||
dashboard_menu.add_command(label="Copy URL", command=copy_url) # type: ignore
|
||||
dashboard_menu.add_command(label="Copy URL", command=copy_url)
|
||||
self.menubar.add_cascade(label="Dashboard", menu=dashboard_menu)
|
||||
|
||||
def add_log(self, message):
|
||||
@@ -303,7 +302,7 @@ class GuiLogViewer:
|
||||
if self.mode == "dashboard":
|
||||
self.menubar = tk.Menu(self.root)
|
||||
server_menu = tk.Menu(self.menubar, tearoff=0)
|
||||
server_menu.add_command(label="Shutdown", command=self._shutdown_server) # type: ignore
|
||||
server_menu.add_command(label="Shutdown", command=self._shutdown_server)
|
||||
self.menubar.add_cascade(label="Server", menu=server_menu)
|
||||
self.root.config(menu=self.menubar)
|
||||
|
||||
|
||||
@@ -225,7 +225,7 @@ class JetBrainsPluginClient(ToStringMixin):
|
||||
return ["_port", "project_root", "_plugin_version"]
|
||||
|
||||
@classmethod
|
||||
def from_project(cls, project: Project, log_warning: bool = True) -> Self:
|
||||
def from_project(cls, project: Project, log_warning: bool = True) -> "JetBrainsPluginClient":
|
||||
resolved_path = Path(project.project_root).resolve()
|
||||
|
||||
if cls._last_port is not None:
|
||||
@@ -355,7 +355,7 @@ class JetBrainsPluginClient(ToStringMixin):
|
||||
"""
|
||||
to_snake_case = lambda s: "".join(["_" + c.lower() if c.isupper() else c for c in s])
|
||||
|
||||
def convert(x): # type: ignore
|
||||
def convert(x):
|
||||
if isinstance(x, dict):
|
||||
return {to_snake_case(k): convert(v) for k, v in x.items()}
|
||||
elif isinstance(x, list):
|
||||
@@ -721,5 +721,5 @@ class JetBrainsPluginClient(ToStringMixin):
|
||||
def __enter__(self) -> Self:
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb): # type: ignore
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
self.close()
|
||||
+3
-3
@@ -34,7 +34,7 @@ from serena.util.logging import MemoryLogHandler
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def configure_logging(*args, **kwargs) -> None: # type: ignore
|
||||
def configure_logging(*args, **kwargs) -> None:
|
||||
# We only do something here if logging has not yet been configured.
|
||||
# Normally, logging is configured in the MCP server startup script.
|
||||
if not logging.is_enabled():
|
||||
@@ -95,7 +95,7 @@ class SerenaFastMCPTool(FastMCPTool):
|
||||
param_desc = f"{param_doc.description.strip().strip('.') + '.'}"
|
||||
properties["description"] = param_desc[0].upper() + param_desc[1:]
|
||||
|
||||
def execute_fn(**kwargs) -> str: # type: ignore
|
||||
def execute_fn(**kwargs) -> str:
|
||||
try:
|
||||
return tool.apply_ex(log_call=True, catch_exceptions=False, **kwargs)
|
||||
except ToolCallError as e:
|
||||
@@ -182,7 +182,7 @@ class SerenaMCPFactory:
|
||||
"""
|
||||
s = deepcopy(schema)
|
||||
|
||||
def walk(node): # type: ignore
|
||||
def walk(node):
|
||||
if not isinstance(node, dict):
|
||||
# lists get handled by parent calls
|
||||
return node
|
||||
|
||||
@@ -107,7 +107,9 @@ class ProjectServer:
|
||||
from flask import cli
|
||||
|
||||
# suppress the default Flask startup banner
|
||||
cli.show_server_banner = lambda *args, **kwargs: None
|
||||
# ty cannot model reassigning a third-party module's function attribute (it rejects any
|
||||
# replacement, even one with an identical signature), so the monkeypatch is suppressed here
|
||||
cli.show_server_banner = lambda *args, **kwargs: None # ty: ignore[invalid-assignment]
|
||||
|
||||
self._app.run(host=host, port=port, debug=False, use_reloader=False, threaded=True)
|
||||
return port
|
||||
|
||||
@@ -1321,7 +1321,7 @@ class SymbolDictGrouper(Generic[TSymbolDict], ABC):
|
||||
"""
|
||||
# avoid side effects by working on a deep-copy
|
||||
symbols_copy = copy.deepcopy(symbols)
|
||||
return self._group_by(symbols_copy, self._group_keys, self._group_children_keys, is_children=False) # type: ignore
|
||||
return self._group_by(symbols_copy, self._group_keys, self._group_children_keys, is_children=False)
|
||||
|
||||
|
||||
class LanguageServerSymbolDictGrouper(SymbolDictGrouper[LanguageServerSymbol.OutputDict]):
|
||||
|
||||
@@ -200,7 +200,7 @@ class TaskExecutor:
|
||||
self._task_executor_task_index += 1
|
||||
else:
|
||||
task_prefix_name = "BackgroundTask"
|
||||
task_name = f"{task_prefix_name}:{name or task.__name__}"
|
||||
task_name = f"{task_prefix_name}:{name or getattr(task, '__name__', 'task')}"
|
||||
if logged:
|
||||
log.info(f"Scheduling {task_name}")
|
||||
task_obj = self.Task(function=task, name=task_name, logged=logged, timeout=timeout)
|
||||
|
||||
@@ -48,5 +48,5 @@ class ExecuteShellCommandTool(Tool, ToolMarkerCanEdit):
|
||||
)
|
||||
|
||||
result = execute_shell_command(command, cwd=_cwd, capture_stderr=capture_stderr)
|
||||
result = result.json()
|
||||
result = result.model_dump_json()
|
||||
return self._limit_length(result, max_answer_chars)
|
||||
@@ -62,7 +62,7 @@ class QueryProjectTool(Tool, ToolMarkerOptional, ToolMarkerDoesNotRequireActiveP
|
||||
assert registered_project is not None, f"Project {project_name} is not registered and cannot be queried."
|
||||
project = registered_project.get_project_instance(self.agent.serena_config)
|
||||
with tool.agent.active_project_context(project):
|
||||
return tool.apply(**json.loads(tool_params_json)) # type: ignore
|
||||
return tool.apply(**json.loads(tool_params_json))
|
||||
|
||||
def _is_project_server_required(self, tool: Tool) -> bool:
|
||||
match self.agent.get_language_backend():
|
||||
|
||||
@@ -228,7 +228,7 @@ class FindSymbolTool(Tool, ToolMarkerSymbolicRead):
|
||||
# In python 3.15 we could specify extra_items=True in the TypedDict definition,
|
||||
# https://peps.python.org/pep-0728/
|
||||
# If we ever upgrade to 3.15, we can remove the type: ignore[typeddict-unknown-key]
|
||||
s_dict["info"] = symbol_info # type: ignore[typeddict-unknown-key]
|
||||
s_dict["info"] = symbol_info
|
||||
|
||||
grouped_symbol_dicts = self.symbol_dict_grouper.group(symbol_dicts)
|
||||
result = self._to_json(grouped_symbol_dicts)
|
||||
@@ -306,12 +306,12 @@ class FindReferencingSymbolsTool(Tool, ToolMarkerSymbolicRead):
|
||||
}
|
||||
)
|
||||
|
||||
result = self.symbol_dict_grouper.group(reference_dicts) # type: ignore
|
||||
result = self.symbol_dict_grouper.group(reference_dicts)
|
||||
|
||||
# shortened result closures, from least to most aggressive shortening
|
||||
def make_refs_without_context() -> str:
|
||||
"""References with name_path and reference line, without surrounding code lines"""
|
||||
grouped = self.symbol_dict_grouper.group(copy.deepcopy(ref_summaries)) # type: ignore
|
||||
grouped = self.symbol_dict_grouper.group(copy.deepcopy(ref_summaries))
|
||||
return f"References without surrounding lines:\n{self._to_json(grouped)}"
|
||||
|
||||
def make_per_file_counts() -> str:
|
||||
|
||||
@@ -327,7 +327,7 @@ class Tool(Component):
|
||||
"""
|
||||
return {}
|
||||
|
||||
def apply_ex(self, log_call: bool = True, catch_exceptions: bool = True, mcp_ctx: Context | None = None, **kwargs) -> str: # type: ignore
|
||||
def apply_ex(self, log_call: bool = True, catch_exceptions: bool = True, mcp_ctx: Context | None = None, **kwargs) -> str:
|
||||
"""
|
||||
Applies the tool with logging and exception handling, using the given keyword arguments.
|
||||
This method either returns a string result or raises a ToolCallError in case of an error during tool application
|
||||
@@ -468,7 +468,7 @@ class EditingToolWithDiagnostics(Tool, ToolMarkerCanEdit):
|
||||
def __enter__(self) -> Self:
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb): # type: ignore
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
pass
|
||||
|
||||
def format_result(
|
||||
|
||||
@@ -19,7 +19,7 @@ def is_headless_environment() -> bool:
|
||||
return False
|
||||
|
||||
# Check for DISPLAY variable (required for X11)
|
||||
if not os.environ.get("DISPLAY"): # type: ignore
|
||||
if not os.environ.get("DISPLAY"):
|
||||
return True
|
||||
|
||||
# Check for SSH session
|
||||
|
||||
@@ -145,7 +145,7 @@ class SuspendedLoggersContext:
|
||||
root_logger.handlers.clear()
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb) -> None: # type: ignore
|
||||
def __exit__(self, exc_type, exc_val, exc_tb) -> None:
|
||||
root_logger = lg.getLogger()
|
||||
root_logger.handlers = self.saved_root_handlers
|
||||
if self.saved_root_level is not None:
|
||||
|
||||
@@ -47,7 +47,7 @@ def subprocess_check_output(
|
||||
) -> str:
|
||||
output = subprocess.check_output(
|
||||
args, stdin=subprocess.DEVNULL, stderr=subprocess.PIPE, timeout=timeout, env=os.environ.copy(), cwd=cwd, **subprocess_kwargs()
|
||||
).decode(encoding) # type: ignore
|
||||
).decode(encoding)
|
||||
if strip:
|
||||
output = output.strip()
|
||||
return output
|
||||
@@ -1038,7 +1038,7 @@ class ALLanguageServer(SolidLanguageServer):
|
||||
if original_name != normalized_name and self._AL_OBJECT_NAME_PATTERN.match(original_name):
|
||||
sel_range = symbol.get("selectionRange")
|
||||
if sel_range:
|
||||
start = sel_range.get("start") # type: ignore
|
||||
start = sel_range.get("start")
|
||||
if start and "line" in start and "character" in start:
|
||||
line = start["line"]
|
||||
char = start["character"]
|
||||
|
||||
@@ -82,7 +82,7 @@ class ClangdLanguageServer(SolidLanguageServer):
|
||||
@override
|
||||
def _document_symbols_cache_fingerprint(self) -> Hashable:
|
||||
cache_format_version = 1
|
||||
cpp_settings: dict[str, Any] = self._custom_settings or {}
|
||||
cpp_settings = self._custom_settings or {}
|
||||
return (
|
||||
cache_format_version,
|
||||
cpp_settings.get("clangd_version"),
|
||||
@@ -179,7 +179,7 @@ class ClangdLanguageServer(SolidLanguageServer):
|
||||
return None
|
||||
|
||||
# Get the target directory from ls_specific_settings, default to .serena
|
||||
cpp_settings: dict[str, Any] = self._custom_settings or {}
|
||||
cpp_settings = self._custom_settings or {}
|
||||
compile_commands_rel_dir = cpp_settings.get("compile_commands_dir", ".serena")
|
||||
compile_commands_dir = os.path.join(self.repository_root_path, compile_commands_rel_dir)
|
||||
os.makedirs(compile_commands_dir, exist_ok=True)
|
||||
@@ -411,9 +411,9 @@ class ClangdLanguageServer(SolidLanguageServer):
|
||||
|
||||
text_document_sync = capabilities["textDocumentSync"]
|
||||
if isinstance(text_document_sync, int):
|
||||
assert text_document_sync == 2 # type: ignore
|
||||
assert text_document_sync == 2
|
||||
else:
|
||||
assert text_document_sync["change"] == 2 # type: ignore
|
||||
assert text_document_sync["change"] == 2
|
||||
|
||||
assert "completionProvider" in capabilities
|
||||
completion_provider = capabilities["completionProvider"]
|
||||
|
||||
@@ -318,7 +318,7 @@ class ClojureLSP(SolidLanguageServer):
|
||||
if source_paths is not None:
|
||||
initialization_options["source-paths"] = source_paths
|
||||
|
||||
result = { # type: ignore
|
||||
result = {
|
||||
"processId": os.getpid(),
|
||||
"rootPath": repository_absolute_path,
|
||||
"rootUri": root_uri,
|
||||
|
||||
@@ -106,7 +106,7 @@ class RuntimeDependencyCollection:
|
||||
if not PlatformUtils.get_platform_id().is_windows():
|
||||
import pwd
|
||||
|
||||
kwargs["user"] = pwd.getpwuid(os.getuid()).pw_name # type: ignore
|
||||
kwargs["user"] = pwd.getpwuid(os.getuid()).pw_name
|
||||
|
||||
command = subprocess_util.convert_shell_cmd(command)
|
||||
log.info("Running command %s in '%s'", f"'{command}'" if isinstance(command, str) else command, cwd)
|
||||
@@ -120,7 +120,7 @@ class RuntimeDependencyCollection:
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
**kwargs,
|
||||
) # type: ignore
|
||||
)
|
||||
if completed_process.returncode != 0:
|
||||
log.warning("Command '%s' failed with return code %d", command, completed_process.returncode)
|
||||
log.warning("Command output:\n%s", completed_process.stdout)
|
||||
|
||||
@@ -277,7 +277,7 @@ class CSharpLanguageServer(SolidLanguageServer):
|
||||
if original_name != normalized_name:
|
||||
sel_range = symbol.get("selectionRange")
|
||||
if sel_range:
|
||||
start = sel_range.get("start") # type: ignore
|
||||
start = sel_range.get("start")
|
||||
if start and "line" in start and "character" in start:
|
||||
line = start["line"]
|
||||
char = start["character"]
|
||||
|
||||
@@ -1299,26 +1299,26 @@ class EclipseJDTLS(SolidLanguageServer):
|
||||
],
|
||||
}
|
||||
|
||||
initialize_params["initializationOptions"]["workspaceFolders"] = [repo_uri] # type: ignore
|
||||
initialize_params["initializationOptions"]["workspaceFolders"] = [repo_uri]
|
||||
|
||||
# IntelliCode bundle: only attached in default vscode-java VSIX mode.
|
||||
# In upstream-jdtls mode (jdtls_path set) we don't ship IntelliCode — agentic Serena workflows
|
||||
# don't use completion ranking, so the bundle would be inert dead weight.
|
||||
if self.runtime_dependency_paths.intellicode_jar_path is not None:
|
||||
initialize_params["initializationOptions"]["bundles"] = [self.runtime_dependency_paths.intellicode_jar_path] # type: ignore
|
||||
initialize_params["initializationOptions"]["bundles"] = [self.runtime_dependency_paths.intellicode_jar_path]
|
||||
else:
|
||||
initialize_params["initializationOptions"]["bundles"] = [] # type: ignore
|
||||
initialize_params["initializationOptions"]["bundles"] = []
|
||||
|
||||
initialize_params["initializationOptions"]["settings"]["java"]["configuration"]["runtimes"] = [ # type: ignore
|
||||
initialize_params["initializationOptions"]["settings"]["java"]["configuration"]["runtimes"] = [
|
||||
{"name": "JavaSE-21", "path": self.runtime_dependency_paths.jre_home_path, "default": True}
|
||||
]
|
||||
|
||||
for runtime in initialize_params["initializationOptions"]["settings"]["java"]["configuration"]["runtimes"]: # type: ignore
|
||||
for runtime in initialize_params["initializationOptions"]["settings"]["java"]["configuration"]["runtimes"]:
|
||||
assert "name" in runtime
|
||||
assert "path" in runtime
|
||||
assert os.path.exists(runtime["path"]), f"Runtime required for eclipse_jdtls at path {runtime['path']} does not exist"
|
||||
|
||||
gradle_settings = initialize_params["initializationOptions"]["settings"]["java"]["import"]["gradle"] # type: ignore
|
||||
gradle_settings = initialize_params["initializationOptions"]["settings"]["java"]["import"]["gradle"]
|
||||
# In upstream-jdtls mode we don't ship a Gradle distribution — Buildship will use the project's
|
||||
# ./gradlew wrapper or a system-installed Gradle via its standard discovery rules.
|
||||
if self.runtime_dependency_paths.gradle_path is not None:
|
||||
@@ -1483,7 +1483,7 @@ class EclipseJDTLS(SolidLanguageServer):
|
||||
symbol["name"] = symbol["name"][: symbol["name"].index("(")]
|
||||
children = symbol.get("children")
|
||||
if children:
|
||||
for child in children: # type: ignore
|
||||
for child in children:
|
||||
fix_name(child)
|
||||
|
||||
for root_symbol in result:
|
||||
|
||||
@@ -212,6 +212,7 @@ class ElixirTools(SolidLanguageServer):
|
||||
)
|
||||
self.server_ready = threading.Event()
|
||||
self.request_id = 0
|
||||
self._building_project = False
|
||||
|
||||
# Set generous timeout for Expert which can be slow to initialize and respond
|
||||
self.set_request_timeout(180.0)
|
||||
|
||||
@@ -299,8 +299,8 @@ class FortranLanguageServer(SolidLanguageServer):
|
||||
|
||||
with self.open_file(relative_file_path):
|
||||
self.server.notify.did_save_text_document(
|
||||
{
|
||||
LSPConstants.TEXT_DOCUMENT: { # type: ignore
|
||||
{ # ty: ignore[invalid-argument-type] # dict built from LSPConstants keys; shape matches the TypedDict
|
||||
LSPConstants.TEXT_DOCUMENT: {
|
||||
LSPConstants.URI: uri,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ class GodotLanguageServer(SolidLanguageServer):
|
||||
process_launch_info: ProcessLaunchInfo,
|
||||
logging_fn: Callable[[str, str, StringDict | str], None] | None,
|
||||
) -> LanguageServerInterface:
|
||||
settings: dict = self._custom_settings or {}
|
||||
settings = self._custom_settings or {}
|
||||
port = settings.get("port", DEFAULT_GODOT_LS_PORT)
|
||||
request_timeout = settings.get("request_timeout", DEFAULT_GODOT_REQUEST_TIMEOUT)
|
||||
self._configured_request_timeout = settings.get("request_timeout")
|
||||
|
||||
@@ -141,7 +141,7 @@ class JuliaLanguageServer(SolidLanguageServer):
|
||||
Returns the initialize params for the Julia Language Server.
|
||||
"""
|
||||
root_uri = pathlib.Path(repository_absolute_path).as_uri()
|
||||
initialize_params: InitializeParams = { # type: ignore
|
||||
initialize_params: InitializeParams = {
|
||||
"processId": os.getpid(),
|
||||
"rootPath": repository_absolute_path,
|
||||
"rootUri": root_uri,
|
||||
@@ -171,7 +171,7 @@ class JuliaLanguageServer(SolidLanguageServer):
|
||||
}
|
||||
],
|
||||
}
|
||||
return initialize_params # type: ignore
|
||||
return initialize_params
|
||||
|
||||
def _start_server(self) -> None:
|
||||
"""Start the LanguageServer.jl server process."""
|
||||
|
||||
@@ -201,7 +201,7 @@ class Marksman(SolidLanguageServer):
|
||||
Returns the initialize params for the Marksman Language Server.
|
||||
"""
|
||||
root_uri = pathlib.Path(repository_absolute_path).as_uri()
|
||||
initialize_params: InitializeParams = { # type: ignore
|
||||
initialize_params: InitializeParams = {
|
||||
"processId": os.getpid(),
|
||||
"locale": "en",
|
||||
"rootPath": repository_absolute_path,
|
||||
|
||||
@@ -412,8 +412,8 @@ class PowerShellLanguageServer(SolidLanguageServer):
|
||||
|
||||
with self.open_file(relative_file_path):
|
||||
self.server.notify.did_save_text_document(
|
||||
{
|
||||
LSPConstants.TEXT_DOCUMENT: { # type: ignore
|
||||
{ # ty: ignore[invalid-argument-type] # dict built from LSPConstants keys; shape matches the TypedDict
|
||||
LSPConstants.TEXT_DOCUMENT: {
|
||||
LSPConstants.URI: uri,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ class PyrightServer(SolidLanguageServer):
|
||||
Returns the initialize params for the Pyright Language Server.
|
||||
"""
|
||||
# Create basic initialization parameters
|
||||
initialize_params = { # type: ignore
|
||||
initialize_params = {
|
||||
"processId": os.getpid(),
|
||||
"rootPath": repository_absolute_path,
|
||||
"rootUri": pathlib.Path(repository_absolute_path).as_uri(),
|
||||
@@ -168,9 +168,10 @@ class PyrightServer(SolidLanguageServer):
|
||||
message_text = ""
|
||||
percentage: object | None = None
|
||||
if isinstance(params, dict):
|
||||
raw_message = params.get("message")
|
||||
params_dict = cast("dict[str, object]", params)
|
||||
raw_message = params_dict.get("message")
|
||||
message_text = "" if raw_message is None else str(raw_message)
|
||||
percentage = params.get("percentage")
|
||||
percentage = params_dict.get("percentage")
|
||||
elif params is not None:
|
||||
message_text = str(params)
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import logging
|
||||
import os
|
||||
import shutil
|
||||
from typing import cast
|
||||
|
||||
from overrides import override
|
||||
|
||||
@@ -62,7 +63,7 @@ class RegalLanguageServer(SolidLanguageServer):
|
||||
:return: LSP initialization parameters
|
||||
"""
|
||||
root_uri = PathUtils.path_to_uri(repository_absolute_path)
|
||||
return {
|
||||
initialize_params = {
|
||||
"processId": os.getpid(),
|
||||
"locale": "en",
|
||||
"rootPath": repository_absolute_path,
|
||||
@@ -76,9 +77,9 @@ class RegalLanguageServer(SolidLanguageServer):
|
||||
"documentSymbol": {
|
||||
"dynamicRegistration": True,
|
||||
"hierarchicalDocumentSymbolSupport": True,
|
||||
"symbolKind": {"valueSet": list(range(1, 27))}, # type: ignore[arg-type]
|
||||
"symbolKind": {"valueSet": list(range(1, 27))},
|
||||
},
|
||||
"hover": {"dynamicRegistration": True, "contentFormat": ["markdown", "plaintext"]}, # type: ignore[list-item]
|
||||
"hover": {"dynamicRegistration": True, "contentFormat": ["markdown", "plaintext"]},
|
||||
"codeAction": {"dynamicRegistration": True},
|
||||
"formatting": {"dynamicRegistration": True},
|
||||
},
|
||||
@@ -95,17 +96,18 @@ class RegalLanguageServer(SolidLanguageServer):
|
||||
}
|
||||
],
|
||||
}
|
||||
return cast(InitializeParams, initialize_params)
|
||||
|
||||
def _start_server(self) -> None:
|
||||
"""Start Regal language server process and wait for initialization."""
|
||||
|
||||
def register_capability_handler(params) -> None: # type: ignore[no-untyped-def]
|
||||
def register_capability_handler(params) -> None:
|
||||
return
|
||||
|
||||
def window_log_message(msg) -> None: # type: ignore[no-untyped-def]
|
||||
def window_log_message(msg) -> None:
|
||||
log.info(f"LSP: window/logMessage: {msg}")
|
||||
|
||||
def do_nothing(params) -> None: # type: ignore[no-untyped-def]
|
||||
def do_nothing(params) -> None:
|
||||
return
|
||||
|
||||
self.server.on_request("client/registerCapability", register_capability_handler)
|
||||
|
||||
@@ -133,7 +133,7 @@ class Solargraph(SolidLanguageServer):
|
||||
if bundle_cmd.startswith("bin/"):
|
||||
bundle_full_path = os.path.join(repository_root_path, bundle_cmd)
|
||||
else:
|
||||
bundle_full_path = find_executable_with_extensions(bundle_cmd) # type: ignore[assignment]
|
||||
bundle_full_path = find_executable_with_extensions(bundle_cmd)
|
||||
if bundle_full_path and os.path.exists(bundle_full_path):
|
||||
bundle_path = bundle_full_path if bundle_cmd.startswith("bin/") else bundle_cmd
|
||||
break
|
||||
@@ -275,12 +275,12 @@ class Solargraph(SolidLanguageServer):
|
||||
root_uri = pathlib.Path(repository_absolute_path).as_uri()
|
||||
exclude_patterns = Solargraph._get_ruby_exclude_patterns(repository_absolute_path)
|
||||
|
||||
initialize_params: InitializeParams = { # type: ignore
|
||||
initialize_params: InitializeParams = {
|
||||
"processId": os.getpid(),
|
||||
"rootPath": repository_absolute_path,
|
||||
"rootUri": root_uri,
|
||||
"initializationOptions": {
|
||||
"exclude": exclude_patterns, # type: ignore[dict-item]
|
||||
"exclude": exclude_patterns,
|
||||
},
|
||||
"capabilities": {
|
||||
"workspace": {
|
||||
@@ -301,7 +301,7 @@ class Solargraph(SolidLanguageServer):
|
||||
}
|
||||
],
|
||||
}
|
||||
return initialize_params # type: ignore[return-value]
|
||||
return initialize_params
|
||||
|
||||
def _start_server(self) -> None:
|
||||
"""
|
||||
|
||||
@@ -313,8 +313,8 @@ class SolidityLanguageServer(SolidLanguageServer):
|
||||
}
|
||||
|
||||
self.server.notify.did_open_text_document(
|
||||
{
|
||||
LSPConstants.TEXT_DOCUMENT: { # type: ignore
|
||||
{ # ty: ignore[invalid-argument-type] # dict built from LSPConstants keys; shape matches the TypedDict
|
||||
LSPConstants.TEXT_DOCUMENT: {
|
||||
LSPConstants.URI: uri,
|
||||
LSPConstants.LANGUAGE_ID: self.language_id,
|
||||
LSPConstants.VERSION: 0,
|
||||
@@ -324,12 +324,12 @@ class SolidityLanguageServer(SolidLanguageServer):
|
||||
)
|
||||
try:
|
||||
self.server.notify.did_change_text_document(
|
||||
{
|
||||
LSPConstants.TEXT_DOCUMENT: { # type: ignore
|
||||
{ # ty: ignore[invalid-argument-type] # dict built from LSPConstants keys; shape matches the TypedDict
|
||||
LSPConstants.TEXT_DOCUMENT: {
|
||||
LSPConstants.URI: uri,
|
||||
LSPConstants.VERSION: 1,
|
||||
},
|
||||
LSPConstants.CONTENT_CHANGES: [ # type: ignore
|
||||
LSPConstants.CONTENT_CHANGES: [
|
||||
{
|
||||
LSPConstants.RANGE: {
|
||||
"start": {"line": 0, "character": 0},
|
||||
@@ -348,8 +348,8 @@ class SolidityLanguageServer(SolidLanguageServer):
|
||||
)
|
||||
finally:
|
||||
self.server.notify.did_close_text_document(
|
||||
{
|
||||
LSPConstants.TEXT_DOCUMENT: { # type: ignore
|
||||
{ # ty: ignore[invalid-argument-type] # dict built from LSPConstants keys; shape matches the TypedDict
|
||||
LSPConstants.TEXT_DOCUMENT: {
|
||||
LSPConstants.URI: uri,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -438,7 +438,7 @@ class SvelteLanguageServer(SolidLanguageServer):
|
||||
return
|
||||
_orig_notify_send("$/onDidChangeTsOrJsFile", {"uri": uri, "changes": changes})
|
||||
|
||||
self.server.notify.send_notification = send_notification_wrapped # type: ignore[method-assign] # type: ignore[method-assign] # type: ignore[method-assign]
|
||||
self.server.notify.send_notification = send_notification_wrapped
|
||||
|
||||
def _get_initialize_params(self) -> InitializeParams:
|
||||
"""
|
||||
|
||||
@@ -36,7 +36,7 @@ if os.name != "nt": # Unix-like systems
|
||||
import pwd
|
||||
else:
|
||||
# Dummy pwd module for Windows
|
||||
class pwd: # type: ignore
|
||||
class pwd:
|
||||
@staticmethod
|
||||
def getpwuid(uid: Any) -> Any:
|
||||
return type("obj", (), {"pw_name": os.environ.get("USERNAME", "unknown")})()
|
||||
|
||||
@@ -344,7 +344,7 @@ class VueLanguageServer(SolidLanguageServer):
|
||||
continue
|
||||
|
||||
new_item: dict = {}
|
||||
new_item.update(item) # type: ignore[arg-type]
|
||||
new_item.update(item)
|
||||
new_item["absolutePath"] = str(abs_path)
|
||||
new_item["relativePath"] = str(rel_path)
|
||||
result.append(ls_types.Location(**new_item)) # type: ignore
|
||||
@@ -390,7 +390,7 @@ class VueLanguageServer(SolidLanguageServer):
|
||||
log.debug(f"Skipping invalid location item: {item}")
|
||||
continue
|
||||
|
||||
abs_path = PathUtils.uri_to_path(item["uri"]) # type: ignore[arg-type]
|
||||
abs_path = PathUtils.uri_to_path(item["uri"])
|
||||
if not Path(abs_path).is_relative_to(self.repository_root_path):
|
||||
log.warning(f"Found file reference outside repository: {abs_path}, skipping")
|
||||
continue
|
||||
@@ -401,7 +401,7 @@ class VueLanguageServer(SolidLanguageServer):
|
||||
continue
|
||||
|
||||
new_item: dict = {}
|
||||
new_item.update(item) # type: ignore[arg-type]
|
||||
new_item.update(item)
|
||||
new_item["absolutePath"] = str(abs_path)
|
||||
new_item["relativePath"] = str(rel_path)
|
||||
ret.append(Location(**new_item)) # type: ignore
|
||||
|
||||
+27
-27
@@ -108,8 +108,8 @@ class LSPFileBuffer:
|
||||
return
|
||||
self._is_open_in_ls = True
|
||||
self.language_server.server.notify.did_open_text_document(
|
||||
{
|
||||
LSPConstants.TEXT_DOCUMENT: { # type: ignore
|
||||
{ # ty: ignore[invalid-argument-type] # dict built from LSPConstants keys; shape matches the TypedDict
|
||||
LSPConstants.TEXT_DOCUMENT: {
|
||||
LSPConstants.URI: self.uri,
|
||||
LSPConstants.LANGUAGE_ID: self.language_id,
|
||||
LSPConstants.VERSION: 0,
|
||||
@@ -121,8 +121,8 @@ class LSPFileBuffer:
|
||||
def close(self) -> None:
|
||||
if self._is_open_in_ls:
|
||||
self.language_server.server.notify.did_close_text_document(
|
||||
{
|
||||
LSPConstants.TEXT_DOCUMENT: { # type: ignore
|
||||
{ # ty: ignore[invalid-argument-type] # dict built from LSPConstants keys; shape matches the TypedDict
|
||||
LSPConstants.TEXT_DOCUMENT: {
|
||||
LSPConstants.URI: self.uri,
|
||||
}
|
||||
}
|
||||
@@ -223,10 +223,10 @@ class SymbolBodyFactory:
|
||||
return existing_body
|
||||
|
||||
assert "location" in symbol
|
||||
start_line = symbol["location"]["range"]["start"]["line"] # type: ignore
|
||||
end_line = symbol["location"]["range"]["end"]["line"] # type: ignore
|
||||
start_col = symbol["location"]["range"]["start"]["character"] # type: ignore
|
||||
end_col = symbol["location"]["range"]["end"]["character"] # type: ignore
|
||||
start_line = symbol["location"]["range"]["start"]["line"]
|
||||
end_line = symbol["location"]["range"]["end"]["line"]
|
||||
start_col = symbol["location"]["range"]["start"]["character"]
|
||||
end_col = symbol["location"]["range"]["end"]["character"]
|
||||
return SymbolBody(self._lines, start_line, start_col, end_line, end_col)
|
||||
|
||||
|
||||
@@ -508,7 +508,7 @@ class SolidLanguageServer(ABC):
|
||||
# For now, we assume that all language server implementations have the same signature of the constructor
|
||||
# (which, unfortunately, differs from the signature of the base class).
|
||||
# If this assumption is ever violated, we need branching logic here.
|
||||
ls = ls_class(config, repository_root_path, solidlsp_settings) # type: ignore
|
||||
ls = ls_class(config, repository_root_path, solidlsp_settings)
|
||||
ls.set_request_timeout(timeout)
|
||||
return ls
|
||||
|
||||
@@ -590,7 +590,7 @@ class SolidLanguageServer(ABC):
|
||||
log.debug(f"LSP: {source} -> {target}: {msg!s}")
|
||||
|
||||
else:
|
||||
logging_fn = None # type: ignore
|
||||
logging_fn = None
|
||||
|
||||
# create the LanguageServerHandler, which provides the functionality to start the language server and communicate with it,
|
||||
# preparing the launch command beforehand
|
||||
@@ -1024,8 +1024,8 @@ class SolidLanguageServer(ABC):
|
||||
if self._supports_pull_diagnostics():
|
||||
try:
|
||||
response = self.server.send.text_document_diagnostic(
|
||||
{
|
||||
LSPConstants.TEXT_DOCUMENT: { # type: ignore
|
||||
{ # ty: ignore[invalid-argument-type] # dict built from LSPConstants keys; shape matches the TypedDict
|
||||
LSPConstants.TEXT_DOCUMENT: {
|
||||
LSPConstants.URI: uri,
|
||||
}
|
||||
}
|
||||
@@ -1380,8 +1380,8 @@ class SolidLanguageServer(ABC):
|
||||
new_contents, new_l, new_c = TextUtils.insert_text_at_position(file_buffer.contents, line, column, text_to_be_inserted)
|
||||
file_buffer.contents = new_contents
|
||||
self.server.notify.did_change_text_document(
|
||||
{
|
||||
LSPConstants.TEXT_DOCUMENT: { # type: ignore
|
||||
{ # ty: ignore[invalid-argument-type] # dict built from LSPConstants keys; shape matches the TypedDict
|
||||
LSPConstants.TEXT_DOCUMENT: {
|
||||
LSPConstants.VERSION: file_buffer.version,
|
||||
LSPConstants.URI: file_buffer.uri,
|
||||
},
|
||||
@@ -1423,8 +1423,8 @@ class SolidLanguageServer(ABC):
|
||||
)
|
||||
file_buffer.contents = new_contents
|
||||
self.server.notify.did_change_text_document(
|
||||
{
|
||||
LSPConstants.TEXT_DOCUMENT: { # type: ignore
|
||||
{ # ty: ignore[invalid-argument-type] # dict built from LSPConstants keys; shape matches the TypedDict
|
||||
LSPConstants.TEXT_DOCUMENT: {
|
||||
LSPConstants.VERSION: file_buffer.version,
|
||||
LSPConstants.URI: file_buffer.uri,
|
||||
},
|
||||
@@ -1766,15 +1766,15 @@ class SolidLanguageServer(ABC):
|
||||
response = self.server.send.completion(completion_params)
|
||||
if isinstance(response, list):
|
||||
response = {"items": response, "isIncomplete": False}
|
||||
if response is None or not response["isIncomplete"]: # type: ignore
|
||||
if response is None or not response["isIncomplete"]:
|
||||
break
|
||||
|
||||
# TODO: Understand how to appropriately handle `isIncomplete`
|
||||
if response is None or (response["isIncomplete"] and not allow_incomplete): # type: ignore
|
||||
if response is None or (response["isIncomplete"] and not allow_incomplete):
|
||||
return []
|
||||
|
||||
if "items" in response:
|
||||
response = response["items"] # type: ignore
|
||||
response = response["items"]
|
||||
|
||||
response = cast(list[LSPTypes.CompletionItem], response)
|
||||
|
||||
@@ -1792,8 +1792,8 @@ class SolidLanguageServer(ABC):
|
||||
|
||||
if "label" in item:
|
||||
completion_item["completionText"] = item["label"]
|
||||
completion_item["kind"] = item["kind"] # type: ignore
|
||||
elif "insertText" in item: # type: ignore
|
||||
completion_item["kind"] = item["kind"]
|
||||
elif "insertText" in item:
|
||||
completion_item["completionText"] = item["insertText"]
|
||||
completion_item["kind"] = item["kind"]
|
||||
elif "textEdit" in item and "newText" in item["textEdit"]:
|
||||
@@ -1977,9 +1977,9 @@ class SolidLanguageServer(ABC):
|
||||
item["location"] = tree_location
|
||||
location = item["location"]
|
||||
if "absolutePath" not in location:
|
||||
location["absolutePath"] = absolute_path # type: ignore
|
||||
location["absolutePath"] = absolute_path
|
||||
if "relativePath" not in location:
|
||||
location["relativePath"] = relative_file_path # type: ignore
|
||||
location["relativePath"] = relative_file_path
|
||||
|
||||
item["body"] = self.create_symbol_body(item, factory=body_factory)
|
||||
|
||||
@@ -2021,7 +2021,7 @@ class SolidLanguageServer(ABC):
|
||||
if "children" in usymbol:
|
||||
usymbol["children"] = convert_symbols_with_common_parent(usymbol["children"], usymbol) # type: ignore
|
||||
else:
|
||||
usymbol["children"] = [] # type: ignore
|
||||
usymbol["children"] = []
|
||||
unified_symbols.append(usymbol)
|
||||
return unified_symbols
|
||||
|
||||
@@ -2080,7 +2080,7 @@ class SolidLanguageServer(ABC):
|
||||
return []
|
||||
|
||||
# Create package symbol for directory
|
||||
package_symbol = ls_types.UnifiedSymbolInformation( # type: ignore
|
||||
package_symbol = ls_types.UnifiedSymbolInformation(
|
||||
name=os.path.basename(abs_dir_path),
|
||||
kind=ls_types.SymbolKind.Package,
|
||||
location=ls_types.Location(
|
||||
@@ -2128,7 +2128,7 @@ class SolidLanguageServer(ABC):
|
||||
|
||||
# Create file symbol, link with children
|
||||
file_range = self._get_range_from_file_content(file_data.contents)
|
||||
file_symbol = ls_types.UnifiedSymbolInformation( # type: ignore
|
||||
file_symbol = ls_types.UnifiedSymbolInformation(
|
||||
name=os.path.splitext(contained_dir_or_file_name)[0],
|
||||
kind=ls_types.SymbolKind.File,
|
||||
range=file_range,
|
||||
@@ -2980,7 +2980,7 @@ class SolidLanguageServer(ABC):
|
||||
migrated_cache[new_cache_key] = (file_hash, root_symbols)
|
||||
num_symbols_migrated += len(all_symbols)
|
||||
log.info("Migrated %d document symbols from legacy cache", num_symbols_migrated)
|
||||
self._raw_document_symbols_cache = migrated_cache # type: ignore
|
||||
self._raw_document_symbols_cache = migrated_cache
|
||||
self._raw_document_symbols_cache_is_modified = True
|
||||
self._save_raw_document_symbols_cache()
|
||||
legacy_cache_file.unlink()
|
||||
|
||||
@@ -571,7 +571,7 @@ class Language(str, Enum):
|
||||
|
||||
return CSharpLanguageServer
|
||||
case self.CSHARP_OMNISHARP:
|
||||
from solidlsp.language_servers.omnisharp import OmniSharp # type: ignore[attr-defined]
|
||||
from solidlsp.language_servers.omnisharp import OmniSharp
|
||||
|
||||
return OmniSharp
|
||||
case self.TYPESCRIPT:
|
||||
@@ -679,7 +679,7 @@ class Language(str, Enum):
|
||||
|
||||
return ZigLanguageServer
|
||||
case self.NIX:
|
||||
from solidlsp.language_servers.nixd_ls import NixLanguageServer # type: ignore
|
||||
from solidlsp.language_servers.nixd_ls import NixLanguageServer
|
||||
|
||||
return NixLanguageServer
|
||||
case self.LUA:
|
||||
|
||||
+20
-14
@@ -10,7 +10,7 @@ from abc import ABC, abstractmethod
|
||||
from collections.abc import Callable
|
||||
from dataclasses import dataclass
|
||||
from queue import Empty, Queue
|
||||
from typing import IO, Any, AnyStr
|
||||
from typing import IO, Any, AnyStr, cast
|
||||
|
||||
from sensai.util.string import ToStringMixin
|
||||
|
||||
@@ -462,24 +462,30 @@ class StdioLanguageServer(LanguageServerInterface):
|
||||
log.info("Starting language server process via command: %s", self.process_launch_info.cmd)
|
||||
kwargs = subprocess_util.subprocess_kwargs()
|
||||
kwargs["start_new_session"] = self.start_independent_lsp_process
|
||||
self.process = subprocess.Popen(
|
||||
cmd,
|
||||
stdout=subprocess.PIPE,
|
||||
stdin=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
env=child_proc_env,
|
||||
cwd=self.process_launch_info.cwd,
|
||||
shell=True,
|
||||
**kwargs,
|
||||
# the language server is launched with binary (bytes) pipes; the cast is needed because the
|
||||
# presence of platform-specific **kwargs prevents ty from selecting the bytes Popen overload
|
||||
process = cast(
|
||||
"subprocess.Popen[bytes]",
|
||||
subprocess.Popen(
|
||||
cmd,
|
||||
stdout=subprocess.PIPE,
|
||||
stdin=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
env=child_proc_env,
|
||||
cwd=self.process_launch_info.cwd,
|
||||
shell=True,
|
||||
**kwargs,
|
||||
),
|
||||
)
|
||||
self.process = process
|
||||
|
||||
# Check if process terminated immediately
|
||||
if self.process.returncode is not None:
|
||||
if process.returncode is not None:
|
||||
log.error("Language server has already terminated/could not be started")
|
||||
# Process has already terminated
|
||||
stderr_data = self.process.stderr.read() if self.process.stderr else b""
|
||||
stderr_data = process.stderr.read() if process.stderr else b""
|
||||
error_message = stderr_data.decode("utf-8", errors="replace")
|
||||
raise RuntimeError(f"Process terminated immediately with code {self.process.returncode}. Error: {error_message}")
|
||||
raise RuntimeError(f"Process terminated immediately with code {process.returncode}. Error: {error_message}")
|
||||
|
||||
# start threads to read stdout and stderr of the process
|
||||
threading.Thread(
|
||||
@@ -522,7 +528,7 @@ class StdioLanguageServer(LanguageServerInterface):
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def _read_bytes_from_process(self, process, stream, num_bytes) -> bytes: # type: ignore
|
||||
def _read_bytes_from_process(self, process, stream, num_bytes) -> bytes:
|
||||
"""Read exactly num_bytes from process stdout"""
|
||||
data = b""
|
||||
while len(data) < num_bytes:
|
||||
|
||||
@@ -527,7 +527,7 @@ class PlatformUtils:
|
||||
_anonymous_ = ("u",)
|
||||
|
||||
sys_info = SYSTEM_INFO()
|
||||
ctypes.windll.kernel32.GetNativeSystemInfo(ctypes.byref(sys_info)) # type: ignore
|
||||
ctypes.windll.kernel32.GetNativeSystemInfo(ctypes.byref(sys_info))
|
||||
|
||||
arch_map = {
|
||||
9: "AMD64",
|
||||
|
||||
@@ -15,7 +15,7 @@ def subprocess_kwargs() -> dict:
|
||||
"""
|
||||
kwargs = {}
|
||||
if platform.system() == "Windows":
|
||||
kwargs["creationflags"] = subprocess.CREATE_NO_WINDOW # type: ignore
|
||||
kwargs["creationflags"] = subprocess.CREATE_NO_WINDOW
|
||||
return kwargs
|
||||
|
||||
|
||||
|
||||
@@ -115,7 +115,7 @@ class SafeZipExtractor:
|
||||
"""
|
||||
if sys.platform.startswith("win"):
|
||||
return Path(rf"\\?\{os.path.abspath(path)}")
|
||||
return path # type: ignore
|
||||
return path
|
||||
|
||||
|
||||
# Example usage:
|
||||
|
||||
@@ -464,22 +464,22 @@ class TestToolUseCounter:
|
||||
counter = ToolUseCounter(n_recent_grep_uses=2, n_recent_read_file_uses=1)
|
||||
|
||||
hook_stub = type("HookStub", (), {"session_persistence_dir": str(tmp_path)})()
|
||||
counter.save(hook_stub) # type: ignore[arg-type]
|
||||
loaded = ToolUseCounter.load(hook_stub) # type: ignore[arg-type]
|
||||
counter.save(hook_stub)
|
||||
loaded = ToolUseCounter.load(hook_stub)
|
||||
|
||||
assert loaded.n_recent_grep_uses == 2
|
||||
assert loaded.n_recent_read_file_uses == 1
|
||||
|
||||
def test_load_returns_fresh_counter_on_missing_file(self, tmp_path: Path):
|
||||
hook_stub = type("HookStub", (), {"session_persistence_dir": str(tmp_path / "nonexistent")})()
|
||||
loaded = ToolUseCounter.load(hook_stub) # type: ignore[arg-type]
|
||||
loaded = ToolUseCounter.load(hook_stub)
|
||||
assert loaded == ToolUseCounter()
|
||||
|
||||
def test_load_returns_fresh_counter_on_corrupt_file(self, tmp_path: Path):
|
||||
hook_stub = type("HookStub", (), {"session_persistence_dir": str(tmp_path)})()
|
||||
path = tmp_path / ToolUseCounter._FILE_NAME
|
||||
path.write_bytes(b"not a pickle")
|
||||
loaded = ToolUseCounter.load(hook_stub) # type: ignore[arg-type]
|
||||
loaded = ToolUseCounter.load(hook_stub)
|
||||
assert loaded == ToolUseCounter()
|
||||
|
||||
def test_is_hook_active_respects_min_interval(self):
|
||||
|
||||
@@ -25,7 +25,7 @@ class BaseMockTool(Tool):
|
||||
"""A mock Tool class for testing."""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(MockAgent()) # type: ignore
|
||||
super().__init__(MockAgent())
|
||||
|
||||
|
||||
class BasicTool(BaseMockTool):
|
||||
|
||||
@@ -46,7 +46,7 @@ class BaseCase:
|
||||
id: str
|
||||
|
||||
def to_pytest_param(self, *marks: MarkDecorator | Mark) -> ParameterSet:
|
||||
return pytest.param(self.language, self, marks=[*get_pytest_markers(self.language), *marks], id=self.id) # type: ignore
|
||||
return pytest.param(self.language, self, marks=[*get_pytest_markers(self.language), *marks], id=self.id)
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -1290,7 +1290,7 @@ class TestPromptProvision:
|
||||
|
||||
@classmethod
|
||||
def _call_tool(cls, agent: SerenaAgent, tool_class: type[Tool], session_id: str = "global", **kwargs) -> str:
|
||||
result = agent.get_tool(tool_class).apply_ex(mcp_ctx=cls.MockContext(session_id), **kwargs) # type: ignore
|
||||
result = agent.get_tool(tool_class).apply_ex(mcp_ctx=cls.MockContext(session_id), **kwargs)
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
|
||||
@@ -251,10 +251,10 @@ class TestSymbolDictTypes:
|
||||
:param key_type: the corresponding key type (Literal[...]) that the dict should have for keys
|
||||
"""
|
||||
dict_type_keys = dict_type.__annotations__.keys()
|
||||
assert len(dict_type_keys) == len(
|
||||
key_type.__args__ # type: ignore
|
||||
), f"Expected {len(key_type.__args__)} keys in {dict_type}, but got {len(dict_type_keys)}" # type: ignore
|
||||
for expected_key in key_type.__args__: # type: ignore
|
||||
assert len(dict_type_keys) == len(key_type.__args__), (
|
||||
f"Expected {len(key_type.__args__)} keys in {dict_type}, but got {len(dict_type_keys)}"
|
||||
)
|
||||
for expected_key in key_type.__args__:
|
||||
assert expected_key in dict_type_keys, f"Expected key '{expected_key}' not found in {dict_type}"
|
||||
|
||||
def test_ls_symbol_dict_type(self):
|
||||
|
||||
@@ -265,7 +265,7 @@ class TestAngularCoreProbe:
|
||||
from solidlsp.language_servers.angular_language_server import AngularLanguageServer
|
||||
|
||||
stub = type("Stub", (), {"repository_root_path": repo_path})()
|
||||
return AngularLanguageServer._find_angular_core_install(stub) # type: ignore[arg-type]
|
||||
return AngularLanguageServer._find_angular_core_install(stub)
|
||||
|
||||
def test_finds_core_at_project_root(self, tmp_path) -> None:
|
||||
core_pkg = tmp_path / "node_modules" / "@angular" / "core" / "package.json"
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# type: ignore
|
||||
import os
|
||||
|
||||
import pytest
|
||||
|
||||
@@ -1485,47 +1485,6 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/64/f2/66bd65ca0139675a0d7b18f0bada6e12b51a984e41a76dbe44761bf1b3ee/mslex-1.3.0-py3-none-any.whl", hash = "sha256:c7074b347201b3466fc077c5692fbce9b5f62a63a51f537a53fbbd02eff2eea4", size = 7820, upload-time = "2024-10-16T13:16:17.566Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mypy"
|
||||
version = "1.17.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "mypy-extensions" },
|
||||
{ name = "pathspec" },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/1e/e3/034322d5a779685218ed69286c32faa505247f1f096251ef66c8fd203b08/mypy-1.17.0.tar.gz", hash = "sha256:e5d7ccc08ba089c06e2f5629c660388ef1fee708444f1dee0b9203fa031dee03", size = 3352114, upload-time = "2025-07-14T20:34:30.181Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/d4/24/82efb502b0b0f661c49aa21cfe3e1999ddf64bf5500fc03b5a1536a39d39/mypy-1.17.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9d4fe5c72fd262d9c2c91c1117d16aac555e05f5beb2bae6a755274c6eec42be", size = 10914150, upload-time = "2025-07-14T20:31:51.985Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/03/96/8ef9a6ff8cedadff4400e2254689ca1dc4b420b92c55255b44573de10c54/mypy-1.17.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d96b196e5c16f41b4f7736840e8455958e832871990c7ba26bf58175e357ed61", size = 10039845, upload-time = "2025-07-14T20:32:30.527Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/df/32/7ce359a56be779d38021d07941cfbb099b41411d72d827230a36203dbb81/mypy-1.17.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:73a0ff2dd10337ceb521c080d4147755ee302dcde6e1a913babd59473904615f", size = 11837246, upload-time = "2025-07-14T20:32:01.28Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/82/16/b775047054de4d8dbd668df9137707e54b07fe18c7923839cd1e524bf756/mypy-1.17.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:24cfcc1179c4447854e9e406d3af0f77736d631ec87d31c6281ecd5025df625d", size = 12571106, upload-time = "2025-07-14T20:34:26.942Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a1/cf/fa33eaf29a606102c8d9ffa45a386a04c2203d9ad18bf4eef3e20c43ebc8/mypy-1.17.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3c56f180ff6430e6373db7a1d569317675b0a451caf5fef6ce4ab365f5f2f6c3", size = 12759960, upload-time = "2025-07-14T20:33:42.882Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/94/75/3f5a29209f27e739ca57e6350bc6b783a38c7621bdf9cac3ab8a08665801/mypy-1.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:eafaf8b9252734400f9b77df98b4eee3d2eecab16104680d51341c75702cad70", size = 9503888, upload-time = "2025-07-14T20:32:34.392Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/12/e9/e6824ed620bbf51d3bf4d6cbbe4953e83eaf31a448d1b3cfb3620ccb641c/mypy-1.17.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f986f1cab8dbec39ba6e0eaa42d4d3ac6686516a5d3dccd64be095db05ebc6bb", size = 11086395, upload-time = "2025-07-14T20:34:11.452Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ba/51/a4afd1ae279707953be175d303f04a5a7bd7e28dc62463ad29c1c857927e/mypy-1.17.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:51e455a54d199dd6e931cd7ea987d061c2afbaf0960f7f66deef47c90d1b304d", size = 10120052, upload-time = "2025-07-14T20:33:09.897Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8a/71/19adfeac926ba8205f1d1466d0d360d07b46486bf64360c54cb5a2bd86a8/mypy-1.17.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3204d773bab5ff4ebbd1f8efa11b498027cd57017c003ae970f310e5b96be8d8", size = 11861806, upload-time = "2025-07-14T20:32:16.028Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0b/64/d6120eca3835baf7179e6797a0b61d6c47e0bc2324b1f6819d8428d5b9ba/mypy-1.17.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1051df7ec0886fa246a530ae917c473491e9a0ba6938cfd0ec2abc1076495c3e", size = 12744371, upload-time = "2025-07-14T20:33:33.503Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1f/dc/56f53b5255a166f5bd0f137eed960e5065f2744509dfe69474ff0ba772a5/mypy-1.17.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f773c6d14dcc108a5b141b4456b0871df638eb411a89cd1c0c001fc4a9d08fc8", size = 12914558, upload-time = "2025-07-14T20:33:56.961Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/69/ac/070bad311171badc9add2910e7f89271695a25c136de24bbafc7eded56d5/mypy-1.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:1619a485fd0e9c959b943c7b519ed26b712de3002d7de43154a489a2d0fd817d", size = 9585447, upload-time = "2025-07-14T20:32:20.594Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/be/7b/5f8ab461369b9e62157072156935cec9d272196556bdc7c2ff5f4c7c0f9b/mypy-1.17.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2c41aa59211e49d717d92b3bb1238c06d387c9325d3122085113c79118bebb06", size = 11070019, upload-time = "2025-07-14T20:32:07.99Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9c/f8/c49c9e5a2ac0badcc54beb24e774d2499748302c9568f7f09e8730e953fa/mypy-1.17.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0e69db1fb65b3114f98c753e3930a00514f5b68794ba80590eb02090d54a5d4a", size = 10114457, upload-time = "2025-07-14T20:33:47.285Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/89/0c/fb3f9c939ad9beed3e328008b3fb90b20fda2cddc0f7e4c20dbefefc3b33/mypy-1.17.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:03ba330b76710f83d6ac500053f7727270b6b8553b0423348ffb3af6f2f7b889", size = 11857838, upload-time = "2025-07-14T20:33:14.462Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4c/66/85607ab5137d65e4f54d9797b77d5a038ef34f714929cf8ad30b03f628df/mypy-1.17.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:037bc0f0b124ce46bfde955c647f3e395c6174476a968c0f22c95a8d2f589bba", size = 12731358, upload-time = "2025-07-14T20:32:25.579Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/73/d0/341dbbfb35ce53d01f8f2969facbb66486cee9804048bf6c01b048127501/mypy-1.17.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c38876106cb6132259683632b287238858bd58de267d80defb6f418e9ee50658", size = 12917480, upload-time = "2025-07-14T20:34:21.868Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/64/63/70c8b7dbfc520089ac48d01367a97e8acd734f65bd07813081f508a8c94c/mypy-1.17.0-cp313-cp313-win_amd64.whl", hash = "sha256:d30ba01c0f151998f367506fab31c2ac4527e6a7b2690107c7a7f9e3cb419a9c", size = 9589666, upload-time = "2025-07-14T20:34:16.841Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e3/fc/ee058cc4316f219078464555873e99d170bde1d9569abd833300dbeb484a/mypy-1.17.0-py3-none-any.whl", hash = "sha256:15d9d0018237ab058e5de3d8fce61b6fa72cc59cc78fd91f1b474bce12abf496", size = 2283195, upload-time = "2025-07-14T20:31:54.753Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mypy-extensions"
|
||||
version = "1.1.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "myst-nb"
|
||||
version = "1.4.0"
|
||||
@@ -2890,7 +2849,6 @@ agno = [
|
||||
dev = [
|
||||
{ name = "jinja2" },
|
||||
{ name = "jupyter-book" },
|
||||
{ name = "mypy" },
|
||||
{ name = "poethepoet" },
|
||||
{ name = "pyasn1" },
|
||||
{ name = "pyinstrument" },
|
||||
@@ -2906,6 +2864,7 @@ dev = [
|
||||
{ name = "syrupy" },
|
||||
{ name = "toml-sort" },
|
||||
{ name = "tornado" },
|
||||
{ name = "ty" },
|
||||
{ name = "types-pyyaml" },
|
||||
{ name = "types-requests" },
|
||||
{ name = "wheel" },
|
||||
@@ -2931,7 +2890,6 @@ requires-dist = [
|
||||
{ name = "jupyter-book", marker = "extra == 'dev'", specifier = "==1.0.4.post1" },
|
||||
{ name = "lsprotocol", specifier = "==2025.0.0" },
|
||||
{ name = "mcp", specifier = "==1.27.0" },
|
||||
{ name = "mypy", marker = "extra == 'dev'", specifier = "==1.17.0" },
|
||||
{ name = "oslex", specifier = "==2.0.0" },
|
||||
{ name = "overrides", specifier = "==7.7.0" },
|
||||
{ name = "pathspec", specifier = "==0.12.1" },
|
||||
@@ -2967,6 +2925,7 @@ requires-dist = [
|
||||
{ name = "toml-sort", marker = "extra == 'dev'", specifier = "==0.24.2" },
|
||||
{ name = "tornado", marker = "extra == 'dev'", specifier = "==6.5.7" },
|
||||
{ name = "tqdm", specifier = "==4.67.1" },
|
||||
{ name = "ty", marker = "extra == 'dev'", specifier = "==0.0.24" },
|
||||
{ name = "types-pyyaml", specifier = "==6.0.12.20250516" },
|
||||
{ name = "types-pyyaml", marker = "extra == 'dev'", specifier = "==6.0.12.20250516" },
|
||||
{ name = "types-requests", marker = "extra == 'dev'", specifier = "==2.32.4.20250809" },
|
||||
@@ -3593,6 +3552,30 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359, upload-time = "2024-04-19T11:11:46.763Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ty"
|
||||
version = "0.0.24"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/7a/96/652a425030f95dc2c9548d9019e52502e17079e1daeefbc4036f1c0905b4/ty-0.0.24.tar.gz", hash = "sha256:9fe42f6b98207bdaef51f71487d6d087f2cb02555ee3939884d779b2b3cc8bfc", size = 5354286, upload-time = "2026-03-19T16:55:57.035Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/da/e5/34457ee11708e734ba81ad65723af83030e484f961e281d57d1eecf08951/ty-0.0.24-py3-none-linux_armv6l.whl", hash = "sha256:1ab4f1f61334d533a3fdf5d9772b51b1300ac5da4f3cdb0be9657a3ccb2ce3e7", size = 10394877, upload-time = "2026-03-19T16:55:54.246Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/44/81/bc9a1b1a87f43db15ab64ad781a4f999734ec3b470ad042624fa875b20e6/ty-0.0.24-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:facbf2c4aaa6985229e08f8f9bf152215eb078212f22b5c2411f35386688ab42", size = 10211109, upload-time = "2026-03-19T16:55:28.554Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e4/63/cfc805adeaa61d63ba3ea71127efa7d97c40ba36d97ee7bd957341d05107/ty-0.0.24-py3-none-macosx_11_0_arm64.whl", hash = "sha256:b6d2a3b6d4470c483552a31e9b368c86f154dcc964bccb5406159dc9cd362246", size = 9694769, upload-time = "2026-03-19T16:55:34.309Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/33/09/edc220726b6ec44a58900401f6b27140997ef15026b791e26b69a6e69eb5/ty-0.0.24-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0c94c25d0500939fd5f8f16ce41cbed5b20528702c1d649bf80300253813f0a2", size = 10176287, upload-time = "2026-03-19T16:55:37.17Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f8/bf/cbe2227be711e65017655d8ee4d050f4c92b113fb4dc4c3bd6a19d3a86d8/ty-0.0.24-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:89cbe7bc7df0fab02dbd8cda79b737df83f1ef7fb573b08c0ee043dc68cffb08", size = 10214832, upload-time = "2026-03-19T16:56:08.518Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/af/1d/d15803ee47e9143d10e10bd81ccc14761d08758082bda402950685f0ddfe/ty-0.0.24-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:db2c5d269bcc9b764850c99f457b5018a79b3ef40ecfbc03344e65effd6cf743", size = 10709892, upload-time = "2026-03-19T16:56:05.727Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/36/12/6db0d86c477147f67b9052de209421d76c3e855197b000c25fcbbe86b3a2/ty-0.0.24-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ba44512db5b97c3bbd59d93e11296e8548d0c9a3bdd1280de36d7ff22d351896", size = 11280872, upload-time = "2026-03-19T16:56:02.899Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1b/fc/155fe83a97c06d33ccc9e0f428258b32df2e08a428300c715d34757f0111/ty-0.0.24-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a52b7f589c3205512a9c50ba5b2b1e8c0698b72e51b8b9285c90420c06f1cae8", size = 11060520, upload-time = "2026-03-19T16:55:59.956Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ac/f1/32c05a1c4c3c2a95c5b7361dee03a9bf1231d4ad096b161c838b45bce5a0/ty-0.0.24-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7981df5c709c054da4ac5d7c93f8feb8f45e69e829e4461df4d5f0988fe67d04", size = 10791455, upload-time = "2026-03-19T16:55:25.728Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/17/2c/53c1ea6bedfa4d4ab64d4de262d8f5e405ecbffefd364459c628c0310d33/ty-0.0.24-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:b2860151ad95a00d0f0280b8fef79900d08dcd63276b57e6e5774f2c055979c5", size = 10156708, upload-time = "2026-03-19T16:55:45.563Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/45/39/7d2919cf194707169474d80720a5f3d793e983416f25e7ffcf80504c9df2/ty-0.0.24-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:5674a1146d927ab77ff198a88e0c4505134ced342a0e7d1beb4a076a728b7496", size = 10236263, upload-time = "2026-03-19T16:55:31.474Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/cf/7f/48eac722f2fd12a5b7aae0effdcb75c46053f94b783d989e3ef0d7380082/ty-0.0.24-py3-none-musllinux_1_2_i686.whl", hash = "sha256:438ecbf1608a9b16dd84502f3f1b23ef2ef32bbd0ab3e0ca5a82f0e0d1cd41ea", size = 10402559, upload-time = "2026-03-19T16:55:39.602Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/75/e0/8cf868b9749ce1e5166462759545964e95b02353243594062b927d8bff2a/ty-0.0.24-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:ddeed3098dd92a83964e7aa7b41e509ba3530eb539fc4cd8322ff64a09daf1f5", size = 10893684, upload-time = "2026-03-19T16:55:51.439Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/17/9f/f54bf3be01d2c2ed731d10a5afa3324dc66f987a6ae0a4a6cbfa2323d080/ty-0.0.24-py3-none-win32.whl", hash = "sha256:83013fb3a4764a8f8bcc6ca11ff8bdfd8c5f719fc249241cb2b8916e80778eb1", size = 9781542, upload-time = "2026-03-19T16:56:11.588Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fb/49/c004c5cc258b10b3a145666e9a9c28ae7678bc958c8926e8078d5d769081/ty-0.0.24-py3-none-win_amd64.whl", hash = "sha256:748a60eb6912d1cf27aaab105ffadb6f4d2e458a3fcadfbd3cf26db0d8062eeb", size = 10764801, upload-time = "2026-03-19T16:55:42.752Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e2/59/006a074e185bfccf5e4c026015245ab4fcd2362b13a8d24cf37a277909a9/ty-0.0.24-py3-none-win_arm64.whl", hash = "sha256:280a3d31e86d0721947238f17030c33f0911cae851d108ea9f4e3ab12a5ed01f", size = 10194093, upload-time = "2026-03-19T16:55:48.303Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typer"
|
||||
version = "0.24.1"
|
||||
|
||||
Reference in new issue
Block a user