Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,5 @@ wheels/
*.egg
trieve
.aider*

.DS_Store
2 changes: 1 addition & 1 deletion lsproxy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
ReferencedSymbolsResponse,
)

__version__ = "0.2.0"
__version__ = "0.3.0"

__all__ = [
"Lsproxy",
Expand Down
20 changes: 14 additions & 6 deletions lsproxy/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@

from .models import (
DefinitionResponse,
FileRange,
ReadSourceCodeResponse,
ReadSourceCodeRequest,
ReferencesResponse,
GetDefinitionRequest,
GetReferencesRequest,
Expand Down Expand Up @@ -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()
Comment on lines 127 to 128
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Consider checking if the request.model_dump() returns a valid JSON object before passing it to the _request method to avoid potential runtime errors. [possible issue]

Suggested change
response = self._request(
"POST", "/workspace/read-source-code", json=request.model_dump()
json_data = request.model_dump()
if not isinstance(json_data, dict):
raise ValueError("Invalid JSON data")
response = self._request(
"POST", "/workspace/read-source-code", json=json_data
)

Expand All @@ -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.
Expand All @@ -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
Expand Down
3 changes: 1 addition & 2 deletions lsproxy/modal.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import time
import json
import hashlib
import subprocess

Expand Down Expand Up @@ -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")

Comment on lines +133 to 134
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Ensure that the self.sandbox.exec("lsproxy") command is checked for successful execution to handle any potential errors during the process. [possible issue]

Suggested change
self.sandbox.exec("lsproxy")
result = self.sandbox.exec("lsproxy")
if result.failed:
raise RuntimeError("Failed to start lsproxy")

def terminate(self):
self.sandbox.terminate()
45 changes: 27 additions & 18 deletions lsproxy/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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,
)
)

Expand All @@ -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(
Expand Down Expand Up @@ -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.",
Expand Down Expand Up @@ -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")
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -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"
Expand Down