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
26 changes: 16 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,14 @@ searchcode "import module" --languages java,javascript
#### In Code

```python
from pprint import pprint
from searchcode import Searchcode

sc = Searchcode(user_agent="My-Searchcode-script")
search = sc.search(query="import module", languages=["Java", "JavaScript"])

for result in search.get("results"):
print(result.language)
for result in search.results:
pprint(result.language)
```

___
Expand All @@ -113,13 +114,14 @@ searchcode "import module" --sources bitbucket,codeplex
#### In Code

```python
from pprint import pprint
from searchcode import Searchcode

sc = Searchcode(user_agent="My-Searchcode-script")
search = sc.search(query="import module", sources=["BitBucket", "CodePlex"])

for result in search.get("results"):
print(result.filename)
for result in search.results:
pprint(result.filename)
```

___
Expand All @@ -135,14 +137,14 @@ searchcode "import module" --lines-of-code-gt 500 --lines-of-code-lt 1000
#### In Code

```python

from pprint import pprint
from searchcode import Searchcode

sc = Searchcode(user_agent="My-Searchcode-script")
search = sc.search(query="import module", lines_of_code_gt=500, lines_of_code_lt=1000)

for result in search.get("results"):
print(result)
for result in search.results:
pprint(result)
```

___
Expand All @@ -158,11 +160,13 @@ searchcode "import module" --callback myCallback
#### In Code

```python
from pprint import pprint
from searchcode import Searchcode

sc = Searchcode(user_agent="My-Searchcode-script")
search = sc.search(query="import module", callback="myCallback")
print(search)

pprint(search)
```

`
Expand Down Expand Up @@ -221,8 +225,10 @@ searchode code 4061576
from searchcode import Searchcode

sc = Searchcode(user_agent="My-Searchcode-script")
code = sc.code(4061576)
print(code)
data = sc.code(4061576)

print(data.language)
print(data.code)
```

---
Expand Down
61 changes: 1 addition & 60 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "searchcode"
version = "0.4.4"
version = "0.5.0"
description = "Simple, comprehensive code search."
authors = ["Ritchie Mwewa <rly0nheart@duck.com>"]
license = "GPLv3+"
Expand All @@ -20,7 +20,6 @@ classifiers = [
python = "^3.10"
requests = "^2.32.2"
rich-click = "^1.8.8"
whats-that-code = "^0.2.0"

[tool.poetry.group.dev.dependencies]
flake8 = "^7.1.2"
Expand Down
2 changes: 1 addition & 1 deletion searchcode/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from .api import Searchcode

__pkg__ = "searchcode"
__version__ = "0.4.4"
__version__ = "0.5.0"
__author__ = "Ritchie Mwewa"


Expand Down
48 changes: 38 additions & 10 deletions searchcode/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,19 @@

import typing as t
from platform import python_version, platform
from types import SimpleNamespace

import requests

from .filters import CODE_LANGUAGES, CODE_SOURCES, get_language_ids, get_source_ids

BASE_API_ENDPOINT = "https://searchcode.com/api"

__all__ = ["Searchcode"]


class Searchcode:
def __init__(self, user_agent: str):
self.user_agent = user_agent
self.__base_api_endpoint: str = "https://searchcode.com/api"

def search(
self,
Expand All @@ -41,7 +41,7 @@ def search(
lines_of_code_gt: t.Optional[int] = None,
lines_of_code_lt: t.Optional[int] = None,
callback: t.Optional[str] = None,
) -> t.Union[t.Dict, str]:
) -> t.Union[SimpleNamespace, str]:
"""
Searches and returns code snippets matching the query.

Expand Down Expand Up @@ -80,7 +80,7 @@ def search(
source_ids = [] if not sources else get_source_ids(source_names=sources)

response = self.__send_request(
endpoint=f"{BASE_API_ENDPOINT}/{'jsonp_codesearch_I' if callback else 'codesearch_I'}/",
endpoint=f"{self.__base_api_endpoint}/{'jsonp_codesearch_I' if callback else 'codesearch_I'}/",
params=[
("q", query),
("p", page),
Expand All @@ -95,22 +95,25 @@ def search(
)

if not callback:
response["results"] = response.get("results", [])[:per_page]
response = self.__to_namespace_obj(response=response)
response.results = response.results[:per_page]

return response

def code(self, __id: int) -> str:
def code(self, __id: int) -> SimpleNamespace:
"""
Returns the raw data from a code file given the code ID which can be found as the `id` in a code search result.

:param __id: The unique identifier of the code result.
:type __id: int
:return: Raw code result data.
:rtype: str
:return: SimpleNamespace object containing code file data.
:rtype: SimpleNamespace
"""

response = self.__send_request(endpoint=f"{BASE_API_ENDPOINT}/result/{__id}")
return response.get("code")
response = self.__send_request(
endpoint=f"{self.__base_api_endpoint}/result/{__id}"
)
return self.__to_namespace_obj(response=response)

# This is deprecated (for now).
# def related(_id: int) -> Dict:
Expand Down Expand Up @@ -156,3 +159,28 @@ def __send_request(
)
response.raise_for_status()
return response.text if callback else response.json()

def __to_namespace_obj(
self,
response: t.Union[t.List[t.Dict], t.Dict],
) -> t.Union[t.List[SimpleNamespace], SimpleNamespace, t.List[t.Dict], t.Dict]:
"""
Recursively converts the API response into a SimpleNamespace object(s).

:param response: The object to convert, either a dictionary or a list of dictionaries.
:type response: Union[List[Dict], Dict]
:return: A SimpleNamespace object or list of SimpleNamespace objects.
:rtype: Union[List[SimpleNamespace], SimpleNamespace, None]
"""

if isinstance(response, t.Dict):
return SimpleNamespace(
**{
key: self.__to_namespace_obj(response=value)
for key, value in response.items()
}
)
elif isinstance(response, t.List):
return [self.__to_namespace_obj(response=item) for item in response]
else:
return response
43 changes: 20 additions & 23 deletions searchcode/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@
import os
import subprocess
import typing as t
from types import SimpleNamespace

import rich_click as click
from rich import box
from rich.console import Console
from rich.panel import Panel
from rich.pretty import pprint
from rich.syntax import Syntax
from whats_that_code.election import guess_language_all_methods

from . import License, __pkg__, __version__
from .api import Searchcode
Expand Down Expand Up @@ -136,11 +136,13 @@ def search(
__clear_screen()
__update_window_title(text=query)

with console.status(f"Querying code index with [green]{query}[/]"):
with console.status(
f"Querying code index with search string: [green]{query}[/]..."
):
languages = languages.split(",") if languages else None
sources = sources.split(",") if sources else None

results = sc.search(
response = sc.search(
query=query,
page=page,
per_page=per_page,
Expand All @@ -152,13 +154,9 @@ def search(
)

(
__print_jsonp(jsonp=results)
__print_jsonp(jsonp=response)
if callback
else (
pprint(results)
if pretty
else __print_panels(data=results.get("results"))
)
else (pprint(response) if pretty else __print_panels(data=response.results))
)


Expand All @@ -172,13 +170,13 @@ def code(id: int):
"""
__clear_screen()
__update_window_title(text=str(id))
with console.status(f"Retrieving code data for [cyan]{id}[/]") as status:
code_data = sc.code(id)
if code_data:
status.update("Determining code language")
language = guess_language_all_methods(code=code_data)
with console.status(f"Fetching data for code file with ID: [cyan]{id}[/]..."):
data = sc.code(id)
lines = data.code
language = data.language
if lines:
syntax = Syntax(
code=code_data, lexer=language, line_numbers=True, theme="dracula"
code=lines, lexer=language, line_numbers=True, theme="dracula"
)
console.print(syntax)

Expand All @@ -193,7 +191,7 @@ def __print_jsonp(jsonp: str) -> None:
console.print(syntax)


def __print_panels(data: t.List[t.Dict]):
def __print_panels(data: t.List[SimpleNamespace]):
"""
Render a list of code records as rich panels with syntax highlighting.
Line numbers are preserved and displayed alongside code content.
Expand All @@ -218,14 +216,13 @@ def extract_code_string_with_linenumbers(lines_dict: t.Dict[str, str]) -> str:
return "\n".join(numbered_lines)

for item in data:
filename = item.get("filename", "Unknown")
repo = item.get("repo", "Unknown")
language = item.get("language", "text")
lines_count = item.get("linescount", "??")
filename = item.filename
repo = item.repo
language = item.language
lines_count = item.linescount
lines = item.lines

code_string = extract_code_string_with_linenumbers(
lines_dict=item.get("lines", {})
)
code_string = extract_code_string_with_linenumbers(lines_dict=lines.__dict__)

syntax = Syntax(
code=code_string,
Expand Down
Loading