Skip to content
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

Split display.py into files for each backend #930

Merged
merged 5 commits into from
Jan 29, 2024

Conversation

Anomalocaridid
Copy link
Contributor

A while ago, when I added the BuiltInDisplay backend in #846, I made an erroneous assumption about how the displays worked. I moved displayio.release_displays() to the __init__() methods of the displays that needed it, which inadvertently broke them. (Which I sincerely apologize for.)

This was later fixed in #871, at the cost of breaking BuiltInDisplay.

I have since come up with a compromise that should ensure all currently supported displays are functional: Break display.py into multiple files:

  • display.py, which contains the classes for the displays that require displayio.release_displays()
  • display_builtin.py, which contains BuiltInDisplay
  • display_common.py, which contains the code shared by both, which is also re-exported by both of the other files for compatibility.

I tried to make all displays work while minimizing breaking changes. As far as I am aware, the only breaking change is that users of BuildInDisplay will need to import from display_builtin instead of display. I have updated Display.md accordingly.

Also, I do not own a keyboard with a SSD1306 display, so I would need someone else who has one to check that I did not break anything again.

@regicidalplutophage
Copy link
Member

regicidalplutophage commented Jan 21, 2024

Yeah, I too were thinking of breaking up this extension, but rather than minimizing breaking changes I thought of separating every "backend" into its own file with display.py functioning as common. Though the way I envisioned it there won't be display.py, only /display/__init__.py and backend files in the /display/ directory. This should bring some degree of future-proofing in case the number of supported displays grows.

@Anomalocaridid
Copy link
Contributor Author

That's a much better idea. I'll rework my PR to do things that way.

@Anomalocaridid Anomalocaridid changed the title Fix BuiltInDisplay Split display.py into files for each backend Jan 23, 2024
@Anomalocaridid
Copy link
Contributor Author

How's this?

Now each backend is in its own file, with kmk/extensions/display/__init__.py holding common logic. I also updated README.md again.

@regicidalplutophage
Copy link
Member

regicidalplutophage commented Jan 23, 2024

Hi! I see your latest commit and I'm trying to fact check myself on whether it's actually good form to use __init__.py as the main body of the package. @xs5871 should know better.

Also, maybe we should call each backend class within each backend module as simply backend so that we can for example:

from kmk.extensions.display import Display, TextEntry, ImageEntry, ssd1306
driver = ssd1306.backend()

Also also, as a person who brought SH1106 support, can you confirm that we need displayio.release_displays() twice in the sh1106 module? It was originally added because because SSD1306 didn't deinitialize on ctrl+c and initializing an initialized display resulted in an error. This function only needed to be called once for that purpose.

@Anomalocaridid
Copy link
Contributor Author

Also, maybe we should call each backend class within each backend module as simply backend

Probably a good idea. I'll make sure to change it to that.

Also also, as a person who brought SH1106 support, can you confirm that we need displayio.release_displays() twice in the sh1106 module? It was originally added because because SSD1306 didn't deinitialize on ctrl+c and initializing an initialized display resulted in an error. This function only needed to be called once for that purpose.

It should only be needed once, just like the SSD1306 display. I'll make sure to fix that as well.

@Anomalocaridid
Copy link
Contributor Author

I removed the unecessary call to displayio.release_displays() and renamed each of the display backends to just backend.

Also I probably should have brought this up earlier, but according to the CI checks, my changes cause an error that makes the tests fail. However, I am not sure how to resolve it.

@regicidalplutophage
Copy link
Member

Yeah, unit tests aren't happy and that has to be resolved.

Copy link
Member

@regicidalplutophage regicidalplutophage left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this.
Not merging yet because I'm not sure what's up with unit tests and also I'd like to see what @xs5871 thinks, since extension being a package is something new for KMK.

@xs5871
Copy link
Collaborator

xs5871 commented Jan 28, 2024

First off: I really like what I'm seeing. Submodules are exactly the right thing to do, and should've been done for other parts of the code as well (rgb for example).
What should go into __init__.py? I don't think there's a hard limit on that. Usually things that aren't meant to be imported by the user directly; there are arguments for both ends of the spectrum "as little as possible" and "everything that's not implementation specific". I don't mind sticking to the latter and split off fragments as deemed necessary.

Concerning the failing unittests: fixed in #934; nice catch -- please rebase your PR on the updated upstream.
There are at least a couple of style issues I have to address, didn't look too closely at the code though yet. I expect that the linter has some complaints first.


# Intended for displays with drivers built into CircuitPython
# that can be used directly without manual initialization
class backend(DisplayBackend):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
class backend(DisplayBackend):
class Backend(DisplayBackend):

Class names are CamelCase.
I personally don't 100% agree that all the backend implementations should have the same name. They are in seperate, appropriately named submodules though, so there's that and I'm not going to complain about it.
There could be an argument, that __init__.DisplayBackend is a slight misnomer, as it's specifically not a backend, more of a "stub" or "abstract" class, whatever your preferred nomenclature. I'd appreciate your opinion on that.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My reasoning for this suggestion was to reduce tautology and make it so that one could intuit the process of setting up a backend from prior experience with another. I'm also not super into calling those backends.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get the reasoning and it's a valid point. The reason I prefer tautologies is that no matter where it turns up, be it in the import or the source itself, if you call it ssd1306.SSD1306 it's always obvious what the thing is you're talking about. It may sound derivative, but I tend to look at adafruit for conventions in general, for example: adafruit_displayio_sh1106.SH1106. That is an intentional tautology, it is verbose, but not to the point where it looks like java. (That's why I dislike the "abstract" moniker for classes. It's pseudo-technical fluff that doesn't reflect what the word is used for in day-to-day conversations.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@xs5871 Good point. I think you're right that it would be better to be explicit in this case. I'll make sure to change back the names of the backend classes.

Also I agree it is probably better to give DisplayBackend a more descriptive name. Maybe something like DisplayBackendBase?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might as well drop the "Backend" in that case and just call it DisplayBase.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The display backends now have their old names back and DisplayBackend is now DisplayBase

Copy link
Collaborator

@xs5871 xs5871 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems my guess about the linter was wrong. Good job.

@@ -0,0 +1,24 @@
from kmk.extensions.display import DisplayBackend
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
from kmk.extensions.display import DisplayBackend
from . import DisplayBackend

We should be using relative imports, especially for "self contained" modules.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replaced the absolute imports with relative imports


# Intended for displays with drivers built into CircuitPython
# that can be used directly without manual initialization
class backend(DisplayBackend):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get the reasoning and it's a valid point. The reason I prefer tautologies is that no matter where it turns up, be it in the import or the source itself, if you call it ssd1306.SSD1306 it's always obvious what the thing is you're talking about. It may sound derivative, but I tend to look at adafruit for conventions in general, for example: adafruit_displayio_sh1106.SH1106. That is an intentional tautology, it is verbose, but not to the point where it looks like java. (That's why I dislike the "abstract" moniker for classes. It's pseudo-technical fluff that doesn't reflect what the word is used for in day-to-day conversations.)

@regicidalplutophage regicidalplutophage merged commit 5d4e787 into KMKfw:master Jan 29, 2024
1 check passed
@Anomalocaridid Anomalocaridid deleted the fix-builtindisplay branch January 29, 2024 23:15
@Anomalocaridid
Copy link
Contributor Author

Thank you!

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