--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To post to this group, send email to django-d...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-developers.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/d251dbee-bc4f-3325-a7bb-bb9d1f996cb1%40nerdocs.at.
For more options, visit https://groups.google.com/d/optout.
* Your “homepage” link on PyPI is example.com. The usual thing to do here is link to your source host or docs. Set this as url in your setup.py.
* I see you list pretix as an inspiration - did you see Raphael have a talk at Djangocon Europe in April on this? https://youtu.be/QbitxAEEZjI It may be old news to you though if you’re familiar
Didn't know this talk, thanks. But I had an email conversation with him a while ago about that and he was the one who I learned a lot from about how to create GDAPS. Basically my implementation does not differ too much, and I even am considering using his "PretixPluginMeta" inner class in the AppConfig of GDAPS plugins too. I just think about other ways ATM - but I'm pretty sure I'll implement his way - in a more generic style.
It even could be that GDAPS plugins are so similar that Pretix
*could* switch it's underlying plugin system to GDAPS without
changing very much.
He did a really great job there and I never would be able to do
this on my own, without the insights he gave me to Pretix. Same
goes for PyUtilib.
* GPL can make your project hard to use, because depending on the lawyers it can be interpreted as having to make the website source code public. In the one dependency audit I went through, GPL and AGPL were disallowed and we had to strip a dependency or two because of this.
Yes, you are right too. This was another too fast shot - I'd like
to release my project which is using GDAPS under the GPL/AGPL
later. GDAPS is a library, and here the GPL doesn't help much. I
need to think about it a bit, a little part of the code is from
PyUtilib (which is BSD), and a bit copied from Graphene-Django
(which is MIT). So maybe I'll switch to BSD too. Recommendations
here for Django libraries, or specially GDAPS?
* What do you think are the implications for Django core? Is there anything Django could do better to support this and all the other plugin systems you’ve looked at? Also I’m totally sure you can contribute, it’s not scary and there is a lot of information on getting started! See
Yes, I'll have a deeper look at the contributing guidelines.
The most parts where I had to struggle within Django were:
* The settings, to let each module provide it's own setting. There is no standardized way of having settings saved. I borrowed the graphene-django way - which had copied it from DRF ;-)
* Django doesn't allow to easily add apps to the running server
when already started. Even adding apps to INSTALLED_APPS after
loading Django is impossible, it has to be done within the setup
process - I solved that using a Pluginmanager method
(find_plugins) which is called after declaring INSTALLED_APPS in
settings.ps, and which returns an INSTALLED_APPS compatible array
which can be merged into INSTALLED_APPS. This method is certainly
not able to call DB commands in that early startup point of time.
So what I initially planned, downloading apps from a connected
"app store" for my application, installing it "on the fly"
(including makemigrations/migrate paths) and hooking in the plugin
into the running process is not possible in Django.
I don't have a big problem here, as installing a plugin ATM in GDAPS is just (for projects without SPA/frontend support):
stop server
pip install fooplugin
./manage.py makemigrations
./manage.py migrate
start server
which is perfectly ok for what I need.
* URL routing was easy to integrate - the only thing which is
remaining IMHO is - django does not help to "weigh" the rules. But
this is a thing I want to implement in GDAPS - to give plugin apps
the possibility to add a "weight" to URL paths so they are
"ordered" in a more deterministic way.
I just created a ticket where I described that a bit:
https://gitlab.com/nerdocs/gdaps/issues/4
Same could go to the INSTALLED_APPS ordering. A "weight" ordering is not ideal here, I think that a dependency resolution system would be much better here. Here Django could help a bit - Django apps are depending on other apps, declared in setup.py or setup.cfg. If this meta information would be available to Django (or GDAPS), the loading of apps (GDAPS plugins) could be at least done automatically in a way that dependant apps are loaded after their dependencies.
So far... much to do.
I hope earth is going to spin slower soon, so a day gets more than
24h. ;-)
But here it is too late. settings.py continues, and *afterwords* all the apps are scanned for their settings. you can't override them again in settings.py after that.I'm a little unclear here. Is it too late because you want to be able to exclude settings from packages that are installed but you don't want "active" in the project?
The main problem is that settings are code in Django, and not declarative. You have to *import* them, you don't parse them. I did that similar to Pretix (mine isn't finished yet): you have to differ between "installed" and "active". Packages which are installed could have a "switch" (which has to be a changeable, cached, database state) where to activate/deactivate it. A deactivated plugin is omitted when itering over its implementations, and doesn't emit signals. That's what you really want, I suppose? I think settings - if they are really just *declarative settings* (without code) - would be nice to be parsed *before* loading apps. But Django uses .py files as settings, which is a blessing and a course. There can be conditionals and code in a settings file, which is cool, but leads to problems. Just to not get me wrong: I don't suggest to change Django settings model here - .py files are ok IMHO. But We have to deal with that somehow.
That you only want 3rd party "settings contributing" plugins to be
activated when selected?
In which case, doesn't it make more sense to include a plugins.cfg to
be processed _before_ settings.py to decide? And if handled well, I
expect only an exclusion list may be required [but an inclusion list
would be safer].
Definitely. That's the main reason I had liked to implement a declarative plugin spec file with plugin metadata (and maybe default settings?) instead of having plugin Metadata in the AppConfig as subclass - like Raphael did in Pretix. This is a cool and easy approach, but you *have to* import the plugin for getting the metadata - and plugin code has already run then. It's too late to decide: No I don't want that plugin running. But in the end I decided, that from a security POV, it makes no difference. If you have a plugin already on your server, it doesn't matter if you have a settings.cfg or pluginspec.cfg file to parse. You have to trust the plugin anyway when you run it's main entry point later. And from that POV, using Python code (= a class) as metadata or settings, is ok, so most certainly I will implement Pretix' Metadata system into GDAPS as well, additionally being most compatible with Pretix.
It wouldn't be necessary to make a setuptools entry point for app/plugin settings. The entry point I would recommend is a "settings.py" for each app - automatically namespaced or better, with a NAMESPACE = "fooplugin" - which would enable having 2 plugins using the same namespace (think of "sub-plugins" of one bigger plugin).Ah, I think I see now. You want INSTALLED_APPS to be the definitive truth of all apps _and_ plugins. So it's not possible to have a plugin that's not also an app?
That was my intention, yes. Because else I would need another entry point system, Django apps are fine except to the fact that they are not pluggable. That's the perfect combination IMHO: Use Django apps as "reusable" apps like DRF etc, like a Mixin which fulfills the same purpose in different contexts, applications etc., and use Django apps that are enhanced as GDAPS plugins to extend *one* single Django application with plugins that could be written by others. That's what Raphael said in his DjangoCon talk.
Sub-plugins opens up the can of works that is dependency resolution.
No, this can is already opened when loading plugins/apps via setuptools entry points. I called "Sub-plugins" the ones that live under the same "namespace", if that will be an option.
Now what we'll need is a way to avoid namespace clashes, and a dev-friendly way to update these settings in settings.pyI would definitely *allow* namespace clashes, as explained above. Like in partial classes. A "Textprinter" plugin could have 3rdparty sub-plugins, which could use the same namespace (HTMLProviderPlugin, MarkdownProviderPlugin etc.)Yes, I did consider this. I think it's valid that a plugin may override another plugins defaults.
Definitely, but only, if it declares a (at least weak) dependency on that other plugin. PluginA could "support" plugins like PluginB and C *if* they are present, and could then override their defaults. I e.g. decided to implement a "core" plugin - like QtCreator did - to make live easier for versioning - plugins relaying on "CorePlugin>=2.3.5" can't be installed then when CorePlugin is 2.0.0. So Core is like any other plugin. And so all plugins depend on Core plugin and could override its defaults. Next problem here is, what if 2 plugins override the default of a third one. The last in the loading row wins then. There are MANY things to consider - but I decided to just start off, and look where the journey brings me.
But in the end, the projects settings.py should be final.
Yes. Christian
I'd like to ask another question concerning plugin apps, and hoping your deeper knowledge about Django internals helps here...
I'm implementing the plugin Metadata for GDAPS plugins ATM, and am a bit concerned wether to implement a construct like the Pretix system or not.
Pretix uses AppConfig classes, and creates a inner PretixPluginMeta classs where it sums up all the information it needs. It's easy then to walk all apps and filter out the ones that have a PretixPluginsMeta - and get their data out.
class PaypalApp(PluginConfig): name = 'pretix_paypal' verbose_name = _("PayPal") class PretixPluginMeta: name = _("PayPal") author = _("the pretix team") version = '1.0.0' visible = True restricted = False description = _("This plugin allows you to receive payments via PayPal") compatibility = "pretix>=2.7.0"
What I need for a good plugin life cycle are methods, callbacks that are called when a plugin is "installed" = run the first time, methods for enabling/disabling etc.
The easiest way would be implementing these methods within the AppConfig subclass.
I asked myself why is there a PluginMeta needed? Can't I add those data attributes directly to AppConfig?
So my question on you all is: Is it a good idea to merge those data deeply with tha AppConfig object? I mean, as a plugin in my sense is more or less the same as an app, it won't matter. But deeply inside, I feel that there is something wrong done. Separate concerns should not me mixed - and I don't know what you want to implement in Django's future into AppConfig. Maybe there could be conflicts.
Another way would be implementing the methods too into the
PluginMeta object.
May I ask for your opinions here?
And a second question: The DJango docs say, that it's not recommended to use "default_app_config". But in each and every example, even in the tutorials and the Django boilerplate code of "./manage.py startproject foo" are NO Appconfigs addressed in INSTALLED_APPS. Nobody does this, right?
How "obligate" is this recommendation, when noone uses it? Should this be kept?
Thanks,
Christian
And a second question: The DJango docs say, that it's not recommended to use "default_app_config". But in each and every example, even in the tutorials and the Django boilerplate code of "./manage.py startproject foo" are NO Appconfigs addressed in INSTALLED_APPS. Nobody does this, right?
How "obligate" is this recommendation, when noone uses it? Should this be kept?
I think it's most likely there as a legacy state, in order to reduce the burden of upgrading.
I do agree it would be better if we abide by our own recommendations.
But is this really necessary?
When you look at your documentation, like the tutorial in
https://docs.djangoproject.com/en/3.0/intro/reusable-apps/ -
"Quick start" - you use
INSTALLED_APPS = [ ... 'polls', ]It should be 'polls.apps.PollsConfig'
I tried to follow that rule in my own framework, but it's like driving 49,99 km/h in 50 speed limit on the street, when everyone else drives 55. Even Google allows it's self driving cars to drive faster than the limit by 10% in some cases ;-)
What I mean is: Why don't you drop that recommendation - when noone is using it - more than one AppConfigs still *are* possible, even when there is a default.
Christian
-- Dr. Christian González https://nerdocs.at
--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/8ddcc796-6a5d-e680-b6bb-aaae6831b4fc%40nerdocs.at.
And to be honest - does this really make sense to urge people - writing more code to satisfy the framework?
What I mean is: Why don't you drop that recommendation - when noone is using it - more than one AppConfigs still *are* possible, even when there is a default
The original intent was to make configuration explicit by having settings.py reference directly the target AppConfig class.
- When you write MIDDLEWARE = ["polls"], do you expect Django to enable "polls.middleware.PollsMiddleware"?- When you write INSTALLED_APPS = ["polls"], do you expect Django to enable "polls.apps.PollsAppConfig"?
Many readers of this mailing list will answer "no" and "yes" respectively. I think the answer to both should be "no", according to Django's design philosophy. (If you're about to argue that an application can provide more than one middleware — I'm aware of this and I know you understood my point anyway.)
[...]
If we're reversing course, giving up on explicitness and going for magic, we could embrace that decision fully: import the "apps" submodule inside each application; if it exists and it defines exactly one AppConfig subclass, use that as the config for this app. Then app authors can stop littering their __init__.py files with default_app_config.
That would be perfect IMHO. One could consider restricting it to the same-named subclass like the app itself, so the app "foo" would need to have "FooConfig" as default.
I'm aware that this violates the 2nd "Zen of Python" principle "Explicit is better than implicit". and "Special cases aren't special enough to break the rules." - but the next one says: "Although practicality beats purity."
Yes, too much "magic" leads to a system where half of it uses magic, and the other half not - so it's not predictable for the developer what a certain line does.
But exactly in this part I think that having a "sane default" - in the sense of app loading using by using the app name only - is ok.
I would bet that the vast majority of apps don't have two
AppConfigs.
And to urge all devs to use the more elaborative AppConfig line in
INSTALLED_APPS, just to make such special cases (and THESE are the
special cases!) are possible, is wrong IMHO.
Let it be easy - even the variable says INSTALLED_APPS, not
INSTALLED_CONFIGS. And let there be the possibility to
declare other AppConfigs on demand.
--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/b37e3655-4253-75a1-b750-6c81a0f6cf26%40nerdocs.at.
Eh, sorry if I misunderstand - but adding a "default = true" line to an AppConfig is the same as addign default_app_config = "foo.apps.FooConfig".
A few things that came to my mind when reading the code:
* You check if there is only one AppConfig available (https://github.com/django/django/pull/12310/commits/6a4ee2d02477cac1fa67708ceefda2ffd56bbf96#diff-239ff7e40a4b9921b462471882a575f6R111) and if so, this one is used - that's perfect IMHO.
* But what if 2 AppConfigs have "default = true" ? Then line
#139+ is run, and silently the default app config class is used -
none of the two ones. Maybe an error message would be better.
default=true should only be valid once!
Best regards,
Christian
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/A037EBE4-78A7-4037-9E8A-29DCC604CB85%40polytechnique.org.
Oh, sorry, I just saw that this is discussed (andanswered) in the
PR.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/f9dc1734-2148-bef7-95b1-d620f285d989%40nerdocs.at.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/a9df802d-62c8-b0c9-7bf1-820284ad26e3%40nerdocs.at.
<pEpkey.asc>
Hello
I created a PR for this: https://github.com/django/django/pull/12310I'd love to get some feedback on the design before I polish the patch.