diff --git a/InvenTree/plugin/base/label/mixins.py b/InvenTree/plugin/base/label/mixins.py index 4e06f9e15a..ddab7cd0c7 100644 --- a/InvenTree/plugin/base/label/mixins.py +++ b/InvenTree/plugin/base/label/mixins.py @@ -4,8 +4,7 @@ from plugin.helpers import MixinNotImplementedError class LabelPrintingMixin: - """ - Mixin which enables direct printing of stock labels. + """Mixin which enables direct printing of stock labels. Each plugin must provide a NAME attribute, which is used to uniquely identify the printer. @@ -13,9 +12,8 @@ class LabelPrintingMixin: """ class MixinMeta: - """ - Meta options for this mixin - """ + """Meta options for this mixin""" + MIXIN_NAME = 'Label printing' def __init__(self): # pragma: no cover @@ -23,8 +21,7 @@ class LabelPrintingMixin: self.add_mixin('labels', True, __class__) def print_label(self, label, **kwargs): - """ - Callback to print a single label + """Callback to print a single label Arguments: label: A black-and-white pillow Image object @@ -32,8 +29,6 @@ class LabelPrintingMixin: kwargs: length: The length of the label (in mm) width: The width of the label (in mm) - """ - # Unimplemented (to be implemented by the particular plugin class) raise MixinNotImplementedError('This Plugin must implement a `print_label` method') diff --git a/InvenTree/plugin/base/label/test_label_mixin.py b/InvenTree/plugin/base/label/test_label_mixin.py index 29250f76a5..32c9f9f450 100644 --- a/InvenTree/plugin/base/label/test_label_mixin.py +++ b/InvenTree/plugin/base/label/test_label_mixin.py @@ -28,7 +28,6 @@ class LabelMixinTests(InvenTreeAPITestCase): def do_activate_plugin(self): """Activate the 'samplelabel' plugin""" - config = registry.get_plugin('samplelabel').plugin_config() config.active = True config.save() @@ -62,7 +61,6 @@ class LabelMixinTests(InvenTreeAPITestCase): def test_wrong_implementation(self): """Test that a wrong implementation raises an error""" - class WrongPlugin(LabelPrintingMixin, InvenTreePlugin): pass @@ -72,7 +70,6 @@ class LabelMixinTests(InvenTreeAPITestCase): def test_installed(self): """Test that the sample printing plugin is installed""" - # Get all label plugins plugins = registry.with_mixin('labels') self.assertEqual(len(plugins), 1) @@ -83,7 +80,6 @@ class LabelMixinTests(InvenTreeAPITestCase): def test_api(self): """Test that we can filter the API endpoint by mixin""" - url = reverse('api-plugin-list') # Try POST (disallowed) @@ -128,7 +124,6 @@ class LabelMixinTests(InvenTreeAPITestCase): def test_printing_process(self): """Test that a label can be printed""" - # Ensure the labels were created apps.get_app_config('label').create_labels() diff --git a/InvenTree/plugin/base/locate/api.py b/InvenTree/plugin/base/locate/api.py index da0488591f..3b00490112 100644 --- a/InvenTree/plugin/base/locate/api.py +++ b/InvenTree/plugin/base/locate/api.py @@ -11,9 +11,7 @@ from stock.models import StockItem, StockLocation class LocatePluginView(APIView): - """ - Endpoint for using a custom plugin to identify or 'locate' a stock item or location - """ + """Endpoint for using a custom plugin to identify or 'locate' a stock item or location""" permission_classes = [ permissions.IsAuthenticated, diff --git a/InvenTree/plugin/base/locate/mixins.py b/InvenTree/plugin/base/locate/mixins.py index 5d804b70f2..64de70c5e8 100644 --- a/InvenTree/plugin/base/locate/mixins.py +++ b/InvenTree/plugin/base/locate/mixins.py @@ -8,8 +8,7 @@ logger = logging.getLogger('inventree') class LocateMixin: - """ - Mixin class which provides support for 'locating' inventory items, + """Mixin class which provides support for 'locating' inventory items, for example identifying the location of a particular StockLocation. Plugins could implement audible or visual cues to direct attention to the location, @@ -23,7 +22,6 @@ class LocateMixin: - locate_stock_location : Used to locate / identify a particular stock location Refer to the default method implementations below for more information! - """ class MixinMeta: @@ -34,8 +32,7 @@ class LocateMixin: self.add_mixin('locate', True, __class__) def locate_stock_item(self, item_pk): - """ - Attempt to locate a particular StockItem + """Attempt to locate a particular StockItem Arguments: item_pk: The PK (primary key) of the StockItem to be located @@ -63,8 +60,7 @@ class LocateMixin: pass def locate_stock_location(self, location_pk): - """ - Attempt to location a particular StockLocation + """Attempt to location a particular StockLocation Arguments: location_pk: The PK (primary key) of the StockLocation to be located diff --git a/InvenTree/plugin/base/locate/test_locate.py b/InvenTree/plugin/base/locate/test_locate.py index 96dfca7cb1..4105167741 100644 --- a/InvenTree/plugin/base/locate/test_locate.py +++ b/InvenTree/plugin/base/locate/test_locate.py @@ -1,6 +1,4 @@ -""" -Unit tests for the 'locate' plugin mixin class -""" +"""Unit tests for the 'locate' plugin mixin class""" from django.urls import reverse @@ -21,7 +19,6 @@ class LocatePluginTests(InvenTreeAPITestCase): def test_installed(self): """Test that a locate plugin is actually installed""" - plugins = registry.with_mixin('locate') self.assertTrue(len(plugins) > 0) @@ -30,7 +27,6 @@ class LocatePluginTests(InvenTreeAPITestCase): def test_locate_fail(self): """Test various API failure modes""" - url = reverse('api-locate-plugin') # Post without a plugin @@ -90,13 +86,11 @@ class LocatePluginTests(InvenTreeAPITestCase): self.assertIn(f"StockLocation matching PK '{pk}' not found", str(response.data)) def test_locate_item(self): - """ - Test that the plugin correctly 'locates' a StockItem + """Test that the plugin correctly 'locates' a StockItem As the background worker is not running during unit testing, the sample 'locate' function will be called 'inline' """ - url = reverse('api-locate-plugin') item = StockItem.objects.get(pk=1) @@ -121,10 +115,7 @@ class LocatePluginTests(InvenTreeAPITestCase): self.assertTrue(item.metadata['located']) def test_locate_location(self): - """ - Test that the plugin correctly 'locates' a StockLocation - """ - + """Test that the plugin correctly 'locates' a StockLocation""" url = reverse('api-locate-plugin') for location in StockLocation.objects.all(): diff --git a/InvenTree/plugin/builtin/action/simpleactionplugin.py b/InvenTree/plugin/builtin/action/simpleactionplugin.py index 54598e72cb..483122a33d 100644 --- a/InvenTree/plugin/builtin/action/simpleactionplugin.py +++ b/InvenTree/plugin/builtin/action/simpleactionplugin.py @@ -1,14 +1,11 @@ -# -*- coding: utf-8 -*- -"""sample implementation for ActionMixin""" +"""Sample implementation for ActionMixin""" + from plugin import InvenTreePlugin from plugin.mixins import ActionMixin class SimpleActionPlugin(ActionMixin, InvenTreePlugin): - """ - An EXTREMELY simple action plugin which demonstrates - the capability of the ActionMixin class - """ + """An EXTREMELY simple action plugin which demonstrates the capability of the ActionMixin class""" NAME = "SimpleActionPlugin" ACTION_NAME = "simple" diff --git a/InvenTree/plugin/builtin/action/test_simpleactionplugin.py b/InvenTree/plugin/builtin/action/test_simpleactionplugin.py index e645dea85c..67ee637a77 100644 --- a/InvenTree/plugin/builtin/action/test_simpleactionplugin.py +++ b/InvenTree/plugin/builtin/action/test_simpleactionplugin.py @@ -1,11 +1,11 @@ -""" Unit tests for action plugins """ +"""Unit tests for action plugins""" from InvenTree.helpers import InvenTreeTestCase from plugin.builtin.action.simpleactionplugin import SimpleActionPlugin class SimpleActionPluginTests(InvenTreeTestCase): - """ Tests for SampleIntegrationPlugin """ + """Tests for SampleIntegrationPlugin""" def setUp(self): super().setUp() @@ -13,12 +13,12 @@ class SimpleActionPluginTests(InvenTreeTestCase): self.plugin = SimpleActionPlugin() def test_name(self): - """check plugn names """ + """Check plugn names""" self.assertEqual(self.plugin.plugin_name(), "SimpleActionPlugin") self.assertEqual(self.plugin.action_name(), "simple") def test_function(self): - """check if functions work """ + """Check if functions work""" # test functions response = self.client.post('/api/action/', data={'action': "simple", 'data': {'foo': "bar", }}) self.assertEqual(response.status_code, 200) diff --git a/InvenTree/plugin/builtin/barcodes/test_inventree_barcode.py b/InvenTree/plugin/builtin/barcodes/test_inventree_barcode.py index 0bc855aa24..cd95f0f35b 100644 --- a/InvenTree/plugin/builtin/barcodes/test_inventree_barcode.py +++ b/InvenTree/plugin/builtin/barcodes/test_inventree_barcode.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """Unit tests for InvenTreeBarcodePlugin""" from django.urls import reverse @@ -18,9 +17,7 @@ class TestInvenTreeBarcode(InvenTreeAPITestCase): ] def test_errors(self): - """ - Test all possible error cases for assigment action - """ + """Test all possible error cases for assigment action""" def test_assert_error(barcode_data): response = self.client.post( @@ -46,10 +43,7 @@ class TestInvenTreeBarcode(InvenTreeAPITestCase): test_assert_error('{"blbla": 10004}') def test_scan(self): - """ - Test that a barcode can be scanned - """ - + """Test that a barcode can be scanned""" response = self.client.post(reverse('api-barcode-scan'), format='json', data={'barcode': 'blbla=10004'}) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertIn('success', response.data) diff --git a/InvenTree/plugin/builtin/integration/core_notifications.py b/InvenTree/plugin/builtin/integration/core_notifications.py index 179fb7994f..a63dff43bc 100644 --- a/InvenTree/plugin/builtin/integration/core_notifications.py +++ b/InvenTree/plugin/builtin/integration/core_notifications.py @@ -1,5 +1,5 @@ -# -*- coding: utf-8 -*- """Core set of Notifications as a Plugin""" + from django.template.loader import render_to_string from django.utils.translation import ugettext_lazy as _ @@ -16,9 +16,7 @@ class PlgMixin: class CoreNotificationsPlugin(SettingsMixin, InvenTreePlugin): - """ - Core notification methods for InvenTree - """ + """Core notification methods for InvenTree""" NAME = "CoreNotificationsPlugin" AUTHOR = _('InvenTree contributors') @@ -50,11 +48,7 @@ class CoreNotificationsPlugin(SettingsMixin, InvenTreePlugin): } def get_targets(self): - """ - Return a list of target email addresses, - only for users which allow email notifications - """ - + """Return a list of target email addresses, only for users which allow email notifications""" allowed_users = [] for user in self.targets: diff --git a/InvenTree/plugin/builtin/integration/test_core_notifications.py b/InvenTree/plugin/builtin/integration/test_core_notifications.py index 3badac2562..cbfa2910c2 100644 --- a/InvenTree/plugin/builtin/integration/test_core_notifications.py +++ b/InvenTree/plugin/builtin/integration/test_core_notifications.py @@ -8,10 +8,7 @@ from plugin.models import NotificationUserSetting class CoreNotificationTestTests(BaseNotificationIntegrationTest): def test_email(self): - """ - Ensure that the email notifications run - """ - + """Ensure that the email notifications run""" # enable plugin and set mail setting to true plugin = registry.plugins.get('corenotificationsplugin') plugin.set_setting('ENABLE_NOTIFICATION_EMAILS', True) diff --git a/InvenTree/plugin/mixins/__init__.py b/InvenTree/plugin/mixins/__init__.py index 80088de561..5c139d76cb 100644 --- a/InvenTree/plugin/mixins/__init__.py +++ b/InvenTree/plugin/mixins/__init__.py @@ -1,6 +1,4 @@ -""" -Utility class to enable simpler imports -""" +"""Utility class to enable simpler imports""" from common.notifications import (BulkNotificationMethod, SingleNotificationMethod) diff --git a/InvenTree/plugin/samples/event/event_sample.py b/InvenTree/plugin/samples/event/event_sample.py index acddbf95c6..6dc7e258f7 100644 --- a/InvenTree/plugin/samples/event/event_sample.py +++ b/InvenTree/plugin/samples/event/event_sample.py @@ -1,6 +1,4 @@ -""" -Sample plugin which responds to events -""" +"""Sample plugin which responds to events""" import warnings @@ -11,16 +9,14 @@ from plugin.mixins import EventMixin class EventPluginSample(EventMixin, InvenTreePlugin): - """ - A sample plugin which provides supports for triggered events - """ + """A sample plugin which provides supports for triggered events""" NAME = "EventPlugin" SLUG = "sampleevent" TITLE = "Triggered Events" def process_event(self, event, *args, **kwargs): - """ Custom event processing """ + """Custom event processing""" print(f"Processing triggered event: '{event}'") print("args:", str(args)) diff --git a/InvenTree/plugin/samples/event/test_event_sample.py b/InvenTree/plugin/samples/event/test_event_sample.py index 284b306a92..964d107673 100644 --- a/InvenTree/plugin/samples/event/test_event_sample.py +++ b/InvenTree/plugin/samples/event/test_event_sample.py @@ -31,7 +31,6 @@ class EventPluginSampleTests(TestCase): def test_mixin(self): """Test that MixinNotImplementedError is raised""" - with self.assertRaises(MixinNotImplementedError): class Wrong(EventMixin, InvenTreePlugin): pass diff --git a/InvenTree/plugin/samples/integration/another_sample.py b/InvenTree/plugin/samples/integration/another_sample.py index 0cc5ce21c3..e509c33299 100644 --- a/InvenTree/plugin/samples/integration/another_sample.py +++ b/InvenTree/plugin/samples/integration/another_sample.py @@ -1,19 +1,15 @@ -"""sample implementation for IntegrationPlugin""" +"""Sample implementation for IntegrationPlugin""" from plugin import InvenTreePlugin from plugin.mixins import UrlsMixin class NoIntegrationPlugin(InvenTreePlugin): - """ - An basic plugin - """ + """A basic plugin""" NAME = "NoIntegrationPlugin" class WrongIntegrationPlugin(UrlsMixin, InvenTreePlugin): - """ - An basic wron plugin with urls - """ + """A basic wron plugin with urls""" NAME = "WrongIntegrationPlugin" diff --git a/InvenTree/plugin/samples/integration/api_caller.py b/InvenTree/plugin/samples/integration/api_caller.py index 98a145de34..81647609f7 100644 --- a/InvenTree/plugin/samples/integration/api_caller.py +++ b/InvenTree/plugin/samples/integration/api_caller.py @@ -1,14 +1,11 @@ -""" -Sample plugin for calling an external API -""" +"""Sample plugin for calling an external API""" from plugin import InvenTreePlugin from plugin.mixins import APICallMixin, SettingsMixin class SampleApiCallerPlugin(APICallMixin, SettingsMixin, InvenTreePlugin): - """ - A small api call sample - """ + """A small api call sample""" + NAME = "Sample API Caller" SETTINGS = { @@ -26,7 +23,5 @@ class SampleApiCallerPlugin(APICallMixin, SettingsMixin, InvenTreePlugin): API_TOKEN_SETTING = 'API_TOKEN' def get_external_url(self): - """ - returns data from the sample endpoint - """ + """Returns data from the sample endpoint""" return self.api_call('api/users/2') diff --git a/InvenTree/plugin/samples/integration/broken_sample.py b/InvenTree/plugin/samples/integration/broken_sample.py index ebd7821fe0..65a5a427d5 100644 --- a/InvenTree/plugin/samples/integration/broken_sample.py +++ b/InvenTree/plugin/samples/integration/broken_sample.py @@ -1,11 +1,10 @@ -"""sample of a broken plugin""" +"""Sample of a broken plugin""" from plugin import InvenTreePlugin class BrokenIntegrationPlugin(InvenTreePlugin): - """ - An very broken plugin - """ + """A very broken plugin""" + NAME = 'Test' TITLE = 'Broken Plugin' SLUG = 'broken' diff --git a/InvenTree/plugin/samples/integration/custom_panel_sample.py b/InvenTree/plugin/samples/integration/custom_panel_sample.py index 3671dc532e..bea8413b04 100644 --- a/InvenTree/plugin/samples/integration/custom_panel_sample.py +++ b/InvenTree/plugin/samples/integration/custom_panel_sample.py @@ -1,6 +1,4 @@ -""" -Sample plugin which renders custom panels on certain pages -""" +"""Sample plugin which renders custom panels on certain pages""" from part.views import PartDetail from plugin import InvenTreePlugin @@ -9,9 +7,7 @@ from stock.views import StockLocationDetail class CustomPanelSample(PanelMixin, SettingsMixin, InvenTreePlugin): - """ - A sample plugin which renders some custom panels. - """ + """A sample plugin which renders some custom panels.""" NAME = "CustomPanelExample" SLUG = "samplepanel" @@ -45,9 +41,7 @@ class CustomPanelSample(PanelMixin, SettingsMixin, InvenTreePlugin): return ctx def get_custom_panels(self, view, request): - - """ - You can decide at run-time which custom panels you want to display! + """You can decide at run-time which custom panels you want to display! - Display on every page - Only on a single page or set of pages diff --git a/InvenTree/plugin/samples/integration/label_sample.py b/InvenTree/plugin/samples/integration/label_sample.py index 845e1b7908..783f67711b 100644 --- a/InvenTree/plugin/samples/integration/label_sample.py +++ b/InvenTree/plugin/samples/integration/label_sample.py @@ -4,9 +4,7 @@ from plugin.mixins import LabelPrintingMixin class SampleLabelPrinter(LabelPrintingMixin, InvenTreePlugin): - """ - Sample plugin which provides a 'fake' label printer endpoint - """ + """Sample plugin which provides a 'fake' label printer endpoint""" NAME = "Label Printer" SLUG = "samplelabel" diff --git a/InvenTree/plugin/samples/integration/sample.py b/InvenTree/plugin/samples/integration/sample.py index a768fb3de3..3d6f20319e 100644 --- a/InvenTree/plugin/samples/integration/sample.py +++ b/InvenTree/plugin/samples/integration/sample.py @@ -1,6 +1,4 @@ -""" -Sample implementations for IntegrationPlugin -""" +"""Sample implementations for IntegrationPlugin""" from django.http import HttpResponse from django.urls import include, re_path @@ -11,9 +9,7 @@ from plugin.mixins import AppMixin, NavigationMixin, SettingsMixin, UrlsMixin class SampleIntegrationPlugin(AppMixin, SettingsMixin, UrlsMixin, NavigationMixin, InvenTreePlugin): - """ - A full plugin example - """ + """A full plugin example""" NAME = "SampleIntegrationPlugin" SLUG = "sample" @@ -23,7 +19,7 @@ class SampleIntegrationPlugin(AppMixin, SettingsMixin, UrlsMixin, NavigationMixi NAVIGATION_TAB_ICON = 'fas fa-plus' def view_test(self, request): - """very basic view""" + """Very basic view""" return HttpResponse(f'Hi there {request.user.username} this works') def setup_urls(self): diff --git a/InvenTree/plugin/samples/integration/scheduled_task.py b/InvenTree/plugin/samples/integration/scheduled_task.py index 2a59f820c6..72473e8a1e 100644 --- a/InvenTree/plugin/samples/integration/scheduled_task.py +++ b/InvenTree/plugin/samples/integration/scheduled_task.py @@ -1,6 +1,4 @@ -""" -Sample plugin which supports task scheduling -""" +"""Sample plugin which supports task scheduling""" from plugin import InvenTreePlugin from plugin.mixins import ScheduleMixin, SettingsMixin @@ -16,9 +14,7 @@ def print_world(): class ScheduledTaskPlugin(ScheduleMixin, SettingsMixin, InvenTreePlugin): - """ - A sample plugin which provides support for scheduled tasks - """ + """A sample plugin which provides support for scheduled tasks""" NAME = "ScheduledTasksPlugin" SLUG = "schedule" @@ -51,10 +47,7 @@ class ScheduledTaskPlugin(ScheduleMixin, SettingsMixin, InvenTreePlugin): } def member_func(self, *args, **kwargs): - """ - A simple member function to demonstrate functionality - """ - + """A simple member function to demonstrate functionality""" t_or_f = self.get_setting('T_OR_F') print(f"Called member_func - value is {t_or_f}") diff --git a/InvenTree/plugin/samples/integration/test_api_caller.py b/InvenTree/plugin/samples/integration/test_api_caller.py index 32ee07bbd3..8f478b88f8 100644 --- a/InvenTree/plugin/samples/integration/test_api_caller.py +++ b/InvenTree/plugin/samples/integration/test_api_caller.py @@ -1,4 +1,4 @@ -""" Unit tests for action caller sample""" +"""Unit tests for action caller sample""" from django.test import TestCase @@ -6,10 +6,10 @@ from plugin import registry class SampleApiCallerPluginTests(TestCase): - """ Tests for SampleApiCallerPluginTests """ + """Tests for SampleApiCallerPluginTests """ def test_return(self): - """check if the external api call works""" + """Check if the external api call works""" # The plugin should be defined self.assertIn('sample-api-caller', registry.plugins) plg = registry.plugins['sample-api-caller'] diff --git a/InvenTree/plugin/samples/integration/test_sample.py b/InvenTree/plugin/samples/integration/test_sample.py index 577aa5812e..38b9a22417 100644 --- a/InvenTree/plugin/samples/integration/test_sample.py +++ b/InvenTree/plugin/samples/integration/test_sample.py @@ -1,13 +1,13 @@ -""" Unit tests for action plugins """ +"""Unit tests for action plugins""" from InvenTree.helpers import InvenTreeTestCase class SampleIntegrationPluginTests(InvenTreeTestCase): - """ Tests for SampleIntegrationPlugin """ + """Tests for SampleIntegrationPlugin""" def test_view(self): - """check the function of the custom sample plugin """ + """Check the function of the custom sample plugin""" response = self.client.get('/plugin/sample/ho/he/') self.assertEqual(response.status_code, 200) self.assertEqual(response.content, b'Hi there testuser this works') diff --git a/InvenTree/plugin/samples/integration/test_scheduled_task.py b/InvenTree/plugin/samples/integration/test_scheduled_task.py index c99a662ff9..3fa01096d7 100644 --- a/InvenTree/plugin/samples/integration/test_scheduled_task.py +++ b/InvenTree/plugin/samples/integration/test_scheduled_task.py @@ -1,4 +1,4 @@ -""" Unit tests for scheduled tasks""" +"""Unit tests for scheduled tasks""" from django.test import TestCase @@ -9,10 +9,10 @@ from plugin.registry import call_function class ExampleScheduledTaskPluginTests(TestCase): - """ Tests for provided ScheduledTaskPlugin """ + """Tests for provided ScheduledTaskPlugin""" def test_function(self): - """check if the scheduling works""" + """Check if the scheduling works""" # The plugin should be defined self.assertIn('schedule', registry.plugins) plg = registry.plugins['schedule'] @@ -44,7 +44,7 @@ class ExampleScheduledTaskPluginTests(TestCase): self.assertEqual(len(scheduled_plugin_tasks), 0) def test_calling(self): - """check if a function can be called without errors""" + """Check if a function can be called without errors""" # Check with right parameters self.assertEqual(call_function('schedule', 'member_func'), False) @@ -53,7 +53,7 @@ class ExampleScheduledTaskPluginTests(TestCase): class ScheduledTaskPluginTests(TestCase): - """ Tests for ScheduledTaskPluginTests mixin base """ + """Tests for ScheduledTaskPluginTests mixin base""" def test_init(self): """Check that all MixinImplementationErrors raise""" @@ -68,8 +68,7 @@ class ScheduledTaskPluginTests(TestCase): NoSchedules() class WrongFuncSchedules(Base): - """ - Plugin with broken functions + """Plugin with broken functions This plugin is missing a func """ @@ -88,8 +87,7 @@ class ScheduledTaskPluginTests(TestCase): WrongFuncSchedules() class WrongFuncSchedules1(WrongFuncSchedules): - """ - Plugin with broken functions + """Plugin with broken functions This plugin is missing a schedule """ @@ -105,8 +103,7 @@ class ScheduledTaskPluginTests(TestCase): WrongFuncSchedules1() class WrongFuncSchedules2(WrongFuncSchedules): - """ - Plugin with broken functions + """Plugin with broken functions This plugin is missing a schedule """ @@ -122,8 +119,7 @@ class ScheduledTaskPluginTests(TestCase): WrongFuncSchedules2() class WrongFuncSchedules3(WrongFuncSchedules): - """ - Plugin with broken functions + """Plugin with broken functions This plugin has a broken schedule """ @@ -140,8 +136,7 @@ class ScheduledTaskPluginTests(TestCase): WrongFuncSchedules3() class WrongFuncSchedules4(WrongFuncSchedules): - """ - Plugin with broken functions + """Plugin with broken functions This plugin is missing a minute marker for its schedule """ diff --git a/InvenTree/plugin/samples/locate/locate_sample.py b/InvenTree/plugin/samples/locate/locate_sample.py index d4ce411098..d1a3a4c7c6 100644 --- a/InvenTree/plugin/samples/locate/locate_sample.py +++ b/InvenTree/plugin/samples/locate/locate_sample.py @@ -13,8 +13,8 @@ logger = logging.getLogger('inventree') class SampleLocatePlugin(LocateMixin, InvenTreePlugin): - """ - A very simple example of the 'locate' plugin. + """A very simple example of the 'locate' plugin. + This plugin class simply prints location information to the logger. """ diff --git a/InvenTree/plugin/samples/locate/test_locate_sample.py b/InvenTree/plugin/samples/locate/test_locate_sample.py index fe7ba28cca..45b0fd292c 100644 --- a/InvenTree/plugin/samples/locate/test_locate_sample.py +++ b/InvenTree/plugin/samples/locate/test_locate_sample.py @@ -51,7 +51,6 @@ class SampleLocatePlugintests(InvenTreeAPITestCase): def test_mixin(self): """Test that MixinNotImplementedError is raised""" - with self.assertRaises(MixinNotImplementedError): class Wrong(LocateMixin, InvenTreePlugin): pass diff --git a/InvenTree/plugin/templatetags/plugin_extras.py b/InvenTree/plugin/templatetags/plugin_extras.py index b949ced8e3..b0e60a6285 100644 --- a/InvenTree/plugin/templatetags/plugin_extras.py +++ b/InvenTree/plugin/templatetags/plugin_extras.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- +"""This module provides template tags for handeling plugins""" -""" This module provides template tags for handeling plugins -""" from django import template from django.conf import settings as djangosettings from django.urls import reverse @@ -15,49 +13,37 @@ register = template.Library() @register.simple_tag() def plugin_list(*args, **kwargs): - """ - List of all installed plugins - """ + """List of all installed plugins""" return registry.plugins @register.simple_tag() def inactive_plugin_list(*args, **kwargs): - """ - List of all inactive plugins - """ + """List of all inactive plugins""" return registry.plugins_inactive @register.simple_tag() def plugin_settings(plugin, *args, **kwargs): - """ - List of all settings for the plugin - """ + """List of all settings for the plugin""" return registry.mixins_settings.get(plugin) @register.simple_tag() def mixin_enabled(plugin, key, *args, **kwargs): - """ - Is the mixin registerd and configured in the plugin? - """ + """Is the mixin registerd and configured in the plugin?""" return plugin.mixin_enabled(key) @register.simple_tag() def mixin_available(mixin, *args, **kwargs): - """ - Returns True if there is at least one active plugin which supports the provided mixin - """ + """Returns True if there is at least one active plugin which supports the provided mixin""" return len(registry.with_mixin(mixin)) > 0 @register.simple_tag() def navigation_enabled(*args, **kwargs): - """ - Is plugin navigation enabled? - """ + """Is plugin navigation enabled?""" if djangosettings.PLUGIN_TESTING: return True return InvenTreeSetting.get_setting('ENABLE_PLUGINS_NAVIGATION') # pragma: no cover @@ -65,8 +51,8 @@ def navigation_enabled(*args, **kwargs): @register.simple_tag() def safe_url(view_name, *args, **kwargs): - """ - Safe lookup fnc for URLs + """Safe lookup fnc for URLs + Returns None if not found """ try: @@ -77,15 +63,11 @@ def safe_url(view_name, *args, **kwargs): @register.simple_tag() def plugin_errors(*args, **kwargs): - """ - All plugin errors in the current session - """ + """All plugin errors in the current session""" return registry.errors @register.simple_tag(takes_context=True) def notification_settings_list(context, *args, **kwargs): - """ - List of all user notification settings - """ + """List of all user notification settings""" return storage.get_usersettings(user=context.get('user', None)) diff --git a/InvenTree/report/api.py b/InvenTree/report/api.py index 106da81f08..9e3a5118b7 100644 --- a/InvenTree/report/api.py +++ b/InvenTree/report/api.py @@ -24,9 +24,7 @@ from .serializers import (BOMReportSerializer, BuildReportSerializer, class ReportListView(generics.ListAPIView): - """ - Generic API class for report templates - """ + """Generic API class for report templates""" filter_backends = [ DjangoFilterBackend, @@ -44,15 +42,10 @@ class ReportListView(generics.ListAPIView): class StockItemReportMixin: - """ - Mixin for extracting stock items from query params - """ + """Mixin for extracting stock items from query params""" def get_items(self): - """ - Return a list of requested stock items - """ - + """Return a list of requested stock items""" items = [] params = self.request.query_params @@ -77,15 +70,10 @@ class StockItemReportMixin: class BuildReportMixin: - """ - Mixin for extracting Build items from query params - """ + """Mixin for extracting Build items from query params""" def get_builds(self): - """ - Return a list of requested Build objects - """ - + """Return a list of requested Build objects""" builds = [] params = self.request.query_params @@ -109,17 +97,13 @@ class BuildReportMixin: class OrderReportMixin: - """ - Mixin for extracting order items from query params + """Mixin for extracting order items from query params requires the OrderModel class attribute to be set! """ def get_orders(self): - """ - Return a list of order objects - """ - + """Return a list of order objects""" orders = [] params = self.request.query_params @@ -143,15 +127,10 @@ class OrderReportMixin: class PartReportMixin: - """ - Mixin for extracting part items from query params - """ + """Mixin for extracting part items from query params""" def get_parts(self): - """ - Return a list of requested part objects - """ - + """Return a list of requested part objects""" parts = [] params = self.request.query_params @@ -176,15 +155,10 @@ class PartReportMixin: class ReportPrintMixin: - """ - Mixin for printing reports - """ + """Mixin for printing reports""" def print(self, request, items_to_print): - """ - Print this report template against a number of pre-validated items. - """ - + """Print this report template against a number of pre-validated items.""" if len(items_to_print) == 0: # No valid items provided, return an error message data = { @@ -283,8 +257,7 @@ class ReportPrintMixin: class StockItemTestReportList(ReportListView, StockItemReportMixin): - """ - API endpoint for viewing list of TestReport objects. + """API endpoint for viewing list of TestReport objects. Filterable by: @@ -347,35 +320,27 @@ class StockItemTestReportList(ReportListView, StockItemReportMixin): class StockItemTestReportDetail(generics.RetrieveUpdateDestroyAPIView): - """ - API endpoint for a single TestReport object - """ + """API endpoint for a single TestReport object""" queryset = TestReport.objects.all() serializer_class = TestReportSerializer class StockItemTestReportPrint(generics.RetrieveAPIView, StockItemReportMixin, ReportPrintMixin): - """ - API endpoint for printing a TestReport object - """ + """API endpoint for printing a TestReport object""" queryset = TestReport.objects.all() serializer_class = TestReportSerializer def get(self, request, *args, **kwargs): - """ - Check if valid stock item(s) have been provided. - """ - + """Check if valid stock item(s) have been provided.""" items = self.get_items() return self.print(request, items) class BOMReportList(ReportListView, PartReportMixin): - """ - API endpoint for viewing a list of BillOfMaterialReport objects. + """API endpoint for viewing a list of BillOfMaterialReport objects. Filterably by: @@ -436,35 +401,27 @@ class BOMReportList(ReportListView, PartReportMixin): class BOMReportDetail(generics.RetrieveUpdateDestroyAPIView): - """ - API endpoint for a single BillOfMaterialReport object - """ + """API endpoint for a single BillOfMaterialReport object""" queryset = BillOfMaterialsReport.objects.all() serializer_class = BOMReportSerializer class BOMReportPrint(generics.RetrieveAPIView, PartReportMixin, ReportPrintMixin): - """ - API endpoint for printing a BillOfMaterialReport object - """ + """API endpoint for printing a BillOfMaterialReport object""" queryset = BillOfMaterialsReport.objects.all() serializer_class = BOMReportSerializer def get(self, request, *args, **kwargs): - """ - Check if valid part item(s) have been provided - """ - + """Check if valid part item(s) have been provided""" parts = self.get_parts() return self.print(request, parts) class BuildReportList(ReportListView, BuildReportMixin): - """ - API endpoint for viewing a list of BuildReport objects. + """API endpoint for viewing a list of BuildReport objects. Can be filtered by: @@ -526,18 +483,14 @@ class BuildReportList(ReportListView, BuildReportMixin): class BuildReportDetail(generics.RetrieveUpdateDestroyAPIView): - """ - API endpoint for a single BuildReport object - """ + """API endpoint for a single BuildReport object""" queryset = BuildReport.objects.all() serializer_class = BuildReportSerializer class BuildReportPrint(generics.RetrieveAPIView, BuildReportMixin, ReportPrintMixin): - """ - API endpoint for printing a BuildReport - """ + """API endpoint for printing a BuildReport""" queryset = BuildReport.objects.all() serializer_class = BuildReportSerializer @@ -607,18 +560,14 @@ class PurchaseOrderReportList(ReportListView, OrderReportMixin): class PurchaseOrderReportDetail(generics.RetrieveUpdateDestroyAPIView): - """ - API endpoint for a single PurchaseOrderReport object - """ + """API endpoint for a single PurchaseOrderReport object""" queryset = PurchaseOrderReport.objects.all() serializer_class = PurchaseOrderReportSerializer class PurchaseOrderReportPrint(generics.RetrieveAPIView, OrderReportMixin, ReportPrintMixin): - """ - API endpoint for printing a PurchaseOrderReport object - """ + """API endpoint for printing a PurchaseOrderReport object""" OrderModel = order.models.PurchaseOrder @@ -690,18 +639,14 @@ class SalesOrderReportList(ReportListView, OrderReportMixin): class SalesOrderReportDetail(generics.RetrieveUpdateDestroyAPIView): - """ - API endpoint for a single SalesOrderReport object - """ + """API endpoint for a single SalesOrderReport object""" queryset = SalesOrderReport.objects.all() serializer_class = SalesOrderReportSerializer class SalesOrderReportPrint(generics.RetrieveAPIView, OrderReportMixin, ReportPrintMixin): - """ - API endpoint for printing a PurchaseOrderReport object - """ + """API endpoint for printing a PurchaseOrderReport object""" OrderModel = order.models.SalesOrder diff --git a/InvenTree/report/apps.py b/InvenTree/report/apps.py index cc7fd6eded..2c93ba5496 100644 --- a/InvenTree/report/apps.py +++ b/InvenTree/report/apps.py @@ -14,19 +14,13 @@ class ReportConfig(AppConfig): name = 'report' def ready(self): - """ - This function is called whenever the report app is loaded - """ - + """This function is called whenever the report app is loaded""" if canAppAccessDatabase(allow_test=True): self.create_default_test_reports() self.create_default_build_reports() def create_default_reports(self, model, reports): - """ - Copy defualt report files across to the media directory. - """ - + """Copy defualt report files across to the media directory.""" # Source directory for report templates src_dir = os.path.join( os.path.dirname(os.path.realpath(__file__)), @@ -82,11 +76,7 @@ class ReportConfig(AppConfig): pass def create_default_test_reports(self): - """ - Create database entries for the default TestReport templates, - if they do not already exist - """ - + """Create database entries for the default TestReport templates, if they do not already exist""" try: from .models import TestReport except: # pragma: no cover @@ -105,11 +95,7 @@ class ReportConfig(AppConfig): self.create_default_reports(TestReport, reports) def create_default_build_reports(self): - """ - Create database entries for the default BuildReport templates - (if they do not already exist) - """ - + """Create database entries for the default BuildReport templates (if they do not already exist)""" try: from .models import BuildReport except: # pragma: no cover diff --git a/InvenTree/report/models.py b/InvenTree/report/models.py index 7714b42306..86c172727d 100644 --- a/InvenTree/report/models.py +++ b/InvenTree/report/models.py @@ -1,6 +1,4 @@ -""" -Report template model definitions -""" +"""Report template model definitions""" import datetime import logging @@ -36,59 +34,41 @@ logger = logging.getLogger("inventree") def rename_template(instance, filename): - """ - Helper function for 'renaming' uploaded report files. + """Helper function for 'renaming' uploaded report files. + Pass responsibility back to the calling class, to ensure that files are uploaded to the correct directory. """ - return instance.rename_file(filename) def validate_stock_item_report_filters(filters): - """ - Validate filter string against StockItem model - """ - + """Validate filter string against StockItem model""" return validateFilterString(filters, model=stock.models.StockItem) def validate_part_report_filters(filters): - """ - Validate filter string against Part model - """ - + """Validate filter string against Part model""" return validateFilterString(filters, model=part.models.Part) def validate_build_report_filters(filters): - """ - Validate filter string against Build model - """ - + """Validate filter string against Build model""" return validateFilterString(filters, model=build.models.Build) def validate_purchase_order_filters(filters): - """ - Validate filter string against PurchaseOrder model - """ - + """Validate filter string against PurchaseOrder model""" return validateFilterString(filters, model=order.models.PurchaseOrder) def validate_sales_order_filters(filters): - """ - Validate filter string against SalesOrder model - """ - + """Validate filter string against SalesOrder model""" return validateFilterString(filters, model=order.models.SalesOrder) class WeasyprintReportMixin(WeasyTemplateResponseMixin): - """ - Class for rendering a HTML template to a PDF. - """ + """Class for rendering a HTML template to a PDF.""" pdf_filename = 'report.pdf' pdf_attachment = True @@ -101,9 +81,7 @@ class WeasyprintReportMixin(WeasyTemplateResponseMixin): class ReportBase(models.Model): - """ - Base class for uploading html templates - """ + """Base class for uploading html templates""" class Meta: abstract = True @@ -151,11 +129,10 @@ class ReportBase(models.Model): @property def template_name(self): - """ - Returns the file system path to the template file. + """Returns the file system path to the template file. + Required for passing the file to an external process """ - template = self.template.name template = template.replace('/', os.path.sep) template = template.replace('\\', os.path.sep) @@ -192,28 +169,20 @@ class ReportBase(models.Model): class ReportTemplateBase(ReportBase): - """ - Reporting template model. + """Reporting template model. Able to be passed context data - """ # Pass a single top-level object to the report template object_to_print = None def get_context_data(self, request): - """ - Supply context data to the template for rendering - """ - + """Supply context data to the template for rendering""" return {} def context(self, request): - """ - All context to be passed to the renderer. - """ - + """All context to be passed to the renderer.""" # Generate custom context data based on the particular report subclass context = self.get_context_data(request) @@ -230,10 +199,7 @@ class ReportTemplateBase(ReportBase): return context def generate_filename(self, request, **kwargs): - """ - Generate a filename for this report - """ - + """Generate a filename for this report""" template_string = Template(self.filename_pattern) ctx = self.context(request) @@ -243,21 +209,17 @@ class ReportTemplateBase(ReportBase): return template_string.render(context) def render_as_string(self, request, **kwargs): - """ - Render the report to a HTML string. + """Render the report to a HTML string. Useful for debug mode (viewing generated code) """ - return render_to_string(self.template_name, self.context(request), request) def render(self, request, **kwargs): - """ - Render the template to a PDF file. + """Render the template to a PDF file. Uses django-weasyprint plugin to render HTML template against Weasyprint """ - # TODO: Support custom filename generation! # filename = kwargs.get('filename', 'report.pdf') @@ -292,9 +254,7 @@ class ReportTemplateBase(ReportBase): class TestReport(ReportTemplateBase): - """ - Render a TestReport against a StockItem object. - """ + """Render a TestReport against a StockItem object.""" @staticmethod def get_api_url(): @@ -321,10 +281,7 @@ class TestReport(ReportTemplateBase): ) def matches_stock_item(self, item): - """ - Test if this report template matches a given StockItem objects - """ - + """Test if this report template matches a given StockItem objects""" try: filters = validateFilterString(self.filters) items = stock.models.StockItem.objects.filter(**filters) @@ -352,9 +309,7 @@ class TestReport(ReportTemplateBase): class BuildReport(ReportTemplateBase): - """ - Build order / work order report - """ + """Build order / work order report""" @staticmethod def get_api_url(): @@ -375,10 +330,7 @@ class BuildReport(ReportTemplateBase): ) def get_context_data(self, request): - """ - Custom context data for the build report - """ - + """Custom context data for the build report""" my_build = self.object_to_print if type(my_build) != build.models.Build: @@ -395,9 +347,7 @@ class BuildReport(ReportTemplateBase): class BillOfMaterialsReport(ReportTemplateBase): - """ - Render a Bill of Materials against a Part object - """ + """Render a Bill of Materials against a Part object""" @staticmethod def get_api_url(): @@ -429,9 +379,7 @@ class BillOfMaterialsReport(ReportTemplateBase): class PurchaseOrderReport(ReportTemplateBase): - """ - Render a report against a PurchaseOrder object - """ + """Render a report against a PurchaseOrder object""" @staticmethod def get_api_url(): @@ -468,9 +416,7 @@ class PurchaseOrderReport(ReportTemplateBase): class SalesOrderReport(ReportTemplateBase): - """ - Render a report against a SalesOrder object - """ + """Render a report against a SalesOrder object""" @staticmethod def get_api_url(): @@ -530,9 +476,7 @@ def rename_snippet(instance, filename): class ReportSnippet(models.Model): - """ - Report template 'snippet' which can be used to make templates - that can then be included in other reports. + """Report template 'snippet' which can be used to make templates that can then be included in other reports. Useful for 'common' template actions, sub-templates, etc """ @@ -568,6 +512,7 @@ def rename_asset(instance, filename): class ReportAsset(models.Model): """Asset file for use in report templates. + For example, an image to use in a header file. Uploaded asset files appear in MEDIA_ROOT/report/assets, and can be loaded in a template using the {% report_asset %} tag.