From 193a9d46a760fc78619445742dfe930665ec9e40 Mon Sep 17 00:00:00 2001 From: Matthias Mair Date: Sun, 24 Mar 2024 19:55:10 +0100 Subject: [PATCH 01/23] add pyright for typing --- .github/workflows/qc_checks.yaml | 4 ++++ InvenTree/InvenTree/admin.py | 4 +++- InvenTree/InvenTree/format.py | 4 ++-- InvenTree/plugin/api.py | 2 +- InvenTree/plugin/plugin.py | 18 +++++++++--------- pyproject.toml | 12 ++++++++++++ requirements-dev.in | 1 + requirements-dev.txt | 5 ++++- 8 files changed, 36 insertions(+), 14 deletions(-) diff --git a/.github/workflows/qc_checks.yaml b/.github/workflows/qc_checks.yaml index dc524bac38e..99c6be09da0 100644 --- a/.github/workflows/qc_checks.yaml +++ b/.github/workflows/qc_checks.yaml @@ -88,6 +88,10 @@ jobs: cache: 'pip' - name: Run pre-commit Checks uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # pin@v3.0.1 + - uses: jakebailey/pyright-action@v1 + name: Pyright + with: + version: 1.1.xxx - name: Check Version run: | pip install requests diff --git a/InvenTree/InvenTree/admin.py b/InvenTree/InvenTree/admin.py index 1c79d07cc14..ad1825c2d28 100644 --- a/InvenTree/InvenTree/admin.py +++ b/InvenTree/InvenTree/admin.py @@ -1,5 +1,7 @@ """Admin classes.""" +from typing import List + from django.contrib import admin from django.db.models.fields import CharField from django.http.request import HttpRequest @@ -21,7 +23,7 @@ class InvenTreeResource(ModelResource): MAX_IMPORT_COLS = 100 # List of fields which should be converted to empty strings if they are null - CONVERT_NULL_FIELDS = [] + CONVERT_NULL_FIELDS: List[str] = [] def import_data_inner( self, diff --git a/InvenTree/InvenTree/format.py b/InvenTree/InvenTree/format.py index b03d28f2a86..9ba58f61292 100644 --- a/InvenTree/InvenTree/format.py +++ b/InvenTree/InvenTree/format.py @@ -182,8 +182,8 @@ def extract_named_group(name: str, value: str, fmt_string: str) -> str: def format_money( money: Money, - decimal_places: int = None, - format: str = None, + decimal_places: int | None = None, + format: str | None = None, include_symbol: bool = True, ) -> str: """Format money object according to the currently set local. diff --git a/InvenTree/plugin/api.py b/InvenTree/plugin/api.py index be16328c0a2..5d7ae798f4a 100644 --- a/InvenTree/plugin/api.py +++ b/InvenTree/plugin/api.py @@ -260,7 +260,7 @@ class PluginSettingList(ListAPI): filterset_fields = ['plugin__active', 'plugin__key'] -def check_plugin(plugin_slug: str, plugin_pk: int) -> InvenTreePlugin: +def check_plugin(plugin_slug: str | None, plugin_pk: int | None) -> InvenTreePlugin: """Check that a plugin for the provided slug exists and get the config. Args: diff --git a/InvenTree/plugin/plugin.py b/InvenTree/plugin/plugin.py index 6cafd510c0c..64c3f03e4d5 100644 --- a/InvenTree/plugin/plugin.py +++ b/InvenTree/plugin/plugin.py @@ -23,9 +23,9 @@ class MetaBase: """Base class for a plugins metadata.""" # Override the plugin name for each concrete plugin instance - NAME = '' - SLUG = None - TITLE = None + NAME: str = '' + SLUG: str | None = None + TITLE: str | None = None def get_meta_value(self, key: str, old_key: str = None, __default=None): """Reference a meta item with a key. @@ -212,12 +212,12 @@ class InvenTreePlugin(VersionMixin, MixinBase, MetaBase): DO NOT USE THIS DIRECTLY, USE plugin.InvenTreePlugin """ - AUTHOR = None - DESCRIPTION = None - PUBLISH_DATE = None - VERSION = None - WEBSITE = None - LICENSE = None + AUTHOR: str | None = None + DESCRIPTION: str | None = None + PUBLISH_DATE: str | None = None + VERSION: str | None = None + WEBSITE: str | None = None + LICENSE: str | None = None def __init__(self): """Init a plugin. diff --git a/pyproject.toml b/pyproject.toml index ec7114a6a86..b39d610c0a4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -79,3 +79,15 @@ src_paths=["InvenTree", "../InvenTree"] skip_glob ="*/migrations/*.py" known_django="django" sections=["FUTURE","STDLIB","DJANGO","THIRDPARTY","FIRSTPARTY","LOCALFOLDER"] + +[tool.pyright] +include = ["InvenTree"] +exclude = ["**/node_modules","**/__pycache__",] +defineConstant = { DEBUG = true } + +reportMissingImports = true +reportMissingTypeStubs = false +reportIncompatibleMethodOverride = false + +pythonVersion = "3.9" +pythonPlatform = "Linux" diff --git a/requirements-dev.in b/requirements-dev.in index d27042e739c..a717ddc3f38 100644 --- a/requirements-dev.in +++ b/requirements-dev.in @@ -9,3 +9,4 @@ pip-tools # Compile pip requirements pre-commit # Git pre-commit setuptools # Standard dependency pdfminer.six # PDF validation +pyright # Static type checking diff --git a/requirements-dev.txt b/requirements-dev.txt index f22086821ac..86eb76f8a7c 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -39,7 +39,9 @@ importlib-metadata==6.11.0 # via build isort==5.13.2 nodeenv==1.8.0 - # via pre-commit + # via + # pre-commit + # pyright packaging==24.0 # via build pdfminer-six==20231228 @@ -55,6 +57,7 @@ pyproject-hooks==1.0.0 # via # build # pip-tools +pyright==1.1.355 pyyaml==6.0.1 # via pre-commit requests==2.31.0 From 9172e4265dd570ba9057af188bf74e2502070c8b Mon Sep 17 00:00:00 2001 From: Matthias Mair Date: Sun, 24 Mar 2024 20:34:30 +0100 Subject: [PATCH 02/23] add helper for plugin config tests --- .vscode/launch.json | 9 +++++++++ InvenTree/InvenTree/unit_test.py | 9 +++++++++ InvenTree/label/tests.py | 5 +++-- InvenTree/plugin/base/integration/test_mixins.py | 9 ++++----- InvenTree/plugin/base/label/test_label_mixin.py | 4 ++-- InvenTree/plugin/samples/event/test_event_sample.py | 3 ++- .../plugin/samples/event/test_filtered_event_sample.py | 5 +++-- .../samples/integration/test_simpleactionplugin.py | 4 ++-- InvenTree/plugin/samples/locate/test_locate_sample.py | 4 ++-- 9 files changed, 36 insertions(+), 16 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index a3029a03250..779057f2579 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -22,6 +22,15 @@ "django": true, "justMyCode": false }, + { + "name": "InvenTree Server - spec", + "type": "python", + "request": "launch", + "program": "${workspaceFolder}/InvenTree/manage.py", + "args": ["spectacular", "--fail-on-warn", "--validate", "--color"], + "django": true, + "justMyCode": false + }, { "name": "InvenTree Frontend - Vite", "type": "chrome", diff --git a/InvenTree/InvenTree/unit_test.py b/InvenTree/InvenTree/unit_test.py index 38713e0fb04..05e5bbe1d25 100644 --- a/InvenTree/InvenTree/unit_test.py +++ b/InvenTree/InvenTree/unit_test.py @@ -89,6 +89,15 @@ def getNewestMigrationFile(app, exclude_extension=True): return newest_file +def get_plugin_config(plugin_slug): + """Return the plugin config for the specified plugin.""" + plg = registry.get_plugin(plugin_slug) + assert plg is not None + cfg = plg.plugin_config() + assert cfg is not None + return cfg + + class UserMixin: """Mixin to setup a user and login for tests. diff --git a/InvenTree/label/tests.py b/InvenTree/label/tests.py index b4afce22168..46f4d58c7a3 100644 --- a/InvenTree/label/tests.py +++ b/InvenTree/label/tests.py @@ -12,7 +12,7 @@ from common.models import InvenTreeSetting from InvenTree.helpers import validateFilterString -from InvenTree.unit_test import InvenTreeAPITestCase +from InvenTree.unit_test import InvenTreeAPITestCase, get_plugin_config from label.models import LabelOutput from part.models import Part from plugin.registry import registry @@ -118,13 +118,14 @@ def test_print_part_label(self): InvenTreeSetting.set_setting('REPORT_ENABLE', True, None) # Set the 'debug' setting for the plugin - plugin = registry.get_plugin('inventreelabel') + plugin = get_plugin_config('inventreelabel') plugin.set_setting('DEBUG', True) # Print via the API (Note: will default to the builtin plugin if no plugin supplied) url = reverse('api-part-label-print', kwargs={'pk': label.pk}) prt = Part.objects.first() + assert prt is not None part_pk = prt.pk part_name = prt.name diff --git a/InvenTree/plugin/base/integration/test_mixins.py b/InvenTree/plugin/base/integration/test_mixins.py index 0cba7f5854c..780ed273bbd 100644 --- a/InvenTree/plugin/base/integration/test_mixins.py +++ b/InvenTree/plugin/base/integration/test_mixins.py @@ -8,7 +8,7 @@ from error_report.models import Error -from InvenTree.unit_test import InvenTreeTestCase +from InvenTree.unit_test import InvenTreeTestCase, get_plugin_config from plugin import InvenTreePlugin from plugin.base.integration.mixins import PanelMixin from plugin.helpers import MixinNotImplementedError @@ -367,12 +367,13 @@ def test_installed(self): def test_disabled(self): """Test that the panels *do not load* if the plugin is not enabled.""" plugin = registry.get_plugin('samplepanel') + assert plugin is not None plugin.set_setting('ENABLE_HELLO_WORLD', True) plugin.set_setting('ENABLE_BROKEN_PANEL', True) # Ensure that the plugin is *not* enabled - config = plugin.plugin_config() + config = get_plugin_config('samplepanel') self.assertFalse(config.active) @@ -394,12 +395,10 @@ def test_disabled(self): @tag('cui') def test_enabled(self): """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) # Ensure that the plugin is enabled - config = plugin.plugin_config() + config = get_plugin_config('samplepanel') config.active = True config.save() diff --git a/InvenTree/plugin/base/label/test_label_mixin.py b/InvenTree/plugin/base/label/test_label_mixin.py index 29b986af0ce..cf00b88f281 100644 --- a/InvenTree/plugin/base/label/test_label_mixin.py +++ b/InvenTree/plugin/base/label/test_label_mixin.py @@ -11,7 +11,7 @@ from PIL import Image from InvenTree.settings import BASE_DIR -from InvenTree.unit_test import InvenTreeAPITestCase +from InvenTree.unit_test import InvenTreeAPITestCase, get_plugin_config from label.models import PartLabel, StockItemLabel, StockLocationLabel from part.models import Part from plugin.base.label.mixins import LabelPrintingMixin @@ -30,7 +30,7 @@ class LabelMixinTests(InvenTreeAPITestCase): def do_activate_plugin(self): """Activate the 'samplelabel' plugin.""" - config = registry.get_plugin('samplelabelprinter').plugin_config() + config = get_plugin_config('samplelabelprinter') config.active = True config.save() diff --git a/InvenTree/plugin/samples/event/test_event_sample.py b/InvenTree/plugin/samples/event/test_event_sample.py index 0e5eb9b86d3..6f46a8916dd 100644 --- a/InvenTree/plugin/samples/event/test_event_sample.py +++ b/InvenTree/plugin/samples/event/test_event_sample.py @@ -4,6 +4,7 @@ from django.test import TestCase from common.models import InvenTreeSetting +from InvenTree.unit_test import get_plugin_config from plugin import InvenTreePlugin, registry from plugin.base.event.events import trigger_event from plugin.helpers import MixinNotImplementedError @@ -18,7 +19,7 @@ class EventPluginSampleTests(TestCase): def test_run_event(self): """Check if the event is issued.""" # Activate plugin - config = registry.get_plugin('sampleevent').plugin_config() + config = get_plugin_config('sampleevent') config.active = True config.save() diff --git a/InvenTree/plugin/samples/event/test_filtered_event_sample.py b/InvenTree/plugin/samples/event/test_filtered_event_sample.py index 1da5a3b499e..6386a54d265 100644 --- a/InvenTree/plugin/samples/event/test_filtered_event_sample.py +++ b/InvenTree/plugin/samples/event/test_filtered_event_sample.py @@ -4,6 +4,7 @@ from django.test import TestCase from common.models import InvenTreeSetting +from InvenTree.unit_test import get_plugin_config from plugin import registry from plugin.base.event.events import trigger_event @@ -16,7 +17,7 @@ class FilteredEventPluginSampleTests(TestCase): def test_run_event(self): """Check if the event is issued.""" # Activate plugin - config = registry.get_plugin('filteredsampleevent').plugin_config() + config = get_plugin_config('filteredsampleevent') config.active = True config.save() @@ -37,7 +38,7 @@ def test_run_event(self): def test_ignore_event(self): """Check if the event is issued.""" # Activate plugin - config = registry.get_plugin('filteredsampleevent').plugin_config() + config = get_plugin_config('filteredsampleevent') config.active = True config.save() diff --git a/InvenTree/plugin/samples/integration/test_simpleactionplugin.py b/InvenTree/plugin/samples/integration/test_simpleactionplugin.py index 57ee67bd4db..bd7b47f6d13 100644 --- a/InvenTree/plugin/samples/integration/test_simpleactionplugin.py +++ b/InvenTree/plugin/samples/integration/test_simpleactionplugin.py @@ -1,6 +1,6 @@ """Unit tests for action plugins.""" -from InvenTree.unit_test import InvenTreeTestCase +from InvenTree.unit_test import InvenTreeTestCase, get_plugin_config from plugin.registry import registry from plugin.samples.integration.simpleactionplugin import SimpleActionPlugin @@ -16,7 +16,7 @@ def test_name(self): def set_plugin_state(self, state: bool): """Set the enabled state of the SimpleActionPlugin.""" - cfg = registry.get_plugin_config('simpleaction') + cfg = get_plugin_config('simpleaction') cfg.active = state cfg.save() diff --git a/InvenTree/plugin/samples/locate/test_locate_sample.py b/InvenTree/plugin/samples/locate/test_locate_sample.py index e34d0de0aea..dd7ac88e290 100644 --- a/InvenTree/plugin/samples/locate/test_locate_sample.py +++ b/InvenTree/plugin/samples/locate/test_locate_sample.py @@ -2,7 +2,7 @@ from django.urls import reverse -from InvenTree.unit_test import InvenTreeAPITestCase +from InvenTree.unit_test import InvenTreeAPITestCase, get_plugin_config from plugin import InvenTreePlugin, registry from plugin.helpers import MixinNotImplementedError from plugin.mixins import LocateMixin @@ -16,7 +16,7 @@ class SampleLocatePlugintests(InvenTreeAPITestCase): def test_run_locator(self): """Check if the event is issued.""" # Activate plugin - config = registry.get_plugin('samplelocate').plugin_config() + config = get_plugin_config('samplelocate') config.active = True config.save() From b265c2d12ca3fc763dea30e4a6b5c72ecff821a3 Mon Sep 17 00:00:00 2001 From: Matthias Mair Date: Sun, 24 Mar 2024 20:35:17 +0100 Subject: [PATCH 03/23] fix usage of modern annotations --- InvenTree/plugin/api.py | 2 ++ InvenTree/plugin/plugin.py | 2 ++ InvenTree/plugin/registry.py | 2 ++ 3 files changed, 6 insertions(+) diff --git a/InvenTree/plugin/api.py b/InvenTree/plugin/api.py index 5d7ae798f4a..f44630370fb 100644 --- a/InvenTree/plugin/api.py +++ b/InvenTree/plugin/api.py @@ -1,5 +1,7 @@ """API for the plugin app.""" +from __future__ import annotations + from django.core.exceptions import ValidationError from django.urls import include, path, re_path from django.utils.translation import gettext_lazy as _ diff --git a/InvenTree/plugin/plugin.py b/InvenTree/plugin/plugin.py index 64c3f03e4d5..40d7533248d 100644 --- a/InvenTree/plugin/plugin.py +++ b/InvenTree/plugin/plugin.py @@ -1,5 +1,7 @@ """Base Class for InvenTree plugins.""" +from __future__ import annotations + import inspect import logging import warnings diff --git a/InvenTree/plugin/registry.py b/InvenTree/plugin/registry.py index ee68b0d04f0..4ce50e6688f 100644 --- a/InvenTree/plugin/registry.py +++ b/InvenTree/plugin/registry.py @@ -4,6 +4,8 @@ - Manages setup and teardown of plugin class instances """ +from __future__ import annotations + import imp import importlib import logging From 11f76ed6148c8571e487c03b94dc5e26fb01c289 Mon Sep 17 00:00:00 2001 From: Matthias Mair Date: Sun, 24 Mar 2024 21:09:00 +0100 Subject: [PATCH 04/23] more types / refactors --- .../plugin/base/barcodes/test_barcode.py | 12 +++++------ .../plugin/base/integration/test_mixins.py | 16 +++++++++------ InvenTree/plugin/base/locate/test_locate.py | 1 + .../barcodes/test_inventree_barcode.py | 9 ++++----- .../integration/test_core_notifications.py | 1 + .../suppliers/test_supplier_barcodes.py | 7 +++++++ InvenTree/plugin/registry.py | 4 ++-- .../plugin/samples/event/test_event_sample.py | 2 +- .../plugin/samples/integration/test_sample.py | 2 ++ .../integration/test_validation_sample.py | 4 ++++ InvenTree/plugin/test_api.py | 14 ++++++++++--- InvenTree/plugin/test_plugin.py | 20 ++++++++++--------- 12 files changed, 60 insertions(+), 32 deletions(-) diff --git a/InvenTree/plugin/base/barcodes/test_barcode.py b/InvenTree/plugin/base/barcodes/test_barcode.py index f6985908845..e6e021ef1de 100644 --- a/InvenTree/plugin/base/barcodes/test_barcode.py +++ b/InvenTree/plugin/base/barcodes/test_barcode.py @@ -57,14 +57,14 @@ def test_empty(self): """ response = self.postBarcode(self.scan_url, '', expected_code=400) - data = response.data - self.assertIn('barcode', data) + self.assertIn('barcode', response.data) self.assertIn('This field may not be blank', str(response.data['barcode'])) def test_find_part(self): """Test that we can lookup a part based on ID.""" part = Part.objects.first() + assert part is not None response = self.post( self.scan_url, {'barcode': f'{{"part": {part.pk}}}'}, expected_code=200 @@ -85,6 +85,7 @@ def test_invalid_part(self): def test_find_stock_item(self): """Test that we can lookup a stock item based on ID.""" item = StockItem.objects.first() + assert item is not None response = self.post( self.scan_url, {'barcode': item.format_barcode()}, expected_code=200 @@ -126,15 +127,13 @@ def test_integer_barcode(self): """Test scan of an integer barcode.""" response = self.postBarcode(self.scan_url, '123456789', expected_code=400) - data = response.data - self.assertIn('error', data) + self.assertIn('error', response.data) def test_array_barcode(self): """Test scan of barcode with string encoded array.""" response = self.postBarcode(self.scan_url, "['foo', 'bar']", expected_code=400) - data = response.data - self.assertIn('error', data) + self.assertIn('error', response.data) def test_barcode_generation(self): """Test that a barcode is generated with a scan.""" @@ -300,6 +299,7 @@ def test_invalid_barcode(self): # Test with a barcode that matches a *different* stock item item = StockItem.objects.exclude(pk=self.stock_item.pk).first() + assert item is not None item.assign_barcode(barcode_data='123456789') result = self.postBarcode( diff --git a/InvenTree/plugin/base/integration/test_mixins.py b/InvenTree/plugin/base/integration/test_mixins.py index 780ed273bbd..c1a5d2055cc 100644 --- a/InvenTree/plugin/base/integration/test_mixins.py +++ b/InvenTree/plugin/base/integration/test_mixins.py @@ -93,7 +93,7 @@ def setUp(self): """Setup for all tests.""" class UrlsCls(UrlsMixin, InvenTreePlugin): - def test(): + def test(self): return 'ccc' URLS = [path('testpath', test, name='test')] @@ -108,6 +108,7 @@ class NoUrlsCls(UrlsMixin, InvenTreePlugin): def test_function(self): """Test that the mixin functions.""" plg_name = self.mixin.plugin_name() + assert plg_name is not None # base_url target_url = f'{PLUGIN_BASE}/{plg_name}/' @@ -117,13 +118,14 @@ def test_function(self): target_pattern = re_path( f'^{plg_name}/', include((self.mixin.urls, plg_name)), name=plg_name ) - self.assertEqual( - self.mixin.urlpatterns.reverse_dict, target_pattern.reverse_dict - ) + + mx_patterns = self.mixin.urlpatterns + assert mx_patterns is not None + self.assertEqual(mx_patterns.reverse_dict, target_pattern.reverse_dict) # resolve the view - self.assertEqual(self.mixin.urlpatterns.resolve('/testpath').func(), 'ccc') - self.assertEqual(self.mixin.urlpatterns.reverse('test'), 'testpath') + self.assertEqual(mx_patterns.resolve('/testpath').func(), 'ccc') + self.assertEqual(mx_patterns.reverse('test'), 'testpath') # no url self.assertIsNone(self.mixin_nothing.urls) @@ -412,6 +414,8 @@ def test_enabled(self): reverse('stock-location-detail', kwargs={'pk': 2}), ] + plugin = registry.get_plugin('samplepanel') + assert plugin is not None plugin.set_setting('ENABLE_HELLO_WORLD', False) plugin.set_setting('ENABLE_BROKEN_PANEL', False) diff --git a/InvenTree/plugin/base/locate/test_locate.py b/InvenTree/plugin/base/locate/test_locate.py index e47d4a6cb58..621d8b6cfed 100644 --- a/InvenTree/plugin/base/locate/test_locate.py +++ b/InvenTree/plugin/base/locate/test_locate.py @@ -71,6 +71,7 @@ def test_locate_item(self): url = reverse('api-locate-plugin') item = StockItem.objects.get(pk=1) + assert item is not None # The sample plugin will set the 'located' metadata tag item.set_metadata('located', False) diff --git a/InvenTree/plugin/builtin/barcodes/test_inventree_barcode.py b/InvenTree/plugin/builtin/barcodes/test_inventree_barcode.py index 4f5a4b405ca..5e4089f0217 100644 --- a/InvenTree/plugin/builtin/barcodes/test_inventree_barcode.py +++ b/InvenTree/plugin/builtin/barcodes/test_inventree_barcode.py @@ -61,12 +61,11 @@ def test_unassign_errors(self): self.assertIn('Missing data: Provide one of', str(response.data['error'])) # Fail with too many fields provided + stock_obj = stock.models.StockItem.objects.first() + part_obj = part.models.Part.objects.first() + assert stock_obj is not None and part_obj is not None response = self.unassign( - { - 'stockitem': stock.models.StockItem.objects.first().pk, - 'part': part.models.Part.objects.first().pk, - }, - expected_code=400, + {'stockitem': stock_obj.pk, 'part': part_obj.pk}, expected_code=400 ) self.assertIn('Multiple conflicting fields:', str(response.data['error'])) diff --git a/InvenTree/plugin/builtin/integration/test_core_notifications.py b/InvenTree/plugin/builtin/integration/test_core_notifications.py index 62d1c2b1ed6..6c07c2ecf87 100644 --- a/InvenTree/plugin/builtin/integration/test_core_notifications.py +++ b/InvenTree/plugin/builtin/integration/test_core_notifications.py @@ -20,6 +20,7 @@ def test_email(self): # enable plugin and set mail setting to true plugin = registry.get_plugin('inventreecorenotificationsplugin') + assert plugin is not None plugin.set_setting('ENABLE_NOTIFICATION_EMAILS', True) NotificationUserSetting.set_setting( key='NOTIFICATION_METHOD_MAIL', diff --git a/InvenTree/plugin/builtin/suppliers/test_supplier_barcodes.py b/InvenTree/plugin/builtin/suppliers/test_supplier_barcodes.py index 49bff6903e4..36457680d62 100644 --- a/InvenTree/plugin/builtin/suppliers/test_supplier_barcodes.py +++ b/InvenTree/plugin/builtin/suppliers/test_supplier_barcodes.py @@ -53,6 +53,7 @@ def test_digikey_barcode(self): self.assertEqual(result.data['plugin'], 'DigiKeyPlugin') supplier_part_data = result.data.get('supplierpart') + assert supplier_part_data is not None self.assertIn('pk', supplier_part_data) supplier_part = SupplierPart.objects.get(pk=supplier_part_data['pk']) @@ -66,6 +67,7 @@ def test_digikey_2_barcode(self): self.assertEqual(result.data['plugin'], 'DigiKeyPlugin') supplier_part_data = result.data.get('supplierpart') + assert supplier_part_data is not None self.assertIn('pk', supplier_part_data) supplier_part = SupplierPart.objects.get(pk=supplier_part_data['pk']) @@ -82,6 +84,7 @@ def test_mouser_barcode(self): ) supplier_part_data = result.data.get('supplierpart') + assert supplier_part_data is not None self.assertIn('pk', supplier_part_data) supplier_part = SupplierPart.objects.get(pk=supplier_part_data['pk']) @@ -94,6 +97,7 @@ def test_old_mouser_barcode(self): ) supplier_part_data = result.data.get('supplierpart') + assert supplier_part_data is not None self.assertIn('pk', supplier_part_data) supplier_part = SupplierPart.objects.get(pk=supplier_part_data['pk']) self.assertEqual(supplier_part.SKU, '2') @@ -107,6 +111,7 @@ def test_lcsc_barcode(self): self.assertEqual(result.data['plugin'], 'LCSCPlugin') supplier_part_data = result.data.get('supplierpart') + assert supplier_part_data is not None self.assertIn('pk', supplier_part_data) supplier_part = SupplierPart.objects.get(pk=supplier_part_data['pk']) @@ -121,6 +126,7 @@ def test_tme_qrcode(self): self.assertEqual(result.data['plugin'], 'TMEPlugin') supplier_part_data = result.data.get('supplierpart') + assert supplier_part_data is not None self.assertIn('pk', supplier_part_data) supplier_part = SupplierPart.objects.get(pk=supplier_part_data['pk']) self.assertEqual(supplier_part.SKU, 'WBP-302') @@ -134,6 +140,7 @@ def test_tme_barcode2d(self): self.assertEqual(result.data['plugin'], 'TMEPlugin') supplier_part_data = result.data.get('supplierpart') + assert supplier_part_data is not None self.assertIn('pk', supplier_part_data) supplier_part = SupplierPart.objects.get(pk=supplier_part_data['pk']) diff --git a/InvenTree/plugin/registry.py b/InvenTree/plugin/registry.py index 4ce50e6688f..300f3643d2a 100644 --- a/InvenTree/plugin/registry.py +++ b/InvenTree/plugin/registry.py @@ -132,7 +132,7 @@ def get_plugin_config(self, slug: str, name: [str, None] = None): try: cfg.name = name cfg.save() - except Exception as e: + except Exception: logger.exception('Failed to update plugin name') return cfg @@ -179,7 +179,7 @@ def call_plugin_function(self, slug, func, *args, **kwargs): return plugin_func(*args, **kwargs) # region registry functions - def with_mixin(self, mixin: str, active=True, builtin=None): + def with_mixin(self, mixin: str, active: bool | None = True, builtin=None): """Returns reference to all plugins that have a specified mixin enabled. Args: diff --git a/InvenTree/plugin/samples/event/test_event_sample.py b/InvenTree/plugin/samples/event/test_event_sample.py index 6f46a8916dd..75b9a57e425 100644 --- a/InvenTree/plugin/samples/event/test_event_sample.py +++ b/InvenTree/plugin/samples/event/test_event_sample.py @@ -5,7 +5,7 @@ from common.models import InvenTreeSetting from InvenTree.unit_test import get_plugin_config -from plugin import InvenTreePlugin, registry +from plugin import InvenTreePlugin from plugin.base.event.events import trigger_event from plugin.helpers import MixinNotImplementedError from plugin.mixins import EventMixin diff --git a/InvenTree/plugin/samples/integration/test_sample.py b/InvenTree/plugin/samples/integration/test_sample.py index 0d7ac58893a..2d3b855ae46 100644 --- a/InvenTree/plugin/samples/integration/test_sample.py +++ b/InvenTree/plugin/samples/integration/test_sample.py @@ -42,6 +42,7 @@ def test_view(self): def test_settings(self): """Check the SettingsMixin.check_settings function.""" plugin = registry.get_plugin('sample') + assert plugin is not None self.assertIsNotNone(plugin) # check settings @@ -54,6 +55,7 @@ def test_settings(self): def test_settings_validator(self): """Test settings validator for plugins.""" plugin = registry.get_plugin('sample') + assert plugin is not None valid_json = '{"ts": 13}' not_valid_json = '{"ts""13"}' diff --git a/InvenTree/plugin/samples/integration/test_validation_sample.py b/InvenTree/plugin/samples/integration/test_validation_sample.py index 6acff5cac9b..03da1d94acf 100644 --- a/InvenTree/plugin/samples/integration/test_validation_sample.py +++ b/InvenTree/plugin/samples/integration/test_validation_sample.py @@ -52,6 +52,8 @@ def test_validate_model_instance(self): # Next, check that we can make a part instance description shorter prt = part.models.Part.objects.first() + assert prt is not None + prt.description = prt.description[:-1] prt.save() @@ -59,6 +61,7 @@ def test_validate_model_instance(self): self.enable_plugin(True) plg = self.get_plugin() + assert plg is not None self.assertIsNotNone(plg) plg.set_setting('BOM_ITEM_INTEGER', True) @@ -99,6 +102,7 @@ def test_validate_ipn(self): """Test the validate_ipn function.""" self.enable_plugin(True) plg = self.get_plugin() + assert plg is not None self.assertIsNotNone(plg) self.part.IPN = 'LMNOP' diff --git a/InvenTree/plugin/test_api.py b/InvenTree/plugin/test_api.py index a0474c551db..36c8959b9b5 100644 --- a/InvenTree/plugin/test_api.py +++ b/InvenTree/plugin/test_api.py @@ -90,9 +90,12 @@ def test_plugin_install(self): def test_plugin_activate(self): """Test the plugin activate.""" test_plg = self.plugin_confs.first() + assert test_plg is not None def assert_plugin_active(self, active): - self.assertEqual(PluginConfig.objects.all().first().active, active) + plgs = PluginConfig.objects.all().first() + assert plgs is not None + self.assertEqual(plgs.active, active) # Should not work - not a superuser response = self.client.post(reverse('api-plugin-activate'), {}, follow=True) @@ -133,6 +136,8 @@ def test_admin_action(self): url = reverse('admin:plugin_pluginconfig_changelist') test_plg = self.plugin_confs.first() + assert test_plg is not None + # deactivate plugin response = self.client.post( url, @@ -181,6 +186,7 @@ def test_model(self): """Test the PluginConfig model.""" # check mixin registry plg = self.plugin_confs.first() + assert plg is not None mixin_dict = plg.mixins() self.assertIn('base', mixin_dict) self.assertDictContainsSubset( @@ -190,6 +196,7 @@ def test_model(self): # check reload on save with self.assertWarns(Warning) as cm: plg_inactive = self.plugin_confs.filter(active=False).first() + assert plg_inactive is not None plg_inactive.active = True plg_inactive.save() self.assertEqual(cm.warning.args[0], 'A reload was triggered') @@ -208,7 +215,7 @@ def test_check_plugin(self): # Wrong with pk with self.assertRaises(NotFound) as exc: - check_plugin(plugin_slug=None, plugin_pk='123') + check_plugin(plugin_slug=None, plugin_pk=123) self.assertEqual(str(exc.exception.detail), "Plugin '123' not installed") def test_plugin_settings(self): @@ -219,8 +226,9 @@ def test_plugin_settings(self): # Activate the 'sample' plugin via the API cfg = PluginConfig.objects.filter(key='sample').first() + assert cfg is not None url = reverse('api-plugin-detail-activate', kwargs={'pk': cfg.pk}) - self.client.patch(url, {}, expected_code=200) + self.client.patch(url, {}) # Valid plugin settings endpoints valid_settings = ['SELECT_PART', 'API_KEY', 'NUMERICAL_SETTING'] diff --git a/InvenTree/plugin/test_plugin.py b/InvenTree/plugin/test_plugin.py index 557a86b75ab..09937c46503 100644 --- a/InvenTree/plugin/test_plugin.py +++ b/InvenTree/plugin/test_plugin.py @@ -194,6 +194,7 @@ def test_version(self): self.assertFalse(self.plugin_version.check_version([0, 1, 4])) plug = registry.plugins_full.get('sampleversion') + assert plug is not None self.assertEqual(plug.is_active(), False) @@ -214,6 +215,7 @@ def run_package_test(self, directory): # Depends on the meta set in InvenTree/plugin/mock/simple:SimplePlugin plg = registry.get_plugin('simple') + assert plg is not None self.assertEqual(plg.slug, 'simple') self.assertEqual(plg.human_name, 'SimplePlugin') @@ -259,6 +261,7 @@ def test_package_loading(self): # Test that plugin was installed plg = registry.get_plugin('zapier') + assert plg is not None self.assertEqual(plg.slug, 'zapier') self.assertEqual(plg.name, 'inventree_zapier') @@ -275,13 +278,12 @@ def test_broken_samples(self): self.assertEqual(len(registry.errors), 3) # There should be at least one discovery error in the module `broken_file` - self.assertTrue(len(registry.errors.get('discovery')) > 0) - self.assertEqual( - registry.errors.get('discovery')[0]['broken_file'], - "name 'bb' is not defined", - ) + _reg_disc = registry.errors.get('discovery') + assert _reg_disc is not None + self.assertTrue(len(_reg_disc) > 0) + self.assertEqual(_reg_disc[0]['broken_file'], "name 'bb' is not defined") # There should be at least one load error with an intentional KeyError - self.assertTrue(len(registry.errors.get('load')) > 0) - self.assertEqual( - registry.errors.get('load')[0]['broken_sample'], "'This is a dummy error'" - ) + _reg_load = registry.errors.get('load') + assert _reg_load is not None + self.assertTrue(len(_reg_load) > 0) + self.assertEqual(_reg_load[0]['broken_sample'], "'This is a dummy error'") From 55a5d882fedc62d4424d96720cd7c24fbad9cecd Mon Sep 17 00:00:00 2001 From: Matthias Mair Date: Sun, 24 Mar 2024 21:20:06 +0100 Subject: [PATCH 05/23] pyright settings --- pyproject.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index b39d610c0a4..6a8aa99fd15 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -88,6 +88,9 @@ defineConstant = { DEBUG = true } reportMissingImports = true reportMissingTypeStubs = false reportIncompatibleMethodOverride = false +reportAttributeAccessIssue = false +reportIndexIssue = false +reportIncompatibleVariableOverride = false pythonVersion = "3.9" pythonPlatform = "Linux" From 3618d70e48e57cf111f64718f53a54cc54fcadc2 Mon Sep 17 00:00:00 2001 From: Matthias Mair Date: Sun, 24 Mar 2024 21:20:37 +0100 Subject: [PATCH 06/23] alter type for Response --- InvenTree/InvenTree/unit_test.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/InvenTree/InvenTree/unit_test.py b/InvenTree/InvenTree/unit_test.py index 05e5bbe1d25..45c8d40aa37 100644 --- a/InvenTree/InvenTree/unit_test.py +++ b/InvenTree/InvenTree/unit_test.py @@ -6,9 +6,11 @@ import re from contextlib import contextmanager from pathlib import Path +from typing import Any from django.contrib.auth import get_user_model from django.contrib.auth.models import Group, Permission +from django.core.handlers.wsgi import WSGIRequest from django.db import connections from django.http.response import StreamingHttpResponse from django.test import TestCase @@ -20,6 +22,8 @@ from plugin import registry from plugin.models import PluginConfig +MyResponse = Any | WSGIRequest + def addUserPermission(user, permission): """Shortcut function for adding a certain permission to a user.""" @@ -302,7 +306,7 @@ def get(self, url, data=None, expected_code=200, format='json', **kwargs): if data is None: data = {} - response = self.client.get(url, data, format=format, **kwargs) + response: MyResponse = self.client.get(url, data, format=format, **kwargs) self.checkResponse(url, 'GET', expected_code, response) @@ -314,7 +318,7 @@ def post(self, url, data=None, expected_code=None, format='json', **kwargs): if data is None: data = {} - response = self.client.post(url, data=data, format=format, **kwargs) + response: MyResponse = self.client.post(url, data=data, format=format, **kwargs) self.checkResponse(url, 'POST', expected_code, response) @@ -325,7 +329,9 @@ def delete(self, url, data=None, expected_code=None, format='json', **kwargs): if data is None: data = {} - response = self.client.delete(url, data=data, format=format, **kwargs) + response: MyResponse = self.client.delete( + url, data=data, format=format, **kwargs + ) self.checkResponse(url, 'DELETE', expected_code, response) @@ -333,7 +339,9 @@ def delete(self, url, data=None, expected_code=None, format='json', **kwargs): def patch(self, url, data, expected_code=None, format='json', **kwargs): """Issue a PATCH request.""" - response = self.client.patch(url, data=data, format=format, **kwargs) + response: MyResponse = self.client.patch( + url, data=data, format=format, **kwargs + ) self.checkResponse(url, 'PATCH', expected_code, response) @@ -341,7 +349,7 @@ def patch(self, url, data, expected_code=None, format='json', **kwargs): def put(self, url, data, expected_code=None, format='json', **kwargs): """Issue a PUT request.""" - response = self.client.put(url, data=data, format=format, **kwargs) + response: MyResponse = self.client.put(url, data=data, format=format, **kwargs) self.checkResponse(url, 'PUT', expected_code, response) @@ -359,7 +367,7 @@ def download_file( self, url, data, expected_code=None, expected_fn=None, decode=True ): """Download a file from the server, and return an in-memory file.""" - response = self.client.get(url, data=data, format='json') + response: MyResponse = self.client.get(url, data=data, format='json') self.checkResponse(url, 'DOWNLOAD_FILE', expected_code, response) From 9c1bf79b02624b36bf38a447936074389b3911bd Mon Sep 17 00:00:00 2001 From: Matthias Mair Date: Sun, 24 Mar 2024 21:25:40 +0100 Subject: [PATCH 07/23] more fixes --- InvenTree/common/notifications.py | 10 +++++++++- .../plugin/builtin/integration/core_notifications.py | 2 ++ InvenTree/plugin/samples/locate/test_locate_sample.py | 1 + InvenTree/plugin/templatetags/plugin_extras.py | 2 ++ 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/InvenTree/common/notifications.py b/InvenTree/common/notifications.py index 7e3c4016f1f..a658d72bfa5 100644 --- a/InvenTree/common/notifications.py +++ b/InvenTree/common/notifications.py @@ -1,5 +1,7 @@ """Base classes and functions for notifications.""" +from __future__ import annotations + import logging from dataclasses import dataclass from datetime import timedelta @@ -29,6 +31,8 @@ class NotificationMethod: GLOBAL_SETTING = None USER_SETTING = None + targets: list | None = None + def __init__(self, obj, category, targets, context) -> None: """Check that the method is read. @@ -185,7 +189,7 @@ class MethodStorageClass: Is initialized on startup as one instance named `storage` in this file. """ - liste = None + liste: list | None = None user_settings = {} def collect(self, selected_classes=None): @@ -234,6 +238,10 @@ def get_usersettings(self, user) -> list: list: All applicablae notification settings. """ methods = [] + + if storage.liste is None: + return methods + for item in storage.liste: if item.USER_SETTING: new_key = f'NOTIFICATION_METHOD_{item.METHOD_NAME.upper()}' diff --git a/InvenTree/plugin/builtin/integration/core_notifications.py b/InvenTree/plugin/builtin/integration/core_notifications.py index 298677c4ecd..3f38650223b 100644 --- a/InvenTree/plugin/builtin/integration/core_notifications.py +++ b/InvenTree/plugin/builtin/integration/core_notifications.py @@ -87,6 +87,8 @@ def get_targets(self): """Return a list of target email addresses, only for users which allow email notifications.""" allowed_users = [] + if not self.targets: + return [] for user in self.targets: if not user.is_active: # Ignore any users who have been deactivated diff --git a/InvenTree/plugin/samples/locate/test_locate_sample.py b/InvenTree/plugin/samples/locate/test_locate_sample.py index dd7ac88e290..539f2fdd00f 100644 --- a/InvenTree/plugin/samples/locate/test_locate_sample.py +++ b/InvenTree/plugin/samples/locate/test_locate_sample.py @@ -54,6 +54,7 @@ class Wrong(LocateMixin, InvenTreePlugin): plugin = Wrong() plugin.locate_stock_location(1) + assert plugin is not None # Test item locator with self.assertRaises(MixinNotImplementedError): diff --git a/InvenTree/plugin/templatetags/plugin_extras.py b/InvenTree/plugin/templatetags/plugin_extras.py index 0483b1588e2..d633c0da306 100644 --- a/InvenTree/plugin/templatetags/plugin_extras.py +++ b/InvenTree/plugin/templatetags/plugin_extras.py @@ -85,6 +85,8 @@ def notification_settings_list(context, *args, **kwargs): @register.simple_tag(takes_context=True) def notification_list(context, *args, **kwargs): """List of all notification methods.""" + if storage.liste is None: + return [] return [ { 'slug': a.METHOD_NAME, From 61d7b874bc1ad4efa9fc9997e90915f8f05b4aa5 Mon Sep 17 00:00:00 2001 From: Matthias Mair Date: Sun, 24 Mar 2024 21:27:58 +0100 Subject: [PATCH 08/23] fix annotations style --- InvenTree/InvenTree/format.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/InvenTree/InvenTree/format.py b/InvenTree/InvenTree/format.py index 9ba58f61292..d91d0e034e9 100644 --- a/InvenTree/InvenTree/format.py +++ b/InvenTree/InvenTree/format.py @@ -1,5 +1,7 @@ """Custom string formatting functions and helpers.""" +from __future__ import annotations + import re import string From ffb91034e6f4a6a45343da0ac8308fffae25c4bd Mon Sep 17 00:00:00 2001 From: Matthias Mair Date: Sun, 24 Mar 2024 21:42:55 +0100 Subject: [PATCH 09/23] fix version --- .github/workflows/qc_checks.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/qc_checks.yaml b/.github/workflows/qc_checks.yaml index 99c6be09da0..2de968c910e 100644 --- a/.github/workflows/qc_checks.yaml +++ b/.github/workflows/qc_checks.yaml @@ -91,7 +91,8 @@ jobs: - uses: jakebailey/pyright-action@v1 name: Pyright with: - version: 1.1.xxx + version: 1.1.355 + continue-on-error: true - name: Check Version run: | pip install requests From a2f40416e39c836422a106a5425430703d237a08 Mon Sep 17 00:00:00 2001 From: Matthias Mair Date: Sun, 24 Mar 2024 22:05:32 +0100 Subject: [PATCH 10/23] Revert "alter type for Response" This reverts commit 3618d70e48e57cf111f64718f53a54cc54fcadc2. --- InvenTree/InvenTree/unit_test.py | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/InvenTree/InvenTree/unit_test.py b/InvenTree/InvenTree/unit_test.py index 45c8d40aa37..05e5bbe1d25 100644 --- a/InvenTree/InvenTree/unit_test.py +++ b/InvenTree/InvenTree/unit_test.py @@ -6,11 +6,9 @@ import re from contextlib import contextmanager from pathlib import Path -from typing import Any from django.contrib.auth import get_user_model from django.contrib.auth.models import Group, Permission -from django.core.handlers.wsgi import WSGIRequest from django.db import connections from django.http.response import StreamingHttpResponse from django.test import TestCase @@ -22,8 +20,6 @@ from plugin import registry from plugin.models import PluginConfig -MyResponse = Any | WSGIRequest - def addUserPermission(user, permission): """Shortcut function for adding a certain permission to a user.""" @@ -306,7 +302,7 @@ def get(self, url, data=None, expected_code=200, format='json', **kwargs): if data is None: data = {} - response: MyResponse = self.client.get(url, data, format=format, **kwargs) + response = self.client.get(url, data, format=format, **kwargs) self.checkResponse(url, 'GET', expected_code, response) @@ -318,7 +314,7 @@ def post(self, url, data=None, expected_code=None, format='json', **kwargs): if data is None: data = {} - response: MyResponse = self.client.post(url, data=data, format=format, **kwargs) + response = self.client.post(url, data=data, format=format, **kwargs) self.checkResponse(url, 'POST', expected_code, response) @@ -329,9 +325,7 @@ def delete(self, url, data=None, expected_code=None, format='json', **kwargs): if data is None: data = {} - response: MyResponse = self.client.delete( - url, data=data, format=format, **kwargs - ) + response = self.client.delete(url, data=data, format=format, **kwargs) self.checkResponse(url, 'DELETE', expected_code, response) @@ -339,9 +333,7 @@ def delete(self, url, data=None, expected_code=None, format='json', **kwargs): def patch(self, url, data, expected_code=None, format='json', **kwargs): """Issue a PATCH request.""" - response: MyResponse = self.client.patch( - url, data=data, format=format, **kwargs - ) + response = self.client.patch(url, data=data, format=format, **kwargs) self.checkResponse(url, 'PATCH', expected_code, response) @@ -349,7 +341,7 @@ def patch(self, url, data, expected_code=None, format='json', **kwargs): def put(self, url, data, expected_code=None, format='json', **kwargs): """Issue a PUT request.""" - response: MyResponse = self.client.put(url, data=data, format=format, **kwargs) + response = self.client.put(url, data=data, format=format, **kwargs) self.checkResponse(url, 'PUT', expected_code, response) @@ -367,7 +359,7 @@ def download_file( self, url, data, expected_code=None, expected_fn=None, decode=True ): """Download a file from the server, and return an in-memory file.""" - response: MyResponse = self.client.get(url, data=data, format='json') + response = self.client.get(url, data=data, format='json') self.checkResponse(url, 'DOWNLOAD_FILE', expected_code, response) From 66e475c9634f2f77ad81807c27e7aa8c9ad477e2 Mon Sep 17 00:00:00 2001 From: Matthias Mair Date: Sun, 24 Mar 2024 22:44:10 +0100 Subject: [PATCH 11/23] fix test --- InvenTree/label/tests.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/InvenTree/label/tests.py b/InvenTree/label/tests.py index 46f4d58c7a3..b394826a482 100644 --- a/InvenTree/label/tests.py +++ b/InvenTree/label/tests.py @@ -118,7 +118,8 @@ def test_print_part_label(self): InvenTreeSetting.set_setting('REPORT_ENABLE', True, None) # Set the 'debug' setting for the plugin - plugin = get_plugin_config('inventreelabel') + plugin = registry.get_plugin('inventreelabel') + assert plugin is not None plugin.set_setting('DEBUG', True) # Print via the API (Note: will default to the builtin plugin if no plugin supplied) From 312887820bb455a618b399d324c245d675c18ef3 Mon Sep 17 00:00:00 2001 From: Matthias Mair Date: Sun, 24 Mar 2024 22:46:04 +0100 Subject: [PATCH 12/23] fix fnc call --- InvenTree/plugin/base/integration/test_mixins.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InvenTree/plugin/base/integration/test_mixins.py b/InvenTree/plugin/base/integration/test_mixins.py index c1a5d2055cc..a0880ea27b2 100644 --- a/InvenTree/plugin/base/integration/test_mixins.py +++ b/InvenTree/plugin/base/integration/test_mixins.py @@ -124,7 +124,7 @@ def test_function(self): self.assertEqual(mx_patterns.reverse_dict, target_pattern.reverse_dict) # resolve the view - self.assertEqual(mx_patterns.resolve('/testpath').func(), 'ccc') + self.assertEqual(mx_patterns.resolve('/testpath').func(None), 'ccc') self.assertEqual(mx_patterns.reverse('test'), 'testpath') # no url From d5085ddaf9ff6d6e5c86edd8d181df6a7efdf800 Mon Sep 17 00:00:00 2001 From: Matthias Mair Date: Sun, 24 Mar 2024 22:54:19 +0100 Subject: [PATCH 13/23] add reqs install --- .github/workflows/qc_checks.yaml | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/.github/workflows/qc_checks.yaml b/.github/workflows/qc_checks.yaml index 2de968c910e..c307572efe8 100644 --- a/.github/workflows/qc_checks.yaml +++ b/.github/workflows/qc_checks.yaml @@ -88,15 +88,20 @@ jobs: cache: 'pip' - name: Run pre-commit Checks uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # pin@v3.0.1 + - name: Check Version + run: | + pip install requests + python3 ci/version_check.py + - name: Set up Environment + uses: ./.github/actions/setup + with: + dev-install: true + install: true - uses: jakebailey/pyright-action@v1 name: Pyright with: version: 1.1.355 continue-on-error: true - - name: Check Version - run: | - pip install requests - python3 ci/version_check.py mkdocs: name: Style [Documentation] From 6f748ade784783245d78b7e73193fb2266feff1d Mon Sep 17 00:00:00 2001 From: Matthias Mair Date: Sun, 24 Mar 2024 23:21:12 +0100 Subject: [PATCH 14/23] ignore migrations --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 6a8aa99fd15..a50d606d26d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -82,7 +82,7 @@ sections=["FUTURE","STDLIB","DJANGO","THIRDPARTY","FIRSTPARTY","LOCALFOLDER"] [tool.pyright] include = ["InvenTree"] -exclude = ["**/node_modules","**/__pycache__",] +exclude = ["**/node_modules","**/__pycache__","**/migrations/**"] defineConstant = { DEBUG = true } reportMissingImports = true From 1e0e14b2934914ede6b3a5522ea9c7c2b80f5825 Mon Sep 17 00:00:00 2001 From: Matthias Mair Date: Sun, 24 Mar 2024 23:21:20 +0100 Subject: [PATCH 15/23] more asserts --- InvenTree/common/tests.py | 7 +++++++ InvenTree/company/test_api.py | 9 +++++++++ InvenTree/company/tests.py | 1 + InvenTree/report/tests.py | 2 ++ InvenTree/users/test_api.py | 1 + InvenTree/users/tests.py | 4 ++++ 6 files changed, 24 insertions(+) diff --git a/InvenTree/common/tests.py b/InvenTree/common/tests.py index 744237ba5b1..98bcf5e04fe 100644 --- a/InvenTree/common/tests.py +++ b/InvenTree/common/tests.py @@ -284,6 +284,7 @@ def test_defaults(self): # Any fields marked as 'boolean' must have a default value specified setting = InvenTreeSetting.get_setting_object(key) + assert setting is not None if setting.is_bool(): if setting.default_value in ['', None]: @@ -374,6 +375,7 @@ def test_global_settings_api_list(self): def test_company_name(self): """Test a settings object lifecycle e2e.""" setting = InvenTreeSetting.get_setting_object('INVENTREE_COMPANY_NAME') + assert setting is not None # Check default value self.assertEqual(setting.value, 'My company name') @@ -474,6 +476,7 @@ def test_user_setting_boolean(self): setting = InvenTreeUserSetting.get_setting_object( 'SEARCH_PREVIEW_SHOW_PARTS', user=self.user ) + assert setting is not None # Check default values self.assertEqual(setting.to_native_value(), True) @@ -520,6 +523,7 @@ def test_user_setting_choice(self): setting = InvenTreeUserSetting.get_setting_object( 'DATE_DISPLAY_FORMAT', user=self.user ) + assert setting is not None url = reverse('api-user-setting-detail', kwargs={'key': setting.key}) @@ -544,6 +548,7 @@ def test_user_setting_integer(self): setting = InvenTreeUserSetting.get_setting_object( 'SEARCH_PREVIEW_RESULTS', user=self.user, cache=False ) + assert setting is not None url = reverse('api-user-setting-detail', kwargs={'key': setting.key}) @@ -1299,6 +1304,7 @@ def test_list(self): def test_edit(self): """Test edit permissions for CustomUnit model.""" unit = CustomUnit.objects.first() + assert unit is not None # Try to edit without permission self.user.is_staff = False @@ -1326,6 +1332,7 @@ def test_edit(self): def test_validation(self): """Test that validation works as expected.""" unit = CustomUnit.objects.first() + assert unit is not None self.user.is_staff = True self.user.save() diff --git a/InvenTree/company/test_api.py b/InvenTree/company/test_api.py index dcb8dc81dc7..d264c1c053f 100644 --- a/InvenTree/company/test_api.py +++ b/InvenTree/company/test_api.py @@ -184,6 +184,7 @@ def test_create(self): n = Contact.objects.count() company = Company.objects.first() + assert company is not None # Without required permissions, creation should fail self.post( @@ -202,6 +203,8 @@ def test_edit(self): """Test that we can edit a Contact via the API.""" # Get the first contact contact = Contact.objects.first() + assert contact is not None + # Use this contact in the tests url = reverse('api-contact-detail', kwargs={'pk': contact.pk}) @@ -219,12 +222,15 @@ def test_edit(self): # Get the contact again contact = Contact.objects.first() + assert contact is not None self.assertEqual(contact.role, 'x') def test_delete(self): """Tests that we can delete a Contact via the API.""" # Get the last contact contact = Contact.objects.first() + assert contact is not None + url = reverse('api-contact-detail', kwargs={'pk': contact.pk}) # Delete (without required permissions) @@ -279,6 +285,7 @@ def test_list(self): def test_filter_list(self): """Test listing addresses filtered on company.""" company = Company.objects.first() + assert company is not None response = self.get(self.url, {'company': company.pk}, expected_code=200) @@ -287,6 +294,7 @@ def test_filter_list(self): def test_create(self): """Test creating a new address.""" company = Company.objects.first() + assert company is not None self.post(self.url, {'company': company.pk, 'title': 'HQ'}, expected_code=403) @@ -297,6 +305,7 @@ def test_create(self): def test_get(self): """Test that objects are properly returned from a get.""" addr = Address.objects.first() + assert addr is not None url = reverse('api-address-detail', kwargs={'pk': addr.pk}) response = self.get(url, expected_code=200) diff --git a/InvenTree/company/tests.py b/InvenTree/company/tests.py index a789b951d43..1509b0a5ba4 100644 --- a/InvenTree/company/tests.py +++ b/InvenTree/company/tests.py @@ -139,6 +139,7 @@ def test_currency_validation(self): def test_metadata(self): """Unit tests for the metadata field.""" p = Company.objects.first() + assert p is not None self.assertIn(p.metadata, [None, {}]) self.assertIsNone(p.get_metadata('test')) diff --git a/InvenTree/report/tests.py b/InvenTree/report/tests.py index e44d19b4670..abf7cd70aa5 100644 --- a/InvenTree/report/tests.py +++ b/InvenTree/report/tests.py @@ -467,6 +467,7 @@ def test_print(self): # Now print with a valid StockItem item = StockItem.objects.first() + assert item is not None response = self.get(url, {'item': item.pk}, expected_code=200) @@ -538,6 +539,7 @@ def test_print(self): inline = InvenTreeUserSetting.get_setting_object( 'REPORT_INLINE', cache=False, user=self.user ) + assert inline is not None inline.value = True inline.save() diff --git a/InvenTree/users/test_api.py b/InvenTree/users/test_api.py index c25b9acbff7..c32b7c150e3 100644 --- a/InvenTree/users/test_api.py +++ b/InvenTree/users/test_api.py @@ -70,6 +70,7 @@ def test_token_generation(self): # If we re-generate a token, the value changes token = ApiToken.objects.filter(name='cat').first() + assert token is not None # Request the token with the same name data = self.get(url, data={'name': 'cat'}, expected_code=200).data diff --git a/InvenTree/users/tests.py b/InvenTree/users/tests.py index 84f0cd1668d..a69e1ba8460 100644 --- a/InvenTree/users/tests.py +++ b/InvenTree/users/tests.py @@ -171,10 +171,12 @@ def test_owner(self): """Tests for the 'owner' model.""" # Check that owner was created for user user_as_owner = Owner.get_owner(self.user) + assert user_as_owner is not None self.assertEqual(type(user_as_owner), Owner) # Check that owner was created for group group_as_owner = Owner.get_owner(self.group) + assert group_as_owner is not None self.assertEqual(type(group_as_owner), Owner) # Check name @@ -182,11 +184,13 @@ def test_owner(self): # Get related owners (user + group) related_owners = group_as_owner.get_related_owners(include_group=True) + assert related_owners is not None self.assertTrue(user_as_owner in related_owners) self.assertTrue(group_as_owner in related_owners) # Get related owners (only user) related_owners = group_as_owner.get_related_owners(include_group=False) + assert related_owners is not None self.assertTrue(user_as_owner in related_owners) self.assertFalse(group_as_owner in related_owners) From b35e2105c55d2ce58a74196ef593ed5172a75fdc Mon Sep 17 00:00:00 2001 From: Matthias Mair Date: Tue, 2 Apr 2024 22:40:09 +0200 Subject: [PATCH 16/23] more typing --- ci/version_check.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/ci/version_check.py b/ci/version_check.py index a46236508a2..b0addf7d0ce 100644 --- a/ci/version_check.py +++ b/ci/version_check.py @@ -46,6 +46,9 @@ def get_existing_release_tags(): tag = release['tag_name'].strip() match = re.match(r'^.*(\d+)\.(\d+)\.(\d+).*$', tag) + if not match: + continue + if len(match.groups()) != 3: print(f"Version '{tag}' did not match expected pattern") continue @@ -184,7 +187,12 @@ def check_version_number(version_string, allow_duplicate=False): print(f"Docker tags: '{docker_tags}'") # Ref: https://getridbug.com/python/how-to-set-environment-variables-in-github-actions-using-python/ - with open(os.getenv('GITHUB_ENV'), 'a') as env_file: + env_file = os.getenv('GITHUB_ENV') + if env_file is None: # pragma: no cover + print('Could not find GITHUB_ENV') + sys.exit(1) + + with open(env_file, 'a') as env_file: # Construct tag string tags = ','.join([f'inventree/inventree:{tag}' for tag in docker_tags]) From 36cea35ac4f7e8e0756f421d4d4ae9e42999d705 Mon Sep 17 00:00:00 2001 From: Matthias Mair Date: Tue, 2 Apr 2024 22:41:03 +0200 Subject: [PATCH 17/23] cover empty states --- InvenTree/generic/states/states.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/InvenTree/generic/states/states.py b/InvenTree/generic/states/states.py index 372a5bec45e..b83d2865290 100644 --- a/InvenTree/generic/states/states.py +++ b/InvenTree/generic/states/states.py @@ -42,6 +42,9 @@ class StatusCode(BaseEnum): Additionally there are helpers to access all additional attributes `text`, `label`, `color`. """ + color: str + _TAG = None + def __new__(cls, *args): """Define object out of args.""" obj = int.__new__(cls) @@ -113,7 +116,7 @@ def tag(cls): @classmethod def items(cls): """All status code items.""" - return [(x.value, x.label) for x in cls.values()] + return [(x.value, x.label) for x in cls.values()] if cls else [] @classmethod def keys(cls): From 78333c502044c7f546e7d325f736712a65d902a6 Mon Sep 17 00:00:00 2001 From: Matthias Mair Date: Tue, 2 Apr 2024 22:41:14 +0200 Subject: [PATCH 18/23] cover none case --- InvenTree/generic/states/transition.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/InvenTree/generic/states/transition.py b/InvenTree/generic/states/transition.py index 6abc7f10102..9441761f118 100644 --- a/InvenTree/generic/states/transition.py +++ b/InvenTree/generic/states/transition.py @@ -77,6 +77,9 @@ def handle_transition( default_action: Default action to be taken if none of the transitions returns a boolean true value """ # Check if there is a custom override function for this transition + if storage.list is None: + return default_action(current_state, target_state, instance, **kwargs) + for override in storage.list: rslt = override.transition( current_state, target_state, instance, default_action, **kwargs From d79eededc1efe16fe6290d0dba9da73fe1b330fa Mon Sep 17 00:00:00 2001 From: Matthias Mair Date: Tue, 2 Apr 2024 22:45:24 +0200 Subject: [PATCH 19/23] sprikle in a few asserts --- InvenTree/build/test_api.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/InvenTree/build/test_api.py b/InvenTree/build/test_api.py index 6f7ad83e149..def3ae38bf6 100644 --- a/InvenTree/build/test_api.py +++ b/InvenTree/build/test_api.py @@ -694,6 +694,8 @@ def test_invalid_bom_item(self): wrong_line = line break + assert wrong_line is not None + data = self.post( self.url, { @@ -725,6 +727,7 @@ def test_valid_data(self): if line.bom_item.sub_part.pk == si.part.pk: right_line = line break + assert right_line is not None self.post( self.url, @@ -744,6 +747,8 @@ def test_valid_data(self): self.assertEqual(self.n + 1, BuildItem.objects.count()) allocation = BuildItem.objects.last() + assert allocation is not None + assert allocation.bom_item is not None self.assertEqual(allocation.quantity, 5000) self.assertEqual(allocation.bom_item.pk, 1) @@ -762,6 +767,7 @@ def test_reallocate(self): if line.bom_item.sub_part.pk == si.part.pk: right_line = line break + assert right_line is not None self.post( self.url, @@ -781,6 +787,8 @@ def test_reallocate(self): self.assertEqual(self.n + 1, BuildItem.objects.count()) allocation = BuildItem.objects.last() + assert allocation is not None + assert allocation.bom_item is not None self.assertEqual(allocation.quantity, 3000) self.assertEqual(allocation.bom_item.pk, 1) @@ -904,6 +912,7 @@ def setUpTestData(cls): required = build_line.quantity + idx + 1 sub_part = build_line.bom_item.sub_part si = StockItem.objects.filter(part=sub_part, quantity__gte=required).first() + assert si is not None cls.state[sub_part] = (si, si.quantity, required) From eedb9ac6690980213075361954c5a53079fa8461 Mon Sep 17 00:00:00 2001 From: Matthias Mair Date: Tue, 2 Apr 2024 23:12:10 +0200 Subject: [PATCH 20/23] more asserts --- InvenTree/InvenTree/tests.py | 2 ++ InvenTree/InvenTree/unit_test.py | 4 ++-- InvenTree/build/test_api.py | 16 ++++++++-------- InvenTree/build/test_migrations.py | 2 ++ InvenTree/common/test_notifications.py | 1 + InvenTree/common/tests.py | 16 +++++++++------- InvenTree/company/test_api.py | 16 +++++++++------- InvenTree/company/test_migrations.py | 4 ++++ InvenTree/company/tests.py | 2 +- InvenTree/generic/states/test_transition.py | 2 ++ InvenTree/label/tests.py | 5 +++-- InvenTree/order/test_api.py | 3 +++ InvenTree/order/tests.py | 5 +++++ InvenTree/part/test_api.py | 8 +++++++- InvenTree/part/test_bom_item.py | 1 + InvenTree/part/test_migrations.py | 1 + InvenTree/part/test_param.py | 2 ++ InvenTree/part/test_part.py | 5 +++++ InvenTree/part/test_pricing.py | 9 +++++++++ InvenTree/plugin/base/barcodes/test_barcode.py | 6 +++--- InvenTree/plugin/base/integration/test_mixins.py | 8 ++++---- InvenTree/plugin/base/locate/test_locate.py | 4 +++- .../builtin/barcodes/test_inventree_barcode.py | 2 +- .../integration/test_core_notifications.py | 2 +- .../builtin/suppliers/test_supplier_barcodes.py | 14 +++++++------- .../plugin/samples/integration/test_sample.py | 4 ++-- .../integration/test_validation_sample.py | 6 +++--- .../plugin/samples/locate/test_locate_sample.py | 2 +- InvenTree/plugin/test_api.py | 12 ++++++------ InvenTree/plugin/test_plugin.py | 10 +++++----- InvenTree/report/tests.py | 7 +++++-- InvenTree/stock/tests.py | 7 +++++++ InvenTree/users/test_api.py | 4 +++- InvenTree/users/tests.py | 8 ++++---- InvenTree/web/tests.py | 2 ++ 35 files changed, 133 insertions(+), 69 deletions(-) diff --git a/InvenTree/InvenTree/tests.py b/InvenTree/InvenTree/tests.py index ff60d838818..2ef0e00220a 100644 --- a/InvenTree/InvenTree/tests.py +++ b/InvenTree/InvenTree/tests.py @@ -1346,6 +1346,7 @@ def test_instance_name(self): # The site should also be changed site_obj = Site.objects.all().order_by('id').first() + assert site_obj self.assertEqual(site_obj.name, 'Testing title') @override_settings(SITE_URL=None) @@ -1365,6 +1366,7 @@ def test_instance_url(self): from django.contrib.sites.models import Site site_obj = Site.objects.all().order_by('id').first() + assert site_obj self.assertEqual(site_obj.domain, 'http://127.1.2.3') except Exception: pass diff --git a/InvenTree/InvenTree/unit_test.py b/InvenTree/InvenTree/unit_test.py index 05e5bbe1d25..48415a32392 100644 --- a/InvenTree/InvenTree/unit_test.py +++ b/InvenTree/InvenTree/unit_test.py @@ -92,9 +92,9 @@ def getNewestMigrationFile(app, exclude_extension=True): def get_plugin_config(plugin_slug): """Return the plugin config for the specified plugin.""" plg = registry.get_plugin(plugin_slug) - assert plg is not None + assert plg cfg = plg.plugin_config() - assert cfg is not None + assert cfg return cfg diff --git a/InvenTree/build/test_api.py b/InvenTree/build/test_api.py index def3ae38bf6..8baf4671114 100644 --- a/InvenTree/build/test_api.py +++ b/InvenTree/build/test_api.py @@ -694,7 +694,7 @@ def test_invalid_bom_item(self): wrong_line = line break - assert wrong_line is not None + assert wrong_line data = self.post( self.url, @@ -727,7 +727,7 @@ def test_valid_data(self): if line.bom_item.sub_part.pk == si.part.pk: right_line = line break - assert right_line is not None + assert right_line self.post( self.url, @@ -747,8 +747,8 @@ def test_valid_data(self): self.assertEqual(self.n + 1, BuildItem.objects.count()) allocation = BuildItem.objects.last() - assert allocation is not None - assert allocation.bom_item is not None + assert allocation + assert allocation.bom_item self.assertEqual(allocation.quantity, 5000) self.assertEqual(allocation.bom_item.pk, 1) @@ -767,7 +767,7 @@ def test_reallocate(self): if line.bom_item.sub_part.pk == si.part.pk: right_line = line break - assert right_line is not None + assert right_line self.post( self.url, @@ -787,8 +787,8 @@ def test_reallocate(self): self.assertEqual(self.n + 1, BuildItem.objects.count()) allocation = BuildItem.objects.last() - assert allocation is not None - assert allocation.bom_item is not None + assert allocation + assert allocation.bom_item self.assertEqual(allocation.quantity, 3000) self.assertEqual(allocation.bom_item.pk, 1) @@ -912,7 +912,7 @@ def setUpTestData(cls): required = build_line.quantity + idx + 1 sub_part = build_line.bom_item.sub_part si = StockItem.objects.filter(part=sub_part, quantity__gte=required).first() - assert si is not None + assert si cls.state[sub_part] = (si, si.quantity, required) diff --git a/InvenTree/build/test_migrations.py b/InvenTree/build/test_migrations.py index dba739764a1..7b3921b121f 100644 --- a/InvenTree/build/test_migrations.py +++ b/InvenTree/build/test_migrations.py @@ -42,6 +42,7 @@ def test_items_exist(self): # Check that the part object now has an assembly field part = Part.objects.all().first() + assert part part.assembly = True part.save() part.assembly = False @@ -262,6 +263,7 @@ def test_build_line_creation(self): ) item = BuildItem.objects.first() + assert item # Check that the "build" field has been removed with self.assertRaises(AttributeError): diff --git a/InvenTree/common/test_notifications.py b/InvenTree/common/test_notifications.py index a517d51e338..8bd6c0797dd 100644 --- a/InvenTree/common/test_notifications.py +++ b/InvenTree/common/test_notifications.py @@ -153,6 +153,7 @@ def send_bulk(self): # make sure the array fits array = storage.get_usersettings(self.user) setting = NotificationUserSetting.objects.all().first() + assert setting # assertions for settings self.assertEqual(setting.name, 'Enable test notifications') diff --git a/InvenTree/common/tests.py b/InvenTree/common/tests.py index 98bcf5e04fe..3050e92dc3e 100644 --- a/InvenTree/common/tests.py +++ b/InvenTree/common/tests.py @@ -75,6 +75,7 @@ def test_settings_functions(self): report_test_obj = InvenTreeSetting.get_setting_object( 'REPORT_ENABLE_TEST_REPORT' ) + assert stale_days and instance_obj and report_size_obj and report_test_obj # check settings base fields self.assertEqual(instance_obj.name, 'Server Instance Name') @@ -284,7 +285,7 @@ def test_defaults(self): # Any fields marked as 'boolean' must have a default value specified setting = InvenTreeSetting.get_setting_object(key) - assert setting is not None + assert setting if setting.is_bool(): if setting.default_value in ['', None]: @@ -375,7 +376,7 @@ def test_global_settings_api_list(self): def test_company_name(self): """Test a settings object lifecycle e2e.""" setting = InvenTreeSetting.get_setting_object('INVENTREE_COMPANY_NAME') - assert setting is not None + assert setting # Check default value self.assertEqual(setting.value, 'My company name') @@ -476,7 +477,7 @@ def test_user_setting_boolean(self): setting = InvenTreeUserSetting.get_setting_object( 'SEARCH_PREVIEW_SHOW_PARTS', user=self.user ) - assert setting is not None + assert setting # Check default values self.assertEqual(setting.to_native_value(), True) @@ -523,7 +524,7 @@ def test_user_setting_choice(self): setting = InvenTreeUserSetting.get_setting_object( 'DATE_DISPLAY_FORMAT', user=self.user ) - assert setting is not None + assert setting url = reverse('api-user-setting-detail', kwargs={'key': setting.key}) @@ -548,7 +549,7 @@ def test_user_setting_integer(self): setting = InvenTreeUserSetting.get_setting_object( 'SEARCH_PREVIEW_RESULTS', user=self.user, cache=False ) - assert setting is not None + assert setting url = reverse('api-user-setting-detail', kwargs={'key': setting.key}) @@ -1207,6 +1208,7 @@ def test_delete(self): # Get the first project code code = ProjectCode.objects.first() + assert code # Delete it self.delete( @@ -1304,7 +1306,7 @@ def test_list(self): def test_edit(self): """Test edit permissions for CustomUnit model.""" unit = CustomUnit.objects.first() - assert unit is not None + assert unit # Try to edit without permission self.user.is_staff = False @@ -1332,7 +1334,7 @@ def test_edit(self): def test_validation(self): """Test that validation works as expected.""" unit = CustomUnit.objects.first() - assert unit is not None + assert unit self.user.is_staff = True self.user.save() diff --git a/InvenTree/company/test_api.py b/InvenTree/company/test_api.py index d264c1c053f..b9409cd967f 100644 --- a/InvenTree/company/test_api.py +++ b/InvenTree/company/test_api.py @@ -184,7 +184,7 @@ def test_create(self): n = Contact.objects.count() company = Company.objects.first() - assert company is not None + assert company # Without required permissions, creation should fail self.post( @@ -203,7 +203,7 @@ def test_edit(self): """Test that we can edit a Contact via the API.""" # Get the first contact contact = Contact.objects.first() - assert contact is not None + assert contact # Use this contact in the tests url = reverse('api-contact-detail', kwargs={'pk': contact.pk}) @@ -222,14 +222,14 @@ def test_edit(self): # Get the contact again contact = Contact.objects.first() - assert contact is not None + assert contact self.assertEqual(contact.role, 'x') def test_delete(self): """Tests that we can delete a Contact via the API.""" # Get the last contact contact = Contact.objects.first() - assert contact is not None + assert contact url = reverse('api-contact-detail', kwargs={'pk': contact.pk}) @@ -285,7 +285,7 @@ def test_list(self): def test_filter_list(self): """Test listing addresses filtered on company.""" company = Company.objects.first() - assert company is not None + assert company response = self.get(self.url, {'company': company.pk}, expected_code=200) @@ -294,7 +294,7 @@ def test_filter_list(self): def test_create(self): """Test creating a new address.""" company = Company.objects.first() - assert company is not None + assert company self.post(self.url, {'company': company.pk, 'title': 'HQ'}, expected_code=403) @@ -305,7 +305,7 @@ def test_create(self): def test_get(self): """Test that objects are properly returned from a get.""" addr = Address.objects.first() - assert addr is not None + assert addr url = reverse('api-address-detail', kwargs={'pk': addr.pk}) response = self.get(url, expected_code=200) @@ -326,6 +326,7 @@ def test_get(self): def test_edit(self): """Test editing an object.""" addr = Address.objects.first() + assert addr url = reverse('api-address-detail', kwargs={'pk': addr.pk}) @@ -342,6 +343,7 @@ def test_edit(self): def test_delete(self): """Test deleting an object.""" addr = Address.objects.first() + assert addr url = reverse('api-address-detail', kwargs={'pk': addr.pk}) diff --git a/InvenTree/company/test_migrations.py b/InvenTree/company/test_migrations.py index bb5b6f27f92..f5932688eaf 100644 --- a/InvenTree/company/test_migrations.py +++ b/InvenTree/company/test_migrations.py @@ -87,6 +87,7 @@ def test_company_objects(self): parts = SupplierPart.objects.filter(manufacturer=acme) self.assertEqual(parts.count(), 1) part = parts.first() + assert part # Checks on the SupplierPart object self.assertEqual(part.manufacturer_name, 'ACME') @@ -209,6 +210,7 @@ def test_manufacturer_part_objects(self): self.assertEqual(manufacturer_parts.count(), 4) manufacturer_part = manufacturer_parts.first() + assert manufacturer_part self.assertEqual(manufacturer_part.MPN, 'MUR-CAP-123456') @@ -305,11 +307,13 @@ def test_address_migration(self): c1 = Company.objects.filter(name='Company 1').first() c2 = Company.objects.filter(name='Company 2').first() + assert c1 and c2 self.assertEqual(len(Address.objects.all()), 2) a1 = Address.objects.filter(company=c1.pk).first() a2 = Address.objects.filter(company=c2.pk).first() + assert a1 and a2 self.assertEqual(a1.line1, self.short_l1) self.assertEqual(a1.line2, '') diff --git a/InvenTree/company/tests.py b/InvenTree/company/tests.py index 1509b0a5ba4..7ece0a90e95 100644 --- a/InvenTree/company/tests.py +++ b/InvenTree/company/tests.py @@ -139,7 +139,7 @@ def test_currency_validation(self): def test_metadata(self): """Unit tests for the metadata field.""" p = Company.objects.first() - assert p is not None + assert p self.assertIn(p.metadata, [None, {}]) self.assertIsNone(p.get_metadata('test')) diff --git a/InvenTree/generic/states/test_transition.py b/InvenTree/generic/states/test_transition.py index 39bde4e1d14..8f0bad72beb 100644 --- a/InvenTree/generic/states/test_transition.py +++ b/InvenTree/generic/states/test_transition.py @@ -59,6 +59,7 @@ def transition(self, *args, **kwargs): # Ensure registering works storage.collect() + assert storage.list # Ensure the class is registered self.assertIn(RaisingImplementation, storage.list) @@ -93,6 +94,7 @@ def transition(self, *args, **kwargs): return False storage.collect() + assert storage.list self.assertIn(ValidImplementationNoEffect, storage.list) self.assertIn(ValidImplementation, storage.list) diff --git a/InvenTree/label/tests.py b/InvenTree/label/tests.py index b394826a482..e5ddbdfbc8b 100644 --- a/InvenTree/label/tests.py +++ b/InvenTree/label/tests.py @@ -70,6 +70,7 @@ def test_label_rendering(self): """Test label rendering.""" labels = PartLabel.objects.all() part = Part.objects.first() + assert part for label in labels: url = reverse('api-part-label-print', kwargs={'pk': label.pk}) @@ -119,14 +120,14 @@ def test_print_part_label(self): # Set the 'debug' setting for the plugin plugin = registry.get_plugin('inventreelabel') - assert plugin is not None + assert plugin plugin.set_setting('DEBUG', True) # Print via the API (Note: will default to the builtin plugin if no plugin supplied) url = reverse('api-part-label-print', kwargs={'pk': label.pk}) prt = Part.objects.first() - assert prt is not None + assert prt part_pk = prt.pk part_name = prt.name diff --git a/InvenTree/order/test_api.py b/InvenTree/order/test_api.py index c00f577b07c..77a9d514046 100644 --- a/InvenTree/order/test_api.py +++ b/InvenTree/order/test_api.py @@ -1059,6 +1059,7 @@ def test_batch_code(self): item_1 = StockItem.objects.filter(supplier_part=line_1.part).first() item_2 = StockItem.objects.filter(supplier_part=line_2.part).first() + assert item_1 is not None and item_2 self.assertEqual(item_1.batch, 'B-abc-123') self.assertEqual(item_2.batch, 'B-xyz-789') @@ -1108,6 +1109,7 @@ def test_serial_numbers(self): self.assertEqual(items.count(), 1) item = items.first() + assert item self.assertEqual(item.quantity, 10) self.assertEqual(item.batch, 'B-xyz-789') @@ -1737,6 +1739,7 @@ def check_template(line_item): for part in parts: stock_item = part.stock_items.last() break + assert stock_item # Fully-allocate each line data['items'].append({ diff --git a/InvenTree/order/tests.py b/InvenTree/order/tests.py index 1b6cdb90810..020476d69a1 100644 --- a/InvenTree/order/tests.py +++ b/InvenTree/order/tests.py @@ -297,6 +297,8 @@ def test_receive_pack_size(self): # Ensure that received quantity and unit purchase price data are correct si = si.first() + assert si + self.assertEqual(si.quantity, 10) self.assertEqual(si.purchase_price, Money(100, 'USD')) @@ -305,6 +307,8 @@ def test_receive_pack_size(self): # Ensure that received quantity and unit purchase price data are correct si = si.first() + assert si + self.assertEqual(si.quantity, 0.5) self.assertEqual(si.purchase_price, Money(100, 'USD')) @@ -342,6 +346,7 @@ def test_overdue_notification(self): self.assertTrue(messages.exists()) msg = messages.first() + assert msg self.assertEqual(msg.target_object_id, 1) self.assertEqual(msg.name, 'Overdue Purchase Order') diff --git a/InvenTree/part/test_api.py b/InvenTree/part/test_api.py index 216d4240663..9f7364d729e 100644 --- a/InvenTree/part/test_api.py +++ b/InvenTree/part/test_api.py @@ -1547,6 +1547,7 @@ def test_existing_image(self): """Test that we can allocate an existing uploaded image to a new Part.""" # First, upload an image for an existing part p = Part.objects.first() + assert p fn = BASE_DIR / '_testfolder' / 'part_image_123abc.png' @@ -1592,6 +1593,7 @@ def test_update_existing_image(self): """Test that we can update the image of an existing part with an already existing image.""" # First, upload an image for an existing part p = Part.objects.first() + assert p fn = BASE_DIR / '_testfolder' / 'part_image_123abc.png' @@ -1633,6 +1635,8 @@ def test_update_existing_image(self): # Attempt to add a non-existent image to an existing part last_p = Part.objects.last() + assert last_p + response = self.patch( reverse('api-part-detail', kwargs={'pk': last_p.pk}), {'existing_image': 'bogus_image.jpg'}, @@ -1872,6 +1876,7 @@ def get_part_data(self): def test_stock_quantity(self): """Simple test for the stock quantity.""" data = self.get_part_data() + assert data self.assertEqual(data['in_stock'], 600) self.assertEqual(data['stock_item_count'], 4) @@ -1885,6 +1890,7 @@ def test_stock_quantity(self): StockItem.objects.create(part=self.part, quantity=9999, customer=customer) data = self.get_part_data() + assert data self.assertEqual(data['in_stock'], 1100) self.assertEqual(data['stock_item_count'], 105) @@ -2157,7 +2163,7 @@ def test_bom_list(self): # Now, let's validate an item bom_item = BomItem.objects.first() - + assert bom_item bom_item.validate_hash() response = self.get(url, data={'validated': True}, expected_code=200) diff --git a/InvenTree/part/test_bom_item.py b/InvenTree/part/test_bom_item.py index 7d5a8293ffe..7af40f4bd6d 100644 --- a/InvenTree/part/test_bom_item.py +++ b/InvenTree/part/test_bom_item.py @@ -238,6 +238,7 @@ def test_metadata(self): """Unit tests for the metadata field.""" for model in [BomItem]: p = model.objects.first() + assert p self.assertIsNone(p.get_metadata('test')) self.assertEqual(p.get_metadata('test', backup_value=123), 123) diff --git a/InvenTree/part/test_migrations.py b/InvenTree/part/test_migrations.py index 1a15e57ebfc..e350794f736 100644 --- a/InvenTree/part/test_migrations.py +++ b/InvenTree/part/test_migrations.py @@ -23,6 +23,7 @@ def prepare(self): # Extract one part object to investigate p = Part.objects.all().last() + assert p # Initially some fields are not present with self.assertRaises(AttributeError): diff --git a/InvenTree/part/test_param.py b/InvenTree/part/test_param.py index 314fe11eb51..a43e3a87f19 100644 --- a/InvenTree/part/test_param.py +++ b/InvenTree/part/test_param.py @@ -51,6 +51,7 @@ def test_metadata(self): """Unit tests for the metadata field.""" for model in [PartParameterTemplate]: p = model.objects.first() + assert p self.assertIsNone(p.get_metadata('test')) self.assertEqual(p.get_metadata('test', backup_value=123), 123) @@ -71,6 +72,7 @@ def test_get_parameter(self): # Check that we can get a parameter by name for name in ['Length', 'Width', 'Thickness']: param = prt.get_parameter(name) + assert param self.assertEqual(param.template.name, name) # Check that an incorrect name returns None diff --git a/InvenTree/part/test_part.py b/InvenTree/part/test_part.py index 57f91af817e..5714e192238 100644 --- a/InvenTree/part/test_part.py +++ b/InvenTree/part/test_part.py @@ -100,6 +100,7 @@ def test_date(self): # In such a case, skip this check pass else: + assert d self.assertEqual(len(d.split('-')), 3) def test_github(self): @@ -293,6 +294,7 @@ def test_metadata(self): """Unit tests for the metadata field.""" for model in [Part]: p = model.objects.first() + assert p self.assertIsNone(p.get_metadata('test')) self.assertEqual(p.get_metadata('test', backup_value=123), 123) @@ -358,6 +360,7 @@ def test_stocktake(self): """Test for adding stocktake data.""" # Grab a part p = Part.objects.all().first() + assert p self.assertIsNone(p.last_stocktake) @@ -394,6 +397,8 @@ def test_template_count(self): self.assertEqual(variant.getTestTemplates(enabled=False).count(), 0) template = variant.getTestTemplates().first() + assert template + template.enabled = False template.save() diff --git a/InvenTree/part/test_pricing.py b/InvenTree/part/test_pricing.py index ba4e7d54efc..1c4b8e1be86 100644 --- a/InvenTree/part/test_pricing.py +++ b/InvenTree/part/test_pricing.py @@ -157,6 +157,8 @@ def test_supplier_part_pricing(self): pricing.update_pricing() + assert pricing.overall_min and pricing.overall_max + self.assertAlmostEqual(float(pricing.overall_min.amount), 2.015, places=2) self.assertAlmostEqual(float(pricing.overall_max.amount), 3.06, places=2) @@ -338,6 +340,13 @@ def test_purchase_pricing(self): min_cost_aud = convert_money(pricing.purchase_cost_min, 'AUD') max_cost_cad = convert_money(pricing.purchase_cost_max, 'CAD') + assert ( + min_cost_aud + and max_cost_cad + and pricing.purchase_cost_min + and pricing.purchase_cost_max + ) + # Min cost in AUD = $2 AUD per metre self.assertAlmostEqual(float(min_cost_aud.amount), 2, places=2) diff --git a/InvenTree/plugin/base/barcodes/test_barcode.py b/InvenTree/plugin/base/barcodes/test_barcode.py index e6e021ef1de..2136eb27084 100644 --- a/InvenTree/plugin/base/barcodes/test_barcode.py +++ b/InvenTree/plugin/base/barcodes/test_barcode.py @@ -64,7 +64,7 @@ def test_empty(self): def test_find_part(self): """Test that we can lookup a part based on ID.""" part = Part.objects.first() - assert part is not None + assert part response = self.post( self.scan_url, {'barcode': f'{{"part": {part.pk}}}'}, expected_code=200 @@ -85,7 +85,7 @@ def test_invalid_part(self): def test_find_stock_item(self): """Test that we can lookup a stock item based on ID.""" item = StockItem.objects.first() - assert item is not None + assert item response = self.post( self.scan_url, {'barcode': item.format_barcode()}, expected_code=200 @@ -299,7 +299,7 @@ def test_invalid_barcode(self): # Test with a barcode that matches a *different* stock item item = StockItem.objects.exclude(pk=self.stock_item.pk).first() - assert item is not None + assert item item.assign_barcode(barcode_data='123456789') result = self.postBarcode( diff --git a/InvenTree/plugin/base/integration/test_mixins.py b/InvenTree/plugin/base/integration/test_mixins.py index a0880ea27b2..d5fb4fc844c 100644 --- a/InvenTree/plugin/base/integration/test_mixins.py +++ b/InvenTree/plugin/base/integration/test_mixins.py @@ -108,7 +108,7 @@ class NoUrlsCls(UrlsMixin, InvenTreePlugin): def test_function(self): """Test that the mixin functions.""" plg_name = self.mixin.plugin_name() - assert plg_name is not None + assert plg_name # base_url target_url = f'{PLUGIN_BASE}/{plg_name}/' @@ -120,7 +120,7 @@ def test_function(self): ) mx_patterns = self.mixin.urlpatterns - assert mx_patterns is not None + assert mx_patterns self.assertEqual(mx_patterns.reverse_dict, target_pattern.reverse_dict) # resolve the view @@ -369,7 +369,7 @@ def test_installed(self): def test_disabled(self): """Test that the panels *do not load* if the plugin is not enabled.""" plugin = registry.get_plugin('samplepanel') - assert plugin is not None + assert plugin plugin.set_setting('ENABLE_HELLO_WORLD', True) plugin.set_setting('ENABLE_BROKEN_PANEL', True) @@ -415,7 +415,7 @@ def test_enabled(self): ] plugin = registry.get_plugin('samplepanel') - assert plugin is not None + assert plugin plugin.set_setting('ENABLE_HELLO_WORLD', False) plugin.set_setting('ENABLE_BROKEN_PANEL', False) diff --git a/InvenTree/plugin/base/locate/test_locate.py b/InvenTree/plugin/base/locate/test_locate.py index 621d8b6cfed..46ceff82d3a 100644 --- a/InvenTree/plugin/base/locate/test_locate.py +++ b/InvenTree/plugin/base/locate/test_locate.py @@ -71,7 +71,7 @@ def test_locate_item(self): url = reverse('api-locate-plugin') item = StockItem.objects.get(pk=1) - assert item is not None + assert item # The sample plugin will set the 'located' metadata tag item.set_metadata('located', False) @@ -83,6 +83,7 @@ def test_locate_item(self): self.assertEqual(response.data['item'], 1) item.refresh_from_db() + assert item.metadata # Item metadata should have been altered! self.assertTrue(item.metadata['located']) @@ -103,6 +104,7 @@ def test_locate_location(self): self.assertEqual(response.data['location'], location.pk) location.refresh_from_db() + assert location.metadata # Item metadata should have been altered! self.assertTrue(location.metadata['located']) diff --git a/InvenTree/plugin/builtin/barcodes/test_inventree_barcode.py b/InvenTree/plugin/builtin/barcodes/test_inventree_barcode.py index 5e4089f0217..90bca90e9fb 100644 --- a/InvenTree/plugin/builtin/barcodes/test_inventree_barcode.py +++ b/InvenTree/plugin/builtin/barcodes/test_inventree_barcode.py @@ -63,7 +63,7 @@ def test_unassign_errors(self): # Fail with too many fields provided stock_obj = stock.models.StockItem.objects.first() part_obj = part.models.Part.objects.first() - assert stock_obj is not None and part_obj is not None + assert stock_obj is not None and part_obj response = self.unassign( {'stockitem': stock_obj.pk, 'part': part_obj.pk}, expected_code=400 ) diff --git a/InvenTree/plugin/builtin/integration/test_core_notifications.py b/InvenTree/plugin/builtin/integration/test_core_notifications.py index 6c07c2ecf87..2fb4bd23004 100644 --- a/InvenTree/plugin/builtin/integration/test_core_notifications.py +++ b/InvenTree/plugin/builtin/integration/test_core_notifications.py @@ -20,7 +20,7 @@ def test_email(self): # enable plugin and set mail setting to true plugin = registry.get_plugin('inventreecorenotificationsplugin') - assert plugin is not None + assert plugin plugin.set_setting('ENABLE_NOTIFICATION_EMAILS', True) NotificationUserSetting.set_setting( key='NOTIFICATION_METHOD_MAIL', diff --git a/InvenTree/plugin/builtin/suppliers/test_supplier_barcodes.py b/InvenTree/plugin/builtin/suppliers/test_supplier_barcodes.py index 36457680d62..dfa0d9aae9b 100644 --- a/InvenTree/plugin/builtin/suppliers/test_supplier_barcodes.py +++ b/InvenTree/plugin/builtin/suppliers/test_supplier_barcodes.py @@ -53,7 +53,7 @@ def test_digikey_barcode(self): self.assertEqual(result.data['plugin'], 'DigiKeyPlugin') supplier_part_data = result.data.get('supplierpart') - assert supplier_part_data is not None + assert supplier_part_data self.assertIn('pk', supplier_part_data) supplier_part = SupplierPart.objects.get(pk=supplier_part_data['pk']) @@ -67,7 +67,7 @@ def test_digikey_2_barcode(self): self.assertEqual(result.data['plugin'], 'DigiKeyPlugin') supplier_part_data = result.data.get('supplierpart') - assert supplier_part_data is not None + assert supplier_part_data self.assertIn('pk', supplier_part_data) supplier_part = SupplierPart.objects.get(pk=supplier_part_data['pk']) @@ -84,7 +84,7 @@ def test_mouser_barcode(self): ) supplier_part_data = result.data.get('supplierpart') - assert supplier_part_data is not None + assert supplier_part_data self.assertIn('pk', supplier_part_data) supplier_part = SupplierPart.objects.get(pk=supplier_part_data['pk']) @@ -97,7 +97,7 @@ def test_old_mouser_barcode(self): ) supplier_part_data = result.data.get('supplierpart') - assert supplier_part_data is not None + assert supplier_part_data self.assertIn('pk', supplier_part_data) supplier_part = SupplierPart.objects.get(pk=supplier_part_data['pk']) self.assertEqual(supplier_part.SKU, '2') @@ -111,7 +111,7 @@ def test_lcsc_barcode(self): self.assertEqual(result.data['plugin'], 'LCSCPlugin') supplier_part_data = result.data.get('supplierpart') - assert supplier_part_data is not None + assert supplier_part_data self.assertIn('pk', supplier_part_data) supplier_part = SupplierPart.objects.get(pk=supplier_part_data['pk']) @@ -126,7 +126,7 @@ def test_tme_qrcode(self): self.assertEqual(result.data['plugin'], 'TMEPlugin') supplier_part_data = result.data.get('supplierpart') - assert supplier_part_data is not None + assert supplier_part_data self.assertIn('pk', supplier_part_data) supplier_part = SupplierPart.objects.get(pk=supplier_part_data['pk']) self.assertEqual(supplier_part.SKU, 'WBP-302') @@ -140,7 +140,7 @@ def test_tme_barcode2d(self): self.assertEqual(result.data['plugin'], 'TMEPlugin') supplier_part_data = result.data.get('supplierpart') - assert supplier_part_data is not None + assert supplier_part_data self.assertIn('pk', supplier_part_data) supplier_part = SupplierPart.objects.get(pk=supplier_part_data['pk']) diff --git a/InvenTree/plugin/samples/integration/test_sample.py b/InvenTree/plugin/samples/integration/test_sample.py index 2d3b855ae46..94840d5391c 100644 --- a/InvenTree/plugin/samples/integration/test_sample.py +++ b/InvenTree/plugin/samples/integration/test_sample.py @@ -42,7 +42,7 @@ def test_view(self): def test_settings(self): """Check the SettingsMixin.check_settings function.""" plugin = registry.get_plugin('sample') - assert plugin is not None + assert plugin self.assertIsNotNone(plugin) # check settings @@ -55,7 +55,7 @@ def test_settings(self): def test_settings_validator(self): """Test settings validator for plugins.""" plugin = registry.get_plugin('sample') - assert plugin is not None + assert plugin valid_json = '{"ts": 13}' not_valid_json = '{"ts""13"}' diff --git a/InvenTree/plugin/samples/integration/test_validation_sample.py b/InvenTree/plugin/samples/integration/test_validation_sample.py index 03da1d94acf..89da6a2c358 100644 --- a/InvenTree/plugin/samples/integration/test_validation_sample.py +++ b/InvenTree/plugin/samples/integration/test_validation_sample.py @@ -52,7 +52,7 @@ def test_validate_model_instance(self): # Next, check that we can make a part instance description shorter prt = part.models.Part.objects.first() - assert prt is not None + assert prt prt.description = prt.description[:-1] prt.save() @@ -61,7 +61,7 @@ def test_validate_model_instance(self): self.enable_plugin(True) plg = self.get_plugin() - assert plg is not None + assert plg self.assertIsNotNone(plg) plg.set_setting('BOM_ITEM_INTEGER', True) @@ -102,7 +102,7 @@ def test_validate_ipn(self): """Test the validate_ipn function.""" self.enable_plugin(True) plg = self.get_plugin() - assert plg is not None + assert plg self.assertIsNotNone(plg) self.part.IPN = 'LMNOP' diff --git a/InvenTree/plugin/samples/locate/test_locate_sample.py b/InvenTree/plugin/samples/locate/test_locate_sample.py index 539f2fdd00f..fc1c9c0038f 100644 --- a/InvenTree/plugin/samples/locate/test_locate_sample.py +++ b/InvenTree/plugin/samples/locate/test_locate_sample.py @@ -54,7 +54,7 @@ class Wrong(LocateMixin, InvenTreePlugin): plugin = Wrong() plugin.locate_stock_location(1) - assert plugin is not None + assert plugin # Test item locator with self.assertRaises(MixinNotImplementedError): diff --git a/InvenTree/plugin/test_api.py b/InvenTree/plugin/test_api.py index 36c8959b9b5..7f830b7f887 100644 --- a/InvenTree/plugin/test_api.py +++ b/InvenTree/plugin/test_api.py @@ -90,11 +90,11 @@ def test_plugin_install(self): def test_plugin_activate(self): """Test the plugin activate.""" test_plg = self.plugin_confs.first() - assert test_plg is not None + assert test_plg def assert_plugin_active(self, active): plgs = PluginConfig.objects.all().first() - assert plgs is not None + assert plgs self.assertEqual(plgs.active, active) # Should not work - not a superuser @@ -136,7 +136,7 @@ def test_admin_action(self): url = reverse('admin:plugin_pluginconfig_changelist') test_plg = self.plugin_confs.first() - assert test_plg is not None + assert test_plg # deactivate plugin response = self.client.post( @@ -186,7 +186,7 @@ def test_model(self): """Test the PluginConfig model.""" # check mixin registry plg = self.plugin_confs.first() - assert plg is not None + assert plg mixin_dict = plg.mixins() self.assertIn('base', mixin_dict) self.assertDictContainsSubset( @@ -196,7 +196,7 @@ def test_model(self): # check reload on save with self.assertWarns(Warning) as cm: plg_inactive = self.plugin_confs.filter(active=False).first() - assert plg_inactive is not None + assert plg_inactive plg_inactive.active = True plg_inactive.save() self.assertEqual(cm.warning.args[0], 'A reload was triggered') @@ -226,7 +226,7 @@ def test_plugin_settings(self): # Activate the 'sample' plugin via the API cfg = PluginConfig.objects.filter(key='sample').first() - assert cfg is not None + assert cfg url = reverse('api-plugin-detail-activate', kwargs={'pk': cfg.pk}) self.client.patch(url, {}) diff --git a/InvenTree/plugin/test_plugin.py b/InvenTree/plugin/test_plugin.py index 09937c46503..f3284014f49 100644 --- a/InvenTree/plugin/test_plugin.py +++ b/InvenTree/plugin/test_plugin.py @@ -194,7 +194,7 @@ def test_version(self): self.assertFalse(self.plugin_version.check_version([0, 1, 4])) plug = registry.plugins_full.get('sampleversion') - assert plug is not None + assert plug self.assertEqual(plug.is_active(), False) @@ -215,7 +215,7 @@ def run_package_test(self, directory): # Depends on the meta set in InvenTree/plugin/mock/simple:SimplePlugin plg = registry.get_plugin('simple') - assert plg is not None + assert plg self.assertEqual(plg.slug, 'simple') self.assertEqual(plg.human_name, 'SimplePlugin') @@ -261,7 +261,7 @@ def test_package_loading(self): # Test that plugin was installed plg = registry.get_plugin('zapier') - assert plg is not None + assert plg self.assertEqual(plg.slug, 'zapier') self.assertEqual(plg.name, 'inventree_zapier') @@ -279,11 +279,11 @@ def test_broken_samples(self): self.assertEqual(len(registry.errors), 3) # There should be at least one discovery error in the module `broken_file` _reg_disc = registry.errors.get('discovery') - assert _reg_disc is not None + assert _reg_disc self.assertTrue(len(_reg_disc) > 0) self.assertEqual(_reg_disc[0]['broken_file'], "name 'bb' is not defined") # There should be at least one load error with an intentional KeyError _reg_load = registry.errors.get('load') - assert _reg_load is not None + assert _reg_load self.assertTrue(len(_reg_load) > 0) self.assertEqual(_reg_load[0]['broken_sample'], "'This is a dummy error'") diff --git a/InvenTree/report/tests.py b/InvenTree/report/tests.py index abf7cd70aa5..ee8294d9f4d 100644 --- a/InvenTree/report/tests.py +++ b/InvenTree/report/tests.py @@ -456,6 +456,7 @@ def setUp(self): def test_print(self): """Printing tests for the TestReport.""" report = self.model.objects.first() + assert report url = reverse(self.print_url, kwargs={'pk': report.pk}) @@ -467,7 +468,7 @@ def test_print(self): # Now print with a valid StockItem item = StockItem.objects.first() - assert item is not None + assert item response = self.get(url, {'item': item.pk}, expected_code=200) @@ -511,6 +512,7 @@ def setUp(self): def test_print(self): """Printing tests for the BuildReport.""" report = self.model.objects.first() + assert report url = reverse(self.print_url, kwargs={'pk': report.pk}) @@ -523,6 +525,7 @@ def test_print(self): # Now print with a valid BuildOrder build = Build.objects.first() + assert build response = self.get(url, {'build': build.pk}) @@ -539,7 +542,7 @@ def test_print(self): inline = InvenTreeUserSetting.get_setting_object( 'REPORT_INLINE', cache=False, user=self.user ) - assert inline is not None + assert inline inline.value = True inline.save() diff --git a/InvenTree/stock/tests.py b/InvenTree/stock/tests.py index 89d9e8e9d23..fa2709a128e 100644 --- a/InvenTree/stock/tests.py +++ b/InvenTree/stock/tests.py @@ -430,6 +430,7 @@ def test_stocktake(self): # Check that a tracking item was added track = StockItemTracking.objects.filter(item=it).latest('id') + assert track.notes self.assertEqual(track.tracking_type, StockHistoryCode.STOCK_COUNT) self.assertIn('Counted items', track.notes) @@ -450,6 +451,7 @@ def test_add_stock(self): # Check that a tracking item was added track = StockItemTracking.objects.filter(item=it).latest('id') + assert track.notes self.assertEqual(track.tracking_type, StockHistoryCode.STOCK_ADD) self.assertIn('Added some items', track.notes) @@ -480,6 +482,7 @@ def test_allocate_to_customer(self): # Check that a tracking item was added track = StockItemTracking.objects.filter(item=ait).latest('id') + assert track.notes self.assertEqual( track.tracking_type, StockHistoryCode.SHIPPED_AGAINST_SALES_ORDER @@ -537,6 +540,7 @@ def test_return_from_customer(self): # Check that a tracking item was added track = StockItemTracking.objects.filter(item=ait).latest('id') + assert track.notes self.assertEqual(track.tracking_type, StockHistoryCode.RETURNED_FROM_CUSTOMER) self.assertIn('Stock removed from customer', track.notes) @@ -557,6 +561,7 @@ def test_take_stock(self): # Check that a tracking item was added track = StockItemTracking.objects.filter(item=it).latest('id') + assert track.notes self.assertEqual(track.tracking_type, StockHistoryCode.STOCK_REMOVE) self.assertIn('Removed some items', track.notes) @@ -672,6 +677,7 @@ def test_big_serials(self): item_next = item.get_next_serialized_item() item_prev = item.get_next_serialized_item(reverse=True) + assert item_next and item_prev self.assertEqual(item_next.serial_int, 101) self.assertEqual(item_prev.serial_int, 99) @@ -975,6 +981,7 @@ def test_serial_numbers(self): # Create a new serial number n = variant.get_latest_serial_number() + assert n item = StockItem(part=variant, quantity=1, serial=n) diff --git a/InvenTree/users/test_api.py b/InvenTree/users/test_api.py index c32b7c150e3..99dc1b5b0dc 100644 --- a/InvenTree/users/test_api.py +++ b/InvenTree/users/test_api.py @@ -70,7 +70,7 @@ def test_token_generation(self): # If we re-generate a token, the value changes token = ApiToken.objects.filter(name='cat').first() - assert token is not None + assert token # Request the token with the same name data = self.get(url, data={'name': 'cat'}, expected_code=200).data @@ -128,6 +128,8 @@ def test_token_auth(self): # Grab the token, and update token = ApiToken.objects.first() + assert token + self.assertEqual(token.key, token_key) self.assertIsNotNone(token.last_seen) diff --git a/InvenTree/users/tests.py b/InvenTree/users/tests.py index a69e1ba8460..a7d9cff23d7 100644 --- a/InvenTree/users/tests.py +++ b/InvenTree/users/tests.py @@ -171,12 +171,12 @@ def test_owner(self): """Tests for the 'owner' model.""" # Check that owner was created for user user_as_owner = Owner.get_owner(self.user) - assert user_as_owner is not None + assert user_as_owner self.assertEqual(type(user_as_owner), Owner) # Check that owner was created for group group_as_owner = Owner.get_owner(self.group) - assert group_as_owner is not None + assert group_as_owner self.assertEqual(type(group_as_owner), Owner) # Check name @@ -184,13 +184,13 @@ def test_owner(self): # Get related owners (user + group) related_owners = group_as_owner.get_related_owners(include_group=True) - assert related_owners is not None + assert related_owners self.assertTrue(user_as_owner in related_owners) self.assertTrue(group_as_owner in related_owners) # Get related owners (only user) related_owners = group_as_owner.get_related_owners(include_group=False) - assert related_owners is not None + assert related_owners self.assertTrue(user_as_owner in related_owners) self.assertFalse(group_as_owner in related_owners) diff --git a/InvenTree/web/tests.py b/InvenTree/web/tests.py index e3ab9042dc6..0e1e43ad047 100644 --- a/InvenTree/web/tests.py +++ b/InvenTree/web/tests.py @@ -26,6 +26,8 @@ def assertSettings(self, settings_data): def test_spa_bundle(self): """Test the 'spa_bundle' template tag.""" resp = spa_helper.spa_bundle() + assert resp + shipped_js = resp.split('