jedi: add new pybricks_jedi package

This package will be used in Pybricks Code to provide some intellesense
operations.
This commit is contained in:
David Lechner
2022-06-24 14:52:45 -05:00
parent 6d0de1effa
commit a2d9c33eb5
27 changed files with 2211 additions and 208 deletions
+33
View File
@@ -0,0 +1,33 @@
name: pybricks_jedi
on: [push, pull_request]
jobs:
test:
if: github.ref_type != 'tag'
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
with:
python-version: "3.10"
- run: pipx install poetry
- run: poetry install
working-directory: ./jedi
- run: poetry run pytest -vv
working-directory: ./jedi
publish:
if: github.ref_type == 'tag' && startsWith(github.ref_name, 'pybricks_jedi/')
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
with:
python-version: "3.10"
- run: pipx install poetry
- run: poetry install
- run: poetry build
- run: poetry publish
env:
POETRY_PYPI_TOKEN_PYPI: ${{ secrets.PYPI_PYBRICKS_JEDI_TOKEN }}
+2 -1
View File
@@ -26,8 +26,9 @@ build/
build-*/
_build/
# Test failure outputs
# Tests
######################
.pytest_cache/
tests/*.exp
tests/*.out
+9
View File
@@ -1,4 +1,5 @@
{
"python.autoComplete.extraPaths": ["jedi/src"],
"python.formatting.provider": "black",
"python.linting.pylintEnabled": false,
"python.linting.flake8Enabled": true,
@@ -9,6 +10,11 @@
"editor.defaultFormatter": "ms-python.python"
},
"python.languageServer": "Pylance",
"python.testing.pytestArgs": [
"jedi/tests"
],
"python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true,
"files.associations": {"*.inc": "restructuredtext"},
"restructuredtext.confPath": "${workspaceFolder}/doc/main",
"spellright.language": [
@@ -40,4 +46,7 @@
"restructuredtext",
],
"rewrap.wrappingColumn": 78,
"python.analysis.extraPaths": [
"jedi/src"
],
}
+13 -1
View File
@@ -27,6 +27,9 @@ from docutils import nodes
from docutils.parsers.rst.directives import flag
from docutils.parsers.rst import Directive
from sphinx.application import Sphinx
from sphinx.addnodes import pending_xref
from sphinx.environment import BuildEnvironment
from sphinx.util.nodes import make_refnode
import toml
TOP_DIR = os.path.abspath(os.path.join("..", ".."))
@@ -307,7 +310,16 @@ class AvailabilityDirective(Directive):
]
def on_missing_reference(app, env, node, contnode):
def on_missing_reference(
app: Sphinx, env: BuildEnvironment, node: pending_xref, contnode: nodes.Element
) -> nodes.Element:
# The Number type alias is on the Signals and Units page instead of on the
# pybricks.parameters page so normal resolution doesn't work
if node["reftype"] == "class" and node["reftarget"] == "Number":
return make_refnode(
app.builder, node["refdoc"], "signaltypes", "numbers", contnode
)
# References with special characters can't exist, so we have to supress
# warnings when Sphinx tries to cross reference units like deg/s. For
# consistency, we also treat units without special characters this way.
+3
View File
@@ -25,6 +25,9 @@ latex_logo = "../common/images/pybricks-logo-large.png"
if os.environ.get("READTHEDOCS", None) == "True":
tags.add("main") # noqa F821
# HACK: this allows Number type alias to be imported by Sphinx
os.environ["SPHINX_BUILD"] = "True"
# Addtional configuration of the IDE docs
if "ide" in tags.tags: # noqa F821
_DISCLAIMER = ""
+2 -16
View File
@@ -7,22 +7,8 @@ quantities. This page gives an overview of each quantity and its unit.
Numbers
~~~~~~~
.. class:: Number
Numbers can be represented as integers or floating point values:
* Integers (:class:`int <ubuiltins.int>`) are whole numbers
like ``15`` or ``-123``.
* Floating point values (:class:`float <ubuiltins.float>`) are decimal
numbers like ``3.14`` or ``-123.45``.
If you see :class:`Number <Number>` as the argument type, both
:class:`int <ubuiltins.int>` and :class:`float <ubuiltins.float>` may be used.
For example, :func:`wait(15) <pybricks.tools.wait>` and
:func:`wait(15.75) <pybricks.tools.wait>` are both allowed. In most functions,
however, your input value will be truncated to a whole number anyway. In this
example, either command makes the program pause for just 15 milliseconds.
.. autodata:: pybricks.parameters.Number
:noindex:
Time
~~~~~~
+370
View File
@@ -0,0 +1,370 @@
[[package]]
name = "atomicwrites"
version = "1.4.0"
description = "Atomic file writes."
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
[[package]]
name = "attrs"
version = "21.4.0"
description = "Classes Without Boilerplate"
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
[package.extras]
dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit", "cloudpickle"]
docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"]
tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "cloudpickle"]
tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "cloudpickle"]
[[package]]
name = "black"
version = "22.3.0"
description = "The uncompromising code formatter."
category = "dev"
optional = false
python-versions = ">=3.6.2"
[package.dependencies]
click = ">=8.0.0"
mypy-extensions = ">=0.4.3"
pathspec = ">=0.9.0"
platformdirs = ">=2"
tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
[package.extras]
colorama = ["colorama (>=0.4.3)"]
d = ["aiohttp (>=3.7.4)"]
jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
uvloop = ["uvloop (>=0.15.2)"]
[[package]]
name = "click"
version = "8.1.3"
description = "Composable command line interface toolkit"
category = "dev"
optional = false
python-versions = ">=3.7"
[package.dependencies]
colorama = {version = "*", markers = "platform_system == \"Windows\""}
[[package]]
name = "colorama"
version = "0.4.5"
description = "Cross-platform colored terminal text."
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
[[package]]
name = "flake8"
version = "4.0.1"
description = "the modular source code checker: pep8 pyflakes and co"
category = "dev"
optional = false
python-versions = ">=3.6"
[package.dependencies]
mccabe = ">=0.6.0,<0.7.0"
pycodestyle = ">=2.8.0,<2.9.0"
pyflakes = ">=2.4.0,<2.5.0"
[[package]]
name = "iniconfig"
version = "1.1.1"
description = "iniconfig: brain-dead simple config-ini parsing"
category = "dev"
optional = false
python-versions = "*"
[[package]]
name = "jedi"
version = "0.18.1"
description = "An autocompletion tool for Python that can be used for text editors."
category = "main"
optional = false
python-versions = ">=3.6"
[package.dependencies]
parso = ">=0.8.0,<0.9.0"
[package.extras]
qa = ["flake8 (==3.8.3)", "mypy (==0.782)"]
testing = ["Django (<3.1)", "colorama", "docopt", "pytest (<7.0.0)"]
[[package]]
name = "mccabe"
version = "0.6.1"
description = "McCabe checker, plugin for flake8"
category = "dev"
optional = false
python-versions = "*"
[[package]]
name = "mypy-extensions"
version = "0.4.3"
description = "Experimental type system extensions for programs checked with the mypy typechecker."
category = "dev"
optional = false
python-versions = "*"
[[package]]
name = "packaging"
version = "21.3"
description = "Core utilities for Python packages"
category = "dev"
optional = false
python-versions = ">=3.6"
[package.dependencies]
pyparsing = ">=2.0.2,<3.0.5 || >3.0.5"
[[package]]
name = "parso"
version = "0.8.3"
description = "A Python Parser"
category = "main"
optional = false
python-versions = ">=3.6"
[package.extras]
qa = ["flake8 (==3.8.3)", "mypy (==0.782)"]
testing = ["docopt", "pytest (<6.0.0)"]
[[package]]
name = "pathspec"
version = "0.9.0"
description = "Utility library for gitignore style pattern matching of file paths."
category = "dev"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
[[package]]
name = "platformdirs"
version = "2.5.2"
description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
category = "dev"
optional = false
python-versions = ">=3.7"
[package.extras]
docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)", "sphinx (>=4)"]
test = ["appdirs (==1.4.4)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)", "pytest (>=6)"]
[[package]]
name = "pluggy"
version = "1.0.0"
description = "plugin and hook calling mechanisms for python"
category = "dev"
optional = false
python-versions = ">=3.6"
[package.extras]
dev = ["pre-commit", "tox"]
testing = ["pytest", "pytest-benchmark"]
[[package]]
name = "py"
version = "1.11.0"
description = "library with cross-python path, ini-parsing, io, code, log facilities"
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
[[package]]
name = "pybricks"
version = "3.2.0b1-r1"
description = "Documentation and user-API stubs for Pybricks MicroPython"
category = "main"
optional = false
python-versions = "^3.8"
develop = true
[package.source]
type = "directory"
url = ".."
[[package]]
name = "pycodestyle"
version = "2.8.0"
description = "Python style guide checker"
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
[[package]]
name = "pyflakes"
version = "2.4.0"
description = "passive checker of Python programs"
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
[[package]]
name = "pyparsing"
version = "3.0.9"
description = "pyparsing module - Classes and methods to define and execute parsing grammars"
category = "dev"
optional = false
python-versions = ">=3.6.8"
[package.extras]
diagrams = ["railroad-diagrams", "jinja2"]
[[package]]
name = "pytest"
version = "7.1.2"
description = "pytest: simple powerful testing with Python"
category = "dev"
optional = false
python-versions = ">=3.7"
[package.dependencies]
atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""}
attrs = ">=19.2.0"
colorama = {version = "*", markers = "sys_platform == \"win32\""}
iniconfig = "*"
packaging = "*"
pluggy = ">=0.12,<2.0"
py = ">=1.8.2"
tomli = ">=1.0.0"
[package.extras]
testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"]
[[package]]
name = "tomli"
version = "2.0.1"
description = "A lil' TOML parser"
category = "dev"
optional = false
python-versions = ">=3.7"
[[package]]
name = "typing-extensions"
version = "4.2.0"
description = "Backported and Experimental Type Hints for Python 3.7+"
category = "main"
optional = false
python-versions = ">=3.7"
[metadata]
lock-version = "1.1"
python-versions = ">= 3.10, < 3.11"
content-hash = "e2b0bd41f109d9d7b6a4a7b73e61784fe3995be07470d76cbd86b9d42ec6205b"
[metadata.files]
atomicwrites = [
{file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"},
{file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"},
]
attrs = [
{file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"},
{file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"},
]
black = [
{file = "black-22.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2497f9c2386572e28921fa8bec7be3e51de6801f7459dffd6e62492531c47e09"},
{file = "black-22.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5795a0375eb87bfe902e80e0c8cfaedf8af4d49694d69161e5bd3206c18618bb"},
{file = "black-22.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e3556168e2e5c49629f7b0f377070240bd5511e45e25a4497bb0073d9dda776a"},
{file = "black-22.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67c8301ec94e3bcc8906740fe071391bce40a862b7be0b86fb5382beefecd968"},
{file = "black-22.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:fd57160949179ec517d32ac2ac898b5f20d68ed1a9c977346efbac9c2f1e779d"},
{file = "black-22.3.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:cc1e1de68c8e5444e8f94c3670bb48a2beef0e91dddfd4fcc29595ebd90bb9ce"},
{file = "black-22.3.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d2fc92002d44746d3e7db7cf9313cf4452f43e9ea77a2c939defce3b10b5c82"},
{file = "black-22.3.0-cp36-cp36m-win_amd64.whl", hash = "sha256:a6342964b43a99dbc72f72812bf88cad8f0217ae9acb47c0d4f141a6416d2d7b"},
{file = "black-22.3.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:328efc0cc70ccb23429d6be184a15ce613f676bdfc85e5fe8ea2a9354b4e9015"},
{file = "black-22.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06f9d8846f2340dfac80ceb20200ea5d1b3f181dd0556b47af4e8e0b24fa0a6b"},
{file = "black-22.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:ad4efa5fad66b903b4a5f96d91461d90b9507a812b3c5de657d544215bb7877a"},
{file = "black-22.3.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e8477ec6bbfe0312c128e74644ac8a02ca06bcdb8982d4ee06f209be28cdf163"},
{file = "black-22.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:637a4014c63fbf42a692d22b55d8ad6968a946b4a6ebc385c5505d9625b6a464"},
{file = "black-22.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:863714200ada56cbc366dc9ae5291ceb936573155f8bf8e9de92aef51f3ad0f0"},
{file = "black-22.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10dbe6e6d2988049b4655b2b739f98785a884d4d6b85bc35133a8fb9a2233176"},
{file = "black-22.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:cee3e11161dde1b2a33a904b850b0899e0424cc331b7295f2a9698e79f9a69a0"},
{file = "black-22.3.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5891ef8abc06576985de8fa88e95ab70641de6c1fca97e2a15820a9b69e51b20"},
{file = "black-22.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:30d78ba6bf080eeaf0b7b875d924b15cd46fec5fd044ddfbad38c8ea9171043a"},
{file = "black-22.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ee8f1f7228cce7dffc2b464f07ce769f478968bfb3dd1254a4c2eeed84928aad"},
{file = "black-22.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ee227b696ca60dd1c507be80a6bc849a5a6ab57ac7352aad1ffec9e8b805f21"},
{file = "black-22.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:9b542ced1ec0ceeff5b37d69838106a6348e60db7b8fdd245294dc1d26136265"},
{file = "black-22.3.0-py3-none-any.whl", hash = "sha256:bc58025940a896d7e5356952228b68f793cf5fcb342be703c3a2669a1488cb72"},
{file = "black-22.3.0.tar.gz", hash = "sha256:35020b8886c022ced9282b51b5a875b6d1ab0c387b31a065b84db7c33085ca79"},
]
click = [
{file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"},
{file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"},
]
colorama = [
{file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"},
{file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"},
]
flake8 = [
{file = "flake8-4.0.1-py2.py3-none-any.whl", hash = "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d"},
{file = "flake8-4.0.1.tar.gz", hash = "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"},
]
iniconfig = [
{file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"},
{file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"},
]
jedi = [
{file = "jedi-0.18.1-py2.py3-none-any.whl", hash = "sha256:637c9635fcf47945ceb91cd7f320234a7be540ded6f3e99a50cb6febdfd1ba8d"},
{file = "jedi-0.18.1.tar.gz", hash = "sha256:74137626a64a99c8eb6ae5832d99b3bdd7d29a3850fe2aa80a4126b2a7d949ab"},
]
mccabe = [
{file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"},
{file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"},
]
mypy-extensions = [
{file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"},
{file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"},
]
packaging = [
{file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"},
{file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"},
]
parso = [
{file = "parso-0.8.3-py2.py3-none-any.whl", hash = "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75"},
{file = "parso-0.8.3.tar.gz", hash = "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0"},
]
pathspec = [
{file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"},
{file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"},
]
platformdirs = [
{file = "platformdirs-2.5.2-py3-none-any.whl", hash = "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788"},
{file = "platformdirs-2.5.2.tar.gz", hash = "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19"},
]
pluggy = [
{file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"},
{file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"},
]
py = [
{file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"},
{file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"},
]
pybricks = []
pycodestyle = [
{file = "pycodestyle-2.8.0-py2.py3-none-any.whl", hash = "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20"},
{file = "pycodestyle-2.8.0.tar.gz", hash = "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f"},
]
pyflakes = [
{file = "pyflakes-2.4.0-py2.py3-none-any.whl", hash = "sha256:3bb3a3f256f4b7968c9c788781e4ff07dce46bdf12339dcda61053375426ee2e"},
{file = "pyflakes-2.4.0.tar.gz", hash = "sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c"},
]
pyparsing = [
{file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"},
{file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"},
]
pytest = [
{file = "pytest-7.1.2-py3-none-any.whl", hash = "sha256:13d0e3ccfc2b6e26be000cb6568c832ba67ba32e719443bfe725814d3c42433c"},
{file = "pytest-7.1.2.tar.gz", hash = "sha256:a06a0425453864a270bc45e71f783330a7428defb4230fb5e6a731fde06ecd45"},
]
tomli = [
{file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
]
typing-extensions = [
{file = "typing_extensions-4.2.0-py3-none-any.whl", hash = "sha256:6657594ee297170d19f67d55c05852a874e7eb634f4f753dbd667855e07c1708"},
{file = "typing_extensions-4.2.0.tar.gz", hash = "sha256:f1c24655a0da0d1b67f07e17a5e6b2a105894e6824b92096378bb3668ef02376"},
]
+25
View File
@@ -0,0 +1,25 @@
[tool.poetry]
name = "pybricks_jedi"
version = "1.0.0"
description = "Code completion for Pybricks."
authors = ["The Pybricks Authors"]
license = "MIT"
[tool.poetry.dependencies]
python = ">= 3.10, < 3.11"
pybricks = { path = "../", develop = true }
jedi = "^0.18.1"
typing-extensions = "^4.2.0"
[tool.poetry.dev-dependencies]
pytest = "^7.1.2"
black = "^22.3.0"
flake8 = "^4.0.1"
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
[tool.pytest.ini_options]
pythonpath = ["src"]
testpaths = ["tests"]
+391
View File
@@ -0,0 +1,391 @@
from enum import IntEnum
import json
from typing_extensions import TypedDict, NotRequired
import jedi
from jedi.api.classes import Completion, Signature, ParamName
# Packages included in Pybricks firmware that ships with Pybricks Code.
PYBRICKS_CODE_PACKAGES = {
"micropython",
"pybricks",
"pybricks.geometry",
"pybricks.hubs",
"pybricks.iodevices",
"pybricks.parameters",
"pybricks.pupdevices",
"pybricks.robotics",
"pybricks.tools",
"uerrno",
"uio",
"umath",
"urandom",
"uselect",
"usys",
}
# Subset of Python builtins included in Pybricks MicroPython.
PYBRICKS_BUILTINS = {
"abs",
"all",
"any",
"ArithmeticError",
"AssertionError",
"AttributeError",
"BaseException",
"bin",
"bool",
"bytearray",
"bytes",
"callable",
"chr",
"classmethod",
"complex",
"dict",
"dir",
"divmod",
"enumerate",
"EOFError",
"eval",
"Exception",
"exec",
"float",
"GeneratorExit",
"getattr",
"globals",
"hasattr",
"hash",
"help",
"hex",
"id",
"ImportError",
"IndentationError",
"IndexError",
"input",
"int",
"isinstance",
"issubclass",
"iter",
"KeyboardInterrupt",
"KeyError",
"len",
"list",
"locals",
"LookupError",
"map",
"max",
"MemoryError",
"min",
"NameError",
"next",
"NotImplementedError",
"object",
"oct",
"ord",
"OSError",
"OverflowError",
"pow",
"print",
"range",
"repr",
"reversed",
"round",
"RuntimeError",
"set",
"setattr",
"slice",
"sorted",
"staticmethod",
"StopIteration",
"str",
"sum",
"super",
"SyntaxError",
"SystemExit",
"tuple",
"type",
"TypeError",
"ValueError",
"ZeroDivisionError",
"zip",
}
# Types from monaco editor
class IRange(TypedDict):
startLineNumber: int
startColumn: int
endLineNumber: int
endColumn: int
class ISingleEditOperation(TypedDict):
range: IRange
text: str # TODO: can also be JavaScript null
forceMoveMarkers: NotRequired[bool]
class Command(TypedDict):
id: str
title: str
tooltip: NotRequired[str]
arguments: NotRequired[list]
class CompletionItemKind(IntEnum):
Method = 0
Function = 1
Constructor = 2
Field = 3
Variable = 4
Class = 5
Struct = 6
Interface = 7
Module = 8
Property = 9
Event = 10
Operator = 11
Unit = 12
Value = 13
Constant = 14
Enum = 15
EnumMember = 16
Keyword = 17
Text = 18
Color = 19
File = 20
Reference = 21
Customcolor = 22
Folder = 23
TypeParameter = 24
User = 25
Issue = 26
Snippet = 27
class CompletionItemTag(IntEnum):
Deprecated = 1
class CompletionItemInsertTextRule(IntEnum):
KeepWhitespace = 1
InsertAsSnippet = 4
class CompletionItemLabel(TypedDict):
label: str
detail: NotRequired[str]
description: NotRequired[str]
class CompletionItemRanges(TypedDict):
insert: IRange
replace: IRange
class CompletionItem(TypedDict):
label: str | CompletionItemLabel
kind: CompletionItemKind
tags: NotRequired[list[CompletionItemTag]]
detail: NotRequired[str]
documentation: NotRequired[str]
sortText: NotRequired[str]
filterText: NotRequired[str]
preselect: NotRequired[bool]
insertText: str
insertTextRules: NotRequired[CompletionItemInsertTextRule]
range: IRange | CompletionItemRanges
commitCharacters: NotRequired[list[str]]
additionalTextEdits: NotRequired[list[ISingleEditOperation]]
command: NotRequired[Command]
class ParameterInformation(TypedDict):
label: str | tuple[int, int]
documentation: NotRequired[str]
class SignatureInformation(TypedDict):
label: str
documentation: NotRequired[str]
parameters: list[ParameterInformation]
activeParameter: NotRequired[int]
class SignatureHelp(TypedDict):
signatures: list[SignatureInformation]
activeSignature: int
activeParameter: int
def _is_pybricks(c: Completion) -> bool:
# filter all "private" names (leading underscore)
if (isinstance(c.name, str)) and c.name.startswith("_"):
return False
if isinstance(c.full_name, str):
# this catches things like `from __future__ import annotations`
if c.full_name.startswith("_") and c.module_name != "__main__":
return False
# filter out enum types
if c.full_name.startswith("enum."):
return False
# filter out typing types
if c.full_name.startswith("typing."):
return False
# filter out packages/modules that are not included in Pybricks firmware
if c.type == "module" or c.type == "namespace":
return c.full_name in PYBRICKS_CODE_PACKAGES
# filter subset of builtins
if c.module_name == "builtins" and c.type != "keyword":
return c.name in PYBRICKS_BUILTINS
# this is a type alias, not a real type
if c.full_name == "pybricks.parameters.Number":
return False
return True
def _map_completion_kind(type: str) -> CompletionItemKind:
match type:
case "module":
return CompletionItemKind.Module
case "class":
return CompletionItemKind.Class
case "instance":
return CompletionItemKind.Variable
case "function":
return CompletionItemKind.Function
case "param":
return CompletionItemKind.Variable
case "path":
return CompletionItemKind.File
case "keyword":
return CompletionItemKind.Keyword
case "property":
return CompletionItemKind.Property
case "statement":
return CompletionItemKind.Variable
case _:
return CompletionItemKind.User
def _map_completion_item(
completion: Completion, line: int, column: int
) -> CompletionItem:
"""
Maps a Jedi completion to a Monaco editor CompletionItem.
Note: All members of the CompletionItem must be directly mappable without
PyProxy in Pyodide.
"""
return CompletionItem(
insertText=completion.name_with_symbols,
kind=_map_completion_kind(completion.type),
label=completion.name_with_symbols,
range=IRange(
startLineNumber=line,
startColumn=column - completion.get_completion_prefix_length(),
endLineNumber=line,
endColumn=column,
),
documentation=completion.docstring(),
)
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_signature(signature: Signature) -> SignatureInformation:
optional = {} if signature.index is None else dict(activeParameter=signature.index)
return SignatureInformation(
label=signature.to_string(),
documentation=signature.docstring(),
parameters=[_map_parameter(p) for p in signature.params],
**optional,
)
def _map_signatures(signatures: list[Signature]) -> SignatureHelp:
return SignatureHelp(
signatures=[_map_signature(s) for s in signatures],
activeSignature=0,
activeParameter=0,
)
def initialize():
"""
Initialize jedi with Pybricks-specific config.
"""
jedi.preload_module(
"typing",
"enum",
"micropython",
"pybricks._common",
"pybricks.ev3dev",
"pybricks.ev3dev.speaker",
"pybricks.geometry",
"pybricks.hubs",
"pybricks.iodevices",
"pybricks.parameters",
"pybricks.pupdevices",
"pybricks.robotics",
"pybricks.tools",
"pybricks",
"ubuiltins",
"uerrno",
"uio",
"ujson",
"umath",
"urandom",
"uselect",
"ustruct",
"usys",
)
# also preload "everything" in builtins
jedi.Script("").complete()
def complete(code: str, line: int, column: int) -> str:
"""
Calls jedi.Script().complete() and filters the results for Pybricks.
Args:
code: The Python code to parse.
line: The 1-based line number of the cursor position.
column: The 1-based column number of the cursor position.
Returns:
A json string containing a filtered list of completion items.
"""
completions = jedi.Script(code).complete(line, column - 1, fuzzy=True)
return json.dumps(
[_map_completion_item(c, line, column) for c in completions if _is_pybricks(c)]
)
def get_signatures(code: str, line: int, column: int) -> str:
"""
Calls jedi.Script().get_signatures().
Args:
code: The Python code to parse.
line: The 1-based line number of the cursor position.
column: The 1-based column number of the cursor position.
Returns:
A json string containing the signature help.
"""
signatures = jedi.Script(code).get_signatures(line, column - 1)
return json.dumps(_map_signatures(signatures))
+30
View File
@@ -0,0 +1,30 @@
import pybricks_jedi
def pytest_configure(config):
"""
Allows plugins and conftest files to perform initial configuration.
This hook is called for every plugin and initial conftest
file after command line options have been parsed.
"""
def pytest_sessionstart(session):
"""
Called after the Session object has been created and
before performing collection and entering the run test loop.
"""
pybricks_jedi.initialize()
def pytest_sessionfinish(session, exitstatus):
"""
Called after whole test run finished, right before
returning the exit status to the system.
"""
def pytest_unconfigure(config):
"""
called before test process is exited.
"""
+126
View File
@@ -0,0 +1,126 @@
# SPDX-License-Identifier: MIT
# Copyright (c) 2022 The Pybricks Authors
"""
Tests for correct code completion of builtins.
"""
import json
from pybricks_jedi import CompletionItem, complete
def test_empty_code():
code = ""
completions: list[CompletionItem] = json.loads(complete(code, 1, 1))
# since nothing has been imported, this is just all builtins and keywords
assert [c["insertText"] for c in completions] == [
"abs",
"all",
"any",
"ArithmeticError",
"assert",
"AssertionError",
"async",
"AttributeError",
"await",
"BaseException",
"bin",
"bool",
"break",
"bytearray",
"bytes",
"callable",
"chr",
"class",
"classmethod",
"complex",
"continue",
"def",
"del",
"dict",
"dir",
"divmod",
"enumerate",
"EOFError",
"eval",
"Exception",
"exec",
"False",
"float",
"for",
"from",
"GeneratorExit",
"getattr",
"global",
"globals",
"hasattr",
"hash",
"help",
"hex",
"id",
"if",
"import",
"ImportError",
"IndentationError",
"IndexError",
"input",
"int",
"isinstance",
"issubclass",
"iter",
"KeyboardInterrupt",
"KeyError",
"lambda",
"len",
"list",
"locals",
"LookupError",
"map",
"max",
"MemoryError",
"min",
"NameError",
"next",
"None",
"nonlocal",
"not",
"NotImplementedError",
"object",
"oct",
"ord",
"OSError",
"OverflowError",
"pass",
"pow",
"print",
"raise",
"range",
"repr",
"return",
"reversed",
"round",
"RuntimeError",
"set",
"setattr",
"slice",
"sorted",
"staticmethod",
"StopIteration",
"str",
"sum",
"super",
"SyntaxError",
"SystemExit",
"True",
"try",
"tuple",
"type",
"TypeError",
"ValueError",
"while",
"with",
"yield",
"ZeroDivisionError",
"zip",
]
+82
View File
@@ -0,0 +1,82 @@
# SPDX-License-Identifier: MIT
# Copyright (c) 2022 The Pybricks Authors
"""
Tests for correct code completion of the CityHub class.
"""
import json
from pybricks_jedi import CompletionItem, complete
IMPORT = "from pybricks.hubs import CityHub"
CREATE_INSTANCE = "hub = CityHub()"
def _create_snippet(line: str) -> str:
"""
Creates a code snippet::
from pybricks.hubs import CityHub
hub = CityHub()
{line}
Args:
line: The value substituted for ``{line}``
"""
return "\n".join((IMPORT, CREATE_INSTANCE, line))
def test_hub_dot():
line = "hub."
code = _create_snippet(line)
completions: list[CompletionItem] = json.loads(complete(code, 3, len(line) + 1))
assert [c["insertText"] for c in completions] == [
"battery",
"button",
"light",
"system",
]
def test_hub_dot_battery_dot():
line = "hub.battery."
code = _create_snippet(line)
completions: list[CompletionItem] = json.loads(complete(code, 3, len(line) + 1))
assert [c["insertText"] for c in completions] == [
"current",
"voltage",
]
def test_hub_dot_button_dot():
line = "hub.button."
code = _create_snippet(line)
completions: list[CompletionItem] = json.loads(complete(code, 3, len(line) + 1))
assert [c["insertText"] for c in completions] == [
"pressed",
]
def test_hub_dot_light_dot():
line = "hub.light."
code = _create_snippet(line)
completions: list[CompletionItem] = json.loads(complete(code, 3, len(line) + 1))
assert [c["insertText"] for c in completions] == [
"animate",
"blink",
"off",
"on",
]
def test_hub_dot_system_dot():
line = "hub.system."
code = _create_snippet(line)
completions: list[CompletionItem] = json.loads(complete(code, 3, len(line) + 1))
assert [c["insertText"] for c in completions] == [
"name",
"reset_reason",
"set_stop_button",
"shutdown",
]
+254
View File
@@ -0,0 +1,254 @@
# SPDX-License-Identifier: MIT
# Copyright (c) 2022 The Pybricks Authors
"""
Tests for correct code completion of import statements.
"""
import json
from pybricks_jedi import CompletionItem, complete
def test_from():
code = "from "
completions: list[CompletionItem] = json.loads(complete(code, 1, len(code) + 1))
# only modules included in Pybricks firmware should be listed
assert [c["insertText"] for c in completions] == [
"micropython",
"pybricks",
"uerrno",
"uio",
"umath",
"urandom",
"uselect",
"usys",
]
def test_from_pybricks_import():
code = "from pybricks import "
completions: list[CompletionItem] = json.loads(complete(code, 1, len(code) + 1))
assert [c["insertText"] for c in completions] == [
"geometry",
"hubs",
"iodevices",
"parameters",
"pupdevices",
"robotics",
"tools",
"version",
]
def test_from_pybricks_dot():
code = "from pybricks."
completions: list[CompletionItem] = json.loads(complete(code, 1, len(code) + 1))
assert [c["insertText"] for c in completions] == [
"geometry",
"hubs",
"iodevices",
"parameters",
"pupdevices",
"robotics",
"tools",
]
def test_from_pybricks_geometry_import():
code = "from pybricks.geometry import "
completions: list[CompletionItem] = json.loads(complete(code, 1, len(code) + 1))
assert [c["insertText"] for c in completions] == [
"Axis",
"Matrix",
"vector",
]
def test_from_pybricks_hubs_import():
code = "from pybricks.hubs import "
completions: list[CompletionItem] = json.loads(complete(code, 1, len(code) + 1))
assert [c["insertText"] for c in completions] == [
"CityHub",
"EV3Brick",
"InventorHub",
"MoveHub",
"PrimeHub",
"TechnicHub",
]
def test_from_pybricks_iodevices_import():
code = "from pybricks.iodevices import "
completions: list[CompletionItem] = json.loads(complete(code, 1, len(code) + 1))
assert [c["insertText"] for c in completions] == [
"AnalogSensor",
"DCMotor",
"Ev3devSensor",
"I2CDevice",
"LUMPDevice",
"LWP3Device",
"PUPDevice",
"UARTDevice",
]
def test_from_pybricks_parameters_import():
code = "from pybricks.parameters import "
completions: list[CompletionItem] = json.loads(complete(code, 1, len(code) + 1))
assert [c["insertText"] for c in completions] == [
"Button",
"Color",
"Direction",
"Icon",
"Port",
"Side",
"Stop",
]
def test_from_pybricks_pupdevices_import():
code = "from pybricks.pupdevices import "
completions: list[CompletionItem] = json.loads(complete(code, 1, len(code) + 1))
assert [c["insertText"] for c in completions] == [
"ColorDistanceSensor",
"ColorLightMatrix",
"ColorSensor",
"DCMotor",
"ForceSensor",
"InfraredSensor",
"Light",
"Motor",
"PFMotor",
"Remote",
"TiltSensor",
"UltrasonicSensor",
]
def test_from_pybricks_robotics_import():
code = "from pybricks.robotics import "
completions: list[CompletionItem] = json.loads(complete(code, 1, len(code) + 1))
assert [c["insertText"] for c in completions] == [
"DriveBase",
]
def test_from_pybricks_tools_import():
code = "from pybricks.tools import "
completions: list[CompletionItem] = json.loads(complete(code, 1, len(code) + 1))
assert [c["insertText"] for c in completions] == [
"DataLog",
"StopWatch",
"wait",
]
def test_from_micropython_import():
code = "from micropython import "
completions: list[CompletionItem] = json.loads(complete(code, 1, len(code) + 1))
assert [c["insertText"] for c in completions] == [
"const",
"kbd_intr",
"mem_info",
"opt_level",
"qstr_info",
"stack_use",
]
def test_from_uerrno_import():
code = "from uerrno import "
completions: list[CompletionItem] = json.loads(complete(code, 1, len(code) + 1))
assert [c["insertText"] for c in completions] == [
"EAGAIN",
"EBUSY",
"ECANCELED",
"EINVAL",
"EIO",
"ENODEV",
"EOPNOTSUPP",
"EPERM",
"errorcode",
"ETIMEDOUT",
]
def test_from_uio_import():
code = "from uio import "
completions: list[CompletionItem] = json.loads(complete(code, 1, len(code) + 1))
assert [c["insertText"] for c in completions] == [
"BytesIO",
"FileIO",
"StringIO",
]
def test_from_umath_import():
code = "from umath import "
completions: list[CompletionItem] = json.loads(complete(code, 1, len(code) + 1))
assert [c["insertText"] for c in completions] == [
"acos",
"asin",
"atan",
"atan2",
"ceil",
"copysign",
"cos",
"degrees",
"e",
"exp",
"fabs",
"floor",
"fmod",
"frexp",
"isfinite",
"isinfinite",
"isnan",
"ldexp",
"log",
"modf",
"pi",
"pow",
"radians",
"sin",
"sqrt",
"tan",
"trunc",
]
def test_from_urandom_import():
code = "from urandom import "
completions: list[CompletionItem] = json.loads(complete(code, 1, len(code) + 1))
assert [c["insertText"] for c in completions] == [
"choice",
"getrandbits",
"randint",
"random",
"randrange",
"seed",
"uniform",
]
def test_from_uselect_import():
code = "from uselect import "
completions: list[CompletionItem] = json.loads(complete(code, 1, len(code) + 1))
assert [c["insertText"] for c in completions] == [
"poll",
"Poll",
"POLLERR",
"POLLHUP",
"POLLIN",
"POLLOUT",
]
def test_from_usys_import():
code = "from usys import "
completions: list[CompletionItem] = json.loads(complete(code, 1, len(code) + 1))
assert [c["insertText"] for c in completions] == [
"stderr",
"stdin",
"stdout",
]
+327
View File
@@ -0,0 +1,327 @@
# SPDX-License-Identifier: MIT
# Copyright (c) 2022 The Pybricks Authors
"""
Tests for correct code completion of the InventorHub class.
"""
import json
from pybricks_jedi import SignatureHelp, complete, get_signatures, CompletionItem
IMPORT = "from pybricks.hubs import InventorHub"
CREATE_INSTANCE = "hub = InventorHub()"
def _create_snippet(line: str) -> str:
"""
Creates a code snippet::
from pybricks.hubs import InventorHub
hub = InventorHub()
{line}
Args:
line: The value substituted for ``{line}``
"""
return "\n".join((IMPORT, CREATE_INSTANCE, line))
def test_hub_dot():
line = "hub."
code = _create_snippet(line)
completions: list[CompletionItem] = json.loads(complete(code, 3, len(line) + 1))
assert [c["insertText"] for c in completions] == [
"battery",
"buttons",
"charger",
"display",
"imu",
"light",
"speaker",
"system",
]
def test_hub_dot_battery_dot():
line = "hub.battery."
code = _create_snippet(line)
completions: list[CompletionItem] = json.loads(complete(code, 3, len(line) + 1))
assert [c["insertText"] for c in completions] == [
"current",
"voltage",
]
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)
completions: list[CompletionItem] = json.loads(complete(code, 3, len(line) + 1))
assert [c["insertText"] for c in completions] == [
"pressed",
]
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)
completions: list[CompletionItem] = json.loads(complete(code, 3, len(line) + 1))
assert [c["insertText"] for c in completions] == [
"connected",
"current",
"status",
]
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)
completions: list[CompletionItem] = json.loads(complete(code, 3, len(line) + 1))
assert [c["insertText"] for c in completions] == [
"animate",
"char",
"image",
"number",
"off",
"orientation",
"pixel",
"text",
]
def test_hub_dot_imu_dot():
line = "hub.imu."
code = _create_snippet(line)
completions: list[CompletionItem] = json.loads(complete(code, 3, len(line) + 1))
assert [c["insertText"] for c in completions] == [
"acceleration",
"angular_velocity",
"heading",
"reset_heading",
"tilt",
"up",
]
def test_hub_dot_light_dot():
line = "hub.light."
code = _create_snippet(line)
completions: list[CompletionItem] = json.loads(complete(code, 3, len(line) + 1))
assert [c["insertText"] for c in completions] == [
"animate",
"blink",
"off",
"on",
]
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)
completions: list[CompletionItem] = json.loads(complete(code, 3, len(line) + 1))
assert [c["insertText"] for c in completions] == [
"beep",
"play_notes",
"volume",
]
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)
completions: list[CompletionItem] = json.loads(complete(code, 3, len(line) + 1))
assert [c["insertText"] for c in completions] == [
"name",
"reset_reason",
"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]
+93
View File
@@ -0,0 +1,93 @@
# SPDX-License-Identifier: MIT
# Copyright (c) 2022 The Pybricks Authors
"""
Tests for correct code completion of the MoveHub class.
"""
import json
from pybricks_jedi import CompletionItem, complete
IMPORT = "from pybricks.hubs import MoveHub"
CREATE_INSTANCE = "hub = MoveHub()"
def _create_snippet(line: str) -> str:
"""
Creates a code snippet::
from pybricks.hubs import MoveHub
hub = MoveHub()
{line}
Args:
line: The value substituted for ``{line}``
"""
return "\n".join((IMPORT, CREATE_INSTANCE, line))
def test_hub_dot():
line = "hub."
code = _create_snippet(line)
completions: list[CompletionItem] = json.loads(complete(code, 3, len(line) + 1))
assert [c["insertText"] for c in completions] == [
"battery",
"button",
"imu",
"light",
"system",
]
def test_hub_dot_battery_dot():
line = "hub.battery."
code = _create_snippet(line)
completions: list[CompletionItem] = json.loads(complete(code, 3, len(line) + 1))
assert [c["insertText"] for c in completions] == [
"current",
"voltage",
]
def test_hub_dot_button_dot():
line = "hub.button."
code = _create_snippet(line)
completions: list[CompletionItem] = json.loads(complete(code, 3, len(line) + 1))
assert [c["insertText"] for c in completions] == [
"pressed",
]
def test_hub_dot_imu_dot():
line = "hub.imu."
code = _create_snippet(line)
completions: list[CompletionItem] = json.loads(complete(code, 3, len(line) + 1))
assert [c["insertText"] for c in completions] == [
"acceleration",
"up",
]
def test_hub_dot_light_dot():
line = "hub.light."
code = _create_snippet(line)
completions: list[CompletionItem] = json.loads(complete(code, 3, len(line) + 1))
assert [c["insertText"] for c in completions] == [
"animate",
"blink",
"off",
"on",
]
def test_hub_dot_system_dot():
line = "hub.system."
code = _create_snippet(line)
completions: list[CompletionItem] = json.loads(complete(code, 3, len(line) + 1))
assert [c["insertText"] for c in completions] == [
"name",
"reset_reason",
"set_stop_button",
"shutdown",
]
+138
View File
@@ -0,0 +1,138 @@
# SPDX-License-Identifier: MIT
# Copyright (c) 2022 The Pybricks Authors
"""
Tests for correct code completion of the PrimeHub class.
"""
import json
from pybricks_jedi import CompletionItem, complete
IMPORT = "from pybricks.hubs import PrimeHub"
CREATE_INSTANCE = "hub = PrimeHub()"
def _create_snippet(line: str) -> str:
"""
Creates a code snippet::
from pybricks.hubs import PrimeHub
hub = PrimeHub()
{line}
Args:
line: The value substituted for ``{line}``
"""
return "\n".join((IMPORT, CREATE_INSTANCE, line))
def test_hub_dot():
line = "hub."
code = _create_snippet(line)
completions: list[CompletionItem] = json.loads(complete(code, 3, len(line) + 1))
assert [c["insertText"] for c in completions] == [
"battery",
"buttons",
"charger",
"display",
"imu",
"light",
"speaker",
"system",
]
def test_hub_dot_battery_dot():
line = "hub.battery."
code = _create_snippet(line)
completions: list[CompletionItem] = json.loads(complete(code, 3, len(line) + 1))
assert [c["insertText"] for c in completions] == [
"current",
"voltage",
]
def test_hub_dot_buttons_dot():
line = "hub.buttons."
code = _create_snippet(line)
completions: list[CompletionItem] = json.loads(complete(code, 3, len(line) + 1))
assert [c["insertText"] for c in completions] == [
"pressed",
]
def test_hub_dot_charger_dot():
line = "hub.charger."
code = _create_snippet(line)
completions: list[CompletionItem] = json.loads(complete(code, 3, len(line) + 1))
assert [c["insertText"] for c in completions] == [
"connected",
"current",
"status",
]
def test_hub_dot_display_dot():
line = "hub.display."
code = _create_snippet(line)
completions: list[CompletionItem] = json.loads(complete(code, 3, len(line) + 1))
assert [c["insertText"] for c in completions] == [
"animate",
"char",
"image",
"number",
"off",
"orientation",
"pixel",
"text",
]
def test_hub_dot_imu_dot():
line = "hub.imu."
code = _create_snippet(line)
completions: list[CompletionItem] = json.loads(complete(code, 3, len(line) + 1))
assert [c["insertText"] for c in completions] == [
"acceleration",
"angular_velocity",
"heading",
"reset_heading",
"tilt",
"up",
]
def test_hub_dot_light_dot():
line = "hub.light."
code = _create_snippet(line)
completions: list[CompletionItem] = json.loads(complete(code, 3, len(line) + 1))
assert [c["insertText"] for c in completions] == [
"animate",
"blink",
"off",
"on",
]
def test_hub_dot_speaker_dot():
line = "hub.speaker."
code = _create_snippet(line)
completions: list[CompletionItem] = json.loads(complete(code, 3, len(line) + 1))
assert [c["insertText"] for c in completions] == [
"beep",
"play_notes",
"volume",
]
def test_hub_dot_system_dot():
line = "hub.system."
code = _create_snippet(line)
completions: list[CompletionItem] = json.loads(complete(code, 3, len(line) + 1))
assert [c["insertText"] for c in completions] == [
"name",
"reset_reason",
"set_stop_button",
"shutdown",
]
+97
View File
@@ -0,0 +1,97 @@
# SPDX-License-Identifier: MIT
# Copyright (c) 2022 The Pybricks Authors
"""
Tests for correct code completion of the TechnicHub class.
"""
import json
from pybricks_jedi import CompletionItem, complete
IMPORT = "from pybricks.hubs import TechnicHub"
CREATE_INSTANCE = "hub = TechnicHub()"
def _create_snippet(line: str) -> str:
"""
Creates a code snippet::
from pybricks.hubs import TechnicHub
hub = TechnicHub()
{line}
Args:
line: The value substituted for ``{line}``
"""
return "\n".join((IMPORT, CREATE_INSTANCE, line))
def test_hub_dot():
line = "hub."
code = _create_snippet(line)
completions: list[CompletionItem] = json.loads(complete(code, 3, len(line) + 1))
assert [c["insertText"] for c in completions] == [
"battery",
"button",
"imu",
"light",
"system",
]
def test_hub_dot_battery_dot():
line = "hub.battery."
code = _create_snippet(line)
completions: list[CompletionItem] = json.loads(complete(code, 3, len(line) + 1))
assert [c["insertText"] for c in completions] == [
"current",
"voltage",
]
def test_hub_dot_button_dot():
line = "hub.button."
code = _create_snippet(line)
completions: list[CompletionItem] = json.loads(complete(code, 3, len(line) + 1))
assert [c["insertText"] for c in completions] == [
"pressed",
]
def test_hub_dot_imu_dot():
line = "hub.imu."
code = _create_snippet(line)
completions: list[CompletionItem] = json.loads(complete(code, 3, len(line) + 1))
assert [c["insertText"] for c in completions] == [
"acceleration",
"angular_velocity",
"heading",
"reset_heading",
"tilt",
"up",
]
def test_hub_dot_light_dot():
line = "hub.light."
code = _create_snippet(line)
completions: list[CompletionItem] = json.loads(complete(code, 3, len(line) + 1))
assert [c["insertText"] for c in completions] == [
"animate",
"blink",
"off",
"on",
]
def test_hub_dot_system_dot():
line = "hub.system."
code = _create_snippet(line)
completions: list[CompletionItem] = json.loads(complete(code, 3, len(line) + 1))
assert [c["insertText"] for c in completions] == [
"name",
"reset_reason",
"set_stop_button",
"shutdown",
]
+1 -1
View File
@@ -1,6 +1,6 @@
[flake8]
exclude = .venv/,*.pyi
exclude = .venv/,*.pyi,jedi/
max-line-length = 88
ignore = E203,W503
+13 -6
View File
@@ -4,16 +4,23 @@
"""Generic cross-platform module for typical devices like lights, displays,
speakers, and batteries."""
from typing import Union, Iterable, overload, Optional, Tuple, Collection
from __future__ import annotations
from typing import Union, Iterable, overload, Optional, Tuple, Collection, TYPE_CHECKING
from .geometry import Matrix, Axis
from .parameters import Direction, Stop, Button, Port, Color, Side, Number
from .parameters import Direction, Stop, Button, Port, Color, Side
if TYPE_CHECKING:
from .parameters import Number
class System:
"""System control actions for a hub."""
def set_stop_button(self, button: Union[Button, Iterable[Button]]) -> None:
def set_stop_button(
self, button: Optional[Union[Button, Iterable[Button]]]
) -> None:
"""
set_stop_button(button)
@@ -62,7 +69,7 @@ class System:
"""
class CommonDCMotor:
class DCMotor:
"""Generic class to control simple motors without rotation sensors, such
as train motors."""
@@ -289,7 +296,7 @@ class Control:
"""
class CommonMotor(CommonDCMotor):
class Motor(DCMotor):
"""Generic class to control motors with built-in rotation sensors."""
control = Control()
@@ -897,7 +904,7 @@ class IMU(Accelerometer):
"""
def reset_heading(self, angle: Number) -> None:
"""reset_heading(angle: Number)
"""reset_heading(angle)
Resets the accumulated heading angle of the robot.
+18 -11
View File
@@ -5,18 +5,23 @@
from typing import Optional, Tuple, List
from ._common import CommonMotor
from .parameters import Direction, Port, Color, Button
from . import _common
from .parameters import (
Button as _Button,
Color as _Color,
Direction as _Direction,
Port as _Port,
)
class Motor(CommonMotor):
class Motor(_common.Motor):
"""LEGO® MINDSTORMS® EV3 Motor."""
class TouchSensor:
"""LEGO® MINDSTORMS® EV3 Touch Sensor."""
def __init__(self, port: Port):
def __init__(self, port: _Port):
"""TouchSensor(port)
Arguments:
@@ -37,14 +42,14 @@ class TouchSensor:
class ColorSensor:
"""LEGO® MINDSTORMS® EV3 Color Sensor."""
def __init__(self, port: Port):
def __init__(self, port: _Port):
"""ColorSensor(port)
Arguments:
port (Port): Port to which the sensor is connected.
"""
def color(self) -> Optional[Color]:
def color(self) -> Optional[_Color]:
"""color() -> Color
Measures the color of a surface.
@@ -92,7 +97,7 @@ class ColorSensor:
class InfraredSensor:
"""LEGO® MINDSTORMS® EV3 Infrared Sensor and Beacon."""
def __init__(self, port: Port):
def __init__(self, port: _Port):
"""InfraredSensor(port)
Arguments:
@@ -129,7 +134,7 @@ class InfraredSensor:
a tuple of (``None``, ``None``) if no remote is detected.
"""
def buttons(self, channel: int) -> List[Button]:
def buttons(self, channel: int) -> List[_Button]:
"""buttons(channel) -> List[Button]
Checks which buttons on the infrared remote are pressed.
@@ -145,7 +150,7 @@ class InfraredSensor:
"""
def keypad(self) -> List[Button]:
def keypad(self) -> List[_Button]:
"""keypad() -> List[Button]
Checks which buttons on the infrared remote are pressed.
@@ -163,7 +168,9 @@ class InfraredSensor:
class GyroSensor:
"""LEGO® MINDSTORMS® EV3 Gyro Sensor."""
def __init__(self, port: Port, positive_direction: Direction = Direction.CLOCKWISE):
def __init__(
self, port: _Port, positive_direction: _Direction = _Direction.CLOCKWISE
):
"""GyroSensor(port)
Arguments:
@@ -207,7 +214,7 @@ class GyroSensor:
class UltrasonicSensor:
"""LEGO® MINDSTORMS® EV3 Ultrasonic Sensor."""
def __init__(self, port: Port):
def __init__(self, port: _Port):
"""UltrasonicSensor(port)
Arguments:
+47 -57
View File
@@ -2,21 +2,11 @@
# Copyright (c) 2018-2020 The Pybricks Authors
"""LEGO® Programmable Hubs."""
from ._common import (
Speaker,
Battery,
ColorLight,
Keypad,
LightMatrix,
IMU,
Charger,
System,
SimpleAccelerometer,
)
from .ev3dev._speaker import Speaker as EV3Speaker
from .geometry import Axis
from .media.ev3dev import Image
from .parameters import Button
from . import _common
from .ev3dev import _speaker
from .geometry import Axis as _Axis
from .media.ev3dev import Image as _Image
from .parameters import Button as _Button
class EV3Brick:
@@ -24,19 +14,19 @@ class EV3Brick:
# These class attributes are here for auto-documentation only.
# In reality, they are instance attributes created by __init__.
buttons = Keypad(
(
Button.LEFT,
Button.RIGHT,
Button.CENTER,
Button.UP,
Button.DOWN,
)
buttons = _common.Keypad(
[
_Button.LEFT,
_Button.RIGHT,
_Button.CENTER,
_Button.UP,
_Button.DOWN,
]
)
screen = Image("_screen_")
speaker = EV3Speaker()
battery = Battery()
light = ColorLight()
screen = _Image("_screen_")
speaker = _speaker.Speaker()
battery = _common.Battery()
light = _common.ColorLight()
class MoveHub:
@@ -44,11 +34,11 @@ class MoveHub:
# These class attributes are here for auto-documentation only.
# In reality, they are instance attributes created by __init__.
battery = Battery()
light = ColorLight()
imu = SimpleAccelerometer()
system = System()
button = Keypad((Button.CENTER,))
battery = _common.Battery()
light = _common.ColorLight()
imu = _common.SimpleAccelerometer()
system = _common.System()
button = _common.Keypad([_Button.CENTER])
class CityHub:
@@ -56,10 +46,10 @@ class CityHub:
# These class attributes are here for auto-documentation only.
# In reality, they are instance attributes created by __init__.
battery = Battery()
light = ColorLight()
system = System()
button = Keypad((Button.CENTER,))
battery = _common.Battery()
light = _common.ColorLight()
system = _common.System()
button = _common.Keypad([_Button.CENTER])
class TechnicHub:
@@ -67,13 +57,13 @@ class TechnicHub:
# These class attributes are here for auto-documentation only.
# In reality, they are instance attributes created by __init__.
battery = Battery()
light = ColorLight()
imu = IMU()
system = System()
button = Keypad((Button.CENTER,))
battery = _common.Battery()
light = _common.ColorLight()
imu = _common.IMU()
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
@@ -94,23 +84,23 @@ class PrimeHub:
# These class attributes are here for auto-documentation only.
# In reality, they are instance attributes created by __init__.
battery = Battery()
buttons = Keypad(
(
Button.LEFT,
Button.RIGHT,
Button.CENTER,
Button.BLUETOOTH,
)
battery = _common.Battery()
buttons = _common.Keypad(
[
_Button.LEFT,
_Button.RIGHT,
_Button.CENTER,
_Button.BLUETOOTH,
]
)
charger = Charger()
light = ColorLight()
display = LightMatrix(5, 5)
speaker = Speaker()
imu = IMU()
system = System()
charger = _common.Charger()
light = _common.ColorLight()
display = _common.LightMatrix(5, 5)
speaker = _common.Speaker()
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
+9 -9
View File
@@ -5,14 +5,14 @@
from typing import Dict, Tuple, Optional, overload
from ._common import CommonDCMotor
from .parameters import Port
from . import _common
from .parameters import Port as _Port
class PUPDevice:
"""Powered Up motor or sensor."""
def __init__(self, port: Port):
def __init__(self, port: _Port):
"""PUPDevice(port)
Arguments:
@@ -55,7 +55,7 @@ class PUPDevice:
class LUMPDevice:
"""Devices using the LEGO UART Messaging Protocol."""
def __init__(self, port: Port):
def __init__(self, port: _Port):
"""LUMPDevice(port)
Arguments:
@@ -75,7 +75,7 @@ class LUMPDevice:
"""
class DCMotor(CommonDCMotor):
class DCMotor(_common.DCMotor):
"""DC Motor for LEGO® MINDSTORMS EV3."""
@@ -88,7 +88,7 @@ class Ev3devSensor:
port_index: int
"""Index of the ev3dev sysfs `lego-port`_ class."""
def __init__(self, port: Port):
def __init__(self, port: _Port):
"""Ev3devSensor(port)
Arguments:
@@ -111,7 +111,7 @@ class Ev3devSensor:
class AnalogSensor:
"""Generic or custom analog sensor."""
def __init__(self, port: Port):
def __init__(self, port: _Port):
"""AnalogSensor(port)
Arguments:
@@ -167,7 +167,7 @@ class AnalogSensor:
class I2CDevice:
"""Generic or custom I2C device."""
def __init__(self, port: Port, address: int):
def __init__(self, port: _Port, address: int):
"""I2CDevice(port, address)
Arguments:
@@ -205,7 +205,7 @@ class I2CDevice:
class UARTDevice:
"""Generic UART device."""
def __init__(self, port: Port, baudrate: int, timeout: Optional[int] = None):
def __init__(self, port: _Port, baudrate: int, timeout: Optional[int] = None):
"""UARTDevice(port, baudrate, timeout=None)
Arguments:
+60 -39
View File
@@ -6,12 +6,33 @@
from __future__ import annotations
from enum import Enum
from typing import Union
from typing import Union, TYPE_CHECKING
import os
from .geometry import Matrix as _Matrix
from .geometry import Matrix
if TYPE_CHECKING or os.environ["SPHINX_BUILD"] == "True":
Number = Union[int, float]
"""
Numbers can be represented as integers or floating point values:
Number = Union[int, float]
* Integers (:class:`int <ubuiltins.int>`) are whole numbers
like ``15`` or ``-123``.
* Floating point values (:class:`float <ubuiltins.float>`) are decimal
numbers like ``3.14`` or ``-123.45``.
If you see :class:`Number` as the argument type, both
:class:`int <ubuiltins.int>` and :class:`float <ubuiltins.float>` may be used.
For example, :func:`wait(15) <pybricks.tools.wait>` and
:func:`wait(15.75) <pybricks.tools.wait>` are both allowed. In most functions,
however, your input value will be truncated to a whole number anyway. In this
example, either command makes the program pause for just 15 milliseconds.
.. warning::
The BOOST Move hub doesn't support floating point numbers due to
limited system resources, so only integers can be used on that hub.
"""
class _PybricksEnumMeta(type(Enum)):
@@ -163,39 +184,39 @@ class Side(_PybricksEnum):
class Icon:
UP: Matrix
DOWN: Matrix
LEFT: Matrix
RIGHT: Matrix
ARROW_RIGHT_UP: Matrix
ARROW_RIGHT_DOWN: Matrix
ARROW_LEFT_UP: Matrix
ARROW_LEFT_DOWN: Matrix
ARROW_UP: Matrix
ARROW_DOWN: Matrix
ARROW_LEFT: Matrix
ARROW_RIGHT: Matrix
HAPPY: Matrix
SAD: Matrix
EYE_LEFT: Matrix
EYE_RIGHT: Matrix
EYE_LEFT_BLINK: Matrix
EYE_RIGHT_BLINK: Matrix
EYE_RIGHT_BROW: Matrix
EYE_LEFT_BROW: Matrix
EYE_LEFT_BROW_UP: Matrix
EYE_RIGHT_BROW_UP: Matrix
HEART: Matrix
PAUSE: Matrix
EMPTY: Matrix
FULL: Matrix
SQUARE: Matrix
TRIANGLE_RIGHT: Matrix
TRIANGLE_LEFT: Matrix
TRIANGLE_UP: Matrix
TRIANGLE_DOWN: Matrix
CIRCLE: Matrix
CLOCKWISE: Matrix
COUNTERCLOCKWISE: Matrix
TRUE: Matrix
FALSE: Matrix
UP: _Matrix
DOWN: _Matrix
LEFT: _Matrix
RIGHT: _Matrix
ARROW_RIGHT_UP: _Matrix
ARROW_RIGHT_DOWN: _Matrix
ARROW_LEFT_UP: _Matrix
ARROW_LEFT_DOWN: _Matrix
ARROW_UP: _Matrix
ARROW_DOWN: _Matrix
ARROW_LEFT: _Matrix
ARROW_RIGHT: _Matrix
HAPPY: _Matrix
SAD: _Matrix
EYE_LEFT: _Matrix
EYE_RIGHT: _Matrix
EYE_LEFT_BLINK: _Matrix
EYE_RIGHT_BLINK: _Matrix
EYE_RIGHT_BROW: _Matrix
EYE_LEFT_BROW: _Matrix
EYE_LEFT_BROW_UP: _Matrix
EYE_RIGHT_BROW_UP: _Matrix
HEART: _Matrix
PAUSE: _Matrix
EMPTY: _Matrix
FULL: _Matrix
SQUARE: _Matrix
TRIANGLE_RIGHT: _Matrix
TRIANGLE_LEFT: _Matrix
TRIANGLE_UP: _Matrix
TRIANGLE_DOWN: _Matrix
CIRCLE: _Matrix
CLOCKWISE: _Matrix
COUNTERCLOCKWISE: _Matrix
TRUE: _Matrix
FALSE: _Matrix
+40 -38
View File
@@ -3,25 +3,27 @@
"""LEGO® Powered Up motor, sensors, and lights."""
from typing import Collection, Optional, Union, overload, Tuple
from __future__ import annotations
from ._common import (
AmbientColorSensor,
ColorLight,
CommonColorSensor,
CommonDCMotor,
CommonMotor,
Keypad,
LightArray,
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, Port
if TYPE_CHECKING:
from .parameters import Number as _Number
class DCMotor(CommonDCMotor):
class DCMotor(_common.DCMotor):
"""LEGO® Powered Up motor without rotation sensors."""
class Motor(CommonMotor):
class Motor(_common.Motor):
"""LEGO® Powered Up motor with rotation sensors."""
def reset_angle(self, angle: Optional[int]) -> None:
@@ -40,21 +42,21 @@ class Motor(CommonMotor):
class Remote:
"""LEGO® Powered Up Bluetooth Remote Control."""
light = ColorLight()
buttons = Keypad(
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]
def __init__(self, name: str = None, timeout: int = 10000):
def __init__(self, name: Optional[str] = None, timeout: int = 10000):
"""Remote(name=None, timeout=10000)
When you instantiate this class, the hub will search for a remote
@@ -92,7 +94,7 @@ class Remote:
class TiltSensor:
"""LEGO® Powered Up Tilt Sensor."""
def __init__(self, port: Port):
def __init__(self, port: _Port):
"""TiltSensor(port)
Arguments:
@@ -109,10 +111,10 @@ class TiltSensor:
"""
class ColorDistanceSensor(CommonColorSensor):
class ColorDistanceSensor(_common.CommonColorSensor):
"""LEGO® Powered Up Color and Distance Sensor."""
light = ColorLight()
light = _common.ColorLight()
def distance(self) -> int:
"""distance() -> int: %
@@ -133,8 +135,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)
@@ -152,18 +154,18 @@ class PFMotor(DCMotor):
"""
class ColorSensor(AmbientColorSensor):
class ColorSensor(_common.AmbientColorSensor):
"""LEGO® SPIKE Color Sensor."""
lights = LightArray(3)
lights = _common.LightArray(3)
class UltrasonicSensor:
"""LEGO® SPIKE Color Sensor."""
lights = LightArray(3)
lights = _common.LightArray(3)
def __init__(self, port: Port):
def __init__(self, port: _Port):
"""UltrasonicSensor(port)
Arguments:
@@ -197,7 +199,7 @@ class UltrasonicSensor:
class ForceSensor:
"""LEGO® SPIKE Force Sensor."""
def __init__(self, port: Port):
def __init__(self, port: _Port):
"""ForceSensor(port)
Arguments:
@@ -222,7 +224,7 @@ class ForceSensor:
Movement up to approximately 8.00 mm.
"""
def pressed(self, force=3) -> bool:
def pressed(self, force: _Number = 3) -> bool:
"""pressed(force=3) -> bool
Checks if the sensor button is pressed.
@@ -253,7 +255,7 @@ class ColorLightMatrix:
LEGO® SPIKE 3x3 Color Light Matrix.
"""
def __init__(self, port: Port):
def __init__(self, port: _Port):
"""ColorLightMatrix(port)
Arguments:
@@ -262,7 +264,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.
@@ -286,7 +288,7 @@ class ColorLightMatrix:
class InfraredSensor:
"""LEGO® Powered Up Infrared Sensor."""
def __init__(self, port: Port):
def __init__(self, port: _Port):
"""InfraredSensor(port)
Arguments:
@@ -326,14 +328,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: int = 100) -> None:
def on(self, brightness: _Number = 100) -> None:
"""on(brightness=100)
Turns on the light at the specified brightness.
+24 -17
View File
@@ -3,10 +3,15 @@
"""Robotics module for the Pybricks API."""
from typing import Tuple, Optional, overload
from __future__ import annotations
from ._common import Control, CommonMotor as Motor
from .parameters import Stop, Number
from typing import Tuple, Optional, overload, TYPE_CHECKING
from . import _common
from .parameters import Stop as _Stop
if TYPE_CHECKING:
from .parameters import Number as _Number
class DriveBase:
@@ -26,7 +31,7 @@ class DriveBase:
"""
distance_control = Control()
distance_control = _common.Control()
"""The traveled distance and drive speed are controlled by a PID
controller. You can use this attribute to change its settings.
See the :ref:`motor control <settings>` attribute for an overview of
@@ -34,7 +39,7 @@ class DriveBase:
functionality, but the settings apply to every millimeter driven by the
drive base, instead of degrees turned by one motor."""
heading_control = Control()
heading_control = _common.Control()
"""The robot turn angle and turn rate are controlled by a PID
controller. You can use this attribute to change its settings.
See the :ref:`motor control <settings>` attribute for an overview of
@@ -45,10 +50,10 @@ class DriveBase:
def __init__(
self,
left_motor: Motor,
right_motor: Motor,
wheel_diameter: Number,
axle_track: Number,
left_motor: _common.Motor,
right_motor: _common.Motor,
wheel_diameter: _Number,
axle_track: _Number,
):
"""DriveBase(left_motor, right_motor, wheel_diameter, axle_track)
@@ -62,7 +67,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
@@ -113,10 +118,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],
straight_acceleration: Optional[_Number],
turn_rate: Optional[_Number],
turn_acceleration: Optional[_Number],
) -> None:
...
@@ -142,7 +147,7 @@ class DriveBase:
deceleration of the robot.
"""
def straight(self, distance, then=Stop.HOLD, wait=True) -> None:
def straight(self, distance: _Number, then=_Stop.HOLD, wait=True) -> None:
"""straight(distance, then=Stop.HOLD, wait=True)
Drives straight for a given distance and then stops.
@@ -154,7 +159,7 @@ class DriveBase:
with the rest of the program.
"""
def turn(self, angle, then=Stop.HOLD, wait=True) -> None:
def turn(self, angle: _Number, then=_Stop.HOLD, wait=True) -> None:
"""turn(angle, then=Stop.HOLD, wait=True)
Turns in place by a given angle and then stops.
@@ -166,7 +171,9 @@ class DriveBase:
with the rest of the program.
"""
def curve(self, radius, angle, then=Stop.HOLD, wait=True) -> None:
def curve(
self, radius: _Number, angle: _Number, then=_Stop.HOLD, wait=True
) -> None:
"""curve(radius, angle, then=Stop.HOLD, wait=True)
Drives an arc along a circle of a given radius, by a given angle.
-8
View File
@@ -25,14 +25,6 @@ This module implements pseudo-random number generators.
from typing import Any, Optional, Sequence, overload
[
"random",
"uniform",
]
# bookkeeping
def seed(a: Optional[int] = None) -> None:
"""
Initialize the random number generator.
+4 -4
View File
@@ -9,11 +9,11 @@
This module provides a subset of the standard Python ``sys`` module.
"""
from uio import FileIO
from uio import FileIO as _FileIO
# REVISIT: most functions are excluded since they aren't useful for Pybricks
stdin: FileIO = FileIO()
stdin: _FileIO = _FileIO()
"""
Stream object (:class:`uio.FileIO`) that receives input from a connected
terminal, if any.
@@ -25,7 +25,7 @@ Also see :func:`micropython.kbd_intr` to disable ``KeyboardInterrupt`` if you
are passing binary data via ``stdin``.
"""
stdout: FileIO = FileIO()
stdout: _FileIO = _FileIO()
"""
Stream object (:class:`uio.FileIO`) that sends output to a connected terminal,
if any.
@@ -34,7 +34,7 @@ Reading may modify newline characters. Use ``usys.stdout.buffer`` instead if
this is undesirable.
"""
stderr: FileIO = FileIO()
stderr: _FileIO = _FileIO()
"""
Alias for :data:`stdout`.
"""