Compare commits

...

91 commits

Author SHA1 Message Date
foamyguy
3b7cc0a51f update rtd.yml file
Signed-off-by: foamyguy <foamyguy@gmail.com>
2025-06-17 10:31:53 -05:00
foamyguy
bbe12f008c
Merge pull request #51 from FoamyGuy/displayio_api_update
displayio API update
2025-05-28 16:20:57 -05:00
foamyguy
3446470fa1 displayio API update 2025-05-27 16:28:36 -05:00
foamyguy
4d945fe51a
Merge pull request #50 from adafruit/use_ruff
change to ruff
2025-05-16 14:46:02 -05:00
foamyguy
8ee4425a0d change to ruff 2025-05-16 19:34:43 +00:00
foamyguy
5da667ae32
Merge pull request #49 from justmobilize/remove-secrets-usage
Remove secrets usage
2025-02-27 20:54:47 -06:00
Justin Myers
cb4511ae61 Remove secrets usage 2025-02-27 15:43:54 -08:00
foamyguy
5aaa6abd75 add sphinx configuration to rtd.yaml
Signed-off-by: foamyguy <foamyguy@gmail.com>
2025-01-16 09:17:58 -06:00
foamyguy
b94d548cd1
Merge pull request #44 from FoamyGuy/circle_and_dot_fix
make circle and dot always use degrees internally
2024-12-12 13:22:09 -06:00
foamyguy
63a6ffbf91
Merge pull request #48 from FoamyGuy/visible_turtle_loc_fix
fix for visible turtle location
2024-12-09 09:57:56 -06:00
foamyguy
277983a836 fix for visible turtle location 2024-12-09 09:12:37 -06:00
foamyguy
49d941a3f2
Merge pull request #45 from adafruit/issue41
Account for fractions of a pixel when drawing
2024-12-05 08:56:15 -06:00
614e9e2b4f Account for fractions of a pixel when drawing
Previously, the endpoint of the line was always moved
along in increments of 1 pixel, so that the endpoint would always be
rounded down. This could accumulate to give quite large differences
from what the program intended.

Ensure that "goto" always ends up storing the floating point endpoints
and that the line is drawn from the rounded-integer starting coordinate
and rounded-integer ending coordinate.

This makes the 3 test lines in the OP's "turtle_truncate.txt" example
be the same length.

Closes: #41
2024-12-04 18:57:14 -06:00
foamyguy
591b805474 remove pylint disables 2024-12-04 10:16:11 -06:00
foamyguy
96222c3429 remove space 2024-12-04 10:12:15 -06:00
foamyguy
e921f796f1 make circle and dot always use degrees internally 2024-12-04 09:30:24 -06:00
foamyguy
06de267b3a
Merge pull request #42 from FoamyGuy/standard_color_docs
Standard color docs
2024-12-04 08:19:24 -06:00
foamyguy
bc7315d4b6
Merge pull request #43 from FoamyGuy/mode_default
default to "standard" mode
2024-12-04 08:19:12 -06:00
foamyguy
f2ae512e0e default to "standard" mode 2024-12-02 17:24:48 -06:00
foamyguy
0c57fd42dc format 2024-12-02 16:06:44 -06:00
foamyguy
ebd591df45 remove duplicate color name 2024-12-02 16:02:41 -06:00
foamyguy
eeac41fe02 list standard colors in the docstrings 2024-12-02 15:58:23 -06:00
foamyguy
057d7fd9fa remove deprecated get_html_theme_path() call
Signed-off-by: foamyguy <foamyguy@gmail.com>
2024-10-07 14:41:49 -05:00
foamyguy
5a170cb7b1 unpin sphinx and add sphinx-rtd-theme to docs reqs
Signed-off-by: foamyguy <foamyguy@gmail.com>
2023-12-04 09:54:58 -06:00
Scott Shawcroft
17a80d38a7
Merge pull request #36 from RetiredWizard/removeShow
Remove depreciated displayio.show
2023-10-19 09:11:19 -07:00
RetiredWizard
9d09f16bb2 Remove depreciated displayio.show 2023-10-19 01:48:10 -04:00
foamyguy
d4477d1126 "fix rtd theme
"
2023-09-18 16:24:09 -05:00
foamyguy
f632227871
Merge pull request #35 from rrahkola/dev/add_type_annotations
adding type annotations for adafruit_turtle.py
2023-09-04 11:03:57 -05:00
foamyguy
d4a599a928 code format, use more specific types than Any 2023-09-04 10:57:38 -05:00
foamyguy
f03cfc7fa1 merge main, handle PR feedback 2023-09-04 10:50:19 -05:00
foamyguy
53d222e3f5 Merge branch 'main' into dev/add_type_annotations
# Conflicts:
#	adafruit_turtle.py
2023-09-04 10:48:48 -05:00
foamyguy
93ea97b2c8
Merge pull request #34 from adafruit/tannewt-fix-koch
Fix koch examples
2023-07-29 10:35:03 -05:00
Tekktrik
751760ebd7 Update .pylintrc, fix jQuery for docs
Signed-off-by: Tekktrik <tekktrik@gmail.com>
2023-05-23 21:16:31 -04:00
Tekktrik
a30359b9d8 Run pre-commit 2023-05-10 22:47:08 -04:00
Tekktrik
141d80ce8f Update pre-commit hooks
Signed-off-by: Tekktrik <tekktrik@gmail.com>
2023-05-10 15:21:52 -04:00
Rauha Rahkola
012c3b3a9c revert some unnecessary refactoring 2023-04-27 08:55:30 -07:00
Rauha Rahkola
614b602f8d adding type annotations for adafruit_turtle.py 2023-04-27 08:47:11 -07:00
Scott Shawcroft
480352b7b9
Fix overlayed koch 2023-04-19 10:57:41 -07:00
Scott Shawcroft
d70d57abca
Fix koch example 2023-04-19 10:55:38 -07:00
Alec Delaney
2ab650e364 Add upload url to release action
Signed-off-by: Alec Delaney <89490472+tekktrik@users.noreply.github.com>
2023-01-19 23:49:52 -05:00
Alec Delaney
0ac3837b82 Add .venv to .gitignore
Signed-off-by: Alec Delaney <89490472+tekktrik@users.noreply.github.com>
2022-11-30 19:38:47 -05:00
Kattni
a9a5385902
Merge pull request #32 from tekktrik/dev/fix-pylint-errors
Fix pylint errors
2022-11-08 15:29:45 -05:00
Alec Delaney
689c01102c Fix pylint errors 2022-11-07 21:07:36 -05:00
Alec Delaney
298f6de310 Update .pylintrc for v2.15.5 2022-11-04 18:34:33 -04:00
Alec Delaney
f97bae7826 Fix release CI files 2022-11-04 09:12:46 -04:00
Alec Delaney
4bdae92772 Update pylint to 2.15.5 2022-11-04 08:15:21 -04:00
Alec Delaney
4fb06f4482 Updated pylint version to 2.13.0 2022-11-04 00:47:01 -04:00
Alec Delaney
332a947519 Switching to composite actions 2022-11-04 00:02:50 -04:00
foamyguy
b7b438657e
Merge pull request #31 from shulltronics/cpython-compatibility
CPython compatibility fix
2022-10-03 17:57:41 -05:00
Carsten Thue-Bludworth
47f94f2aa8
Merge pull request #1 from FoamyGuy/foamyguy_cpython_compat
CPython compatibility
2022-10-01 21:43:14 -04:00
foamyguy
12e4ec2756 Merge remote-tracking branch 'shulltronics/cpython-compatibility' into foamyguy_cpython_compat
# Conflicts:
#	adafruit_turtle.py
2022-10-01 11:17:30 -05:00
foamyguy
87ee248a95 remove unused super init 2022-10-01 11:11:26 -05:00
foamyguy
c146d6bb77 allow import outside top for board 2022-10-01 11:10:10 -05:00
foamyguy
5acb2d0585 only import board if we are going to try to use builtin display 2022-10-01 11:04:45 -05:00
foamyguy
017591b4d4 try has-a tuple instead of is-a tuple for Vec2D 2022-10-01 10:53:31 -05:00
Carsten Thue-Bludworth
8c3267999c Removed author info 2022-10-01 10:50:56 -04:00
Carsten Thue-Bludworth
cf9a11aac8 Fixed test errors by implementing __getitem__ method for Vec2D 2022-09-27 23:30:15 -04:00
Carsten Thue-Bludworth
0161017036 Actually added author info 2022-09-27 22:30:59 -04:00
Carsten Thue-Bludworth
b197cd6135 Added author info and ran through black 2022-09-27 22:27:30 -04:00
Carsten Thue-Bludworth
30c0988eb6 Fixed CPython compatibility 2022-09-27 22:20:03 -04:00
Alec Delaney
9f23b464df Use year duration range for copyright attribution 2022-08-23 17:26:23 -04:00
Alec Delaney
6f672a2351 Keep copyright up to date in documentation 2022-08-22 21:36:33 -04:00
Alec Delaney
2a993cbc38 Fix version strings in workflow files 2022-08-16 21:09:16 -04:00
Alec Delaney
79828c040f Update version string 2022-08-16 18:09:16 -04:00
Alec Delaney
d1e81525cd Add setuptools-scm to build system requirements
Signed-off-by: Alec Delaney <tekktrik@gmail.com>
2022-08-09 13:33:04 -04:00
Alec Delaney
463058218d Switched to pyproject.toml 2022-08-08 22:05:55 -04:00
evaherrada
be87a2c4e5
Added Black formatting badge 2022-08-02 17:01:12 -04:00
evaherrada
6e6270800b
Changed .env to .venv in README.rst 2022-07-22 13:59:28 -04:00
evaherrada
4cedbc39d3
Added cp.org link to index.rst 2022-06-07 15:35:09 -04:00
Alec Delaney
1a5e4b0448 Set language to "en" for documentation
Signed-off-by: Alec Delaney <tekktrik@gmail.com>
2022-05-30 17:51:51 -04:00
Alec Delaney
6df5a460dd Switch to inclusive terminology
Signed-off-by: Alec Delaney <tekktrik@gmail.com>
2022-05-25 23:14:32 -04:00
Alec Delaney
7f8109fd9d Increase min lines similarity
Signed-off-by: Alec Delaney <tekktrik@gmail.com>
2022-05-25 19:30:35 -04:00
Alec Delaney
a51d60d572 Patch .pre-commit-config.yaml 2022-05-15 12:49:54 -04:00
foamyguy
c3a0d4150c change discord badge 2022-04-24 14:06:41 -05:00
evaherrada
8ccecc57b7
Patch: Replaced discord badge image 2022-04-22 15:59:30 -04:00
evaherrada
de4b5821e2
Updated gitignore
Signed-off-by: evaherrada <eva.herrada@adafruit.com>
2022-04-21 16:46:40 -04:00
Kattni Rembor
0335851da3 Update Black to latest.
Signed-off-by: Kattni Rembor <kattni@adafruit.com>
2022-03-28 18:11:52 -04:00
Dan Halbert
5a5ef0efe4
Merge pull request #29 from FoamyGuy/remove_cp_6_fallback
Remove cp 6 fallback
2022-02-19 15:06:35 -05:00
foamyguy
28047a70f2 remove file opening and closing for ODBs 2022-02-19 11:15:07 -06:00
foamyguy
37e173e89d updates to remove CP 6 fallback 2022-02-19 10:58:27 -06:00
foamyguy
cb3d4b5652
Merge pull request #25 from lesamouraipourpre/ondiskbitmap-changes
Update the pixel_shader usage of OnDiskBitmap
2022-02-19 10:35:07 -06:00
dherrada
2dab785f8f Fixed readthedocs build
Signed-off-by: dherrada <dylan.herrada@adafruit.com>
2022-02-15 11:56:28 -05:00
Alec Delaney
051c51dc9f Consolidate Documentation sections of README 2022-02-10 10:16:52 -05:00
dherrada
7ce5a9a3a5 Updated docs link, updated python docs link, updated setup.py 2022-01-24 16:46:17 -05:00
dherrada
d6549f1829 First part of patch
Signed-off-by: dherrada <dylan.herrada@adafruit.com>
2022-01-19 13:52:10 -05:00
foamyguy
b37b26f25d update rtd py version 2021-11-23 13:16:53 -06:00
dherrada
457bd3845d Updated readthedocs file
Signed-off-by: dherrada <dylan.herrada@adafruit.com>
2021-11-09 15:27:05 -05:00
dherrada
41470b253d Disabled unspecified-encoding pylint check
Signed-off-by: dherrada <dylan.herrada@adafruit.com>
2021-11-05 15:19:23 -04:00
Kattni
4ebb440c82
Merge pull request #28 from adafruit/patch-fix
Linted
2021-11-05 13:51:10 -04:00
James Carr
15e766f51e Update the pixel_shader usage of OnDiskBitmap 2021-07-11 15:53:21 +01:00
James Carr
488c3c3295 Add an example which uses the methods that use OnDiskBitmap 2021-07-11 15:51:40 +01:00
38 changed files with 655 additions and 900 deletions

11
.gitattributes vendored Normal file
View file

@ -0,0 +1,11 @@
# SPDX-FileCopyrightText: 2024 Justin Myers for Adafruit Industries
#
# SPDX-License-Identifier: Unlicense
.py text eol=lf
.rst text eol=lf
.txt text eol=lf
.yaml text eol=lf
.toml text eol=lf
.license text eol=lf
.md text eol=lf

View file

@ -4,7 +4,7 @@
Thank you for contributing! Before you submit a pull request, please read the following.
Make sure any changes you're submitting are in line with the CircuitPython Design Guide, available here: https://circuitpython.readthedocs.io/en/latest/docs/design_guide.html
Make sure any changes you're submitting are in line with the CircuitPython Design Guide, available here: https://docs.circuitpython.org/en/latest/docs/design_guide.html
If your changes are to documentation, please verify that the documentation builds locally by following the steps found here: https://adafru.it/build-docs

View file

@ -10,66 +10,5 @@ jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- name: Translate Repo Name For Build Tools filename_prefix
id: repo-name
run: |
echo ::set-output name=repo-name::$(
echo ${{ github.repository }} |
awk -F '\/' '{ print tolower($2) }' |
tr '_' '-'
)
- name: Set up Python 3.7
uses: actions/setup-python@v1
with:
python-version: 3.7
- name: Versions
run: |
python3 --version
- name: Checkout Current Repo
uses: actions/checkout@v1
with:
submodules: true
- name: Checkout tools repo
uses: actions/checkout@v2
with:
repository: adafruit/actions-ci-circuitpython-libs
path: actions-ci
- name: Install dependencies
# (e.g. - apt-get: gettext, etc; pip: circuitpython-build-tools, requirements.txt; etc.)
run: |
source actions-ci/install.sh
- name: Pip install Sphinx, pre-commit
run: |
pip install --force-reinstall Sphinx sphinx-rtd-theme pre-commit
- name: Library version
run: git describe --dirty --always --tags
- name: Pre-commit hooks
run: |
pre-commit run --all-files
- name: Build assets
run: circuitpython-build-bundles --filename_prefix ${{ steps.repo-name.outputs.repo-name }} --library_location .
- name: Archive bundles
uses: actions/upload-artifact@v2
with:
name: bundles
path: ${{ github.workspace }}/bundles/
- name: Build docs
working-directory: docs
run: sphinx-build -E -W -b html . _build/html
- name: Check For setup.py
id: need-pypi
run: |
echo ::set-output name=setup-py::$( find . -wholename './setup.py' )
- name: Build Python package
if: contains(steps.need-pypi.outputs.setup-py, 'setup.py')
run: |
pip install --upgrade setuptools wheel twine readme_renderer testresources
python setup.py sdist
python setup.py bdist_wheel --universal
twine check dist/*
- name: Setup problem matchers
uses: adafruit/circuitpython-action-library-ci-problem-matchers@v1
- name: Run Build CI workflow
uses: adafruit/workflows-circuitpython-libs/build@main

View file

@ -1,85 +0,0 @@
# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
#
# SPDX-License-Identifier: MIT
name: Release Actions
on:
release:
types: [published]
jobs:
upload-release-assets:
runs-on: ubuntu-latest
steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- name: Translate Repo Name For Build Tools filename_prefix
id: repo-name
run: |
echo ::set-output name=repo-name::$(
echo ${{ github.repository }} |
awk -F '\/' '{ print tolower($2) }' |
tr '_' '-'
)
- name: Set up Python 3.6
uses: actions/setup-python@v1
with:
python-version: 3.6
- name: Versions
run: |
python3 --version
- name: Checkout Current Repo
uses: actions/checkout@v1
with:
submodules: true
- name: Checkout tools repo
uses: actions/checkout@v2
with:
repository: adafruit/actions-ci-circuitpython-libs
path: actions-ci
- name: Install deps
run: |
source actions-ci/install.sh
- name: Build assets
run: circuitpython-build-bundles --filename_prefix ${{ steps.repo-name.outputs.repo-name }} --library_location .
- name: Upload Release Assets
# the 'official' actions version does not yet support dynamically
# supplying asset names to upload. @csexton's version chosen based on
# discussion in the issue below, as its the simplest to implement and
# allows for selecting files with a pattern.
# https://github.com/actions/upload-release-asset/issues/4
#uses: actions/upload-release-asset@v1.0.1
uses: csexton/release-asset-action@master
with:
pattern: "bundles/*"
github-token: ${{ secrets.GITHUB_TOKEN }}
upload-pypi:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Check For setup.py
id: need-pypi
run: |
echo ::set-output name=setup-py::$( find . -wholename './setup.py' )
- name: Set up Python
if: contains(steps.need-pypi.outputs.setup-py, 'setup.py')
uses: actions/setup-python@v1
with:
python-version: '3.x'
- name: Install dependencies
if: contains(steps.need-pypi.outputs.setup-py, 'setup.py')
run: |
python -m pip install --upgrade pip
pip install setuptools wheel twine
- name: Build and publish
if: contains(steps.need-pypi.outputs.setup-py, 'setup.py')
env:
TWINE_USERNAME: ${{ secrets.pypi_username }}
TWINE_PASSWORD: ${{ secrets.pypi_password }}
run: |
python setup.py sdist
twine upload dist/*

19
.github/workflows/release_gh.yml vendored Normal file
View file

@ -0,0 +1,19 @@
# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
#
# SPDX-License-Identifier: MIT
name: GitHub Release Actions
on:
release:
types: [published]
jobs:
upload-release-assets:
runs-on: ubuntu-latest
steps:
- name: Run GitHub Release CI workflow
uses: adafruit/workflows-circuitpython-libs/release-gh@main
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
upload-url: ${{ github.event.release.upload_url }}

19
.github/workflows/release_pypi.yml vendored Normal file
View file

@ -0,0 +1,19 @@
# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
#
# SPDX-License-Identifier: MIT
name: PyPI Release Actions
on:
release:
types: [published]
jobs:
upload-release-assets:
runs-on: ubuntu-latest
steps:
- name: Run PyPI Release CI workflow
uses: adafruit/workflows-circuitpython-libs/release-pypi@main
with:
pypi-username: ${{ secrets.pypi_username }}
pypi-password: ${{ secrets.pypi_password }}

55
.gitignore vendored
View file

@ -1,15 +1,54 @@
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-FileCopyrightText: 2022 Kattni Rembor, written for Adafruit Industries
#
# SPDX-License-Identifier: Unlicense
# SPDX-License-Identifier: MIT
# Do not include files and directories created by your personal work environment, such as the IDE
# you use, except for those already listed here. Pull requests including changes to this file will
# not be accepted.
# This .gitignore file contains rules for files generated by working with CircuitPython libraries,
# including building Sphinx, testing with pip, and creating a virual environment, as well as the
# MacOS and IDE-specific files generated by using MacOS in general, or the PyCharm or VSCode IDEs.
# If you find that there are files being generated on your machine that should not be included in
# your git commit, you should create a .gitignore_global file on your computer to include the
# files created by your personal setup. To do so, follow the two steps below.
# First, create a file called .gitignore_global somewhere convenient for you, and add rules for
# the files you want to exclude from git commits.
# Second, configure Git to use the exclude file for all Git repositories by running the
# following via commandline, replacing "path/to/your/" with the actual path to your newly created
# .gitignore_global file:
# git config --global core.excludesfile path/to/your/.gitignore_global
# CircuitPython-specific files
*.mpy
.idea
# Python-specific files
__pycache__
_build
*.pyc
# Sphinx build-specific files
_build
# MyPy-specific type-checking files
.mypy_cache
# pip install files
/build/
# This file results from running `pip -e install .` in a local repository
*.egg-info
# Virtual environment-specific files
.env
bundles
.venv
# MacOS-specific files
*.DS_Store
.eggs
dist
**/*.egg-info
# IDE-specific files
.idea
.vscode
*~

View file

@ -1,42 +1,21 @@
# SPDX-FileCopyrightText: 2020 Diego Elio Pettenò
# SPDX-FileCopyrightText: 2024 Justin Myers for Adafruit Industries
#
# SPDX-License-Identifier: Unlicense
repos:
- repo: https://github.com/python/black
rev: 20.8b1
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: black
- repo: https://github.com/fsfe/reuse-tool
rev: v0.12.1
- id: check-yaml
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.3.4
hooks:
- id: reuse
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v2.3.0
- id: ruff-format
- id: ruff
args: ["--fix"]
- repo: https://github.com/fsfe/reuse-tool
rev: v3.0.1
hooks:
- id: check-yaml
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/pycqa/pylint
rev: v2.11.1
hooks:
- id: pylint
name: pylint (library code)
types: [python]
args:
- --disable=consider-using-f-string
exclude: "^(docs/|examples/|tests/|setup.py$)"
- id: pylint
name: pylint (example code)
description: Run pylint rules on "examples/*.py" files
types: [python]
files: "^examples/"
args:
- --disable=missing-docstring,invalid-name,consider-using-f-string,duplicate-code
- id: pylint
name: pylint (test code)
description: Run pylint rules on "tests/*.py" files
types: [python]
files: "^tests/"
args:
- --disable=missing-docstring,consider-using-f-string,duplicate-code
- id: reuse

436
.pylintrc
View file

@ -1,436 +0,0 @@
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
#
# SPDX-License-Identifier: Unlicense
[MASTER]
# A comma-separated list of package or module names from where C extensions may
# be loaded. Extensions are loading into the active Python interpreter and may
# run arbitrary code
extension-pkg-whitelist=
# Add files or directories to the blacklist. They should be base names, not
# paths.
ignore=CVS
# Add files or directories matching the regex patterns to the blacklist. The
# regex matches against base names, not paths.
ignore-patterns=
# Python code to execute, usually for sys.path manipulation such as
# pygtk.require().
#init-hook=
# Use multiple processes to speed up Pylint.
jobs=1
# List of plugins (as comma separated values of python modules names) to load,
# usually to register additional checkers.
load-plugins=
# Pickle collected data for later comparisons.
persistent=yes
# Specify a configuration file.
#rcfile=
# Allow loading of arbitrary C extensions. Extensions are imported into the
# active Python interpreter and may run arbitrary code.
unsafe-load-any-extension=no
[MESSAGES CONTROL]
# Only show warnings with the listed confidence levels. Leave empty to show
# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED
confidence=
# Disable the message, report, category or checker with the given id(s). You
# can either give multiple identifiers separated by comma (,) or put this
# option multiple times (only on the command line, not in the configuration
# file where it should appear only once).You can also use "--disable=all" to
# disable everything first and then reenable specific checks. For example, if
# you want to run only the similarities checker, you can use "--disable=all
# --enable=similarities". If you want to run only the classes checker, but have
# no Warning level messages displayed, use"--disable=all --enable=classes
# --disable=W"
# disable=import-error,print-statement,parameter-unpacking,unpacking-in-except,old-raise-syntax,backtick,long-suffix,old-ne-operator,old-octal-literal,import-star-module-level,raw-checker-failed,bad-inline-option,locally-disabled,locally-enabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,apply-builtin,basestring-builtin,buffer-builtin,cmp-builtin,coerce-builtin,execfile-builtin,file-builtin,long-builtin,raw_input-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,no-absolute-import,old-division,dict-iter-method,dict-view-method,next-method-called,metaclass-assignment,indexing-exception,raising-string,reload-builtin,oct-method,hex-method,nonzero-method,cmp-method,input-builtin,round-builtin,intern-builtin,unichr-builtin,map-builtin-not-iterating,zip-builtin-not-iterating,range-builtin-not-iterating,filter-builtin-not-iterating,using-cmp-argument,eq-without-hash,div-method,idiv-method,rdiv-method,exception-message-attribute,invalid-str-codec,sys-max-int,bad-python3-import,deprecated-string-function,deprecated-str-translate-call
disable=print-statement,parameter-unpacking,unpacking-in-except,old-raise-syntax,backtick,long-suffix,old-ne-operator,old-octal-literal,import-star-module-level,raw-checker-failed,bad-inline-option,locally-disabled,locally-enabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,apply-builtin,basestring-builtin,buffer-builtin,cmp-builtin,coerce-builtin,execfile-builtin,file-builtin,long-builtin,raw_input-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,no-absolute-import,old-division,dict-iter-method,dict-view-method,next-method-called,metaclass-assignment,indexing-exception,raising-string,reload-builtin,oct-method,hex-method,nonzero-method,cmp-method,input-builtin,round-builtin,intern-builtin,unichr-builtin,map-builtin-not-iterating,zip-builtin-not-iterating,range-builtin-not-iterating,filter-builtin-not-iterating,using-cmp-argument,eq-without-hash,div-method,idiv-method,rdiv-method,exception-message-attribute,invalid-str-codec,sys-max-int,bad-python3-import,deprecated-string-function,deprecated-str-translate-call,import-error,bad-continuation
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option
# multiple time (only on the command line, not in the configuration file where
# it should appear only once). See also the "--disable" option for examples.
enable=
[REPORTS]
# Python expression which should return a note less than 10 (10 is the highest
# note). You have access to the variables errors warning, statement which
# respectively contain the number of errors / warnings messages and the total
# number of statements analyzed. This is used by the global evaluation report
# (RP0004).
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
# Template used to display messages. This is a python new-style format string
# used to format the message information. See doc for all details
#msg-template=
# Set the output format. Available formats are text, parseable, colorized, json
# and msvs (visual studio).You can also give a reporter class, eg
# mypackage.mymodule.MyReporterClass.
output-format=text
# Tells whether to display a full report or only the messages
reports=no
# Activate the evaluation score.
score=yes
[REFACTORING]
# Maximum number of nested blocks for function / method body
max-nested-blocks=5
[LOGGING]
# Logging modules to check that the string format arguments are in logging
# function parameter format
logging-modules=logging
[SPELLING]
# Spelling dictionary name. Available dictionaries: none. To make it working
# install python-enchant package.
spelling-dict=
# List of comma separated words that should not be checked.
spelling-ignore-words=
# A path to a file that contains private dictionary; one word per line.
spelling-private-dict-file=
# Tells whether to store unknown words to indicated private dictionary in
# --spelling-private-dict-file option instead of raising a message.
spelling-store-unknown-words=no
[MISCELLANEOUS]
# List of note tags to take in consideration, separated by a comma.
# notes=FIXME,XXX,TODO
notes=FIXME,XXX
[TYPECHECK]
# List of decorators that produce context managers, such as
# contextlib.contextmanager. Add to this list to register other decorators that
# produce valid context managers.
contextmanager-decorators=contextlib.contextmanager
# List of members which are set dynamically and missed by pylint inference
# system, and so shouldn't trigger E1101 when accessed. Python regular
# expressions are accepted.
generated-members=
# Tells whether missing members accessed in mixin class should be ignored. A
# mixin class is detected if its name ends with "mixin" (case insensitive).
ignore-mixin-members=yes
# This flag controls whether pylint should warn about no-member and similar
# checks whenever an opaque object is returned when inferring. The inference
# can return multiple potential results while evaluating a Python object, but
# some branches might not be evaluated, which results in partial inference. In
# that case, it might be useful to still emit no-member and other checks for
# the rest of the inferred objects.
ignore-on-opaque-inference=yes
# List of class names for which member attributes should not be checked (useful
# for classes with dynamically set attributes). This supports the use of
# qualified names.
ignored-classes=optparse.Values,thread._local,_thread._local
# List of module names for which member attributes should not be checked
# (useful for modules/projects where namespaces are manipulated during runtime
# and thus existing member attributes cannot be deduced by static analysis. It
# supports qualified module names, as well as Unix pattern matching.
ignored-modules=board
# Show a hint with possible names when a member name was not found. The aspect
# of finding the hint is based on edit distance.
missing-member-hint=yes
# The minimum edit distance a name should have in order to be considered a
# similar match for a missing member name.
missing-member-hint-distance=1
# The total number of similar names that should be taken in consideration when
# showing a hint for a missing member.
missing-member-max-choices=1
[VARIABLES]
# List of additional names supposed to be defined in builtins. Remember that
# you should avoid to define new builtins when possible.
additional-builtins=
# Tells whether unused global variables should be treated as a violation.
allow-global-unused-variables=yes
# List of strings which can identify a callback function by name. A callback
# name must start or end with one of those strings.
callbacks=cb_,_cb
# A regular expression matching the name of dummy variables (i.e. expectedly
# not used).
dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
# Argument names that match this expression will be ignored. Default to name
# with leading underscore
ignored-argument-names=_.*|^ignored_|^unused_
# Tells whether we should check for unused import in __init__ files.
init-import=no
# List of qualified module names which can have objects that can redefine
# builtins.
redefining-builtins-modules=six.moves,future.builtins
[FORMAT]
# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
# expected-line-ending-format=
expected-line-ending-format=LF
# Regexp for a line that is allowed to be longer than the limit.
ignore-long-lines=^\s*(# )?<?https?://\S+>?$
# Number of spaces of indent required inside a hanging or continued line.
indent-after-paren=4
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
# tab).
indent-string=' '
# Maximum number of characters on a single line.
max-line-length=100
# Maximum number of lines in a module
max-module-lines=1000
# List of optional constructs for which whitespace checking is disabled. `dict-
# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}.
# `trailing-comma` allows a space between comma and closing bracket: (a, ).
# `empty-line` allows space-only lines.
no-space-check=trailing-comma,dict-separator
# Allow the body of a class to be on the same line as the declaration if body
# contains single statement.
single-line-class-stmt=no
# Allow the body of an if to be on the same line as the test if there is no
# else.
single-line-if-stmt=no
[SIMILARITIES]
# Ignore comments when computing similarities.
ignore-comments=yes
# Ignore docstrings when computing similarities.
ignore-docstrings=yes
# Ignore imports when computing similarities.
ignore-imports=yes
# Minimum lines number of a similarity.
min-similarity-lines=4
[BASIC]
# Naming hint for argument names
argument-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
# Regular expression matching correct argument names
argument-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
# Naming hint for attribute names
attr-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
# Regular expression matching correct attribute names
attr-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
# Bad variable names which should always be refused, separated by a comma
bad-names=foo,bar,baz,toto,tutu,tata
# Naming hint for class attribute names
class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
# Regular expression matching correct class attribute names
class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
# Naming hint for class names
# class-name-hint=[A-Z_][a-zA-Z0-9]+$
class-name-hint=[A-Z_][a-zA-Z0-9_]+$
# Regular expression matching correct class names
# class-rgx=[A-Z_][a-zA-Z0-9]+$
class-rgx=[A-Z_][a-zA-Z0-9_]+$
# Naming hint for constant names
const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$
# Regular expression matching correct constant names
const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$
# Minimum line length for functions/classes that require docstrings, shorter
# ones are exempt.
docstring-min-length=-1
# Naming hint for function names
function-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
# Regular expression matching correct function names
function-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
# Good variable names which should always be accepted, separated by a comma
# good-names=i,j,k,ex,Run,_
good-names=r,g,b,w,i,j,k,n,x,y,z,ex,ok,Run,_
# Include a hint for the correct naming format with invalid-name
include-naming-hint=no
# Naming hint for inline iteration names
inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$
# Regular expression matching correct inline iteration names
inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
# Naming hint for method names
method-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
# Regular expression matching correct method names
method-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
# Naming hint for module names
module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
# Regular expression matching correct module names
module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
# Colon-delimited sets of names that determine each other's naming style when
# the name regexes allow several styles.
name-group=
# Regular expression which should only match function or class names that do
# not require a docstring.
no-docstring-rgx=^_
# List of decorators that produce properties, such as abc.abstractproperty. Add
# to this list to register other decorators that produce valid properties.
property-classes=abc.abstractproperty
# Naming hint for variable names
variable-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
# Regular expression matching correct variable names
variable-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
[IMPORTS]
# Allow wildcard imports from modules that define __all__.
allow-wildcard-with-all=no
# Analyse import fallback blocks. This can be used to support both Python 2 and
# 3 compatible code, which means that the block might have code that exists
# only in one or another interpreter, leading to false positives when analysed.
analyse-fallback-blocks=no
# Deprecated modules which should not be used, separated by a comma
deprecated-modules=optparse,tkinter.tix
# Create a graph of external dependencies in the given file (report RP0402 must
# not be disabled)
ext-import-graph=
# Create a graph of every (i.e. internal and external) dependencies in the
# given file (report RP0402 must not be disabled)
import-graph=
# Create a graph of internal dependencies in the given file (report RP0402 must
# not be disabled)
int-import-graph=
# Force import order to recognize a module as part of the standard
# compatibility libraries.
known-standard-library=
# Force import order to recognize a module as part of a third party library.
known-third-party=enchant
[CLASSES]
# List of method names used to declare (i.e. assign) instance attributes.
defining-attr-methods=__init__,__new__,setUp
# List of member names, which should be excluded from the protected access
# warning.
exclude-protected=_asdict,_fields,_replace,_source,_make
# List of valid names for the first argument in a class method.
valid-classmethod-first-arg=cls
# List of valid names for the first argument in a metaclass class method.
valid-metaclass-classmethod-first-arg=mcs
[DESIGN]
# Maximum number of arguments for function / method
max-args=5
# Maximum number of attributes for a class (see R0902).
# max-attributes=7
max-attributes=11
# Maximum number of boolean expressions in a if statement
max-bool-expr=5
# Maximum number of branch for function / method body
max-branches=12
# Maximum number of locals for function / method body
max-locals=15
# Maximum number of parents for a class (see R0901).
max-parents=7
# Maximum number of public methods for a class (see R0904).
max-public-methods=20
# Maximum number of return / yield for function / method body
max-returns=6
# Maximum number of statements in function / method body
max-statements=50
# Minimum number of public methods for a class (see R0903).
min-public-methods=1
[EXCEPTIONS]
# Exceptions that will emit a warning when being caught. Defaults to
# "Exception"
overgeneral-exceptions=Exception

22
.readthedocs.yaml Normal file
View file

@ -0,0 +1,22 @@
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
#
# SPDX-License-Identifier: Unlicense
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
# Required
version: 2
sphinx:
configuration: docs/conf.py
build:
os: ubuntu-lts-latest
tools:
python: "3"
python:
install:
- requirements: docs/requirements.txt
- requirements: requirements.txt

View file

@ -1,7 +0,0 @@
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
#
# SPDX-License-Identifier: Unlicense
python:
version: 3
requirements_file: docs/requirements.txt

View file

@ -2,10 +2,10 @@ Introduction
============
.. image:: https://readthedocs.org/projects/adafruit-circuitpython-turtle/badge/?version=latest
:target: https://circuitpython.readthedocs.io/projects/turtle/en/latest/
:target: https://docs.circuitpython.org/projects/turtle/en/latest/
:alt: Documentation Status
.. image:: https://img.shields.io/discord/327254708534116352.svg
.. image:: https://raw.githubusercontent.com/adafruit/Adafruit_CircuitPython_Bundle/main/badges/adafruit_discord.svg
:target: https://adafru.it/discord
:alt: Discord
@ -13,6 +13,10 @@ Introduction
:target: https://github.com/adafruit/Adafruit_CircuitPython_turtle/actions/
:alt: Build Status
.. image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json
:target: https://github.com/astral-sh/ruff
:alt: Code Style: Ruff
Turtle graphics library for CircuitPython and displayio
@ -48,8 +52,8 @@ To install in a virtual environment in your current project:
.. code-block:: shell
mkdir project-name && cd project-name
python3 -m venv .env
source .env/bin/activate
python3 -m venv .venv
source .venv/bin/activate
pip3 install adafruit-circuitpython-turtle
Usage Example
@ -84,7 +88,9 @@ Usage Example
Documentation
=============
API documentation for this library can be found on `Read the Docs <https://circuitpython.readthedocs.io/projects/turtle/en/latest/>`_.
API documentation for this library can be found on `Read the Docs <https://docs.circuitpython.org/projects/turtle/en/latest/>`_.
For information on building library documentation, please check out `this guide <https://learn.adafruit.com/creating-and-sharing-a-circuitpython-library/sharing-our-docs-on-readthedocs#sphinx-5-1>`_.
Contributing
============
@ -92,8 +98,3 @@ Contributing
Contributions are welcome! Please read our `Code of Conduct
<https://github.com/adafruit/Adafruit_CircuitPython_turtle/blob/main/CODE_OF_CONDUCT.md>`_
before contributing to help this project stay welcoming.
Documentation
=============
For information on building library documentation, please check out `this guide <https://learn.adafruit.com/creating-and-sharing-a-circuitpython-library/sharing-our-docs-on-readthedocs#sphinx-5-1>`_.

View file

@ -24,16 +24,24 @@ Implementation Notes
https://github.com/adafruit/Adafruit_CircuitPython_BusDevice
"""
from __future__ import annotations
# pylint:disable=too-many-public-methods, too-many-instance-attributes, invalid-name
# pylint:disable=too-few-public-methods, too-many-lines, too-many-arguments
import gc
import math
import time
import board
import displayio
__version__ = "0.0.0-auto.0"
try:
from typing import List, Optional, Tuple, Union
import busdisplay
except ImportError:
pass
__version__ = "0.0.0+auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_turtle.git"
@ -41,21 +49,84 @@ class Color:
"""Standard colors"""
WHITE = 0xFFFFFF
"""0xFFFFFF
:meta hide-value:"""
BLACK = 0x000000
"""0x000000
:meta hide-value:"""
RED = 0xFF0000
"""0xFF0000
:meta hide-value:"""
ORANGE = 0xFFA500
"""0xFFA500
:meta hide-value:"""
YELLOW = 0xFFEE00
"""0xFFEE00
:meta hide-value:"""
GREEN = 0x00C000
"""0x00C000
:meta hide-value:"""
BLUE = 0x0000FF
"""0x0000FF
:meta hide-value:"""
PURPLE = 0x8040C0
"""0x8040C0
:meta hide-value:"""
PINK = 0xFF40C0
"""0xFF40C0
:meta hide-value:"""
LIGHT_GRAY = 0xAAAAAA
"""0xAAAAAA
:meta hide-value:"""
GRAY = 0x444444
"""0x444444
:meta hide-value:"""
BROWN = 0xCA801D
"""0xCA801D
:meta hide-value:"""
DARK_GREEN = 0x008700
"""0x008700
:meta hide-value:"""
TURQUOISE = 0x00C0C0
"""0x00C0C0
:meta hide-value:"""
DARK_BLUE = 0x0000AA
"""0x0000AA
:meta hide-value:"""
DARK_RED = 0x800000
"""0x800000
:meta hide-value:"""
colors = (
BLACK,
@ -76,11 +147,11 @@ class Color:
DARK_RED,
)
def __init__(self):
def __init__(self) -> None:
pass
class Vec2D(tuple):
class Vec2D:
"""A 2 dimensional vector class, used as a helper class
for implementing turtle graphics.
May be useful for turtle graphics programs also.
@ -94,32 +165,35 @@ class Vec2D(tuple):
# k*a and a*k multiplication with scalar
# |a| absolute value of a
# a.rotate(angle) rotation
def __init__(self, x, y):
super().__init__((x, y))
def __init__(self, x: float, y: float) -> None:
self.values = (x, y)
def __add__(self, other):
def __getitem__(self, index: int) -> float:
return self.values[index]
def __add__(self, other: Vec2D) -> Vec2D:
return Vec2D(self[0] + other[0], self[1] + other[1])
def __mul__(self, other):
def __mul__(self, other: Union[float, Vec2D]) -> Union[float, Vec2D]:
if isinstance(other, Vec2D):
return self[0] * other[0] + self[1] * other[1]
return Vec2D(self[0] * other, self[1] * other)
def __rmul__(self, other):
def __rmul__(self, other: float) -> Optional[Vec2D]:
if isinstance(other, (float, int)):
return Vec2D(self[0] * other, self[1] * other)
return None
def __sub__(self, other):
def __sub__(self, other: Vec2D) -> Vec2D:
return Vec2D(self[0] - other[0], self[1] - other[1])
def __neg__(self):
def __neg__(self) -> Vec2D:
return Vec2D(-self[0], -self[1])
def __abs__(self):
def __abs__(self) -> float:
return (self[0] ** 2 + self[1] ** 2) ** 0.5
def rotate(self, angle):
def rotate(self, angle: float) -> Vec2D:
"""Rotate self counterclockwise by angle.
:param angle: how much to rotate
@ -130,44 +204,42 @@ class Vec2D(tuple):
c, s = math.cos(angle), math.sin(angle)
return Vec2D(self[0] * c + perp[0] * s, self[1] * c + perp[1] * s)
def __getnewargs__(self):
def __getnewargs__(self) -> Tuple[float, float]:
return (self[0], self[1])
def __repr__(self):
return "({:.2f},{:.2f})".format(self[0], self[1])
def __repr__(self) -> str:
return f"({self[0]:.2f},{self[1]:.2f})"
class turtle:
"""A Turtle that can be given commands to draw."""
# pylint:disable=too-many-statements
def __init__(self, display=None, scale=1):
def __init__(self, display: Optional[busdisplay.BusDisplay] = None, scale: float = 1) -> None:
if display:
self._display = display
else:
try:
import board
self._display = board.DISPLAY
except AttributeError as err:
raise RuntimeError(
"No display available. One must be provided."
) from err
raise RuntimeError("No display available. One must be provided.") from err
self._w = self._display.width
self._h = self._display.height
self._w: int = self._display.width
self._h: int = self._display.height
self._x = self._w // (2 * scale)
self._y = self._h // (2 * scale)
self._speed = 6
self._heading = 0
self._logomode = True
self._heading: float = 0
self._fullcircle = 360.0
self._degreesPerAU = 1.0
self._angleOrient = 1
self._angleOffset = 0
self._logomode = False
self._angleOrient = -1
self._angleOffset: float = self._fullcircle / 4
self._bg_color = 0
self._splash = displayio.Group()
self._bgscale = 1
self._splash: displayio.Group = displayio.Group()
self._bgscale: int = 1
if self._w == self._h:
i = 1
while self._bgscale == 1:
@ -191,7 +263,7 @@ class turtle:
# group to add background pictures (and/or user-defined stuff)
self._bg_addon_group = displayio.Group()
self._splash.append(self._bg_addon_group)
self._fg_scale = scale
self._fg_scale: int = int(scale)
self._w = self._w // self._fg_scale
self._h = self._h // self._fg_scale
self._fg_bitmap = displayio.Bitmap(self._w, self._h, len(Color.colors))
@ -236,47 +308,46 @@ class turtle:
self._turtle_pic = None
self._turtle_odb = None
self._turtle_alt_sprite = None
self._turtle_x = self._x
self._turtle_y = self._y
self._drawturtle()
self._stamps = {}
self._turtle_odb_use = 0
self._turtle_odb_file = None
self._odb_tilegrid = None
gc.collect()
self._display.show(self._splash)
self._display.root_group = self._splash
# pylint:enable=too-many-statements
def _drawturtle(self):
def _drawturtle(self) -> None:
if self._turtle_pic is None:
self._turtle_sprite.x = int(self._x - 4)
self._turtle_sprite.y = int(self._y - 4)
self._turtle_sprite.x = int(self._turtle_x - 4)
self._turtle_sprite.y = int(self._turtle_y - 4)
elif self._turtle_odb is not None:
self._turtle_alt_sprite.x = int(self._turtle_x - self._turtle_odb.width // 2)
self._turtle_alt_sprite.y = int(self._turtle_y - self._turtle_odb.height // 2)
else:
if self._turtle_odb is not None:
self._turtle_alt_sprite.x = int(self._x - self._turtle_odb.width // 2)
self._turtle_alt_sprite.y = int(self._y - self._turtle_odb.height // 2)
else:
self._turtle_alt_sprite.x = int(self._x - self._turtle_pic[0] // 2)
self._turtle_alt_sprite.y = int(self._y - self._turtle_pic[1] // 2)
self._turtle_alt_sprite.x = int(self._turtle_x - self._turtle_pic[0] // 2)
self._turtle_alt_sprite.y = int(self._turtle_y - self._turtle_pic[1] // 2)
###########################################################################
# Move and draw
def forward(self, distance):
def forward(self, distance: float) -> None:
"""Move the turtle forward by the specified distance, in the direction the turtle is headed.
:param distance: how far to move (integer or float)
"""
p = self.pos()
angle = (
self._angleOffset + self._angleOrient * self._heading
) % self._fullcircle
angle = (self._angleOffset + self._angleOrient * self._heading) % self._fullcircle
x1 = p[0] + math.sin(math.radians(angle)) * distance
y1 = p[1] + math.cos(math.radians(angle)) * distance
self.goto(x1, y1)
fd = forward
def backward(self, distance):
def backward(self, distance: float) -> None:
"""Move the turtle backward by distance, opposite to the direction the turtle is headed.
Does not change the turtle's heading.
@ -288,7 +359,7 @@ class turtle:
bk = backward
back = backward
def right(self, angle):
def right(self, angle: float) -> None:
"""Turn turtle right by angle units. (Units are by default degrees,
but can be set via the degrees() and radians() functions.)
Angle orientation depends on the turtle mode, see mode().
@ -302,7 +373,7 @@ class turtle:
rt = right
def left(self, angle):
def left(self, angle: float) -> None:
"""Turn turtle left by angle units. (Units are by default degrees,
but can be set via the degrees() and radians() functions.)
Angle orientation depends on the turtle mode, see mode().
@ -317,7 +388,9 @@ class turtle:
lt = left
# pylint:disable=too-many-branches,too-many-statements
def goto(self, x1, y1=None):
def goto(
self, x1: Union[float, Vec2D, Tuple[float, float]], y1: Optional[float] = None
) -> None:
"""If y1 is None, x1 must be a pair of coordinates or an (x, y) tuple
Move turtle to an absolute position. If the pen is down, draw line.
@ -326,35 +399,38 @@ class turtle:
:param x1: a number or a pair of numbers
:param y1: a number or None
"""
if y1 is None:
y1 = x1[1]
x1 = x1[0]
x1 += self._w // 2
y1 = self._h // 2 - y1
x0 = self._x
y0 = self._y
yn: float = x1[1] if y1 is None else y1 # type: ignore
xn: float = x1[0] if y1 is None else x1 # type: ignore
xn += self._w // 2
yn = self._h // 2 - yn
if not self.isdown():
self._x = x1 # woot, we just skip ahead
self._y = y1
self._x = xn # woot, we just skip ahead
self._y = yn
self._drawturtle()
return
steep = abs(y1 - y0) > abs(x1 - x0)
self._do_draw_line(round(self._x), round(self._y), round(xn), round(yn))
self._x = xn
self._y = yn
def _do_draw_line(self, x0: int, y0: int, xn: int, yn: int):
steep = abs(yn - y0) > abs(xn - x0)
rev = False
dx = x1 - x0
dx = xn - x0
if steep:
x0, y0 = y0, x0
x1, y1 = y1, x1
dx = x1 - x0
xn, yn = yn, xn
dx = xn - x0
if x0 > x1:
if x0 > xn:
rev = True
dx = x0 - x1
dx = x0 - xn
dy = abs(y1 - y0)
dy = abs(yn - y0)
err = dx / 2
ystep = -1
if y0 < y1:
if y0 < yn:
ystep = 1
step = 1
if self._speed > 0:
@ -362,21 +438,21 @@ class turtle:
else:
ts = 0
while (not rev and x0 <= x1) or (rev and x1 <= x0):
while (not rev and x0 <= xn) or (rev and xn <= x0):
if steep:
try:
self._plot(int(y0), int(x0), self._pencolor)
except IndexError:
pass
self._x = y0
self._y = x0
self._turtle_x = y0
self._turtle_y = x0
else:
try:
self._plot(int(x0), int(y0), self._pencolor)
except IndexError:
pass
self._x = x0
self._y = y0
self._turtle_x = x0
self._turtle_y = y0
if self._speed > 0:
if step >= self._speed:
# mark the step
@ -397,9 +473,10 @@ class turtle:
setpos = goto
setposition = goto
# pylint:enable=too-many-branches,too-many-statements
def setx(self, x):
def setx(self, x: float) -> None:
"""Set the turtle's first coordinate to x, leave second coordinate
unchanged.
@ -408,7 +485,7 @@ class turtle:
"""
self.goto(x, self.pos()[1])
def sety(self, y):
def sety(self, y: float) -> None:
"""Set the turtle's second coordinate to y, leave first coordinate
unchanged.
@ -417,7 +494,7 @@ class turtle:
"""
self.goto(self.pos()[0], y)
def setheading(self, to_angle):
def setheading(self, to_angle: float) -> None:
"""Set the orientation of the turtle to to_angle. Here are some common
directions in degrees:
@ -437,7 +514,7 @@ class turtle:
seth = setheading
def home(self):
def home(self) -> None:
"""Move turtle to the origin - coordinates (0,0) - and set its heading
to its start-orientation
(which depends on the mode, see mode()).
@ -446,7 +523,7 @@ class turtle:
self.goto(0, 0)
# pylint:disable=too-many-locals, too-many-statements, too-many-branches
def _plot(self, x, y, c):
def _plot(self, x: float, y: float, c: int) -> None:
if self._pensize == 1:
try:
self._fg_bitmap[int(x), int(y)] = c
@ -454,9 +531,7 @@ class turtle:
except IndexError:
pass
r = self._pensize // 2 + 1
angle = (
self._angleOffset + self._angleOrient * self._heading - 90
) % self._fullcircle
angle = (self._angleOffset + self._angleOrient * self._heading - 90) % self._fullcircle
sin = math.sin(math.radians(angle))
cos = math.cos(math.radians(angle))
x0 = x + sin * r
@ -526,7 +601,9 @@ class turtle:
# pylint:enable=too-many-locals, too-many-statements, too-many-branches
def circle(self, radius, extent=None, steps=None):
def circle(
self, radius: float, extent: Optional[float] = None, steps: Optional[int] = None
) -> None:
"""Draw a circle with given radius. The center is radius units left of
the turtle; extent - an angle - determines which part of the circle is
drawn. If extent is not given, draw the entire circle. If extent is not
@ -547,6 +624,12 @@ class turtle:
# --or: circle(radius, extent) # arc
# --or: circle(radius, extent, steps)
# --or: circle(radius, steps=6) # 6-sided polygon
change_back = False
if not self._in_degrees():
change_back = True
original_mode = "standard" if not self._logomode else "logo"
self.degrees()
self.mode("standard")
pos = self.pos()
h = self._heading
if extent is None:
@ -568,11 +651,13 @@ class turtle:
# get back to exact same position and heading
self.goto(pos)
self.setheading(h)
if change_back:
self.radians()
self.mode(original_mode)
# pylint:disable=inconsistent-return-statements
def speed(self, speed=None):
def speed(self, speed: Optional[int] = None) -> Optional[int]:
"""
Set the turtle's speed to an integer value in the range 0..10. If no
argument is given, return current speed.
@ -599,10 +684,11 @@ class turtle:
self._speed = 0
else:
self._speed = speed
return None
# pylint:enable=inconsistent-return-statements
def dot(self, size=None, color=None):
def dot(self, size: Optional[int] = None, color: Optional[int] = None) -> None:
"""Draw a circular dot with diameter size, using color.
If size is not given, the maximum of pensize+4 and
2*pensize is used.
@ -611,6 +697,13 @@ class turtle:
:param color: the color of the dot
"""
change_back = False
if not self._in_degrees():
change_back = True
original_mode = "standard" if not self._logomode else "logo"
print(f"old mode: {original_mode}")
self.degrees()
self.mode("standard")
if size is None:
size = max(self._pensize + 4, self._pensize * 2)
if color is None:
@ -634,16 +727,20 @@ class turtle:
self._pensize = 1
self._plot(self._x, self._y, color)
self._pensize = pensize
if change_back:
self.radians()
self.mode(original_mode)
def stamp(self, bitmap=None, palette=None):
def stamp(
self,
bitmap: Optional[displayio.Bitmap] = None,
palette: Optional[displayio.Palette] = None,
) -> int:
"""
Stamp a copy of the turtle shape onto the canvas at the current
turtle position. Return a stamp_id for that stamp, which can be used to
delete it by calling clearstamp(stamp_id).
"""
if len(self._fg_addon_group) >= 6:
print("Addon group full")
return -1
s_id = len(self._stamps)
if self._turtle_pic is None:
# easy.
@ -657,7 +754,7 @@ class turtle:
# odb bitmap
new_stamp = displayio.TileGrid(
self._turtle_odb,
pixel_shader=displayio.ColorConverter(),
pixel_shader=self._turtle_odb.pixel_shader,
x=int(self._x - self._turtle_odb.width // 2),
y=int(self._y - self._turtle_odb.height // 2),
)
@ -681,7 +778,7 @@ class turtle:
return s_id
def clearstamp(self, stampid):
def clearstamp(self, stampid: int) -> None:
"""
Delete stamp with given stampid.
@ -694,8 +791,7 @@ class turtle:
if isinstance(self._stamps[stampid], tuple):
self._fg_addon_group.remove(self._stamps[stampid][0])
self._turtle_odb_use -= 1
if self._turtle_odb_use == 0:
self._stamps[stampid][1].close()
else:
self._fg_addon_group.remove(self._stamps[stampid])
self._stamps[stampid] = None
@ -704,9 +800,8 @@ class turtle:
else:
raise TypeError("Stamp id must be an int")
def clearstamps(self, n=None):
def clearstamps(self, n: Optional[int] = None) -> None:
"""
Delete all or first/last n of turtle's stamps. If n is None, delete
all stamps, if n > 0 delete first n stamps, else if n < 0 delete last
n stamps.
@ -715,7 +810,7 @@ class turtle:
"""
i = 1
for sid in self._stamps: # pylint: disable=consider-using-dict-items
for sid in self._stamps:
if self._stamps[sid] is not None:
self.clearstamp(sid)
if n is not None and i >= n:
@ -725,13 +820,15 @@ class turtle:
###########################################################################
# Tell turtle's state
def pos(self):
def pos(self) -> Vec2D:
"""Return the turtle's current location (x,y) (as a Vec2D vector)."""
return Vec2D(self._x - self._w // 2, self._h // 2 - self._y)
position = pos
def towards(self, x1, y1=None):
def towards(
self, x1: Union[float, Vec2D, Tuple[float, float]], y1: Optional[float] = None
) -> float:
"""
Return the angle between the line from turtle position to position
specified by (x,y) or the vector. This depends on the turtle's start
@ -750,21 +847,23 @@ class turtle:
result /= self._degreesPerAU
return (self._angleOffset + self._angleOrient * result) % self._fullcircle
def xcor(self):
def xcor(self) -> float:
"""Return the turtle's x coordinate."""
return self._x - self._w // 2
def ycor(self):
def ycor(self) -> float:
"""Return the turtle's y coordinate."""
return self._h // 2 - self._y
def heading(self):
def heading(self) -> float:
"""Return the turtle's current heading (value depends on the turtle
mode, see mode()).
"""
return self._heading
def distance(self, x1, y1=None):
def distance(
self, x1: Union[float, List[float], Tuple[float, float]], y1: Optional[float]
) -> float:
"""
Return the distance from the turtle to (x,y) or the vector, in turtle
step units.
@ -773,16 +872,16 @@ class turtle:
:param y: a number if x is a number, else None
"""
if y1 is None:
y1 = x1[1]
x1 = x1[0]
x0, y0 = self.pos()
return math.sqrt((x0 - x1) ** 2 + (y0 - y1) ** 2)
yn: float = x1[1] if y1 is None else y1 # type: ignore
xn: float = x1[0] if y1 is None else x1 # type: ignore
p = self.pos()
x0, y0 = (p[0], p[1])
return math.sqrt((x0 - xn) ** 2 + (y0 - yn) ** 2)
###########################################################################
# Setting and measurement
def _setDegreesPerAU(self, fullcircle):
def _setDegreesPerAU(self, fullcircle: float) -> None:
"""Helper function for degrees() and radians()"""
self._fullcircle = fullcircle
self._degreesPerAU = 360 / fullcircle
@ -791,7 +890,7 @@ class turtle:
else:
self._angleOffset = -fullcircle / 4
def degrees(self, fullcircle=360):
def degrees(self, fullcircle: float = 360) -> None:
"""Set angle measurement units, i.e. set number of "degrees" for
a full circle.
Default value is 360 degrees.
@ -800,12 +899,16 @@ class turtle:
"""
self._setDegreesPerAU(fullcircle)
def radians(self):
def _in_degrees(self) -> bool:
print(self._degreesPerAU)
return self._degreesPerAU == 1.0
def radians(self) -> None:
"""Set the angle measurement units to radians.
Equivalent to degrees(2*math.pi)."""
self._setDegreesPerAU(2 * math.pi)
def mode(self, mode=None):
def mode(self, mode: Optional[str] = None) -> Optional[str]:
"""
Set turtle mode ("standard" or "logo") and perform reset.
@ -832,12 +935,12 @@ class turtle:
raise RuntimeError("Mode must be 'logo', 'standard', or None")
return None
def window_height(self):
def window_height(self) -> float:
"""
Return the height of the turtle window."""
return self._h
def window_width(self):
def window_width(self) -> float:
"""
Return the width of the turtle window."""
return self._w
@ -845,25 +948,25 @@ class turtle:
###########################################################################
# Drawing state
def pendown(self):
def pendown(self) -> None:
"""Pull the pen down - drawing when moving."""
self._penstate = True
pd = pendown
down = pendown
def penup(self):
def penup(self) -> None:
"""Pull the pen up - no drawing when moving."""
self._penstate = False
pu = penup
up = penup
def isdown(self):
def isdown(self) -> bool:
"""Return True if pen is down, False if it's up."""
return self._penstate
def pensize(self, width=None):
def pensize(self, width: Optional[int] = None) -> int:
"""
Set the line thickness to width or return it.
If no argument is given, the current pensize is returned.
@ -882,12 +985,12 @@ class turtle:
# pylint:disable=no-self-use
def _color_to_pencolor(self, c):
def _color_to_pencolor(self, c: int) -> int:
return Color.colors.index(c)
# pylint:enable=no-self-use
def pencolor(self, c=None):
def pencolor(self, c: Optional[int] = None) -> int:
"""
Return or set the pencolor.
@ -915,7 +1018,7 @@ class turtle:
self._turtle_palette.make_opaque(1)
return c
def bgcolor(self, c=None):
def bgcolor(self, c: Optional[int] = None) -> int:
"""
Return or set the background color.
@ -949,7 +1052,7 @@ class turtle:
return Color.colors[self._bg_color]
# pylint:disable=inconsistent-return-statements
def bgpic(self, picname=None):
def bgpic(self, picname: Optional[str] = None) -> Optional[str]:
"""Set background image or return name of current backgroundimage.
Optional argument:
picname -- a string, name of an image file or "nopic".
@ -963,27 +1066,28 @@ class turtle:
if self._bg_pic is not None:
self._bg_addon_group.remove(self._odb_tilegrid)
self._odb_tilegrid = None
self._bg_pic.close()
self._bg_pic = None
self._bg_pic_filename = ""
else:
with open(picname, "rb") as self._bg_pic:
odb = displayio.OnDiskBitmap(self._bg_pic)
odb = displayio.OnDiskBitmap(picname)
self._odb_tilegrid = displayio.TileGrid(
odb, pixel_shader=displayio.ColorConverter()
odb,
pixel_shader=odb.pixel_shader,
)
self._bg_addon_group.append(self._odb_tilegrid)
self._bg_pic_filename = picname
# centered
self._odb_tilegrid.y = ((self._h * self._fg_scale) // 2) - (odb.height // 2)
self._odb_tilegrid.x = ((self._w * self._fg_scale) // 2) - (odb.width // 2)
return None
# pylint:enable=inconsistent-return-statements
###########################################################################
# More drawing control
def reset(self):
def reset(self) -> None:
"""
Delete the turtle's drawings from the screen, re-center the turtle
and set variables to the default values."""
@ -997,7 +1101,7 @@ class turtle:
self.pensize(1)
self.pencolor(Color.WHITE)
def clear(self):
def clear(self) -> None:
"""Delete the turtle's drawings from the screen. Do not move turtle."""
self.clearstamps()
for w in range(self._w):
@ -1012,7 +1116,7 @@ class turtle:
###########################################################################
# Visibility
def showturtle(self):
def showturtle(self) -> None:
"""
Make the turtle visible."""
if self._turtle_group:
@ -1024,7 +1128,7 @@ class turtle:
st = showturtle
def hideturtle(self):
def hideturtle(self) -> None:
"""
Make the turtle invisible."""
if not self._turtle_group:
@ -1033,7 +1137,7 @@ class turtle:
ht = hideturtle
def isvisible(self):
def isvisible(self) -> bool:
"""
Return True if the Turtle is shown, False if it's hidden."""
if self._turtle_group:
@ -1041,7 +1145,11 @@ class turtle:
return False
# pylint:disable=too-many-statements, too-many-branches
def changeturtle(self, source=None, dimensions=(12, 12)):
def changeturtle(
self,
source: Optional[Union[displayio.TileGrid, str]] = None,
dimensions: Tuple[int, int] = (12, 12),
) -> None:
"""
Change the turtle.
if a string is provided, its a path to an image opened via OnDiskBitmap
@ -1059,8 +1167,6 @@ class turtle:
self._turtle_odb_use -= 1
self._turtle_odb = None
if self._turtle_odb_file is not None:
if self._turtle_odb_use == 0:
self._turtle_odb_file.close()
self._turtle_odb_file = None
self._turtle_pic = None
self._drawturtle()
@ -1073,17 +1179,13 @@ class turtle:
self._turtle_alt_sprite = None
self._turtle_odb = None
if not isinstance(self._turtle_pic, tuple):
self._turtle_odb_file.close()
self._turtle_odb_file = None
self._turtle_odb_use -= 1
self._turtle_pic = None
self._turtle_odb_file = open( # pylint: disable=consider-using-with
source, "rb"
)
try:
self._turtle_odb = displayio.OnDiskBitmap(self._turtle_odb_file)
self._turtle_odb = displayio.OnDiskBitmap(source)
except:
self._turtle_odb_file.close()
self._turtle_odb_file = None
self._turtle_pic = None
if visible:
@ -1092,7 +1194,8 @@ class turtle:
self._turtle_odb_use += 1
self._turtle_pic = True
self._turtle_alt_sprite = displayio.TileGrid(
self._turtle_odb, pixel_shader=displayio.ColorConverter()
self._turtle_odb,
pixel_shader=self._turtle_odb.pixel_shader,
)
if self._turtle_group:
@ -1104,8 +1207,6 @@ class turtle:
if self._turtle_pic is not None:
if self._turtle_odb_file is not None:
self._turtle_odb_use -= 1
if self._turtle_odb_use == 0:
self._turtle_odb_file.close()
self._turtle_pic = dimensions
self._turtle_alt_sprite = source
if self._turtle_group:
@ -1113,16 +1214,14 @@ class turtle:
self._turtle_group.append(self._turtle_alt_sprite)
self._drawturtle()
else:
raise TypeError(
'Argument must be "str", a "displayio.TileGrid" or nothing.'
)
raise TypeError('Argument must be "str", a "displayio.TileGrid" or nothing.')
# pylint:enable=too-many-statements, too-many-branches
###########################################################################
# Other
def _turn(self, angle):
def _turn(self, angle: float) -> None:
if angle % self._fullcircle == 0:
return
if not self.isdown() or self._pensize == 1:
@ -1130,9 +1229,7 @@ class turtle:
self._heading %= self._fullcircle # wrap
return
start_angle = self._heading
steps = math.ceil(
(self._pensize * 2) * 3.1415 * (abs(angle) / self._fullcircle)
)
steps = math.ceil((self._pensize * 2) * 3.1415 * (abs(angle) / self._fullcircle))
if steps < 1:
d_angle = angle
steps = 1
@ -1153,7 +1250,7 @@ class turtle:
return
if abs(angle - steps * d_angle) >= abs(d_angle):
steps += abs(angle - steps * d_angle) // abs(d_angle)
steps += int(abs(angle - steps * d_angle) // abs(d_angle))
self._plot(self._x, self._y, self._pencolor)
for _ in range(steps):
@ -1167,7 +1264,7 @@ class turtle:
self._heading %= self._fullcircle
self._plot(self._x, self._y, self._pencolor)
def _GCD(self, a, b):
def _GCD(self, a: int, b: int) -> int:
"""GCD(a,b):
recursive 'Greatest common divisor' calculus for int numbers a and b"""
if b == 0:

View file

@ -4,5 +4,8 @@
.. If your library file(s) are nested in a directory (e.g. /adafruit_foo/foo.py)
.. use this format as the module name: "adafruit_foo.foo"
API Reference
#############
.. automodule:: adafruit_turtle
:members:

View file

@ -1,9 +1,8 @@
# -*- coding: utf-8 -*-
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
#
# SPDX-License-Identifier: MIT
import datetime
import os
import sys
@ -16,6 +15,7 @@ sys.path.insert(0, os.path.abspath(".."))
# ones.
extensions = [
"sphinx.ext.autodoc",
"sphinxcontrib.jquery",
"sphinx.ext.intersphinx",
"sphinx.ext.napoleon",
"sphinx.ext.todo",
@ -37,7 +37,6 @@ autodoc_mock_imports = [
"adafruit_bitmap_font",
"adafruit_display_text",
"adafruit_esp32spi",
"secrets",
"adafruit_sdcard",
"storage",
"adafruit_io",
@ -48,12 +47,12 @@ autodoc_mock_imports = [
intersphinx_mapping = {
"python": ("https://docs.python.org/3.4", None),
"python": ("https://docs.python.org/3", None),
"BusDevice": (
"https://circuitpython.readthedocs.io/projects/busdevice/en/latest/",
"https://docs.circuitpython.org/projects/busdevice/en/latest/",
None,
),
"CircuitPython": ("https://circuitpython.readthedocs.io/en/latest/", None),
"CircuitPython": ("https://docs.circuitpython.org/en/latest/", None),
}
# Add any paths that contain templates here, relative to this directory.
@ -66,7 +65,12 @@ master_doc = "index"
# General information about the project.
project = "Adafruit turtle Library"
copyright = "2019 Adafruit"
creation_year = "2019"
current_year = str(datetime.datetime.now().year)
year_duration = (
current_year if current_year == creation_year else creation_year + " - " + current_year
)
copyright = year_duration + " Adafruit"
author = "Adafruit"
# The version info for the project you're documenting, acts as replacement for
@ -83,7 +87,7 @@ release = "1.0"
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
language = "en"
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
@ -115,19 +119,9 @@ napoleon_numpy_docstring = False
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
on_rtd = os.environ.get("READTHEDOCS", None) == "True"
import sphinx_rtd_theme
if not on_rtd: # only import and set the theme if we're building docs locally
try:
import sphinx_rtd_theme
html_theme = "sphinx_rtd_theme"
html_theme_path = [sphinx_rtd_theme.get_html_theme_path(), "."]
except:
html_theme = "default"
html_theme_path = ["."]
else:
html_theme_path = ["."]
html_theme = "sphinx_rtd_theme"
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,

View file

@ -29,8 +29,9 @@ Table of Contents
.. toctree::
:caption: Other Links
Download <https://github.com/adafruit/Adafruit_CircuitPython_turtle/releases/latest>
CircuitPython Reference Documentation <https://circuitpython.readthedocs.io>
Download from GitHub <https://github.com/adafruit/Adafruit_CircuitPython_turtle/releases/latest>
Download Library Bundle <https://circuitpython.org/libraries>
CircuitPython Reference Documentation <https://docs.circuitpython.org>
CircuitPython Support Forum <https://forums.adafruit.com/viewforum.php?f=60>
Discord Chat <https://adafru.it/discord>
Adafruit Learning System <https://learn.adafruit.com>

View file

@ -2,4 +2,6 @@
#
# SPDX-License-Identifier: Unlicense
sphinx>=4.0.0
sphinx
sphinxcontrib-jquery
sphinx-rtd-theme

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -0,0 +1,2 @@
# SPDX-FileCopyrightText: 2021 Tim C for Adafruit Industries
# SPDX-License-Identifier: MIT

View file

@ -2,6 +2,7 @@
# SPDX-License-Identifier: MIT
import board
from adafruit_turtle import Color, turtle
turtle = turtle(board.DISPLAY)

View file

@ -0,0 +1,38 @@
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT
import board
from adafruit_turtle import Color, turtle
turtle = turtle(board.DISPLAY)
# The purpose of this test is to check that the OnDiskBitmap usage is
# working correctly: bgpic(), changeturtle() & stamp()
# Make sure that the following file is copied to the CircuitPython drive
ICON = "/icons/Play_48x48_small.bmp"
turtle.bgpic(ICON)
turtle.changeturtle(ICON)
starsize = min(board.DISPLAY.width, board.DISPLAY.height) * 0.9 # 90% of screensize
print("Turtle time! Lets draw a star")
turtle.pencolor(Color.BLUE)
turtle.setheading(90)
turtle.penup()
turtle.goto(-starsize / 2, 0)
turtle.pendown()
start = turtle.pos()
while True:
turtle.forward(starsize)
turtle.stamp()
turtle.left(170)
if abs(turtle.pos() - start) < 1:
break
while True:
pass

View file

@ -2,6 +2,7 @@
# SPDX-License-Identifier: MIT
import board
from adafruit_turtle import Color, turtle
turtle = turtle(board.DISPLAY)

View file

@ -2,6 +2,7 @@
# SPDX-License-Identifier: MIT
import board
from adafruit_turtle import turtle
turtle = turtle(board.DISPLAY)

View file

@ -2,6 +2,7 @@
# SPDX-License-Identifier: MIT
import board
from adafruit_turtle import turtle
print("Turtle time! Lets draw a square with dots")

View file

@ -2,6 +2,7 @@
# SPDX-License-Identifier: MIT
import board
from adafruit_turtle import turtle

View file

@ -2,26 +2,28 @@
# SPDX-License-Identifier: MIT
import board
from adafruit_turtle import turtle
def f(side_length, depth, generation):
if depth != 0:
side = lambda: f(side_length / 3, depth - 1, generation + 1)
side()
turtle.left(60)
side()
turtle.right(120)
side()
turtle.left(60)
side()
if depth == 0:
turtle.forward(side_length)
return
side = lambda: f(side_length / 3, depth - 1, generation + 1)
side()
turtle.left(60)
side()
turtle.right(120)
side()
turtle.left(60)
side()
turtle = turtle(board.DISPLAY)
unit = min(board.DISPLAY.width / 3, board.DISPLAY.height / 4)
top_len = unit * 3
print(top_len)
turtle.penup()
turtle.goto(-1.5 * unit, unit)
turtle.pendown()

View file

@ -2,6 +2,7 @@
# SPDX-License-Identifier: MIT
import board
from adafruit_turtle import turtle
turtle = turtle(board.DISPLAY)

View file

@ -2,21 +2,24 @@
# SPDX-License-Identifier: MIT
import board
from adafruit_turtle import turtle, Color
generation_colors = [Color.RED, Color.BLUE, Color.GREEN]
from adafruit_turtle import Color, turtle
generation_colors = [Color.RED, Color.BLUE, Color.GREEN, Color.YELLOW]
def f(side_length, depth, generation):
if depth != 0:
side = lambda: f(side_length / 3, depth - 1, generation + 1)
side()
turtle.left(60)
side()
turtle.right(120)
side()
turtle.left(60)
side()
if depth == 0:
turtle.forward(side_length)
return
side = lambda: f(side_length / 3, depth - 1, generation + 1)
side()
turtle.left(60)
side()
turtle.right(120)
side()
turtle.left(60)
side()
def snowflake(num_generations, generation_color):
@ -40,7 +43,7 @@ turtle.penup()
turtle.goto(-1.5 * unit, unit)
turtle.pendown()
for generations in range(3):
for generations in range(4):
snowflake(generations, generation_colors[generations])
turtle.right(120)

View file

@ -2,6 +2,7 @@
# SPDX-License-Identifier: MIT
import board
from adafruit_turtle import turtle
@ -10,7 +11,6 @@ def getMid(p1, p2):
def triangle(points, depth):
turtle.penup()
turtle.goto(points[0][0], points[0][1])
turtle.pendown()

View file

@ -2,6 +2,7 @@
# SPDX-License-Identifier: MIT
import board
from adafruit_turtle import Color, turtle
turtle = turtle(board.DISPLAY)

View file

@ -2,6 +2,7 @@
# SPDX-License-Identifier: MIT
import board
from adafruit_turtle import Color, turtle
turtle = turtle(board.DISPLAY)

View file

@ -2,6 +2,7 @@
# SPDX-License-Identifier: MIT
import board
from adafruit_turtle import Color, turtle
turtle = turtle(board.DISPLAY)

View file

@ -2,7 +2,8 @@
# SPDX-License-Identifier: MIT
import board
from adafruit_turtle import turtle, Color
from adafruit_turtle import Color, turtle
turtle = turtle(board.DISPLAY)

View file

@ -0,0 +1,3 @@
# SPDX-FileCopyrightText: 2022 Alec Delaney, for Adafruit Industries
#
# SPDX-License-Identifier: Unlicense

45
pyproject.toml Normal file
View file

@ -0,0 +1,45 @@
# SPDX-FileCopyrightText: 2022 Alec Delaney for Adafruit Industries
#
# SPDX-License-Identifier: MIT
[build-system]
requires = [
"setuptools",
"wheel",
"setuptools-scm",
]
[project]
name = "adafruit-circuitpython-turtle"
description = "Turtle graphics library for CircuitPython and displayio"
version = "0.0.0+auto.0"
readme = "README.rst"
authors = [
{name = "Adafruit Industries", email = "circuitpython@adafruit.com"}
]
urls = {Homepage = "https://github.com/adafruit/Adafruit_CircuitPython_turtle"}
keywords = [
"adafruit",
"blinka",
"circuitpython",
"micropython",
"turtle",
"graphics,turtle",
]
license = {text = "MIT"}
classifiers = [
"Intended Audience :: Developers",
"Topic :: Software Development :: Libraries",
"Topic :: Software Development :: Embedded Systems",
"Topic :: System :: Hardware",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
]
dynamic = ["dependencies", "optional-dependencies"]
[tool.setuptools]
py-modules = ["adafruit_turtle"]
[tool.setuptools.dynamic]
dependencies = {file = ["requirements.txt"]}
optional-dependencies = {optional = {file = ["optional_requirements.txt"]}}

View file

@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-FileCopyrightText: 2022 Alec Delaney, for Adafruit Industries
#
# SPDX-License-Identifier: Unlicense

111
ruff.toml Normal file
View file

@ -0,0 +1,111 @@
# SPDX-FileCopyrightText: 2024 Tim Cocks for Adafruit Industries
#
# SPDX-License-Identifier: MIT
target-version = "py38"
line-length = 100
[lint]
preview = true
select = ["I", "PL", "UP"]
extend-select = [
"D419", # empty-docstring
"E501", # line-too-long
"W291", # trailing-whitespace
"PLC0414", # useless-import-alias
"PLC2401", # non-ascii-name
"PLC2801", # unnecessary-dunder-call
"PLC3002", # unnecessary-direct-lambda-call
"E999", # syntax-error
"PLE0101", # return-in-init
"F706", # return-outside-function
"F704", # yield-outside-function
"PLE0116", # continue-in-finally
"PLE0117", # nonlocal-without-binding
"PLE0241", # duplicate-bases
"PLE0302", # unexpected-special-method-signature
"PLE0604", # invalid-all-object
"PLE0605", # invalid-all-format
"PLE0643", # potential-index-error
"PLE0704", # misplaced-bare-raise
"PLE1141", # dict-iter-missing-items
"PLE1142", # await-outside-async
"PLE1205", # logging-too-many-args
"PLE1206", # logging-too-few-args
"PLE1307", # bad-string-format-type
"PLE1310", # bad-str-strip-call
"PLE1507", # invalid-envvar-value
"PLE2502", # bidirectional-unicode
"PLE2510", # invalid-character-backspace
"PLE2512", # invalid-character-sub
"PLE2513", # invalid-character-esc
"PLE2514", # invalid-character-nul
"PLE2515", # invalid-character-zero-width-space
"PLR0124", # comparison-with-itself
"PLR0202", # no-classmethod-decorator
"PLR0203", # no-staticmethod-decorator
"UP004", # useless-object-inheritance
"PLR0206", # property-with-parameters
"PLR0904", # too-many-public-methods
"PLR0911", # too-many-return-statements
"PLR0912", # too-many-branches
"PLR0913", # too-many-arguments
"PLR0914", # too-many-locals
"PLR0915", # too-many-statements
"PLR0916", # too-many-boolean-expressions
"PLR1702", # too-many-nested-blocks
"PLR1704", # redefined-argument-from-local
"PLR1711", # useless-return
"C416", # unnecessary-comprehension
"PLR1733", # unnecessary-dict-index-lookup
"PLR1736", # unnecessary-list-index-lookup
# ruff reports this rule is unstable
#"PLR6301", # no-self-use
"PLW0108", # unnecessary-lambda
"PLW0120", # useless-else-on-loop
"PLW0127", # self-assigning-variable
"PLW0129", # assert-on-string-literal
"B033", # duplicate-value
"PLW0131", # named-expr-without-context
"PLW0245", # super-without-brackets
"PLW0406", # import-self
"PLW0602", # global-variable-not-assigned
"PLW0603", # global-statement
"PLW0604", # global-at-module-level
# fails on the try: import typing used by libraries
#"F401", # unused-import
"F841", # unused-variable
"E722", # bare-except
"PLW0711", # binary-op-exception
"PLW1501", # bad-open-mode
"PLW1508", # invalid-envvar-default
"PLW1509", # subprocess-popen-preexec-fn
"PLW2101", # useless-with-lock
"PLW3301", # nested-min-max
]
ignore = [
"PLR2004", # magic-value-comparison
"UP030", # format literals
"PLW1514", # unspecified-encoding
"PLR0913", # too-many-arguments
"PLR0915", # too-many-statements
"PLR0917", # too-many-positional-arguments
"PLR0904", # too-many-public-methods
"PLR0912", # too-many-branches
"PLR0916", # too-many-boolean-expressions
"PLR6301", # could-be-static no-self-use
"PLC0415", # import outside toplevel
"PLC2701", # private import
"UP007", # x | y typing
"UP006", # builtin instead of typing import
"PLR0914", # too many locals
]
[format]
line-ending = "lf"

View file

@ -1,57 +0,0 @@
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
#
# SPDX-License-Identifier: MIT
"""A setuptools based setup module.
See:
https://packaging.python.org/en/latest/distributing.html
https://github.com/pypa/sampleproject
"""
from setuptools import setup, find_packages
# To use a consistent encoding
from codecs import open
from os import path
here = path.abspath(path.dirname(__file__))
# Get the long description from the README file
with open(path.join(here, "README.rst"), encoding="utf-8") as f:
long_description = f.read()
setup(
name="adafruit-circuitpython-turtle",
use_scm_version=True,
setup_requires=["setuptools_scm"],
description="Turtle graphics library for CircuitPython and displayio",
long_description=long_description,
long_description_content_type="text/x-rst",
# The project's main homepage.
url="https://github.com/adafruit/Adafruit_CircuitPython_turtle",
# Author details
author="Adafruit Industries",
author_email="circuitpython@adafruit.com",
install_requires=["Adafruit-Blinka", "adafruit-circuitpython-busdevice"],
# Choose your license
license="MIT",
# See https://pypi.python.org/pypi?%3Aaction=list_classifiers
classifiers=[
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"Topic :: Software Development :: Libraries",
"Topic :: System :: Hardware",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
],
# What does your project relate to?
keywords="adafruit blinka circuitpython micropython turtle graphics,turtle",
# You can just specify the packages manually here if your project is
# simple. Or you can use find_packages().
# TODO: IF LIBRARY FILES ARE A PACKAGE FOLDER,
# CHANGE `py_modules=['...']` TO `packages=['...']`
py_modules=["adafruit_turtle"],
)