Skip to content

Commit

Permalink
Squashed commit of the following:
Browse files Browse the repository at this point in the history
commit c4b7ada05a63c92c94e17cd6383c90284a16b820
Author: bagel897 <[email protected]>
Date:   Wed Jan 10 11:16:51 2024 -0600

    reformat

commit eb8e5fb
Author: bagel897 <[email protected]>
Date:   Mon Nov 7 23:17:15 2022 -0600

    Clean docs, add async support

commit a07151a
Merge: 1f0556c 764bbe1
Author: Bagel <[email protected]>
Date:   Thu Nov 3 20:46:31 2022 -0500

    Merge branch 'master' into autoimport_docstring

commit 1f0556c
Author: bagel897 <[email protected]>
Date:   Thu Nov 3 01:52:32 2022 -0500

    Expose the modname

commit 3788d54
Author: bagel897 <[email protected]>
Date:   Thu Nov 3 00:52:52 2022 -0500

    initial docstring support
  • Loading branch information
bagel897 committed Jan 10, 2024
1 parent 95585e8 commit 6476478
Show file tree
Hide file tree
Showing 7 changed files with 134 additions and 22 deletions.
7 changes: 7 additions & 0 deletions rope/contrib/autoimport/defs.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class ModuleInfo(NamedTuple):
modname: str
underlined: bool
process_imports: bool
description: str


class ModuleFile(ModuleInfo):
Expand Down Expand Up @@ -100,19 +101,25 @@ class Name(NamedTuple):
package: str
source: Source
name_type: NameType
description: str
mod_desc: str


class PartialName(NamedTuple):
"""Partial information of a Name."""

name: str
name_type: NameType
description: str
mod_desc: str


class SearchResult(NamedTuple):
"""Search Result."""

import_statement: str
name: str
modname: str
source: int
itemkind: int
description: str
2 changes: 2 additions & 0 deletions rope/contrib/autoimport/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ class Name(Model):
"package": "TEXT",
"source": "INTEGER",
"type": "INTEGER",
"description": "TEXT",
"mod_desc": "TEXT",
}
columns = list(schema.keys())
objects = Query(table_name, columns)
Expand Down
42 changes: 38 additions & 4 deletions rope/contrib/autoimport/parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,24 +49,38 @@ def get_names_from_file(
except SyntaxError as error:
print(error)
return
mod_desc: str = ast.get_docstring(root_node) or ""
for node in ast.iter_child_nodes(root_node):
if isinstance(node, ast.Assign):
for target in node.targets:
try:
assert isinstance(target, ast.Name)
if underlined or not target.id.startswith("_"):
try:
doc = ast.get_docstring(node.value, clean=True)
except:
logger.debug(
"failed to get doc for %r, a value for %r",
node.value,
target.id,
)
doc = ""
yield PartialName(
target.id,
get_type_ast(node),
doc,
mod_desc,
)
except (AttributeError, AssertionError):
# TODO handle tuple assignment
pass
elif isinstance(node, (ast.FunctionDef, ast.ClassDef)):
elif isinstance(node, (ast.FunctionDef, ast.ClassDef, ast.AsyncFunctionDef)):
if underlined or not node.name.startswith("_"):
yield PartialName(
node.name,
get_type_ast(node),
ast.get_docstring(node, clean=True) or "",
mod_desc,
)
elif process_imports and isinstance(node, ast.ImportFrom):
# When we process imports, we want to include names in it's own package.
Expand All @@ -83,7 +97,12 @@ def get_names_from_file(
else:
real_name = name
if underlined or not real_name.startswith("_"):
yield PartialName(real_name, get_type_ast(node))
yield PartialName(
real_name,
get_type_ast(node),
"",
mod_desc,
)


def get_type_object(imported_object) -> NameType:
Expand Down Expand Up @@ -143,6 +162,7 @@ def get_names_from_compiled(
logger.error(f"{package} could not be imported for autoimport analysis")
return
else:
mod_desc: str = inspect.getdoc(module) or ""
for name, value in inspect.getmembers(module):
if underlined or not name.startswith("_"):
if (
Expand All @@ -151,10 +171,24 @@ def get_names_from_compiled(
or inspect.isbuiltin(value)
):
yield Name(
str(name), package, package, source, get_type_object(value)
str(name),
package,
package,
source,
get_type_object(value),
inspect.getdoc(value) or "",
mod_desc,
)


def combine(package: Package, module: ModuleFile, name: PartialName) -> Name:
"""Combine information to form a full name."""
return Name(name.name, module.modname, package.name, package.source, name.name_type)
return Name(
name.name,
module.modname,
package.name,
package.source,
name.name_type,
name.description,
name.mod_desc,
)
42 changes: 31 additions & 11 deletions rope/contrib/autoimport/sqlite.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,10 +234,8 @@ def search(self, name: str, exact_match: bool = False) -> List[Tuple[str, str]]:
Returns a sorted list of import statement, modname pairs
"""
results: List[Tuple[str, str, int]] = [
(statement, import_name, source)
for statement, import_name, source, type in self.search_full(
name, exact_match
)
(suggestion.import_statement, suggestion.name, suggestion.source)
for suggestion in self.search_full(name, exact_match)
]
return sort_and_deduplicate_tuple(results)

Expand Down Expand Up @@ -282,16 +280,26 @@ def _search_name(
"""
if not exact_match:
name = name + "%" # Makes the query a starts_with query
for import_name, module, source, name_type in self._execute(
models.Name.search_by_name_like.select("name", "module", "source", "type"),
for (
import_name,
module,
source,
name_type,
description,
) in self._execute(
models.Name.search_by_name_like.select(
"name", "module", "source", "type", "description"
),
(name,),
):
yield (
SearchResult(
f"from {module} import {import_name}",
import_name,
module,
source,
name_type,
description,
)
)

Expand All @@ -305,8 +313,9 @@ def _search_module(
"""
if not exact_match:
name = name + "%" # Makes the query a starts_with query
for module, source in self._execute(
models.Name.search_submodule_like.select("module", "source"), (name,)
for module, source, mod_desc in self._execute(
models.Name.search_submodule_like.select("module", "source", "mod_desc"),
(name,),
):
parts = module.split(".")
import_name = parts[-1]
Expand All @@ -318,17 +327,25 @@ def _search_module(
SearchResult(
f"from {remaining} import {import_name}",
import_name,
module,
source,
NameType.Module.value,
mod_desc,
)
)
for module, source in self._execute(
models.Name.search_module_like.select("module", "source"), (name,)
for module, source, mod_desc in self._execute(
models.Name.search_module_like.select("module", "source", "mod_desc"),
(name,),
):
if "." in module:
continue
yield SearchResult(
f"import {module}", module, source, NameType.Module.value
f"import {module}",
module,
module,
source,
NameType.Module.value,
mod_desc,
)

def get_modules(self, name) -> List[str]:
Expand Down Expand Up @@ -593,6 +610,8 @@ def _convert_name(name: Name) -> tuple:
name.package,
name.source.value,
name.name_type.value,
name.description,
name.mod_desc,
)

def _add_names(self, names: Iterable[Name]):
Expand Down Expand Up @@ -636,6 +655,7 @@ def _resource_to_module(
resource_modname,
underlined,
resource_path.name == "__init__.py",
"",
)

def _execute(self, query: models.FinalQuery, *args, **kwargs):
Expand Down
11 changes: 8 additions & 3 deletions rope/contrib/autoimport/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,11 @@ def get_files(
"""Find all files to parse in a given path using __init__.py."""
if package.type in (PackageType.COMPILED, PackageType.BUILTIN):
if package.source in (Source.STANDARD, Source.BUILTIN):
yield ModuleCompiled(None, package.name, underlined, True)
yield ModuleCompiled(None, package.name, underlined, True, "")
elif package.type == PackageType.SINGLE_FILE:
assert package.path
assert package.path.suffix == ".py"
yield ModuleFile(package.path, package.path.stem, underlined, False)
yield ModuleFile(package.path, package.path.stem, underlined, False, "")
else:
assert package.path
for file in package.path.glob("**/*.py"):
Expand All @@ -125,8 +125,13 @@ def get_files(
get_modname_from_path(file.parent, package.path),
underlined,
True,
"",
)
elif should_parse(file, underlined):
yield ModuleFile(
file, get_modname_from_path(file, package.path), underlined, False
file,
get_modname_from_path(file, package.path),
underlined,
False,
"",
)
50 changes: 47 additions & 3 deletions ropetest/contrib/autoimport/parsetest.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,61 @@
import os
import pathlib
import sys
import typing
from inspect import getdoc
from os import _exit
from sys import exit

from rope.contrib.autoimport import parse
from rope.contrib.autoimport.defs import Name, NameType, PartialName, Source


def test_typing_names(typing_path):
names = list(parse.get_names_from_file(typing_path))
assert PartialName("Text", NameType.Variable) in names
# No docs for typing, its docstrings are SUPER weird
assert PartialName("Text", NameType.Variable, "", getdoc(typing)) in names


def test_docstring():
names = list(
node
for node in parse.get_names_from_file(pathlib.Path(pathlib.__file__))
if node.name == "Path"
)
assert (
PartialName("Path", NameType.Class, getdoc(pathlib.Path), getdoc(pathlib) or "")
in names
)


def test_find_sys():
names = list(parse.get_names_from_compiled("sys", Source.BUILTIN))
assert Name("exit", "sys", "sys", Source.BUILTIN, NameType.Function) in names
print(names)
assert (
Name(
"exit",
"sys",
"sys",
Source.BUILTIN,
NameType.Function,
getdoc(exit),
getdoc(sys),
)
in names
)


def test_find_underlined():
names = list(parse.get_names_from_compiled("os", Source.BUILTIN, underlined=True))
assert Name("_exit", "os", "os", Source.BUILTIN, NameType.Function) in names
assert (
Name(
"_exit",
"os",
"os",
Source.BUILTIN,
NameType.Function,
getdoc(_exit),
getdoc(os),
)
in names
)
2 changes: 1 addition & 1 deletion ropetest/reprtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ def test_repr_findit_location(project, mod1):


def test_autoimport_models_query(project, mod1):
expected_repr = '''Query("names WHERE module LIKE (?)", columns=['name', 'module', 'package', 'source', 'type'])'''
expected_repr = '''Query("names WHERE module LIKE (?)", columns=['name', 'module', 'package', 'source', 'type', 'description', 'mod_desc'])'''
obj = models.Name.search_module_like
assert isinstance(obj, models.Query)
assert repr(obj) == expected_repr
Expand Down

0 comments on commit 6476478

Please sign in to comment.