Skip to content

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

Merged
merged 11 commits into from
Oct 3, 2022

Conversation

shulltronics
Copy link
Contributor

For this PR, I changed two things.

  1. I added a conditional import for the board module, so that on non-CircuitPython devices (i.e. generic computers), this script will library will still work.
  2. I removed the tuple subclass from the Vec2D class, as the constructor/initializer was incompatible with CPython. Instead, I use the __new__ constructor and just explicitly return a tuple instead of calling the super 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 like PygameDisplay.

@tekktrik
Copy link
Member

Looks like the CI is having some issues, you'll need to lint this. You can use pre-commit to help automate the formatting changes and work through the linter issues. Instructions on getting started with pre-commit can be found in this Learn Guide:

https://learn.adafruit.com/creating-and-sharing-a-circuitpython-library/check-your-code

@tekktrik tekktrik self-requested a review September 28, 2022 03:00
@shulltronics
Copy link
Contributor Author

@tekktrik Can't believe I missed this part :( But I fixed the issues!

import displayio

try:
import board
Copy link
Member

@tekktrik tekktrik Sep 30, 2022

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.

Copy link
Contributor Author

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!

Copy link
Member

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!

Copy link
Contributor Author

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.

Copy link
Member

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!

Copy link
Contributor

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.

@FoamyGuy
Copy link
Contributor

Thanks for tracking this down and submitting the fix @shulltronics. I will look into this and try it out tomorrow.

@@ -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
Copy link
Contributor

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.

Copy link
Contributor Author

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.

Copy link
Contributor

@FoamyGuy FoamyGuy left a 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

def __init__(self, x, y):
super().__init__((x, y))
def __new__(cls, x, y):
return (x, y)
Copy link
Contributor

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.

return (x, y)

def __getitem__(self, index):
return getattr(self, index)
Copy link
Contributor

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.

@@ -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
Copy link
Contributor

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.

FoamyGuy and others added 2 commits October 1, 2022 11:17
…o foamyguy_cpython_compat

# Conflicts:
#	adafruit_turtle.py
@shulltronics
Copy link
Contributor Author

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.

Copy link
Contributor

@FoamyGuy FoamyGuy left a 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.

@FoamyGuy FoamyGuy merged commit b7b4386 into adafruit:main Oct 3, 2022
@shulltronics
Copy link
Contributor Author

Thank you everyone! Appreciate the time and energy to get these changes added in :)

adafruit-adabot added a commit to adafruit/Adafruit_CircuitPython_Bundle that referenced this pull request Oct 4, 2022
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants