pyGrowler / Growler

A micro web-framework using asyncio coroutines and chained middleware.
http://www.growler.rocks
Apache License 2.0
686 stars 29 forks source link

Suggestion: remove growler.ext mechanism #16

Open spookylukey opened 7 years ago

spookylukey commented 7 years ago

I saw this feature in your README, and was reminded of our experience with Django and doing magical imports etc. - back in the day, your own models would end up being imported from a Django namespace, rather than your own Python modules. This was unnecessary magic that caused complications of various kinds (similar to the way that you can't do normal imports such as from growler.ext import foo). The fact that you have to mention "it doesn't work quite the way you expect" tells you that you will have trouble with it.

The end result was that we removed this feature, along with a whole lot of unnecessary magic that required people to learn “the Django way” instead of just using "the Python way" which was perfectly adequate.

In this case, it seems like this mechanism just adds complications - like:

There doesn't seem to be a reason why it is needed. If you really need a registry of plugins, that could be explicit. You could almost certainly use setuptools entrypoints for this - http://stackoverflow.com/questions/774824/explain-python-entry-points#9615473 https://setuptools.readthedocs.io/en/latest/pkg_resources.html#entry-points

akubera commented 7 years ago

Ohh, so there could be some standard growler entry points that allow users to search for the packages that provide the correct services? Thanks, I had not considered this option.

The goal of the growler_ext namespace and the growler.ext pseduo-module was not to restrict people's packaging setup, but allow for a common interface exposing all supported packages' middleware for simple importing (by this I mean importing using only the classname). I also hoped it would allow for seamless transitions between packages if someone wanted to switch the 'backend' (no changes to code, only dependencies).

Mostly, it was just for me learn how to use namespaces properly - which was non-trivial due to the amount of legacy "best practices" which can be found online.

I will look into the entrypoints methods when I start to work on growler again; I'm currently focusing on other works and don't have the time for this side project. If you (or anyone else reading this) would like to provide a implementation, please go ahead!

Thanks again.

akubera commented 7 years ago

I've refactored the extension mechanism to use pkg_resources in the 'refactor/ext' branch. I think it's a lot cleaner, but now has an explicit dependency on setuptools, but I'm not too worried about it.

All a package has to do to add a class or function to the growler.ext "namespace" is add the entry point to the setup function in setup.py. For example, to be able to load the class my_package.growler.MyRenderer via from growler.ext import MyRenderer, do

setup(
    ...
    entry_points={
        'growler.ext': [
            'MyRenderer = my_package.growler:MyRenderer
        ],
    }
    ...
)

Here is the new module source. It scans through and loads all members of the growler.ext group upon the first load of growler.ext. I'm not sure how to do lazy loading without resorting to a weird class again.

I'd appreciate any comments.

The docs still need updating.