Skip to content

Commit f1698fd

Browse files
committed
chore: use abstract classes instead of Protocol
1 parent 0b3cbb7 commit f1698fd

File tree

11 files changed

+104
-125
lines changed

11 files changed

+104
-125
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ Supported backends:
6868

6969
## Prerequisites
7070

71-
- **Python 3.10+**: Required for running the MCP servers
71+
- **Python 3.13+**: Required for running the MCP servers
7272
- **Search Backend**: Either a Sourcegraph instance or Zoekt server
7373
- **UV** (optional): Modern Python package manager for easier dependency management
7474
- **Langfuse** (optional): For observability and tracing

src/backends/__init__.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
"""Search backends for the MCP server."""
22

3-
from .content_fetcher_factory import ContentFetcherFactory
4-
from .content_fetcher_protocol import ContentFetcherProtocol
5-
from .search_factory import SearchClientFactory
6-
from .search_protocol import SearchClientProtocol
3+
from .content_fetcher import AbstractContentFetcher, ContentFetcherFactory
4+
from .search import AbstractSearchClient, SearchClientFactory
75

86
__all__ = [
97
"ContentFetcherFactory",
10-
"ContentFetcherProtocol",
8+
"AbstractContentFetcher",
119
"SearchClientFactory",
12-
"SearchClientProtocol",
10+
"AbstractSearchClient",
1311
]

src/backends/content_fetcher_factory.py renamed to src/backends/content_fetcher.py

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,37 @@
1-
from backends.content_fetcher_protocol import ContentFetcherProtocol
2-
from backends.sourcegraph.fetcher import SourcegraphContentFetcher
3-
from backends.zoekt.fetcher import ZoektContentFetcher
1+
from abc import ABC, abstractmethod
2+
3+
MAX_FILE_SIZE = 100_000
4+
5+
6+
class AbstractContentFetcher(ABC):
7+
"""
8+
Interface for content fetchers.
9+
"""
10+
11+
@abstractmethod
12+
def get_content(self, repository: str, path: str = "", depth: int = 2, ref: str = "HEAD") -> str:
13+
"""Get content from repository.
14+
15+
Args:
16+
repository: Repository path (e.g., "git.divar.cloud/divar/rpc/autogenerated/divar-interface-swift")
17+
path: File or directory path (e.g., "Sources/DivarInterfaceClient/divar_interface_sms_sms.grpc.swift")
18+
depth: Tree depth for directory listings
19+
ref: Git reference (branch, tag, or commit SHA)
20+
21+
Returns:
22+
File content if path is a file, directory tree if path is a directory
23+
24+
Raises:
25+
ValueError: If repository or path does not exist
26+
"""
27+
...
428

529

630
class ContentFetcherFactory:
731
"""Factory class for creating content fetcher instances based on configuration."""
832

933
@staticmethod
10-
def create_fetcher(backend: str, **kwargs) -> ContentFetcherProtocol:
34+
def create_fetcher(backend: str, **kwargs) -> AbstractContentFetcher:
1135
"""Create a content fetcher based on the specified backend.
1236
1337
Args:
@@ -28,7 +52,7 @@ def create_fetcher(backend: str, **kwargs) -> ContentFetcherProtocol:
2852
raise ValueError(f"Unsupported content fetcher backend: {backend}")
2953

3054
@staticmethod
31-
def _create_sourcegraph_fetcher(**kwargs) -> SourcegraphContentFetcher:
55+
def _create_sourcegraph_fetcher(**kwargs) -> "SourcegraphContentFetcher":
3256
"""Create and configure a Sourcegraph content fetcher.
3357
3458
Args:
@@ -40,6 +64,8 @@ def _create_sourcegraph_fetcher(**kwargs) -> SourcegraphContentFetcher:
4064
Raises:
4165
ValueError: If required configuration is missing
4266
"""
67+
from backends.sourcegraph.fetcher import SourcegraphContentFetcher
68+
4369
endpoint = kwargs.get("endpoint")
4470
token = kwargs.get("token", "")
4571

@@ -49,7 +75,7 @@ def _create_sourcegraph_fetcher(**kwargs) -> SourcegraphContentFetcher:
4975
return SourcegraphContentFetcher(endpoint=endpoint, token=token)
5076

5177
@staticmethod
52-
def _create_zoekt_fetcher(**kwargs) -> ZoektContentFetcher:
78+
def _create_zoekt_fetcher(**kwargs) -> "ZoektContentFetcher":
5379
"""Create and configure a Zoekt content fetcher.
5480
5581
Args:
@@ -58,6 +84,8 @@ def _create_zoekt_fetcher(**kwargs) -> ZoektContentFetcher:
5884
Returns:
5985
ZoektContentFetcher: Configured Zoekt content fetcher
6086
"""
87+
from backends.zoekt.fetcher import ZoektContentFetcher
88+
6189
zoekt_url = kwargs.get("zoekt_url")
6290

6391
if not zoekt_url:

src/backends/content_fetcher_protocol.py

Lines changed: 0 additions & 29 deletions
This file was deleted.

src/backends/search_factory.py renamed to src/backends/search.py

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,46 @@
1-
from backends.search_protocol import SearchClientProtocol
2-
from backends.sourcegraph import SourcegraphClient
3-
from backends.zoekt import Client as ZoektClient
1+
from abc import ABC, abstractmethod
2+
from typing import List
3+
4+
from backends.models import FormattedResult
5+
6+
7+
class AbstractSearchClient(ABC):
8+
"""
9+
Interface for search clients.
10+
"""
11+
12+
@abstractmethod
13+
def search(self, query: str, num: int) -> dict:
14+
"""Execute a search query and return raw results.
15+
16+
Args:
17+
query: The search query string
18+
num: Maximum number of results to return
19+
20+
Returns:
21+
Raw search results as a dictionary
22+
"""
23+
...
24+
25+
@abstractmethod
26+
def format_results(self, results: dict, num: int) -> List[FormattedResult]:
27+
"""Format raw search results into structured FormattedResult objects.
28+
29+
Args:
30+
results: Raw search results from the search method
31+
num: Maximum number of results to format
32+
33+
Returns:
34+
List of formatted results
35+
"""
36+
...
437

538

639
class SearchClientFactory:
740
"""Factory class for creating search client instances based on configuration."""
841

942
@staticmethod
10-
def create_client(backend: str, **kwargs) -> SearchClientProtocol:
43+
def create_client(backend: str, **kwargs) -> AbstractSearchClient:
1144
"""Create a search client based on the specified backend.
1245
1346
Args:
@@ -28,7 +61,7 @@ def create_client(backend: str, **kwargs) -> SearchClientProtocol:
2861
raise ValueError(f"Unsupported search backend: {backend}")
2962

3063
@staticmethod
31-
def _create_sourcegraph_client(**kwargs) -> SourcegraphClient:
64+
def _create_sourcegraph_client(**kwargs) -> "SourcegraphClient":
3265
"""Create and configure a Sourcegraph client.
3366
3467
Args:
@@ -40,6 +73,8 @@ def _create_sourcegraph_client(**kwargs) -> SourcegraphClient:
4073
Raises:
4174
ValueError: If required configuration is missing
4275
"""
76+
from backends.sourcegraph import SourcegraphClient
77+
4378
endpoint = kwargs.get("endpoint")
4479
token = kwargs.get("token", "")
4580

@@ -54,7 +89,7 @@ def _create_sourcegraph_client(**kwargs) -> SourcegraphClient:
5489
)
5590

5691
@staticmethod
57-
def _create_zoekt_client(**kwargs) -> ZoektClient:
92+
def _create_zoekt_client(**kwargs) -> "ZoektClient":
5893
"""Create and configure a Zoekt client.
5994
6095
Args:
@@ -63,6 +98,8 @@ def _create_zoekt_client(**kwargs) -> ZoektClient:
6398
Returns:
6499
ZoektClient: Configured Zoekt client
65100
"""
101+
from backends.zoekt import Client as ZoektClient
102+
66103
base_url = kwargs.get("base_url")
67104

68105
if not base_url:

src/backends/search_protocol.py

Lines changed: 0 additions & 36 deletions
This file was deleted.

src/backends/sourcegraph/client.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import requests
77

88
from backends.models import FormattedResult, Match
9-
from backends.search_protocol import SearchClientProtocol
9+
from backends.search import AbstractSearchClient
1010

1111
logger = logging.getLogger(__name__)
1212

@@ -68,9 +68,7 @@ def _parse_event(self, event_text: str) -> Dict[str, str]:
6868
return {}
6969

7070

71-
class SourcegraphClient(SearchClientProtocol):
72-
"""Sourcegraph search client implementing the SearchClientProtocol interface."""
73-
71+
class SourcegraphClient(AbstractSearchClient):
7472
def __init__(
7573
self,
7674
endpoint: str,

src/backends/sourcegraph/fetcher.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@
66

77
import requests
88

9-
from backends.content_fetcher_protocol import MAX_FILE_SIZE, ContentFetcherProtocol
9+
from backends.content_fetcher import MAX_FILE_SIZE, AbstractContentFetcher
1010

1111

12-
class SourcegraphContentFetcher(ContentFetcherProtocol):
12+
class SourcegraphContentFetcher(AbstractContentFetcher):
1313
"""Fetches content from Sourcegraph repositories."""
1414

1515
def __init__(self, endpoint: str, token: str = ""):

src/backends/zoekt/client.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
import requests
44

55
from backends.models import FormattedResult, Match
6-
from backends.search_protocol import SearchClientProtocol
6+
from backends.search import AbstractSearchClient
77

88

9-
class Client(SearchClientProtocol):
9+
class Client(AbstractSearchClient):
1010
def __init__(
1111
self,
1212
base_url: str,

src/backends/zoekt/fetcher.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55

66
import requests
77

8-
from backends.content_fetcher_protocol import MAX_FILE_SIZE, ContentFetcherProtocol
8+
from backends.content_fetcher import MAX_FILE_SIZE, AbstractContentFetcher
99

1010

11-
class ZoektContentFetcher(ContentFetcherProtocol):
11+
class ZoektContentFetcher(AbstractContentFetcher):
1212
def __init__(self, zoekt_url: str):
1313
self.zoekt_url = zoekt_url.rstrip("/")
1414

0 commit comments

Comments
 (0)