From 391c8b4ac19e51b1ef197b10de4defd919cedae1 Mon Sep 17 00:00:00 2001
From: Matthias <code@mjmair.com>
Date: Sat, 28 May 2022 02:51:15 +0200
Subject: [PATCH] fix docstrings 5

---
 InvenTree/plugin/base/barcodes/mixins.py      |  72 +++------
 .../plugin/base/barcodes/test_barcode.py      |  28 +---
 InvenTree/plugin/base/event/events.py         |  31 +---
 InvenTree/plugin/base/event/mixins.py         |  12 +-
 InvenTree/plugin/base/integration/mixins.py   | 146 +++++-------------
 .../plugin/base/integration/test_mixins.py    |  10 +-
 InvenTree/plugin/base/label/label.py          |   5 +-
 7 files changed, 85 insertions(+), 219 deletions(-)

diff --git a/InvenTree/plugin/base/barcodes/mixins.py b/InvenTree/plugin/base/barcodes/mixins.py
index ef3b6004ee..ce87f8163f 100644
--- a/InvenTree/plugin/base/barcodes/mixins.py
+++ b/InvenTree/plugin/base/barcodes/mixins.py
@@ -1,6 +1,5 @@
-"""
-Plugin mixin classes for barcode plugin
-"""
+"""Plugin mixin classes for barcode plugin"""
+
 import hashlib
 import string
 
@@ -10,15 +9,13 @@ from stock.serializers import LocationSerializer, StockItemSerializer
 
 
 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,
           as it seems browers will remove special control characters...
 
     TODO: Work out a way around this!
     """
-
     barcode_data = str(barcode_data).strip()
 
     printable_chars = filter(lambda x: x in string.printable, barcode_data)
@@ -30,16 +27,16 @@ def hash_barcode(barcode_data):
 
 
 class BarcodeMixin:
-    """
-    Mixin that enables barcode handeling
+    """Mixin that enables barcode handeling
+
     Custom barcode plugins should use and extend this mixin as necessary.
     """
+
     ACTION_NAME = ""
 
     class MixinMeta:
-        """
-        meta options for this mixin
-        """
+        """Meta options for this mixin"""
+
         MIXIN_NAME = 'Barcode'
 
     def __init__(self):
@@ -48,35 +45,27 @@ class BarcodeMixin:
 
     @property
     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
 
     def init(self, barcode_data):
-        """
-        Initialize the BarcodePlugin instance
+        """Initialize the BarcodePlugin instance
 
         Args:
             barcode_data - The raw barcode data
         """
-
         self.data = barcode_data
 
     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
         """
-
         return None  # pragma: no cover
 
     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:
             item = StockItem.objects.get(uid=self.hash())
             return item
@@ -84,48 +73,37 @@ class BarcodeMixin:
             return None
 
     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)
         return serializer.data
 
     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
         """
-
         return None  # pragma: no cover
 
     def renderStockLocation(self, loc):
-        """
-        Render a stock location to a JSON response
-        """
-
+        """Render a stock location to a JSON response"""
         serializer = LocationSerializer(loc)
         return serializer.data
 
     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
         """
-
         return None  # pragma: no cover
 
     def renderPart(self, part):
-        """
-        Render a part to JSON response
-        """
-
+        """Render a part to JSON response"""
         serializer = PartSerializer(part)
         return serializer.data
 
     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,
         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
         by a subclass.
-
         """
-
         return hash_barcode(self.data)
 
     def validate(self):
-        """
-        Default implementation returns False
-        """
+        """Default implementation returns False"""
         return False  # pragma: no cover
diff --git a/InvenTree/plugin/base/barcodes/test_barcode.py b/InvenTree/plugin/base/barcodes/test_barcode.py
index 4b66f8b208..178223816e 100644
--- a/InvenTree/plugin/base/barcodes/test_barcode.py
+++ b/InvenTree/plugin/base/barcodes/test_barcode.py
@@ -1,8 +1,4 @@
-# -*- coding: utf-8 -*-
-
-"""
-Unit tests for Barcode endpoints
-"""
+"""Unit tests for Barcode endpoints"""
 
 from django.urls import reverse
 
@@ -62,10 +58,7 @@ class BarcodeAPITest(InvenTreeAPITestCase):
         self.assertIsNone(data['plugin'])
 
     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(
             self.scan_url,
             {
@@ -98,10 +91,7 @@ class BarcodeAPITest(InvenTreeAPITestCase):
         self.assertEqual(response.data['part'], 'Part does not exist')
 
     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(
             self.scan_url,
             {
@@ -119,7 +109,6 @@ class BarcodeAPITest(InvenTreeAPITestCase):
 
     def test_invalid_item(self):
         """Test response for invalid stock item"""
-
         response = self.client.post(
             self.scan_url,
             {
@@ -135,10 +124,7 @@ class BarcodeAPITest(InvenTreeAPITestCase):
         self.assertEqual(response.data['stockitem'], 'Stock item does not exist')
 
     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(
             self.scan_url,
             {
@@ -156,7 +142,6 @@ class BarcodeAPITest(InvenTreeAPITestCase):
 
     def test_invalid_location(self):
         """Test response for an invalid location"""
-
         response = self.client.post(
             self.scan_url,
             {
@@ -215,10 +200,7 @@ class BarcodeAPITest(InvenTreeAPITestCase):
         self.assertEqual(pk, item.pk)
 
     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)
 
         self.assertEqual(len(item.uid), 0)
diff --git a/InvenTree/plugin/base/event/events.py b/InvenTree/plugin/base/event/events.py
index d870269736..d510755465 100644
--- a/InvenTree/plugin/base/event/events.py
+++ b/InvenTree/plugin/base/event/events.py
@@ -1,6 +1,4 @@
-"""
-Functions for triggering and responding to server side events
-"""
+"""Functions for triggering and responding to server side events"""
 
 import logging
 
@@ -17,13 +15,11 @@ logger = logging.getLogger('inventree')
 
 
 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,
     and the worker will respond to it later on.
     """
-
     if not settings.PLUGINS_ENABLED:
         # Do nothing if plugins are not enabled
         return  # pragma: no cover
@@ -44,8 +40,7 @@ def trigger_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,
     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):
-    """
-    Respond to a triggered event.
+    """Respond to a triggered event.
 
     This function is run by the background worker process.
-
     This function may queue multiple functions to be handled by the background worker.
     """
-
     logger.info(f"Plugin '{plugin_slug}' is processing triggered event '{event}'")
 
     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):
-    """
-    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!
     """
-
     if isImportingData():
         # Prevent table events during the data import process
         return False  # pragma: no cover
@@ -143,10 +134,7 @@ def allow_table_event(table_name):
 
 @receiver(post_save)
 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
 
     instance_id = getattr(instance, 'id', None)
@@ -173,10 +161,7 @@ def after_save(sender, instance, created, **kwargs):
 
 @receiver(post_delete)
 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
 
     if not allow_table_event(table):
diff --git a/InvenTree/plugin/base/event/mixins.py b/InvenTree/plugin/base/event/mixins.py
index 8df9bfd164..d18c800bfe 100644
--- a/InvenTree/plugin/base/event/mixins.py
+++ b/InvenTree/plugin/base/event/mixins.py
@@ -4,24 +4,22 @@ from plugin.helpers import MixinNotImplementedError
 
 
 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:
     """
 
     def process_event(self, event, *args, **kwargs):
-        """
-        Function to handle events
+        """Function to handle events
+
         Must be overridden by plugin
         """
         # Default implementation does not do anything
         raise MixinNotImplementedError
 
     class MixinMeta:
-        """
-        Meta options for this mixin
-        """
+        """Meta options for this mixin"""
+
         MIXIN_NAME = 'Events'
 
     def __init__(self):
diff --git a/InvenTree/plugin/base/integration/mixins.py b/InvenTree/plugin/base/integration/mixins.py
index 4cd2123ef3..7cf24a1ea3 100644
--- a/InvenTree/plugin/base/integration/mixins.py
+++ b/InvenTree/plugin/base/integration/mixins.py
@@ -1,6 +1,4 @@
-"""
-Plugin mixin classes
-"""
+"""Plugin mixin classes"""
 
 import json
 import logging
@@ -21,9 +19,7 @@ logger = logging.getLogger('inventree')
 
 
 class SettingsMixin:
-    """
-    Mixin that enables global settings for the plugin
-    """
+    """Mixin that enables global settings for the plugin"""
 
     class MixinMeta:
         MIXIN_NAME = 'Settings'
@@ -35,23 +31,15 @@ class SettingsMixin:
 
     @property
     def has_settings(self):
-        """
-        Does this plugin use custom global settings
-        """
+        """Does this plugin use custom global settings"""
         return bool(self.settings)
 
     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)
 
     def set_setting(self, key, value, user=None):
-        """
-        Set plugin setting value by key
-        """
-
+        """Set plugin setting value by key"""
         try:
             plugin, _ = PluginConfig.objects.get_or_create(key=self.plugin_slug(), name=self.plugin_name())
         except (OperationalError, ProgrammingError):  # pragma: no cover
@@ -66,8 +54,7 @@ class SettingsMixin:
 
 
 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,
     which provides information on the tasks to be scheduled.
@@ -99,9 +86,8 @@ class ScheduleMixin:
     SCHEDULED_TASKS = {}
 
     class MixinMeta:
-        """
-        Meta options for this mixin
-        """
+        """Meta options for this mixin"""
+
         MIXIN_NAME = 'Schedule'
 
     def __init__(self):
@@ -116,16 +102,11 @@ class ScheduleMixin:
 
     @property
     def has_scheduled_tasks(self):
-        """
-        Are tasks defined for this plugin
-        """
+        """Are tasks defined for this plugin"""
         return bool(self.scheduled_tasks)
 
     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:
             raise MixinImplementationError("SCHEDULED_TASKS not defined")
 
@@ -147,25 +128,18 @@ class ScheduleMixin:
                 raise MixinImplementationError(f"Task '{key}' is missing 'minutes' parameter")
 
     def get_task_name(self, key):
-        """
-        Task name for key
-        """
+        """Task name for key"""
         # Generate a 'unique' task name
         slug = self.plugin_slug()
         return f"plugin.{slug}.{key}"
 
     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
         return [self.get_task_name(key) for key in self.scheduled_tasks.keys()]
 
     def register_tasks(self):
-        """
-        Register the tasks with the database
-        """
-
+        """Register the tasks with the database"""
         try:
             from django_q.models import Schedule
 
@@ -182,10 +156,7 @@ class ScheduleMixin:
                 func_name = task['func'].strip()
 
                 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(
                         name=task_name,
@@ -196,8 +167,7 @@ class ScheduleMixin:
                     )
 
                 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.
                     """
@@ -218,10 +188,7 @@ class ScheduleMixin:
             logger.warning("register_tasks failed, database not ready")
 
     def unregister_tasks(self):
-        """
-        Deregister the tasks with the database
-        """
-
+        """Deregister the tasks with the database"""
         try:
             from django_q.models import Schedule
 
@@ -240,14 +207,11 @@ class ScheduleMixin:
 
 
 class UrlsMixin:
-    """
-    Mixin that enables custom URLs for the plugin
-    """
+    """Mixin that enables custom URLs for the plugin"""
 
     class MixinMeta:
-        """
-        Meta options for this mixin
-        """
+        """Meta options for this mixin"""
+
         MIXIN_NAME = 'URLs'
 
     def __init__(self):
@@ -256,54 +220,41 @@ class UrlsMixin:
         self.urls = self.setup_urls()
 
     def setup_urls(self):
-        """
-        Setup url endpoints for this plugin
-        """
+        """Setup url endpoints for this plugin"""
         return getattr(self, 'URLS', None)
 
     @property
     def base_url(self):
-        """
-        Base url for this plugin
-        """
+        """Base url for this plugin"""
         return f'{PLUGIN_BASE}/{self.slug}/'
 
     @property
     def internal_name(self):
-        """
-        Internal url pattern name
-        """
+        """Internal url pattern name"""
         return f'plugin:{self.slug}:'
 
     @property
     def urlpatterns(self):
-        """
-        Urlpatterns for this plugin
-        """
+        """Urlpatterns for this plugin"""
         if self.has_urls:
             return re_path(f'^{self.slug}/', include((self.urls, self.slug)), name=self.slug)
         return None
 
     @property
     def has_urls(self):
-        """
-        Does this plugin use custom urls
-        """
+        """Does this plugin use custom urls"""
         return bool(self.urls)
 
 
 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_ICON = "fas fa-question"
 
     class MixinMeta:
-        """
-        Meta options for this mixin
-        """
+        """Meta options for this mixin"""
+
         MIXIN_NAME = 'Navigation Links'
 
     def __init__(self):
@@ -312,9 +263,7 @@ class NavigationMixin:
         self.navigation = self.setup_navigation()
 
     def setup_navigation(self):
-        """
-        Setup navigation links for this plugin
-        """
+        """Setup navigation links for this plugin"""
         nav_links = getattr(self, 'NAVIGATION', None)
         if nav_links:
             # check if needed values are configured
@@ -325,16 +274,12 @@ class NavigationMixin:
 
     @property
     def has_naviation(self):
-        """
-        Does this plugin define navigation elements
-        """
+        """Does this plugin define navigation elements"""
         return bool(self.navigation)
 
     @property
     def navigation_name(self):
-        """
-        Name for navigation tab
-        """
+        """Name for navigation tab"""
         name = getattr(self, 'NAVIGATION_TAB_NAME', None)
         if not name:
             name = self.human_name
@@ -342,21 +287,16 @@ class NavigationMixin:
 
     @property
     def navigation_icon(self):
-        """
-        Icon-name for navigation tab
-        """
+        """Icon-name for navigation tab"""
         return getattr(self, 'NAVIGATION_TAB_ICON', "fas fa-question")
 
 
 class AppMixin:
-    """
-    Mixin that enables full django app functions for a plugin
-    """
+    """Mixin that enables full django app functions for a plugin"""
 
     class MixinMeta:
-        """m
-        Mta options for this mixin
-        """
+        """Meta options for this mixin"""
+
         MIXIN_NAME = 'App registration'
 
     def __init__(self):
@@ -365,15 +305,12 @@ class AppMixin:
 
     @property
     def has_app(self):
-        """
-        This plugin is always an app with this plugin
-        """
+        """This plugin is always an app with this plugin"""
         return True
 
 
 class APICallMixin:
-    """
-    Mixin that enables easier API calls for a plugin
+    """Mixin that enables easier API calls for a plugin
 
     Steps to set up:
     1. Add this mixin before (left of) SettingsMixin and PluginBase
@@ -424,7 +361,7 @@ class APICallMixin:
     API_TOKEN = 'Bearer'
 
     class MixinMeta:
-        """meta options for this mixin"""
+        """Meta options for this mixin"""
         MIXIN_NAME = 'API calls'
 
     def __init__(self):
@@ -487,8 +424,7 @@ class APICallMixin:
 
 
 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:
 
@@ -540,17 +476,15 @@ class PanelMixin:
         self.add_mixin('panel', True, __class__)
 
     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")
 
     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.
 
         (See the example in "custom_panel_sample.py")
         """
-
         # Provide some standard context items to the template for rendering
         context['plugin'] = self
         context['request'] = request
diff --git a/InvenTree/plugin/base/integration/test_mixins.py b/InvenTree/plugin/base/integration/test_mixins.py
index e91f4da365..b3eb9f4418 100644
--- a/InvenTree/plugin/base/integration/test_mixins.py
+++ b/InvenTree/plugin/base/integration/test_mixins.py
@@ -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.test import TestCase
@@ -170,9 +170,7 @@ class APICallMixinTest(BaseMixinDefinition, TestCase):
             API_TOKEN_SETTING = 'API_TOKEN'
 
             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)
         self.mixin = MixinCls()
 
@@ -263,7 +261,6 @@ class PanelMixinTests(InvenTreeTestCase):
 
     def test_installed(self):
         """Test that the sample panel plugin is installed"""
-
         plugins = registry.with_mixin('panel')
 
         self.assertTrue(len(plugins) > 0)
@@ -276,7 +273,6 @@ class PanelMixinTests(InvenTreeTestCase):
 
     def test_disabled(self):
         """Test that the panels *do not load* if the plugin is not enabled"""
-
         plugin = registry.get_plugin('samplepanel')
 
         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
         """
-
         plugin = registry.get_plugin('samplepanel')
 
         self.assertEqual(len(registry.with_mixin('panel', active=True)), 0)
@@ -383,7 +378,6 @@ class PanelMixinTests(InvenTreeTestCase):
 
     def test_mixin(self):
         """Test that ImplementationError is raised"""
-
         with self.assertRaises(MixinNotImplementedError):
             class Wrong(PanelMixin, InvenTreePlugin):
                 pass
diff --git a/InvenTree/plugin/base/label/label.py b/InvenTree/plugin/base/label/label.py
index d85251dd81..f02420bf61 100644
--- a/InvenTree/plugin/base/label/label.py
+++ b/InvenTree/plugin/base/label/label.py
@@ -1,4 +1,5 @@
 """Functions to print a label to a mixin printer"""
+
 import logging
 
 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):
-    """
-    Print label with the provided plugin.
+    """Print label with the provided plugin.
 
     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
         label_image: A PIL.Image image object to be printed
     """
-
     logger.info(f"Plugin '{plugin_slug}' is printing a label")
 
     plugin = registry.plugins.get(plugin_slug, None)