Clean up the application registry

This commit is contained in:
jeremystretch 2023-02-19 13:58:01 -05:00
parent c84f0de8f8
commit c109daf1d8
6 changed files with 53 additions and 65 deletions

View File

@ -1,14 +1,2 @@
# Webhook content types
HTTP_CONTENT_TYPE_JSON = 'application/json'
# Registerable extras features
EXTRAS_FEATURES = [
'custom_fields',
'custom_links',
'export_templates',
'job_results',
'journaling',
'synced_data',
'tags',
'webhooks'
]

View File

@ -14,13 +14,13 @@ from .registration import *
from .templates import *
# Initialize plugin registry
registry['plugins'] = {
registry['plugins'].update({
'graphql_schemas': [],
'menus': [],
'menu_items': {},
'preferences': {},
'template_extensions': collections.defaultdict(list),
}
})
DEFAULT_RESOURCE_PATHS = {
'search_indexes': 'search.indexes',

View File

@ -2,7 +2,6 @@ from django.db.models import Q
from django.utils.deconstruct import deconstructible
from taggit.managers import _TaggableManager
from extras.constants import EXTRAS_FEATURES
from netbox.registry import registry
@ -18,7 +17,7 @@ def is_taggable(obj):
def image_upload(instance, filename):
"""
Return a path for uploading image attchments.
Return a path for uploading image attachments.
"""
path = 'image-attachments/'
@ -56,8 +55,14 @@ class FeatureQuery:
def register_features(model, features):
"""
Register model features in the application registry.
"""
app_label, model_name = model._meta.label_lower.split('.')
for feature in features:
if feature not in EXTRAS_FEATURES:
raise ValueError(f"{feature} is not a valid extras feature!")
app_label, model_name = model._meta.label_lower.split('.')
registry['model_features'][feature][app_label].add(model_name)
try:
registry['model_features'][feature][app_label].add(model_name)
except KeyError:
raise KeyError(
f"{feature} is not a valid model feature! Valid keys are: {registry['model_features'].keys()}"
)

View File

@ -12,6 +12,7 @@ from taggit.managers import TaggableManager
from extras.choices import CustomFieldVisibilityChoices, ObjectChangeActionChoices
from extras.utils import is_taggable, register_features
from netbox.registry import registry
from netbox.signals import post_clean
from utilities.json import CustomFieldJSONEncoder
from utilities.utils import serialize_object
@ -388,22 +389,26 @@ class SyncedDataMixin(models.Model):
raise NotImplementedError(f"{self.__class__} must implement a sync_data() method.")
FEATURES_MAP = (
('custom_fields', CustomFieldsMixin),
('custom_links', CustomLinksMixin),
('export_templates', ExportTemplatesMixin),
('job_results', JobResultsMixin),
('journaling', JournalingMixin),
('synced_data', SyncedDataMixin),
('tags', TagsMixin),
('webhooks', WebhooksMixin),
)
FEATURES_MAP = {
'custom_fields': CustomFieldsMixin,
'custom_links': CustomLinksMixin,
'export_templates': ExportTemplatesMixin,
'job_results': JobResultsMixin,
'journaling': JournalingMixin,
'synced_data': SyncedDataMixin,
'tags': TagsMixin,
'webhooks': WebhooksMixin,
}
registry['model_features'].update({
feature: defaultdict(set) for feature in FEATURES_MAP.keys()
})
@receiver(class_prepared)
def _register_features(sender, **kwargs):
features = {
feature for feature, cls in FEATURES_MAP if issubclass(sender, cls)
feature for feature, cls in FEATURES_MAP.items() if issubclass(sender, cls)
}
register_features(sender, features)

View File

@ -1,12 +1,10 @@
import collections
from extras.constants import EXTRAS_FEATURES
class Registry(dict):
"""
Central registry for registration of functionality. Once a store (key) is defined, it cannot be overwritten or
deleted (although its value may be manipulated).
Central registry for registration of functionality. Once a Registry is initialized, keys cannot be added or
removed (though the value of each key is mutable).
"""
def __getitem__(self, key):
try:
@ -15,20 +13,18 @@ class Registry(dict):
raise KeyError(f"Invalid store: {key}")
def __setitem__(self, key, value):
if key in self:
raise KeyError(f"Store already set: {key}")
super().__setitem__(key, value)
raise TypeError("Cannot add stores to registry after initialization")
def __delitem__(self, key):
raise TypeError("Cannot delete stores from registry")
# Initialize the global registry
registry = Registry()
registry['data_backends'] = dict()
registry['denormalized_fields'] = collections.defaultdict(list)
registry['model_features'] = {
feature: collections.defaultdict(set) for feature in EXTRAS_FEATURES
}
registry['search'] = dict()
registry['views'] = collections.defaultdict(dict)
registry = Registry({
'data_backends': dict(),
'denormalized_fields': collections.defaultdict(list),
'model_features': dict(),
'plugins': dict(),
'search': dict(),
'views': collections.defaultdict(dict),
})

View File

@ -5,29 +5,23 @@ from netbox.registry import Registry
class RegistryTest(TestCase):
def test_add_store(self):
reg = Registry()
reg['foo'] = 123
def test_set_store(self):
reg = Registry({
'foo': 123,
})
with self.assertRaises(TypeError):
reg['bar'] = 456
self.assertEqual(reg['foo'], 123)
def test_manipulate_store(self):
reg = Registry()
reg['foo'] = [1, 2]
def test_mutate_store(self):
reg = Registry({
'foo': [1, 2],
})
reg['foo'].append(3)
self.assertListEqual(reg['foo'], [1, 2, 3])
def test_overwrite_store(self):
reg = Registry()
reg['foo'] = 123
with self.assertRaises(KeyError):
reg['foo'] = 456
def test_delete_store(self):
reg = Registry()
reg['foo'] = 123
reg = Registry({
'foo': 123,
})
with self.assertRaises(TypeError):
del reg['foo']