beeware / toga

A Python native, OS native GUI toolkit.
https://toga.readthedocs.io/en/latest/
BSD 3-Clause "New" or "Revised" License
4.2k stars 656 forks source link

Eliminate `factory` modules #2687

Open mhsmith opened 4 days ago

mhsmith commented 4 days ago

The sub-module structure of each backend is identical, so that can already be considered a well-defined API between the interface and backend layers. Putting the "factory" namespace in between them adds complexity for no benefit.

For example, where we currently write:

self.factory.Camera

We could instead have:

import_backend("hardware.camera.Camera")

Which on macOS would translate into an import of toga_cocoa.hardware.camera, and a getattr of Camera.

For previous discussion, start at https://github.com/beeware/toga/pull/2584#pullrequestreview-2092686462.

freakboy3742 commented 3 days ago

As noted in this comment, it may be preferable to expose this API as import_backend("hardware").camera.Camera or import_backend("hardware.camera").Camera; that makes import_backend a relatively lightweight wrapper around import_module, but injecting the platform name, and yielding a module.

A related thought: this mechanism could also be used to provide a plugin interface for third-party widgets to provide platform-specific implementations. Consider the case of a third party widget that has native platform implementations - the widget could register as having providing a macOS implementation, then the interface use a standard import_backend API to access the platform backend. That avoids third-party widget needing to replicate the "if sys.platform ..." logic that would be the core of import_backend, and should be able to do this as a fallback if an AttributeError is raised on a first-pass lookup on the built-in backend.