2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-06-15 19:45:46 +00:00

fix docstrings 5

This commit is contained in:
Matthias
2022-05-28 02:51:15 +02:00
parent 61287dba2b
commit 391c8b4ac1
7 changed files with 85 additions and 219 deletions

View File

@ -1,6 +1,5 @@
""" """Plugin mixin classes for barcode plugin"""
Plugin mixin classes for barcode plugin
"""
import hashlib import hashlib
import string import string
@ -10,15 +9,13 @@ from stock.serializers import LocationSerializer, StockItemSerializer
def hash_barcode(barcode_data): def hash_barcode(barcode_data):
""" """Calculate an MD5 hash of barcode data.
Calculate an MD5 hash of barcode data.
HACK: Remove any 'non printable' characters from the hash, HACK: Remove any 'non printable' characters from the hash,
as it seems browers will remove special control characters... as it seems browers will remove special control characters...
TODO: Work out a way around this! TODO: Work out a way around this!
""" """
barcode_data = str(barcode_data).strip() barcode_data = str(barcode_data).strip()
printable_chars = filter(lambda x: x in string.printable, barcode_data) printable_chars = filter(lambda x: x in string.printable, barcode_data)
@ -30,16 +27,16 @@ def hash_barcode(barcode_data):
class BarcodeMixin: class BarcodeMixin:
""" """Mixin that enables barcode handeling
Mixin that enables barcode handeling
Custom barcode plugins should use and extend this mixin as necessary. Custom barcode plugins should use and extend this mixin as necessary.
""" """
ACTION_NAME = "" ACTION_NAME = ""
class MixinMeta: class MixinMeta:
""" """Meta options for this mixin"""
meta options for this mixin
"""
MIXIN_NAME = 'Barcode' MIXIN_NAME = 'Barcode'
def __init__(self): def __init__(self):
@ -48,35 +45,27 @@ class BarcodeMixin:
@property @property
def has_barcode(self): def has_barcode(self):
""" """Does this plugin have everything needed to process a barcode"""
Does this plugin have everything needed to process a barcode
"""
return True return True
def init(self, barcode_data): def init(self, barcode_data):
""" """Initialize the BarcodePlugin instance
Initialize the BarcodePlugin instance
Args: Args:
barcode_data - The raw barcode data barcode_data - The raw barcode data
""" """
self.data = barcode_data self.data = barcode_data
def getStockItem(self): def getStockItem(self):
""" """Attempt to retrieve a StockItem associated with this barcode.
Attempt to retrieve a StockItem associated with this barcode.
Default implementation returns None Default implementation returns None
""" """
return None # pragma: no cover return None # pragma: no cover
def getStockItemByHash(self): def getStockItemByHash(self):
"""Attempt to retrieve a StockItem associated with this barcode, based on the barcode hash.
""" """
Attempt to retrieve a StockItem associated with this barcode,
based on the barcode hash.
"""
try: try:
item = StockItem.objects.get(uid=self.hash()) item = StockItem.objects.get(uid=self.hash())
return item return item
@ -84,48 +73,37 @@ class BarcodeMixin:
return None return None
def renderStockItem(self, item): def renderStockItem(self, item):
""" """Render a stock item to JSON response"""
Render a stock item to JSON response
"""
serializer = StockItemSerializer(item, part_detail=True, location_detail=True, supplier_part_detail=True) serializer = StockItemSerializer(item, part_detail=True, location_detail=True, supplier_part_detail=True)
return serializer.data return serializer.data
def getStockLocation(self): def getStockLocation(self):
""" """Attempt to retrieve a StockLocation associated with this barcode.
Attempt to retrieve a StockLocation associated with this barcode.
Default implementation returns None Default implementation returns None
""" """
return None # pragma: no cover return None # pragma: no cover
def renderStockLocation(self, loc): def renderStockLocation(self, loc):
""" """Render a stock location to a JSON response"""
Render a stock location to a JSON response
"""
serializer = LocationSerializer(loc) serializer = LocationSerializer(loc)
return serializer.data return serializer.data
def getPart(self): def getPart(self):
""" """Attempt to retrieve a Part associated with this barcode.
Attempt to retrieve a Part associated with this barcode.
Default implementation returns None Default implementation returns None
""" """
return None # pragma: no cover return None # pragma: no cover
def renderPart(self, part): def renderPart(self, part):
""" """Render a part to JSON response"""
Render a part to JSON response
"""
serializer = PartSerializer(part) serializer = PartSerializer(part)
return serializer.data return serializer.data
def hash(self): def hash(self):
""" """Calculate a hash for the barcode data.
Calculate a hash for the barcode data.
This is supposed to uniquely identify the barcode contents, This is supposed to uniquely identify the barcode contents,
at least within the bardcode sub-type. at least within the bardcode sub-type.
@ -134,13 +112,9 @@ class BarcodeMixin:
This may be sufficient for most applications, but can obviously be overridden This may be sufficient for most applications, but can obviously be overridden
by a subclass. by a subclass.
""" """
return hash_barcode(self.data) return hash_barcode(self.data)
def validate(self): def validate(self):
""" """Default implementation returns False"""
Default implementation returns False
"""
return False # pragma: no cover return False # pragma: no cover

View File

@ -1,8 +1,4 @@
# -*- coding: utf-8 -*- """Unit tests for Barcode endpoints"""
"""
Unit tests for Barcode endpoints
"""
from django.urls import reverse from django.urls import reverse
@ -62,10 +58,7 @@ class BarcodeAPITest(InvenTreeAPITestCase):
self.assertIsNone(data['plugin']) self.assertIsNone(data['plugin'])
def test_find_part(self): def test_find_part(self):
""" """Test that we can lookup a part based on ID"""
Test that we can lookup a part based on ID
"""
response = self.client.post( response = self.client.post(
self.scan_url, self.scan_url,
{ {
@ -98,10 +91,7 @@ class BarcodeAPITest(InvenTreeAPITestCase):
self.assertEqual(response.data['part'], 'Part does not exist') self.assertEqual(response.data['part'], 'Part does not exist')
def test_find_stock_item(self): def test_find_stock_item(self):
""" """Test that we can lookup a stock item based on ID"""
Test that we can lookup a stock item based on ID
"""
response = self.client.post( response = self.client.post(
self.scan_url, self.scan_url,
{ {
@ -119,7 +109,6 @@ class BarcodeAPITest(InvenTreeAPITestCase):
def test_invalid_item(self): def test_invalid_item(self):
"""Test response for invalid stock item""" """Test response for invalid stock item"""
response = self.client.post( response = self.client.post(
self.scan_url, self.scan_url,
{ {
@ -135,10 +124,7 @@ class BarcodeAPITest(InvenTreeAPITestCase):
self.assertEqual(response.data['stockitem'], 'Stock item does not exist') self.assertEqual(response.data['stockitem'], 'Stock item does not exist')
def test_find_location(self): def test_find_location(self):
""" """Test that we can lookup a stock location based on ID"""
Test that we can lookup a stock location based on ID
"""
response = self.client.post( response = self.client.post(
self.scan_url, self.scan_url,
{ {
@ -156,7 +142,6 @@ class BarcodeAPITest(InvenTreeAPITestCase):
def test_invalid_location(self): def test_invalid_location(self):
"""Test response for an invalid location""" """Test response for an invalid location"""
response = self.client.post( response = self.client.post(
self.scan_url, self.scan_url,
{ {
@ -215,10 +200,7 @@ class BarcodeAPITest(InvenTreeAPITestCase):
self.assertEqual(pk, item.pk) self.assertEqual(pk, item.pk)
def test_association(self): def test_association(self):
""" """Test that a barcode can be associated with a StockItem"""
Test that a barcode can be associated with a StockItem
"""
item = StockItem.objects.get(pk=522) item = StockItem.objects.get(pk=522)
self.assertEqual(len(item.uid), 0) self.assertEqual(len(item.uid), 0)

View File

@ -1,6 +1,4 @@
""" """Functions for triggering and responding to server side events"""
Functions for triggering and responding to server side events
"""
import logging import logging
@ -17,13 +15,11 @@ logger = logging.getLogger('inventree')
def trigger_event(event, *args, **kwargs): def trigger_event(event, *args, **kwargs):
""" """Trigger an event with optional arguments.
Trigger an event with optional arguments.
This event will be stored in the database, This event will be stored in the database,
and the worker will respond to it later on. and the worker will respond to it later on.
""" """
if not settings.PLUGINS_ENABLED: if not settings.PLUGINS_ENABLED:
# Do nothing if plugins are not enabled # Do nothing if plugins are not enabled
return # pragma: no cover return # pragma: no cover
@ -44,8 +40,7 @@ def trigger_event(event, *args, **kwargs):
def register_event(event, *args, **kwargs): def register_event(event, *args, **kwargs):
""" """Register the event with any interested plugins.
Register the event with any interested plugins.
Note: This function is processed by the background worker, Note: This function is processed by the background worker,
as it performs multiple database access operations. as it performs multiple database access operations.
@ -80,14 +75,11 @@ def register_event(event, *args, **kwargs):
def process_event(plugin_slug, event, *args, **kwargs): def process_event(plugin_slug, event, *args, **kwargs):
""" """Respond to a triggered event.
Respond to a triggered event.
This function is run by the background worker process. This function is run by the background worker process.
This function may queue multiple functions to be handled by the background worker. This function may queue multiple functions to be handled by the background worker.
""" """
logger.info(f"Plugin '{plugin_slug}' is processing triggered event '{event}'") logger.info(f"Plugin '{plugin_slug}' is processing triggered event '{event}'")
plugin = registry.plugins.get(plugin_slug, None) plugin = registry.plugins.get(plugin_slug, None)
@ -100,11 +92,10 @@ def process_event(plugin_slug, event, *args, **kwargs):
def allow_table_event(table_name): def allow_table_event(table_name):
""" """Determine if an automatic event should be fired for a given table.
Determine if an automatic event should be fired for a given table.
We *do not* want events to be fired for some tables! We *do not* want events to be fired for some tables!
""" """
if isImportingData(): if isImportingData():
# Prevent table events during the data import process # Prevent table events during the data import process
return False # pragma: no cover return False # pragma: no cover
@ -143,10 +134,7 @@ def allow_table_event(table_name):
@receiver(post_save) @receiver(post_save)
def after_save(sender, instance, created, **kwargs): def after_save(sender, instance, created, **kwargs):
""" """Trigger an event whenever a database entry is saved"""
Trigger an event whenever a database entry is saved
"""
table = sender.objects.model._meta.db_table table = sender.objects.model._meta.db_table
instance_id = getattr(instance, 'id', None) instance_id = getattr(instance, 'id', None)
@ -173,10 +161,7 @@ def after_save(sender, instance, created, **kwargs):
@receiver(post_delete) @receiver(post_delete)
def after_delete(sender, instance, **kwargs): def after_delete(sender, instance, **kwargs):
""" """Trigger an event whenever a database entry is deleted"""
Trigger an event whenever a database entry is deleted
"""
table = sender.objects.model._meta.db_table table = sender.objects.model._meta.db_table
if not allow_table_event(table): if not allow_table_event(table):

View File

@ -4,24 +4,22 @@ from plugin.helpers import MixinNotImplementedError
class EventMixin: class EventMixin:
""" """Mixin that provides support for responding to triggered events.
Mixin that provides support for responding to triggered events.
Implementing classes must provide a "process_event" function: Implementing classes must provide a "process_event" function:
""" """
def process_event(self, event, *args, **kwargs): def process_event(self, event, *args, **kwargs):
""" """Function to handle events
Function to handle events
Must be overridden by plugin Must be overridden by plugin
""" """
# Default implementation does not do anything # Default implementation does not do anything
raise MixinNotImplementedError raise MixinNotImplementedError
class MixinMeta: class MixinMeta:
""" """Meta options for this mixin"""
Meta options for this mixin
"""
MIXIN_NAME = 'Events' MIXIN_NAME = 'Events'
def __init__(self): def __init__(self):

View File

@ -1,6 +1,4 @@
""" """Plugin mixin classes"""
Plugin mixin classes
"""
import json import json
import logging import logging
@ -21,9 +19,7 @@ logger = logging.getLogger('inventree')
class SettingsMixin: class SettingsMixin:
""" """Mixin that enables global settings for the plugin"""
Mixin that enables global settings for the plugin
"""
class MixinMeta: class MixinMeta:
MIXIN_NAME = 'Settings' MIXIN_NAME = 'Settings'
@ -35,23 +31,15 @@ class SettingsMixin:
@property @property
def has_settings(self): def has_settings(self):
""" """Does this plugin use custom global settings"""
Does this plugin use custom global settings
"""
return bool(self.settings) return bool(self.settings)
def get_setting(self, key): def get_setting(self, key):
""" """Return the 'value' of the setting associated with this plugin"""
Return the 'value' of the setting associated with this plugin
"""
return PluginSetting.get_setting(key, plugin=self) return PluginSetting.get_setting(key, plugin=self)
def set_setting(self, key, value, user=None): def set_setting(self, key, value, user=None):
""" """Set plugin setting value by key"""
Set plugin setting value by key
"""
try: try:
plugin, _ = PluginConfig.objects.get_or_create(key=self.plugin_slug(), name=self.plugin_name()) plugin, _ = PluginConfig.objects.get_or_create(key=self.plugin_slug(), name=self.plugin_name())
except (OperationalError, ProgrammingError): # pragma: no cover except (OperationalError, ProgrammingError): # pragma: no cover
@ -66,8 +54,7 @@ class SettingsMixin:
class ScheduleMixin: class ScheduleMixin:
""" """Mixin that provides support for scheduled tasks.
Mixin that provides support for scheduled tasks.
Implementing classes must provide a dict object called SCHEDULED_TASKS, Implementing classes must provide a dict object called SCHEDULED_TASKS,
which provides information on the tasks to be scheduled. which provides information on the tasks to be scheduled.
@ -99,9 +86,8 @@ class ScheduleMixin:
SCHEDULED_TASKS = {} SCHEDULED_TASKS = {}
class MixinMeta: class MixinMeta:
""" """Meta options for this mixin"""
Meta options for this mixin
"""
MIXIN_NAME = 'Schedule' MIXIN_NAME = 'Schedule'
def __init__(self): def __init__(self):
@ -116,16 +102,11 @@ class ScheduleMixin:
@property @property
def has_scheduled_tasks(self): def has_scheduled_tasks(self):
""" """Are tasks defined for this plugin"""
Are tasks defined for this plugin
"""
return bool(self.scheduled_tasks) return bool(self.scheduled_tasks)
def validate_scheduled_tasks(self): def validate_scheduled_tasks(self):
""" """Check that the provided scheduled tasks are valid"""
Check that the provided scheduled tasks are valid
"""
if not self.has_scheduled_tasks: if not self.has_scheduled_tasks:
raise MixinImplementationError("SCHEDULED_TASKS not defined") raise MixinImplementationError("SCHEDULED_TASKS not defined")
@ -147,25 +128,18 @@ class ScheduleMixin:
raise MixinImplementationError(f"Task '{key}' is missing 'minutes' parameter") raise MixinImplementationError(f"Task '{key}' is missing 'minutes' parameter")
def get_task_name(self, key): def get_task_name(self, key):
""" """Task name for key"""
Task name for key
"""
# Generate a 'unique' task name # Generate a 'unique' task name
slug = self.plugin_slug() slug = self.plugin_slug()
return f"plugin.{slug}.{key}" return f"plugin.{slug}.{key}"
def get_task_names(self): def get_task_names(self):
""" """All defined task names"""
All defined task names
"""
# Returns a list of all task names associated with this plugin instance # Returns a list of all task names associated with this plugin instance
return [self.get_task_name(key) for key in self.scheduled_tasks.keys()] return [self.get_task_name(key) for key in self.scheduled_tasks.keys()]
def register_tasks(self): def register_tasks(self):
""" """Register the tasks with the database"""
Register the tasks with the database
"""
try: try:
from django_q.models import Schedule from django_q.models import Schedule
@ -182,10 +156,7 @@ class ScheduleMixin:
func_name = task['func'].strip() func_name = task['func'].strip()
if '.' in func_name: if '.' in func_name:
""" """Dotted notation indicates that we wish to run a globally defined function, from a specified Python module."""
Dotted notation indicates that we wish to run a globally defined function,
from a specified Python module.
"""
Schedule.objects.create( Schedule.objects.create(
name=task_name, name=task_name,
@ -196,8 +167,7 @@ class ScheduleMixin:
) )
else: else:
""" """Non-dotted notation indicates that we wish to call a 'member function' of the calling plugin.
Non-dotted notation indicates that we wish to call a 'member function' of the calling plugin.
This is managed by the plugin registry itself. This is managed by the plugin registry itself.
""" """
@ -218,10 +188,7 @@ class ScheduleMixin:
logger.warning("register_tasks failed, database not ready") logger.warning("register_tasks failed, database not ready")
def unregister_tasks(self): def unregister_tasks(self):
""" """Deregister the tasks with the database"""
Deregister the tasks with the database
"""
try: try:
from django_q.models import Schedule from django_q.models import Schedule
@ -240,14 +207,11 @@ class ScheduleMixin:
class UrlsMixin: class UrlsMixin:
""" """Mixin that enables custom URLs for the plugin"""
Mixin that enables custom URLs for the plugin
"""
class MixinMeta: class MixinMeta:
""" """Meta options for this mixin"""
Meta options for this mixin
"""
MIXIN_NAME = 'URLs' MIXIN_NAME = 'URLs'
def __init__(self): def __init__(self):
@ -256,54 +220,41 @@ class UrlsMixin:
self.urls = self.setup_urls() self.urls = self.setup_urls()
def setup_urls(self): def setup_urls(self):
""" """Setup url endpoints for this plugin"""
Setup url endpoints for this plugin
"""
return getattr(self, 'URLS', None) return getattr(self, 'URLS', None)
@property @property
def base_url(self): def base_url(self):
""" """Base url for this plugin"""
Base url for this plugin
"""
return f'{PLUGIN_BASE}/{self.slug}/' return f'{PLUGIN_BASE}/{self.slug}/'
@property @property
def internal_name(self): def internal_name(self):
""" """Internal url pattern name"""
Internal url pattern name
"""
return f'plugin:{self.slug}:' return f'plugin:{self.slug}:'
@property @property
def urlpatterns(self): def urlpatterns(self):
""" """Urlpatterns for this plugin"""
Urlpatterns for this plugin
"""
if self.has_urls: if self.has_urls:
return re_path(f'^{self.slug}/', include((self.urls, self.slug)), name=self.slug) return re_path(f'^{self.slug}/', include((self.urls, self.slug)), name=self.slug)
return None return None
@property @property
def has_urls(self): def has_urls(self):
""" """Does this plugin use custom urls"""
Does this plugin use custom urls
"""
return bool(self.urls) return bool(self.urls)
class NavigationMixin: class NavigationMixin:
""" """Mixin that enables custom navigation links with the plugin"""
Mixin that enables custom navigation links with the plugin
"""
NAVIGATION_TAB_NAME = None NAVIGATION_TAB_NAME = None
NAVIGATION_TAB_ICON = "fas fa-question" NAVIGATION_TAB_ICON = "fas fa-question"
class MixinMeta: class MixinMeta:
""" """Meta options for this mixin"""
Meta options for this mixin
"""
MIXIN_NAME = 'Navigation Links' MIXIN_NAME = 'Navigation Links'
def __init__(self): def __init__(self):
@ -312,9 +263,7 @@ class NavigationMixin:
self.navigation = self.setup_navigation() self.navigation = self.setup_navigation()
def setup_navigation(self): def setup_navigation(self):
""" """Setup navigation links for this plugin"""
Setup navigation links for this plugin
"""
nav_links = getattr(self, 'NAVIGATION', None) nav_links = getattr(self, 'NAVIGATION', None)
if nav_links: if nav_links:
# check if needed values are configured # check if needed values are configured
@ -325,16 +274,12 @@ class NavigationMixin:
@property @property
def has_naviation(self): def has_naviation(self):
""" """Does this plugin define navigation elements"""
Does this plugin define navigation elements
"""
return bool(self.navigation) return bool(self.navigation)
@property @property
def navigation_name(self): def navigation_name(self):
""" """Name for navigation tab"""
Name for navigation tab
"""
name = getattr(self, 'NAVIGATION_TAB_NAME', None) name = getattr(self, 'NAVIGATION_TAB_NAME', None)
if not name: if not name:
name = self.human_name name = self.human_name
@ -342,21 +287,16 @@ class NavigationMixin:
@property @property
def navigation_icon(self): def navigation_icon(self):
""" """Icon-name for navigation tab"""
Icon-name for navigation tab
"""
return getattr(self, 'NAVIGATION_TAB_ICON', "fas fa-question") return getattr(self, 'NAVIGATION_TAB_ICON', "fas fa-question")
class AppMixin: class AppMixin:
""" """Mixin that enables full django app functions for a plugin"""
Mixin that enables full django app functions for a plugin
"""
class MixinMeta: class MixinMeta:
"""m """Meta options for this mixin"""
Mta options for this mixin
"""
MIXIN_NAME = 'App registration' MIXIN_NAME = 'App registration'
def __init__(self): def __init__(self):
@ -365,15 +305,12 @@ class AppMixin:
@property @property
def has_app(self): def has_app(self):
""" """This plugin is always an app with this plugin"""
This plugin is always an app with this plugin
"""
return True return True
class APICallMixin: class APICallMixin:
""" """Mixin that enables easier API calls for a plugin
Mixin that enables easier API calls for a plugin
Steps to set up: Steps to set up:
1. Add this mixin before (left of) SettingsMixin and PluginBase 1. Add this mixin before (left of) SettingsMixin and PluginBase
@ -424,7 +361,7 @@ class APICallMixin:
API_TOKEN = 'Bearer' API_TOKEN = 'Bearer'
class MixinMeta: class MixinMeta:
"""meta options for this mixin""" """Meta options for this mixin"""
MIXIN_NAME = 'API calls' MIXIN_NAME = 'API calls'
def __init__(self): def __init__(self):
@ -487,8 +424,7 @@ class APICallMixin:
class PanelMixin: class PanelMixin:
""" """Mixin which allows integration of custom 'panels' into a particular page.
Mixin which allows integration of custom 'panels' into a particular page.
The mixin provides a number of key functionalities: The mixin provides a number of key functionalities:
@ -540,17 +476,15 @@ class PanelMixin:
self.add_mixin('panel', True, __class__) self.add_mixin('panel', True, __class__)
def get_custom_panels(self, view, request): def get_custom_panels(self, view, request):
""" This method *must* be implemented by the plugin class """ """This method *must* be implemented by the plugin class"""
raise MixinNotImplementedError(f"{__class__} is missing the 'get_custom_panels' method") raise MixinNotImplementedError(f"{__class__} is missing the 'get_custom_panels' method")
def get_panel_context(self, view, request, context): def get_panel_context(self, view, request, context):
""" """Build the context data to be used for template rendering.
Build the context data to be used for template rendering.
Custom class can override this to provide any custom context data. Custom class can override this to provide any custom context data.
(See the example in "custom_panel_sample.py") (See the example in "custom_panel_sample.py")
""" """
# Provide some standard context items to the template for rendering # Provide some standard context items to the template for rendering
context['plugin'] = self context['plugin'] = self
context['request'] = request context['request'] = request

View File

@ -1,4 +1,4 @@
""" Unit tests for base mixins for plugins """ """Unit tests for base mixins for plugins"""
from django.conf import settings from django.conf import settings
from django.test import TestCase from django.test import TestCase
@ -170,9 +170,7 @@ class APICallMixinTest(BaseMixinDefinition, TestCase):
API_TOKEN_SETTING = 'API_TOKEN' API_TOKEN_SETTING = 'API_TOKEN'
def get_external_url(self, simple: bool = True): def get_external_url(self, simple: bool = True):
''' """Returns data from the sample endpoint"""
returns data from the sample endpoint
'''
return self.api_call('api/users/2', simple_response=simple) return self.api_call('api/users/2', simple_response=simple)
self.mixin = MixinCls() self.mixin = MixinCls()
@ -263,7 +261,6 @@ class PanelMixinTests(InvenTreeTestCase):
def test_installed(self): def test_installed(self):
"""Test that the sample panel plugin is installed""" """Test that the sample panel plugin is installed"""
plugins = registry.with_mixin('panel') plugins = registry.with_mixin('panel')
self.assertTrue(len(plugins) > 0) self.assertTrue(len(plugins) > 0)
@ -276,7 +273,6 @@ class PanelMixinTests(InvenTreeTestCase):
def test_disabled(self): def test_disabled(self):
"""Test that the panels *do not load* if the plugin is not enabled""" """Test that the panels *do not load* if the plugin is not enabled"""
plugin = registry.get_plugin('samplepanel') plugin = registry.get_plugin('samplepanel')
plugin.set_setting('ENABLE_HELLO_WORLD', True) plugin.set_setting('ENABLE_HELLO_WORLD', True)
@ -308,7 +304,6 @@ class PanelMixinTests(InvenTreeTestCase):
""" """
Test that the panels *do* load if the plugin is enabled Test that the panels *do* load if the plugin is enabled
""" """
plugin = registry.get_plugin('samplepanel') plugin = registry.get_plugin('samplepanel')
self.assertEqual(len(registry.with_mixin('panel', active=True)), 0) self.assertEqual(len(registry.with_mixin('panel', active=True)), 0)
@ -383,7 +378,6 @@ class PanelMixinTests(InvenTreeTestCase):
def test_mixin(self): def test_mixin(self):
"""Test that ImplementationError is raised""" """Test that ImplementationError is raised"""
with self.assertRaises(MixinNotImplementedError): with self.assertRaises(MixinNotImplementedError):
class Wrong(PanelMixin, InvenTreePlugin): class Wrong(PanelMixin, InvenTreePlugin):
pass pass

View File

@ -1,4 +1,5 @@
"""Functions to print a label to a mixin printer""" """Functions to print a label to a mixin printer"""
import logging import logging
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
@ -10,8 +11,7 @@ logger = logging.getLogger('inventree')
def print_label(plugin_slug, label_image, label_instance=None, user=None): def print_label(plugin_slug, label_image, label_instance=None, user=None):
""" """Print label with the provided plugin.
Print label with the provided plugin.
This task is nominally handled by the background worker. This task is nominally handled by the background worker.
@ -21,7 +21,6 @@ def print_label(plugin_slug, label_image, label_instance=None, user=None):
plugin_slug: The unique slug (key) of the plugin plugin_slug: The unique slug (key) of the plugin
label_image: A PIL.Image image object to be printed label_image: A PIL.Image image object to be printed
""" """
logger.info(f"Plugin '{plugin_slug}' is printing a label") logger.info(f"Plugin '{plugin_slug}' is printing a label")
plugin = registry.plugins.get(plugin_slug, None) plugin = registry.plugins.get(plugin_slug, None)