Compare commits

...
Author SHA1 Message Date
David Lechner 37cdd2a83b v3.2.0b1-r2 2022-06-24 15:14:42 -05:00
David Lechner a2d9c33eb5 jedi: add new pybricks_jedi package
This package will be used in Pybricks Code to provide some intellesense
operations.
2022-06-24 14:52:45 -05:00
Laurens Valk 6d0de1effa doc/main: Drop beta tag.
Less variants is better. Now we'll just have to add beta support for SPIKE in the next release.

Fixes https://github.com/pybricks/pybricks-api/issues/102
2022-06-10 11:31:08 +02:00
Laurens Valk 8e7fc53974 doc/main: Disable NXT and EV3 pages again.
Now that all typehints have been added, we can
revert commit 4c583a9d4e again.
2022-06-10 11:20:32 +02:00
Laurens Valk e456c8ef91 pybricks: Drop underscores on imports.
Fixes https://github.com/pybricks/pybricks-api/issues/101
2022-06-10 11:10:20 +02:00
Laurens Valk 6500440031 pybricks: Drop most ellipsis and pass instances.
See [1]: "I still prefer ... over pass. This clarifies to the readers that they are reading a stub. But if there's a docstring we need neither."

[1] https://github.com/srittau/type-stub-pep/issues/88#issuecomment-758843441

Fixes https://github.com/pybricks/pybricks-api/issues/101#issuecomment-1148780369
2022-06-10 10:46:44 +02:00
Laurens Valk 8ec1b18629 pybricks.parameters: Add typing, part 2. 2022-06-10 10:33:33 +02:00
Laurens Valk 26908040eb pybricks.common: Add CommonColorSensor class.
Fixes https://github.com/pybricks/pybricks-api/issues/103
2022-06-10 10:05:13 +02:00
Laurens Valk f67c98105a pybricks.parameters: Add typing, part 1. 2022-06-10 10:05:13 +02:00
Laurens Valk 877391dea7 pybricks.parameters: Add typing. 2022-06-10 10:05:13 +02:00
Laurens Valk fb3446ad0d pybricks.robotics: Add typing. 2022-06-10 10:05:12 +02:00
Laurens Valk 31256d70c1 pybricks.tools: Add typing. 2022-06-10 10:05:12 +02:00
Laurens Valk f87e1b48ac pybricks.messaging: Add typing. 2022-06-10 10:05:12 +02:00
Laurens Valk 6bcf6117c3 pybricks.hubs: Add typing. 2022-06-10 10:05:11 +02:00
Laurens Valk c77682f50d pybricks.iodevices: Add typing. 2022-06-10 10:05:11 +02:00
Laurens Valk 4c583a9d4e doc/main: Enable NXT and EV3 pages.
This will help us review the pages as we add typing to the documentation. Then they will be hidden again.

This commit can be cherry-picked later on if we ever enable NXT and EV3 content again.
2022-06-10 10:05:10 +02:00
Laurens Valk 0688b8dded doc/common/conf.py: Add missing units.
These are used for NXT sensors.
2022-06-10 10:05:10 +02:00
Laurens Valk d1a4327751 pybricks.ev3dev.media: Type file classes. 2022-06-10 10:05:10 +02:00
Laurens Valk 4aec24a051 pybricks.ev3dev.media: Type Font class. 2022-06-10 10:05:09 +02:00
Laurens Valk 7bc995d0b6 pybricks.ev3dev.media: Type Image class. 2022-06-10 10:05:09 +02:00
Laurens Valk 725a07e6e1 pybricks.ev3dev._speaker: Add typing. 2022-06-10 10:05:09 +02:00
David Lechner d43bf94720 v3.2.0b1-r1 2022-06-09 19:31:04 -05:00
David Lechner c6163fcc81 pybricks: add __init__.py
This file was missing which breaks some tools that don't know about
namespace packages. Also `from pybricks import version` is a thing.
2022-06-09 19:25:44 -05:00
David Lechner 34992d5b20 vscode: drop deprecated setting
This setting no longer has any effect.
2022-06-09 19:25:21 -05:00
50 changed files with 3307 additions and 1849 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 -1
View File
@@ -1,5 +1,5 @@
{
"python.pythonPath": "${workspaceFolder}/.venv",
"python.autoComplete.extraPaths": ["jedi/src"],
"python.formatting.provider": "black",
"python.linting.pylintEnabled": false,
"python.linting.flake8Enabled": true,
@@ -10,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": [
@@ -41,4 +46,7 @@
"restructuredtext",
],
"rewrap.wrappingColumn": 78,
"python.analysis.extraPaths": [
"jedi/src"
],
}
+11
View File
@@ -2,6 +2,17 @@
<!-- refer to https://keepachangelog.com/en/1.0.0/ for guidance -->
## 3.2.0b1-r2 - 2022-06-24
### Changed
- Moved remaining type hints from `.pyi` files to the python stub modules, and
fixed numerous errors in the type hints throughout.
## 3.2.0b1-r1 - 2022-06-09
## Added
- Added `__init__.py` to `pybricks` package.
## 3.2.0b1 - 2022-06-02
### Added
+2 -5
View File
@@ -8,13 +8,10 @@ SPHINXPROJ = Pybricks
SOURCEDIR = main
BUILDDIR = "$(SOURCEDIR)"/build
TAG = main
ifeq ($(BETA),1)
BETATAG = "-tbeta"
endif
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(TAG) $(BETATAG) $(O)
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(TAG) $(O)
.PHONY: help Makefile
@@ -25,4 +22,4 @@ diagrams:
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) -t $(TAG) $(BETATAG) $(O)
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) -t $(TAG) $(O)
+17 -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.
@@ -324,6 +336,10 @@ def on_missing_reference(app, env, node, contnode):
"ms",
"mNm",
"Hz",
"°C",
"J",
"Ω",
"N",
]:
# If they match on raw source, we are dealing with argument types.
+2 -3
View File
@@ -25,9 +25,8 @@ latex_logo = "../common/images/pybricks-logo-large.png"
if os.environ.get("READTHEDOCS", None) == "True":
tags.add("main") # noqa F821
# On https://docs.pybricks.com/en/latest/, show features tagged as beta.
if os.environ.get("READTHEDOCS_VERSION_NAME", None) == "latest":
tags.add("beta") # 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
+149 -155
View File
@@ -6,256 +6,250 @@ Prime Hub / Inventor Hub
.. figure:: ../../main/images/primeinventorhub.png
:height: 15 em
.. only:: not beta
.. note:: Pybricks support for these hubs is currently in development.
Please check back later!
.. note:: Pybricks support for these hubs is in beta.
Check the `installation instructions`_ to try it out.
The following functions may change before the final release.
.. only:: beta
.. class:: InventorHub
.. note:: Pybricks support for these hubs is in beta.
Check the `installation instructions`_ to try it out.
The following functions may change before the final release.
This class is the same as the ``PrimeHub`` class, shown below. Both classes
work on both hubs.
.. class:: InventorHub
These hubs are completely identical. They use the same Pybricks firmware.
This class is the same as the ``PrimeHub`` class, shown below. Both classes
work on both hubs.
.. autoclass:: pybricks.hubs.PrimeHub
:no-members:
These hubs are completely identical. They use the same Pybricks firmware.
.. rubric:: Using the hub status light
.. autoclass:: pybricks.hubs.PrimeHub
:no-members:
.. figure:: ../../main/images/primehub_light_label.png
:width: 22 em
.. rubric:: Using the hub status light
.. automethod:: pybricks.hubs::PrimeHub.light.on
.. figure:: ../../main/images/primehub_light_label.png
:width: 22 em
.. automethod:: pybricks.hubs::PrimeHub.light.off
.. automethod:: pybricks.hubs::PrimeHub.light.on
.. automethod:: pybricks.hubs::PrimeHub.light.blink
.. automethod:: pybricks.hubs::PrimeHub.light.off
.. automethod:: pybricks.hubs::PrimeHub.light.animate
.. automethod:: pybricks.hubs::PrimeHub.light.blink
.. rubric:: Using the light matrix display
.. automethod:: pybricks.hubs::PrimeHub.light.animate
.. figure:: ../../main/images/primehub_display_label.png
:width: 22 em
.. rubric:: Using the light matrix display
.. automethod:: pybricks.hubs::PrimeHub.display.orientation
.. figure:: ../../main/images/primehub_display_label.png
:width: 22 em
.. automethod:: pybricks.hubs::PrimeHub.display.off
.. automethod:: pybricks.hubs::PrimeHub.display.orientation
.. automethod:: pybricks.hubs::PrimeHub.display.pixel
.. automethod:: pybricks.hubs::PrimeHub.display.off
.. automethod:: pybricks.hubs::PrimeHub.display.image
.. automethod:: pybricks.hubs::PrimeHub.display.pixel
.. automethod:: pybricks.hubs::PrimeHub.display.animate
.. automethod:: pybricks.hubs::PrimeHub.display.image
.. automethod:: pybricks.hubs::PrimeHub.display.number
.. automethod:: pybricks.hubs::PrimeHub.display.animate
.. automethod:: pybricks.hubs::PrimeHub.display.char
.. automethod:: pybricks.hubs::PrimeHub.display.number
.. automethod:: pybricks.hubs::PrimeHub.display.text
.. automethod:: pybricks.hubs::PrimeHub.display.char
.. rubric:: Using the buttons
.. automethod:: pybricks.hubs::PrimeHub.display.text
.. figure:: ../../main/images/primehub_buttons_label.png
:width: 22 em
.. rubric:: Using the buttons
.. automethod:: pybricks.hubs::PrimeHub.buttons.pressed
.. figure:: ../../main/images/primehub_buttons_label.png
:width: 22 em
.. rubric:: Using the IMU
.. automethod:: pybricks.hubs::PrimeHub.buttons.pressed
.. automethod:: pybricks.hubs::PrimeHub.imu.up
.. rubric:: Using the IMU
.. automethod:: pybricks.hubs::PrimeHub.imu.tilt
.. automethod:: pybricks.hubs::PrimeHub.imu.up
.. automethod:: pybricks.hubs::PrimeHub.imu.acceleration
.. automethod:: pybricks.hubs::PrimeHub.imu.tilt
.. automethod:: pybricks.hubs::PrimeHub.imu.angular_velocity
.. automethod:: pybricks.hubs::PrimeHub.imu.acceleration
.. automethod:: pybricks.hubs::PrimeHub.imu.heading
.. automethod:: pybricks.hubs::PrimeHub.imu.angular_velocity
.. automethod:: pybricks.hubs::PrimeHub.imu.reset_heading
.. automethod:: pybricks.hubs::PrimeHub.imu.heading
.. rubric:: Using the speaker
.. automethod:: pybricks.hubs::PrimeHub.imu.reset_heading
.. automethod:: pybricks.hubs::PrimeHub.speaker.volume
.. rubric:: Using the speaker
.. automethod:: pybricks.hubs::PrimeHub.speaker.beep
.. automethod:: pybricks.hubs::PrimeHub.speaker.volume
.. automethod:: pybricks.hubs::PrimeHub.speaker.play_notes
.. automethod:: pybricks.hubs::PrimeHub.speaker.beep
.. rubric:: Using the battery
.. automethod:: pybricks.hubs::PrimeHub.speaker.play_notes
.. automethod:: pybricks.hubs::PrimeHub.battery.voltage
.. rubric:: Using the battery
.. automethod:: pybricks.hubs::PrimeHub.battery.current
.. automethod:: pybricks.hubs::PrimeHub.battery.voltage
.. rubric:: Getting the charger status
.. automethod:: pybricks.hubs::PrimeHub.battery.current
.. automethod:: pybricks.hubs::PrimeHub.charger.connected
.. rubric:: Getting the charger status
.. automethod:: pybricks.hubs::PrimeHub.charger.current
.. automethod:: pybricks.hubs::PrimeHub.charger.connected
.. automethod:: pybricks.hubs::PrimeHub.charger.status
.. automethod:: pybricks.hubs::PrimeHub.charger.current
.. rubric:: System control
.. automethod:: pybricks.hubs::PrimeHub.charger.status
.. automethod:: pybricks.hubs::PrimeHub.system.set_stop_button
.. rubric:: System control
.. automethod:: pybricks.hubs::PrimeHub.system.name
.. automethod:: pybricks.hubs::PrimeHub.system.set_stop_button
.. automethod:: pybricks.hubs::PrimeHub.system.shutdown
.. automethod:: pybricks.hubs::PrimeHub.system.name
.. automethod:: pybricks.hubs::PrimeHub.system.reset_reason
.. automethod:: pybricks.hubs::PrimeHub.system.shutdown
.. note:: The examples below use the ``PrimeHub`` class. The examples work fine
on both hubs because they are the identical. If you prefer, you can
change this to ``InventorHub``.
.. automethod:: pybricks.hubs::PrimeHub.system.reset_reason
Status light examples
---------------------
.. note:: The examples below use the ``PrimeHub`` class. The examples work fine
on both hubs because they are the identical. If you prefer, you can
change this to ``InventorHub``.
Turning the light on and off
****************************
Status light examples
---------------------
.. literalinclude::
../../../examples/pup/hub_primehub/light_off.py
Turning the light on and off
****************************
Changing brightness and using custom colors
*******************************************
.. literalinclude::
../../../examples/pup/hub_primehub/light_off.py
.. literalinclude::
../../../examples/pup/hub_primehub/light_hsv.py
Changing brightness and using custom colors
*******************************************
Making the light blink
**********************
.. literalinclude::
../../../examples/pup/hub_primehub/light_hsv.py
.. literalinclude::
../../../examples/pup/hub_primehub/light_blink.py
Making the light blink
**********************
Creating light animations
*************************
.. literalinclude::
../../../examples/pup/hub_primehub/light_blink.py
.. literalinclude::
../../../examples/pup/hub_primehub/light_animate.py
Creating light animations
*************************
Matrix display examples
-----------------------
.. literalinclude::
../../../examples/pup/hub_primehub/light_animate.py
Displaying images
*****************
Matrix display examples
-----------------------
.. literalinclude::
../../../examples/pup/hub_primehub/display_image.py
Displaying images
*****************
Displaying numbers
******************
.. literalinclude::
../../../examples/pup/hub_primehub/display_image.py
.. literalinclude::
../../../examples/pup/hub_primehub/display_number.py
Displaying numbers
******************
Displaying text
***************
.. literalinclude::
../../../examples/pup/hub_primehub/display_number.py
.. literalinclude::
../../../examples/pup/hub_primehub/display_text.py
Displaying text
***************
Displaying individual pixels
****************************
.. literalinclude::
../../../examples/pup/hub_primehub/display_text.py
.. literalinclude::
../../../examples/pup/hub_primehub/display_pixel.py
Displaying individual pixels
****************************
Changing the display orientation
********************************
.. literalinclude::
../../../examples/pup/hub_primehub/display_pixel.py
.. literalinclude::
../../../examples/pup/hub_primehub/display_orientation.py
Changing the display orientation
********************************
.. literalinclude::
../../../examples/pup/hub_primehub/display_orientation_imu.py
.. literalinclude::
../../../examples/pup/hub_primehub/display_orientation.py
Making your own images
**********************
.. literalinclude::
../../../examples/pup/hub_primehub/display_orientation_imu.py
.. literalinclude::
../../../examples/pup/hub_primehub/display_matrix.py
Making your own images
**********************
Combining images to make expressions
************************************
.. literalinclude::
../../../examples/pup/hub_primehub/display_matrix.py
.. literalinclude::
../../../examples/pup/hub_primehub/display_expression.py
Combining images to make expressions
************************************
Displaying animations
*********************
.. literalinclude::
../../../examples/pup/hub_primehub/display_expression.py
.. literalinclude::
../../../examples/pup/hub_primehub/display_animate.py
Displaying animations
*********************
Button examples
---------------
.. literalinclude::
../../../examples/pup/hub_primehub/display_animate.py
Detecting button presses
************************
Button examples
---------------
.. literalinclude::
../../../examples/pup/hub_primehub/button_main.py
Detecting button presses
************************
IMU examples
---------------
.. literalinclude::
../../../examples/pup/hub_primehub/button_main.py
Testing which way is up
********************************
IMU examples
---------------
.. literalinclude::
../../../examples/pup/hub_primehub/imu_up.py
Testing which way is up
********************************
.. literalinclude::
../../../examples/pup/hub_primehub/imu_up.py
Reading the tilt value
********************************
.. literalinclude::
../../../examples/pup/hub_primehub/imu_tilt.py
Reading the tilt value
********************************
Using a custom hub orientation
**************************************************
.. literalinclude::
../../../examples/pup/hub_primehub/imu_tilt.py
.. literalinclude::
../../../examples/pup/hub_primehub/imu_tilt_blast.py
Using a custom hub orientation
**************************************************
Reading acceleration and angular velocity vectors
**************************************************
.. literalinclude::
../../../examples/pup/hub_primehub/imu_tilt_blast.py
.. literalinclude::
../../../examples/pup/hub_primehub/imu_read_vector.py
Reading acceleration and angular velocity vectors
**************************************************
Reading acceleration and angular velocity on one axis
*****************************************************
.. literalinclude::
../../../examples/pup/hub_primehub/imu_read_vector.py
.. literalinclude::
../../../examples/pup/hub_primehub/imu_read_scalar.py
Reading acceleration and angular velocity on one axis
*****************************************************
System examples
----------------------------------
.. literalinclude::
../../../examples/pup/hub_primehub/imu_read_scalar.py
Changing the stop button combination
*****************************************
System examples
----------------------------------
.. literalinclude::
../../../examples/pup/hub_primehub/button_stop.py
Changing the stop button combination
*****************************************
Turning the hub off
*****************************************
.. literalinclude::
../../../examples/pup/hub_primehub/button_stop.py
Turning the hub off
*****************************************
.. literalinclude::
../../../examples/pup/hub_primehub/system_shutdown.py
.. literalinclude::
../../../examples/pup/hub_primehub/system_shutdown.py
.. _installation instructions: https://pybricks.com/install/
+3 -3
View File
@@ -9,12 +9,12 @@ EV3 DC Motor
.. figure:: ../../main/images/rcxmotor.png
:width: 40 %
.. autoclass:: pybricks._common.DCMotor
.. autoclass:: pybricks.iodevices.DCMotor
:noindex:
:no-members:
.. automethod:: pybricks._common.DCMotor.dc
.. automethod:: pybricks.iodevices.DCMotor.dc
:noindex:
.. automethod:: pybricks._common.DCMotor.stop
.. automethod:: pybricks.iodevices.DCMotor.stop
:noindex:
+6
View File
@@ -45,6 +45,12 @@ NXT Color Sensor
.. automethod:: pybricks.nxtdevices.ColorSensor.rgb
.. rubric:: Advanced color sensing
.. automethod:: pybricks.nxtdevices.ColorSensor.hsv
.. automethod:: pybricks.nxtdevices.ColorSensor.detectable_colors
.. rubric:: Built-in light
This sensor has a built-in light. You can make it red, green, blue, or turn
+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
~~~~~~
+2 -6
View File
@@ -15,10 +15,6 @@ if "%TAG%" == "" (
set TAG=main
)
if "%BETA%" == "1" (
set BETATAG=-tbeta
)
if "%1" == "" goto help
%SPHINXBUILD% >NUL 2>NUL
@@ -34,11 +30,11 @@ if errorlevel 9009 (
exit /b 1
)
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% -t %TAG% %BETATAG%
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% -t %TAG%
goto end
:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% -t %TAG% %BETATAG%
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% -t %TAG%
:end
popd
+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-r2"
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 = "9b91afcb8ccd46cc8be150f48170e45e86a6c65686d7e6e97ac3de67988c0ff5"
[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"},
]
+26
View File
@@ -0,0 +1,26 @@
[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 = "^3.2.0b1-r2"
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"
pybricks = { path = "../", develop = true }
[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 @@
[tool.poetry]
name = "pybricks"
version = "3.2.0b1"
version = "3.2.0b1-r2"
description = "Documentation and user-API stubs for Pybricks MicroPython"
authors = ["The Pybricks Authors <dev@pybricks.com>"]
maintainers = ["Laurens Valk <laurens@pybricks.com>", "David Lechner <david@pybricks.com>" ]
+1 -1
View File
@@ -1,6 +1,6 @@
[flake8]
exclude = .venv/,*.pyi
exclude = .venv/,*.pyi,jedi/
max-line-length = 88
ignore = E203,W503
+8
View File
@@ -0,0 +1,8 @@
from typing import Tuple
version: Tuple[str, str, str] = (
"hub",
"3.2.0b1",
"v3.2.0b1-GIT_HASH on DATE",
)
+147 -66
View File
@@ -4,20 +4,23 @@
"""Generic cross-platform module for typical devices like lights, displays,
speakers, and batteries."""
from .parameters import Direction, Stop, Button, Port, Color, Side
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
from typing import Union, Iterable, overload, Optional, Tuple, Collection
Number = Union[int, float]
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)
@@ -33,13 +36,11 @@ class System:
or a tuple of multiple buttons. Choose ``None`` to disable the
stop button altogether.
"""
pass
def shutdown(self) -> None:
"""shutdown()
Stops your program and shuts the hub down."""
pass
def reset_reason(self) -> int:
"""reset_reason() -> int
@@ -56,7 +57,6 @@ class System:
crashed due to a watchdog timeout, which indicates a firmware
issue.
"""
pass
def name(self) -> str:
"""name() -> str
@@ -67,7 +67,6 @@ class System:
Returns:
The hub name.
"""
pass
class DCMotor:
@@ -75,14 +74,13 @@ class DCMotor:
as train motors."""
def __init__(self, port: Port, positive_direction: Direction = Direction.CLOCKWISE):
"""DCMotor(port, positive_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.
"""
pass
def dc(self, duty: Number) -> None:
"""dc(duty)
@@ -92,7 +90,6 @@ class DCMotor:
Arguments:
duty (Number, %): The duty cycle (-100.0 to 100).
"""
pass
def stop(self) -> None:
"""stop()
@@ -100,7 +97,6 @@ class DCMotor:
Stops the motor and lets it spin freely.
The motor gradually stops due to friction."""
pass
def brake(self) -> None:
"""brake()
@@ -109,7 +105,6 @@ class DCMotor:
The motor stops due to friction, plus the voltage that
is generated while the motor is still moving."""
pass
@overload
def settings(self, max_voltage: Optional[int] = None) -> None:
@@ -131,7 +126,6 @@ class DCMotor:
max_voltage (Number, mV):
Maximum voltage applied to the motor during all motor commands.
"""
pass
class Control:
@@ -177,7 +171,6 @@ class Control:
torque (:ref:`torque`):
Maximum feedback torque during control.
"""
pass
@overload
def pid(self) -> Tuple[int, int, int, None, int]:
@@ -215,7 +208,6 @@ class Control:
integral_rate (Number, deg/s or Number, mm/s): Maximum rate at
which the error integral is allowed to grow.
"""
pass
@overload
def target_tolerances(self) -> Tuple[int, int]:
@@ -242,7 +234,6 @@ class Control:
deviation from the target before motion is considered
complete.
"""
pass
@overload
def stall_tolerances(self) -> Tuple[int, int]:
@@ -269,7 +260,6 @@ class Control:
time (Number, ms): How long the controller has to be below this
minimum ``speed`` before we say it is stalled.
"""
pass
def stalled(self) -> bool:
"""stalled() -> bool
@@ -282,7 +272,6 @@ class Control:
Returns:
``True`` if the controller is stalled, ``False`` if not.
"""
pass
def done(self) -> bool:
"""done() -> bool
@@ -292,7 +281,6 @@ class Control:
Returns:
``True`` if the command is done, ``False`` if not.
"""
pass
def load(self) -> int:
"""load() -> int: mNm
@@ -306,7 +294,6 @@ class Control:
Returns:
The load torque. It returns 0 if control is not active.
"""
pass
class Motor(DCMotor):
@@ -325,7 +312,7 @@ class Motor(DCMotor):
gears: Optional[Union[Collection[int], Collection[Collection[int]]]] = None,
reset_angle: bool = True,
):
"""Motor(port, positive_direction=Direction.CLOCKWISE, gears=None, reset_angle=True)
"""__init__(port, positive_direction=Direction.CLOCKWISE, gears=None, reset_angle=True)
Arguments:
port (Port): Port to which the motor is connected.
@@ -349,7 +336,6 @@ class Motor(DCMotor):
current value, so your program knows where it left off last
time.
"""
pass
def angle(self) -> int:
"""angle() -> int: deg
@@ -359,7 +345,6 @@ class Motor(DCMotor):
Returns:
Motor angle.
"""
pass
def speed(self) -> int:
"""speed() -> int: deg/s
@@ -370,7 +355,6 @@ class Motor(DCMotor):
Motor speed.
"""
pass
def reset_angle(self, angle: Number) -> None:
"""
@@ -381,13 +365,11 @@ class Motor(DCMotor):
Arguments:
angle (Number, deg): Value to which the angle should be reset.
"""
pass
def hold(self) -> None:
"""hold()
Stops the motor and actively holds it at its current angle."""
pass
def run(self, speed: Number) -> None:
"""run(speed)
@@ -400,7 +382,6 @@ class Motor(DCMotor):
Arguments:
speed (Number, deg/s): Speed of the motor.
"""
pass
def run_time(
self, speed: Number, time: Number, then: Stop = Stop.HOLD, wait: bool = True
@@ -420,7 +401,6 @@ class Motor(DCMotor):
wait (bool): Wait for the maneuver to complete before continuing
with the rest of the program.
"""
pass
def run_angle(
self,
@@ -441,7 +421,6 @@ class Motor(DCMotor):
wait (bool): Wait for the maneuver to complete before continuing
with the rest of the program.
"""
pass
def run_target(
self,
@@ -464,7 +443,6 @@ class Motor(DCMotor):
wait (bool): Wait for the motor to reach the target
before continuing with the rest of the program.
"""
pass
def run_until_stalled(
self,
@@ -488,7 +466,6 @@ class Motor(DCMotor):
Returns:
Angle at which the motor becomes stalled.
"""
pass
def track_target(self, target_angle: Number) -> None:
"""track_target(target_angle)
@@ -502,7 +479,6 @@ class Motor(DCMotor):
target_angle (Number, deg): Target angle that the motor should
rotate to.
"""
pass
class Speaker:
@@ -527,7 +503,6 @@ class Speaker:
Arguments:
volume (Number, %): Volume of the speaker in the 0-100 range.
"""
pass
def beep(self, frequency: Number = 500, duration: Number = 100) -> None:
"""beep(frequency=500, duration=100)
@@ -542,7 +517,6 @@ class Speaker:
than 0, then the method returns immediately and the frequency
play continues to play indefinitely.
"""
pass
def play_notes(self, notes: Iterable[str], tempo: Number = 120) -> None:
"""play_notes(notes, tempo=120)
@@ -577,7 +551,6 @@ class Speaker:
tempo (int):
Beats per minute. A quarter note is one beat.
"""
pass
class ColorLight:
@@ -591,13 +564,11 @@ class ColorLight:
Arguments:
color (Color): Color of the light.
"""
pass
def off(self) -> None:
"""off()
Turns off the light."""
pass
def blink(self, color: Color, durations: Collection[int]) -> None:
"""blink(color, durations)
@@ -645,7 +616,6 @@ class LightArray:
Arguments:
n (int): Number of lights
"""
pass
def on(self, brightness: Union[int, Collection[int]]) -> None:
"""on(brightness)
@@ -658,13 +628,11 @@ class LightArray:
If you give just one brightness value, all lights get that
brightness.
"""
pass
def off(self) -> None:
"""off()
Turns off all the lights."""
pass
class LightMatrix:
@@ -679,7 +647,6 @@ class LightMatrix:
rows (int): Number of rows in the grid
columns (int): Number of columns in the grid
"""
pass
def orientation(self, up: Side) -> None:
"""orientation(up)
@@ -694,7 +661,6 @@ class LightMatrix:
design. Choose ``Side.TOP``, ``Side.LEFT``, ``Side.RIGHT``,
or ``Side.BOTTOM``.
"""
pass
def image(self, matrix: Matrix) -> None:
"""image(matrix)
@@ -706,7 +672,6 @@ class LightMatrix:
matrix (Matrix): Matrix of intensities (:ref:`brightness`). A 2D
list is also accepted.
"""
pass
def animate(self, matrices: Collection[Matrix], interval: Number) -> None:
"""animate(matrices, interval)
@@ -722,7 +687,6 @@ class LightMatrix:
:class:`Matrix <pybricks.geometry.Matrix>` of intensities.
interval (Number, ms): Time to display each image in the list.
"""
pass
def pixel(self, row: int, column: int, brightness: Number = 100) -> None:
"""pixel(row, column, brightness=100)
@@ -734,13 +698,11 @@ class LightMatrix:
column (int): Horizontal grid index, starting at 0 from the left.
brightness (:ref:`brightness`): Brightness of the pixel.
"""
pass
def off(self) -> None:
"""off()
Turns off all the pixels."""
pass
def number(self, number: Number) -> None:
"""number(number)
@@ -754,7 +716,6 @@ class LightMatrix:
Arguments:
number (int): The number to be displayed.
"""
pass
def char(self, char: str) -> None:
"""char(char)
@@ -766,7 +727,6 @@ class LightMatrix:
Arguments:
character (str): The character or symbol to be displayed.
"""
pass
def text(self, text: str, on: Number = 500, off: Number = 50) -> None:
"""text(text, on=500, off=50)
@@ -781,14 +741,13 @@ class LightMatrix:
off (Number, ms): For how long the display is off between
characters.
"""
pass
class Keypad:
"""Get status of buttons on a keypad layout."""
def __init__(self, active_buttons):
pass
...
def pressed(self) -> Tuple[Button]:
"""pressed() -> Tuple[Button]
@@ -798,7 +757,6 @@ class Keypad:
Returns:
Tuple of pressed buttons.
"""
pass
class Battery:
@@ -812,7 +770,6 @@ class Battery:
Returns:
Battery voltage.
"""
pass
def current(self) -> int:
"""current() -> int: mA
@@ -822,7 +779,6 @@ class Battery:
Returns:
Battery current.
"""
pass
class Charger:
@@ -852,7 +808,6 @@ class Charger:
Returns:
Status value.
"""
pass
def current(self) -> int:
"""current() -> int: mA
@@ -862,7 +817,6 @@ class Charger:
Returns:
Charging current.
"""
pass
class SimpleAccelerometer:
@@ -876,7 +830,6 @@ class SimpleAccelerometer:
Returns:
Acceleration along all three axes.
"""
pass
def up(self) -> Side:
"""up() -> Side
@@ -887,7 +840,6 @@ class SimpleAccelerometer:
``Side.TOP``, ``Side.BOTTOM``, ``Side.LEFT``, ``Side.RIGHT``,
``Side.FRONT`` or ``Side.BACK``.
"""
pass
class Accelerometer(SimpleAccelerometer):
@@ -917,7 +869,6 @@ class Accelerometer(SimpleAccelerometer):
Acceleration along the specified axis. If you specify no axis,
this returns a vector of accelerations along all axes.
"""
pass
def tilt(self) -> Tuple[int, int]:
"""tilt() -> Tuple[int, int]
@@ -932,7 +883,6 @@ class Accelerometer(SimpleAccelerometer):
Returns:
Tuple of pitch and roll angles.
"""
pass
class IMU(Accelerometer):
@@ -952,10 +902,9 @@ class IMU(Accelerometer):
Heading angle relative to starting orientation.
"""
pass
def reset_heading(self, angle: Number) -> None:
"""reset_heading(angle: Number)
"""reset_heading(angle)
Resets the accumulated heading angle of the robot.
@@ -964,7 +913,6 @@ class IMU(Accelerometer):
Arguments:
angle (Number, deg): Value to which the heading should be reset.
"""
pass
@overload
def angular_velocity(self) -> Matrix:
@@ -989,4 +937,137 @@ class IMU(Accelerometer):
Angular velocity along the specified axis. If you specify no axis,
this returns a vector of accelerations along all axes.
"""
pass
class CommonColorSensor:
"""Generic color sensor that supports Pybricks color calibration."""
def __init__(self, port: Port):
"""__init__(port)
Arguments:
port (Port): Port to which the sensor is connected.
"""
def color(self) -> Color:
"""color() -> Color
Scans the color of a surface.
You choose which colors are detected using the
``detectable_colors()`` method. By default, it detects
``Color.RED``, ``Color.YELLOW``, ``Color.GREEN``, ``Color.BLUE``,
``Color.WHITE``, or ``Color.NONE``.
Returns:
Detected color.
"""
def hsv(self) -> Color:
"""hsv() -> Color
Scans the color of a surface.
This method is similar to ``color()``, but it gives the full range
of hue, saturation and brightness values, instead of rounding it to the
nearest detectable color.
Returns:
Measured color. The color is described by a hue (0--359), a
saturation (0--100), and a brightness value (0--100).
"""
def ambient(self) -> int:
"""ambient() -> int: %
Measures the ambient light intensity.
Returns:
Ambient light intensity, ranging from 0% (dark)
to 100% (bright).
"""
def reflection(self) -> int:
"""reflection() -> int: %
Measures how much a surface reflects the light emitted by the
sensor.
Returns:
Measured reflection, ranging from 0% (no reflection) to
100% (high reflection).
"""
@overload
def detectable_colors(self, colors: Collection[Color]) -> None:
...
@overload
def detectable_colors(self) -> Tuple[Color]:
...
def detectable_colors(self, *args):
"""
detectable_colors(colors)
detectable_colors() -> Tuple[Color]
Configures which colors the ``color()`` method should detect.
Specify only colors that you wish to detect in your application.
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.
Arguments:
colors (tuple): Tuple 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
better results. You measure your own colors with the
``hsv()`` method.
"""
class AmbientColorSensor(CommonColorSensor):
"""Like CommonColorSensor, but also detects ambient colors when the sensor
light is turned off"""
def color(self, surface: bool = True) -> Optional[Color]:
"""color(surface=True) -> Color
Scans the color of a surface or an external light source.
You choose which colors are detected using the
``detectable_colors()`` method. By default, it detects
``Color.RED``, ``Color.YELLOW``, ``Color.GREEN``, ``Color.BLUE``,
``Color.WHITE``, or ``Color.NONE``.
Arguments:
surface (bool): Choose ``true`` to scan the color of objects
and surfaces. Choose ``false`` to scan the color of
screens and other external light sources.
Returns:
Detected color.`
"""
def hsv(self, surface: bool = True) -> Color:
"""hsv(surface=True) -> Color
Scans the color of a surface or an external light source.
This method is similar to ``color()``, but it gives the full range
of hue, saturation and brightness values, instead of rounding it to the
nearest detectable color.
Arguments:
surface (bool): Choose ``true`` to scan the color of objects
and surfaces. Choose ``false`` to scan the color of
screens and other external light sources.
Returns:
Measured color. The color is described by a hue (0--359), a
saturation (0--100), and a brightness value (0--100).
"""
+40 -26
View File
@@ -1,26 +1,33 @@
# SPDX-License-Identifier: MIT
# Copyright (c) 2018-2021 The Pybricks Authors
from typing import Iterable, Union, Optional
from ..media.ev3dev import SoundFile
class Speaker:
"""Plays beeps and sounds using a speaker."""
def beep(self, frequency=500, duration=100):
"""Play a beep/tone.
def beep(self, frequency: int = 500, duration: int = 100) -> None:
"""beep(frequency=500, duration=100)
Play a beep/tone.
Arguments:
frequency (:ref:`frequency`):
Frequency of the beep. Frequencies below 100
are treated as 100.
duration (:ref:`time`):
Duration of the beep. If the duration is less
than 0, then the method returns immediately and the frequency
play continues to play indefinitely.
frequency (Number, Hz):
Frequency of the beep. Frequencies below 100 Hz are treated as
100 Hz.
duration (Number, ms):
Duration of the beep. If the duration is less than 0, then the
method returns immediately and the frequency play continues to
play indefinitely.
"""
pass
def play_notes(self, notes, tempo=120):
"""Plays a sequence of musical notes. For example:
def play_notes(self, notes: Iterable[str], tempo: int = 120) -> None:
"""play_notes(notes, tempo=120)
Plays a sequence of musical notes. For example:
``['C4/4', 'C4/4', 'G4/4', 'G4/4']``.
Each note is a string with the following format:
@@ -50,20 +57,21 @@ class Speaker:
tempo (int):
Beats per minute. A quarter note is one beat.
"""
pass
def play_file(self, file):
"""Plays a sound file.
def play_file(self, file_name: Union[SoundFile, str]) -> None:
"""play_file(file_name)
Plays a sound file.
Arguments:
file (str):
Path to the sound file, including the file extension.
"""
pass
def say(self, text: str) -> None:
"""say(text)
def say(self, text):
"""Says a given text string.
Says a given text string.
You can configure the language and voice of the text using
:meth:`.set_speech_options`.
@@ -72,10 +80,16 @@ class Speaker:
text (str): What to say.
"""
pass
def set_speech_options(
self,
language: Optional[str] = None,
voice: Optional[str] = None,
speed: Optional[int] = None,
pitch: Optional[int] = None,
):
"""set_speech_options(language, voice, speed, pitch)
def set_speech_options(self, language=None, voice=None, speed=None, pitch=None):
"""Configures speech settings used by the :meth:`.say` method.
Configures speech settings used by the :meth:`.say` method.
Any option that is set to ``None`` will not be changed. If an option
is set to an invalid value :meth:`.say` will use the default value
@@ -95,13 +109,14 @@ class Speaker:
Pitch (0 to 99). Higher numbers make the voice higher pitched
and lower numbers make the voice lower pitched.
"""
pass
def set_volume(self, volume, which="_all_"):
"""Sets the speaker volume.
def set_volume(self, volume: int, which: str = "_all_") -> None:
"""set_volume(volume, which="_all_")
Sets the speaker volume.
Arguments:
volume (:ref:`percentage`):
volume (Number, %):
Volume of the speaker.
which (str):
Which volume to set. ``'Beep'`` sets the volume for
@@ -109,4 +124,3 @@ class Speaker:
volume for :meth:`.play_file` and :meth:`.say`. ``'_all_'``
sets both at the same time.
"""
pass
-20
View File
@@ -1,20 +0,0 @@
# SPDX-License-Identifier: MIT
# Copyright (c) 2020-2021 The Pybricks Authors
from typing import Iterable, Optional, Union
from pybricks.media.ev3dev import SoundFile
class Speaker:
def beep(self, frequency: int = 500, duration: int = 100) -> None: ...
def play_notes(self, notes: Iterable[str], tempo: int = 120) -> None: ...
def play_file(self, file_name: Union[SoundFile, str]) -> None: ...
def say(self, text: str) -> None: ...
def set_speech_options(
self,
language: Optional[str] = None,
voice: Optional[str] = None,
speed: Optional[int] = None,
pitch: Optional[int] = None,
): ...
def set_volume(self, volume: int, which: str = "_all_") -> None: ...
+20 -32
View File
@@ -3,26 +3,30 @@
"""LEGO® MINDSTORMS® EV3 motors and sensors."""
from .parameters import Direction, Port, Color, Button
from ._common import Motor as _Motor
from typing import Optional, Tuple, List
from . import _common
from .parameters import (
Button as _Button,
Color as _Color,
Direction as _Direction,
Port as _Port,
)
class Motor(_Motor):
pass
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:
port (Port): Port to which the sensor is connected.
"""
pass
def pressed(self) -> bool:
"""pressed() -> bool
@@ -33,21 +37,19 @@ class TouchSensor:
``True`` if the sensor is pressed, ``False`` if it is
not pressed.
"""
pass
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.
"""
pass
def color(self) -> Optional[Color]:
def color(self) -> Optional[_Color]:
"""color() -> Color
Measures the color of a surface.
@@ -58,7 +60,6 @@ class ColorSensor:
or ``None`` if no color is detected.
"""
pass
def ambient(self) -> int:
"""ambient() -> int: %
@@ -69,7 +70,6 @@ class ColorSensor:
Ambient light intensity, ranging from 0% (dark)
to 100% (bright).
"""
pass
def reflection(self) -> int:
"""reflection() -> int: %
@@ -81,7 +81,6 @@ class ColorSensor:
100% (high reflection).
"""
pass
def rgb(self) -> Tuple[int, int, int]:
"""rgb() -> Tuple[int, int, int]
@@ -93,20 +92,18 @@ class ColorSensor:
Tuple of reflections for red, green, and blue light, each
ranging from 0.0% (no reflection) to 100.0% (high reflection).
"""
pass
class InfraredSensor:
"""LEGO® MINDSTORMS® EV3 Infrared Sensor and Beacon."""
def __init__(self, port: Port):
def __init__(self, port: _Port):
"""InfraredSensor(port)
Arguments:
port (Port): Port to which the sensor is connected.
"""
pass
def distance(self) -> int:
"""distance() -> int: %
@@ -119,7 +116,6 @@ class InfraredSensor:
to 100% (farthest).
"""
pass
def beacon(self, channel: int) -> Tuple[Optional[int], Optional[int]]:
"""
@@ -137,9 +133,8 @@ class InfraredSensor:
(-75 to 75 degrees) between remote and infrared sensor or
a tuple of (``None``, ``None``) if no remote is detected.
"""
pass
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.
@@ -154,9 +149,8 @@ class InfraredSensor:
List of pressed buttons on the remote on the selected channel.
"""
pass
def keypad(self) -> List[Button]:
def keypad(self) -> List[_Button]:
"""keypad() -> List[Button]
Checks which buttons on the infrared remote are pressed.
@@ -169,13 +163,14 @@ class InfraredSensor:
Returns:
List of pressed buttons.
"""
pass
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:
@@ -185,7 +180,6 @@ class GyroSensor:
of the sensor.
"""
pass
def speed(self) -> int:
"""speed() -> int: deg/s
@@ -196,7 +190,6 @@ class GyroSensor:
Angular velocity.
"""
pass
def angle(self) -> int:
"""angle() -> int: deg
@@ -207,7 +200,6 @@ class GyroSensor:
Rotation angle.
"""
pass
def reset_angle(self, angle: int) -> None:
"""reset_angle(angle)
@@ -217,20 +209,18 @@ class GyroSensor:
Arguments:
angle (Number, deg): Value to which the angle should be reset.
"""
pass
class UltrasonicSensor:
"""LEGO® MINDSTORMS® EV3 Ultrasonic Sensor."""
def __init__(self, port: Port):
def __init__(self, port: _Port):
"""UltrasonicSensor(port)
Arguments:
port (Port): Port to which the sensor is connected.
"""
pass
def distance(self, silent: bool = False) -> int:
"""distance(silent=False) -> int: mm
@@ -249,7 +239,6 @@ class UltrasonicSensor:
Measured distance.
"""
pass
def presence(self) -> bool:
"""presence() -> bool
@@ -265,4 +254,3 @@ class UltrasonicSensor:
``True`` if ultrasonic sounds are detected,
``False`` if not.
"""
pass
-3
View File
@@ -63,14 +63,12 @@ class Matrix:
def T(self) -> Matrix:
"""Returns a new :class:`.Matrix` that is the transpose of the
original."""
pass
@property
def shape(self) -> Tuple[int, int]:
"""Returns a tuple (``m``, ``n``),
where ``m`` is the number of rows and ``n`` is the number of columns.
"""
pass
@overload
@@ -99,7 +97,6 @@ def vector(*args):
Returns:
A matrix with the shape of a column vector.
"""
pass
class Axis:
+36 -50
View File
@@ -2,18 +2,8 @@
# Copyright (c) 2018-2020 The Pybricks Authors
"""LEGO® Programmable Hubs."""
from ._common import (
Speaker as _Speaker,
Battery as _Battery,
ColorLight as _ColorLight,
Keypad as _Keypad,
LightMatrix as _LightMatrix,
IMU as _IMU,
Charger as _Charger,
System as _System,
SimpleAccelerometer as _SimpleAccelerometer,
)
from .ev3dev._speaker import Speaker as _EV3Speaker
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
@@ -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(
(
buttons = _common.Keypad(
[
_Button.LEFT,
_Button.RIGHT,
_Button.CENTER,
_Button.UP,
_Button.DOWN,
)
]
)
screen = _Image("_screen_")
speaker = _EV3Speaker()
battery = _Battery()
light = _ColorLight()
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,14 +57,14 @@ 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.Z, front_side=_Axis.X):
"""__init__(top_side=Axis.Z, front_side=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
:ref:`placed in your design <robotframe>` by saying in which
@@ -87,7 +77,6 @@ class TechnicHub:
front_side (Axis): The axis that passes through the *front side* of
the hub.
"""
pass
class PrimeHub:
@@ -95,24 +84,24 @@ class PrimeHub:
# These class attributes are here for auto-documentation only.
# In reality, they are instance attributes created by __init__.
battery = _Battery()
buttons = _Keypad(
(
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.Z, front_side=_Axis.X):
"""__init__(top_side=Axis.Z, front_side=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
:ref:`placed in your design <robotframe>` by saying in which
@@ -125,10 +114,7 @@ class PrimeHub:
front_side (Axis): The axis that passes through the *front side* of
the hub.
"""
pass
class InventorHub(PrimeHub):
"""LEGO® MINDSTORMS Inventor Hub."""
pass
-55
View File
@@ -1,55 +0,0 @@
# SPDX-License-Identifier: MIT
# Copyright (c) 2020 The Pybricks Authors
from ._common import (
Battery,
ColorLight,
Charger,
IMU,
Keypad,
LightMatrix,
SimpleAccelerometer,
Speaker,
System,
)
from .ev3dev._speaker import Speaker as EV3Speaker
from .geometry import Axis
from .media.ev3dev import Image
class EV3Brick:
screen: Image
speaker: EV3Speaker
battery: Battery
light: ColorLight
buttons = Keypad
class MoveHub:
battery: Battery
light: ColorLight
system: System
imu: SimpleAccelerometer
class CityHub:
battery: Battery
light: ColorLight
system: System
class TechnicHub:
def __init__(self, top_size: Axis, front_side: Axis): ...
battery: Battery
light: ColorLight
system: System
imu: IMU
class PrimeHub:
def __init__(self, top_side: Axis = Axis.Z, front_side: Axis = Axis.X): ...
battery: Battery
light: ColorLight
display: LightMatrix
buttons: Keypad
speaker: Speaker
system: System
imu: IMU
charger: Charger
class InventorHub(PrimeHub): ...
+133 -102
View File
@@ -3,132 +3,146 @@
"""Generic input/output devices."""
from typing import Dict, Tuple, Optional, overload
from . import _common
from .parameters import Port as _Port
class PUPDevice:
"""Powered Up motor or sensor."""
def __init__(self, port):
"""
def __init__(self, port: _Port):
"""PUPDevice(port)
Arguments:
port (Port): Port to which the device is connected.
"""
pass
def info(self):
"""Returns information about the device.
def info(self) -> Dict[str, str]:
"""info() -> Dict
Gets information about the device.
Returns:
``dict``: Dictionary with information, such as the device ``id``.
Dictionary with information, such as the device ``id``.
"""
pass
def read(self, mode):
"""Reads values from a given mode.
def read(self, mode: int) -> Tuple:
"""read(mode) -> Tuple
Reads values from a given mode.
Arguments:
mode (``int``): Device mode.
mode (int): Device mode.
Returns:
``tuple``: Values read from the sensor.
Values read from the sensor.
"""
pass
def write(self, mode, data):
"""Writes values to the sensor. Only selected sensors and modes support
def write(self, mode: int, data: Tuple) -> None:
"""write(mode, data)
Writes values to the sensor. Only selected sensors and modes support
this.
Arguments:
mode (``int``): Device mode.
data (``tuple``): Values to be written.
mode (int): Device mode.
data (tuple): Values to be written.
"""
pass
class LUMPDevice:
"""Devices using the LEGO UART Messaging Protocol."""
def __init__(self, port):
"""
def __init__(self, port: _Port):
"""LUMPDevice(port)
Arguments:
port (Port): Port to which the device is connected.
"""
pass
def read(self, mode):
"""Reads values from a given mode.
def read(self, mode: int) -> Tuple:
"""read(mode) -> Tuple
Reads values from a given mode.
Arguments:
mode (``int``): Device mode.
mode (int): Device mode.
Returns:
``tuple``: Values read from the sensor.
Values read from the sensor.
"""
pass
class DCMotor(_common.DCMotor):
"""DC Motor for LEGO® MINDSTORMS EV3."""
class Ev3devSensor:
"""Read values of an ev3dev-compatible sensor."""
sensor_index = 0
sensor_index: int
"""Index of the ev3dev sysfs `lego-sensor`_ class."""
port_index = 0
port_index: int
"""Index of the ev3dev sysfs `lego-port`_ class."""
def __init__(self, port):
"""
def __init__(self, port: _Port):
"""Ev3devSensor(port)
Arguments:
port (Port): Port to which the device is connected.
"""
pass
def read(self, mode):
"""Reads values at a given mode.
def read(self, mode: str) -> Tuple:
"""read(mode) -> Tuple
Reads values at a given mode.
Arguments:
mode (``str``): `Mode name`_.
mode (str): `Mode name`_.
Returns:
``tuple``: Values read from the sensor.
values read from the sensor.
"""
pass
class AnalogSensor:
"""Generic or custom analog sensor."""
def __init__(self, port):
"""
def __init__(self, port: _Port):
"""AnalogSensor(port)
Arguments:
port (Port): Port to which the sensor is connected.
"""
pass
def voltage(self):
"""Measures analog voltage.
def voltage(self) -> int:
"""voltage() -> int: mV
Measures analog voltage.
Returns:
:ref:`voltage`: Analog voltage.
Analog voltage.
"""
pass
def resistance(self):
"""Measures resistance.
def resistance(self) -> int:
"""resistance() -> int: Ω
Measures resistance.
This value is only meaningful if the analog device is a passive load
such as a resistor or thermistor.
Returns:
:ref:`resistance: Ω <voltage>`: Resistance of the analog device.
Resistance of the analog device.
"""
pass
def active(self):
"""Sets sensor to active mode. This sets pin 5 of the sensor
def active(self) -> None:
"""active()
Sets sensor to active mode. This sets pin 5 of the sensor
port to `high`.
This is used in some analog
@@ -136,10 +150,11 @@ class AnalogSensor:
Sensor as a custom analog sensor, this method will turn the light on.
From then on, ``voltage()`` returns the raw reflected light value.
"""
pass
def passive(self):
"""Sets sensor to passive mode. This sets pin 5 of the sensor
def passive(self) -> None:
"""passive()
Sets sensor to passive mode. This sets pin 5 of the sensor
port to `low`.
This is used in some analog
@@ -147,116 +162,120 @@ class AnalogSensor:
Sensor as a custom analog sensor, this method will turn the light off.
From then on, ``voltage()`` returns the raw ambient light value.
"""
pass
class I2CDevice:
"""Generic or custom I2C device."""
def __init__(self, port, address):
"""
def __init__(self, port: _Port, address: int):
"""I2CDevice(port, address)
Arguments:
port (Port): Port to which the device is connected.
address(int): I2C address of the client device. See
:ref:`I2C Addresses <i2caddress>`.
"""
pass
def read(self, reg, length=1):
"""Reads bytes, starting at a given register.
def read(self, reg: Optional[int], length: Optional[int] = 1) -> bytes:
"""read(reg, length=1)
Reads bytes, starting at a given register.
Arguments:
reg (``int``): Register at which to begin
reg (int): Register at which to begin
reading: 0--255 or 0x00--0xFF.
length (``int``): How many bytes to read.
length (int): How many bytes to read.
Returns:
``bytes``: Bytes returned from the device.
Bytes returned from the device.
"""
pass
def write(self, reg, data=None):
"""Writes bytes, starting at a given register.
def write(self, reg: Optional[int], data: Optional[bytes] = None) -> None:
"""write(reg, data=None)
Writes bytes, starting at a given register.
Arguments:
reg (``int``): Register at which to begin
reg (int): Register at which to begin
writing: 0--255 or 0x00--0xFF.
data (``bytes``): Bytes to be written.
data (bytes): Bytes to be written.
"""
pass
class UARTDevice:
"""Generic UART device."""
def __init__(self, port, baudrate, timeout=None):
"""
def __init__(self, port: _Port, baudrate: int, timeout: Optional[int] = None):
"""UARTDevice(port, baudrate, timeout=None)
Arguments:
port (Port): Port to which the device is connected.
baudrate (int): Baudrate of the UART device.
timeout (:ref:`time`): How long to wait
timeout (Number, ms): How long to wait
during ``read`` before giving up. If you choose ``None``,
it will wait forever.
"""
pass
def read(self, length=1):
"""Reads a given number of bytes from the buffer.
def read(self, length: int = 1) -> bytes:
"""read(length=1) -> bytes
Reads a given number of bytes from the buffer.
Your program will wait until the requested number of bytes are
received. If this takes longer than ``timeout``, the ``ETIMEDOUT``
exception is raised.
Arguments:
length (``int``): How many bytes to read.
length (int): How many bytes to read.
Returns:
``bytes``: Bytes returned from the device.
Bytes returned from the device.
"""
pass
def read_all(self):
"""Reads all bytes from the buffer.
def read_all(self) -> bytes:
"""read_all() -> bytes
Reads all bytes from the buffer.
Returns:
``bytes``: Bytes returned from the device.
Bytes returned from the device.
"""
pass
def write(self, data):
"""Writes bytes.
def write(self, data: bytes) -> None:
"""write(data)
Writes bytes.
Arguments:
data (``bytes``): Bytes to be written.
data (bytes): Bytes to be written.
"""
pass
def waiting(self):
"""Gets how many bytes are still waiting to be read.
def waiting(self) -> int:
"""waiting() -> int
Gets how many bytes are still waiting to be read.
Returns:
``int``: Number of bytes in the buffer.
Number of bytes in the buffer.
"""
pass
def clear(self):
"""Empties the buffer."""
pass
def clear(self) -> None:
"""clear()
Empties the buffer."""
class LWP3Device:
"""
Connects to a remote hub running official LEGO firmware using the the
Connects to a hub running official LEGO firmware using the
`LEGO Wireless Protocol v3`_
.. _`LEGO Wireless Protocol v3`:
https://lego.github.io/lego-ble-wireless-protocol-docs/
"""
def __init__(self, hub_kind, name=None, timeout=10000):
"""
def __init__(self, hub_kind: int, name: str = None, timeout: int = 10000):
"""LWP3Device(hub_kind, name=None, timeout=10000)
Arguments:
hub_kind (int):
@@ -273,30 +292,42 @@ class LWP3Device:
https://github.com/pybricks/technical-info/blob/master/assigned-numbers.md#hub-type-ids
"""
def name(self, name=None):
"""Gets or sets the Bluetooth name of the remote.
@overload
def name(self, name: str) -> None:
...
If no name is given, this method returns the current name.
@overload
def name(self) -> str:
...
def name(self, *args):
"""name(name)
name() -> str
Sets or gets the Bluetooth name of the device.
Arguments:
name (str): New Bluetooth name of the remote.
name (str): New Bluetooth name of the device. If no name is given,
this method returns the current name.
"""
def write(self, buf):
"""
def write(self, buf: bytes) -> None:
"""write(buf)
Sends a message to the remote hub.
Arguments:
buf (bytes): The raw binary message to send.
"""
def read(self):
"""
def read(self) -> bytes:
"""read() -> bytes
Retrieves the most recent message received from the remote hub.
If a message has not been received since the last read, the method will
block until a message is received.
Returns:
bytes: The raw binary message.
The raw binary message.
"""
-52
View File
@@ -1,52 +0,0 @@
# SPDX-License-Identifier: MIT
# Copyright (c) 2020 The Pybricks Authors
from typing import Dict, Optional, Tuple, overload
from .parameters import Port
class PUPDevice:
def __init__(self, port: Port): ...
def info(self) -> Dict[str, str]: ...
def read(self, mode: int) -> Tuple: ...
def write(self, mode: int, data: Tuple) -> None: ...
class LUMPDevice:
def __init__(self, port: Port): ...
def read(self, mode: int) -> Tuple: ...
class Ev3devSensor:
sensor_index: int
port_index: int
def __init__(self, port: Port): ...
def read(self, mode: int) -> Tuple: ...
class AnalogSensor:
def __init__(self, port: Port): ...
def voltage(self) -> int: ...
def resistance(self) -> int: ...
def active(self) -> None: ...
def passive(self) -> None: ...
class I2CDevice:
def __init__(self, port: Port, address: int): ...
def read(self, reg: Optional[int], length: Optional[int] = 1) -> bytes: ...
def write(self, reg: Optional[int], data: Optional[bytes] = None) -> None: ...
class UARTDevice:
def __init__(self, port: Port, baudrate: int, timeout: Optional[int] = None): ...
def read(self, length: int = 1) -> bytes: ...
def read_all(self) -> bytes: ...
def write(self, data: bytes) -> None: ...
def waiting(self) -> int: ...
def clear(self) -> None: ...
class LWP3Device:
def __init__(self, hub_kind: int, name: str = None, timeout: int = 10000): ...
@overload
def name(self) -> str: ...
@overload
def name(self, name: str) -> None: ...
def name(self, *args): ...
def read(self) -> bytes: ...
def write(self, buf: bytes) -> None: ...
+279 -208
View File
@@ -3,7 +3,11 @@
"""Images and Sounds for Pybricks on ev3dev."""
from ..parameters import Color as _Color
from __future__ import annotations
from typing import Union, Literal, overload, Optional, Any
from ..parameters import Color
class Image:
@@ -15,8 +19,20 @@ class Image:
# in that context and it is automatically replaced when the documentation
# is generated.
def __init__(self, source, sub=False):
"""
@overload
def __init__(self, /, source: Union[Image, ImageFile, str]):
...
@overload
def __init__(
self, /, source: Image, sub: Literal[False], x1: int, y1: int, x2: int, y2: int
):
...
def __init__(self, *args):
"""Image(source, sub=False)
Arguments:
source (str or Image):
The source of the image.
@@ -39,36 +55,47 @@ class Image:
bottom-right coordinates in the ``source`` image that will be
used as the bounds for the sub-image.
"""
pass
@property
def width(self):
def width(self) -> int:
"""Gets the width of |this image| in pixels."""
return 0
@property
def height(self):
def height(self) -> int:
"""Gets the height of |this image| in pixels."""
return 0
def clear(self):
"""Clears |this image|. All pixels on |this image| will be set to
def clear(self) -> None:
"""clear()
Clears |this image|. All pixels on |this image| will be set to
:attr:`Color.WHITE <pybricks.parameters.Color.WHITE>`.
"""
pass
def draw_pixel(self, x, y, color=_Color.BLACK):
"""Draws a single pixel on |this image|.
def draw_pixel(self, x: int, y: int, color: Color = Color.BLACK) -> None:
"""draw_pixel(x, y, color=Color.BLACK)
Draws a single pixel on |this image|.
Arguments:
x (int): The x coordinate of the pixel.
y (int): The y coordinate of the pixel.
color (Color): The color of the pixel.
"""
pass
def draw_line(self, x1, y1, x2, y2, width=1, color=_Color.BLACK):
"""Draws a line on |this image|.
def draw_line(
self,
x1: int,
y1: int,
x2: int,
y2: int,
width: int = 1,
color: Color = Color.BLACK,
) -> None:
"""draw_line(x1, y1, x2, y2, width=1, color=Color.BLACK)
Draws a line on |this image|.
Arguments:
x1 (int): The x coordinate of the starting point of the line.
@@ -78,10 +105,20 @@ class Image:
width (int): The width of the line in pixels.
color (Color): The color of the line.
"""
pass
def draw_box(self, x1, y1, x2, y2, r=0, fill=False, color=_Color.BLACK):
"""Draws a box on |this image|.
def draw_box(
self,
x1: int,
y1: int,
x2: int,
y2: int,
r: int = 0,
fill: bool = False,
color: Color = Color.BLACK,
) -> None:
"""draw_box(x1, y1, x2, y2, r=0, fill=False, color=Color.BLACK)
Draws a box on |this image|.
Arguments:
x1 (int): The x coordinate of the left side of the box.
@@ -93,10 +130,13 @@ class Image:
otherwise only the outline of the box will be drawn.
color (Color): The color of the box.
"""
pass
def draw_circle(self, x, y, r, fill=False, color=_Color.BLACK):
"""Draws a circle on |this image|.
def draw_circle(
self, x: int, y: int, r: int, fill: bool = False, color: Color = Color.BLACK
) -> None:
"""draw_circle(x, y, r, fill=False, color=Color.BLACK)
Draws a circle on |this image|.
Arguments:
x (int): The x coordinate of the center of the circle.
@@ -106,10 +146,17 @@ class Image:
``color``, otherwise only the circumference will be drawn.
color (Color): The color of the circle.
"""
pass
def draw_image(self, x, y, source, transparent=None):
"""Draws the ``source`` image on |this image|.
def draw_image(
self,
x: int,
y: int,
source: Union[Image, ImageFile, str],
transparent: Optional[Color] = None,
) -> None:
"""draw_image(x, y, source, transparent=None)
Draws the ``source`` image on |this image|.
Arguments:
x (int):
@@ -125,8 +172,10 @@ class Image:
no transparency.
"""
def load_image(self, source):
"""Clears this image, then draws the ``source`` image centered in
def load_image(self, source: Union[Image, ImageFile, str]) -> None:
"""load_image(source)
Clears this image, then draws the ``source`` image centered in
|this image|.
Arguments:
@@ -136,8 +185,17 @@ class Image:
from file.
"""
def draw_text(self, x, y, text, text_color=_Color.BLACK, background_color=None):
"""Draws text on |this image|.
def draw_text(
self,
x: int,
y: int,
text: str,
text_color: Color = Color.BLACK,
background_color: Optional[Color] = None,
) -> None:
"""draw_text(x, y, text, text_color=Color.BLACK, background_color=None)
Draws text on |this image|.
The most recent font set using :meth:`.set_font` will be used or
:data:`Font.DEFAULT <pybricks.media.ev3dev.Font.DEFAULT>` if no font
@@ -156,10 +214,11 @@ class Image:
The color used to fill the rectangle behind the text or
``None`` for transparent background.
"""
pass
def print(self, *args, sep=" ", end="\n"):
"""Prints a line of text on |this image|.
def print(self, *args: Any, sep: str = " ", end: str = "\n") -> None:
"""print(*args, sep=" ", end="\\n")
Prints a line of text on |this image|.
This method works like the builtin ``print()`` function, but it writes
on |this image| instead.
@@ -176,18 +235,16 @@ class Image:
bottom of |this image|.
Arguments:
* (object):
Zero or more objects to print.
sep (str):
Separator that will be placed between each object that is
printed.
end (str):
End of line that will be printed after the last object.
args (Any): Zero or more objects to print.
sep (str): Separator that will be placed between each object that
is printed.
end (str): End of line that will be printed after the last object.
"""
pass
def set_font(self, font):
"""Sets the font used for writing on |this image|.
def set_font(self, font: Font) -> None:
"""set_font(font)
Sets the font used for writing on |this image|.
The font is used for both :meth:`.draw_text` and :meth:`.print`.
@@ -195,11 +252,10 @@ class Image:
font (Font):
The font to use.
"""
pass
@staticmethod
def empty(width=178, height=128):
"""empty(width=<screen width>, height=<screen height>)
def empty(width: int = 178, height: int = 128) -> Image:
"""empty(width=178, height=128) -> Image
Creates a new empty :class:`Image` object.
@@ -210,21 +266,22 @@ class Image:
The height of the image in pixels.
Returns:
Image:
A new image with all pixels set to :attr:`Color.WHITE
<pybricks.parameters.Color.WHITE>`.
A new image with all pixels set
to :attr:`Color.WHITE <pybricks.parameters.Color.WHITE>`.
Raises:
TypeError:
``width`` or ``height`` is not a number.
If ``width`` or ``height`` is not a number.
ValueError:
``width`` or ``height`` is less than 1.
If ``width`` or ``height`` is less than 1.
RuntimeError:
There was a problem allocating a new image.
If there was a problem allocating a new image.
"""
def save(self, filename):
"""Saves |this image| as a ``.png`` file.
def save(self, filename: str) -> None:
"""save(filename)
Saves |this image| as a ``.png`` file.
Arguments:
filename (str):
@@ -241,13 +298,21 @@ class Image:
class Font:
"""Object that represents a font for writing text."""
DEFAULT = None # assigned later since we can't use Font() here
DEFAULT: Font = None # assigned later since we can't use Font() here
"""The default font."""
def __init__(
self, family=None, size=12, bold=False, monospace=False, lang=None, script=None
self,
family: Optional[str] = None,
size: int = 12,
bold: bool = False,
monospace: bool = False,
lang: Optional[str] = None,
script: Optional[str] = None,
):
"""The font object will be a font that is the "best" match based on the
"""Font(family=None, size=12, bold=False, monospace=False, lang=None, script=None)
The font object will be a font that is the "best" match based on the
parameters given and available fonts installed.
Arguments:
@@ -269,30 +334,34 @@ class Font:
"""
@property
def family(self):
def family(self) -> str:
"""Gets the family name of the font."""
return "Lucida"
@property
def style(self):
"""Gets a string describing the font style.
def style(self) -> str:
"""style -> str
Gets a string describing the font style.
Can be "Regular" or "Bold".
"""
return "Regular"
@property
def width(self):
def width(self) -> int:
"""Gets the width of the widest character of the font."""
return 0
@property
def height(self):
def height(self) -> int:
"""Gets the height of the font."""
return 0
def text_width(self, text):
"""Gets the width of the text when the text is drawn using this font.
def text_width(self, text: str) -> int:
"""text_width(text)
Gets the width of the text when the text is drawn using this font.
Arguments:
text (str):
@@ -304,8 +373,10 @@ class Font:
"""
return 0
def text_height(self, text):
"""Gets the height of the text when the text is drawn using this font.
def text_height(self, text: str) -> int:
"""text_height(text)
Gets the height of the text when the text is drawn using this font.
Arguments:
text (str):
@@ -324,153 +395,153 @@ Font.DEFAULT = Font("Lucida", 12)
class SoundFile:
"""Paths to standard EV3 sounds."""
_BASE_PATH = "/usr/share/sounds/ev3dev/"
SHOUTING = _BASE_PATH + "expressions/shouting.wav"
CHEERING = _BASE_PATH + "expressions/cheering.wav"
CRYING = _BASE_PATH + "expressions/crying.wav"
OUCH = _BASE_PATH + "expressions/ouch.wav"
LAUGHING_2 = _BASE_PATH + "expressions/laughing_2.wav"
SNEEZING = _BASE_PATH + "expressions/sneezing.wav"
SMACK = _BASE_PATH + "expressions/smack.wav"
BOING = _BASE_PATH + "expressions/boing.wav"
BOO = _BASE_PATH + "expressions/boo.wav"
UH_OH = _BASE_PATH + "expressions/uh-oh.wav"
SNORING = _BASE_PATH + "expressions/snoring.wav"
KUNG_FU = _BASE_PATH + "expressions/kung_fu.wav"
FANFARE = _BASE_PATH + "expressions/fanfare.wav"
CRUNCHING = _BASE_PATH + "expressions/crunching.wav"
MAGIC_WAND = _BASE_PATH + "expressions/magic_wand.wav"
LAUGHING_1 = _BASE_PATH + "expressions/laughing_1.wav"
LEFT = _BASE_PATH + "information/left.wav"
BACKWARDS = _BASE_PATH + "information/backwards.wav"
RIGHT = _BASE_PATH + "information/right.wav"
OBJECT = _BASE_PATH + "information/object.wav"
COLOR = _BASE_PATH + "information/color.wav"
FLASHING = _BASE_PATH + "information/flashing.wav"
ERROR = _BASE_PATH + "information/error.wav"
ERROR_ALARM = _BASE_PATH + "information/error_alarm.wav"
DOWN = _BASE_PATH + "information/down.wav"
FORWARD = _BASE_PATH + "information/forward.wav"
ACTIVATE = _BASE_PATH + "information/activate.wav"
SEARCHING = _BASE_PATH + "information/searching.wav"
TOUCH = _BASE_PATH + "information/touch.wav"
UP = _BASE_PATH + "information/up.wav"
ANALYZE = _BASE_PATH + "information/analyze.wav"
STOP = _BASE_PATH + "information/stop.wav"
DETECTED = _BASE_PATH + "information/detected.wav"
TURN = _BASE_PATH + "information/turn.wav"
START = _BASE_PATH + "information/start.wav"
MORNING = _BASE_PATH + "communication/morning.wav"
EV3 = _BASE_PATH + "communication/ev3.wav"
GO = _BASE_PATH + "communication/go.wav"
GOOD_JOB = _BASE_PATH + "communication/good_job.wav"
OKEY_DOKEY = _BASE_PATH + "communication/okey-dokey.wav"
GOOD = _BASE_PATH + "communication/good.wav"
NO = _BASE_PATH + "communication/no.wav"
THANK_YOU = _BASE_PATH + "communication/thank_you.wav"
YES = _BASE_PATH + "communication/yes.wav"
GAME_OVER = _BASE_PATH + "communication/game_over.wav"
OKAY = _BASE_PATH + "communication/okay.wav"
SORRY = _BASE_PATH + "communication/sorry.wav"
BRAVO = _BASE_PATH + "communication/bravo.wav"
GOODBYE = _BASE_PATH + "communication/goodbye.wav"
HI = _BASE_PATH + "communication/hi.wav"
HELLO = _BASE_PATH + "communication/hello.wav"
MINDSTORMS = _BASE_PATH + "communication/mindstorms.wav"
LEGO = _BASE_PATH + "communication/lego.wav"
FANTASTIC = _BASE_PATH + "communication/fantastic.wav"
SPEED_IDLE = _BASE_PATH + "movements/speed_idle.wav"
SPEED_DOWN = _BASE_PATH + "movements/speed_down.wav"
SPEED_UP = _BASE_PATH + "movements/speed_up.wav"
BROWN = _BASE_PATH + "colors/brown.wav"
GREEN = _BASE_PATH + "colors/green.wav"
BLACK = _BASE_PATH + "colors/black.wav"
WHITE = _BASE_PATH + "colors/white.wav"
RED = _BASE_PATH + "colors/red.wav"
BLUE = _BASE_PATH + "colors/blue.wav"
YELLOW = _BASE_PATH + "colors/yellow.wav"
TICK_TACK = _BASE_PATH + "mechanical/tick_tack.wav"
HORN_1 = _BASE_PATH + "mechanical/horn_1.wav"
BACKING_ALERT = _BASE_PATH + "mechanical/backing_alert.wav"
MOTOR_IDLE = _BASE_PATH + "mechanical/motor_idle.wav"
AIR_RELEASE = _BASE_PATH + "mechanical/air_release.wav"
AIRBRAKE = _BASE_PATH + "mechanical/airbrake.wav"
RATCHET = _BASE_PATH + "mechanical/ratchet.wav"
MOTOR_STOP = _BASE_PATH + "mechanical/motor_stop.wav"
HORN_2 = _BASE_PATH + "mechanical/horn_2.wav"
LASER = _BASE_PATH + "mechanical/laser.wav"
SONAR = _BASE_PATH + "mechanical/sonar.wav"
MOTOR_START = _BASE_PATH + "mechanical/motor_start.wav"
INSECT_BUZZ_2 = _BASE_PATH + "animals/insect_buzz_2.wav"
ELEPHANT_CALL = _BASE_PATH + "animals/elephant_call.wav"
SNAKE_HISS = _BASE_PATH + "animals/snake_hiss.wav"
DOG_BARK_2 = _BASE_PATH + "animals/dog_bark_2.wav"
DOG_WHINE = _BASE_PATH + "animals/dog_whine.wav"
INSECT_BUZZ_1 = _BASE_PATH + "animals/insect_buzz_1.wav"
DOG_SNIFF = _BASE_PATH + "animals/dog_sniff.wav"
T_REX_ROAR = _BASE_PATH + "animals/t-rex_roar.wav"
INSECT_CHIRP = _BASE_PATH + "animals/insect_chirp.wav"
DOG_GROWL = _BASE_PATH + "animals/dog_growl.wav"
SNAKE_RATTLE = _BASE_PATH + "animals/snake_rattle.wav"
DOG_BARK_1 = _BASE_PATH + "animals/dog_bark_1.wav"
CAT_PURR = _BASE_PATH + "animals/cat_purr.wav"
EIGHT = _BASE_PATH + "numbers/eight.wav"
SEVEN = _BASE_PATH + "numbers/seven.wav"
SIX = _BASE_PATH + "numbers/six.wav"
FOUR = _BASE_PATH + "numbers/four.wav"
TEN = _BASE_PATH + "numbers/ten.wav"
ONE = _BASE_PATH + "numbers/one.wav"
TWO = _BASE_PATH + "numbers/two.wav"
THREE = _BASE_PATH + "numbers/three.wav"
ZERO = _BASE_PATH + "numbers/zero.wav"
FIVE = _BASE_PATH + "numbers/five.wav"
NINE = _BASE_PATH + "numbers/nine.wav"
READY = _BASE_PATH + "system/ready.wav"
CONFIRM = _BASE_PATH + "system/confirm.wav"
GENERAL_ALERT = _BASE_PATH + "system/general_alert.wav"
CLICK = _BASE_PATH + "system/click.wav"
OVERPOWER = _BASE_PATH + "system/overpower.wav"
_BASE_PATH: str = "/usr/share/sounds/ev3dev/"
SHOUTING: str = _BASE_PATH + "expressions/shouting.wav"
CHEERING: str = _BASE_PATH + "expressions/cheering.wav"
CRYING: str = _BASE_PATH + "expressions/crying.wav"
OUCH: str = _BASE_PATH + "expressions/ouch.wav"
LAUGHING_2: str = _BASE_PATH + "expressions/laughing_2.wav"
SNEEZING: str = _BASE_PATH + "expressions/sneezing.wav"
SMACK: str = _BASE_PATH + "expressions/smack.wav"
BOING: str = _BASE_PATH + "expressions/boing.wav"
BOO: str = _BASE_PATH + "expressions/boo.wav"
UH_OH: str = _BASE_PATH + "expressions/uh-oh.wav"
SNORING: str = _BASE_PATH + "expressions/snoring.wav"
KUNG_FU: str = _BASE_PATH + "expressions/kung_fu.wav"
FANFARE: str = _BASE_PATH + "expressions/fanfare.wav"
CRUNCHING: str = _BASE_PATH + "expressions/crunching.wav"
MAGIC_WAND: str = _BASE_PATH + "expressions/magic_wand.wav"
LAUGHING_1: str = _BASE_PATH + "expressions/laughing_1.wav"
LEFT: str = _BASE_PATH + "information/left.wav"
BACKWARDS: str = _BASE_PATH + "information/backwards.wav"
RIGHT: str = _BASE_PATH + "information/right.wav"
OBJECT: str = _BASE_PATH + "information/object.wav"
COLOR: str = _BASE_PATH + "information/color.wav"
FLASHING: str = _BASE_PATH + "information/flashing.wav"
ERROR: str = _BASE_PATH + "information/error.wav"
ERROR_ALARM: str = _BASE_PATH + "information/error_alarm.wav"
DOWN: str = _BASE_PATH + "information/down.wav"
FORWARD: str = _BASE_PATH + "information/forward.wav"
ACTIVATE: str = _BASE_PATH + "information/activate.wav"
SEARCHING: str = _BASE_PATH + "information/searching.wav"
TOUCH: str = _BASE_PATH + "information/touch.wav"
UP: str = _BASE_PATH + "information/up.wav"
ANALYZE: str = _BASE_PATH + "information/analyze.wav"
STOP: str = _BASE_PATH + "information/stop.wav"
DETECTED: str = _BASE_PATH + "information/detected.wav"
TURN: str = _BASE_PATH + "information/turn.wav"
START: str = _BASE_PATH + "information/start.wav"
MORNING: str = _BASE_PATH + "communication/morning.wav"
EV3: str = _BASE_PATH + "communication/ev3.wav"
GO: str = _BASE_PATH + "communication/go.wav"
GOOD_JOB: str = _BASE_PATH + "communication/good_job.wav"
OKEY_DOKEY: str = _BASE_PATH + "communication/okey-dokey.wav"
GOOD: str = _BASE_PATH + "communication/good.wav"
NO: str = _BASE_PATH + "communication/no.wav"
THANK_YOU: str = _BASE_PATH + "communication/thank_you.wav"
YES: str = _BASE_PATH + "communication/yes.wav"
GAME_OVER: str = _BASE_PATH + "communication/game_over.wav"
OKAY: str = _BASE_PATH + "communication/okay.wav"
SORRY: str = _BASE_PATH + "communication/sorry.wav"
BRAVO: str = _BASE_PATH + "communication/bravo.wav"
GOODBYE: str = _BASE_PATH + "communication/goodbye.wav"
HI: str = _BASE_PATH + "communication/hi.wav"
HELLO: str = _BASE_PATH + "communication/hello.wav"
MINDSTORMS: str = _BASE_PATH + "communication/mindstorms.wav"
LEGO: str = _BASE_PATH + "communication/lego.wav"
FANTASTIC: str = _BASE_PATH + "communication/fantastic.wav"
SPEED_IDLE: str = _BASE_PATH + "movements/speed_idle.wav"
SPEED_DOWN: str = _BASE_PATH + "movements/speed_down.wav"
SPEED_UP: str = _BASE_PATH + "movements/speed_up.wav"
BROWN: str = _BASE_PATH + "colors/brown.wav"
GREEN: str = _BASE_PATH + "colors/green.wav"
BLACK: str = _BASE_PATH + "colors/black.wav"
WHITE: str = _BASE_PATH + "colors/white.wav"
RED: str = _BASE_PATH + "colors/red.wav"
BLUE: str = _BASE_PATH + "colors/blue.wav"
YELLOW: str = _BASE_PATH + "colors/yellow.wav"
TICK_TACK: str = _BASE_PATH + "mechanical/tick_tack.wav"
HORN_1: str = _BASE_PATH + "mechanical/horn_1.wav"
BACKING_ALERT: str = _BASE_PATH + "mechanical/backing_alert.wav"
MOTOR_IDLE: str = _BASE_PATH + "mechanical/motor_idle.wav"
AIR_RELEASE: str = _BASE_PATH + "mechanical/air_release.wav"
AIRBRAKE: str = _BASE_PATH + "mechanical/airbrake.wav"
RATCHET: str = _BASE_PATH + "mechanical/ratchet.wav"
MOTOR_STOP: str = _BASE_PATH + "mechanical/motor_stop.wav"
HORN_2: str = _BASE_PATH + "mechanical/horn_2.wav"
LASER: str = _BASE_PATH + "mechanical/laser.wav"
SONAR: str = _BASE_PATH + "mechanical/sonar.wav"
MOTOR_START: str = _BASE_PATH + "mechanical/motor_start.wav"
INSECT_BUZZ_2: str = _BASE_PATH + "animals/insect_buzz_2.wav"
ELEPHANT_CALL: str = _BASE_PATH + "animals/elephant_call.wav"
SNAKE_HISS: str = _BASE_PATH + "animals/snake_hiss.wav"
DOG_BARK_2: str = _BASE_PATH + "animals/dog_bark_2.wav"
DOG_WHINE: str = _BASE_PATH + "animals/dog_whine.wav"
INSECT_BUZZ_1: str = _BASE_PATH + "animals/insect_buzz_1.wav"
DOG_SNIFF: str = _BASE_PATH + "animals/dog_sniff.wav"
T_REX_ROAR: str = _BASE_PATH + "animals/t-rex_roar.wav"
INSECT_CHIRP: str = _BASE_PATH + "animals/insect_chirp.wav"
DOG_GROWL: str = _BASE_PATH + "animals/dog_growl.wav"
SNAKE_RATTLE: str = _BASE_PATH + "animals/snake_rattle.wav"
DOG_BARK_1: str = _BASE_PATH + "animals/dog_bark_1.wav"
CAT_PURR: str = _BASE_PATH + "animals/cat_purr.wav"
EIGHT: str = _BASE_PATH + "numbers/eight.wav"
SEVEN: str = _BASE_PATH + "numbers/seven.wav"
SIX: str = _BASE_PATH + "numbers/six.wav"
FOUR: str = _BASE_PATH + "numbers/four.wav"
TEN: str = _BASE_PATH + "numbers/ten.wav"
ONE: str = _BASE_PATH + "numbers/one.wav"
TWO: str = _BASE_PATH + "numbers/two.wav"
THREE: str = _BASE_PATH + "numbers/three.wav"
ZERO: str = _BASE_PATH + "numbers/zero.wav"
FIVE: str = _BASE_PATH + "numbers/five.wav"
NINE: str = _BASE_PATH + "numbers/nine.wav"
READY: str = _BASE_PATH + "system/ready.wav"
CONFIRM: str = _BASE_PATH + "system/confirm.wav"
GENERAL_ALERT: str = _BASE_PATH + "system/general_alert.wav"
CLICK: str = _BASE_PATH + "system/click.wav"
OVERPOWER: str = _BASE_PATH + "system/overpower.wav"
class ImageFile:
"""Paths to standard EV3 images."""
_BASE_PATH = "/usr/share/images/ev3dev/mono/"
RIGHT = _BASE_PATH + "information/right.png"
FORWARD = _BASE_PATH + "information/forward.png"
ACCEPT = _BASE_PATH + "information/accept.png"
QUESTION_MARK = _BASE_PATH + "information/question_mark.png"
STOP_1 = _BASE_PATH + "information/stop_1.png"
LEFT = _BASE_PATH + "information/left.png"
DECLINE = _BASE_PATH + "information/decline.png"
THUMBS_DOWN = _BASE_PATH + "information/thumbs_down.png"
BACKWARD = _BASE_PATH + "information/backward.png"
NO_GO = _BASE_PATH + "information/no_go.png"
WARNING = _BASE_PATH + "information/warning.png"
STOP_2 = _BASE_PATH + "information/stop_2.png"
THUMBS_UP = _BASE_PATH + "information/thumbs_up.png"
EV3 = _BASE_PATH + "lego/ev3.png"
EV3_ICON = _BASE_PATH + "lego/ev3_icon.png"
TARGET = _BASE_PATH + "objects/target.png"
BOTTOM_RIGHT = _BASE_PATH + "eyes/bottom_right.png"
BOTTOM_LEFT = _BASE_PATH + "eyes/bottom_left.png"
EVIL = _BASE_PATH + "eyes/evil.png"
CRAZY_2 = _BASE_PATH + "eyes/crazy_2.png"
KNOCKED_OUT = _BASE_PATH + "eyes/knocked_out.png"
PINCHED_RIGHT = _BASE_PATH + "eyes/pinched_right.png"
WINKING = _BASE_PATH + "eyes/winking.png"
DIZZY = _BASE_PATH + "eyes/dizzy.png"
DOWN = _BASE_PATH + "eyes/down.png"
TIRED_MIDDLE = _BASE_PATH + "eyes/tired_middle.png"
MIDDLE_RIGHT = _BASE_PATH + "eyes/middle_right.png"
SLEEPING = _BASE_PATH + "eyes/sleeping.png"
MIDDLE_LEFT = _BASE_PATH + "eyes/middle_left.png"
TIRED_RIGHT = _BASE_PATH + "eyes/tired_right.png"
PINCHED_LEFT = _BASE_PATH + "eyes/pinched_left.png"
PINCHED_MIDDLE = _BASE_PATH + "eyes/pinched_middle.png"
CRAZY_1 = _BASE_PATH + "eyes/crazy_1.png"
NEUTRAL = _BASE_PATH + "eyes/neutral.png"
AWAKE = _BASE_PATH + "eyes/awake.png"
UP = _BASE_PATH + "eyes/up.png"
TIRED_LEFT = _BASE_PATH + "eyes/tired_left.png"
ANGRY = _BASE_PATH + "eyes/angry.png"
_BASE_PATH: str = "/usr/share/images/ev3dev/mono/"
RIGHT: str = _BASE_PATH + "information/right.png"
FORWARD: str = _BASE_PATH + "information/forward.png"
ACCEPT: str = _BASE_PATH + "information/accept.png"
QUESTION_MARK: str = _BASE_PATH + "information/question_mark.png"
STOP_1: str = _BASE_PATH + "information/stop_1.png"
LEFT: str = _BASE_PATH + "information/left.png"
DECLINE: str = _BASE_PATH + "information/decline.png"
THUMBS_DOWN: str = _BASE_PATH + "information/thumbs_down.png"
BACKWARD: str = _BASE_PATH + "information/backward.png"
NO_GO: str = _BASE_PATH + "information/no_go.png"
WARNING: str = _BASE_PATH + "information/warning.png"
STOP_2: str = _BASE_PATH + "information/stop_2.png"
THUMBS_UP: str = _BASE_PATH + "information/thumbs_up.png"
EV3: str = _BASE_PATH + "lego/ev3.png"
EV3_ICON: str = _BASE_PATH + "lego/ev3_icon.png"
TARGET: str = _BASE_PATH + "objects/target.png"
BOTTOM_RIGHT: str = _BASE_PATH + "eyes/bottom_right.png"
BOTTOM_LEFT: str = _BASE_PATH + "eyes/bottom_left.png"
EVIL: str = _BASE_PATH + "eyes/evil.png"
CRAZY_2: str = _BASE_PATH + "eyes/crazy_2.png"
KNOCKED_OUT: str = _BASE_PATH + "eyes/knocked_out.png"
PINCHED_RIGHT: str = _BASE_PATH + "eyes/pinched_right.png"
WINKING: str = _BASE_PATH + "eyes/winking.png"
DIZZY: str = _BASE_PATH + "eyes/dizzy.png"
DOWN: str = _BASE_PATH + "eyes/down.png"
TIRED_MIDDLE: str = _BASE_PATH + "eyes/tired_middle.png"
MIDDLE_RIGHT: str = _BASE_PATH + "eyes/middle_right.png"
SLEEPING: str = _BASE_PATH + "eyes/sleeping.png"
MIDDLE_LEFT: str = _BASE_PATH + "eyes/middle_left.png"
TIRED_RIGHT: str = _BASE_PATH + "eyes/tired_right.png"
PINCHED_LEFT: str = _BASE_PATH + "eyes/pinched_left.png"
PINCHED_MIDDLE: str = _BASE_PATH + "eyes/pinched_middle.png"
CRAZY_1: str = _BASE_PATH + "eyes/crazy_1.png"
NEUTRAL: str = _BASE_PATH + "eyes/neutral.png"
AWAKE: str = _BASE_PATH + "eyes/awake.png"
UP: str = _BASE_PATH + "eyes/up.png"
TIRED_LEFT: str = _BASE_PATH + "eyes/tired_left.png"
ANGRY: str = _BASE_PATH + "eyes/angry.png"
-232
View File
@@ -1,232 +0,0 @@
# SPDX-License-Identifier: MIT
# Copyright (c) 2020 The Pybricks Authors
from typing import Any, Literal, Optional, Union, overload
from ..parameters import Color
class Image:
@overload
def __init__(self, /, source: Union[Image, ImageFile, str]): ...
@overload
def __init__(
self, /, source: Image, sub: Literal[True], x1: int, y1: int, x2: int, y2: int
): ...
@property
def width(self) -> int: ...
@property
def height(self) -> int: ...
def clear(self) -> None: ...
def draw_pixel(self, x: int, y: int, color: Color = Color.BLACK) -> None: ...
def draw_line(
self,
x1: int,
y1: int,
x2: int,
y2: int,
width: int = 1,
color: Color = Color.BLACK,
) -> None: ...
def draw_box(
self,
x1: int,
y1: int,
x2: int,
y2: int,
r: int = 0,
fill: bool = False,
color: Color = Color.BLACK,
) -> None: ...
def draw_circle(
self, x: int, y: int, r: int, fill: bool = False, color: Color = Color.BLACK
) -> None: ...
def draw_image(
self,
x: int,
y: int,
source: Union[Image, ImageFile, str],
transparent: Optional[Color] = None,
) -> None: ...
def load_image(self, source: Union[Image, ImageFile, str]) -> None: ...
def draw_text(
self,
x: int,
y: int,
text: str,
text_color: Color = Color.BLACK,
background_color: Optional[Color] = None,
) -> None: ...
def print(self, *args: Any, sep: str = " ", end: str = "\n") -> None: ...
def set_font(self, font: Font) -> None: ...
@staticmethod
def empty(width: int = 178, height: int = 128) -> Image: ...
def save(self, filename: str) -> None: ...
class Font:
DEFAULT: Font
def __init__(
self,
family: Optional[str] = None,
size: int = 12,
bold: bool = False,
monospace: bool = False,
lang: Optional[str] = None,
script: Optional[str] = None,
): ...
@property
def family(self) -> str: ...
@property
def style(self) -> str: ...
@property
def width(self) -> int: ...
@property
def height(self) -> int: ...
def text_width(self, text: str) -> int: ...
def text_height(self, text: str) -> int: ...
class SoundFile:
SHOUTING: SoundFile
CHEERING: SoundFile
CRYING: SoundFile
OUCH: SoundFile
LAUGHING_2: SoundFile
SNEEZING: SoundFile
SMACK: SoundFile
BOING: SoundFile
BOO: SoundFile
UH_OH: SoundFile
SNORING: SoundFile
KUNG_FU: SoundFile
FANFARE: SoundFile
CRUNCHING: SoundFile
MAGIC_WAND: SoundFile
LAUGHING_1: SoundFile
LEFT: SoundFile
BACKWARDS: SoundFile
RIGHT: SoundFile
OBJECT: SoundFile
COLOR: SoundFile
FLASHING: SoundFile
ERROR: SoundFile
ERROR_ALARM: SoundFile
DOWN: SoundFile
FORWARD: SoundFile
ACTIVATE: SoundFile
SEARCHING: SoundFile
TOUCH: SoundFile
UP: SoundFile
ANALYZE: SoundFile
STOP: SoundFile
DETECTED: SoundFile
TURN: SoundFile
START: SoundFile
MORNING: SoundFile
EV3: SoundFile
GO: SoundFile
GOOD_JOB: SoundFile
OKEY_DOKEY: SoundFile
GOOD: SoundFile
NO: SoundFile
THANK_YOU: SoundFile
YES: SoundFile
GAME_OVER: SoundFile
OKAY: SoundFile
SORRY: SoundFile
BRAVO: SoundFile
GOODBYE: SoundFile
HI: SoundFile
HELLO: SoundFile
MINDSTORMS: SoundFile
LEGO: SoundFile
FANTASTIC: SoundFile
SPEED_IDLE: SoundFile
SPEED_DOWN: SoundFile
SPEED_UP: SoundFile
BROWN: SoundFile
GREEN: SoundFile
BLACK: SoundFile
WHITE: SoundFile
RED: SoundFile
BLUE: SoundFile
YELLOW: SoundFile
TICK_TACK: SoundFile
HORN_1: SoundFile
BACKING_ALERT: SoundFile
MOTOR_IDLE: SoundFile
AIR_RELEASE: SoundFile
AIRBRAKE: SoundFile
RATCHET: SoundFile
MOTOR_STOP: SoundFile
HORN_2: SoundFile
LASER: SoundFile
SONAR: SoundFile
MOTOR_START: SoundFile
INSECT_BUZZ_2: SoundFile
ELEPHANT_CALL: SoundFile
SNAKE_HISS: SoundFile
DOG_BARK_2: SoundFile
DOG_WHINE: SoundFile
INSECT_BUZZ_1: SoundFile
DOG_SNIFF: SoundFile
T_REX_ROAR: SoundFile
INSECT_CHIRP: SoundFile
DOG_GROWL: SoundFile
SNAKE_RATTLE: SoundFile
DOG_BARK_1: SoundFile
CAT_PURR: SoundFile
EIGHT: SoundFile
SEVEN: SoundFile
SIX: SoundFile
FOUR: SoundFile
TEN: SoundFile
ONE: SoundFile
TWO: SoundFile
THREE: SoundFile
ZERO: SoundFile
FIVE: SoundFile
NINE: SoundFile
READY: SoundFile
CONFIRM: SoundFile
GENERAL_ALERT: SoundFile
CLICK: SoundFile
OVERPOWER: SoundFile
class ImageFile:
RIGHT: ImageFile
FORWARD: ImageFile
ACCEPT: ImageFile
QUESTION_MARK: ImageFile
STOP_1: ImageFile
LEFT: ImageFile
DECLINE: ImageFile
THUMBS_DOWN: ImageFile
BACKWARD: ImageFile
NO_GO: ImageFile
WARNING: ImageFile
STOP_2: ImageFile
THUMBS_UP: ImageFile
EV3: ImageFile
EV3_ICON: ImageFile
TARGET: ImageFile
BOTTOM_RIGHT: ImageFile
BOTTOM_LEFT: ImageFile
EVIL: ImageFile
CRAZY_2: ImageFile
KNOCKED_OUT: ImageFile
PINCHED_RIGHT: ImageFile
WINKING: ImageFile
DIZZY: ImageFile
DOWN: ImageFile
TIRED_MIDDLE: ImageFile
MIDDLE_RIGHT: ImageFile
SLEEPING: ImageFile
MIDDLE_LEFT: ImageFile
TIRED_RIGHT: ImageFile
PINCHED_LEFT: ImageFile
PINCHED_MIDDLE: ImageFile
CRAZY_1: ImageFile
NEUTRAL: ImageFile
AWAKE: ImageFile
UP: ImageFile
TIRED_LEFT: ImageFile
ANGRY: ImageFile
+84 -35
View File
@@ -5,10 +5,38 @@
Classes to exchange messages between EV3 bricks.
"""
from __future__ import annotations
class Mailbox:
def __init__(self, name, connection, encode=None, decode=None):
"""Object that represents a mailbox containing data.
from typing import abstractmethod, TypeVar, Optional, Callable, Generic
T = TypeVar("T")
class Connection:
@abstractmethod
def read_from_mailbox(self, name: str) -> bytes:
...
@abstractmethod
def send_to_mailbox(self, name: str, data: bytes) -> None:
...
@abstractmethod
def wait_for_mailbox_update(self, name: str) -> None:
...
class Mailbox(Generic[T]):
def __init__(
self,
name: str,
connection: Connection,
encode: Optional[Callable[[T], bytes]] = None,
decode: Optional[Callable[[bytes], T]] = None,
):
"""Mailbox(name, connection, encode=None, decode=None)
Object that represents a mailbox containing data.
You can read data that is delivered by other EV3 bricks, or send data
to other bricks that have the same mailbox.
@@ -29,16 +57,20 @@ class Mailbox:
Function that creates a new Python object from bytes.
"""
def read(self):
"""Gets the current value of the mailbox.
def read(self) -> T:
"""read()
Gets the current value of the mailbox.
Returns:
The current value or ``None`` if the mailbox is empty.
"""
return ""
def send(self, value, brick=None):
"""Sends a value to this mailbox on connected devices.
def send(self, value: T, brick: Optional[str] = None) -> None:
"""send(value, brick=None)
Sends a value to this mailbox on connected devices.
Arguments:
value:
@@ -52,23 +84,28 @@ class Mailbox:
There is a problem with the connection.
"""
def wait(self):
"""Waits for the mailbox to be updated by remote device."""
def wait(self) -> None:
"""wait()
def wait_new(self):
"""Waits for a new value to be delivered to the mailbox that is not
Waits for the mailbox to be updated by remote device."""
def wait_new(self) -> T:
"""wait_new()
Waits for a new value to be delivered to the mailbox that is not
equal to the current value in the mailbox.
Returns:
The new value.
"""
return object()
class LogicMailbox(Mailbox):
def __init__(self, name, connection):
"""Object that represents a mailbox containing boolean data.
class LogicMailbox(Mailbox[bool]):
def __init__(self, name: str, connection: Connection):
"""LogicMailbox(name, connection)
Object that represents a mailbox containing boolean data.
This works just like a regular :class:`Mailbox`, but values
must be ``True`` or ``False``.
@@ -83,9 +120,11 @@ class LogicMailbox(Mailbox):
"""
class NumericMailbox(Mailbox):
def __init__(self, name, connection):
"""Object that represents a mailbox containing numeric data.
class NumericMailbox(Mailbox[float]):
def __init__(self, name: str, connection: Connection):
"""NumericMailbox(name, connection)
Object that represents a mailbox containing numeric data.
This works just like a regular :class:`Mailbox`, but values must be a
number, such as ``15`` or ``12.345``
@@ -100,12 +139,14 @@ class NumericMailbox(Mailbox):
"""
class TextMailbox(Mailbox):
def __init__(self, name, connection):
"""Object that represents a mailbox containing text data.
class TextMailbox(Mailbox[str]):
def __init__(self, name: str, connection: Connection):
"""TextMailbox(name, connection)
Object that represents a mailbox containing text data.
This works just like a regular :class:`Mailbox`, but data must be a
string, such as ``'hello!'`` or ``'My name is EV3'``.
string, such as ``'hello!'``.
This is compatible with the "text" mailbox type in EV3-G.
@@ -127,14 +168,16 @@ class BluetoothMailboxServer:
A "server" waits for a "client" to connect to it.
"""
def __enter__(self):
def __enter__(self) -> BluetoothMailboxServer:
return self
def __exit__(self, type, value, traceback):
self.close()
def __exit__(self, type, value, traceback) -> None:
self.server_close()
def wait_for_connection(self, count=1):
"""Waits for a :class:`BluetoothMailboxClient` on a remote device to
def wait_for_connection(self, count: int = 1) -> None:
"""wait_for_connection(count=1)
Waits for a :class:`BluetoothMailboxClient` on a remote device to
connect.
Arguments:
@@ -146,8 +189,10 @@ class BluetoothMailboxServer:
There was a problem establishing the connection.
"""
def close(self):
"""Closes all connections."""
def server_close(self) -> None:
"""server_close()
Closes all connections."""
class BluetoothMailboxClient:
@@ -159,14 +204,16 @@ class BluetoothMailboxClient:
A "client" initiates a connection to a waiting "server".
"""
def __enter__(self):
def __enter__(self) -> BluetoothMailboxClient:
return self
def __exit__(self, type, value, traceback):
def __exit__(self, type, value, traceback) -> None:
self.close()
def connect(self, brick):
"""Connects to an :class:`BluetoothMailboxServer` on another device.
def connect(self, brick: str) -> None:
"""connect(brick)
Connects to an :class:`BluetoothMailboxServer` on another device.
The remote device must be paired and waiting for a connection. See
:meth:`BluetoothMailboxServer.wait_for_connection`.
@@ -180,5 +227,7 @@ class BluetoothMailboxClient:
There was a problem establishing the connection.
"""
def server_close(self):
"""Closes all connections."""
def close(self) -> None:
"""close()
Closes all connections."""
-49
View File
@@ -1,49 +0,0 @@
# SPDX-License-Identifier: MIT
# Copyright (c) 2020 The Pybricks Authors
from abc import abstractmethod
from typing import Callable, Generic, Optional, TypeVar
T = TypeVar("T")
class Connection:
@abstractmethod
def read_from_mailbox(self, name: str) -> bytes: ...
@abstractmethod
def send_to_mailbox(self, name: str, data: bytes) -> None: ...
@abstractmethod
def wait_for_mailbox_update(self, name: str) -> None: ...
class Mailbox(Generic[T]):
def __init__(
self,
name: str,
connection: Connection,
encode: Optional[Callable[[T], bytes]] = None,
decode: Optional[Callable[[bytes], T]] = None,
): ...
def read(self) -> T: ...
def send(self, value: T, brick: Optional[str] = None) -> None: ...
def wait(self) -> None: ...
def wait_new(self) -> T: ...
class LogicMailbox(Mailbox[bool]):
def __init__(self, name, connection: Connection): ...
class NumericMailbox(Mailbox[float]):
def __init__(self, name, connection: Connection): ...
class TextMailbox(Mailbox[str]):
def __init__(self, name, connection: Connection): ...
class BluetoothMailboxServer(Connection):
def __enter__(self) -> BluetoothMailboxServer: ...
def __exit__(self, type, value, traceback) -> None: ...
def wait_for_connection(self, count: int = 1) -> None: ...
def server_close(self) -> None: ...
class BluetoothMailboxClient(Connection):
def __enter__(self) -> BluetoothMailboxClient: ...
def __exit__(self, type, value, traceback) -> None: ...
def connect(self, brick: str) -> None: ...
def close(self) -> None: ...
+3 -63
View File
@@ -4,10 +4,10 @@
"""Use LEGO® MINDSTORMS® NXT motors and sensors with the EV3 brick."""
from .parameters import Port, Color
from .parameters import Port
from ._common import ColorLight, CommonColorSensor
from .iodevices import AnalogSensor
from ._common import ColorLight
from typing import Callable, Optional, Tuple
@@ -22,7 +22,6 @@ class TouchSensor:
Arguments:
port (Port): Port to which the sensor is connected.
"""
pass
def pressed(self) -> bool:
"""pressed() -> bool
@@ -33,7 +32,6 @@ class TouchSensor:
``True`` if the sensor is pressed, ``False`` if it is
not pressed.
"""
pass
class LightSensor:
@@ -45,7 +43,6 @@ class LightSensor:
Arguments:
port (Port): Port to which the sensor is connected.
"""
pass
def ambient(self) -> int:
"""ambient() -> int: %
@@ -55,7 +52,6 @@ class LightSensor:
Returns:
Ambient light intensity, ranging from 0% (dark) to 100% (bright).
"""
pass
def reflection(self) -> int:
"""reflection() -> int: %
@@ -66,54 +62,13 @@ class LightSensor:
Reflection, ranging from 0% (no reflection) to 100% (high
reflection).
"""
pass
class ColorSensor(LightSensor):
class ColorSensor(CommonColorSensor):
"""LEGO® MINDSTORMS® NXT Color Sensor."""
light = ColorLight()
def __init__(self, port: Port):
"""ColorSensor(port)
Arguments:
port (Port): Port to which the sensor is connected.
"""
pass
def color(self) -> Color:
"""color() -> Color
Measures the color of a surface.
Returns:
``Color.BLACK``, ``Color.BLUE``, ``Color.GREEN``, ``Color.YELLOW``,
``Color.RED``, ``Color.WHITE`` or ``Color.NONE``.
"""
pass
def ambient(self) -> int:
"""ambient() -> int: %
Measures the ambient light intensity.
Returns:
Ambient light intensity, ranging from 0% (dark) to 100% (bright).
"""
pass
def reflection(self) -> int:
"""reflection() -> int: %
Measures the reflection of a surface using a red light.
Returns:
Reflection, ranging from 0% (no reflection) to 100% (high
reflection).
"""
pass
def rgb(self) -> Tuple[int, int, int]:
"""Measures the reflection of a surface using a red, green, and then a
blue light.
@@ -122,7 +77,6 @@ class ColorSensor(LightSensor):
Tuple of reflections for red, green, and blue light, each
ranging from 0.0% (no reflection) to 100.0% (high reflection).
"""
pass
class UltrasonicSensor:
@@ -134,7 +88,6 @@ class UltrasonicSensor:
Arguments:
port (Port): Port to which the sensor is connected.
"""
pass
def distance(self) -> int:
"""distance() -> int: mm
@@ -145,7 +98,6 @@ class UltrasonicSensor:
Returns:
Measured distance.
"""
pass
class SoundSensor:
@@ -157,7 +109,6 @@ class SoundSensor:
Arguments:
port (Port): Port to which the sensor is connected.
"""
pass
def intensity(self, audible_only: bool = True) -> int:
"""intensity(audible_only=True) -> int: %
@@ -172,7 +123,6 @@ class SoundSensor:
Returns:
Sound intensity.
"""
pass
class TemperatureSensor:
@@ -184,7 +134,6 @@ class TemperatureSensor:
Arguments:
port (Port): Port to which the sensor is connected.
"""
pass
def temperature(self) -> int:
"""temperature() -> float: °C
@@ -194,7 +143,6 @@ class TemperatureSensor:
Returns:
Measured temperature.
"""
pass
class EnergyMeter:
@@ -206,7 +154,6 @@ class EnergyMeter:
Arguments:
port (Port): Port to which the sensor is connected.
"""
pass
def storage(self) -> int:
"""storage() -> int: J
@@ -216,7 +163,6 @@ class EnergyMeter:
Returns:
Remaining stored energy.
"""
pass
def input(self) -> Tuple[int, int, int]:
"""input() -> Tuple[int, int, int]
@@ -232,7 +178,6 @@ class EnergyMeter:
Voltage (mV), current (mA), and power (mW) measured at the input
port.
"""
pass
def output(self) -> Tuple[int, int, int]:
"""output() -> Tuple[int, int, int]
@@ -248,7 +193,6 @@ class EnergyMeter:
Voltage (mV), current (mA), and power (mW) measured at the output
port.
"""
pass
class VernierAdapter(AnalogSensor):
@@ -265,7 +209,6 @@ class VernierAdapter(AnalogSensor):
own conversion function. The example given below demonstrates
the conversion for the Surface Temperature Sensor.
"""
pass
def voltage(self) -> int:
"""voltage() -> int: mV
@@ -275,7 +218,6 @@ class VernierAdapter(AnalogSensor):
Returns:
Analog voltage.
"""
pass
def conversion(self, voltage: int) -> float:
"""conversion(voltage) -> float
@@ -291,7 +233,6 @@ class VernierAdapter(AnalogSensor):
Returns:
Converted sensor value.
"""
pass
def value(self) -> float:
"""value() -> float
@@ -302,4 +243,3 @@ class VernierAdapter(AnalogSensor):
Returns:
Converted sensor value.
"""
pass
+126 -52
View File
@@ -1,12 +1,41 @@
# SPDX-License-Identifier: MIT
# Copyright (c) 2018-2020 The Pybricks Authors
# Copyright (c) 2018-2022 The Pybricks Authors
"""Constant parameters/arguments for the Pybricks API."""
from enum import Enum as _Enum
from __future__ import annotations
from enum import Enum
from typing import Union, TYPE_CHECKING
import os
from .geometry import Matrix as _Matrix
if TYPE_CHECKING or os.environ["SPHINX_BUILD"] == "True":
Number = Union[int, float]
"""
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` 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)):
class _PybricksEnumMeta(type(Enum)):
def __dir__(cls):
yield "__class__"
yield "__name__"
@@ -14,7 +43,7 @@ class _PybricksEnumMeta(type(_Enum)):
yield member.name
class _PybricksEnum(_Enum, metaclass=_PybricksEnumMeta):
class _PybricksEnum(Enum, metaclass=_PybricksEnumMeta):
def __dir__(self):
yield "__class__"
for member in type(self):
@@ -30,7 +59,18 @@ class _PybricksEnum(_Enum, metaclass=_PybricksEnumMeta):
class Color:
"""Light or surface color."""
def __init__(self, h, s=100, v=100):
h: int
s: int
v: int
def __init__(self, h: Number, s: Number = 100, v: Number = 100):
"""Color(h, s=100, v=100)
Arguments:
h (Number, deg): Hue (0--360)
s (Number, %): Saturation.
v (Number, %): Brightness value.
"""
self.h = h % 360
self.s = max(0, min(s, 100))
self.v = max(0, min(v, 100))
@@ -38,25 +78,20 @@ class Color:
def __repr__(self):
return "Color(h={}, s={}, v={})".format(self.h, self.s, self.v)
def __eq__(self, other):
return (
isinstance(other, Color)
and self.h == other.h
and self.s == other.s
and self.v == other.v
)
def __eq__(self, other: Color) -> bool:
...
def __mul__(self, scale):
def __mul__(self, scale: float) -> Color:
v = max(0, min(self.v * scale, 100))
return Color(self.h, self.s, int(v), self.name)
def __rmul__(self, scale):
def __rmul__(self, scale: float) -> Color:
return self.__mul__(scale)
def __truediv__(self, scale):
def __truediv__(self, scale: float) -> Color:
return self.__mul__(1 / scale)
def __floordiv__(self, scale):
def __floordiv__(self, scale: int) -> Color:
return self.__mul__(1 / scale)
@@ -79,30 +114,30 @@ class Port(_PybricksEnum):
"""Port on the programmable brick or hub."""
# Generic motor/sensor ports
A = ord("A")
B = ord("B")
C = ord("C")
D = ord("D")
E = ord("E")
F = ord("F")
A: Port = ord("A")
B: Port = ord("B")
C: Port = ord("C")
D: Port = ord("D")
E: Port = ord("E")
F: Port = ord("F")
# NXT/EV3 sensor ports
S1 = ord("1")
S2 = ord("2")
S3 = ord("3")
S4 = ord("4")
S1: Port = ord("1")
S2: Port = ord("2")
S3: Port = ord("3")
S4: Port = ord("4")
class Stop(_PybricksEnum):
"""Action after the motor stops."""
COAST = 0
COAST: Port = 0
"""Let the motor move freely."""
BRAKE = 1
BRAKE: Port = 1
"""Passively resist small external forces."""
HOLD = 2
HOLD: Port = 2
"""Keep controlling the motor to hold it at the commanded angle. This is
only available on motors with encoders."""
@@ -110,39 +145,78 @@ class Stop(_PybricksEnum):
class Direction(_PybricksEnum):
"""Rotational direction for positive speed or angle values."""
CLOCKWISE = 0
CLOCKWISE: Direction = 0
"""A positive speed value should make the motor move clockwise."""
COUNTERCLOCKWISE = 1
COUNTERCLOCKWISE: Direction = 1
"""A positive speed value should make the motor move counterclockwise."""
class Button(_PybricksEnum):
"""Buttons on a hub or remote."""
LEFT_DOWN = 1
LEFT_MINUS = 1
DOWN = 2
RIGHT_DOWN = 3
RIGHT_MINUS = 3
LEFT = 4
CENTER = 5
RIGHT = 6
LEFT_UP = 7
LEFT_PLUS = 7
UP = 8
BEACON = 8
RIGHT_UP = 9
RIGHT_PLUS = 9
BLUETOOTH = 9
LEFT_DOWN: Button = 1
LEFT_MINUS: Button = 1
DOWN: Button = 2
RIGHT_DOWN: Button = 3
RIGHT_MINUS: Button = 3
LEFT: Button = 4
CENTER: Button = 5
RIGHT: Button = 6
LEFT_UP: Button = 7
LEFT_PLUS: Button = 7
UP: Button = 8
BEACON: Button = 8
RIGHT_UP: Button = 9
RIGHT_PLUS: Button = 9
BLUETOOTH: Button = 9
class Side(_PybricksEnum):
"""Side of a hub or a sensor."""
RIGHT = 6
FRONT = 0
TOP = 8
LEFT = 4
BACK = 5
BOTTOM = 2
RIGHT: Side = 6
FRONT: Side = 0
TOP: Side = 8
LEFT: Side = 4
BACK: Side = 5
BOTTOM: Side = 2
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
-109
View File
@@ -1,109 +0,0 @@
# SPDX-License-Identifier: MIT
# Copyright (c) 2020 The Pybricks Authors
from geometry import Matrix
class Color:
BLACK: Color
BLUE: Color
BROWN: Color
CYAN: Color
GRAY: Color
GREEN: Color
MAGENTA: Color
NONE: Color
ORANGE: Color
RED: Color
VIOLET: Color
WHITE: Color
YELLOW: Color
def __init__(self, h: int, s: int = 100, v: int = 100): ...
def __eq__(self, other: "Color") -> bool: ...
def __mul__(self, scale: float) -> Color: ...
def __rmul__(self, scale: float) -> Color: ...
def __truediv__(self, scale: float) -> Color: ...
def __floordiv__(self, scale: int) -> Color: ...
class Port:
A: Port
B: Port
C: Port
D: Port
E: Port
F: Port
S1: Port
S2: Port
S3: Port
S4: Port
class Stop:
COAST: Stop
BRAKE: Stop
HOLD: Stop
class Direction:
CLOCKWISE: Direction
COUNTERCLOCKWISE: Direction
class Button:
LEFT_DOWN: Button
LEFT_MINUS: Button
DOWN: Button
RIGHT_DOWN: Button
RIGHT_MINUS: Button
LEFT: Button
CENTER: Button
RIGHT: Button
LEFT_UP: Button
LEFT_PLUS: Button
UP: Button
BEACON: Button
RIGHT_UP: Button
RIGHT_PLUS: Button
BLUETOOTH: Button
class Side:
RIGHT: Side
FRONT: Side
TOP: Side
LEFT: Side
BACK: Side
BOTTOM: Side
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
+127 -264
View File
@@ -3,25 +3,28 @@
"""LEGO® Powered Up motor, sensors, and lights."""
from typing import Optional
from __future__ import annotations
from ._common import (
Keypad as _Keypad,
DCMotor as _DCMotor,
ColorLight as _ColorLight,
Motor as _Motor,
LightArray as _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 Direction as _Direction, Button as _Button
if TYPE_CHECKING:
from .parameters import Number as _Number
class DCMotor(_DCMotor):
pass
class DCMotor(_common.DCMotor):
"""LEGO® Powered Up motor without rotation sensors."""
class Motor(_Motor):
"""Generic class to control motors with built-in rotation sensors."""
class Motor(_common.Motor):
"""LEGO® Powered Up motor with rotation sensors."""
def reset_angle(self, angle: Optional[int]) -> None:
"""reset_angle(angle=None)
@@ -34,14 +37,13 @@ class Motor(_Motor):
Arguments:
angle (Number, deg): Value to which the angle should be reset.
"""
pass
class Remote:
"""LEGO® Powered Up Bluetooth Remote Control."""
light = _ColorLight()
buttons = _Keypad(
light = _common.ColorLight()
buttons = _common.Keypad(
(
_Button.LEFT_MINUS,
_Button.RIGHT_MINUS,
@@ -52,9 +54,12 @@ class Remote:
_Button.RIGHT_PLUS,
)
)
addresss: Union[str, None]
def __init__(self, name=None, timeout=10000):
"""When you instantiate this class, the hub will search for a remote
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
and connect automatically.
The remote must be on and ready for a connection, as indicated by a
@@ -63,137 +68,77 @@ class Remote:
Arguments:
name (str): Bluetooth name of the remote. If no name is given,
the hub connects to the first remote that it finds.
timeout (:ref:`time`): How long to search for the remote.
timeout (Number, ms): How long to search for the remote.
"""
pass
def name(self, name=None):
"""Gets or sets the Bluetooth name of the remote.
@overload
def name(self, name: str) -> None:
...
If no name is given, this method returns the current name.
@overload
def name(self) -> str:
...
def name(self, *args):
"""name(name)
name() -> str
Sets or gets the Bluetooth name of the remote.
Arguments:
name (str): New Bluetooth name of the remote.
name (str): New Bluetooth name of the remote. If no name is given,
this method returns the current name.
"""
class TiltSensor:
"""LEGO® Powered Up Tilt Sensor."""
def __init__(self, port):
"""
def __init__(self, port: _Port):
"""TiltSensor(port)
Arguments:
port (Port): Port to which the sensor is connected.
"""
pass
def tilt(self):
"""Measures the tilt relative to the horizontal plane.
def tilt(self) -> Tuple[int, int]:
"""tilt() -> Tuple[int, int]: deg
Measures the tilt relative to the horizontal plane.
Returns:
(:ref:`angle`, :ref:`angle`): Tuple of pitch and roll angles.
Tuple of pitch and roll angles.
"""
pass
class ColorDistanceSensor:
class ColorDistanceSensor(_common.CommonColorSensor):
"""LEGO® Powered Up Color and Distance Sensor."""
light = _ColorLight()
light = _common.ColorLight()
def __init__(self, port):
"""ColorDistanceSensor(port)
def distance(self) -> int:
"""distance() -> int: %
Arguments:
port (Port): Port to which the sensor is connected.
"""
pass
def color(self):
"""Scans the color of a surface.
You choose which colors are detected using the
:meth:`.detectable_colors` method. By default, it detects
``Color.RED``, ``Color.YELLOW``, ``Color.GREEN``, ``Color.BLUE``,
``Color.WHITE``, or ``Color.NONE``.
:returns:
Detected color.
:rtype: :class:`Color <.parameters.Color>`
"""
pass
def ambient(self):
"""Measures the ambient light intensity.
Returns:
:ref:`percentage`: Ambient light intensity, ranging from 0 (dark)
to 100 (bright).
"""
pass
def reflection(self):
"""Measures the reflection of a surface.
Returns:
:ref:`percentage`: Reflection, ranging from 0.0 (no reflection) to
100.0 (high reflection).
"""
pass
def detectable_colors(self, colors):
"""Configures which colors the :meth:`.color` method should detect.
Specify only colors that you wish to detect in your application.
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.
Arguments:
colors (list): Tuple 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
better results. You measure your own colors with the
:meth:`.hsv` method.
"""
pass
def hsv(self):
"""Scans the color of a surface.
This method is similar to :meth:`.color`, but it gives the full range
of hue, saturation and brightness values, instead of rounding it to the
nearest detectable color.
:returns:
Measured color. The color is described by a hue (0--359), a
saturation (0--100), and a brightness value (0--100).
:rtype: :class:`Color <.parameters.Color>`
"""
pass
def distance(self):
"""Measures the relative distance between the sensor and an object
Measures the relative distance between the sensor and an object
using infrared light.
Returns:
:ref:`relativedistance`: Relative distance ranging from 0 (closest)
to 100 (farthest).
Distance ranging from 0% (closest) to 100% (farthest).
"""
pass
class PFMotor(DCMotor):
"""Control Power Functions motors with the infrared functionality of the
:class:`ColorDistanceSensor <pybricks.pupdevices.ColorDistanceSensor>`."""
def __init__(self, sensor, channel, color, positive_direction=_Direction.CLOCKWISE):
"""
def __init__(
self,
sensor: ColorDistanceSensor,
channel: int,
color: _Color,
positive_direction: _Direction = _Direction.CLOCKWISE,
):
"""PFMotor(sensor, channel, color, positive_direction=Direction.CLOCKWISE)
Arguments:
sensor (ColorDistanceSensor):
@@ -207,193 +152,111 @@ class PFMotor(DCMotor):
positive_direction (Direction): Which direction the motor should
turn when you give a positive duty cycle value.
"""
pass
class ColorSensor:
class ColorSensor(_common.AmbientColorSensor):
"""LEGO® SPIKE Color Sensor."""
lights = _LightArray(3)
def __init__(self, port):
"""
Arguments:
port (Port): Port to which the sensor is connected.
"""
pass
def color(self, surface=True):
"""Scans the color of a surface or an external light source.
You choose which colors are detected using the
:meth:`.detectable_colors` method. By default, it detects
``Color.RED``, ``Color.YELLOW``, ``Color.GREEN``, ``Color.BLUE``,
``Color.WHITE``, or ``Color.NONE``.
Arguments:
surface (bool): Choose ``true`` to scan the color of objects
and surfaces. Choose ``false`` to scan the color of
screens and other external light sources.
:returns:
Detected color.
:rtype: :class:`Color <.parameters.Color>`
"""
pass
def detectable_colors(self, colors):
"""Configures which colors the :meth:`.color` method should detect.
Specify only colors that you wish to detect in your application.
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.
Arguments:
colors (list): Tuple 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
better results. You measure your own colors with the
:meth:`.hsv` method.
"""
pass
def hsv(self, surface=True):
"""Scans the color of a surface or an external light source.
This method is similar to :meth:`.color`, but it gives the full range
of hue, saturation and brightness values, instead of rounding it to the
nearest detectable color.
Arguments:
surface (bool): Choose ``true`` to scan the color of objects
and surfaces. Choose ``false`` to scan the color of
screens and other external light sources.
:returns:
Measured color. The color is described by a hue (0--359), a
saturation (0--100), and a brightness value (0--100).
:rtype: :class:`Color <.parameters.Color>`
"""
pass
def ambient(self):
"""Measures the ambient light intensity.
Returns:
:ref:`percentage`: Ambient light intensity, ranging from 0 (dark)
to 100 (bright).
"""
pass
def reflection(self):
"""Measures the reflection of a surface.
Returns:
:ref:`percentage`: Reflection, ranging from 0.0 (no reflection) to
100.0 (high reflection).
"""
pass
lights = _common.LightArray(3)
class UltrasonicSensor:
"""LEGO® SPIKE Color Sensor."""
lights = _LightArray(3)
lights = _common.LightArray(3)
def __init__(self, port):
"""
def __init__(self, port: _Port):
"""UltrasonicSensor(port)
Arguments:
port (Port): Port to which the sensor is connected.
"""
pass
def distance(self):
"""Measures the distance between the sensor and an object using
def distance(self) -> int:
"""distance() -> int: mm
Measures the distance between the sensor and an object using
ultrasonic sound waves.
Returns:
:ref:`distance`: Measured distance. If no valid distance was
measured, it returns 2000 mm.
Measured distance. If no valid distance was measured,
it returns 2000 mm.
"""
pass
def presence(self):
"""Checks for the presence of other ultrasonic sensors by detecting
def presence(self) -> bool:
"""presence() -> bool
Checks for the presence of other ultrasonic sensors by detecting
ultrasonic sounds.
Returns:
bool: ``True`` if ultrasonic sounds are detected,
``False`` if not.
``True`` if ultrasonic sounds are detected, ``False`` if not.
"""
pass
class ForceSensor:
"""LEGO® SPIKE Force Sensor."""
def __init__(self, port):
"""
def __init__(self, port: _Port):
"""ForceSensor(port)
Arguments:
port (Port): Port to which the sensor is connected.
"""
pass
def force(self):
"""Measures the force exerted on the sensor.
def force(self) -> float:
"""force() -> float: N
Measures the force exerted on the sensor.
Returns:
:ref:`force`: Measured force (up to approximately 10.00 N).
Measured force (up to approximately 10.00 N).
"""
def distance(self):
"""Measures by how much the sensor button has moved.
def distance(self) -> float:
"""distance() -> float: mm
Measures by how much the sensor button has moved.
Returns:
:ref:`distance`: How much the sensor button has
moved (up to approximately 8.00 mm).
Movement up to approximately 8.00 mm.
"""
def pressed(self, force=3):
"""Checks if the sensor button is pressed.
def pressed(self, force: _Number = 3) -> bool:
"""pressed(force=3) -> bool
Checks if the sensor button is pressed.
Arguments:
force (:ref:`force`): Minimum force to be considered pressed.
force (Number, N): Minimum force to be considered pressed.
Returns:
bool: ``True`` if the sensor is pressed, ``False`` if it is not.
``True`` if the sensor is pressed, ``False`` if it is not.
"""
def touched(self):
"""Checks if the sensor is touched.
def touched(self) -> bool:
"""touched() -> bool
Checks if the sensor is touched.
This is similar to :meth:`pressed`, but it detects slight movements of
the button even when the measured force is still considered zero.
Returns:
bool: ``True`` if the sensor is touched or pressed, ``False``
``True`` if the sensor is touched or pressed, ``False``
if it is not.
"""
pass
class ColorLightMatrix:
"""
LEGO® SPIKE 3x3 Color Light Matrix.
"""
def __init__(self, port):
"""
def __init__(self, port: _Port):
"""ColorLightMatrix(port)
Arguments:
port (Port): Port to which the device is connected.
@@ -401,8 +264,9 @@ class ColorLightMatrix:
"""
...
def on(self, colors):
"""
def on(self, color: Union[_Color, Collection[_Color]]) -> None:
"""on(colors)
Turns the lights on.
Arguments:
@@ -413,9 +277,10 @@ class ColorLightMatrix:
"""
...
def off(self):
"""
Turns all of the lights off.
def off(self) -> None:
"""off()
Turns all lights off.
"""
...
@@ -423,55 +288,54 @@ class ColorLightMatrix:
class InfraredSensor:
"""LEGO® Powered Up Infrared Sensor."""
def __init__(self, port):
"""
def __init__(self, port: _Port):
"""InfraredSensor(port)
Arguments:
port (Port): Port to which the sensor is connected.
"""
pass
def reflection(self):
"""Measures the reflection of a surface using an infrared light.
def reflection(self) -> int:
"""reflection() -> int: %
Measures the reflection of a surface using an infrared light.
Returns:
:ref:`percentage`: Reflection, ranging from 0.0 (no reflection) to
100.0 (high reflection).
Measured reflection, ranging from 0% (no reflection) to
100% (high reflection).
"""
pass
def distance(self):
"""Measures the relative distance between the sensor and an object
def distance(self) -> int:
"""distance() -> int: %
Measures the relative distance between the sensor and an object
using infrared light.
Returns:
:ref:`relativedistance`: Relative distance ranging from 0 (closest)
to 100 (farthest).
Distance ranging from 0% (closest) to 100% (farthest).
"""
pass
def count(self):
"""Counts the number of objects that have passed by the sensor.
def count(self) -> int:
"""count() -> int
Counts the number of objects that have passed by the sensor.
Returns:
int: Number of objects counted.
Number of objects counted.
"""
pass
class Light:
"""LEGO® Powered Up Light."""
def __init__(self, port):
"""
def __init__(self, port: _Port):
"""Light(port)
Arguments:
port (Port): Port to which the device is connected.
"""
pass
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.
@@ -485,4 +349,3 @@ class Light:
"""off()
Turns off the light."""
pass
-80
View File
@@ -1,80 +0,0 @@
# SPDX-License-Identifier: MIT
# Copyright (c) 2020-2022 The Pybricks Authors
from typing import Collection, List, Optional, Tuple, Union
from ._common import (
Keypad,
DCMotor as _DCMotor,
ColorLight,
LightArray,
Motor as _Motor,
Light as BaseLight,
)
from .parameters import Color, Direction, Port
class Remote:
light: ColorLight
buttons: Keypad
addresss: Union[str, None]
def __init__(self, address: str = None, timeout: int = 10000): ...
class TiltSensor:
def __init__(self, port: Port): ...
def tilt(self) -> Tuple[int, int]: ...
class ColorDistanceSensor:
light: ColorLight
def __init__(self, port: Port): ...
def color(self) -> Optional[Color]: ...
def ambient(self) -> int: ...
def reflection(self) -> int: ...
def detectable_colors(self, colors: Collection[Color]) -> None: ...
def hsv(self) -> Color: ...
def distance(self) -> int: ...
class PFMotor(DCMotor):
def __init__(
self,
sensor: ColorDistanceSensor,
channel: int,
color: Color,
positive_direction: Direction = Direction.CLOCKWISE,
): ...
class ColorSensor:
lights: LightArray
def __init__(self, port: Port): ...
def color(self, surface: bool = True) -> Optional[Color]: ...
def detectable_colors(self, colors: Collection[Color]) -> None: ...
def hsv(self, surface: bool = True) -> Color: ...
def ambient(self) -> int: ...
def reflection(self) -> int: ...
class UltrasonicSensor:
lights: LightArray
def __init__(self, port: Port): ...
def distance(self) -> int: ...
def presence(self) -> bool: ...
class ForceSensor:
def __init__(self, port: Port): ...
def force(self) -> int: ...
def distance(self) -> int: ...
def pressed(self, force: int = 3) -> bool: ...
def touched(self) -> bool: ...
class ColorLightMatrix:
def __init__(self, port: Port) -> None: ...
def on(self, color: Union[Color, List[Color]]) -> None: ...
def off(self) -> None: ...
class InfraredSensor:
def __init__(self, port: Port): ...
def reflection(self) -> int: ...
def distance(self) -> int: ...
def count(self) -> int: ...
class Light(BaseLight):
def __init__(self, port: Port): ...
+87 -56
View File
@@ -3,10 +3,16 @@
"""Robotics module for the Pybricks API."""
from ._common import Control as _Control
from __future__ import annotations
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:
"""A robotic vehicle with two powered wheels and an optional support
@@ -25,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
@@ -33,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
@@ -42,7 +48,13 @@ class DriveBase:
whole drive base (viewed from the top) instead of degrees turned by one
motor."""
def __init__(self, left_motor, right_motor, wheel_diameter, axle_track):
def __init__(
self,
left_motor: _common.Motor,
right_motor: _common.Motor,
wheel_diameter: _Number,
axle_track: _Number,
):
"""DriveBase(left_motor, right_motor, wheel_diameter, axle_track)
Arguments:
@@ -50,107 +62,126 @@ class DriveBase:
The motor that drives the left wheel.
right_motor (Motor):
The motor that drives the right wheel.
wheel_diameter (:ref:`dimension`): Diameter of the wheels.
axle_track (:ref:`dimension`): Distance between the points where
wheel_diameter (Number, mm): Diameter of the wheels.
axle_track (Number, mm): Distance between the points where
both wheels touch the ground.
"""
def drive(self, speed, turn_rate):
"""Starts driving at the specified speed and turn rate. Both values are
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
measured at the center point between the wheels of the robot.
Arguments:
speed (:ref:`linspeed`): Speed of the robot.
turn_rate (:ref:`speed`): Turn rate of the robot.
speed (Number, mm/s): Speed of the robot.
turn_rate (Number, deg/s): Turn rate of the robot.
"""
pass
def stop(self):
"""Stops the robot by letting the motors spin freely."""
pass
def stop(self) -> None:
"""stop()
def distance(self):
"""Gets the estimated driven distance.
Stops the robot by letting the motors spin freely."""
def distance(self) -> int:
"""distance() -> int: mm
Gets the estimated driven distance.
Returns:
:ref:`distance`: Driven distance since last reset.
Driven distance since last reset.
"""
pass
def angle(self):
"""Gets the estimated rotation angle of the drive base.
def angle(self) -> int:
"""angle() -> int: deg
Gets the estimated rotation angle of the drive base.
Returns:
:ref:`angle`: Accumulated angle since last reset.
Accumulated angle since last reset.
"""
pass
def state(self):
"""Gets the state of the robot.
def state(self) -> Tuple[int, int, int, int]:
"""state() -> Tuple[int, int, int, int]
This returns the current :meth:`.distance`, the drive speed, the
:meth:`.angle`, and the turn rate.
Gets the state of the robot.
:returns: Distance, drive speed, angle, turn rate
:rtype: (:ref:`distance`, :ref:`linspeed`, :ref:`angle`, :ref:`speed`)
Returns:
Tuple of distance, drive speed, angle, and turn rate of the robot.
"""
pass
def reset(self):
"""Resets the estimated driven distance and angle to 0."""
pass
def reset(self) -> None:
"""reset()
Resets the estimated driven distance and angle to 0."""
@overload
def settings(
self, straight_speed, straight_acceleration, turn_rate, turn_acceleration
):
"""Configures the speed and acceleration used
self,
straight_speed: Optional[_Number],
straight_acceleration: Optional[_Number],
turn_rate: Optional[_Number],
turn_acceleration: Optional[_Number],
) -> None:
...
@overload
def settings(self) -> Tuple[int, int, int, int]:
...
def settings(self, *args):
"""settings(straight_speed, straight_acceleration, turn_rate, turn_acceleration)
settings() -> Tuple[int, int, int, int]
Configures the speed and acceleration used
by :meth:`.straight`, :meth:`.turn`, and :meth:`.curve`.
If you give no arguments, this returns the current values as a tuple.
You can only change the settings while the robot is stopped. This is
either before you begin driving or after you call :meth:`.stop`.
Arguments:
straight_speed (:ref:`linspeed`): Straight-line speed of the robot.
straight_acceleration (:ref:`linacceleration`): Straight-line
straight_speed (Number, mm/s): Straight-line speed of the robot.
straight_acceleration (Number, mm/): Straight-line
acceleration and deceleration of the robot.
turn_rate (:ref:`speed`): Turn rate of the robot.
turn_acceleration (:ref:`acceleration`): Angular acceleration and
turn_rate (Number, deg/s): Turn rate of the robot.
turn_acceleration (Number, deg/): Angular acceleration and
deceleration of the robot.
"""
pass
def straight(self, distance, then=_Stop.HOLD, wait=True):
"""Drives straight for a given distance and then stops.
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.
Arguments:
distance (:ref:`distance`): Distance to travel
distance (Number, mm): Distance to travel
then (Stop): What to do after coming to a standstill.
wait (bool): Wait for the maneuver to complete before continuing
with the rest of the program.
"""
pass
def turn(self, angle, then=_Stop.HOLD, wait=True):
"""Turns in place by a given angle and then stops.
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.
Arguments:
angle (:ref:`angle`): Angle of the turn.
angle (Number, deg): Angle of the turn.
then (Stop): What to do after coming to a standstill.
wait (bool): Wait for the maneuver to complete before continuing
with the rest of the program.
"""
pass
def curve(self, radius, angle, then=_Stop.HOLD, wait=True):
"""Drives an arc along a circle of a given radius, by a given angle.
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.
Arguments:
radius (:ref:`dimension`): Radius of the circle.
angle (:ref:`angle`): Angle along the circle.
radius (Number, mm): Radius of the circle.
angle (Number, deg): Angle along the circle.
then (Stop): What to do after coming to a standstill.
wait (bool): Wait for the maneuver to complete before continuing
with the rest of the program.
"""
pass
-39
View File
@@ -1,39 +0,0 @@
# SPDX-License-Identifier: MIT
# Copyright (c) 2020-2021 The Pybricks Authors
from typing import Optional, Tuple, overload, Union
from ._common import Control, Motor
from .parameters import Stop
class DriveBase:
distance_control: Control
heading_control: Control
def __init__(
self,
left_motor: Motor,
right_motor: Motor,
wheel_diameter: Union[int, float],
axle_track: Union[int, float],
): ...
def drive(self, speed: int, turn_rate: int) -> None: ...
def stop(self) -> None: ...
def distance(self) -> int: ...
def angle(self) -> int: ...
def state(self) -> Tuple[int, int, int, int]: ...
def reset(self) -> None: ...
@overload
def settings(self) -> Tuple[int, int, int, int]: ...
@overload
def settings(
self,
straight_speed: Optional[int],
straight_acceleration: Optional[int],
turn_rate: Optional[int],
turn_acceleration: Optional[int],
) -> None: ...
def straight(self, distance: int) -> None: ...
def turn(self, angle: int) -> None: ...
def curve(
self, radius: int, angle: int, then: Stop = Stop.HOLD, wait: bool = True
) -> None: ...
+39 -28
View File
@@ -1,17 +1,19 @@
# SPDX-License-Identifier: MIT
# Copyright (c) 2018-2020 The Pybricks Authors
# Copyright (c) 2018-2022 The Pybricks Authors
"""Common tools for timing and data logging."""
from typing import Any
def wait(time):
"""Pauses the user program for a specified amount of time.
def wait(time: int) -> None:
"""wait(time)
Pauses the user program for a specified amount of time.
Arguments:
time (:ref:`time`): How long to wait.
time (Number, ms): How long to wait.
"""
pass
class StopWatch:
@@ -19,45 +21,54 @@ class StopWatch:
feature on your phone."""
def __init__(self):
pass
...
def time(self):
"""Gets the current time of the stopwatch.
def time(self) -> int:
"""time() -> int: ms
Gets the current time of the stopwatch.
Returns:
:ref:`time`: Elapsed time.
Elapsed time.
"""
pass
def pause(self):
"""Pauses the stopwatch."""
pass
def pause(self) -> None:
"""pause()
def resume(self):
"""Resumes the stopwatch."""
pass
Pauses the stopwatch."""
def reset(self):
"""Resets the stopwatch time to 0.
def resume(self) -> None:
"""resume()
Resumes the stopwatch."""
def reset(self) -> None:
"""reset()
Resets the stopwatch time to 0.
The run state is unaffected:
* If it was paused, it stays paused (but now at 0).
* If it was running, it stays running (but starting again from 0).
"""
pass
class DataLog:
"""Create a file and log data."""
def __init__(
self, *headers, name="log", timestamp=True, extension="csv", append=False
self,
*headers: str,
name: str = "log",
timestamp: bool = True,
extension: str = "csv",
append: bool = False
):
"""
"""DataLog(*headers, name='log', timestamp=True, extension='csv', append=False)
Arguments:
headers (`col1`, `col2`, `...`): Column headers. These are the
headers (str, str, ...): Column headers. These are the
names of the data columns. For example, choose ``'time'`` and
``'angle'``.
name (str): Name of the file.
@@ -70,12 +81,12 @@ class DataLog:
data. If the file does not exist yet, an empty file will be
created either way.
"""
pass
def log(self, *values):
"""Saves one or more values on a new line in the file.
def log(self, *values: Any) -> None:
"""log(value1, value2, ...)
Saves one or more values on a new line in the file.
Arguments:
values (object, object, `...`): One or more objects or values.
values (object, object, ...): One or more objects or values.
"""
pass
-23
View File
@@ -1,23 +0,0 @@
# SPDX-License-Identifier: MIT
# Copyright (c) 2020 The Pybricks Authors
from typing import Any
def wait(time: int) -> None: ...
class StopWatch:
def time(self) -> int: ...
def pause(self) -> None: ...
def resume(self) -> None: ...
def reset(self) -> None: ...
class DataLog:
def __init__(
self,
*headers: str,
name: str = "log",
timestamp: bool = True,
extension: str = "csv",
append: bool = False
): ...
def log(self, *values: Any) -> None: ...
-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`.
"""