Compare commits

..
Author SHA1 Message Date
David Lechner bc592b4469 npm/jedi: v1.9.0 2023-05-16 15:45:40 -05:00
David Lechner 784c7ec5fc jedi: v1.9.0
Update pybricks package for next beta.
2023-05-16 15:43:09 -05:00
David Lechner 9e2bac457a github/workflows/publish-ide-docs: poetry install --only=doc
We don't need to install other dependencies to build the docs.
2023-05-16 15:39:14 -05:00
David Lechner 61d18ebe6f @pybricks/ide-docs v2.9.0 2023-05-16 15:33:45 -05:00
David Lechner ff0b767e3e v3.3.0a5 2023-05-16 15:27:22 -05:00
David Lechner 3274cef849 pybricks.common: Add new BLE class.
This adds a new BLE class that is used for connectionless broadcasting/
observing on hubs with built-in Bluetooth Low Energy.

Also see https://github.com/pybricks/pybricks-micropython/pull/158.
2023-05-16 14:46:53 -05:00
David Lechner b4ff3af36d pyproject: split lint and doc dependencies
This allows a subset of dependencies to be installed if needed and
allows sharing requirements with readthedocs.
2023-05-10 14:35:08 -05:00
David Lechner 8e5891d9e8 all: spelling
Misc spelling fixes.
2023-05-10 14:16:15 -05:00
David Lechner 7de67852f7 vscode: change to ms-python.black-formatter
Microsoft is breaking out various Python tools into separate extensions.
2023-05-10 13:43:49 -05:00
David Lechner 31d3a117d6 doc/main/conf: update copyright year 2023-04-21 17:39:28 -05:00
David Lechner 263fe3a1cb npm/jedi: v1.8.0 2023-04-21 17:31:17 -05:00
David Lechner db8de447d5 jedi: v1.8.0 2023-04-21 17:26:38 -05:00
David Lechner 46d6189eb1 jedi: update pybricks package version
also bump python requirement since Pyodide is now using Python 3.11.
2023-04-21 17:24:47 -05:00
David Lechner 2278c7bcda @pybricks/ide-docs v2.8.0 2023-04-21 17:10:51 -05:00
David Lechner 4da3618428 v3.3.0b4 2023-04-21 17:00:18 -05:00
Laurens Valk 5bc11b185d pybricks.tools: Add versionchanged note. 2023-04-21 14:07:46 +02:00
Laurens Valk be9f99d41b pybricks.tools: Add category headings. 2023-04-21 13:59:16 +02:00
Laurens Valk 870aae83c0 pybricks.tools: Document cross product. 2023-04-21 13:39:08 +02:00
Laurens Valk 9cde749e8a pybricks.geometry: Drop module.
See https://github.com/pybricks/pybricks-micropython/pull/160
2023-04-21 13:33:19 +02:00
Laurens Valk 8bca5eb6e4 pybricks.robotics: Add GyroDriveBase. 2023-04-21 10:42:30 +02:00
Laurens Valk 95a12a7386 pybricks.robotics: Drop note suggesting to flip motors.
This will still work, but it is asking for trouble when including the gyro.

So it is probably better not to mention this at all.
2023-04-21 10:42:30 +02:00
Laurens Valk d6c78f1f39 pybricks.robotics: Drop note restricting when to change settings. 2023-04-21 10:42:30 +02:00
Laurens Valk 98f2bb27fe pybricks.robotics.DriveBase: Drop positive direction.
This reverts commit e4650cb1c9.

This is not needed for gyro support, so it is better to remove it
before it is ever released.
2023-04-21 10:42:30 +02:00
Laurens Valk fdbd078388 pybricks._common.IMU: Heading is clockwise positive.
This is not a breaking change because heading() was never implemented until now.
2023-04-21 10:42:30 +02:00
Laurens Valk ccd2b46819 pybricks.robotics.DriveBase: Revert gyro use via init.
This reverts commit dadaab6f61.

We will introduce a separate class instead.
2023-04-21 10:42:30 +02:00
Laurens Valk c0cb05dd74 pybricks.robotics.DriveBase: Document use of gyro. 2023-04-21 10:42:30 +02:00
Laurens Valk b183e1420a pybricks.pupdevices.Motor: Document speed time window. 2023-04-21 10:42:30 +02:00
Laurens Valk b311c54261 pybricks._common.IMU: Change settings setter. 2023-04-21 10:42:30 +02:00
Laurens Valk bb37b94f5e pybricks._common.IMU: Add imu status. 2023-04-21 10:42:30 +02:00
Laurens Valk 5b25606afa pybricks._common.IMU: Add rotation and orientation.
Also update implementation status for heading and reset_heading.
2023-04-21 10:42:30 +02:00
Laurens Valk 8172d11ef6 urandom: Fix formula in getrandbits. 2023-03-28 08:50:00 +02:00
Laurens Valk c415296b71 pybricks._common.Motor: Document profile.
Fixes https://github.com/pybricks/support/issues/966
2023-03-20 15:12:36 +01:00
Laurens Valk e4650cb1c9 pybricks.robotics.DriveBase: Document positive direction.
Fixes https://github.com/pybricks/support/issues/992
2023-03-20 14:22:25 +01:00
Laurens Valk 91154a394c pybricks.robotics.DriveBase: Clarify settings method.
Fixes https://github.com/pybricks/support/issues/882
2023-03-20 14:00:42 +01:00
David Lechner 3c36010c04 pybricks.ev3devices: Fix Gyro direction parameter name.
The actual implemented name is `direction`, not `positive_direction`.

Fixes: https://github.com/pybricks/support/issues/509
2023-03-20 13:56:16 +01:00
Laurens Valk a553df3b03 pybricks.iodevices.PUPDevice: Add device class as comments. 2023-02-23 16:31:38 +01:00
Hans Willemen dbd1cc8dc9 pybricks.iodevices.PUPDevice: Add more devices.
Added:
- non-uart DCMotors  (Medium and Train)
- non-uart Light
- SPIKE 3x3 Color Matrix
- SPIKE Small Angular Motor
2023-02-23 16:31:38 +01:00
Laurens Valk b40c3989aa pybricks.common.Motor: Add Model() class instance.
This is mainly used to debug the motor model, and to quickly select the
feedback parameters. This is useful when adding or configuring new motor
types.

Reading the estimated speed can also be useful in advanced applications
where the user builds their own PID controller.

We may choose to hide this method from the documentation before the
release.
2023-02-09 10:25:15 +01:00
Laurens Valk 13612bdb1a README: Fix D002 Trailing whitespace. 2023-02-09 10:25:10 +01:00
kai-morich 031e905e12 README: document stub usage in vs code
Fixes: pybricks/support#937
2023-02-07 15:37:15 -06:00
Laurens Valk 428bca79ab pybricks.common.Control: Document deadzone. 2023-02-02 14:45:34 +01:00
Laurens Valk 0e8b6cfd97 doc/main/cad/devices: Generate motor model. 2023-02-02 14:44:50 +01:00
David Lechner eea8ff0924 examples/ev3/bluetooth: remove 3rd party dependency
Since Python 3.10, RFCOMM sockets are available in Python on Windows
so we no longer need 3rd party code.

Fixes: pybricks/support#902
2023-01-06 14:17:29 -06:00
David Lechner 8c673ab280 github: update actions/checkout to v3
This fixes deprecation warnings about node v12.
2022-12-28 16:16:01 -06:00
David Lechner 73477169ae npm/jedi: v1.7.0
Update pybricks_jedi package to v1.7.0 and bump version for release.
2022-12-28 16:13:28 -06:00
David Lechner 5ccc60c177 jedi/pyproject: v1.7.0 2022-12-28 16:09:37 -06:00
David Lechner 93c4fcc884 jedi: add update_user_modules() function
This function will be used to fix import completion of user module
names in Pybricks Code.

Issue: https://github.com/pybricks/support/issues/759
2022-12-28 16:06:47 -06:00
David Lechner aa72605e99 jedi: fix code completion for local _*
This fixes code completion for identifier names starting with "_" in
the local ("__main__") file.
2022-12-28 15:33:33 -06:00
David Lechner 8ee725722f jedi: fix completion of builtin types
Completions for `x.` where `x` is an instance of a builtin type was
broken because of filtering on the `builtins` modules. This extends
the filtering to allow attributes available on common builtin types
in Pybricks MicroPython.
2022-12-28 15:33:33 -06:00
David Lechner 236bda5f31 ubuiltins.round: Fix example.
The example did not have proper line breaks between statements.

Also add an additional example using f-strings.
2022-12-28 14:09:18 -06:00
David Lechner 36ee3bd9ef pyproject: v3.2.0 2022-12-20 15:46:44 -06:00
David Lechner 16a0621e03 @pybricks/ide-docs v2.7.0 2022-12-20 11:05:36 -06:00
Laurens Valk 7c4c5439a4 pyproject: v3.2.0c2 2022-12-20 16:08:48 +01:00
69 changed files with 3552 additions and 1306 deletions
+3 -11
View File
@@ -6,7 +6,7 @@ name: Build Python package and docs
on:
push:
tags-ignore:
- "*"
- '**'
pull_request:
paths:
- doc/**
@@ -20,19 +20,11 @@ on:
jobs:
build:
runs-on: ubuntu-20.04
strategy:
matrix:
python-version: [3.8, 3.9]
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v1
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
pip install poetry
+5 -5
View File
@@ -7,17 +7,17 @@ on:
jobs:
publish_ide_docs:
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
steps:
- name: Ubuntu packages
run: |
sudo apt-get update
sudo apt-get install -y dvisvgm preview-latex-style texlive texlive-fonts-extra texlive-latex-extra
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Set up Python 3.8
uses: actions/setup-python@v1
uses: actions/setup-python@v4
with:
python-version: 3.8
- name: Install dependencies
@@ -25,8 +25,8 @@ jobs:
pip install poetry
poetry run python -m pip install --upgrade pip
poetry run python -m pip install --upgrade setuptools
poetry install
- uses: actions/setup-node@v1
poetry install --only=doc
- uses: actions/setup-node@v3
with:
node-version: '14.x'
registry-url: 'https://registry.npmjs.org'
+1 -1
View File
@@ -9,7 +9,7 @@ jobs:
publish_jedi:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
# Setup .npmrc file to publish to npm
- uses: actions/setup-node@v3
with:
+26
View File
@@ -0,0 +1,26 @@
# .readthedocs.yaml
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
# Required
version: 2
build:
os: "ubuntu-22.04"
tools:
python: "3.10"
jobs:
post_create_environment:
- pip install poetry
- poetry config virtualenvs.create false
post_install:
- poetry install --only=doc
# Build documentation in the doc/main/ directory with Sphinx
sphinx:
configuration: doc/main/conf.py
fail_on_warning: true
# Optionally build your docs in additional formats such as PDF
formats:
- pdf
+2 -1
View File
@@ -4,7 +4,8 @@
// List of extensions which should be recommended for users of this workspace.
"recommendations": [
"ms-python.python"
"ms-python.python",
"ms-python.black-formatter"
],
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
"unwantedRecommendations": [
+2 -2
View File
@@ -4,14 +4,14 @@
},
"python.defaultInterpreterPath": ".venv/bin/python",
"python.autoComplete.extraPaths": ["jedi/src"],
"python.formatting.provider": "black",
"python.formatting.provider": "none",
"python.linting.pylintEnabled": false,
"python.linting.flake8Enabled": true,
"python.linting.pycodestyleEnabled": false,
"python.linting.enabled": true,
"[python]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "ms-python.python"
"editor.defaultFormatter": "ms-python.black-formatter"
},
"python.languageServer": "Pylance",
"python.testing.pytestArgs": [
+26
View File
@@ -4,6 +4,32 @@
## Unreleased
## 3.3.0b5 - 2023-05-16
### Added
- Documented new `hub.ble` methods.
## 3.3.0b4 - 2023-04-21
### Added
- Documented `integral_deadzone` in `Control.pid()`.
- Documented `Motor.model`. This can be used to view the estimated motor
state and change its settings.
- Added `rotation`, `orientation`, `ready`, `stationary` and `settings` methods
to `IMU` class.
- Added `GyroDriveBase` class to `pybricks.robotics`.
### Changed
- Change implementation status of `IMU.heading` and `IMU.reset_heading`. They
are now implemented, with some limitations as noted in a note box.
- Moved `Matrix` and `vector` from `pybricks.geometry` to `pybricks.tools`.
- Moved `Axis` from `pybricks.geometry` to `pybricks.parameters`.
### Removed
- Removed `pybricks.geometry` module.
## 3.2.0 - 2022-12-20
### Changed
- Changed module TOC headings to make it easier to find things.
+5
View File
@@ -12,6 +12,11 @@ used to generate the `official documentation`_.
See the `contributor's guide <CONTRIBUTING.md>`_ for acceptable changes and
instructions to build the documentation locally.
You can use the API stubs in this repository for syntax highlighting and code
completion when programming the EV3 with VS Code. To enable, remove the
``"python.languageServer"="None"`` line in the ``.vscode/settings.json`` file
generated by the *LEGO® MINDSTORMS® EV3 MicroPython* extension.
For general discussion, please visit the `support`_ issue tracker.
.. _Pybricks package: pybricks
+2 -1
View File
@@ -321,10 +321,11 @@ def on_missing_reference(
app.builder, node["refdoc"], "signaltypes", "numbers", contnode
)
# References with special characters can't exist, so we have to supress
# References with special characters can't exist, so we have to suppress
# warnings when Sphinx tries to cross reference units like deg/s. For
# consistency, we also treat units without special characters this way.
for unit in [
"dBm",
"deg",
"deg/s",
"deg/s²",
+4 -5
View File
@@ -10,7 +10,6 @@ FEATURES_SMALL = set()
# Medium feature set.
FEATURES_MEDIUM = FEATURES_SMALL | {
"pybricks-geometry",
"pybricks-common-control",
"pybricks-iodevices",
"stm32-extra",
@@ -24,10 +23,10 @@ FEATURES_LARGE = FEATURES_MEDIUM | set()
HUB_FEATURES = {
"movehub": {"movehub"} | FEATURES_SMALL,
"cityhub": {"cityhub"} | FEATURES_MEDIUM,
"technichub": {"technichub"} | FEATURES_MEDIUM,
"primehub": {"primehub", "inventorhub", "light-matrix"} | FEATURES_LARGE,
"inventorhub": {"primehub", "inventorhub", "light-matrix"} | FEATURES_LARGE,
"essentialhub": {"essentialhub"} | FEATURES_LARGE,
"technichub": {"technichub", "gyro"} | FEATURES_MEDIUM,
"primehub": {"primehub", "inventorhub", "light-matrix", "gyro"} | FEATURES_LARGE,
"inventorhub": {"primehub", "inventorhub", "light-matrix", "gyro"} | FEATURES_LARGE,
"essentialhub": {"essentialhub", "gyro"} | FEATURES_LARGE,
}
+1169 -6
View File
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -8,7 +8,7 @@ import sys
# General information about the project.
project = "pybricks"
copyright = "2018-2021 The Pybricks Authors"
copyright = "2018-2023 The Pybricks Authors"
author = ""
_TITLE = "Pybricks Modules and Examples"
@@ -29,7 +29,7 @@ if os.environ.get("READTHEDOCS", None) == "True":
# HACK: this allows Number type alias to be imported by Sphinx
os.environ["SPHINX_BUILD"] = "True"
# Addtional configuration of the IDE docs
# Additional configuration of the IDE docs
if "ide" in tags.tags: # noqa F821
_DISCLAIMER = ""
html_show_copyright = False
@@ -45,7 +45,7 @@ if "ide" in tags.tags: # noqa F821
exec(open(os.path.abspath("../common/conf.py")).read())
# Addtional configuration of the IDE docs
# Additional configuration of the IDE docs
if "ide" in tags.tags: # noqa F821
extensions.remove("sphinx.ext.mathjax") # noqa F821
+2 -2
View File
@@ -20,12 +20,12 @@ Motors
.. rubric:: Measuring
.. automethod:: pybricks.ev3devices.Motor.speed
.. automethod:: pybricks.ev3devices.Motor.angle
.. automethod:: pybricks.ev3devices.Motor.reset_angle
.. automethod:: pybricks.ev3devices.Motor.speed
.. automethod:: pybricks.ev3devices.Motor.load
.. automethod:: pybricks.ev3devices.Motor.stalled
-51
View File
@@ -1,51 +0,0 @@
.. pybricks-requirements:: stm32-float
:mod:`geometry <pybricks.geometry>` -- Geometry and algebra
============================================================
.. module:: pybricks.geometry
.. autoclass:: pybricks.geometry.Matrix
:no-members:
.. autoattribute:: pybricks.geometry::Matrix.T
.. autoattribute:: pybricks.geometry::Matrix.shape
.. autofunction:: pybricks.geometry.vector
.. autoclass:: pybricks.geometry.Axis
:no-members:
.. _robotframe:
Reference frames
-----------------------
The Pybricks module and this documentation use the following conventions:
- X: Positive means forward. Negative means backward.
- Y: Positive means to the left. Negative means to the right.
- Z: Positive means upward. Negative means downward.
To make sure that all hub measurements (such as acceleration) have the correct
value and sign, you can specify how the hub is mounted in your creation. This
adjust the measurements so that it is easy to see how your *robot* is moving,
rather than how the *hub* is moving.
For example, the hub may be mounted upside down in your design. If you
configure the settings as shown in :numref:`fig_imuexamples`, the hub
measurements will be adjusted accordingly. This way, a positive acceleration
value in the X direction means that your *robot* accelerates forward, even
though the *hub* accelerates backward.
.. _fig_imuexamples:
.. figure:: ../main/diagrams/imuexamples.png
:width: 100 %
How to configure the ``top_side`` and ``front_side`` settings for three
different robot designs. The same technique can be applied to other hubs
and other creations, by noting which way the top and
front :class:`Side <Side>` of the hub are pointing. The example
on the left is the default configuration.
+22
View File
@@ -19,6 +19,17 @@ City Hub
.. automethod:: pybricks.hubs::CityHub.light.animate
.. rubric:: Using connectionless Bluetooth messaging
``ble.broadcast()`` does not work on ``CityHub`` due to a bug in the
Bluetooth chip firmware.
.. automethod:: pybricks.hubs::CityHub.ble.observe
.. automethod:: pybricks.hubs::CityHub.ble.signal_strength
.. automethod:: pybricks.hubs::CityHub.ble.version
.. rubric:: Using the battery
.. automethod:: pybricks.hubs::CityHub.battery.voltage
@@ -70,6 +81,17 @@ Creating light animations
.. literalinclude::
../../../examples/pup/hub_common/build/light_animate_cityhub.py
Bluetooth examples
------------------
Observing data from other hubs
******************************
.. literalinclude::
../../../examples/pup/hub_common/build/ble_observe_cityhub.py
Button and system examples
----------------------------------
+37
View File
@@ -25,6 +25,10 @@ Essential Hub
.. rubric:: Using the IMU
.. automethod:: pybricks.hubs::EssentialHub.imu.ready
.. automethod:: pybricks.hubs::EssentialHub.imu.stationary
.. automethod:: pybricks.hubs::EssentialHub.imu.up
.. automethod:: pybricks.hubs::EssentialHub.imu.tilt
@@ -37,6 +41,22 @@ Essential Hub
.. automethod:: pybricks.hubs::EssentialHub.imu.reset_heading
.. automethod:: pybricks.hubs::EssentialHub.imu.rotation
.. automethod:: pybricks.hubs::EssentialHub.imu.orientation
.. automethod:: pybricks.hubs::EssentialHub.imu.settings
.. rubric:: Using connectionless Bluetooth messaging
.. automethod:: pybricks.hubs::EssentialHub.ble.broadcast
.. automethod:: pybricks.hubs::EssentialHub.ble.observe
.. automethod:: pybricks.hubs::EssentialHub.ble.signal_strength
.. automethod:: pybricks.hubs::EssentialHub.ble.version
.. rubric:: Using the battery
.. automethod:: pybricks.hubs::EssentialHub.battery.voltage
@@ -126,6 +146,23 @@ Reading acceleration and angular velocity on one axis
.. literalinclude::
../../../examples/pup/hub_common/build/imu_read_scalar_essentialhub.py
Bluetooth examples
------------------
Broadcasting data to other hubs
*******************************
.. literalinclude::
../../../examples/pup/hub_common/build/ble_broadcast_essentialhub.py
Observing data from other hubs
******************************
.. literalinclude::
../../../examples/pup/hub_common/build/ble_observe_essentialhub.py
System examples
----------------------------------
+27
View File
@@ -31,6 +31,16 @@ Move Hub
Changed acceleration units from m/s² to mm/s².
.. rubric:: Using connectionless Bluetooth messaging
.. automethod:: pybricks.hubs::MoveHub.ble.broadcast
.. automethod:: pybricks.hubs::MoveHub.ble.observe
.. automethod:: pybricks.hubs::MoveHub.ble.signal_strength
.. automethod:: pybricks.hubs::MoveHub.ble.version
.. rubric:: Using the battery
.. automethod:: pybricks.hubs::MoveHub.battery.voltage
@@ -85,6 +95,23 @@ Reading acceleration
.. literalinclude::
../../../examples/pup/hub_movehub/imu_read_acceleration.py
Bluetooth examples
------------------
Broadcasting data to other hubs
*******************************
.. literalinclude::
../../../examples/pup/hub_common/build/ble_broadcast_movehub.py
Observing data from other hubs
******************************
.. literalinclude::
../../../examples/pup/hub_common/build/ble_observe_movehub.py
Button and system examples
----------------------------------
+37
View File
@@ -59,6 +59,10 @@ Prime Hub / Inventor Hub
.. rubric:: Using the IMU
.. automethod:: pybricks.hubs::PrimeHub.imu.ready
.. automethod:: pybricks.hubs::PrimeHub.imu.stationary
.. automethod:: pybricks.hubs::PrimeHub.imu.up
.. automethod:: pybricks.hubs::PrimeHub.imu.tilt
@@ -71,6 +75,12 @@ Prime Hub / Inventor Hub
.. automethod:: pybricks.hubs::PrimeHub.imu.reset_heading
.. automethod:: pybricks.hubs::PrimeHub.imu.rotation
.. automethod:: pybricks.hubs::PrimeHub.imu.orientation
.. automethod:: pybricks.hubs::PrimeHub.imu.settings
.. rubric:: Using the speaker
.. automethod:: pybricks.hubs::PrimeHub.speaker.volume
@@ -79,6 +89,16 @@ Prime Hub / Inventor Hub
.. automethod:: pybricks.hubs::PrimeHub.speaker.play_notes
.. rubric:: Using connectionless Bluetooth messaging
.. automethod:: pybricks.hubs::PrimeHub.ble.broadcast
.. automethod:: pybricks.hubs::PrimeHub.ble.observe
.. automethod:: pybricks.hubs::PrimeHub.ble.signal_strength
.. automethod:: pybricks.hubs::PrimeHub.ble.version
.. rubric:: Using the battery
.. automethod:: pybricks.hubs::PrimeHub.battery.voltage
@@ -237,6 +257,23 @@ Reading acceleration and angular velocity on one axis
.. literalinclude::
../../../examples/pup/hub_common/build/imu_read_scalar_primehub.py
Bluetooth examples
------------------
Broadcasting data to other hubs
*******************************
.. literalinclude::
../../../examples/pup/hub_common/build/ble_broadcast_primehub.py
Observing data from other hubs
******************************
.. literalinclude::
../../../examples/pup/hub_common/build/ble_observe_primehub.py
System examples
----------------------------------
+37
View File
@@ -21,6 +21,10 @@ Technic Hub
.. rubric:: Using the IMU
.. automethod:: pybricks.hubs::TechnicHub.imu.ready
.. automethod:: pybricks.hubs::TechnicHub.imu.stationary
.. automethod:: pybricks.hubs::TechnicHub.imu.up
.. automethod:: pybricks.hubs::TechnicHub.imu.tilt
@@ -33,6 +37,22 @@ Technic Hub
.. automethod:: pybricks.hubs::TechnicHub.imu.reset_heading
.. automethod:: pybricks.hubs::TechnicHub.imu.rotation
.. automethod:: pybricks.hubs::TechnicHub.imu.orientation
.. automethod:: pybricks.hubs::TechnicHub.imu.settings
.. rubric:: Using connectionless Bluetooth messaging
.. automethod:: pybricks.hubs::TechnicHub.ble.broadcast
.. automethod:: pybricks.hubs::TechnicHub.ble.observe
.. automethod:: pybricks.hubs::TechnicHub.ble.signal_strength
.. automethod:: pybricks.hubs::TechnicHub.ble.version
.. rubric:: Using the battery
.. automethod:: pybricks.hubs::TechnicHub.battery.voltage
@@ -118,6 +138,23 @@ Reading acceleration and angular velocity on one axis
.. literalinclude::
../../../examples/pup/hub_common/build/imu_read_scalar_technichub.py
Bluetooth examples
------------------
Broadcasting data to other hubs
*******************************
.. literalinclude::
../../../examples/pup/hub_common/build/ble_broadcast_technichub.py
Observing data from other hubs
******************************
.. literalinclude::
../../../examples/pup/hub_common/build/ble_observe_technichub.py
Button and system examples
----------------------------------
-1
View File
@@ -60,7 +60,6 @@ above to reveal this menu.
parameters/index
tools/index
robotics
geometry
signaltypes
.. toctree::
+1 -1
View File
@@ -38,7 +38,7 @@ Powers and logarithms
.. autofunction:: umath.sqrt
Trigonomety
Trigonometry
-------------------------------
.. autodata:: umath.pi
+7
View File
@@ -0,0 +1,7 @@
.. pybricks-requirements:: stm32-float
Axis
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. autoclass:: pybricks.parameters.Axis
:no-members:
+3
View File
@@ -10,6 +10,7 @@
:maxdepth: 1
:hidden:
axis
button
color
direction
@@ -18,6 +19,8 @@
side
stop
.. pybricks-classlink:: Axis
.. pybricks-classlink:: Button
.. pybricks-classlink:: Color
+10 -2
View File
@@ -18,12 +18,12 @@ Motors with rotation sensors
.. rubric:: Measuring
.. automethod:: pybricks.pupdevices.Motor.speed
.. automethod:: pybricks.pupdevices.Motor.angle
.. automethod:: pybricks.pupdevices.Motor.reset_angle
.. automethod:: pybricks.pupdevices.Motor.speed
.. automethod:: pybricks.pupdevices.Motor.load
.. automethod:: pybricks.pupdevices.Motor.stalled
@@ -93,6 +93,14 @@ Motors with rotation sensors
The :meth:`done`, :meth:`stalled` and :meth:`load` methods have been
moved.
.. pybricks-requirements:: pybricks-common-control
.. automethod:: pybricks.pupdevices.Motor.model.state
.. pybricks-requirements:: pybricks-common-control
.. automethod:: pybricks.pupdevices.Motor.model.settings
Initialization examples
-----------------------
+37 -5
View File
@@ -1,11 +1,10 @@
.. pybricks-requirements::
:mod:`robotics <pybricks.robotics>` -- Robotics and drive bases
===============================================================
.. automodule:: pybricks.robotics
:no-members:
.. pybricks-requirements::
.. autoclass:: pybricks.robotics.DriveBase
:no-members:
@@ -103,9 +102,6 @@
the default speed and acceleration for straight maneuvers and turns.
Use the following attributes to adjust more advanced control settings.
You can only change the settings while the robot is stopped. This is
either before you begin driving or after you call :meth:`.stop`.
.. autoattribute:: pybricks.robotics.DriveBase.distance_control
:annotation:
@@ -116,11 +112,47 @@
The :meth:`done` and :meth:`stalled` methods have been moved.
.. pybricks-requirements:: gyro
.. class:: GyroDriveBase
This class works just like the :class:`DriveBase`, but it uses the hub's
built-in gyroscope to drive straight and turn more accurately.
If your hub is not mounted flat in your robot, make sure to specify
the ``top_side`` and ``front_side`` parameters when you initialize the
:class:`PrimeHub() <pybricks.hubs.PrimeHub>`,
:class:`InventorHub() <pybricks.hubs.PrimeHub>`,
:class:`EssentialHub() <pybricks.hubs.EssentialHub>`, or
:class:`TechnicHub() <pybricks.hubs.TechnicHub>`. This way your robot
knows which rotation to measure when turning.
The gyro in each hub is a bit different, which can cause it to be a few
degrees off for big turns, or many small turns in the same
direction. For example, you may need to use
:meth:`turn(357) <pybricks.robotics.DriveBase.turn>` or
:meth:`turn(362) <pybricks.robotics.DriveBase.turn>`
on your robot to make a full turn.
By default, this class tries to maintain the robot's position after a move
completes. This means the wheels will spin if you pick the robot up, in an
effort to maintain its heading angle. To avoid this, you can choose
``then=Stop.COAST`` in your last
:meth:`straight <pybricks.robotics.DriveBase.straight>`,
:meth:`turn <pybricks.robotics.DriveBase.turn>`, or
:meth:`curve <pybricks.robotics.DriveBase.curve>` command.
Examples
-------------------
Driving straight and turning in place
**********************************************
The following program shows the basics of driving and turning.
To use the built-in gyro, just replace the two occurrences of
:class:`DriveBase` with :class:`GyroDriveBase`.
.. literalinclude::
../../examples/pup/robotics/drivebase_basics.py
+34 -1
View File
@@ -248,7 +248,7 @@ For example, you can choose the frequency of a beep to change the pitch.
temperature: °C
---------------
Temperature is measured in degrees Celcius (°C). To convert to degrees
Temperature is measured in degrees Celsius (°C). To convert to degrees
Fahrenheit (°F) or Kelvin (K), you can use the following conversion formulas:
:math:`^{\circ}\kern1pt\!F =\kern1pt^{\circ}\kern1pt\!C \cdot \frac{9}{5} + 32`.
@@ -260,3 +260,36 @@ Fahrenheit (°F) or Kelvin (K), you can use the following conversion formulas:
hue: deg
--------------
Hue of a color (0-359 degrees).
.. _robotframe:
Reference frames
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The Pybricks module and this documentation use the following conventions:
- X: Positive means forward. Negative means backward.
- Y: Positive means to the left. Negative means to the right.
- Z: Positive means upward. Negative means downward.
To make sure that all hub measurements (such as acceleration) have the correct
value and sign, you can specify how the hub is mounted in your creation. This
adjust the measurements so that it is easy to see how your *robot* is moving,
rather than how the *hub* is moving.
For example, the hub may be mounted upside down in your design. If you
configure the settings as shown in :numref:`fig_imuexamples`, the hub
measurements will be adjusted accordingly. This way, a positive acceleration
value in the X direction means that your *robot* accelerates forward, even
though the *hub* accelerates backward.
.. _fig_imuexamples:
.. figure:: ../main/diagrams/imuexamples.png
:width: 100 %
How to configure the ``top_side`` and ``front_side`` settings for three
different robot designs. The same technique can be applied to other hubs
and other creations, by noting which way the top and
front :class:`Side <Side>` of the hub are pointing. The example
on the left is the default configuration.
+25 -1
View File
@@ -1,11 +1,14 @@
.. pybricks-requirements::
:mod:`tools <pybricks.tools>` -- Timing tools
:mod:`tools <pybricks.tools>` -- General purpose tools
========================================================
.. automodule:: pybricks.tools
:no-members:
Timing tools
---------------
.. autofunction:: wait
.. autoclass:: pybricks.tools.StopWatch
@@ -19,3 +22,24 @@
.. automethod:: pybricks.tools.StopWatch.reset
Linear algebra tools
--------------------
.. versionchanged:: 3.3
These tools were previously located in the ``pybricks.geometry`` module.
.. pybricks-requirements:: stm32-float
.. autoclass:: pybricks.tools.Matrix
:no-members:
.. autoattribute:: pybricks.tools::Matrix.T
.. autoattribute:: pybricks.tools::Matrix.shape
.. pybricks-requirements:: stm32-float
.. autofunction:: pybricks.tools.vector
.. autofunction:: pybricks.tools.cross
+28
View File
@@ -0,0 +1,28 @@
#!/usr/bin/env python3
from pybricks.messaging import BluetoothMailboxServer, TextMailbox
# This demo makes your PC talk to an EV3 over Bluetooth.
#
# This is identical to the EV3 server example in ../bluetooth_server
#
# The only difference is that it runs in Python3 on your computer, thanks to
# the Python3 implementation of the messaging module that is included here.
# As far as the EV3 is concerned, it thinks it just talks to an EV3 client.
#
# So, the EV3 client example needs no further modifications. The connection
# procedure is also the same as documented in the messaging module docs:
# https://docs.pybricks.com/en/latest/messaging.html
server = BluetoothMailboxServer()
mbox = TextMailbox("greeting", server)
# The server must be started before the client!
print("waiting for connection...")
server.wait_for_connection()
print("connected!")
# In this program, the server waits for the client to send the first message
# and then sends a reply.
mbox.wait()
print(mbox.read())
mbox.send("hello to you!")
+16 -56
View File
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: MIT
# Copyright (C) 2020 The Pybricks Authors
# Copyright (C) 2020,2023 The Pybricks Authors
"""
:class:`RFCOMMServer` can be used to communicate with other Bluetooth RFCOMM
@@ -10,29 +10,13 @@ remain a strict subset of that implementation when it comes to low-level
implementation details.
"""
from bluetooth import BluetoothSocket, RFCOMM
from socket import socket, AF_BLUETOOTH, BTPROTO_RFCOMM, SOCK_STREAM
from socketserver import ThreadingMixIn
BDADDR_ANY = ""
def str2ba(string, ba):
"""Convert string to Bluetooth address"""
for i, v in enumerate(string.split(":")):
ba.b[5 - i] = int(v, 16)
def ba2str(ba):
"""Convert Bluetooth address to string"""
string = []
for b in ba.b:
string.append("{:02X}".format(b))
string.reverse()
return ":".join(string).upper()
class RFCOMMServer:
"""Object that simplifies setting up an RFCOMM socket server.
"""
Object that simplifies setting up an RFCOMM socket server.
This is based on the ``socketserver.SocketServer`` class in the Python
standard library.
@@ -44,10 +28,10 @@ class RFCOMMServer:
self.server_address = server_address
self.RequestHandlerClass = RequestHandlerClass
self.socket = BluetoothSocket(RFCOMM)
self.socket = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)
try:
self.socket.bind((server_address[0], server_address[1]))
self.socket.bind(server_address)
# self.server_address = self.socket.getsockname()
self.socket.listen(self.request_queue_size)
except Exception:
@@ -83,50 +67,22 @@ class RFCOMMServer:
self.socket.close()
class StreamRequestHandler:
"""Class that handles incoming requests.
This is based on ``socketserver.StreamRequestHandler`` from the Python
standard library.
"""
def __init__(self, request, client_address, server):
self.request = request
self.client_address = client_address
self.server = server
self.setup()
try:
self.handle()
finally:
self.finish()
def setup(self):
self.wfile = self.request
self.rfile = self.request
def handle(self):
pass
def finish(self):
pass
class ThreadingRFCOMMServer(ThreadingMixIn, RFCOMMServer):
"""Version of :class:`RFCOMMServer` that handles connections in a new
thread.
"""
Version of :class:`RFCOMMServer` that handles connections in a new thread.
"""
pass
daemon_threads = True
class RFCOMMClient:
def __init__(self, client_address, RequestHandlerClass):
self.client_address = client_address
self.RequestHandlerClass = RequestHandlerClass
self.socket = BluetoothSocket(RFCOMM)
self.socket = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)
def handle_request(self):
self.socket.connect((self.client_address[0], self.client_address[1]))
self.socket.connect(self.client_address)
try:
self.process_request(self.socket, self.client_address)
except Exception:
@@ -145,4 +101,8 @@ class RFCOMMClient:
class ThreadingRFCOMMClient(ThreadingMixIn, RFCOMMClient):
pass
"""
Version of :class:`RFCOMMClient` that handles connections in a new thread.
"""
daemon_threads = True
+11 -14
View File
@@ -1,16 +1,13 @@
# SPDX-License-Identifier: MIT
# Copyright (C) 2020 The Pybricks Authors
# Copyright (C) 2020,2023 The Pybricks Authors
from _thread import allocate_lock
from errno import ECONNRESET
from struct import pack, unpack
from socket import BDADDR_ANY
from socketserver import StreamRequestHandler
from threading import Lock
from .bluetooth import (
BDADDR_ANY,
ThreadingRFCOMMServer,
ThreadingRFCOMMClient,
StreamRequestHandler,
)
from .bluetooth import ThreadingRFCOMMServer, ThreadingRFCOMMClient
def resolve(brick):
@@ -151,7 +148,7 @@ class MailboxHandler(StreamRequestHandler):
self.server._clients[self.client_address[0]] = self.request
while True:
try:
buf = self.rfile.recv(2)
buf = self.rfile.read(2)
if len(buf) == 0:
break
except OSError as ex:
@@ -160,7 +157,7 @@ class MailboxHandler(StreamRequestHandler):
break
raise
(size,) = unpack("<H", buf)
buf = self.rfile.recv(size)
buf = self.rfile.read(size)
msg_count, cmd_type, cmd, name_size = unpack("<HBBB", buf[0:5])
if cmd_type != SYSTEM_COMMAND_NO_REPLY:
raise ValueError("Bad message type")
@@ -180,7 +177,7 @@ class MailboxHandler(StreamRequestHandler):
class MailboxHandlerMixIn:
def __init__(self):
# protects against concurrent access of other attributes
self._lock = allocate_lock()
self._lock = Lock()
# map of mailbox name to raw data
self._mailboxes = {}
# map of device name/address to object with send() method
@@ -247,7 +244,7 @@ class MailboxHandlerMixIn:
def wait_for_mailbox_update(self, mbox):
"""Waits until ``mbox`` receives a value."""
lock = allocate_lock()
lock = Lock()
lock.acquire()
with self._lock:
self._updates[mbox] = lock
@@ -264,7 +261,7 @@ class BluetoothMailboxServer(MailboxHandlerMixIn, ThreadingRFCOMMServer):
EV3.
The remote EV3 can either be running MicroPython or the standard EV3
firmare.
firmware.
"""
super().__init__()
super(ThreadingRFCOMMServer, self).__init__(
@@ -307,7 +304,7 @@ class BluetoothMailboxClient(MailboxHandlerMixIn):
remote EV3s.
The remote EV3s can either be running MicroPython or the standard EV3
firmare.
firmware.
"""
def __enter__(self):
+1 -1
View File
@@ -36,7 +36,7 @@ def scale(val, src, dst):
# Create a loop to react to events
# This loop reacte to all main PS4 button and stick events. I have left out
# This loop reacts to all main PS4 button and stick events. I have left out
# buttons like share and options, but can easily be added in by referring
# to the table at: https://github.com/codeadamca/python-connect-ps4
+24
View File
@@ -0,0 +1,24 @@
# ThisHub = MoveHub CityHub TechnicHub PrimeHub EssentialHub
from pybricks.hubs import ThisHub
from pybricks.pupdevices import Motor
from pybricks.parameters import Port
from pybricks.tools import wait
# Initialize the hub.
hub = ThisHub(broadcast_channel=1)
# Initialize the motors.
left_motor = Motor(Port.A)
right_motor = Motor(Port.B)
while True:
# Read the motor angles to be sent to the other hub.
left_angle = left_motor.angle()
right_angle = right_motor.angle()
# Set the broadcast data and start broadcasting if not already doing so.
hub.ble.broadcast(left_angle, right_angle)
# Broadcasts are only sent every 100 milliseconds, so there is no reason
# to call the broadcast() method more often than that.
wait(100)
+39
View File
@@ -0,0 +1,39 @@
# ThisHub = MoveHub CityHub TechnicHub PrimeHub EssentialHub
from pybricks.hubs import ThisHub
from pybricks.pupdevices import Motor
from pybricks.parameters import Color, Port
from pybricks.tools import wait
# Initialize the hub.
hub = ThisHub(observe_channels=[1])
# Initialize the motors.
left_motor = Motor(Port.A)
right_motor = Motor(Port.B)
while True:
# Receive broadcast from the other hub.
data = hub.ble.observe(1)
if data is None:
# No data has been received in the last 1 second.
hub.light.on(Color.RED)
else:
# Data was received and is less that one second old.
hub.light.on(Color.GREEN)
# *data* contains the same values in the same order
# that were passed to hub.ble.broadcast() on the
# other hub.
left_angle = data[0]
right_angle = data[1]
# Make the motors on this hub mirror the position of the
# motors on the other hub.
left_motor.track_target(left_angle)
right_motor.track_target(right_angle)
# Broadcasts are only sent every 100 milliseconds, so there is
# no reason to call the observe() method more often than that.
wait(100)
+1 -1
View File
@@ -1,7 +1,7 @@
# ThisHub = TechnicHub PrimeHub EssentialHub
from pybricks.hubs import ThisHub
from pybricks.tools import wait
from pybricks.geometry import Axis
from pybricks.parameters import Axis
# Initialize the hub.
hub = ThisHub()
+1 -1
View File
@@ -1,7 +1,7 @@
# ThisHub = TechnicHub PrimeHub EssentialHub
from pybricks.hubs import ThisHub
from pybricks.tools import wait
from pybricks.geometry import Axis
from pybricks.parameters import Axis
# Initialize the hub. In this case, specify that the hub is mounted with the
# top side facing forward and the front side facing to the right.
+1 -2
View File
@@ -1,6 +1,5 @@
from pybricks.hubs import PrimeHub
from pybricks.tools import wait
from pybricks.geometry import Matrix
from pybricks.tools import wait, Matrix
# Initialize the hub.
hub = PrimeHub()
+21 -6
View File
@@ -4,19 +4,34 @@ from uerrno import ENODEV
# Dictionary of device identifiers along with their name.
device_names = {
34: "Wedo 2.0 Tilt Sensor",
35: "Wedo 2.0 Infrared Sensor",
37: "BOOST Color Distance Sensor",
# pybricks.pupdevices.DCMotor
1: "Wedo 2.0 Medium Motor",
2: "Powered Up Train Motor",
# pybricks.pupdevices.Light
8: "Powered Up Light",
# pybricks.pupdevices.Motor
38: "BOOST Interactive Motor",
46: "Technic Large Motor",
47: "Technic Extra Large Motor",
48: "SPIKE Medium Angular Motor",
49: "SPIKE Large Angular Motor",
61: "SPIKE Color Sensor",
62: "SPIKE Ultrasonic Sensor",
63: "SPIKE Force Sensor",
65: "SPIKE Small Angular Motor",
75: "Technic Medium Angular Motor",
76: "Technic Large Angular Motor",
# pybricks.pupdevices.TiltSensor
34: "Wedo 2.0 Tilt Sensor",
# pybricks.pupdevices.InfraredSensor
35: "Wedo 2.0 Infrared Motion Sensor",
# pybricks.pupdevices.ColorDistanceSensor
37: "BOOST Color Distance Sensor",
# pybricks.pupdevices.ColorSensor
61: "SPIKE Color Sensor",
# pybricks.pupdevices.UltrasonicSensor
62: "SPIKE Ultrasonic Sensor",
# pybricks.pupdevices.ForceSensor
63: "SPIKE Force Sensor",
# pybricks.pupdevices.ColorLightMatrix
64: "SPIKE 3x3 Color Light Matrix",
}
# Make a list of known ports.
+2 -2
View File
@@ -14,10 +14,10 @@ drive_base = DriveBase(left_motor, right_motor, wheel_diameter=56, axle_track=11
# Drive forward by 500mm (half a meter).
drive_base.straight(500)
# Turn around clockwise (180 degrees)
# Turn around clockwise by 180 degrees.
drive_base.turn(180)
# Drive forward again to drive back.
# Drive forward again to get back to the start.
drive_base.straight(500)
# Turn around counterclockwise.
+19
View File
@@ -4,6 +4,25 @@
## Unreleased
## 1.9.0 - 2023-05-16
### Changed
- Updated `pybricks` package to v3.3.0b5.
## 1.8.0 - 2023-04-21
### Changed
- Updated `pybricks` package to v3.3.0b4.
## 1.7.0 - 2022-12-28
### Added
- Added `update_user_modules()` function for filtering on user modules.
### Fixed
- Fixed code completion for builtin types.
- Fixed code completion for names starting with `_`.
## 1.6.0 - 2022-12-09
### Changed
+267 -267
View File
@@ -1,3 +1,5 @@
# This file is automatically @generated by Poetry and should not be changed by hand.
[[package]]
name = "attrs"
version = "22.1.0"
@@ -5,6 +7,10 @@ description = "Classes Without Boilerplate"
category = "dev"
optional = false
python-versions = ">=3.5"
files = [
{file = "attrs-22.1.0-py2.py3-none-any.whl", hash = "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c"},
{file = "attrs-22.1.0.tar.gz", hash = "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6"},
]
[package.extras]
dev = ["cloudpickle", "coverage[toml] (>=5.0.2)", "furo", "hypothesis", "mypy (>=0.900,!=0.940)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "sphinx", "sphinx-notfound-page", "zope.interface"]
@@ -19,252 +25,7 @@ description = "The uncompromising code formatter."
category = "dev"
optional = false
python-versions = ">=3.7"
[package.dependencies]
click = ">=8.0.0"
mypy-extensions = ">=0.4.3"
pathspec = ">=0.9.0"
platformdirs = ">=2"
tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""}
[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.6"
description = "Cross-platform colored terminal text."
category = "dev"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
[[package]]
name = "docstring-parser"
version = "0.14.1"
description = "Parse Python docstrings in reST, Google and Numpydoc format"
category = "main"
optional = false
python-versions = ">=3.6,<4.0"
[[package]]
name = "exceptiongroup"
version = "1.0.4"
description = "Backport of PEP 654 (exception groups)"
category = "dev"
optional = false
python-versions = ">=3.7"
[package.extras]
test = ["pytest (>=6)"]
[[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.10.2"
description = "Utility library for gitignore style pattern matching of file paths."
category = "dev"
optional = false
python-versions = ">=3.7"
[[package]]
name = "platformdirs"
version = "2.5.4"
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
category = "dev"
optional = false
python-versions = ">=3.7"
[package.extras]
docs = ["furo (>=2022.9.29)", "proselint (>=0.13)", "sphinx (>=5.3)", "sphinx-autodoc-typehints (>=1.19.4)"]
test = ["appdirs (==1.4.4)", "pytest (>=7.2)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"]
[[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 = "pybricks"
version = "3.2.0c1"
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 = ["jinja2", "railroad-diagrams"]
[[package]]
name = "pytest"
version = "7.2.0"
description = "pytest: simple powerful testing with Python"
category = "dev"
optional = false
python-versions = ">=3.7"
[package.dependencies]
attrs = ">=19.2.0"
colorama = {version = "*", markers = "sys_platform == \"win32\""}
exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""}
iniconfig = "*"
packaging = "*"
pluggy = ">=0.12,<2.0"
tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""}
[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 = "971c6d0dddd9bb8e33a942e2360905a7d80a1a9d33015c0defc08345df5c1019"
[metadata.files]
attrs = [
{file = "attrs-22.1.0-py2.py3-none-any.whl", hash = "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c"},
{file = "attrs-22.1.0.tar.gz", hash = "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6"},
]
black = [
files = [
{file = "black-22.10.0-1fixedarch-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:5cc42ca67989e9c3cf859e84c2bf014f6633db63d1cbdf8fdb666dcd9e77e3fa"},
{file = "black-22.10.0-1fixedarch-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:5d8f74030e67087b219b032aa33a919fae8806d49c867846bfacde57f43972ef"},
{file = "black-22.10.0-1fixedarch-cp37-cp37m-macosx_10_16_x86_64.whl", hash = "sha256:197df8509263b0b8614e1df1756b1dd41be6738eed2ba9e9769f3880c2b9d7b6"},
@@ -287,84 +48,323 @@ black = [
{file = "black-22.10.0-py3-none-any.whl", hash = "sha256:c957b2b4ea88587b46cf49d1dc17681c1e672864fd7af32fc1e9664d572b3458"},
{file = "black-22.10.0.tar.gz", hash = "sha256:f513588da599943e0cde4e32cc9879e825d58720d6557062d1098c5ad80080e1"},
]
click = [
[package.dependencies]
click = ">=8.0.0"
mypy-extensions = ">=0.4.3"
pathspec = ">=0.9.0"
platformdirs = ">=2"
tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""}
[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"
files = [
{file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"},
{file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"},
]
colorama = [
[package.dependencies]
colorama = {version = "*", markers = "platform_system == \"Windows\""}
[[package]]
name = "colorama"
version = "0.4.6"
description = "Cross-platform colored terminal text."
category = "dev"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
files = [
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
]
docstring-parser = [
[[package]]
name = "docstring-parser"
version = "0.14.1"
description = "Parse Python docstrings in reST, Google and Numpydoc format"
category = "main"
optional = false
python-versions = ">=3.6,<4.0"
files = [
{file = "docstring_parser-0.14.1-py3-none-any.whl", hash = "sha256:14ac6ec1f1ba6905c4d8cb90fd0bc55394f5678183752c90e44812bf28d7a515"},
{file = "docstring_parser-0.14.1.tar.gz", hash = "sha256:2c77522e31b7c88b1ab457a1f3c9ae38947ad719732260ba77ee8a3deb58622a"},
]
exceptiongroup = [
[[package]]
name = "exceptiongroup"
version = "1.0.4"
description = "Backport of PEP 654 (exception groups)"
category = "dev"
optional = false
python-versions = ">=3.7"
files = [
{file = "exceptiongroup-1.0.4-py3-none-any.whl", hash = "sha256:542adf9dea4055530d6e1279602fa5cb11dab2395fa650b8674eaec35fc4a828"},
{file = "exceptiongroup-1.0.4.tar.gz", hash = "sha256:bd14967b79cd9bdb54d97323216f8fdf533e278df937aa2a90089e7d6e06e5ec"},
]
flake8 = [
[package.extras]
test = ["pytest (>=6)"]
[[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"
files = [
{file = "flake8-4.0.1-py2.py3-none-any.whl", hash = "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d"},
{file = "flake8-4.0.1.tar.gz", hash = "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"},
]
iniconfig = [
[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 = "*"
files = [
{file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"},
{file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"},
]
jedi = [
[[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"
files = [
{file = "jedi-0.18.1-py2.py3-none-any.whl", hash = "sha256:637c9635fcf47945ceb91cd7f320234a7be540ded6f3e99a50cb6febdfd1ba8d"},
{file = "jedi-0.18.1.tar.gz", hash = "sha256:74137626a64a99c8eb6ae5832d99b3bdd7d29a3850fe2aa80a4126b2a7d949ab"},
]
mccabe = [
[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 = "*"
files = [
{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 = [
[[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 = "*"
files = [
{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 = [
[[package]]
name = "packaging"
version = "21.3"
description = "Core utilities for Python packages"
category = "dev"
optional = false
python-versions = ">=3.6"
files = [
{file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"},
{file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"},
]
parso = [
[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"
files = [
{file = "parso-0.8.3-py2.py3-none-any.whl", hash = "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75"},
{file = "parso-0.8.3.tar.gz", hash = "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0"},
]
pathspec = [
[package.extras]
qa = ["flake8 (==3.8.3)", "mypy (==0.782)"]
testing = ["docopt", "pytest (<6.0.0)"]
[[package]]
name = "pathspec"
version = "0.10.2"
description = "Utility library for gitignore style pattern matching of file paths."
category = "dev"
optional = false
python-versions = ">=3.7"
files = [
{file = "pathspec-0.10.2-py3-none-any.whl", hash = "sha256:88c2606f2c1e818b978540f73ecc908e13999c6c3a383daf3705652ae79807a5"},
{file = "pathspec-0.10.2.tar.gz", hash = "sha256:8f6bf73e5758fd365ef5d58ce09ac7c27d2833a8d7da51712eac6e27e35141b0"},
]
platformdirs = [
[[package]]
name = "platformdirs"
version = "2.5.4"
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
category = "dev"
optional = false
python-versions = ">=3.7"
files = [
{file = "platformdirs-2.5.4-py3-none-any.whl", hash = "sha256:af0276409f9a02373d540bf8480021a048711d572745aef4b7842dad245eba10"},
{file = "platformdirs-2.5.4.tar.gz", hash = "sha256:1006647646d80f16130f052404c6b901e80ee4ed6bef6792e1f238a8969106f7"},
]
pluggy = [
[package.extras]
docs = ["furo (>=2022.9.29)", "proselint (>=0.13)", "sphinx (>=5.3)", "sphinx-autodoc-typehints (>=1.19.4)"]
test = ["appdirs (==1.4.4)", "pytest (>=7.2)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"]
[[package]]
name = "pluggy"
version = "1.0.0"
description = "plugin and hook calling mechanisms for python"
category = "dev"
optional = false
python-versions = ">=3.6"
files = [
{file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"},
{file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"},
]
pybricks = []
pycodestyle = [
[package.extras]
dev = ["pre-commit", "tox"]
testing = ["pytest", "pytest-benchmark"]
[[package]]
name = "pybricks"
version = "3.3.0a5"
description = "Documentation and user-API stubs for Pybricks MicroPython"
category = "main"
optional = false
python-versions = "^3.8"
files = []
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.*"
files = [
{file = "pycodestyle-2.8.0-py2.py3-none-any.whl", hash = "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20"},
{file = "pycodestyle-2.8.0.tar.gz", hash = "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f"},
]
pyflakes = [
[[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.*"
files = [
{file = "pyflakes-2.4.0-py2.py3-none-any.whl", hash = "sha256:3bb3a3f256f4b7968c9c788781e4ff07dce46bdf12339dcda61053375426ee2e"},
{file = "pyflakes-2.4.0.tar.gz", hash = "sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c"},
]
pyparsing = [
[[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"
files = [
{file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"},
{file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"},
]
pytest = [
[package.extras]
diagrams = ["jinja2", "railroad-diagrams"]
[[package]]
name = "pytest"
version = "7.2.0"
description = "pytest: simple powerful testing with Python"
category = "dev"
optional = false
python-versions = ">=3.7"
files = [
{file = "pytest-7.2.0-py3-none-any.whl", hash = "sha256:892f933d339f068883b6fd5a459f03d85bfcb355e4981e146d2c7616c21fef71"},
{file = "pytest-7.2.0.tar.gz", hash = "sha256:c4014eb40e10f11f355ad4e3c2fb2c6c6d1919c73f3b5a433de4708202cade59"},
]
tomli = [
[package.dependencies]
attrs = ">=19.2.0"
colorama = {version = "*", markers = "sys_platform == \"win32\""}
exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""}
iniconfig = "*"
packaging = "*"
pluggy = ">=0.12,<2.0"
tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""}
[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"
files = [
{file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
]
typing-extensions = [
[[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"
files = [
{file = "typing_extensions-4.2.0-py3-none-any.whl", hash = "sha256:6657594ee297170d19f67d55c05852a874e7eb634f4f753dbd667855e07c1708"},
{file = "typing_extensions-4.2.0.tar.gz", hash = "sha256:f1c24655a0da0d1b67f07e17a5e6b2a105894e6824b92096378bb3668ef02376"},
]
[metadata]
lock-version = "2.0"
python-versions = ">= 3.10, < 3.12"
content-hash = "25da309474c7393923efe8ea98d47ed5759f373fdf8f4c71f6ccdc76c5f21882"
+3 -3
View File
@@ -1,13 +1,13 @@
[tool.poetry]
name = "pybricks_jedi"
version = "1.6.0"
version = "1.9.0"
description = "Code completion for Pybricks."
authors = ["The Pybricks Authors <team@pybricks.com>"]
license = "MIT"
[tool.poetry.dependencies]
python = ">= 3.10, < 3.11"
pybricks = "3.2.0c1"
python = ">= 3.10, < 3.12"
pybricks = "3.3.0a5"
jedi = "0.18.1"
typing-extensions = "4.2.0"
docstring-parser = "0.14.1"
+171 -90
View File
@@ -2,6 +2,7 @@ import io
import json
import re
from enum import IntEnum
from typing import Iterable
import docstring_parser
import jedi
@@ -12,7 +13,6 @@ from typing_extensions import NotRequired, TypedDict
PYBRICKS_CODE_PACKAGES = {
"micropython",
"pybricks",
"pybricks.geometry",
"pybricks.hubs",
"pybricks.iodevices",
"pybricks.parameters",
@@ -31,90 +31,153 @@ PYBRICKS_CODE_PACKAGES = {
# 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",
"builtins.abs",
"builtins.all",
"builtins.any",
"builtins.ArithmeticError",
"builtins.AssertionError",
"builtins.AttributeError",
"builtins.BaseException",
"builtins.bin",
"builtins.bool",
"builtins.bytearray",
"builtins.bytes",
"builtins.callable",
"builtins.chr",
"builtins.classmethod",
"builtins.complex",
"builtins.dict",
"builtins.dir",
"builtins.divmod",
"builtins.enumerate",
"builtins.EOFError",
"builtins.eval",
"builtins.Exception",
"builtins.exec",
"builtins.float",
"builtins.GeneratorExit",
"builtins.getattr",
"builtins.globals",
"builtins.hasattr",
"builtins.hash",
"builtins.help",
"builtins.hex",
"builtins.id",
"builtins.ImportError",
"builtins.IndentationError",
"builtins.IndexError",
"builtins.input",
"builtins.int",
"builtins.isinstance",
"builtins.issubclass",
"builtins.iter",
"builtins.KeyboardInterrupt",
"builtins.KeyError",
"builtins.len",
"builtins.list",
"builtins.locals",
"builtins.LookupError",
"builtins.map",
"builtins.max",
"builtins.MemoryError",
"builtins.min",
"builtins.NameError",
"builtins.next",
"builtins.NotImplementedError",
"builtins.object",
"builtins.oct",
"builtins.ord",
"builtins.OSError",
"builtins.OverflowError",
"builtins.pow",
"builtins.print",
"builtins.range",
"builtins.repr",
"builtins.reversed",
"builtins.round",
"builtins.RuntimeError",
"builtins.set",
"builtins.setattr",
"builtins.slice",
"builtins.sorted",
"builtins.staticmethod",
"builtins.StopIteration",
"builtins.str",
"builtins.sum",
"builtins.super",
"builtins.SyntaxError",
"builtins.SystemExit",
"builtins.tuple",
"builtins.type",
"builtins.TypeError",
"builtins.ValueError",
"builtins.ZeroDivisionError",
"builtins.zip",
"builtins.bytearray.append",
"builtins.bytearray.extend",
"builtins.dict.clear",
"builtins.dict.copy",
"builtins.dict.fromkeys",
"builtins.dict.get",
"builtins.dict.items",
"builtins.dict.keys",
"builtins.dict.pop",
"builtins.dict.popitem",
"builtins.dict.setdefault",
"builtins.dict.update",
"builtins.dict.values",
"builtins.int.from_bytes",
"builtins.int.to_bytes",
"builtins.list.append",
"builtins.list.clear",
"builtins.list.copy",
"builtins.list.count",
"builtins.list.extend",
"builtins.list.index",
"builtins.list.insert",
"builtins.list.pop",
"builtins.list.remove",
"builtins.list.reverse",
"builtins.list.sort",
"builtins.str.count",
"builtins.str.endswith",
"builtins.str.find",
"builtins.str.format",
"builtins.str.index",
"builtins.str.isalpha",
"builtins.str.isdigit",
"builtins.str.islower",
"builtins.str.isspace",
"builtins.str.isupper",
"builtins.str.join",
"builtins.str.lower",
"builtins.str.lstrip",
"builtins.str.replace",
"builtins.str.rfind",
"builtins.str.rindex",
"builtins.str.rsplit",
"builtins.str.rstrip",
"builtins.str.split",
"builtins.str.startswith",
"builtins.str.strip",
"builtins.str.upper",
"builtins.tuple.count",
"builtins.tuple.index",
}
PYBRICKS_BUILTINS_NO_FULLNAME = {"items", "values"}
PYBRICKS_TYPING = {
"typing.MutableSequence.append",
"typing.MutableSequence.extend",
"typing.MutableMapping.pop",
"typing.Mapping.get",
}
MICROPY_NOT_SUPPORTED_DUNDER = {"__doc__", "__package__"}
user_modules = set()
# Types from monaco editor
@@ -243,10 +306,14 @@ class SignatureHelp(TypedDict):
def _is_pybricks(c: Completion) -> bool:
# filter all "private" names (leading underscore)
if (isinstance(c.name, str)) and c.name.startswith("_"):
return False
if c.name is not None:
if c.name.startswith("_") and c.module_name != "__main__":
return False
if isinstance(c.full_name, str):
if c.name in MICROPY_NOT_SUPPORTED_DUNDER:
return False
if c.full_name is not None:
# this catches things like `from __future__ import annotations`
if c.full_name.startswith("_") and c.module_name != "__main__":
return False
@@ -256,16 +323,19 @@ def _is_pybricks(c: Completion) -> bool:
return False
# filter out typing types
if c.full_name.startswith("typing."):
if c.full_name.startswith("typing.") and c.full_name not in PYBRICKS_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
return c.full_name in PYBRICKS_CODE_PACKAGES or c.full_name in user_modules
# filter subset of builtins
if c.module_name == "builtins" and c.type != "keyword":
return c.name in PYBRICKS_BUILTINS
if c.full_name is None:
return c.name in PYBRICKS_BUILTINS_NO_FULLNAME
return c.full_name in PYBRICKS_BUILTINS
# this is a type alias, not a real type
if c.full_name == "pybricks.parameters.Number":
@@ -418,7 +488,6 @@ def initialize():
"pybricks._common",
"pybricks.ev3dev",
"pybricks.ev3dev.speaker",
"pybricks.geometry",
"pybricks.hubs",
"pybricks.iodevices",
"pybricks.parameters",
@@ -473,3 +542,15 @@ def get_signatures(code: str, line: int, column: int) -> str:
"""
signatures = jedi.Script(code).get_signatures(line, column - 1)
return json.dumps(_map_signatures(signatures))
def update_user_modules(names: Iterable[str]) -> None:
"""
Updates the set of user module names used for filtering.
Args:
names:
An iterable of module names.
"""
user_modules.clear()
user_modules.update(names)
+143
View File
@@ -7,6 +7,9 @@ Tests for correct code completion of builtins.
import json
import pytest
from pybricks_jedi import CompletionItem, complete
@@ -123,4 +126,144 @@ def test_empty_code():
"yield",
"ZeroDivisionError",
"zip",
"__name__",
]
FUNCTION_PARAMS = [
pytest.param(
"''.",
[
"count",
"endswith",
"find",
"format",
"index",
"isalpha",
"isdigit",
"islower",
"isspace",
"isupper",
"join",
"lower",
"lstrip",
"replace",
"rfind",
"rindex",
"rsplit",
"rstrip",
"split",
"startswith",
"strip",
"upper",
],
),
pytest.param(
"str().",
[
"count",
"endswith",
"find",
"format",
"index",
"isalpha",
"isdigit",
"islower",
"isspace",
"isupper",
"join",
"lower",
"lstrip",
"replace",
"rfind",
"rindex",
"rsplit",
"rstrip",
"split",
"startswith",
"strip",
"upper",
],
),
pytest.param("(0).", ["from_bytes", "to_bytes"]),
pytest.param("int().", ["from_bytes", "to_bytes"]),
pytest.param(
"{}.",
[
"clear",
"copy",
"fromkeys",
"get",
"items",
"keys",
"pop",
"popitem",
"setdefault",
"update",
"values",
],
),
pytest.param(
"dict().",
[
"clear",
"copy",
"fromkeys",
"get",
"items",
"keys",
"pop",
"popitem",
"setdefault",
"update",
"values",
],
),
pytest.param(
"[].",
[
"append",
"clear",
"copy",
"count",
"extend",
"index",
"insert",
"pop",
"remove",
"reverse",
"sort",
],
),
pytest.param(
"list().",
[
"append",
"clear",
"copy",
"count",
"extend",
"index",
"insert",
"pop",
"remove",
"reverse",
"sort",
],
),
pytest.param("().", ["count", "index"]),
pytest.param("tuple().", ["count", "index"]),
pytest.param("bytearray().", ["append", "extend"]),
pytest.param("bytes().", []),
pytest.param("b''.", []),
pytest.param("float().", []),
pytest.param("(0.0).", []),
pytest.param("complex().", []),
pytest.param("type().", []),
]
@pytest.mark.parametrize("code,attributes", FUNCTION_PARAMS)
def test_get_completion_for_builtins(code: str, attributes: list[str]):
completions: list[CompletionItem] = json.loads(complete(code, 1, len(code) + 1))
assert [c["insertText"] for c in completions] == attributes
+1
View File
@@ -33,6 +33,7 @@ def test_hub_dot():
completions: list[CompletionItem] = json.loads(complete(code, 3, len(line) + 1))
assert [c["insertText"] for c in completions] == [
"battery",
"ble",
"button",
"light",
"system",
@@ -33,6 +33,7 @@ def test_hub_dot():
completions: list[CompletionItem] = json.loads(complete(code, 3, len(line) + 1))
assert [c["insertText"] for c in completions] == [
"battery",
"ble",
"button",
"charger",
"imu",
@@ -79,7 +80,12 @@ def test_hub_dot_imu_dot():
"acceleration",
"angular_velocity",
"heading",
"orientation",
"ready",
"reset_heading",
"rotation",
"settings",
"stationary",
"tilt",
"up",
]
+34 -16
View File
@@ -6,7 +6,9 @@ Tests for correct code completion of import statements.
"""
import json
from pybricks_jedi import CompletionItem, complete
import pytest
from pybricks_jedi import CompletionItem, complete, update_user_modules
def test_from():
@@ -27,11 +29,36 @@ def test_from():
]
@pytest.fixture
def user_modules():
update_user_modules(["jedi", "pytest"])
yield
update_user_modules([])
def test_from_with_user_modules(user_modules):
code = "from "
completions: list[CompletionItem] = json.loads(complete(code, 1, len(code) + 1))
assert [c["insertText"] for c in completions] == [
"jedi",
"micropython",
"pybricks",
"pytest",
"uerrno",
"uio",
"ujson",
"umath",
"urandom",
"uselect",
"ustruct",
"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",
@@ -46,7 +73,6 @@ 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",
@@ -56,16 +82,6 @@ def test_from_pybricks_dot():
]
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))
@@ -99,6 +115,7 @@ 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] == [
"Axis",
"Button",
"Color",
"Direction",
@@ -131,17 +148,18 @@ def test_from_pybricks_pupdevices_import():
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",
]
assert [c["insertText"] for c in completions] == ["DriveBase", "GyroDriveBase"]
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] == [
"cross",
"DataLog",
"Matrix",
"StopWatch",
"vector",
"wait",
]
+32
View File
@@ -0,0 +1,32 @@
import json
from pybricks_jedi import CompletionItem, complete
def test_get_completion_for_private_globals():
code = """
_X = 0
_
"""
completions: list[CompletionItem] = json.loads(complete(code, 4, 2))
assert [c["insertText"] for c in completions] == ["_X", "__name__"]
def test_get_completion_for_private_attributes():
code = """
class X:
def __init__(self):
self.public = 0
self._protected = 0
self.__private = 0
x = X()
x.
"""
completions: list[CompletionItem] = json.loads(complete(code, 10, 3))
assert [c["insertText"] for c in completions] == [
"public",
"_protected",
"__init__",
]
+1
View File
@@ -33,6 +33,7 @@ def test_hub_dot():
completions: list[CompletionItem] = json.loads(complete(code, 3, len(line) + 1))
assert [c["insertText"] for c in completions] == [
"battery",
"ble",
"button",
"imu",
"light",
+6
View File
@@ -33,6 +33,7 @@ def test_hub_dot():
completions: list[CompletionItem] = json.loads(complete(code, 3, len(line) + 1))
assert [c["insertText"] for c in completions] == [
"battery",
"ble",
"buttons",
"charger",
"display",
@@ -97,7 +98,12 @@ def test_hub_dot_imu_dot():
"acceleration",
"angular_velocity",
"heading",
"orientation",
"ready",
"reset_heading",
"rotation",
"settings",
"stationary",
"tilt",
"up",
]
+6
View File
@@ -33,6 +33,7 @@ def test_hub_dot():
completions: list[CompletionItem] = json.loads(complete(code, 3, len(line) + 1))
assert [c["insertText"] for c in completions] == [
"battery",
"ble",
"button",
"imu",
"light",
@@ -67,7 +68,12 @@ def test_hub_dot_imu_dot():
"acceleration",
"angular_velocity",
"heading",
"orientation",
"ready",
"reset_heading",
"rotation",
"settings",
"stationary",
"tilt",
"up",
]
+70 -9
View File
@@ -31,7 +31,7 @@ def _get_function_signature(module: str, function: str) -> SignatureHelp:
FUNCTION_PARAMS = [
pytest.param("pybricks.tools", "wait", [(["time: Number"], "None")]),
pytest.param(
"pybricks.geometry",
"pybricks.tools",
"vector",
[
(["x: float", "y: float"], "Matrix"),
@@ -78,17 +78,51 @@ def _get_constructor_signature(module: str, type: str) -> SignatureHelp:
CONSTRUCTOR_PARAMS = [
pytest.param("pybricks.hubs", "MoveHub", [[]]),
pytest.param("pybricks.hubs", "CityHub", [[]]),
pytest.param(
"pybricks.hubs",
"MoveHub",
[["broadcast_channel: int=0", "observe_channels: Sequence[int]=[]"]],
),
pytest.param(
"pybricks.hubs",
"CityHub",
[["broadcast_channel: int=0", "observe_channels: Sequence[int]=[]"]],
),
pytest.param(
"pybricks.hubs",
"TechnicHub",
[["top_side: Axis=Axis.Z", "front_side: Axis=Axis.X"]],
[
[
"top_side: Axis=Axis.Z",
"front_side: Axis=Axis.X",
"broadcast_channel: int=0",
"observe_channels: Sequence[int]=[]",
]
],
),
pytest.param(
"pybricks.hubs",
"PrimeHub",
[["top_side: Axis=Axis.Z", "front_side: Axis=Axis.X"]],
[
[
"top_side: Axis=Axis.Z",
"front_side: Axis=Axis.X",
"broadcast_channel: int=0",
"observe_channels: Sequence[int]=[]",
]
],
),
pytest.param(
"pybricks.hubs",
"EssentialHub",
[
[
"top_side: Axis=Axis.Z",
"front_side: Axis=Axis.X",
"broadcast_channel: int=0",
"observe_channels: Sequence[int]=[]",
]
],
),
pytest.param(
"pybricks.pupdevices",
@@ -104,6 +138,7 @@ CONSTRUCTOR_PARAMS = [
"positive_direction: Direction=Direction.CLOCKWISE",
"gears: Optional[Union[Collection[int], Collection[Collection[int]]]]=None",
"reset_angle: bool=True",
"profile: Number=None",
]
],
),
@@ -151,7 +186,7 @@ CONSTRUCTOR_PARAMS = [
],
),
pytest.param(
"pybricks.geometry",
"pybricks.tools",
"Matrix",
[["rows: Sequence[Sequence[float]]"]],
),
@@ -306,12 +341,19 @@ METHOD_PARAMS = [
[(["axis: Axis"], "float"), ([], "Matrix")],
),
pytest.param("pybricks.hubs", "TechnicHub", "imu.heading", [([], "float")]),
pytest.param("pybricks.hubs", "TechnicHub", "imu.orientation", [([], "Matrix")]),
pytest.param(
"pybricks.hubs",
"TechnicHub",
"imu.reset_heading",
[(["angle: Number"], "None")],
),
pytest.param(
"pybricks.hubs",
"TechnicHub",
"imu.rotation",
[(["axis: Axis"], "float")],
),
pytest.param("pybricks.hubs", "TechnicHub", "battery.voltage", [([], "int")]),
pytest.param("pybricks.hubs", "TechnicHub", "battery.current", [([], "int")]),
pytest.param(
@@ -398,12 +440,19 @@ METHOD_PARAMS = [
[(["axis: Axis"], "float"), ([], "Matrix")],
),
pytest.param("pybricks.hubs", "PrimeHub", "imu.heading", [([], "float")]),
pytest.param("pybricks.hubs", "PrimeHub", "imu.orientation", [([], "Matrix")]),
pytest.param(
"pybricks.hubs",
"PrimeHub",
"imu.reset_heading",
[(["angle: Number"], "None")],
),
pytest.param(
"pybricks.hubs",
"PrimeHub",
"imu.rotation",
[(["axis: Axis"], "float")],
),
pytest.param(
"pybricks.hubs",
"PrimeHub",
@@ -481,12 +530,19 @@ METHOD_PARAMS = [
[(["axis: Axis"], "float"), ([], "Matrix")],
),
pytest.param("pybricks.hubs", "EssentialHub", "imu.heading", [([], "float")]),
pytest.param("pybricks.hubs", "EssentialHub", "imu.orientation", [([], "Matrix")]),
pytest.param(
"pybricks.hubs",
"EssentialHub",
"imu.reset_heading",
[(["angle: Number"], "None")],
),
pytest.param(
"pybricks.hubs",
"EssentialHub",
"imu.rotation",
[(["axis: Axis"], "float")],
),
pytest.param("pybricks.hubs", "EssentialHub", "battery.voltage", [([], "int")]),
pytest.param("pybricks.hubs", "EssentialHub", "battery.current", [([], "int")]),
pytest.param("pybricks.hubs", "EssentialHub", "charger.connected", [([], "bool")]),
@@ -520,7 +576,12 @@ METHOD_PARAMS = [
"settings",
[(["max_voltage: Number"], "None"), ([], "Tuple[int]")],
),
pytest.param("pybricks.pupdevices", "Motor", "speed", [([], "int")]),
pytest.param(
"pybricks.pupdevices",
"Motor",
"speed",
[(["window: Number=100"], "int")],
),
pytest.param("pybricks.pupdevices", "Motor", "angle", [([], "int")]),
pytest.param(
"pybricks.pupdevices",
@@ -637,12 +698,12 @@ METHOD_PARAMS = [
"kp: Optional[Number]=None",
"ki: Optional[Number]=None",
"kd: Optional[Number]=None",
"reserved: Optional[Number]=None",
"integral_deadzone: Optional[Number]=None",
"integral_rate: Optional[Number]=None",
],
"None",
),
([], "Tuple[int, int, int, None, int]"),
([], "Tuple[int, int, int, int, int]"),
],
),
pytest.param(
+15
View File
@@ -2,6 +2,21 @@
<!-- refer to https://keepachangelog.com/en/1.0.0/ for guidance -->
## 2.9.0 - 2023-05-16
### Changed
- Updated docs to v3.3.0b5.
## 2.8.0 - 2023-04-21
### Changed
- Updated docs to v3.3.0b4.
## 2.7.0 - 2022-12-20
### Changed
- Updated docs to v3.2.0c2.
## 2.6.0 - 2022-12-09
### Changed
+1 -1
View File
@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2018-2021 The Pybricks Authors
Copyright (c) 2018-2023 The Pybricks Authors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@pybricks/ide-docs",
"version": "2.6.0",
"version": "2.9.0",
"description": "Special build of Pybricks API docs for embedding in an IDE.",
"repository": {
"type": "git",
+15
View File
@@ -4,6 +4,21 @@
## Unreleased
## 1.9.0 - 2023-05-16
### Changed
- Updated `pybricks_jedi` Python package to v1.9.0.
## 1.8.0 - 2023-04-21
### Changed
- Updated `pybricks_jedi` Python package to v1.8.0.
## 1.7.0 - 2022-12-28
### Changed
- Updated `pybricks_jedi` Python package to v1.7.0.
## 1.6.0 - 2022-12-09
### Changed
+3 -3
View File
@@ -12,7 +12,7 @@ BUILD_DIR = (pathlib.Path(__file__).parent / "build").resolve()
package_json = {
"name": "@pybricks/jedi",
"version": "1.6.0",
"version": "1.9.0",
"description": "Binary distribution of pybricks-jedi Python package and dependencies for use with Pyodide.",
"repository": {
"type": "git",
@@ -30,7 +30,7 @@ whl_map: dict[str, str] = {}
shutil.rmtree(BUILD_DIR, True)
BUILD_DIR.mkdir()
# download package and depedencies (*.whl files)
# download package and dependencies (*.whl files)
subprocess.check_call(
[
sys.executable,
@@ -38,7 +38,7 @@ subprocess.check_call(
"pip",
"download",
"--only-binary=any",
"pybricks-jedi==1.6.0",
"pybricks-jedi==1.9.0",
],
cwd=BUILD_DIR,
)
Generated
+540 -540
View File
File diff suppressed because it is too large Load Diff
+4 -2
View File
@@ -1,6 +1,6 @@
[tool.poetry]
name = "pybricks"
version = "3.2.0c1"
version = "3.3.0a5"
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>" ]
@@ -29,10 +29,12 @@ packages = [
[tool.poetry.dependencies]
python = "^3.8"
[tool.poetry.dev-dependencies]
[tool.poetry.group.lint.dependencies]
black = "^22.3.0"
doc8 = "^0.8.1"
flake8 = "^4.0"
[tool.poetry.group.doc.dependencies]
Sphinx = { git = "https://github.com/pybricks/sphinx.git", rev = "b00124cb" }
sphinx-rtd-theme = "^1.0.0"
toml = "^0.10.0"
-5
View File
@@ -1,5 +0,0 @@
# This file is strictly for building docs on readthedocs.org
# See pyproject.toml for local development
git+https://github.com/pybricks/sphinx@b00124c#egg=Sphinx
sphinx-rtd-theme==1.0.0
toml
+266 -22
View File
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: MIT
# Copyright (c) 2018-2021 The Pybricks Authors
# Copyright (c) 2018-2023 The Pybricks Authors
"""Generic cross-platform module for typical devices like lights, displays,
speakers, and batteries."""
@@ -8,8 +8,8 @@ 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 .tools import Matrix
from .parameters import Axis, Direction, Stop, Button, Port, Color, Side
if TYPE_CHECKING:
from .parameters import Number
@@ -219,18 +219,18 @@ class Control:
kp: Optional[Number] = None,
ki: Optional[Number] = None,
kd: Optional[Number] = None,
reserved: Optional[Number] = None,
integral_deadzone: Optional[Number] = None,
integral_rate: Optional[Number] = None,
) -> None:
...
@overload
def pid(self) -> Tuple[int, int, int, None, int]:
def pid(self) -> Tuple[int, int, int, int, int]:
...
def pid(self, *args):
"""pid(kp, ki, kd, reserved, integral_rate)
pid() -> Tuple[int, int, int, None, int]
"""pid(kp, ki, kd, integral_deadzone, integral_rate)
pid() -> Tuple[int, int, int, int, int]
Gets or sets the PID values for position and speed control.
@@ -245,7 +245,8 @@ class Control:
kd (int): Derivative position (or proportional speed) control
constant. It is the feedback torque per
unit of speed: µNm/(deg/s).
reserved: This setting is not used.
integral_deadzone (Number, deg or Number, mm): Zone around the
target where the error integral does not accumulate errors.
integral_rate (Number, deg/s or Number, mm/s): Maximum rate at
which the error integral is allowed to grow.
"""
@@ -303,6 +304,52 @@ class Control:
"""
class Model:
"""Class to interact with motor state observer and settings."""
def state(self) -> Tuple[float, float, float, bool]:
"""state() -> Tuple[float, float, float, bool]
Gets the estimated angle, speed, current, and stall state of the motor,
using a simulation model that mimics the real motor.
These estimates are updated faster than the real measurements,
which can be useful when building your own PID controllers.
For most applications it is better to used the *measured*
:meth:`angle <pybricks.pupdevices.Motor.angle>`,
:meth:`speed <pybricks.pupdevices.Motor.speed>`,
:meth:`load <pybricks.pupdevices.Motor.load>`, and
:meth:`stall <pybricks.pupdevices.Motor.stalled>` state instead.
Returns:
Tuple with the estimated angle (deg), speed (deg/s), current (mA),
and stall state (``True`` or ``False``).
"""
@overload
def settings(self, values: tuple) -> None:
...
@overload
def settings(self) -> tuple:
...
def settings(self, speed, time):
"""settings(values)
settings() -> Tuple
Gets or sets model settings as a tuple of integers. If no arguments are
given, this will return the current values. This method is mainly used
to debug the motor model class. Changing these settings should not be
needed in user programs.
.. _model settings: https://docs.pybricks.com/projects/pbio/en/latest/struct__pbio__observer__settings__t.html
Arguments:
values (Tuple): Tuple with `model settings`_.
"""
class Motor(DCMotor):
"""Generic class to control motors with built-in rotation sensors."""
@@ -312,14 +359,18 @@ class Motor(DCMotor):
``control`` attribute of the motor. See :ref:`control` for an overview
of available methods."""
model = Model()
"""Model representing the observer that estimates the motor state."""
def __init__(
self,
port: Port,
positive_direction: Direction = Direction.CLOCKWISE,
gears: Optional[Union[Collection[int], Collection[Collection[int]]]] = None,
reset_angle: bool = True,
profile: Number = None,
):
"""__init__(port, positive_direction=Direction.CLOCKWISE, gears=None, reset_angle=True)
"""__init__(port, positive_direction=Direction.CLOCKWISE, gears=None, reset_angle=True, profile=None)
Arguments:
port (Port): Port to which the motor is connected.
@@ -336,12 +387,16 @@ class Motor(DCMotor):
When you specify a gear train, all motor commands and settings
are automatically adjusted to account for the resulting gear
ratio. The motor direction remains unchanged by this.
reset_angle(bool):
reset_angle (bool):
Choose ``True`` to reset the rotation sensor value to the
absolute marker angle (between -180 and 179).
Choose ``False`` to keep the
current value, so your program knows where it left off last
time.
profile (Number, deg): Precision profile. A lower value
means more precise movement; a larger value means
smoother movement. If no value is given, a suitable profile for
this motor type will be selected automatically.
"""
def angle(self) -> int:
@@ -353,11 +408,19 @@ class Motor(DCMotor):
Motor angle.
"""
def speed(self) -> int:
"""speed() -> int: deg/s
def speed(self, window: Number = 100) -> int:
"""speed(window=100) -> int: deg/s
Gets the speed of the motor.
The speed is measured as the change in the motor angle during the
given time window. A short window makes the speed value more
responsive to motor movement, but less steady. A long window makes the
speed value less responsive, but more steady.
Arguments:
window (Number, ms): The time window used to determine the speed.
Returns:
Motor speed.
@@ -731,7 +794,7 @@ class LightMatrix:
Arguments:
matrices (iter): Sequence of
:class:`Matrix <pybricks.geometry.Matrix>` of intensities.
:class:`Matrix <pybricks.tools.Matrix>` of intensities.
interval (Number, ms): Time to display each image in the list.
"""
@@ -928,22 +991,94 @@ class Accelerometer(SimpleAccelerometer):
along the x-axis.
Returns:
Tuple of pitch and roll angles.
Tuple of pitch and roll angles in degrees.
"""
class IMU(Accelerometer):
def ready(self) -> bool:
"""ready() -> bool
Checks if the device is calibrated and ready for use.
This becomes ``True`` when the robot has been sitting stationary for a
few seconds, which allows the device to re-calibrate. It is ``False``
if the hub has just been started, or if it hasn't had a chance to
calibrate for more than 10 minutes.
Returns:
``True`` if it is ready for use, ``False`` if not.
"""
def stationary(self) -> bool:
"""stationary() -> bool
Checks if the device is currently stationary (not moving).
Returns:
``True`` if stationary for at least a second, ``False`` if it is
moving.
"""
@overload
def settings(
self,
angular_velocity_threshold: float = None,
acceleration_threshold: float = None,
) -> None:
...
@overload
def settings(self) -> Tuple[float, float]:
...
def settings(self, *args):
"""
settings(angular_velocity_threshold, acceleration_threshold)
settings() -> Tuple[float, float]
Configures the IMU settings. If no arguments are given,
this returns the current values.
The ``angular_velocity_threshold`` and ``acceleration_threshold``
define when the hub is considered stationary. If all
measurements stay below these thresholds for one second, the IMU
will recalibrate itself.
In a noisy room with high ambient vibrations (such as a
competition hall), it is recommended to increase the thresholds
slightly to give your robot the chance to calibrate.
To verify that your settings are working as expected, test that
the ``stationary()`` method gives ``False`` if your robot is moving,
and ``True`` if it is sitting still for at least a second.
Arguments:
angular_velocity_threshold (Number, deg/s): The threshold for
angular velocity. The default value is 1.5 deg/s.
acceleration_threshold (Number, mm/s²): The threshold for angular
velocity. The default value is 250 mm/s².
"""
def heading(self) -> float:
"""heading() -> float: deg
Gets the heading angle relative to the starting orientation. It is a
positive rotation around the :ref:`z-axis in the robot
frame <robotframe>`, prior to applying any tilt rotation.
Gets the heading angle of your robot. A positive value means a
clockwise turn.
For a vehicle viewed from the top, this means that
a positive heading value corresponds to a counterclockwise rotation.
The heading is 0 when your program starts. The value continues to grow
even as the robot turns more than 180 degrees. It does not wrap around
to -180 like it does in some apps.
.. note:: This method is not yet implemented.
.. note:: *For now, this method only keeps track of the heading while
the robot is on a flat surface.*
This means that the value is
no longer correct if you lift it from the table. To solve
this, you can call ``reset_heading`` to reset the heading to
a known value *after* you put it back down. For example, you
could align your robot with the side of the competition table
and reset the heading 90 degrees as the new starting point.
Returns:
Heading angle relative to starting orientation.
@@ -955,8 +1090,6 @@ class IMU(Accelerometer):
Resets the accumulated heading angle of the robot.
.. note:: This method is not yet implemented.
Arguments:
angle (Number, deg): Value to which the heading should be reset.
"""
@@ -985,6 +1118,41 @@ class IMU(Accelerometer):
this returns a vector of accelerations along all axes.
"""
def rotation(self, axis: Axis) -> float:
"""
rotation(axis) -> float: deg
Gets the rotation of the device along a given axis in
the :ref:`robot reference frame <robotframe>`.
This value is useful if your robot *only* rotates along the requested
axis. For general three-dimensional motion, use the
``orientation()`` method instead.
The value starts counting from ``0`` when you initialize this class.
Arguments:
axis (Axis): Axis along which the rotation should be measured.
Returns:
The rotation angle.
"""
def orientation(self) -> Matrix:
"""
orientation() -> Matrix
Gets the three-dimensional orientation of the robot in
the :ref:`robot reference frame <robotframe>`.
It returns a rotation matrix whose columns represent the ``X``, ``Y``,
and ``Z`` axis of the robot.
.. note:: This method is not yet implemented.
Returns:
The rotation matrix.
"""
class CommonColorSensor:
"""Generic color sensor that supports Pybricks color calibration."""
@@ -1117,3 +1285,79 @@ class AmbientColorSensor(CommonColorSensor):
Measured color. The color is described by a hue (0--359), a
saturation (0--100), and a brightness value (0--100).
"""
class BLE:
"""
Bluetooth Low Energy.
.. versionadded:: 3.3
"""
def broadcast(self, *args: Union[None, bool, int, float, str, bytes]) -> None:
"""broadcast(data0, data1, ...)
Starts broadcasting the given data values.
Each value can be any of ``int``, ``float``, ``str`, ``bytes``,
``None``, ``True``, or ``False``. The data is broadcasted on the
*broadcast_channel* you selected when initializing the hub.
The total data size is quite limited (26 bytes). ``None``, ``True`` and
``False`` take 1 byte each. ``float`` takes 5 bytes. ``int`` takes 2 to
5 bytes depending on how big the number is. ``str`` and ``bytes`` take
the number of bytes in the object plus one extra byte.
Params:
args: Zero or more values to be broadcast.
.. versionadded:: 3.3
"""
def observe(
self, channel: int
) -> Optional[Tuple[Union[None, bool, int, float, str, bytes], ...]]:
"""observe(channel) -> tuple | None
Retrieves the last observed data for a given channel.
Args:
channel (int): The channel to observe (0 to 255).
Returns:
A tuple of the received data or ``None`` if no recent data is
available.
.. tip:: Receiving data is more reliable when the hub is not connected
to a computer or other devices at the same time.
.. versionadded:: 3.3
"""
def signal_strength(self, channel: int) -> int:
"""signal_strength(channel) -> int: dBm
Gets the average signal strength in dBm for the given channel.
This is useful for detecting how near the broadcasting device is. A close
device may have a signal strength around -40 dBm while a far away device
might have a signal strength around -70 dBm.
Args:
channel (int): The channel number (0 to 255).
Returns:
The signal strength or ``-128`` if there is no recent observed data.
.. versionadded:: 3.3
"""
def version(self) -> str:
"""version() -> str
Gets the firmware version from the Bluetooth chip.
.. versionadded:: 3.3
"""
+2 -4
View File
@@ -168,14 +168,12 @@ class InfraredSensor:
class GyroSensor:
"""LEGO® MINDSTORMS® EV3 Gyro Sensor."""
def __init__(
self, port: _Port, positive_direction: _Direction = _Direction.CLOCKWISE
):
def __init__(self, port: _Port, direction: _Direction = _Direction.CLOCKWISE):
"""GyroSensor(port)
Arguments:
port (Port): Port to which the sensor is connected.
positive_direction (Direction):
direction (Direction):
Positive rotation direction when looking at the red dot on top
of the sensor.
-132
View File
@@ -1,132 +0,0 @@
# SPDX-License-Identifier: MIT
# Copyright (c) 2018-2022 The Pybricks Authors
"""Core linear algebra functionality for orientation sensors and robotics."""
from __future__ import annotations
from typing import Sequence, Tuple, overload
class Matrix:
"""Mathematical representation of a matrix. It supports
addition (``A + B``), subtraction (``A - B``),
and matrix multiplication (``A * B``) for matrices of compatible size.
It also supports scalar multiplication (``c * A`` or ``A * c``)
and scalar division (``A / c``).
A :class:`.Matrix` object is immutable."""
def __add__(self, other) -> Matrix:
...
def __iadd__(self, other) -> Matrix:
...
def __sub__(self, other) -> Matrix:
...
def __isub__(self, other) -> Matrix:
...
def __mul__(self, other) -> Matrix:
...
def __rmul__(self, other) -> Matrix:
...
def __imul__(self, other) -> Matrix:
...
def __truediv__(self, other) -> Matrix:
...
def __itruediv__(self, other) -> Matrix:
...
def __floordiv__(self, other) -> Matrix:
...
def __ifloordiv__(self, other) -> Matrix:
...
def __init__(self, rows: Sequence[Sequence[float]]):
"""Matrix(rows)
Arguments:
rows (list): List of rows. Each row is itself a list of numbers.
"""
@property
def T(self) -> Matrix: # noqa: N802
"""Returns a new :class:`.Matrix` that is the transpose of the
original."""
@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.
"""
@overload
def vector(x: float, y: float) -> Matrix:
"""
Convenience function to create a :class:`.Matrix` with the shape (``2``, ``1``).
Arguments:
x (float): x-coordinate of the vector.
y (float): y-coordinate of the vector.
Returns:
A matrix with the shape of a column vector.
"""
@overload
def vector(x: float, y: float, z: float) -> Matrix:
"""
Convenience function to create a :class:`.Matrix` with the shape (``3``, ``1``).
Arguments:
x (float): x-coordinate of the vector.
y (float): y-coordinate of the vector.
z (float): z-coordinate of the vector.
Returns:
A matrix with the shape of a column vector.
"""
def vector(*args):
"""
vector(x, y) -> Matrix
vector(x, y, z) -> Matrix
Convenience function to create a :class:`.Matrix` with the
shape (``2``, ``1``) or (``3``, ``1``).
Arguments:
x (float): x-coordinate of the vector.
y (float): y-coordinate of the vector.
z (float): z-coordinate of the vector (optional).
Returns:
A matrix with the shape of a column vector.
"""
class Axis:
"""Unit axes of a coordinate system.
.. data:: X = vector(1, 0, 0)
.. data:: Y = vector(0, 1, 0)
.. data:: Z = vector(0, 0, 1)
"""
X: Matrix = vector(1, 0, 0)
Y: Matrix = vector(0, 1, 0)
Z: Matrix = vector(0, 0, 1)
+100 -9
View File
@@ -1,12 +1,14 @@
# SPDX-License-Identifier: MIT
# Copyright (c) 2018-2022 The Pybricks Authors
# Copyright (c) 2018-2023 The Pybricks Authors
"""LEGO® Programmable Hubs."""
from typing import Sequence
from . import _common
from .ev3dev import _speaker
from .geometry import Axis
from .media.ev3dev import Image as _Image
from .parameters import Button as _Button
from .parameters import Button as _Button, Axis
class EV3Brick:
@@ -39,6 +41,25 @@ class MoveHub:
imu = _common.SimpleAccelerometer()
system = _common.System()
button = _common.Keypad([_Button.CENTER])
ble = _common.BLE()
def __init__(
self, broadcast_channel: int = 0, observe_channels: Sequence[int] = []
):
"""MoveHub(broadcast_channel=0, observe_channels=[])
Arguments:
broadcast_channel:
A value from 0 to 255 indicating which channel ``hub.ble.broadcast()``
will use. Default is channel 0.
observe_channels:
A list of channels to listen to when ``hub.ble.observe()`` is
called. Listening to more channels requires more memory.
Default is an empty list (no channels).
.. versionchanged:: 3.3
Added *broadcast_channel* and *observe_channels* arguments.
"""
class CityHub:
@@ -50,6 +71,25 @@ class CityHub:
light = _common.ColorLight()
system = _common.System()
button = _common.Keypad([_Button.CENTER])
ble = _common.BLE()
def __init__(
self, broadcast_channel: int = 0, observe_channels: Sequence[int] = []
):
"""CityHub(broadcast_channel=0, observe_channels=[])
Arguments:
broadcast_channel:
A value from 0 to 255 indicating which channel ``hub.ble.broadcast()``
will use. Default is channel 0.
observe_channels:
A list of channels to listen to when ``hub.ble.observe()`` is
called. Listening to more channels requires more memory.
Default is an empty list (no channels).
.. versionchanged:: 3.3
Added *broadcast_channel* and *observe_channels* arguments.
"""
class TechnicHub:
@@ -62,9 +102,16 @@ class TechnicHub:
imu = _common.IMU()
system = _common.System()
button = _common.Keypad([_Button.CENTER])
ble = _common.BLE()
def __init__(self, top_side: Axis = Axis.Z, front_side: Axis = Axis.X):
"""TechnicHub(top_side=Axis.Z, front_side=Axis.X)
def __init__(
self,
top_side: Axis = Axis.Z,
front_side: Axis = Axis.X,
broadcast_channel: int = 0,
observe_channels: Sequence[int] = [],
):
"""TechnicHub(top_side=Axis.Z, front_side=Axis.X, broadcast_channel=0, observe_channels=[])
Initializes the hub. Optionally, specify how the hub is
:ref:`placed in your design <robotframe>` by saying in which
@@ -76,6 +123,16 @@ class TechnicHub:
the hub.
front_side (Axis): The axis that passes through the *front side* of
the hub.
broadcast_channel:
A value from 0 to 255 indicating which channel ``hub.ble.broadcast()``
will use. Default is channel 0.
observe_channels:
A list of channels to listen to when ``hub.ble.observe()`` is
called. Listening to more channels requires more memory.
Default is an empty list (no channels).
.. versionchanged:: 3.3
Added *broadcast_channel* and *observe_channels* arguments.
"""
@@ -90,9 +147,16 @@ class EssentialHub:
light = _common.ColorLight()
imu = _common.IMU()
system = _common.System()
ble = _common.BLE()
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,
broadcast_channel: int = 0,
observe_channels: Sequence[int] = [],
):
"""EssentialHub(top_side=Axis.Z, front_side=Axis.X, broadcast_channel=0, observe_channels=[])
Initializes the hub. Optionally, specify how the hub is
:ref:`placed in your design <robotframe>` by saying in which
@@ -104,6 +168,16 @@ class EssentialHub:
the hub.
front_side (Axis): The axis that passes through the *front side* of
the hub.
broadcast_channel:
A value from 0 to 255 indicating which channel ``hub.ble.broadcast()``
will use. Default is channel 0.
observe_channels:
A list of channels to listen to when ``hub.ble.observe()`` is
called. Listening to more channels requires more memory.
Default is an empty list (no channels).
.. versionchanged:: 3.3
Added *broadcast_channel* and *observe_channels* arguments.
"""
pass
@@ -128,9 +202,16 @@ class PrimeHub:
speaker = _common.Speaker()
imu = _common.IMU()
system = _common.System()
ble = _common.BLE()
def __init__(self, top_side: Axis = Axis.Z, front_side: Axis = Axis.X):
"""PrimeHub(top_side=Axis.Z, front_side=Axis.X)
def __init__(
self,
top_side: Axis = Axis.Z,
front_side: Axis = Axis.X,
broadcast_channel: int = 0,
observe_channels: Sequence[int] = [],
):
"""PrimeHub(top_side=Axis.Z, front_side=Axis.X, broadcast_channel=0, observe_channels=[])
Initializes the hub. Optionally, specify how the hub is
:ref:`placed in your design <robotframe>` by saying in which
@@ -142,6 +223,16 @@ class PrimeHub:
the hub.
front_side (Axis): The axis that passes through the *front side* of
the hub.
broadcast_channel:
A value from 0 to 255 indicating which channel ``hub.ble.broadcast()``
will use. Default is channel 0.
observe_channels:
A list of channels to listen to when ``hub.ble.observe()`` is
called. Listening to more channels requires more memory.
Default is an empty list (no channels).
.. versionchanged:: 3.3
Added *broadcast_channel* and *observe_channels* arguments.
"""
+15 -1
View File
@@ -9,7 +9,7 @@ from enum import Enum
from typing import Union, TYPE_CHECKING
import os
from .geometry import Matrix as _Matrix
from .tools import Matrix as _Matrix, vector as _vector
if TYPE_CHECKING or os.environ.get("SPHINX_BUILD") == "True":
Number = Union[int, float]
@@ -57,6 +57,20 @@ class _PybricksEnum(Enum, metaclass=_PybricksEnumMeta):
return str(self)
class Axis:
"""Unit axes of a coordinate system.
.. data:: X = vector(1, 0, 0)
.. data:: Y = vector(0, 1, 0)
.. data:: Z = vector(0, 0, 1)
"""
X: _Matrix = _vector(1, 0, 0)
Y: _Matrix = _vector(0, 1, 0)
Z: _Matrix = _vector(0, 0, 1)
class Color:
"""Light or surface color."""
+8 -3
View File
@@ -38,8 +38,9 @@ class Motor(_common.Motor):
positive_direction: Direction = Direction.CLOCKWISE,
gears: Optional[Union[Collection[int], Collection[Collection[int]]]] = None,
reset_angle: bool = True,
profile: Number = None,
):
"""__init__(port, positive_direction=Direction.CLOCKWISE, gears=None, reset_angle=True)
"""__init__(port, positive_direction=Direction.CLOCKWISE, gears=None, reset_angle=True, profile=None)
Arguments:
port (Port): Port to which the motor is connected.
@@ -56,12 +57,16 @@ class Motor(_common.Motor):
When you specify a gear train, all motor commands and settings
are automatically adjusted to account for the resulting gear
ratio. The motor direction remains unchanged by this.
reset_angle(bool):
reset_angle (bool):
Choose ``True`` to reset the rotation sensor value to the
absolute marker angle (between -180 and 179).
Choose ``False`` to keep the
current value, so your program knows where it left off last
time.
profile (Number, deg): Precision profile. A lower value
means more precise movement; a larger value means
smoother movement. If no value is given, a suitable profile for
this motor type will be selected automatically.
"""
def reset_angle(self, angle: Optional[Number] = None) -> None:
@@ -92,7 +97,7 @@ class Remote:
Button.RIGHT_PLUS,
)
)
addresss: Union[str, None]
address: Union[str, None]
def __init__(self, name: Optional[str] = None, timeout: int = 10000):
"""Remote(name=None, timeout=10000)
+18 -9
View File
@@ -28,9 +28,7 @@ class DriveBase:
**Positive** angles and turn rates mean turning **right**.
**Negative** means **left**. So when viewed from the top,
positive means clockwise and negative means counterclockwise. If desired,
you can flip this convention by reversing the ``left_motor`` and
``right_motor`` when you initialize this class.
positive means clockwise and negative means counterclockwise.
See the `measuring`_ section for tips to measure and adjust the diameter
and axle track values.
@@ -135,25 +133,30 @@ class DriveBase:
...
def settings(self, *args):
"""settings(straight_speed, straight_acceleration, turn_rate, turn_acceleration)
"""
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`.
Configures the drive base speed and acceleration.
If you give no arguments, this returns the current values as a tuple.
The default values are automatically configured based on your wheel
The initial values are automatically configured based on your wheel
diameter and axle track. They are selected such that your robot
drives at about 40% of its maximum speed.
The speed values given here do not apply to the :meth:`.drive` method,
since you provide your own speed values as arguments in that method.
Arguments:
straight_speed (Number, mm/s): Straight-line speed of the robot.
straight_acceleration (Number, mm/): Straight-line
acceleration and deceleration of the robot.
acceleration and deceleration of the robot. Provide a tuple with
two values to set acceleration and deceleration separately.
turn_rate (Number, deg/s): Turn rate of the robot.
turn_acceleration (Number, deg/): Angular acceleration and
deceleration of the robot.
deceleration of the robot. Provide a tuple with
two values to set acceleration and deceleration separately.
"""
def straight(
@@ -219,6 +222,12 @@ class DriveBase:
"""
class GyroDriveBase(DriveBase):
"""A robotic vehicle with two powered wheels and an optional support
wheel or caster. It measures the heading using the hub's built-in gyroscope,
which can make turning and driving straight more accurate."""
# HACK: hide from jedi
if TYPE_CHECKING:
del Motor
+128 -3
View File
@@ -1,11 +1,11 @@
# SPDX-License-Identifier: MIT
# Copyright (c) 2018-2022 The Pybricks Authors
# Copyright (c) 2018-2023 The Pybricks Authors
"""Common tools for timing and data logging."""
"""Common tools for timing, data logging, and linear algebra."""
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from typing import TYPE_CHECKING, Any, Sequence, Tuple, overload
if TYPE_CHECKING:
from .parameters import Number
@@ -97,6 +97,131 @@ class DataLog:
"""
class Matrix:
"""Mathematical representation of a matrix. It supports
addition (``A + B``), subtraction (``A - B``),
and matrix multiplication (``A * B``) for matrices of compatible size.
It also supports scalar multiplication (``c * A`` or ``A * c``)
and scalar division (``A / c``).
A :class:`.Matrix` object is immutable."""
def __add__(self, other) -> Matrix:
...
def __iadd__(self, other) -> Matrix:
...
def __sub__(self, other) -> Matrix:
...
def __isub__(self, other) -> Matrix:
...
def __mul__(self, other) -> Matrix:
...
def __rmul__(self, other) -> Matrix:
...
def __imul__(self, other) -> Matrix:
...
def __truediv__(self, other) -> Matrix:
...
def __itruediv__(self, other) -> Matrix:
...
def __floordiv__(self, other) -> Matrix:
...
def __ifloordiv__(self, other) -> Matrix:
...
def __init__(self, rows: Sequence[Sequence[float]]):
"""Matrix(rows)
Arguments:
rows (list): List of rows. Each row is itself a list of numbers.
"""
@property
def T(self) -> Matrix: # noqa: N802
"""Returns a new :class:`.Matrix` that is the transpose of the
original."""
@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.
"""
@overload
def vector(x: float, y: float) -> Matrix:
"""
Convenience function to create a :class:`.Matrix` with the shape (``2``, ``1``).
Arguments:
x (float): x-coordinate of the vector.
y (float): y-coordinate of the vector.
Returns:
A matrix with the shape of a column vector.
"""
@overload
def vector(x: float, y: float, z: float) -> Matrix:
"""
Convenience function to create a :class:`.Matrix` with the shape (``3``, ``1``).
Arguments:
x (float): x-coordinate of the vector.
y (float): y-coordinate of the vector.
z (float): z-coordinate of the vector.
Returns:
A matrix with the shape of a column vector.
"""
def vector(*args):
"""
vector(x, y) -> Matrix
vector(x, y, z) -> Matrix
Convenience function to create a :class:`.Matrix` with the
shape (``2``, ``1``) or (``3``, ``1``).
Arguments:
x (float): x-coordinate of the vector.
y (float): y-coordinate of the vector.
z (float): z-coordinate of the vector (optional).
Returns:
A matrix with the shape of a column vector.
"""
def cross(a: Matrix, b: Matrix) -> Matrix:
"""
cross(a, b) -> Matrix
Gets the cross product ``a`` × ``b`` of two vectors.
Arguments:
a (Matrix): A three-dimensional vector.
b (Matrix): A three-dimensional vector.
Returns:
The cross product, also a three-dimensional vector.
"""
# HACK: hide from jedi
if TYPE_CHECKING:
del Number
+4 -3
View File
@@ -1074,8 +1074,9 @@ def round(*args):
truncate trailing zeros. To print numbers nicely, format strings instead::
# print two decimal places
print('my number: %.2f' % number) print('my number:
{:.2f}'.format(number))
print('my number: %.2f' % number)
print('my number: {:.2f}'.format(number))
print(f'my number: {number:.2f}')
Arguments:
number (float): The number to be rounded.
@@ -1169,7 +1170,7 @@ class str:
If no argument is given, this creates an empty ``str`` object.
Arguments:
object: If only this argument is given, this returns the stirng
object: If only this argument is given, this returns the string
representation of the object.
encoding (str): If the first argument is a ``bytearray`` or ``bytes``
object and the encoding argument is ``"utf-8"``, this will decode
+1 -1
View File
@@ -88,7 +88,7 @@ def getrandbits(k: int) -> int:
"""
getrandbits(k) -> int
Gets a random integer :math:`N` satisfying :math:`0 \\leq N < 2^{\\text{bits}}`.
Gets a random integer :math:`N` satisfying :math:`0 \\leq N < 2^{\\text{k}}`.
Arguments:
k (int): How many bits to use for the result.