mirror of
https://github.com/pybricks/pybricks-api.git
synced 2026-09-11 17:14:41 +00:00
jedi: improve signature information
This fixes numerous issues where jedi provided incomplete or poorly formatted signatures and docstrings. Issue: https://github.com/pybricks/pybricks-code/issues/932
This commit is contained in:
@@ -2,6 +2,11 @@
|
||||
|
||||
<!-- refer to https://keepachangelog.com/en/1.0.0/ for guidance -->
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Fixed
|
||||
- Fixed more type hints and improved compatibility with jedi.
|
||||
|
||||
## 3.2.0b1-r2 - 2022-06-24
|
||||
|
||||
### Changed
|
||||
|
||||
Generated
+13
-1
@@ -60,6 +60,14 @@ category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
|
||||
[[package]]
|
||||
name = "docstring-parser"
|
||||
version = "0.14.1"
|
||||
description = "Parse Python docstrings in reST, Google and Numpydoc format"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6,<4.0"
|
||||
|
||||
[[package]]
|
||||
name = "flake8"
|
||||
version = "4.0.1"
|
||||
@@ -255,7 +263,7 @@ python-versions = ">=3.7"
|
||||
[metadata]
|
||||
lock-version = "1.1"
|
||||
python-versions = ">= 3.10, < 3.11"
|
||||
content-hash = "9b91afcb8ccd46cc8be150f48170e45e86a6c65686d7e6e97ac3de67988c0ff5"
|
||||
content-hash = "207f86e378bd5ea0d9751f27aa1b8eff5709ccce56851eeede184a4c343b8ac1"
|
||||
|
||||
[metadata.files]
|
||||
atomicwrites = [
|
||||
@@ -299,6 +307,10 @@ colorama = [
|
||||
{file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"},
|
||||
{file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"},
|
||||
]
|
||||
docstring-parser = [
|
||||
{file = "docstring_parser-0.14.1-py3-none-any.whl", hash = "sha256:14ac6ec1f1ba6905c4d8cb90fd0bc55394f5678183752c90e44812bf28d7a515"},
|
||||
{file = "docstring_parser-0.14.1.tar.gz", hash = "sha256:2c77522e31b7c88b1ab457a1f3c9ae38947ad719732260ba77ee8a3deb58622a"},
|
||||
]
|
||||
flake8 = [
|
||||
{file = "flake8-4.0.1-py2.py3-none-any.whl", hash = "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d"},
|
||||
{file = "flake8-4.0.1.tar.gz", hash = "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"},
|
||||
|
||||
@@ -10,6 +10,7 @@ python = ">= 3.10, < 3.11"
|
||||
pybricks = "^3.2.0b1-r2"
|
||||
jedi = "^0.18.1"
|
||||
typing-extensions = "^4.2.0"
|
||||
docstring-parser = "0.14.1"
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
pytest = "^7.1.2"
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
from enum import IntEnum
|
||||
import io
|
||||
import json
|
||||
from typing_extensions import TypedDict, NotRequired
|
||||
import re
|
||||
from enum import IntEnum
|
||||
|
||||
import docstring_parser
|
||||
import jedi
|
||||
from jedi.api.classes import Completion, Signature, ParamName
|
||||
from jedi.api.classes import BaseName, Completion, Name, ParamName, Signature
|
||||
from typing_extensions import NotRequired, TypedDict
|
||||
|
||||
# Packages included in Pybricks firmware that ships with Pybricks Code.
|
||||
PYBRICKS_CODE_PACKAGES = {
|
||||
@@ -132,6 +136,23 @@ class Command(TypedDict):
|
||||
arguments: NotRequired[list]
|
||||
|
||||
|
||||
class UriComponents(TypedDict):
|
||||
scheme: str
|
||||
authority: str
|
||||
path: str
|
||||
query: str
|
||||
fragment: str
|
||||
|
||||
|
||||
class IMarkdownString(TypedDict):
|
||||
value: str
|
||||
isTrusted: NotRequired[bool]
|
||||
supportThemeIcons: NotRequired[bool]
|
||||
supportHtml: NotRequired[bool]
|
||||
baseUri: NotRequired[UriComponents]
|
||||
uris: NotRequired[dict[str, UriComponents]]
|
||||
|
||||
|
||||
class CompletionItemKind(IntEnum):
|
||||
Method = 0
|
||||
Function = 1
|
||||
@@ -251,6 +272,66 @@ def _is_pybricks(c: Completion) -> bool:
|
||||
return True
|
||||
|
||||
|
||||
def _get_docstring(name: BaseName) -> str:
|
||||
"""
|
||||
Gets the docstring for a name.
|
||||
"""
|
||||
|
||||
docstring = name.docstring(raw=True)
|
||||
|
||||
# jedi does not appear to be smart enough to use __init__ docstring for class
|
||||
if name.type == "class" and isinstance(name, Name):
|
||||
n: Name
|
||||
for n in name.defined_names():
|
||||
if n.name == "__init__":
|
||||
docstring = "\n".join([docstring, _get_docstring(n)])
|
||||
|
||||
return docstring
|
||||
|
||||
|
||||
def _parse_docstring(text: str) -> tuple[IMarkdownString, list[IMarkdownString]]:
|
||||
"""
|
||||
Parses a doc string, removes the overload declarations, performs some
|
||||
fixups and extracts the individual parameter strings.
|
||||
|
||||
Args:
|
||||
The raw docstring.
|
||||
|
||||
Returns:
|
||||
A tuple with the fixed up doc string and a list of parameter doc strings.
|
||||
"""
|
||||
# docstring_parser does not support signatures at the beginning of the
|
||||
# docstring, so we have to remove them
|
||||
# https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html#confval-autodoc_docstring_signature
|
||||
|
||||
lines, end_of_signatures = [], False
|
||||
|
||||
for line in io.StringIO(text).readlines():
|
||||
# signatures look like: "name(params...)"
|
||||
if not end_of_signatures and re.match(r"^\w+\(.*\)", line):
|
||||
continue
|
||||
|
||||
end_of_signatures = True
|
||||
|
||||
# TODO: we may want to do some restructured text to markdown fixes,
|
||||
# e.g. strip off ":class:" from ":class:`SomeClass`" and replace
|
||||
# ".. some-directive::" with an appropriate header
|
||||
|
||||
lines.append(line)
|
||||
|
||||
text = "".join(lines)
|
||||
|
||||
doc = docstring_parser.parse(text, docstring_parser.DocstringStyle.GOOGLE)
|
||||
|
||||
# convert to numpy doc for better markdown rendering (section names are underlined)
|
||||
numpy_doc = docstring_parser.compose(doc, docstring_parser.Style.NUMPYDOC)
|
||||
|
||||
docstring = IMarkdownString(value=numpy_doc)
|
||||
param_docstrings = [IMarkdownString(value=p.description) for p in doc.params]
|
||||
|
||||
return docstring, param_docstrings
|
||||
|
||||
|
||||
def _map_completion_kind(type: str) -> CompletionItemKind:
|
||||
match type:
|
||||
case "module":
|
||||
@@ -294,22 +375,23 @@ def _map_completion_item(
|
||||
endLineNumber=line,
|
||||
endColumn=column,
|
||||
),
|
||||
documentation=completion.docstring(),
|
||||
documentation=_parse_docstring(_get_docstring(completion))[0],
|
||||
)
|
||||
|
||||
|
||||
def _map_parameter(param: ParamName) -> ParameterInformation:
|
||||
# NB: it is not possible to get docstring for individual parameters from jedi
|
||||
return ParameterInformation(label=param.to_string())
|
||||
def _map_parameter(param: ParamName, docstr: str) -> ParameterInformation:
|
||||
return ParameterInformation(label=param.to_string(), documentation=docstr)
|
||||
|
||||
|
||||
def _map_signature(signature: Signature) -> SignatureInformation:
|
||||
optional = {} if signature.index is None else dict(activeParameter=signature.index)
|
||||
|
||||
docstr, param_docstr = _parse_docstring(_get_docstring(signature))
|
||||
|
||||
return SignatureInformation(
|
||||
label=signature.to_string(),
|
||||
documentation=signature.docstring(),
|
||||
parameters=[_map_parameter(p) for p in signature.params],
|
||||
documentation=docstr,
|
||||
parameters=[_map_parameter(*p) for p in zip(signature.params, param_docstr)],
|
||||
**optional,
|
||||
)
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ Tests for correct code completion of the InventorHub class.
|
||||
|
||||
|
||||
import json
|
||||
from pybricks_jedi import SignatureHelp, complete, get_signatures, CompletionItem
|
||||
from pybricks_jedi import complete, CompletionItem
|
||||
|
||||
IMPORT = "from pybricks.hubs import InventorHub"
|
||||
CREATE_INSTANCE = "hub = InventorHub()"
|
||||
@@ -53,22 +53,6 @@ def test_hub_dot_battery_dot():
|
||||
]
|
||||
|
||||
|
||||
def test_hub_dot_battery_dot_current():
|
||||
line = "hub.battery.current("
|
||||
code = _create_snippet(line)
|
||||
signatures: SignatureHelp = json.loads(get_signatures(code, 3, len(line) + 1))
|
||||
assert [s["label"] for s in signatures["signatures"]] == ["current() -> int"]
|
||||
assert [s.get("activeParameter") for s in signatures["signatures"]] == [None]
|
||||
|
||||
|
||||
def test_hub_dot_battery_dot_voltage():
|
||||
line = "hub.battery.voltage("
|
||||
code = _create_snippet(line)
|
||||
signatures: SignatureHelp = json.loads(get_signatures(code, 3, len(line) + 1))
|
||||
assert [s["label"] for s in signatures["signatures"]] == ["voltage() -> int"]
|
||||
assert [s.get("activeParameter") for s in signatures["signatures"]] == [None]
|
||||
|
||||
|
||||
def test_hub_dot_buttons_dot():
|
||||
line = "hub.buttons."
|
||||
code = _create_snippet(line)
|
||||
@@ -78,16 +62,6 @@ def test_hub_dot_buttons_dot():
|
||||
]
|
||||
|
||||
|
||||
def test_hub_dot_battery_dot_pressed():
|
||||
line = "hub.buttons.pressed("
|
||||
code = _create_snippet(line)
|
||||
signatures: SignatureHelp = json.loads(get_signatures(code, 3, len(line) + 1))
|
||||
assert [s["label"] for s in signatures["signatures"]] == [
|
||||
"pressed() -> Tuple[Button]"
|
||||
]
|
||||
assert [s.get("activeParameter") for s in signatures["signatures"]] == [None]
|
||||
|
||||
|
||||
def test_hub_dot_charger_dot():
|
||||
line = "hub.charger."
|
||||
code = _create_snippet(line)
|
||||
@@ -99,22 +73,6 @@ def test_hub_dot_charger_dot():
|
||||
]
|
||||
|
||||
|
||||
def test_hub_dot_charger_dot_connected():
|
||||
line = "hub.charger.connected("
|
||||
code = _create_snippet(line)
|
||||
signatures: SignatureHelp = json.loads(get_signatures(code, 3, len(line) + 1))
|
||||
assert [s["label"] for s in signatures["signatures"]] == ["connected() -> bool"]
|
||||
assert [s.get("activeParameter") for s in signatures["signatures"]] == [None]
|
||||
|
||||
|
||||
def test_hub_dot_charger_dot_current():
|
||||
line = "hub.charger.current("
|
||||
code = _create_snippet(line)
|
||||
signatures: SignatureHelp = json.loads(get_signatures(code, 3, len(line) + 1))
|
||||
assert [s["label"] for s in signatures["signatures"]] == ["current() -> int"]
|
||||
assert [s.get("activeParameter") for s in signatures["signatures"]] == [None]
|
||||
|
||||
|
||||
def test_hub_dot_display_dot():
|
||||
line = "hub.display."
|
||||
code = _create_snippet(line)
|
||||
@@ -157,62 +115,6 @@ def test_hub_dot_light_dot():
|
||||
]
|
||||
|
||||
|
||||
def test_hub_dot_light_dot_animate():
|
||||
line = "hub.light.animate("
|
||||
code = _create_snippet(line)
|
||||
signatures: SignatureHelp = json.loads(get_signatures(code, 3, len(line) + 1))
|
||||
assert [s["label"] for s in signatures["signatures"]] == [
|
||||
"animate(colors: Collection[Color], interval: Number) -> None",
|
||||
]
|
||||
assert [s.get("activeParameter") for s in signatures["signatures"]] == [0]
|
||||
assert [
|
||||
[p["label"] for p in s["parameters"]] for s in signatures["signatures"]
|
||||
] == [["colors: Collection[Color]", "interval: Number"]]
|
||||
|
||||
|
||||
def test_hub_dot_light_dot_animate2():
|
||||
line = "hub.light.animate([],"
|
||||
code = _create_snippet(line)
|
||||
signatures: SignatureHelp = json.loads(get_signatures(code, 3, len(line) + 1))
|
||||
assert [s["label"] for s in signatures["signatures"]] == [
|
||||
"animate(colors: Collection[Color], interval: Number) -> None",
|
||||
]
|
||||
assert [s.get("activeParameter") for s in signatures["signatures"]] == [1]
|
||||
assert [
|
||||
[p["label"] for p in s["parameters"]] for s in signatures["signatures"]
|
||||
] == [["colors: Collection[Color]", "interval: Number"]]
|
||||
|
||||
|
||||
def test_hub_dot_light_dot_blink():
|
||||
line = "hub.light.blink("
|
||||
code = _create_snippet(line)
|
||||
signatures: SignatureHelp = json.loads(get_signatures(code, 3, len(line) + 1))
|
||||
assert [s["label"] for s in signatures["signatures"]] == [
|
||||
"blink(color: Color, durations: Collection[int]) -> None",
|
||||
]
|
||||
assert [s.get("activeParameter") for s in signatures["signatures"]] == [0]
|
||||
|
||||
|
||||
def test_hub_dot_light_dot_blink2():
|
||||
line = "hub.light.blink(Color.RED,"
|
||||
code = _create_snippet(line)
|
||||
signatures: SignatureHelp = json.loads(get_signatures(code, 3, len(line) + 1))
|
||||
assert [s["label"] for s in signatures["signatures"]] == [
|
||||
"blink(color: Color, durations: Collection[int]) -> None",
|
||||
]
|
||||
assert [s.get("activeParameter") for s in signatures["signatures"]] == [1]
|
||||
|
||||
|
||||
def test_hub_dot_light_dot_on():
|
||||
line = "hub.light.on("
|
||||
code = _create_snippet(line)
|
||||
signatures: SignatureHelp = json.loads(get_signatures(code, 3, len(line) + 1))
|
||||
assert [s["label"] for s in signatures["signatures"]] == [
|
||||
"on(color: Color) -> None",
|
||||
]
|
||||
assert [s.get("activeParameter") for s in signatures["signatures"]] == [0]
|
||||
|
||||
|
||||
def test_hub_dot_speaker_dot():
|
||||
line = "hub.speaker."
|
||||
code = _create_snippet(line)
|
||||
@@ -224,57 +126,6 @@ def test_hub_dot_speaker_dot():
|
||||
]
|
||||
|
||||
|
||||
def test_hub_dot_speaker_dot_beep():
|
||||
line = "hub.speaker.beep("
|
||||
code = _create_snippet(line)
|
||||
signatures: SignatureHelp = json.loads(get_signatures(code, 3, len(line) + 1))
|
||||
assert [s["label"] for s in signatures["signatures"]] == [
|
||||
"beep(frequency: Number=500, duration: Number=100) -> None",
|
||||
]
|
||||
assert [s.get("activeParameter") for s in signatures["signatures"]] == [0]
|
||||
|
||||
|
||||
def test_hub_dot_speaker_dot_beep2():
|
||||
line = "hub.speaker.beep(100,"
|
||||
code = _create_snippet(line)
|
||||
signatures: SignatureHelp = json.loads(get_signatures(code, 3, len(line) + 1))
|
||||
assert [s["label"] for s in signatures["signatures"]] == [
|
||||
"beep(frequency: Number=500, duration: Number=100) -> None",
|
||||
]
|
||||
assert [s.get("activeParameter") for s in signatures["signatures"]] == [1]
|
||||
|
||||
|
||||
def test_hub_dot_speaker_dot_play_notes():
|
||||
line = "hub.speaker.play_notes("
|
||||
code = _create_snippet(line)
|
||||
signatures: SignatureHelp = json.loads(get_signatures(code, 3, len(line) + 1))
|
||||
assert [s["label"] for s in signatures["signatures"]] == [
|
||||
"play_notes(notes: Iterable[str], tempo: Number=120) -> None",
|
||||
]
|
||||
assert [s.get("activeParameter") for s in signatures["signatures"]] == [0]
|
||||
|
||||
|
||||
def test_hub_dot_speaker_dot_play_notes2():
|
||||
line = "hub.speaker.play_notes([],"
|
||||
code = _create_snippet(line)
|
||||
signatures: SignatureHelp = json.loads(get_signatures(code, 3, len(line) + 1))
|
||||
assert [s["label"] for s in signatures["signatures"]] == [
|
||||
"play_notes(notes: Iterable[str], tempo: Number=120) -> None",
|
||||
]
|
||||
assert [s.get("activeParameter") for s in signatures["signatures"]] == [1]
|
||||
|
||||
|
||||
def test_hub_dot_speaker_dot_volume():
|
||||
line = "hub.speaker.volume("
|
||||
code = _create_snippet(line)
|
||||
signatures: SignatureHelp = json.loads(get_signatures(code, 3, len(line) + 1))
|
||||
assert [s["label"] for s in signatures["signatures"]] == [
|
||||
"volume() -> int",
|
||||
"volume(volume: Number) -> None",
|
||||
]
|
||||
assert [s.get("activeParameter") for s in signatures["signatures"]] == [None, 0]
|
||||
|
||||
|
||||
def test_hub_dot_system_dot():
|
||||
line = "hub.system."
|
||||
code = _create_snippet(line)
|
||||
@@ -285,43 +136,3 @@ def test_hub_dot_system_dot():
|
||||
"set_stop_button",
|
||||
"shutdown",
|
||||
]
|
||||
|
||||
|
||||
def test_hub_dot_system_dot_name():
|
||||
line = "hub.system.name("
|
||||
code = _create_snippet(line)
|
||||
signatures: SignatureHelp = json.loads(get_signatures(code, 3, len(line) + 1))
|
||||
assert [s["label"] for s in signatures["signatures"]] == [
|
||||
"name() -> str",
|
||||
]
|
||||
assert [s.get("activeParameter") for s in signatures["signatures"]] == [None]
|
||||
|
||||
|
||||
def test_hub_dot_system_dot_reset_reason():
|
||||
line = "hub.system.reset_reason("
|
||||
code = _create_snippet(line)
|
||||
signatures: SignatureHelp = json.loads(get_signatures(code, 3, len(line) + 1))
|
||||
assert [s["label"] for s in signatures["signatures"]] == [
|
||||
"reset_reason() -> int",
|
||||
]
|
||||
assert [s.get("activeParameter") for s in signatures["signatures"]] == [None]
|
||||
|
||||
|
||||
def test_hub_dot_system_dot_set_stop_button():
|
||||
line = "hub.system.set_stop_button("
|
||||
code = _create_snippet(line)
|
||||
signatures: SignatureHelp = json.loads(get_signatures(code, 3, len(line) + 1))
|
||||
assert [s["label"] for s in signatures["signatures"]] == [
|
||||
"set_stop_button(button: Optional[Union[Button, Iterable[Button]]]) -> None",
|
||||
]
|
||||
assert [s.get("activeParameter") for s in signatures["signatures"]] == [0]
|
||||
|
||||
|
||||
def test_hub_dot_system_dot_shutdown():
|
||||
line = "hub.system.shutdown("
|
||||
code = _create_snippet(line)
|
||||
signatures: SignatureHelp = json.loads(get_signatures(code, 3, len(line) + 1))
|
||||
assert [s["label"] for s in signatures["signatures"]] == [
|
||||
"shutdown() -> None",
|
||||
]
|
||||
assert [s.get("activeParameter") for s in signatures["signatures"]] == [None]
|
||||
|
||||
@@ -0,0 +1,779 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
# Copyright (c) 2022 The Pybricks Authors
|
||||
|
||||
"""
|
||||
Tests for correct signatures of the pupdevices.Motor class.
|
||||
"""
|
||||
|
||||
|
||||
from itertools import zip_longest
|
||||
import json
|
||||
|
||||
import pytest
|
||||
from pybricks_jedi import SignatureHelp, get_signatures
|
||||
|
||||
|
||||
def _get_function_signature(module: str, function: str) -> SignatureHelp:
|
||||
"""
|
||||
Gets the signature help object for code like::
|
||||
|
||||
from {module} import {function}
|
||||
{function}(
|
||||
|
||||
Args:
|
||||
module: the module name
|
||||
func: the function name (a function in the module)
|
||||
"""
|
||||
code = f"from {module} import {function}; {function}("
|
||||
return json.loads(get_signatures(code, 1, len(code) + 1))
|
||||
|
||||
|
||||
FUNCTION_PARAMS = [
|
||||
pytest.param("pybricks.tools", "wait", [(["time: Number"], "None")]),
|
||||
pytest.param(
|
||||
"pybricks.geometry",
|
||||
"vector",
|
||||
[
|
||||
(["x: float", "y: float"], "Matrix"),
|
||||
(["x: float", "y: float", "z: float"], "Matrix"),
|
||||
],
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("module,function,signatures", FUNCTION_PARAMS)
|
||||
def test_get_signature_for_functions(
|
||||
module: str, function: str, signatures: list[tuple[list[str], str]]
|
||||
):
|
||||
help = _get_function_signature(module, function)
|
||||
|
||||
assert help["activeSignature"] == 0
|
||||
assert help["activeParameter"] == 0
|
||||
assert help["signatures"]
|
||||
|
||||
for sig, (params, returns) in zip_longest(help["signatures"], signatures):
|
||||
assert sig["label"] == f"{function}({', '.join(params)}) -> {returns}"
|
||||
assert sig["documentation"]["value"]
|
||||
# ensure signatures are stripped from doc comment
|
||||
assert not sig["documentation"]["value"].startswith(f"{function}(")
|
||||
|
||||
for pi, p in zip_longest(sig["parameters"], params):
|
||||
assert pi["label"] == p
|
||||
assert pi["documentation"]["value"]
|
||||
|
||||
|
||||
def _get_constructor_signature(module: str, type: str) -> SignatureHelp:
|
||||
"""
|
||||
Gets the signature help object for code like::
|
||||
|
||||
from {module} import {type}
|
||||
instance = {type}(
|
||||
|
||||
Args:
|
||||
module: the module name
|
||||
type: the type name (a type in the module)
|
||||
"""
|
||||
code = f"from {module} import {type}; {type}("
|
||||
return json.loads(get_signatures(code, 1, len(code) + 1))
|
||||
|
||||
|
||||
CONSTRUCTOR_PARAMS = [
|
||||
pytest.param("pybricks.hubs", "MoveHub", [[]]),
|
||||
pytest.param("pybricks.hubs", "CityHub", [[]]),
|
||||
pytest.param(
|
||||
"pybricks.hubs",
|
||||
"TechnicHub",
|
||||
[["top_side: Axis=Axis.Z", "front_side: Axis=Axis.X"]],
|
||||
),
|
||||
pytest.param(
|
||||
"pybricks.hubs",
|
||||
"PrimeHub",
|
||||
[["top_side: Axis=Axis.Z", "front_side: Axis=Axis.X"]],
|
||||
),
|
||||
pytest.param(
|
||||
"pybricks.pupdevices",
|
||||
"DCMotor",
|
||||
[["port: Port", "positive_direction: Direction=Direction.CLOCKWISE"]],
|
||||
),
|
||||
pytest.param(
|
||||
"pybricks.pupdevices",
|
||||
"Motor",
|
||||
[
|
||||
[
|
||||
"port: Port",
|
||||
"positive_direction: Direction=Direction.CLOCKWISE",
|
||||
"gears: Optional[Union[Collection[int], Collection[Collection[int]]]]=None",
|
||||
"reset_angle: bool=True",
|
||||
]
|
||||
],
|
||||
),
|
||||
pytest.param("pybricks.pupdevices", "TiltSensor", [["port: Port"]]),
|
||||
pytest.param("pybricks.pupdevices", "InfraredSensor", [["port: Port"]]),
|
||||
pytest.param("pybricks.pupdevices", "ColorDistanceSensor", [["port: Port"]]),
|
||||
pytest.param(
|
||||
"pybricks.pupdevices",
|
||||
"PFMotor",
|
||||
[
|
||||
[
|
||||
"sensor: ColorDistanceSensor",
|
||||
"channel: int",
|
||||
"color: Color",
|
||||
"positive_direction: Direction=Direction.CLOCKWISE",
|
||||
]
|
||||
],
|
||||
),
|
||||
pytest.param("pybricks.pupdevices", "ColorSensor", [["port: Port"]]),
|
||||
pytest.param("pybricks.pupdevices", "UltrasonicSensor", [["port: Port"]]),
|
||||
pytest.param("pybricks.pupdevices", "ForceSensor", [["port: Port"]]),
|
||||
pytest.param("pybricks.pupdevices", "ColorLightMatrix", [["port: Port"]]),
|
||||
pytest.param("pybricks.pupdevices", "Light", [["port: Port"]]),
|
||||
pytest.param(
|
||||
"pybricks.pupdevices",
|
||||
"Remote",
|
||||
[["name: Optional[str]=None", "timeout: int=10000"]],
|
||||
),
|
||||
# TODO: iodevices go here
|
||||
pytest.param(
|
||||
"pybricks.parameters",
|
||||
"Color",
|
||||
[["h: Number", "s: Number=100", "v: Number=100"]],
|
||||
),
|
||||
pytest.param(
|
||||
"pybricks.robotics",
|
||||
"DriveBase",
|
||||
[
|
||||
[
|
||||
"left_motor: Motor",
|
||||
"right_motor: Motor",
|
||||
"wheel_diameter: Number",
|
||||
"axle_track: Number",
|
||||
]
|
||||
],
|
||||
),
|
||||
pytest.param(
|
||||
"pybricks.geometry",
|
||||
"Matrix",
|
||||
[["rows: Sequence[Sequence[float]]"]],
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("module,type,signatures", CONSTRUCTOR_PARAMS)
|
||||
def test_get_signature_for_constructors(
|
||||
module: str, type: str, signatures: list[list[str]]
|
||||
):
|
||||
help = _get_constructor_signature(module, type)
|
||||
|
||||
assert help["activeSignature"] == 0
|
||||
assert help["activeParameter"] == 0
|
||||
assert help["signatures"]
|
||||
|
||||
for sig, params in zip_longest(help["signatures"], signatures):
|
||||
assert sig["label"] == f"{type}({', '.join(params)})"
|
||||
assert sig["documentation"]["value"]
|
||||
# ensure signatures are stripped from doc comment
|
||||
assert not sig["documentation"]["value"].startswith(f"{type}(")
|
||||
|
||||
for pi, p in zip_longest(sig["parameters"], params):
|
||||
assert pi["label"] == p
|
||||
assert pi["documentation"]["value"]
|
||||
|
||||
|
||||
def _get_method_signature(module: str, type: str, method: str) -> SignatureHelp:
|
||||
"""
|
||||
Gets the signature help object for code like::
|
||||
|
||||
from {module} import {type}
|
||||
instance = {type}()
|
||||
instance.{method}(
|
||||
|
||||
Args:
|
||||
module: the module name
|
||||
type: the type name (a type in the module)
|
||||
method: the method name (a method of the type)
|
||||
"""
|
||||
code = f"from {module} import {type}; x = {type}(); x.{method}("
|
||||
return json.loads(get_signatures(code, 1, len(code) + 1))
|
||||
|
||||
|
||||
METHOD_PARAMS = [
|
||||
pytest.param("pybricks.hubs", "MoveHub", "light.on", [(["color: Color"], "None")]),
|
||||
pytest.param("pybricks.hubs", "MoveHub", "light.off", [([], "None")]),
|
||||
pytest.param(
|
||||
"pybricks.hubs",
|
||||
"MoveHub",
|
||||
"light.blink",
|
||||
[(["color: Color", "durations: Collection[Number]"], "None")],
|
||||
),
|
||||
pytest.param(
|
||||
"pybricks.hubs",
|
||||
"MoveHub",
|
||||
"light.animate",
|
||||
[(["colors: Collection[Color]", "interval: Number"], "None")],
|
||||
),
|
||||
pytest.param("pybricks.hubs", "MoveHub", "imu.up", [([], "Side")]),
|
||||
pytest.param(
|
||||
"pybricks.hubs", "MoveHub", "imu.acceleration", [([], "Tuple[int, int, int]")]
|
||||
),
|
||||
pytest.param("pybricks.hubs", "MoveHub", "battery.voltage", [([], "int")]),
|
||||
pytest.param("pybricks.hubs", "MoveHub", "battery.current", [([], "int")]),
|
||||
pytest.param(
|
||||
"pybricks.hubs", "MoveHub", "button.pressed", [([], "Collection[Button]")]
|
||||
),
|
||||
pytest.param(
|
||||
"pybricks.hubs",
|
||||
"MoveHub",
|
||||
"system.set_stop_button",
|
||||
[(["button: Optional[Union[Button, Iterable[Button]]]"], "None")],
|
||||
),
|
||||
pytest.param("pybricks.hubs", "MoveHub", "system.name", [([], "str")]),
|
||||
pytest.param("pybricks.hubs", "MoveHub", "system.shutdown", [([], "None")]),
|
||||
pytest.param("pybricks.hubs", "MoveHub", "system.reset_reason", [([], "int")]),
|
||||
pytest.param("pybricks.hubs", "CityHub", "light.on", [(["color: Color"], "None")]),
|
||||
pytest.param("pybricks.hubs", "CityHub", "light.off", [([], "None")]),
|
||||
pytest.param(
|
||||
"pybricks.hubs",
|
||||
"CityHub",
|
||||
"light.blink",
|
||||
[(["color: Color", "durations: Collection[Number]"], "None")],
|
||||
),
|
||||
pytest.param(
|
||||
"pybricks.hubs",
|
||||
"CityHub",
|
||||
"light.animate",
|
||||
[(["colors: Collection[Color]", "interval: Number"], "None")],
|
||||
),
|
||||
pytest.param("pybricks.hubs", "CityHub", "battery.voltage", [([], "int")]),
|
||||
pytest.param("pybricks.hubs", "CityHub", "battery.current", [([], "int")]),
|
||||
pytest.param(
|
||||
"pybricks.hubs", "CityHub", "button.pressed", [([], "Collection[Button]")]
|
||||
),
|
||||
pytest.param(
|
||||
"pybricks.hubs",
|
||||
"CityHub",
|
||||
"system.set_stop_button",
|
||||
[(["button: Optional[Union[Button, Iterable[Button]]]"], "None")],
|
||||
),
|
||||
pytest.param("pybricks.hubs", "CityHub", "system.name", [([], "str")]),
|
||||
pytest.param("pybricks.hubs", "CityHub", "system.shutdown", [([], "None")]),
|
||||
pytest.param("pybricks.hubs", "CityHub", "system.reset_reason", [([], "int")]),
|
||||
pytest.param(
|
||||
"pybricks.hubs", "TechnicHub", "light.on", [(["color: Color"], "None")]
|
||||
),
|
||||
pytest.param("pybricks.hubs", "TechnicHub", "light.off", [([], "None")]),
|
||||
pytest.param(
|
||||
"pybricks.hubs",
|
||||
"TechnicHub",
|
||||
"light.blink",
|
||||
[(["color: Color", "durations: Collection[Number]"], "None")],
|
||||
),
|
||||
pytest.param(
|
||||
"pybricks.hubs",
|
||||
"TechnicHub",
|
||||
"light.animate",
|
||||
[(["colors: Collection[Color]", "interval: Number"], "None")],
|
||||
),
|
||||
pytest.param("pybricks.hubs", "TechnicHub", "imu.up", [([], "Side")]),
|
||||
pytest.param("pybricks.hubs", "TechnicHub", "imu.tilt", [([], "Tuple[int, int]")]),
|
||||
pytest.param(
|
||||
"pybricks.hubs",
|
||||
"TechnicHub",
|
||||
"imu.acceleration",
|
||||
[(["axis: Axis"], "float"), ([], "Matrix")],
|
||||
),
|
||||
pytest.param(
|
||||
"pybricks.hubs",
|
||||
"TechnicHub",
|
||||
"imu.angular_velocity",
|
||||
[(["axis: Axis"], "float"), ([], "Matrix")],
|
||||
),
|
||||
pytest.param("pybricks.hubs", "TechnicHub", "imu.heading", [([], "float")]),
|
||||
pytest.param(
|
||||
"pybricks.hubs",
|
||||
"TechnicHub",
|
||||
"imu.reset_heading",
|
||||
[(["angle: Number"], "None")],
|
||||
),
|
||||
pytest.param("pybricks.hubs", "TechnicHub", "battery.voltage", [([], "int")]),
|
||||
pytest.param("pybricks.hubs", "TechnicHub", "battery.current", [([], "int")]),
|
||||
pytest.param(
|
||||
"pybricks.hubs", "TechnicHub", "button.pressed", [([], "Collection[Button]")]
|
||||
),
|
||||
pytest.param(
|
||||
"pybricks.hubs",
|
||||
"TechnicHub",
|
||||
"system.set_stop_button",
|
||||
[(["button: Optional[Union[Button, Iterable[Button]]]"], "None")],
|
||||
),
|
||||
pytest.param("pybricks.hubs", "TechnicHub", "system.name", [([], "str")]),
|
||||
pytest.param("pybricks.hubs", "TechnicHub", "system.shutdown", [([], "None")]),
|
||||
pytest.param("pybricks.hubs", "TechnicHub", "system.reset_reason", [([], "int")]),
|
||||
pytest.param("pybricks.hubs", "PrimeHub", "light.on", [(["color: Color"], "None")]),
|
||||
pytest.param("pybricks.hubs", "PrimeHub", "light.off", [([], "None")]),
|
||||
pytest.param(
|
||||
"pybricks.hubs",
|
||||
"PrimeHub",
|
||||
"light.blink",
|
||||
[(["color: Color", "durations: Collection[Number]"], "None")],
|
||||
),
|
||||
pytest.param(
|
||||
"pybricks.hubs",
|
||||
"PrimeHub",
|
||||
"light.animate",
|
||||
[(["colors: Collection[Color]", "interval: Number"], "None")],
|
||||
),
|
||||
pytest.param(
|
||||
"pybricks.hubs", "PrimeHub", "display.orientation", [(["up: Side"], "None")]
|
||||
),
|
||||
pytest.param("pybricks.hubs", "PrimeHub", "display.off", [([], "None")]),
|
||||
pytest.param(
|
||||
"pybricks.hubs",
|
||||
"PrimeHub",
|
||||
"display.pixel",
|
||||
[(["row: Number", "column: Number", "brightness: Number=100"], "None")],
|
||||
),
|
||||
pytest.param(
|
||||
"pybricks.hubs", "PrimeHub", "display.image", [(["matrix: Matrix"], "None")]
|
||||
),
|
||||
pytest.param(
|
||||
"pybricks.hubs",
|
||||
"PrimeHub",
|
||||
"display.animate",
|
||||
[(["matrices: Collection[Matrix]", "interval: Number"], "None")],
|
||||
),
|
||||
pytest.param(
|
||||
"pybricks.hubs", "PrimeHub", "display.number", [(["number: Number"], "None")]
|
||||
),
|
||||
pytest.param(
|
||||
"pybricks.hubs", "PrimeHub", "display.char", [(["char: str"], "None")]
|
||||
),
|
||||
pytest.param(
|
||||
"pybricks.hubs",
|
||||
"PrimeHub",
|
||||
"display.text",
|
||||
[(["text: str", "on: Number=500", "off: Number=50"], "None")],
|
||||
),
|
||||
pytest.param(
|
||||
"pybricks.hubs", "PrimeHub", "buttons.pressed", [([], "Collection[Button]")]
|
||||
),
|
||||
pytest.param("pybricks.hubs", "PrimeHub", "imu.up", [([], "Side")]),
|
||||
pytest.param("pybricks.hubs", "PrimeHub", "imu.tilt", [([], "Tuple[int, int]")]),
|
||||
pytest.param(
|
||||
"pybricks.hubs",
|
||||
"PrimeHub",
|
||||
"imu.acceleration",
|
||||
[(["axis: Axis"], "float"), ([], "Matrix")],
|
||||
),
|
||||
pytest.param(
|
||||
"pybricks.hubs",
|
||||
"PrimeHub",
|
||||
"imu.angular_velocity",
|
||||
[(["axis: Axis"], "float"), ([], "Matrix")],
|
||||
),
|
||||
pytest.param("pybricks.hubs", "PrimeHub", "imu.heading", [([], "float")]),
|
||||
pytest.param(
|
||||
"pybricks.hubs",
|
||||
"PrimeHub",
|
||||
"imu.reset_heading",
|
||||
[(["angle: Number"], "None")],
|
||||
),
|
||||
pytest.param(
|
||||
"pybricks.hubs",
|
||||
"PrimeHub",
|
||||
"speaker.volume",
|
||||
[(["volume: Number"], "None"), ([], "int")],
|
||||
),
|
||||
pytest.param(
|
||||
"pybricks.hubs",
|
||||
"PrimeHub",
|
||||
"speaker.beep",
|
||||
[(["frequency: Number=500", "duration: Number=100"], "None")],
|
||||
),
|
||||
pytest.param(
|
||||
"pybricks.hubs",
|
||||
"PrimeHub",
|
||||
"speaker.play_notes",
|
||||
[(["notes: Iterable[str]", "tempo: Number=120"], "None")],
|
||||
),
|
||||
pytest.param("pybricks.hubs", "PrimeHub", "battery.voltage", [([], "int")]),
|
||||
pytest.param("pybricks.hubs", "PrimeHub", "battery.current", [([], "int")]),
|
||||
pytest.param("pybricks.hubs", "PrimeHub", "charger.connected", [([], "bool")]),
|
||||
pytest.param("pybricks.hubs", "PrimeHub", "charger.current", [([], "int")]),
|
||||
pytest.param("pybricks.hubs", "PrimeHub", "charger.status", [([], "int")]),
|
||||
pytest.param(
|
||||
"pybricks.hubs",
|
||||
"PrimeHub",
|
||||
"system.set_stop_button",
|
||||
[(["button: Optional[Union[Button, Iterable[Button]]]"], "None")],
|
||||
),
|
||||
pytest.param("pybricks.hubs", "PrimeHub", "system.name", [([], "str")]),
|
||||
pytest.param("pybricks.hubs", "PrimeHub", "system.shutdown", [([], "None")]),
|
||||
pytest.param("pybricks.hubs", "PrimeHub", "system.reset_reason", [([], "int")]),
|
||||
# TODO: iodevices module here
|
||||
pytest.param("pybricks.pupdevices", "DCMotor", "dc", [(["duty: Number"], "None")]),
|
||||
pytest.param("pybricks.pupdevices", "DCMotor", "stop", [([], "None")]),
|
||||
pytest.param("pybricks.pupdevices", "DCMotor", "brake", [([], "None")]),
|
||||
pytest.param(
|
||||
"pybricks.pupdevices",
|
||||
"DCMotor",
|
||||
"settings",
|
||||
[(["max_voltage: Number"], "None"), ([], "Tuple[int]")],
|
||||
),
|
||||
pytest.param("pybricks.pupdevices", "Motor", "speed", [([], "int")]),
|
||||
pytest.param("pybricks.pupdevices", "Motor", "angle", [([], "int")]),
|
||||
pytest.param(
|
||||
"pybricks.pupdevices",
|
||||
"Motor",
|
||||
"reset_angle",
|
||||
[(["angle: Optional[Number]=None"], "None")],
|
||||
),
|
||||
pytest.param("pybricks.pupdevices", "Motor", "stop", [([], "None")]),
|
||||
pytest.param("pybricks.pupdevices", "Motor", "brake", [([], "None")]),
|
||||
pytest.param("pybricks.pupdevices", "Motor", "hold", [([], "None")]),
|
||||
pytest.param("pybricks.pupdevices", "Motor", "run", [(["speed: Number"], "None")]),
|
||||
pytest.param(
|
||||
"pybricks.pupdevices",
|
||||
"Motor",
|
||||
"run_time",
|
||||
[
|
||||
(
|
||||
[
|
||||
"speed: Number",
|
||||
"time: Number",
|
||||
"then: Stop=Stop.HOLD",
|
||||
"wait: bool=True",
|
||||
],
|
||||
"None",
|
||||
)
|
||||
],
|
||||
),
|
||||
pytest.param(
|
||||
"pybricks.pupdevices",
|
||||
"Motor",
|
||||
"run_angle",
|
||||
[
|
||||
(
|
||||
[
|
||||
"speed: Number",
|
||||
"rotation_angle: Number",
|
||||
"then: Stop=Stop.HOLD",
|
||||
"wait: bool=True",
|
||||
],
|
||||
"None",
|
||||
)
|
||||
],
|
||||
),
|
||||
pytest.param(
|
||||
"pybricks.pupdevices",
|
||||
"Motor",
|
||||
"run_target",
|
||||
[
|
||||
(
|
||||
[
|
||||
"speed: Number",
|
||||
"target_angle: Number",
|
||||
"then: Stop=Stop.HOLD",
|
||||
"wait: bool=True",
|
||||
],
|
||||
"None",
|
||||
)
|
||||
],
|
||||
),
|
||||
pytest.param(
|
||||
"pybricks.pupdevices",
|
||||
"Motor",
|
||||
"track_target",
|
||||
[(["target_angle: Number"], "None")],
|
||||
),
|
||||
pytest.param(
|
||||
"pybricks.pupdevices",
|
||||
"Motor",
|
||||
"run_until_stalled",
|
||||
[
|
||||
(
|
||||
[
|
||||
"speed: Number",
|
||||
"then: Stop=Stop.COAST",
|
||||
"duty_limit: Optional[Number]=None",
|
||||
],
|
||||
"int",
|
||||
)
|
||||
],
|
||||
),
|
||||
pytest.param("pybricks.pupdevices", "Motor", "dc", [(["duty: Number"], "None")]),
|
||||
pytest.param("pybricks.pupdevices", "Motor", "control.done", [([], "bool")]),
|
||||
pytest.param("pybricks.pupdevices", "Motor", "control.stalled", [([], "bool")]),
|
||||
pytest.param("pybricks.pupdevices", "Motor", "control.load", [([], "int")]),
|
||||
pytest.param(
|
||||
"pybricks.pupdevices",
|
||||
"Motor",
|
||||
"settings",
|
||||
[(["max_voltage: Number"], "None"), ([], "Tuple[int]")],
|
||||
),
|
||||
pytest.param(
|
||||
"pybricks.pupdevices",
|
||||
"Motor",
|
||||
"control.limits",
|
||||
[
|
||||
(
|
||||
[
|
||||
"speed: Optional[Number]=None",
|
||||
"acceleration: Optional[Number]=None",
|
||||
"torque: Optional[Number]=None",
|
||||
],
|
||||
"None",
|
||||
),
|
||||
([], "Tuple[int, int, int]"),
|
||||
],
|
||||
),
|
||||
pytest.param(
|
||||
"pybricks.pupdevices",
|
||||
"Motor",
|
||||
"control.pid",
|
||||
[
|
||||
(
|
||||
[
|
||||
"kp: Optional[Number]=None",
|
||||
"ki: Optional[Number]=None",
|
||||
"kd: Optional[Number]=None",
|
||||
"reserved: Optional[Number]=None",
|
||||
"integral_rate: Optional[Number]=None",
|
||||
],
|
||||
"None",
|
||||
),
|
||||
([], "Tuple[int, int, int, None, int]"),
|
||||
],
|
||||
),
|
||||
pytest.param(
|
||||
"pybricks.pupdevices",
|
||||
"Motor",
|
||||
"control.target_tolerances",
|
||||
[
|
||||
(
|
||||
[
|
||||
"speed: Optional[Number]=None",
|
||||
"position: Optional[Number]=None",
|
||||
],
|
||||
"None",
|
||||
),
|
||||
([], "Tuple[int, int]"),
|
||||
],
|
||||
),
|
||||
pytest.param(
|
||||
"pybricks.pupdevices",
|
||||
"Motor",
|
||||
"control.stall_tolerances",
|
||||
[
|
||||
(
|
||||
[
|
||||
"speed: Optional[Number]=None",
|
||||
"time: Optional[Number]=None",
|
||||
],
|
||||
"None",
|
||||
),
|
||||
([], "Tuple[int, int]"),
|
||||
],
|
||||
),
|
||||
pytest.param(
|
||||
"pybricks.pupdevices", "TiltSensor", "tilt", [([], "Tuple[int, int]")]
|
||||
),
|
||||
pytest.param("pybricks.pupdevices", "InfraredSensor", "distance", [([], "int")]),
|
||||
pytest.param("pybricks.pupdevices", "InfraredSensor", "reflection", [([], "int")]),
|
||||
pytest.param("pybricks.pupdevices", "InfraredSensor", "count", [([], "int")]),
|
||||
pytest.param(
|
||||
"pybricks.pupdevices", "ColorDistanceSensor", "color", [([], "Color")]
|
||||
),
|
||||
pytest.param(
|
||||
"pybricks.pupdevices", "ColorDistanceSensor", "reflection", [([], "int")]
|
||||
),
|
||||
pytest.param(
|
||||
"pybricks.pupdevices", "ColorDistanceSensor", "ambient", [([], "int")]
|
||||
),
|
||||
pytest.param(
|
||||
"pybricks.pupdevices", "ColorDistanceSensor", "distance", [([], "int")]
|
||||
),
|
||||
pytest.param("pybricks.pupdevices", "ColorDistanceSensor", "hsv", [([], "Color")]),
|
||||
pytest.param(
|
||||
"pybricks.pupdevices",
|
||||
"ColorDistanceSensor",
|
||||
"detectable_colors",
|
||||
[(["colors: Collection[Color]"], "None"), ([], "Collection[Color]")],
|
||||
),
|
||||
pytest.param(
|
||||
"pybricks.pupdevices",
|
||||
"ColorDistanceSensor",
|
||||
"light.on",
|
||||
[(["color: Color"], "None")],
|
||||
),
|
||||
pytest.param(
|
||||
"pybricks.pupdevices", "ColorDistanceSensor", "light.off", [([], "None")]
|
||||
),
|
||||
pytest.param("pybricks.pupdevices", "PFMotor", "dc", [(["duty: Number"], "None")]),
|
||||
pytest.param("pybricks.pupdevices", "PFMotor", "stop", [([], "None")]),
|
||||
pytest.param("pybricks.pupdevices", "PFMotor", "brake", [([], "None")]),
|
||||
pytest.param(
|
||||
"pybricks.pupdevices",
|
||||
"ColorSensor",
|
||||
"color",
|
||||
[(["surface: bool=True"], "Optional[Color]")],
|
||||
),
|
||||
pytest.param("pybricks.pupdevices", "ColorSensor", "reflection", [([], "int")]),
|
||||
pytest.param("pybricks.pupdevices", "ColorSensor", "ambient", [([], "int")]),
|
||||
pytest.param(
|
||||
"pybricks.pupdevices",
|
||||
"ColorSensor",
|
||||
"hsv",
|
||||
[(["surface: bool=True"], "Color")],
|
||||
),
|
||||
pytest.param(
|
||||
"pybricks.pupdevices",
|
||||
"ColorSensor",
|
||||
"detectable_colors",
|
||||
[(["colors: Collection[Color]"], "None"), ([], "Collection[Color]")],
|
||||
),
|
||||
pytest.param(
|
||||
"pybricks.pupdevices",
|
||||
"ColorSensor",
|
||||
"lights.on",
|
||||
[(["brightness: Union[Number, Tuple[Number, Number, Number]]"], "None")],
|
||||
),
|
||||
pytest.param("pybricks.pupdevices", "ColorSensor", "lights.off", [([], "None")]),
|
||||
pytest.param("pybricks.pupdevices", "UltrasonicSensor", "distance", [([], "int")]),
|
||||
pytest.param("pybricks.pupdevices", "UltrasonicSensor", "presence", [([], "bool")]),
|
||||
pytest.param(
|
||||
"pybricks.pupdevices",
|
||||
"UltrasonicSensor",
|
||||
"lights.on",
|
||||
[
|
||||
(
|
||||
["brightness: Union[Number, Tuple[Number, Number, Number, Number]]"],
|
||||
"None",
|
||||
)
|
||||
],
|
||||
),
|
||||
pytest.param(
|
||||
"pybricks.pupdevices", "UltrasonicSensor", "lights.off", [([], "None")]
|
||||
),
|
||||
pytest.param("pybricks.pupdevices", "ForceSensor", "force", [([], "float")]),
|
||||
pytest.param("pybricks.pupdevices", "ForceSensor", "distance", [([], "float")]),
|
||||
pytest.param(
|
||||
"pybricks.pupdevices",
|
||||
"ForceSensor",
|
||||
"pressed",
|
||||
[(["force: Number=3"], "bool")],
|
||||
),
|
||||
pytest.param("pybricks.pupdevices", "ForceSensor", "touched", [([], "bool")]),
|
||||
pytest.param(
|
||||
"pybricks.pupdevices",
|
||||
"ColorLightMatrix",
|
||||
"on",
|
||||
[(["color: Union[Color, Collection[Color]]"], "None")],
|
||||
),
|
||||
pytest.param("pybricks.pupdevices", "ColorLightMatrix", "off", [([], "None")]),
|
||||
pytest.param(
|
||||
"pybricks.pupdevices", "Light", "on", [(["brightness: Number=100"], "None")]
|
||||
),
|
||||
pytest.param("pybricks.pupdevices", "Light", "off", [([], "None")]),
|
||||
pytest.param(
|
||||
"pybricks.pupdevices",
|
||||
"Remote",
|
||||
"name",
|
||||
[(["name: str"], "None"), ([], "str")],
|
||||
),
|
||||
pytest.param(
|
||||
"pybricks.pupdevices", "Remote", "light.on", [(["color: Color"], "None")]
|
||||
),
|
||||
pytest.param("pybricks.pupdevices", "Remote", "light.off", [([], "None")]),
|
||||
pytest.param(
|
||||
"pybricks.pupdevices",
|
||||
"Remote",
|
||||
"buttons.pressed",
|
||||
[([], "Collection[Button]")],
|
||||
),
|
||||
pytest.param("pybricks.tools", "StopWatch", "time", [([], "int")]),
|
||||
pytest.param("pybricks.tools", "StopWatch", "pause", [([], "None")]),
|
||||
pytest.param("pybricks.tools", "StopWatch", "resume", [([], "None")]),
|
||||
pytest.param("pybricks.tools", "StopWatch", "reset", [([], "None")]),
|
||||
pytest.param(
|
||||
"pybricks.robotics",
|
||||
"DriveBase",
|
||||
"straight",
|
||||
[(["distance: Number", "then: Stop=Stop.HOLD", "wait: bool=True"], "None")],
|
||||
),
|
||||
pytest.param(
|
||||
"pybricks.robotics",
|
||||
"DriveBase",
|
||||
"turn",
|
||||
[(["angle: Number", "then: Stop=Stop.HOLD", "wait: bool=True"], "None")],
|
||||
),
|
||||
pytest.param(
|
||||
"pybricks.robotics",
|
||||
"DriveBase",
|
||||
"curve",
|
||||
[
|
||||
(
|
||||
[
|
||||
"radius: Number",
|
||||
"angle: Number",
|
||||
"then: Stop=Stop.HOLD",
|
||||
"wait: bool=True",
|
||||
],
|
||||
"None",
|
||||
)
|
||||
],
|
||||
),
|
||||
pytest.param(
|
||||
"pybricks.robotics",
|
||||
"DriveBase",
|
||||
"settings",
|
||||
[
|
||||
(
|
||||
[
|
||||
"straight_speed: Optional[Number]=None",
|
||||
"straight_acceleration: Optional[Number]=None",
|
||||
"turn_rate: Optional[Number]=None",
|
||||
"turn_acceleration: Optional[Number]=None",
|
||||
],
|
||||
"None",
|
||||
),
|
||||
([], "Tuple[int, int, int, int]"),
|
||||
],
|
||||
),
|
||||
pytest.param(
|
||||
"pybricks.robotics",
|
||||
"DriveBase",
|
||||
"drive",
|
||||
[(["speed: Number", "turn_rate: Number"], "None")],
|
||||
),
|
||||
pytest.param("pybricks.robotics", "DriveBase", "stop", [([], "None")]),
|
||||
pytest.param("pybricks.robotics", "DriveBase", "distance", [([], "int")]),
|
||||
pytest.param("pybricks.robotics", "DriveBase", "angle", [([], "int")]),
|
||||
pytest.param(
|
||||
"pybricks.robotics", "DriveBase", "state", [([], "Tuple[int, int, int, int]")]
|
||||
),
|
||||
pytest.param("pybricks.robotics", "DriveBase", "reset", [([], "None")]),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("module,type,method,signatures", METHOD_PARAMS)
|
||||
def test_get_signature_for_methods(
|
||||
module: str, type: str, method: str, signatures: list[tuple[list[str], str]]
|
||||
):
|
||||
help = _get_method_signature(module, type, method)
|
||||
|
||||
# strip method now that code has been generated (may have leading subcomponent)
|
||||
method = method.split(".")[-1]
|
||||
|
||||
assert help["activeSignature"] == 0
|
||||
assert help["activeParameter"] == 0
|
||||
assert help["signatures"]
|
||||
|
||||
for sig, (params, returns) in zip_longest(help["signatures"], signatures):
|
||||
assert sig["label"] == f"{method}({', '.join(params)}) -> {returns}"
|
||||
assert sig["documentation"]["value"]
|
||||
# ensure signatures are stripped from doc comment
|
||||
assert not sig["documentation"]["value"].startswith(f"{method}(")
|
||||
|
||||
for pi, p in zip_longest(sig["parameters"], params):
|
||||
assert pi["label"] == p
|
||||
assert pi["documentation"]["value"]
|
||||
+46
-47
@@ -107,7 +107,7 @@ class DCMotor:
|
||||
is generated while the motor is still moving."""
|
||||
|
||||
@overload
|
||||
def settings(self, max_voltage: Optional[int] = None) -> None:
|
||||
def settings(self, max_voltage: Number) -> None:
|
||||
...
|
||||
|
||||
@overload
|
||||
@@ -140,16 +140,16 @@ class Control:
|
||||
"""
|
||||
|
||||
@overload
|
||||
def limits(self) -> Tuple[int, int, int]:
|
||||
def limits(
|
||||
self,
|
||||
speed: Optional[Number] = None,
|
||||
acceleration: Optional[Number] = None,
|
||||
torque: Optional[Number] = None,
|
||||
) -> None:
|
||||
...
|
||||
|
||||
@overload
|
||||
def limits(
|
||||
self,
|
||||
speed: Optional[int] = None,
|
||||
acceleration: Optional[int] = None,
|
||||
torque: Optional[int] = None,
|
||||
) -> None:
|
||||
def limits(self) -> Tuple[int, int, int]:
|
||||
...
|
||||
|
||||
def limits(self, *args):
|
||||
@@ -173,18 +173,18 @@ class Control:
|
||||
"""
|
||||
|
||||
@overload
|
||||
def pid(self) -> Tuple[int, int, int, None, int]:
|
||||
def pid(
|
||||
self,
|
||||
kp: Optional[Number] = None,
|
||||
ki: Optional[Number] = None,
|
||||
kd: Optional[Number] = None,
|
||||
reserved: Optional[Number] = None,
|
||||
integral_rate: Optional[Number] = None,
|
||||
) -> None:
|
||||
...
|
||||
|
||||
@overload
|
||||
def pid(
|
||||
self,
|
||||
kp: Optional[int] = None,
|
||||
ki: Optional[int] = None,
|
||||
kd: Optional[int] = None,
|
||||
reserved: Optional[int] = None,
|
||||
integral_rate: Optional[int] = None,
|
||||
) -> None:
|
||||
def pid(self) -> Tuple[int, int, int, None, int]:
|
||||
...
|
||||
|
||||
def pid(self, *args):
|
||||
@@ -210,13 +210,13 @@ class Control:
|
||||
"""
|
||||
|
||||
@overload
|
||||
def target_tolerances(self) -> Tuple[int, int]:
|
||||
def target_tolerances(
|
||||
self, speed: Optional[Number] = None, position: Optional[Number] = None
|
||||
) -> None:
|
||||
...
|
||||
|
||||
@overload
|
||||
def target_tolerances(
|
||||
self, speed: Optional[int] = None, position: Optional[int] = None
|
||||
) -> None:
|
||||
def target_tolerances(self) -> Tuple[int, int]:
|
||||
...
|
||||
|
||||
def target_tolerances(self, *args):
|
||||
@@ -236,13 +236,13 @@ class Control:
|
||||
"""
|
||||
|
||||
@overload
|
||||
def stall_tolerances(self) -> Tuple[int, int]:
|
||||
def stall_tolerances(
|
||||
self, speed: Optional[Number] = None, time: Optional[Number] = None
|
||||
) -> None:
|
||||
...
|
||||
|
||||
@overload
|
||||
def stall_tolerances(
|
||||
self, speed: Optional[int] = None, time: Optional[int] = None
|
||||
) -> None:
|
||||
def stall_tolerances(self) -> Tuple[int, int]:
|
||||
...
|
||||
|
||||
def stall_tolerances(self, speed, time):
|
||||
@@ -356,7 +356,7 @@ class Motor(DCMotor):
|
||||
|
||||
"""
|
||||
|
||||
def reset_angle(self, angle: Number) -> None:
|
||||
def reset_angle(self, angle: Optional[Number]) -> None:
|
||||
"""
|
||||
reset_angle(angle)
|
||||
|
||||
@@ -485,11 +485,11 @@ class Speaker:
|
||||
"""Plays beeps and sounds using a speaker."""
|
||||
|
||||
@overload
|
||||
def volume(self) -> int:
|
||||
def volume(self, volume: Number) -> None:
|
||||
...
|
||||
|
||||
@overload
|
||||
def volume(self, volume: Number) -> None:
|
||||
def volume(self) -> int:
|
||||
...
|
||||
|
||||
def volume(self, *args):
|
||||
@@ -570,7 +570,7 @@ class ColorLight:
|
||||
|
||||
Turns off the light."""
|
||||
|
||||
def blink(self, color: Color, durations: Collection[int]) -> None:
|
||||
def blink(self, color: Color, durations: Collection[Number]) -> None:
|
||||
"""blink(color, durations)
|
||||
|
||||
Blinks the light at a given color by turning it on and off for given
|
||||
@@ -599,7 +599,7 @@ class ColorLight:
|
||||
keeps running. When the animation completes, it repeats.
|
||||
|
||||
Arguments:
|
||||
colors (iter): Sequence of :class:`Color <.parameters.Color>`
|
||||
colors (list): Sequence of :class:`Color <.parameters.Color>`
|
||||
values.
|
||||
interval (Number, ms): Time between color updates.
|
||||
"""
|
||||
@@ -617,7 +617,7 @@ class LightArray:
|
||||
n (int): Number of lights
|
||||
"""
|
||||
|
||||
def on(self, brightness: Union[int, Collection[int]]) -> None:
|
||||
def on(self, brightness: Union[Number, Collection[Number]]) -> None:
|
||||
"""on(brightness)
|
||||
|
||||
Turns on the lights at the specified brightness.
|
||||
@@ -688,15 +688,15 @@ class LightMatrix:
|
||||
interval (Number, ms): Time to display each image in the list.
|
||||
"""
|
||||
|
||||
def pixel(self, row: int, column: int, brightness: Number = 100) -> None:
|
||||
def pixel(self, row: Number, column: Number, brightness: Number = 100) -> None:
|
||||
"""pixel(row, column, brightness=100)
|
||||
|
||||
Turns on one pixel at the specified brightness.
|
||||
|
||||
Arguments:
|
||||
row (int): Vertical grid index, starting at 0 from the top.
|
||||
column (int): Horizontal grid index, starting at 0 from the left.
|
||||
brightness (:ref:`brightness`): Brightness of the pixel.
|
||||
row (Number): Vertical grid index, starting at 0 from the top.
|
||||
column (Number): Horizontal grid index, starting at 0 from the left.
|
||||
brightness (Number :ref:`brightness`): Brightness of the pixel.
|
||||
"""
|
||||
|
||||
def off(self) -> None:
|
||||
@@ -749,13 +749,13 @@ class Keypad:
|
||||
def __init__(self, active_buttons):
|
||||
...
|
||||
|
||||
def pressed(self) -> Tuple[Button]:
|
||||
"""pressed() -> Tuple[Button]
|
||||
def pressed(self) -> Collection[Button]:
|
||||
"""pressed() -> Collection[Button]
|
||||
|
||||
Checks which buttons are currently pressed.
|
||||
|
||||
Returns:
|
||||
Tuple of pressed buttons.
|
||||
Set of pressed buttons.
|
||||
"""
|
||||
|
||||
|
||||
@@ -846,11 +846,11 @@ class Accelerometer(SimpleAccelerometer):
|
||||
"""Get measurements from an accelerometer."""
|
||||
|
||||
@overload
|
||||
def acceleration(self) -> Matrix:
|
||||
def acceleration(self, axis: Axis) -> float:
|
||||
...
|
||||
|
||||
@overload
|
||||
def acceleration(self, axis: Axis) -> float:
|
||||
def acceleration(self) -> Matrix:
|
||||
...
|
||||
|
||||
def acceleration(self, *args):
|
||||
@@ -915,11 +915,11 @@ class IMU(Accelerometer):
|
||||
"""
|
||||
|
||||
@overload
|
||||
def angular_velocity(self) -> Matrix:
|
||||
def angular_velocity(self, axis: Axis) -> float:
|
||||
...
|
||||
|
||||
@overload
|
||||
def angular_velocity(self, axis: Axis) -> float:
|
||||
def angular_velocity(self) -> Matrix:
|
||||
...
|
||||
|
||||
def angular_velocity(self, *args):
|
||||
@@ -1003,13 +1003,13 @@ class CommonColorSensor:
|
||||
...
|
||||
|
||||
@overload
|
||||
def detectable_colors(self) -> Tuple[Color]:
|
||||
def detectable_colors(self) -> Collection[Color]:
|
||||
...
|
||||
|
||||
def detectable_colors(self, *args):
|
||||
"""
|
||||
detectable_colors(colors)
|
||||
detectable_colors() -> Tuple[Color]
|
||||
detectable_colors() -> Collection[Color]
|
||||
|
||||
Configures which colors the ``color()`` method should detect.
|
||||
|
||||
@@ -1017,11 +1017,10 @@ class CommonColorSensor:
|
||||
This way, the full-color measurements are rounded to the nearest
|
||||
desired color, and other colors are ignored. This improves reliability.
|
||||
|
||||
If you give no arguments, the currently chosen colors will be returned
|
||||
as a tuple.
|
||||
If you give no arguments, the currently chosen colors will be returned.
|
||||
|
||||
Arguments:
|
||||
colors (tuple): Tuple of :class:`Color <.parameters.Color>`
|
||||
colors (list or tuple): List of :class:`Color <.parameters.Color>`
|
||||
objects: the colors that you want to detect. You can pick
|
||||
standard colors such as ``Color.MAGENTA``, or provide your
|
||||
own colors like ``Color(h=348, s=96, v=40)`` for even
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Tuple, Collection, overload
|
||||
from typing import Sequence, Tuple, overload
|
||||
|
||||
|
||||
class Matrix:
|
||||
@@ -51,7 +51,7 @@ class Matrix:
|
||||
def __ifloordiv__(self, other) -> Matrix:
|
||||
...
|
||||
|
||||
def __init__(self, rows: Collection[Collection[int]]):
|
||||
def __init__(self, rows: Sequence[Sequence[float]]):
|
||||
"""Matrix(rows)
|
||||
|
||||
Arguments:
|
||||
@@ -73,12 +73,31 @@ class Matrix:
|
||||
|
||||
@overload
|
||||
def vector(x: float, y: float) -> Matrix:
|
||||
...
|
||||
"""
|
||||
Convenience function to create a :class:`.Matrix` with the shape (``2``, ``1``).
|
||||
|
||||
Arguments:
|
||||
x (float): x-coordinate of the vector.
|
||||
y (float): y-coordinate of the vector.
|
||||
|
||||
Returns:
|
||||
A matrix with the shape of a column vector.
|
||||
"""
|
||||
|
||||
|
||||
@overload
|
||||
def vector(x: float, y: float, z: float) -> Matrix:
|
||||
...
|
||||
"""
|
||||
Convenience function to create a :class:`.Matrix` with the shape (``3``, ``1``).
|
||||
|
||||
Arguments:
|
||||
x (float): x-coordinate of the vector.
|
||||
y (float): y-coordinate of the vector.
|
||||
z (float): z-coordinate of the vector.
|
||||
|
||||
Returns:
|
||||
A matrix with the shape of a column vector.
|
||||
"""
|
||||
|
||||
|
||||
def vector(*args):
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"""LEGO® Programmable Hubs."""
|
||||
from . import _common
|
||||
from .ev3dev import _speaker
|
||||
from .geometry import Axis as _Axis
|
||||
from .geometry import Axis
|
||||
from .media.ev3dev import Image as _Image
|
||||
from .parameters import Button as _Button
|
||||
|
||||
@@ -63,7 +63,7 @@ class TechnicHub:
|
||||
system = _common.System()
|
||||
button = _common.Keypad([_Button.CENTER])
|
||||
|
||||
def __init__(self, top_side: _Axis = _Axis.Z, front_side: _Axis = _Axis.X):
|
||||
def __init__(self, top_side: Axis = Axis.Z, front_side: Axis = Axis.X):
|
||||
"""TechnicHub(top_side=Axis.Z, front_side=Axis.X)
|
||||
|
||||
Initializes the hub. Optionally, specify how the hub is
|
||||
@@ -100,7 +100,7 @@ class PrimeHub:
|
||||
imu = _common.IMU()
|
||||
system = _common.System()
|
||||
|
||||
def __init__(self, top_side: _Axis = _Axis.Z, front_side: _Axis = _Axis.X):
|
||||
def __init__(self, top_side: Axis = Axis.Z, front_side: Axis = Axis.X):
|
||||
"""PrimeHub(top_side=Axis.Z, front_side=Axis.X)
|
||||
|
||||
Initializes the hub. Optionally, specify how the hub is
|
||||
@@ -118,3 +118,7 @@ class PrimeHub:
|
||||
|
||||
class InventorHub(PrimeHub):
|
||||
"""LEGO® MINDSTORMS Inventor Hub."""
|
||||
|
||||
|
||||
# HACK: hide from jedi
|
||||
del Axis
|
||||
|
||||
+127
-28
@@ -8,25 +8,63 @@ from __future__ import annotations
|
||||
from typing import TYPE_CHECKING, Collection, Optional, Union, overload, Tuple
|
||||
|
||||
from . import _common
|
||||
from .parameters import (
|
||||
Button as _Button,
|
||||
Color as _Color,
|
||||
Direction as _Direction,
|
||||
Port as _Port,
|
||||
)
|
||||
from .parameters import Button, Color, Direction
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .parameters import Number as _Number
|
||||
from .parameters import Number, Port
|
||||
|
||||
|
||||
class DCMotor(_common.DCMotor):
|
||||
"""LEGO® Powered Up motor without rotation sensors."""
|
||||
|
||||
# HACK: jedi can't find inherited __init__ so we have to duplicate docs
|
||||
def __init__(self, port: Port, positive_direction: Direction = Direction.CLOCKWISE):
|
||||
"""__init__(port, positive_direction=Direction.CLOCKWISE)
|
||||
|
||||
Arguments:
|
||||
port (Port): Port to which the motor is connected.
|
||||
positive_direction (Direction): Which direction the motor should
|
||||
turn when you give a positive duty cycle value.
|
||||
"""
|
||||
|
||||
|
||||
class Motor(_common.Motor):
|
||||
"""LEGO® Powered Up motor with rotation sensors."""
|
||||
|
||||
def reset_angle(self, angle: Optional[int]) -> None:
|
||||
# HACK: jedi can't find inherited __init__ so we have to duplicate docs
|
||||
def __init__(
|
||||
self,
|
||||
port: Port,
|
||||
positive_direction: Direction = Direction.CLOCKWISE,
|
||||
gears: Optional[Union[Collection[int], Collection[Collection[int]]]] = None,
|
||||
reset_angle: bool = True,
|
||||
):
|
||||
"""__init__(port, positive_direction=Direction.CLOCKWISE, gears=None, reset_angle=True)
|
||||
|
||||
Arguments:
|
||||
port (Port): Port to which the motor is connected.
|
||||
positive_direction (Direction): Which direction the motor should
|
||||
turn when you give a positive speed value or
|
||||
angle.
|
||||
gears (list):
|
||||
List of gears linked to the motor.
|
||||
|
||||
For example: ``[12, 36]`` represents a gear train with a
|
||||
12-tooth and a 36-tooth gear. Use a list of lists for multiple
|
||||
gear trains, such as ``[[12, 36], [20, 16, 40]]``.
|
||||
|
||||
When you specify a gear train, all motor commands and settings
|
||||
are automatically adjusted to account for the resulting gear
|
||||
ratio. The motor direction remains unchanged by this.
|
||||
reset_angle(bool):
|
||||
Choose ``True`` to reset the rotation sensor value to the
|
||||
absolute marker angle (between -180 and 179).
|
||||
Choose ``False`` to keep the
|
||||
current value, so your program knows where it left off last
|
||||
time.
|
||||
"""
|
||||
|
||||
def reset_angle(self, angle: Optional[Number] = None) -> None:
|
||||
"""reset_angle(angle=None)
|
||||
|
||||
Sets the accumulated rotation angle of the motor to a desired value.
|
||||
@@ -45,13 +83,13 @@ class Remote:
|
||||
light = _common.ColorLight()
|
||||
buttons = _common.Keypad(
|
||||
(
|
||||
_Button.LEFT_MINUS,
|
||||
_Button.RIGHT_MINUS,
|
||||
_Button.LEFT,
|
||||
_Button.CENTER,
|
||||
_Button.RIGHT,
|
||||
_Button.LEFT_PLUS,
|
||||
_Button.RIGHT_PLUS,
|
||||
Button.LEFT_MINUS,
|
||||
Button.RIGHT_MINUS,
|
||||
Button.LEFT,
|
||||
Button.CENTER,
|
||||
Button.RIGHT,
|
||||
Button.LEFT_PLUS,
|
||||
Button.RIGHT_PLUS,
|
||||
)
|
||||
)
|
||||
addresss: Union[str, None]
|
||||
@@ -94,7 +132,7 @@ class Remote:
|
||||
class TiltSensor:
|
||||
"""LEGO® Powered Up Tilt Sensor."""
|
||||
|
||||
def __init__(self, port: _Port):
|
||||
def __init__(self, port: Port):
|
||||
"""TiltSensor(port)
|
||||
|
||||
Arguments:
|
||||
@@ -116,6 +154,14 @@ class ColorDistanceSensor(_common.CommonColorSensor):
|
||||
|
||||
light = _common.ColorLight()
|
||||
|
||||
# HACK: jedi can't find inherited __init__ so docs have to be duplicated
|
||||
def __init__(self, port: Port):
|
||||
"""__init__(port)
|
||||
|
||||
Arguments:
|
||||
port (Port): Port to which the sensor is connected.
|
||||
"""
|
||||
|
||||
def distance(self) -> int:
|
||||
"""distance() -> int: %
|
||||
|
||||
@@ -135,8 +181,8 @@ class PFMotor(DCMotor):
|
||||
self,
|
||||
sensor: ColorDistanceSensor,
|
||||
channel: int,
|
||||
color: _Color,
|
||||
positive_direction: _Direction = _Direction.CLOCKWISE,
|
||||
color: Color,
|
||||
positive_direction: Direction = Direction.CLOCKWISE,
|
||||
):
|
||||
"""PFMotor(sensor, channel, color, positive_direction=Direction.CLOCKWISE)
|
||||
|
||||
@@ -157,15 +203,59 @@ class PFMotor(DCMotor):
|
||||
class ColorSensor(_common.AmbientColorSensor):
|
||||
"""LEGO® SPIKE Color Sensor."""
|
||||
|
||||
lights = _common.LightArray(3)
|
||||
class _LightArray(_common.LightArray):
|
||||
def __init__(self):
|
||||
super().__init__(3)
|
||||
|
||||
def on(self, brightness: Union[Number, Tuple[Number, Number, Number]]) -> None:
|
||||
"""on(brightness)
|
||||
|
||||
Turns on the lights at the specified brightness.
|
||||
|
||||
Arguments:
|
||||
brightness (Number or tuple, %):
|
||||
A single value will set the brightness of all three lights
|
||||
to the same value. A tuple of 3 values will set the
|
||||
brightness of each LED individually.
|
||||
"""
|
||||
return super().on(brightness)
|
||||
|
||||
lights = _LightArray()
|
||||
|
||||
# HACK: jedi can't find inherited __init__ so docs have to be duplicated
|
||||
def __init__(self, port: Port):
|
||||
"""__init__(port)
|
||||
|
||||
Arguments:
|
||||
port (Port): Port to which the sensor is connected.
|
||||
"""
|
||||
|
||||
|
||||
class UltrasonicSensor:
|
||||
"""LEGO® SPIKE Color Sensor."""
|
||||
|
||||
lights = _common.LightArray(3)
|
||||
class _LightArray(_common.LightArray):
|
||||
def __init__(self):
|
||||
super().__init__(4)
|
||||
|
||||
def __init__(self, port: _Port):
|
||||
def on(
|
||||
self, brightness: Union[Number, Tuple[Number, Number, Number, Number]]
|
||||
) -> None:
|
||||
"""on(brightness)
|
||||
|
||||
Turns on the lights at the specified brightness.
|
||||
|
||||
Arguments:
|
||||
brightness (Number or tuple, %):
|
||||
A single value will set the brightness of all four lights
|
||||
to the same value. A tuple of 4 values will set the
|
||||
brightness of each LED individually.
|
||||
"""
|
||||
return super().on(brightness)
|
||||
|
||||
lights = _LightArray()
|
||||
|
||||
def __init__(self, port: Port):
|
||||
"""UltrasonicSensor(port)
|
||||
|
||||
Arguments:
|
||||
@@ -199,7 +289,7 @@ class UltrasonicSensor:
|
||||
class ForceSensor:
|
||||
"""LEGO® SPIKE Force Sensor."""
|
||||
|
||||
def __init__(self, port: _Port):
|
||||
def __init__(self, port: Port):
|
||||
"""ForceSensor(port)
|
||||
|
||||
Arguments:
|
||||
@@ -224,7 +314,7 @@ class ForceSensor:
|
||||
Movement up to approximately 8.00 mm.
|
||||
"""
|
||||
|
||||
def pressed(self, force: _Number = 3) -> bool:
|
||||
def pressed(self, force: Number = 3) -> bool:
|
||||
"""pressed(force=3) -> bool
|
||||
|
||||
Checks if the sensor button is pressed.
|
||||
@@ -255,7 +345,7 @@ class ColorLightMatrix:
|
||||
LEGO® SPIKE 3x3 Color Light Matrix.
|
||||
"""
|
||||
|
||||
def __init__(self, port: _Port):
|
||||
def __init__(self, port: Port):
|
||||
"""ColorLightMatrix(port)
|
||||
|
||||
Arguments:
|
||||
@@ -264,7 +354,7 @@ class ColorLightMatrix:
|
||||
"""
|
||||
...
|
||||
|
||||
def on(self, color: Union[_Color, Collection[_Color]]) -> None:
|
||||
def on(self, color: Union[Color, Collection[Color]]) -> None:
|
||||
"""on(colors)
|
||||
|
||||
Turns the lights on.
|
||||
@@ -288,7 +378,7 @@ class ColorLightMatrix:
|
||||
class InfraredSensor:
|
||||
"""LEGO® Powered Up Infrared Sensor."""
|
||||
|
||||
def __init__(self, port: _Port):
|
||||
def __init__(self, port: Port):
|
||||
"""InfraredSensor(port)
|
||||
|
||||
Arguments:
|
||||
@@ -328,14 +418,14 @@ class InfraredSensor:
|
||||
class Light:
|
||||
"""LEGO® Powered Up Light."""
|
||||
|
||||
def __init__(self, port: _Port):
|
||||
def __init__(self, port: Port):
|
||||
"""Light(port)
|
||||
|
||||
Arguments:
|
||||
port (Port): Port to which the device is connected.
|
||||
"""
|
||||
|
||||
def on(self, brightness: _Number = 100) -> None:
|
||||
def on(self, brightness: Number = 100) -> None:
|
||||
"""on(brightness=100)
|
||||
|
||||
Turns on the light at the specified brightness.
|
||||
@@ -349,3 +439,12 @@ class Light:
|
||||
"""off()
|
||||
|
||||
Turns off the light."""
|
||||
|
||||
|
||||
# HACK: exclude from jedi
|
||||
if TYPE_CHECKING:
|
||||
del Button
|
||||
del Color
|
||||
del Direction
|
||||
del Number
|
||||
del Port
|
||||
|
||||
+25
-15
@@ -1,5 +1,5 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
# Copyright (c) 2018-2021 The Pybricks Authors
|
||||
# Copyright (c) 2018-2022 The Pybricks Authors
|
||||
|
||||
"""Robotics module for the Pybricks API."""
|
||||
|
||||
@@ -8,10 +8,11 @@ from __future__ import annotations
|
||||
from typing import Tuple, Optional, overload, TYPE_CHECKING
|
||||
|
||||
from . import _common
|
||||
from .parameters import Stop as _Stop
|
||||
from .parameters import Stop
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .parameters import Number as _Number
|
||||
from ._common import Motor
|
||||
from .parameters import Number
|
||||
|
||||
|
||||
class DriveBase:
|
||||
@@ -50,10 +51,10 @@ class DriveBase:
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
left_motor: _common.Motor,
|
||||
right_motor: _common.Motor,
|
||||
wheel_diameter: _Number,
|
||||
axle_track: _Number,
|
||||
left_motor: Motor,
|
||||
right_motor: Motor,
|
||||
wheel_diameter: Number,
|
||||
axle_track: Number,
|
||||
):
|
||||
"""DriveBase(left_motor, right_motor, wheel_diameter, axle_track)
|
||||
|
||||
@@ -67,7 +68,7 @@ class DriveBase:
|
||||
both wheels touch the ground.
|
||||
"""
|
||||
|
||||
def drive(self, speed: _Number, turn_rate: _Number) -> None:
|
||||
def drive(self, speed: Number, turn_rate: Number) -> None:
|
||||
"""drive(speed, turn_rate)
|
||||
|
||||
Starts driving at the specified speed and turn rate. Both values are
|
||||
@@ -118,10 +119,10 @@ class DriveBase:
|
||||
@overload
|
||||
def settings(
|
||||
self,
|
||||
straight_speed: Optional[_Number],
|
||||
straight_acceleration: Optional[_Number],
|
||||
turn_rate: Optional[_Number],
|
||||
turn_acceleration: Optional[_Number],
|
||||
straight_speed: Optional[Number] = None,
|
||||
straight_acceleration: Optional[Number] = None,
|
||||
turn_rate: Optional[Number] = None,
|
||||
turn_acceleration: Optional[Number] = None,
|
||||
) -> None:
|
||||
...
|
||||
|
||||
@@ -147,7 +148,9 @@ class DriveBase:
|
||||
deceleration of the robot.
|
||||
"""
|
||||
|
||||
def straight(self, distance: _Number, then=_Stop.HOLD, wait=True) -> None:
|
||||
def straight(
|
||||
self, distance: Number, then: Stop = Stop.HOLD, wait: bool = True
|
||||
) -> None:
|
||||
"""straight(distance, then=Stop.HOLD, wait=True)
|
||||
|
||||
Drives straight for a given distance and then stops.
|
||||
@@ -159,7 +162,7 @@ class DriveBase:
|
||||
with the rest of the program.
|
||||
"""
|
||||
|
||||
def turn(self, angle: _Number, then=_Stop.HOLD, wait=True) -> None:
|
||||
def turn(self, angle: Number, then: Stop = Stop.HOLD, wait: bool = True) -> None:
|
||||
"""turn(angle, then=Stop.HOLD, wait=True)
|
||||
|
||||
Turns in place by a given angle and then stops.
|
||||
@@ -172,7 +175,7 @@ class DriveBase:
|
||||
"""
|
||||
|
||||
def curve(
|
||||
self, radius: _Number, angle: _Number, then=_Stop.HOLD, wait=True
|
||||
self, radius: Number, angle: Number, then: Stop = Stop.HOLD, wait: bool = True
|
||||
) -> None:
|
||||
"""curve(radius, angle, then=Stop.HOLD, wait=True)
|
||||
|
||||
@@ -185,3 +188,10 @@ class DriveBase:
|
||||
wait (bool): Wait for the maneuver to complete before continuing
|
||||
with the rest of the program.
|
||||
"""
|
||||
|
||||
|
||||
# HACK: hide from jedi
|
||||
if TYPE_CHECKING:
|
||||
del Motor
|
||||
del Number
|
||||
del Stop
|
||||
|
||||
+13
-3
@@ -3,10 +3,15 @@
|
||||
|
||||
"""Common tools for timing and data logging."""
|
||||
|
||||
from typing import Any
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .parameters import Number
|
||||
|
||||
|
||||
def wait(time: int) -> None:
|
||||
def wait(time: Number) -> None:
|
||||
"""wait(time)
|
||||
|
||||
Pauses the user program for a specified amount of time.
|
||||
@@ -63,7 +68,7 @@ class DataLog:
|
||||
name: str = "log",
|
||||
timestamp: bool = True,
|
||||
extension: str = "csv",
|
||||
append: bool = False
|
||||
append: bool = False,
|
||||
):
|
||||
"""DataLog(*headers, name='log', timestamp=True, extension='csv', append=False)
|
||||
|
||||
@@ -90,3 +95,8 @@ class DataLog:
|
||||
Arguments:
|
||||
values (object, object, ...): One or more objects or values.
|
||||
"""
|
||||
|
||||
|
||||
# HACK: hide from jedi
|
||||
if TYPE_CHECKING:
|
||||
del Number
|
||||
|
||||
Reference in New Issue
Block a user