-
Notifications
You must be signed in to change notification settings - Fork 11
CPython compatibility fix #31
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Looks like the CI is having some issues, you'll need to lint this. You can use https://learn.adafruit.com/creating-and-sharing-a-circuitpython-library/check-your-code |
@tekktrik Can't believe I missed this part :( But I fixed the issues! |
adafruit_turtle.py
Outdated
import displayio | ||
|
||
try: | ||
import board |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an usual import to mask with a try
/except
, both because it seems its used functionally in this module (not just for typing) and because it silently does so, masking what should be an exception with a print()
statement. Is there any reason when we're catching NotImplementedError
instead of ImportError
? Maybe I'm missing something, I still need to check the rest, but wanted to ask about this in the meantime.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @tekktrik, the reason I catch that exception is so that I can run this module on systems that don't have the board
module. When running with Blinka, the board module is defined for systems such as a Raspberry Pi SBC, but on generic x86 computers, the Blinka library will raise a NotImplementedError
error (not sure why it's not an ImportError
). That exception is thrown at the bottom of this file.
I suppose another approach could be to remove the import all together, and then in the turtle
initializer make the display
argument a required one. This would force users to pass the board.DISPLAY
for CircuitPython boards with a built-in display, vs the current behavior where that is the default -- note that this itself is wrapped in a try/except, which seems a bit weird because it will cause an exception on CircuitPython boards without a built-in display. This change, however, would break some existing scripts that use the library without passing the display
parameter.
Let me know what you think!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this was written before the generic x86 computer implementation was added, hence why it currently only catches AttributeError
. However, is there a use case where a display can be defined for a generic x86 computer? I'm not familiar with that implementation of Blinka and how it's used, and I've reached out to the other devs as well. If you know of one, it would help me out!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes there is! @FoamyGuy has one here, and I've included that code in my project here. It's fun because you can incorporate displayio
graphics into CPython applications. It's also useful for designing/testing embedded UIs for CircuitPython when you might not have access to the hardware.
I've been using this to demonstrate the power of abstraction/modularity to some of my students at University of Florida, where we can run (almost) identical code on laptops, RPis (either with HDMI or a PiTFT), and on microcontrollers with an embedded display -- just by changing the display
object to target the proper display for our system.
I worked on this pull request because I want to be able to use turtle
in a similar fashion, but the current implementation just doesn't allow for it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it, thanks! I'll get to this in the next few days, but that helps but the change into context!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another potential option is to move the import down to inside the if statement so that it will only try to import board. if the user has not passed a display object.
Thanks for tracking this down and submitting the fix @shulltronics. I will look into this and try it out tomorrow. |
adafruit_turtle.py
Outdated
@@ -1,6 +1,7 @@ | |||
# SPDX-FileCopyrightText: 2006-2010 Gregor Lingl for Adafruit Industries | |||
# SPDX-FileCopyrightText: 2019 LadyAda for Adafruit Industries | |||
# SPDX-FileCopyrightText: 2021 Dave Astels for Adafruit Industries | |||
# SPDX-FileCopyrightText: 2022 Carsten Thue-Bludworth for Adafruit Industries |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the intention is to only use for Adafruit Industiries
if you were paid by them for the development work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Haha, ok I understand (I wish I was working for Adafruit!). I added it because I was trying to follow all of the proper protocols for contributing according to this guide.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried this out and was running into some issues with it crashing. I've tinkered a bit and found a version which does (so far) seem to be working on both microcontroller and CPython. I'll PR it to your branch @shulltronics
adafruit_turtle.py
Outdated
def __init__(self, x, y): | ||
super().__init__((x, y)) | ||
def __new__(cls, x, y): | ||
return (x, y) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I get this error using this version on a PyPortal running the simpletest script in this repo:
Adafruit CircuitPython 8.0.0-beta.0 on 2022-08-18; Adafruit PyPortal with samd51j20
Board ID:pyportal
Traceback (most recent call last):
File "code.py", line 32, in <module>
TypeError: unsupported types for __sub__: 'tuple', 'tuple'
The simpletest is trying to subtract positions here:
if abs(turtle.pos() - start) < 1: |
Which turns out not to work because tuple doesn't have support for minus operator. This was odd to me at first because __sub__
is defined for Vec2D but it turns out because of the change in __new__
that these were actually being tuple objects instead of Vec2D objects.
I ended up trying this version with CPython using PyGameDisplay and got the same error from the simpletest where it crashes due to trying to subtract the Vec2D's which are actually tuples instead.
Some of the functionality does work properly though because you can see it draw the first line of the star in the simpletest before crashing. It seems only if you try to utilize some of the other Vec2D functions it will have trouble.
adafruit_turtle.py
Outdated
return (x, y) | ||
|
||
def __getitem__(self, index): | ||
return getattr(self, index) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The way you overrode __getitem__
here gave me inspiration for a different approach. If we can have Vec2D "hold" a tuple instead of "being" a tuple then perhaps we can have the "best of both worlds" and it will work on both microcontroller and SBC / CPYthon.
adafruit_turtle.py
Outdated
@@ -1,7 +1,6 @@ | |||
# SPDX-FileCopyrightText: 2006-2010 Gregor Lingl for Adafruit Industries | |||
# SPDX-FileCopyrightText: 2019 LadyAda for Adafruit Industries | |||
# SPDX-FileCopyrightText: 2021 Dave Astels for Adafruit Industries | |||
# SPDX-FileCopyrightText: 2022 Carsten Thue-Bludworth for Adafruit Industries |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you'd like to keep yourself credited, you can definitely do that, just without the for Adafruit Industries
portion. It is up to you though.
…o foamyguy_cpython_compat # Conflicts: # adafruit_turtle.py
CPython compatibility
I merged the changes made by @FoamyGuy and tested on three platforms including stable CircuitPython 7.3.0 on a Feather nRF52840 with an SPI display, an Adafruit CLUE running 8.0.0beta, and on CPython 3.10.7 with the PygameDisplay. Seems to work well on all of them. I tested quite a few of the example scripts in the turtle library. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me.
Tested successfully with PyPortal, RaspberryPi + SPI Display w/ Blinka_DisplayIO, and PC with Blinka_DIsplayIO + PygameDisplay
Thanks again for working on this @shulltronics. Also for sharing what you're doing with it :) it's always great to hear that it's been used to teach these concepts.
Thank you everyone! Appreciate the time and energy to get these changes added in :) |
Updating https://github.com/adafruit/Adafruit_CircuitPython_ESP_ATcontrol to 0.8.0 from 0.7.0: > Merge pull request adafruit/Adafruit_CircuitPython_ESP_ATcontrol#63 from bablokb/fix-retries Updating https://github.com/adafruit/Adafruit_CircuitPython_GPS to 3.10.5 from 3.10.4: > Merge pull request adafruit/Adafruit_CircuitPython_GPS#86 from tekktrik/doc/add-typing Updating https://github.com/adafruit/Adafruit_CircuitPython_INA260 to 1.3.11 from 1.3.10: > Merge pull request adafruit/Adafruit_CircuitPython_INA260#21 from gpongelli/patch-3 Updating https://github.com/adafruit/Adafruit_CircuitPython_LIS331 to 1.0.13 from 1.0.12: > Merge pull request adafruit/Adafruit_CircuitPython_LIS331#6 from tcfranks/main Updating https://github.com/adafruit/Adafruit_CircuitPython_turtle to 2.2.11 from 2.2.10: > Merge pull request adafruit/Adafruit_CircuitPython_turtle#31 from shulltronics/cpython-compatibility
For this PR, I changed two things.
board
module, so that on non-CircuitPython devices (i.e. generic computers), this script will library will still work.tuple
subclass from theVec2D
class, as the constructor/initializer was incompatible with CPython. Instead, I use the__new__
constructor and just explicitly return atuple
instead of calling thesuper
constructor.Now this library works as-is for devices running
adafruit-blinka
, such as a Raspberry Pi with a PiTFT display, or generic PCs using something likePygameDisplay
.