-
Notifications
You must be signed in to change notification settings - Fork 54
Draft: add rdmo.config app for Plugin model (plugin managament)
#1436
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
base: 2.5.0/release
Are you sure you want to change the base?
Conversation
jochenklar
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great! Lets discuss in the meeting.
rdmo/config/models.py
Outdated
| help_text=_('Designates whether this plugin is generally available for projects.') | ||
| ) | ||
|
|
||
| class PluginType(models.TextChoices): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can do without this, the Plugin(-class) should know this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have now something like this as a utils.py function, to detect the plugin type from the class inheritance.
PLUGIN_BASES = {
'optionset_provider': OptionsetProvider,
'export': Export,
'import': Import,
'issue_provider': IssueProvider,
}
def detect_plugin_type(plugin_class):
if not issubclass(plugin_class, Plugin):
return "not_an_rdmo_plugin"
for type_name, base_cls in PLUGIN_BASES.items():
if issubclass(plugin_class, base_cls):
return type_name
return 'rdmo_plugin_unknown_type'I kept it as a property in the Plugin model:
@property
def plugin_type(self) -> str:
try:
plugin_class = self.get_class()
except Exception as e:
return e.__class__.__qualname__.lower()
return detect_plugin_type(plugin_class)| verbose_name=_("Python path"), | ||
| ) | ||
| plugin_type = models.CharField(max_length=32, choices=PluginType.choices) | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But what we need to add is plugin_settings which is used to set the settings for this plugin.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the plugin_settings field is there now:
plugin_settings = models.JSONField(
blank=True, default=dict,
verbose_name=_("Plugin settings"),
help_text=_("Contains the settings for this plugin in JSON format."),
)rdmo.config app for Plugin model
|
I'm getting some strange DB errors for mysql in ci(and sqlite in local testing). django.db.utils.OperationalError: foreign key mismatch - "questions_question" referencing "domain_attribute"From the ci logs: # at
query = b'ALTER TABLE `domain_attribute` DROP COLUMN `attributeentity_ptr_id`' django.db.utils.OperationalError:
(1829, "Cannot drop column 'attributeentity_ptr_id':
needed in a foreign key constraint 'questions_questionse_attribute_id_30ee3ea9_fk_domain_at' of table 'questions_questionset'")The problem can be resolved by removing the app |
Think that I found the bug with help of GPT and could fix it by adding a single dependency to the GPT:
|
rdmo.config app for Plugin modelrdmo.config app for Plugin model
|
Ok got it! Good explanation by ChatGPT. This is why you don't do multi-table inheritance and why past-Jochen dismantled it. |
107f379 to
f5eae22
Compare
|
7031a4b to
6875f9a
Compare
6875f9a to
9791229
Compare
dceca19 to
ae887db
Compare
| return self.filter(Q(groups=None) | Q(groups__in=groups)) | ||
|
|
||
|
|
||
| class ForSiteQuerySetMixin: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could implement this already in #1488, see #1488 (comment)
27516be to
4026f9a
Compare
rdmo.config app for Plugin modelrdmo.config app for Plugin model (plugin managament)
Signed-off-by: David Wallace <david.wallace@tu-darmstadt.de>
Signed-off-by: David Wallace <david.wallace@tu-darmstadt.de>
Signed-off-by: David Wallace <david.wallace@tu-darmstadt.de>
e9b3b51 to
0ffb48a
Compare
|
rebased to |
jochenklar
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot for the work! I like the implementation, but I have some requests, in particular with the management scripts.
Additionally, the integration into the old front-end seems to be missing.
I have not tested yet with real plugins, I will do so in the next iteration.
| plugin_type=PluginType.PROJECT_ISSUE_PROVIDER.value, | ||
| format=provider_key | ||
| ) | ||
| provider = plugins.first().initialize_class() if plugins else None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should be try: ... except DoesNotExist:
|
|
||
| dependencies = [ | ||
| ('questions', '0031_rename_attribute_entity_to_attribute'), | ||
| ('domain', '0038_rename_attributeentity_to_attribute'), # post hoc fix for mysql/sqlite |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Didn't we fix this before?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, before in this PR #1436 (comment)
rdmo/options/viewsets.py
Outdated
| queryset = settings.OPTIONSET_PROVIDERS | ||
|
|
||
| def get_queryset(self): | ||
| return getattr(settings, 'OPTIONSET_PROVIDERS', []) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
settings in RDMO should have a default so that we don't need those checks. But I guess OPTIONSET_PROVIDERS is now a queryset anyway so this might be an oversight.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it's an oversight, it needs to query the Plugin objects.
| verbose_name=_('Conditions'), | ||
| help_text=_('The list of conditions evaluated for this option set.') | ||
| ) | ||
| plugins = models.ManyToManyField( # can not import Plugin due to circular import |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting, we now have multiple plugins for an optionset, lets see what crasy things people will do with it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could be crazy?! 😏 https://github.com/rdmorganiser/rdmo-plugins-generic-search
| from django.utils.dateparse import parse_date | ||
| from django.utils.encoding import force_str | ||
| from django.utils.formats import get_format | ||
| from django.utils.module_loading import import_string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this exists since Django 1.7? 🤯
| <Tabs id="#plugin-tabs" defaultActiveKey={0} animation={false}> | ||
| { | ||
| config.settings && config.settings.languages.map(([lang_code, lang], index) => ( | ||
| <Tab className="pt-10" key={index} eventKey={index} title={lang}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
help is missing here.
| const [value, setValue] = useState(formatValue(element[field])) | ||
| const [parseError, setParseError] = useState(false) | ||
|
|
||
| useEffect(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is buggy, if I type something in the field it (almost) instantly runs the validation, which is different from the other fields. I would prefer that the indenting happens only after pressing save.
rdmo/config/models.py
Outdated
| verbose_name_plural = _('Plugins') | ||
|
|
||
| def __str__(self): | ||
| return f"({self.python_path}, {self.plugin_type}) {self.uri}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be just the URI.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could add that f-string to a __repr__ right?!
| models.QuerySet): | ||
|
|
||
| def filter_for_project(self, project): | ||
| return ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to check for availability. Right now, I can export using an unavailable Plugin.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still need to look into this, I though I'm using only the for_context query (it has a check for availability) for the Plugins and this filter_for_project is used inside of it.
|
The test plugins can be used in the import importlib.util
import sys
from pathlib import Path
rdmo_path = Path(importlib.util.find_spec('rdmo').origin).parent.parent
sys.path.append(str(rdmo_path / 'testing'))
INSTALLED_APPS += ['plugins']to the settings. |
Signed-off-by: David Wallace <david.wallace@tu-darmstadt.de>
Signed-off-by: David Wallace <david.wallace@tu-darmstadt.de>
Signed-off-by: David Wallace <david.wallace@tu-darmstadt.de>
Signed-off-by: David Wallace <david.wallace@tu-darmstadt.de>
Signed-off-by: David Wallace <david.wallace@tu-darmstadt.de>
Signed-off-by: David Wallace <david.wallace@tu-darmstadt.de>
| format=self.provider_key) | ||
| ) | ||
| if plugins.exists(): | ||
| return plugins.first().initialize_class() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently this will "arbitrarily" only return the first plugin instance as provider. At some other places in the code I also simply return plugins.first().initialize_class(), this was a temporary hack to make a working version.
How should it be handled when there are multiple plugin instances available as providers? Should a new property like providers be added?
Signed-off-by: David Wallace <david.wallace@tu-darmstadt.de>
Signed-off-by: David Wallace <david.wallace@tu-darmstadt.de>
Signed-off-by: David Wallace <david.wallace@tu-darmstadt.de>
Signed-off-by: David Wallace <david.wallace@tu-darmstadt.de>
Signed-off-by: David Wallace <david.wallace@tu-darmstadt.de>
Signed-off-by: David Wallace <david.wallace@tu-darmstadt.de>
Signed-off-by: David Wallace <david.wallace@tu-darmstadt.de>
Signed-off-by: David Wallace <david.wallace@tu-darmstadt.de>
Signed-off-by: David Wallace <david.wallace@tu-darmstadt.de>
Signed-off-by: David Wallace <david.wallace@tu-darmstadt.de>
Signed-off-by: David Wallace <david.wallace@tu-darmstadt.de>
Signed-off-by: David Wallace <david.wallace@tu-darmstadt.de>
Signed-off-by: David Wallace <david.wallace@tu-darmstadt.de>
Description
rdmo.configappPluginmodelPluginbehaves similar to any other element (Catalog, Taks, View)PLUGINS = [ .. ]which replaces the legacy settings (e.g.PROJECT_IMPORT).Deprecations and legacy
rdmo.core.pluginsrdmo.config.pluginsand renamed toPluginBaseRelated issue: #1413