Skip to content

Commit 735a209

Browse files
committed
feat: show more informations in hint over a variables import
1 parent f784613 commit 735a209

File tree

2 files changed

+162
-62
lines changed

2 files changed

+162
-62
lines changed

Diff for: packages/language_server/src/robotcode/language_server/robotframework/diagnostics/imports_manager.py

+40-25
Original file line numberDiff line numberDiff line change
@@ -1103,7 +1103,8 @@ async def _get_libdoc(name: str, args: Tuple[Any, ...], working_dir: str, base_d
11031103
except BaseException as e:
11041104
self._logger.exception(e)
11051105

1106-
with ProcessPoolExecutor(max_workers=1, mp_context=mp.get_context("spawn")) as executor:
1106+
executor = ProcessPoolExecutor(max_workers=1, mp_context=mp.get_context("spawn"))
1107+
try:
11071108
result = await asyncio.wait_for(
11081109
asyncio.get_running_loop().run_in_executor(
11091110
executor,
@@ -1117,6 +1118,13 @@ async def _get_libdoc(name: str, args: Tuple[Any, ...], working_dir: str, base_d
11171118
),
11181119
LOAD_LIBRARY_TIME_OUT,
11191120
)
1121+
except (SystemExit, KeyboardInterrupt):
1122+
raise
1123+
except BaseException as e:
1124+
self._logger.exception(e)
1125+
raise
1126+
finally:
1127+
executor.shutdown(wait=True)
11201128

11211129
if result.stdout:
11221130
self._logger.warning(lambda: f"stdout captured at loading library {name}{args!r}:\n{result.stdout}")
@@ -1350,7 +1358,8 @@ async def _get_libdoc(name: str, args: Tuple[Any, ...], working_dir: str, base_d
13501358
except BaseException as e:
13511359
self._logger.exception(e)
13521360

1353-
with ProcessPoolExecutor(max_workers=1, mp_context=mp.get_context("spawn")) as executor:
1361+
executor = ProcessPoolExecutor(max_workers=1, mp_context=mp.get_context("spawn"))
1362+
try:
13541363
result = await asyncio.wait_for(
13551364
asyncio.get_running_loop().run_in_executor(
13561365
executor,
@@ -1364,32 +1373,38 @@ async def _get_libdoc(name: str, args: Tuple[Any, ...], working_dir: str, base_d
13641373
),
13651374
LOAD_LIBRARY_TIME_OUT,
13661375
)
1376+
except (SystemExit, KeyboardInterrupt):
1377+
raise
1378+
except BaseException as e:
1379+
self._logger.exception(e)
1380+
raise
1381+
finally:
1382+
executor.shutdown(True)
13671383

1368-
if result.stdout:
1369-
self._logger.warning(
1370-
lambda: f"stdout captured at loading variables {name}{args!r}:\n{result.stdout}"
1371-
)
1384+
if result.stdout:
1385+
self._logger.warning(lambda: f"stdout captured at loading variables {name}{args!r}:\n{result.stdout}")
13721386

1373-
try:
1374-
if meta is not None:
1375-
meta_file = Path(self.variables_doc_cache_path, meta.filepath_base.with_suffix(".meta.json"))
1376-
spec_file = Path(self.variables_doc_cache_path, meta.filepath_base.with_suffix(".spec.json"))
1377-
spec_file.parent.mkdir(parents=True, exist_ok=True)
1387+
try:
1388+
if meta is not None:
1389+
meta_file = Path(self.variables_doc_cache_path, meta.filepath_base.with_suffix(".meta.json"))
1390+
spec_file = Path(self.variables_doc_cache_path, meta.filepath_base.with_suffix(".spec.json"))
1391+
spec_file.parent.mkdir(parents=True, exist_ok=True)
13781392

1379-
try:
1380-
spec_file.write_text(as_json(result), "utf-8")
1381-
except (SystemExit, KeyboardInterrupt):
1382-
raise
1383-
except BaseException as e:
1384-
raise RuntimeError(f"Cannot write spec file for variables '{name}' to '{spec_file}'") from e
1385-
meta_file.write_text(as_json(meta), "utf-8")
1386-
else:
1387-
self._logger.debug(lambda: f"Skip caching variables {name}{args!r}")
1388-
except (SystemExit, KeyboardInterrupt):
1389-
raise
1390-
except BaseException as e:
1391-
self._logger.exception(e)
1392-
return result
1393+
try:
1394+
spec_file.write_text(as_json(result), "utf-8")
1395+
except (SystemExit, KeyboardInterrupt):
1396+
raise
1397+
except BaseException as e:
1398+
raise RuntimeError(f"Cannot write spec file for variables '{name}' to '{spec_file}'") from e
1399+
meta_file.write_text(as_json(meta), "utf-8")
1400+
else:
1401+
self._logger.debug(lambda: f"Skip caching variables {name}{args!r}")
1402+
except (SystemExit, KeyboardInterrupt):
1403+
raise
1404+
except BaseException as e:
1405+
self._logger.exception(e)
1406+
1407+
return result
13931408

13941409
resolved_args = resolve_args(
13951410
args,

Diff for: packages/language_server/src/robotcode/language_server/robotframework/diagnostics/library_doc.py

+122-37
Original file line numberDiff line numberDiff line change
@@ -851,13 +851,57 @@ def _create_toc(self, doc: str, only_doc: bool = True) -> str:
851851
return "\n".join(f"- [{entry}](#{entry.lower().replace(' ', '-')})" for entry in entries)
852852

853853

854+
def var_repr(value: Any) -> str:
855+
if value is None:
856+
return ""
857+
858+
if isinstance(value, NativeValue):
859+
value = value.value
860+
861+
if value is None:
862+
return "${None}"
863+
864+
if isinstance(value, (int, float, bool)):
865+
return f"${{{value!r}}}"
866+
867+
if isinstance(value, str) and value == "":
868+
return "${EMPTY}"
869+
870+
if isinstance(value, str) and value == "\\ \\":
871+
return "${SPACE}"
872+
873+
if isinstance(value, str):
874+
return value
875+
876+
return "${{ " + repr(value) + " }}"
877+
878+
854879
@dataclass
855880
class VariablesDoc(LibraryDoc):
856881
type: str = "VARIABLES"
857882
scope: str = "GLOBAL"
858883

859884
variables: List[ImportedVariableDefinition] = field(default_factory=list)
860885

886+
def to_markdown(self, add_signature: bool = True, only_doc: bool = True, header_level: int = 2) -> str:
887+
result = super().to_markdown(add_signature, only_doc, header_level)
888+
889+
if self.variables:
890+
result += "\n---\n\n"
891+
892+
result += "\n```robotframework"
893+
result += "\n*** Variables ***"
894+
895+
for var in self.variables:
896+
result += "\n" + var.name
897+
if var.has_value:
898+
result += " " + var_repr(var.value)
899+
else:
900+
result += " ..."
901+
result += "\n```"
902+
903+
return result
904+
861905

862906
def is_library_by_path(path: str) -> bool:
863907
return path.lower().endswith((".py", "/", os.sep))
@@ -1563,7 +1607,7 @@ def get_variables_doc(
15631607
) -> VariablesDoc:
15641608
from robot.libdocpkg.robotbuilder import KeywordDocBuilder
15651609
from robot.output import LOGGER
1566-
from robot.running.handlers import _PythonHandler
1610+
from robot.running.handlers import _PythonHandler, _PythonInitHandler
15671611
from robot.utils.importer import Importer
15681612
from robot.variables.filesetter import PythonImporter, YamlImporter
15691613

@@ -1575,6 +1619,8 @@ def get_variables_doc(
15751619
module_spec: Optional[ModuleSpec] = None
15761620
source: Optional[str] = None
15771621
try:
1622+
python_import = False
1623+
15781624
with _std_capture() as std_capturer:
15791625
import_name = find_variables(name, working_dir, base_dir, command_line_variables, variables)
15801626
get_variables = None
@@ -1586,6 +1632,8 @@ def get_variables_doc(
15861632
source = import_name
15871633
importer = JsonImporter()
15881634
else:
1635+
python_import = True
1636+
15891637
if not is_variables_by_path(import_name):
15901638
module_spec = get_module_spec(import_name)
15911639

@@ -1645,43 +1693,80 @@ def is_dynamic(self) -> bool:
16451693
python_path=sys.path,
16461694
)
16471695

1648-
if get_variables is not None:
1649-
1650-
class VarHandler(_PythonHandler):
1651-
def _get_name(self, handler_name: Any, handler_method: Any) -> Any:
1652-
return get_variables.__name__ if get_variables is not None else ""
1653-
1654-
def _get_initial_handler(self, library: Any, name: Any, method: Any) -> Any:
1655-
return None
1656-
1657-
vars_initializer = VarHandler(libdoc, get_variables.__name__, get_variables)
1658-
1659-
libdoc.inits = KeywordStore(
1660-
keywords=[
1661-
KeywordDoc(
1662-
name=libdoc.name,
1663-
args=[KeywordArgumentDoc.from_robot(a) for a in kw[0].args],
1664-
doc=kw[0].doc,
1665-
tags=list(kw[0].tags),
1666-
source=kw[0].source,
1667-
line_no=kw[0].lineno if kw[0].lineno is not None else -1,
1668-
col_offset=-1,
1669-
end_col_offset=-1,
1670-
end_line_no=-1,
1671-
type="library",
1672-
libname=libdoc.name,
1673-
libtype=libdoc.type,
1674-
longname=f"{libdoc.name}.{kw[0].name}",
1675-
is_initializer=True,
1676-
arguments=ArgumentSpec.from_robot_argument_spec(kw[1].arguments),
1677-
parent=libdoc.digest,
1678-
)
1679-
for kw in [
1680-
(KeywordDocBuilder().build_keyword(k), k)
1681-
for k in [KeywordWrapper(vars_initializer, libdoc.source or "")]
1696+
if python_import:
1697+
if get_variables is not None:
1698+
1699+
class VarHandler(_PythonHandler):
1700+
def _get_name(self, handler_name: Any, handler_method: Any) -> Any:
1701+
return get_variables.__name__ if get_variables is not None else ""
1702+
1703+
def _get_initial_handler(self, library: Any, name: Any, method: Any) -> Any:
1704+
return None
1705+
1706+
vars_initializer = VarHandler(libdoc, get_variables.__name__, get_variables)
1707+
1708+
libdoc.inits = KeywordStore(
1709+
keywords=[
1710+
KeywordDoc(
1711+
name=libdoc.name,
1712+
args=[KeywordArgumentDoc.from_robot(a) for a in kw[0].args],
1713+
doc=kw[0].doc,
1714+
source=kw[0].source,
1715+
line_no=kw[0].lineno if kw[0].lineno is not None else -1,
1716+
col_offset=-1,
1717+
end_col_offset=-1,
1718+
end_line_no=-1,
1719+
type="library",
1720+
libname=libdoc.name,
1721+
libtype=libdoc.type,
1722+
longname=f"{libdoc.name}.{kw[0].name}",
1723+
is_initializer=True,
1724+
arguments=ArgumentSpec.from_robot_argument_spec(kw[1].arguments),
1725+
parent=libdoc.digest,
1726+
)
1727+
for kw in [
1728+
(KeywordDocBuilder().build_keyword(k), k)
1729+
for k in [KeywordWrapper(vars_initializer, libdoc.source or "")]
1730+
]
16821731
]
1683-
]
1684-
)
1732+
)
1733+
else:
1734+
get_variables = getattr(libcode, "__init__", None) or getattr(libcode, "__init__", None)
1735+
1736+
class InitVarHandler(_PythonInitHandler):
1737+
def _get_name(self, handler_name: Any, handler_method: Any) -> Any:
1738+
return get_variables.__name__ if get_variables is not None else ""
1739+
1740+
def _get_initial_handler(self, library: Any, name: Any, method: Any) -> Any:
1741+
return None
1742+
1743+
if get_variables is not None:
1744+
vars_initializer = InitVarHandler(libdoc, get_variables.__name__, get_variables, None)
1745+
1746+
libdoc.inits = KeywordStore(
1747+
keywords=[
1748+
KeywordDoc(
1749+
name=libdoc.name,
1750+
args=[],
1751+
doc=kw[0].doc,
1752+
source=kw[0].source,
1753+
line_no=kw[0].lineno if kw[0].lineno is not None else -1,
1754+
col_offset=-1,
1755+
end_col_offset=-1,
1756+
end_line_no=-1,
1757+
type="library",
1758+
libname=libdoc.name,
1759+
libtype=libdoc.type,
1760+
longname=f"{libdoc.name}.{kw[0].name}",
1761+
is_initializer=True,
1762+
parent=libdoc.digest,
1763+
)
1764+
for kw in [
1765+
(KeywordDocBuilder().build_keyword(k), k)
1766+
for k in [KeywordWrapper(vars_initializer, libdoc.source or "")]
1767+
]
1768+
]
1769+
)
16851770

16861771
return libdoc
16871772
except (SystemExit, KeyboardInterrupt, IgnoreEasterEggLibraryWarning):

0 commit comments

Comments
 (0)