From 088f630ac08bccb6e9dd0292085a620122b2c30b Mon Sep 17 00:00:00 2001 From: maks-ivanov Date: Mon, 10 Feb 2025 15:11:27 -0500 Subject: [PATCH] refactor: Update models and client to use new ReadSourceCodeRequest --- .gitignore | 2 ++ lsproxy/__init__.py | 2 +- lsproxy/client.py | 20 ++++++++++++++------ lsproxy/modal.py | 3 +-- lsproxy/models.py | 45 +++++++++++++++++++++++++++------------------ pyproject.toml | 2 +- 6 files changed, 46 insertions(+), 28 deletions(-) diff --git a/.gitignore b/.gitignore index 8da99af..e7c67b9 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,5 @@ wheels/ *.egg trieve .aider* + +.DS_Store diff --git a/lsproxy/__init__.py b/lsproxy/__init__.py index c109c7f..dd0baa7 100644 --- a/lsproxy/__init__.py +++ b/lsproxy/__init__.py @@ -14,7 +14,7 @@ ReferencedSymbolsResponse, ) -__version__ = "0.2.0" +__version__ = "0.3.0" __all__ = [ "Lsproxy", diff --git a/lsproxy/client.py b/lsproxy/client.py index cd900bd..d2622d3 100644 --- a/lsproxy/client.py +++ b/lsproxy/client.py @@ -6,8 +6,8 @@ from .models import ( DefinitionResponse, - FileRange, ReadSourceCodeResponse, + ReadSourceCodeRequest, ReferencesResponse, GetDefinitionRequest, GetReferencesRequest, @@ -111,11 +111,18 @@ def list_files(self) -> List[str]: files = response.json() return files - def read_source_code(self, request: FileRange) -> ReadSourceCodeResponse: - """Read source code from a specified file range.""" - if not isinstance(request, FileRange): + def read_source_code(self, request: ReadSourceCodeRequest) -> ReadSourceCodeResponse: + """Read source code from a specified file range. + + Args: + request: The request containing the file path and an optional range. + + Returns: + ReadSourceCodeResponse containing the source code. + """ + if not isinstance(request, ReadSourceCodeRequest): raise TypeError( - f"Expected FileRange, got {type(request).__name__}. Please use FileRange model to construct the request." + f"Expected ReadSourceCodeRequest, got {type(request).__name__}. Please use ReadSourceCodeRequest to construct the request." ) response = self._request( "POST", "/workspace/read-source-code", json=request.model_dump() @@ -129,7 +136,7 @@ def initialize_with_modal( git_token: Optional[str] = None, sha: Optional[str] = None, timeout: Optional[int] = None, - version: str = "0.3.5", + version: str = "0.4.0", ) -> "Lsproxy": """ Initialize lsproxy by starting a Modal sandbox with the server and connecting to it. @@ -140,6 +147,7 @@ def initialize_with_modal( git_token: Optional Git personal access token for private repositories sha: Optional commit to checkout in the repo timeout: Sandbox timeout in seconds (defaults to Modal's 5-minute timeout if None) + version: lsproxy version to use (defaults to "0.4.0") Returns: Configured Lsproxy client instance diff --git a/lsproxy/modal.py b/lsproxy/modal.py index 6a3ac8c..ffed913 100644 --- a/lsproxy/modal.py +++ b/lsproxy/modal.py @@ -1,5 +1,4 @@ import time -import json import hashlib import subprocess @@ -131,7 +130,7 @@ def __init__(self, repo_url: str, git_token: str, sha: str, timeout: int, versio self.tunnel_url = self.sandbox.tunnels()[4444].url # Start lsproxy - p = self.sandbox.exec(f"lsproxy") + self.sandbox.exec("lsproxy") def terminate(self): self.sandbox.terminate() diff --git a/lsproxy/models.py b/lsproxy/models.py index c266992..47d6b97 100644 --- a/lsproxy/models.py +++ b/lsproxy/models.py @@ -71,33 +71,40 @@ def __hash__(self) -> int: return hash((self.path, self.position.line, self.position.character)) +class Range(BaseModel): + start: Position = Field(..., description="Start position of the range.") + end: Position = Field(..., description="End position of the range.") + + def __hash__(self) -> int: + return hash((self.start.line, self.start.character, self.end.line, self.end.character)) + + class FileRange(BaseModel): """Range within a file, defined by start and end positions.""" path: str = Field(..., description="The path to the file.", example="src/main.py") - start: Position = Field(..., description="Start position of the range.") - end: Position = Field(..., description="End position of the range.") + range: Range = Field(..., description="The range within the file.") def contains(self, file_position: FilePosition) -> bool: """Check if a position is within the range.""" return ( self.path == file_position.path - and self.start <= file_position.position - and file_position.position <= self.end + and self.range.start <= file_position.position + and file_position.position <= self.range.end ) def __lt__(self, other: "FileRange") -> bool: """Compare ranges by path first, then start position.""" if self.path != other.path: return self.path < other.path - return self.start < other.start + return self.range.start < other.range.start def __eq__(self, other: "FileRange") -> bool: """Check if two ranges are equal.""" return ( self.path == other.path - and self.start == other.start - and self.end == other.end + and self.range.start == other.range.start + and self.range.end == other.range.end ) def __le__(self, other: "FileRange") -> bool: @@ -116,10 +123,10 @@ def __hash__(self) -> int: return hash( ( self.path, - self.start.line, - self.start.character, - self.end.line, - self.end.character, + self.range.start.line, + self.range.start.character, + self.range.end.line, + self.range.end.character, ) ) @@ -145,17 +152,17 @@ class Symbol(BaseModel): identifier_position: FilePosition = Field( ..., description="The start position of the symbol's identifier." ) - range: FileRange = Field(..., description="The full range of the symbol.") + file_range: FileRange = Field(..., description="The full range of the symbol.") def __hash__(self) -> int: - return hash((self.kind, self.name, self.identifier_position, self.range)) + return hash((self.kind, self.name, self.identifier_position, self.file_range)) class Identifier(BaseModel): """Representation of an identifier in code.""" name: str = Field(..., description="The name of the identifier.") - range: FileRange = Field( + file_range: FileRange = Field( ..., description="The range of the identifier in the file." ) kind: Optional[str] = Field( @@ -253,10 +260,6 @@ class GetReferencesRequest(BaseModel): description="Number of source code lines to include around each reference.", ge=0, ) - include_declaration: Optional[bool] = Field( - False, - description="Whether to include the declaration of the symbol in the references.", - ) include_raw_response: Optional[bool] = Field( False, description="Whether to include the raw response from the language server.", @@ -308,3 +311,9 @@ class ReadSourceCodeResponse(BaseModel): source_code: str = Field( ..., description="The source code for the specified range." ) + + +class ReadSourceCodeRequest(BaseModel): + """Request to read source code from a file with an optional range.""" + path: str = Field(..., description="Path to the file, relative to the workspace root") + range: Optional[Range] = Field(None, description="Optional range within the file to read") diff --git a/pyproject.toml b/pyproject.toml index b074882..92f223a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "lsproxy-sdk" -version = "0.2.5" +version = "0.3.0" description = "SDK for interacting with lsproxy container" readme = "README.md" requires-python = ">=3.10"