Add more checks to pre-commit (#3132)

* Add bandit to pre-commit checks

* fix catchall exceptions

* remove unused definitons

* remove unuseed ariables

* Add docstring

* fix B006, B008 errors

* fix B007 error

* ignore B009

* Add checks for formatting and naming
This commit is contained in:
Matthias Mair 2022-06-06 00:56:52 +02:00 committed by GitHub
parent bbbfd003e0
commit f38386b13c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
56 changed files with 154 additions and 109 deletions

View File

@ -18,6 +18,12 @@ repos:
rev: '4.0.1' rev: '4.0.1'
hooks: hooks:
- id: flake8 - id: flake8
additional_dependencies: [
'flake8-bugbear',
'flake8-docstrings',
'flake8-string-format',
'pep8-naming ',
]
- repo: https://github.com/pycqa/isort - repo: https://github.com/pycqa/isort
rev: '5.10.1' rev: '5.10.1'
hooks: hooks:

View File

@ -105,8 +105,12 @@ class InvenTreeAPITestCase(UserMixin, APITestCase):
return actions return actions
def get(self, url, data={}, expected_code=200): def get(self, url, data=None, expected_code=200):
"""Issue a GET request.""" """Issue a GET request."""
# Set default - see B006
if data is None:
data = {}
response = self.client.get(url, data, format='json') response = self.client.get(url, data, format='json')
if expected_code is not None: if expected_code is not None:

View File

@ -136,7 +136,7 @@ class InvenTreeConfig(AppConfig):
logger.info("Exchange backend not found - updating") logger.info("Exchange backend not found - updating")
update = True update = True
except: except Exception:
# Some other error - potentially the tables are not ready yet # Some other error - potentially the tables are not ready yet
return return

View File

@ -43,12 +43,16 @@ class InvenTreeExchange(SimpleExchangeBackend):
context = ssl.create_default_context(cafile=certifi.where()) context = ssl.create_default_context(cafile=certifi.where())
response = urlopen(url, timeout=5, context=context) response = urlopen(url, timeout=5, context=context)
return response.read() return response.read()
except: except Exception:
# Returning None here will raise an error upstream # Returning None here will raise an error upstream
return None return None
def update_rates(self, base_currency=currency_code_default()): def update_rates(self, base_currency=None):
"""Set the requested currency codes and get rates.""" """Set the requested currency codes and get rates."""
# Set default - see B008
if base_currency is None:
base_currency = currency_code_default()
symbols = ','.join(currency_codes()) symbols = ','.join(currency_codes())
try: try:

View File

@ -95,7 +95,7 @@ def TestIfImage(img):
try: try:
Image.open(img).verify() Image.open(img).verify()
return True return True
except: except Exception:
return False return False

View File

@ -17,7 +17,7 @@ class Command(BaseCommand):
from part.models import Part from part.models import Part
Part.objects.rebuild() Part.objects.rebuild()
except: except Exception:
print("Error rebuilding Part objects") print("Error rebuilding Part objects")
# Part category # Part category
@ -26,7 +26,7 @@ class Command(BaseCommand):
from part.models import PartCategory from part.models import PartCategory
PartCategory.objects.rebuild() PartCategory.objects.rebuild()
except: except Exception:
print("Error rebuilding PartCategory objects") print("Error rebuilding PartCategory objects")
# StockItem model # StockItem model
@ -35,7 +35,7 @@ class Command(BaseCommand):
from stock.models import StockItem from stock.models import StockItem
StockItem.objects.rebuild() StockItem.objects.rebuild()
except: except Exception:
print("Error rebuilding StockItem objects") print("Error rebuilding StockItem objects")
# StockLocation model # StockLocation model
@ -44,7 +44,7 @@ class Command(BaseCommand):
from stock.models import StockLocation from stock.models import StockLocation
StockLocation.objects.rebuild() StockLocation.objects.rebuild()
except: except Exception:
print("Error rebuilding StockLocation objects") print("Error rebuilding StockLocation objects")
# Build model # Build model
@ -53,5 +53,5 @@ class Command(BaseCommand):
from build.models import Build from build.models import Build
Build.objects.rebuild() Build.objects.rebuild()
except: except Exception:
print("Error rebuilding Build objects") print("Error rebuilding Build objects")

View File

@ -137,7 +137,7 @@ class InvenTreeMetadata(SimpleMetadata):
if callable(default): if callable(default):
try: try:
default = default() default = default()
except: except Exception:
continue continue
serializer_info[name]['default'] = default serializer_info[name]['default'] = default

View File

@ -98,7 +98,7 @@ class AuthRequiredMiddleware(object):
if path not in urls and not any([path.startswith(p) for p in paths_ignore]): if path not in urls and not any([path.startswith(p) for p in paths_ignore]):
# Save the 'next' parameter to pass through to the login view # Save the 'next' parameter to pass through to the login view
return redirect('{}?next={}'.format(reverse_lazy('account_login'), request.path)) return redirect(f'{reverse_lazy("account_login")}?next={request.path}')
else: else:
# Return a 401 (Unauthorized) response code for this request # Return a 401 (Unauthorized) response code for this request

View File

@ -133,7 +133,7 @@ def extract_int(reference, clip=0x7fffffff):
ref = result.groups()[0] ref = result.groups()[0]
try: try:
ref_int = int(ref) ref_int = int(ref)
except: except Exception:
ref_int = 0 ref_int = 0
# Ensure that the returned values are within the range that can be stored in an IntegerField # Ensure that the returned values are within the range that can be stored in an IntegerField
@ -276,7 +276,7 @@ class InvenTreeAttachment(models.Model):
os.rename(old_file, new_file) os.rename(old_file, new_file)
self.attachment.name = os.path.join(self.getSubdir(), fn) self.attachment.name = os.path.join(self.getSubdir(), fn)
self.save() self.save()
except: except Exception:
raise ValidationError(_("Error renaming file")) raise ValidationError(_("Error renaming file"))
class Meta: class Meta:

View File

@ -47,7 +47,7 @@ class InvenTreeMoneySerializer(MoneyField):
try: try:
if amount is not None and amount is not empty: if amount is not None and amount is not empty:
amount = Decimal(amount) amount = Decimal(amount)
except: except Exception:
raise ValidationError({ raise ValidationError({
self.field_name: [_("Must be a valid number")], self.field_name: [_("Must be a valid number")],
}) })
@ -120,7 +120,7 @@ class InvenTreeModelSerializer(serializers.ModelSerializer):
if callable(value): if callable(value):
try: try:
value = value() value = value()
except: except Exception:
continue continue
data[field_name] = value data[field_name] = value
@ -150,7 +150,7 @@ class InvenTreeModelSerializer(serializers.ModelSerializer):
if callable(value): if callable(value):
try: try:
value = value() value = value()
except: except Exception:
continue continue
initials[field_name] = value initials[field_name] = value
@ -302,7 +302,7 @@ class InvenTreeDecimalField(serializers.FloatField):
# Convert the value to a string, and then a decimal # Convert the value to a string, and then a decimal
try: try:
return Decimal(str(data)) return Decimal(str(data))
except: except Exception:
raise serializers.ValidationError(_("Invalid value")) raise serializers.ValidationError(_("Invalid value"))
@ -423,7 +423,7 @@ class DataFileUploadSerializer(serializers.Serializer):
if self.TARGET_MODEL: if self.TARGET_MODEL:
try: try:
model_fields = self.TARGET_MODEL.get_import_fields() model_fields = self.TARGET_MODEL.get_import_fields()
except: except Exception:
pass pass
# Extract a list of valid model field names # Extract a list of valid model field names
@ -515,7 +515,7 @@ class DataFileExtractSerializer(serializers.Serializer):
if self.TARGET_MODEL: if self.TARGET_MODEL:
try: try:
model_fields = self.TARGET_MODEL.get_import_fields() model_fields = self.TARGET_MODEL.get_import_fields()
except: except Exception:
model_fields = {} model_fields = {}
rows = [] rows = []
@ -568,7 +568,7 @@ class DataFileExtractSerializer(serializers.Serializer):
if self.TARGET_MODEL: if self.TARGET_MODEL:
try: try:
model_fields = self.TARGET_MODEL.get_import_fields() model_fields = self.TARGET_MODEL.get_import_fields()
except: except Exception:
model_fields = {} model_fields = {}
cols_seen = set() cols_seen = set()

View File

@ -242,7 +242,7 @@ def update_exchange_rates():
# Apps not yet loaded! # Apps not yet loaded!
logger.info("Could not perform 'update_exchange_rates' - App registry not ready") logger.info("Could not perform 'update_exchange_rates' - App registry not ready")
return return
except: # pragma: no cover except Exception: # pragma: no cover
# Other error? # Other error?
return return
@ -251,7 +251,7 @@ def update_exchange_rates():
backend = ExchangeBackend.objects.get(name='InvenTreeExchange') backend = ExchangeBackend.objects.get(name='InvenTreeExchange')
except ExchangeBackend.DoesNotExist: except ExchangeBackend.DoesNotExist:
pass pass
except: # pragma: no cover except Exception: # pragma: no cover
# Some other error # Some other error
logger.warning("update_exchange_rates: Database not ready") logger.warning("update_exchange_rates: Database not ready")
return return

View File

@ -417,7 +417,7 @@ class CurrencyTests(TestCase):
update_successful = False update_successful = False
# Note: the update sometimes fails in CI, let's give it a few chances # Note: the update sometimes fails in CI, let's give it a few chances
for idx in range(10): for _ in range(10):
InvenTree.tasks.update_exchange_rates() InvenTree.tasks.update_exchange_rates()
rates = Rate.objects.all() rates = Rate.objects.all()
@ -469,12 +469,20 @@ class TestSettings(helpers.InvenTreeTestCase):
superuser = True superuser = True
def in_env_context(self, envs={}): def in_env_context(self, envs=None):
"""Patch the env to include the given dict.""" """Patch the env to include the given dict."""
# Set default - see B006
if envs is None:
envs = {}
return mock.patch.dict(os.environ, envs) return mock.patch.dict(os.environ, envs)
def run_reload(self, envs={}): def run_reload(self, envs=None):
"""Helper function to reload InvenTree.""" """Helper function to reload InvenTree."""
# Set default - see B006
if envs is None:
envs = {}
from plugin import registry from plugin import registry
with self.in_env_context(envs): with self.in_env_context(envs):

View File

@ -92,7 +92,7 @@ def validate_sales_order_reference(value):
def validate_tree_name(value): def validate_tree_name(value):
"""Prevent illegal characters in tree item names.""" """Prevent illegal characters in tree item names."""
for c in "!@#$%^&*'\"\\/[]{}<>,|+=~`\"": for c in "!@#$%^&*'\"\\/[]{}<>,|+=~`\"": # noqa: P103
if c in str(value): if c in str(value):
raise ValidationError(_('Illegal character in name ({x})'.format(x=c))) raise ValidationError(_('Illegal character in name ({x})'.format(x=c)))

View File

@ -99,7 +99,7 @@ def inventreeCommitHash():
try: try:
return str(subprocess.check_output('git rev-parse --short HEAD'.split()), 'utf-8').strip() return str(subprocess.check_output('git rev-parse --short HEAD'.split()), 'utf-8').strip()
except: # pragma: no cover except Exception: # pragma: no cover
return None return None
@ -114,5 +114,5 @@ def inventreeCommitDate():
try: try:
d = str(subprocess.check_output('git show -s --format=%ci'.split()), 'utf-8').strip() d = str(subprocess.check_output('git show -s --format=%ci'.split()), 'utf-8').strip()
return d.split(' ')[0] return d.split(' ')[0]
except: # pragma: no cover except Exception: # pragma: no cover
return None return None

View File

@ -527,7 +527,7 @@ class AjaxDeleteView(AjaxMixin, UpdateView):
"""Return object matched to the model of the calling class.""" """Return object matched to the model of the calling class."""
try: try:
self.object = self.model.objects.get(pk=self.kwargs['pk']) self.object = self.model.objects.get(pk=self.kwargs['pk'])
except: except Exception:
return None return None
return self.object return self.object
@ -691,14 +691,14 @@ class SettingsView(TemplateView):
try: try:
backend = ExchangeBackend.objects.get(name='InvenTreeExchange') backend = ExchangeBackend.objects.get(name='InvenTreeExchange')
ctx["rates_updated"] = backend.last_update ctx["rates_updated"] = backend.last_update
except: except Exception:
ctx["rates_updated"] = None ctx["rates_updated"] = None
# load locale stats # load locale stats
STAT_FILE = os.path.abspath(os.path.join(settings.BASE_DIR, 'InvenTree/locale_stats.json')) STAT_FILE = os.path.abspath(os.path.join(settings.BASE_DIR, 'InvenTree/locale_stats.json'))
try: try:
ctx["locale_stats"] = json.load(open(STAT_FILE, 'r')) ctx["locale_stats"] = json.load(open(STAT_FILE, 'r'))
except: except Exception:
ctx["locale_stats"] = {} ctx["locale_stats"] = {}
# Forms and context for allauth # Forms and context for allauth

View File

@ -223,7 +223,7 @@ class BuildUnallocate(generics.CreateAPIView):
try: try:
ctx['build'] = Build.objects.get(pk=self.kwargs.get('pk', None)) ctx['build'] = Build.objects.get(pk=self.kwargs.get('pk', None))
except: except Exception:
pass pass
ctx['request'] = self.request ctx['request'] = self.request
@ -243,7 +243,7 @@ class BuildOrderContextMixin:
try: try:
ctx['build'] = Build.objects.get(pk=self.kwargs.get('pk', None)) ctx['build'] = Build.objects.get(pk=self.kwargs.get('pk', None))
except: except Exception:
pass pass
return ctx return ctx

View File

@ -21,7 +21,7 @@ def build_refs(apps, schema_editor):
if result and len(result.groups()) == 1: if result and len(result.groups()) == 1:
try: try:
ref = int(result.groups()[0]) ref = int(result.groups()[0])
except: # pragma: no cover except Exception: # pragma: no cover
ref = 0 ref = 0
build.reference_int = ref build.reference_int = ref

View File

@ -1244,13 +1244,13 @@ class BuildItem(models.Model):
try: try:
# Try to extract the thumbnail # Try to extract the thumbnail
thumb_url = self.stock_item.part.image.thumbnail.url thumb_url = self.stock_item.part.image.thumbnail.url
except: except Exception:
pass pass
if thumb_url is None and self.bom_item and self.bom_item.sub_part: if thumb_url is None and self.bom_item and self.bom_item.sub_part:
try: try:
thumb_url = self.bom_item.sub_part.image.thumbnail.url thumb_url = self.bom_item.sub_part.image.thumbnail.url
except: except Exception:
pass pass
if thumb_url is not None: if thumb_url is not None:

View File

@ -195,7 +195,7 @@ class BuildTest(BuildAPITest):
self.assertEqual(self.build.incomplete_outputs.count(), 0) self.assertEqual(self.build.incomplete_outputs.count(), 0)
# Create some more build outputs # Create some more build outputs
for ii in range(10): for _ in range(10):
self.build.create_build_output(10) self.build.create_build_output(10)
# Check that we are in a known state # Check that we are in a known state

View File

@ -27,5 +27,5 @@ class CommonConfig(AppConfig):
if common.models.InvenTreeSetting.get_setting('SERVER_RESTART_REQUIRED', backup_value=False, create=False): if common.models.InvenTreeSetting.get_setting('SERVER_RESTART_REQUIRED', backup_value=False, create=False):
logger.info("Clearing SERVER_RESTART_REQUIRED flag") logger.info("Clearing SERVER_RESTART_REQUIRED flag")
common.models.InvenTreeSetting.set_setting('SERVER_RESTART_REQUIRED', False, None) common.models.InvenTreeSetting.set_setting('SERVER_RESTART_REQUIRED', False, None)
except: except Exception:
pass pass

View File

@ -142,7 +142,7 @@ class FileManager:
guess = self.guess_header(header, threshold=95) guess = self.guess_header(header, threshold=95)
# Check if already present # Check if already present
guess_exists = False guess_exists = False
for idx, data in enumerate(headers): for _idx, data in enumerate(headers):
if guess == data['guess']: if guess == data['guess']:
guess_exists = True guess_exists = True
break break

View File

@ -571,7 +571,7 @@ class BaseInvenTreeSetting(models.Model):
# If a valid class has been found, see if it has registered an API URL # If a valid class has been found, see if it has registered an API URL
try: try:
return model_class.get_api_url() return model_class.get_api_url()
except: except Exception:
pass pass
return None return None

View File

@ -495,8 +495,12 @@ class FileManagementAjaxView(AjaxView):
self.storage.current_step = self.steps.first self.storage.current_step = self.steps.first
return self.renderJsonResponse(request) return self.renderJsonResponse(request)
def renderJsonResponse(self, request, form=None, data={}, context=None): def renderJsonResponse(self, request, form=None, data=None, context=None):
"""Always set the right templates before rendering.""" """Always set the right templates before rendering."""
# Set default - see B006
if data is None:
data = {}
self.setTemplate() self.setTemplate()
return super().renderJsonResponse(request, form=form, data=data, context=context) return super().renderJsonResponse(request, form=form, data=data, context=context)

View File

@ -151,7 +151,7 @@ class CompanyImageDownloadFromURL(AjaxUpdateView):
try: try:
self.image = Image.open(response.raw).convert() self.image = Image.open(response.raw).convert()
self.image.verify() self.image.verify()
except: except Exception:
form.add_error('url', _("Supplied URL is not a valid image file")) form.add_error('url', _("Supplied URL is not a valid image file"))
return return

View File

@ -363,7 +363,7 @@ class StockLocationLabelList(LabelListView, StockLocationLabelMixin):
# Filter string defined for the StockLocationLabel object # Filter string defined for the StockLocationLabel object
try: try:
filters = InvenTree.helpers.validateFilterString(label.filters) filters = InvenTree.helpers.validateFilterString(label.filters)
except: # pragma: no cover except Exception: # pragma: no cover
# Skip if there was an error validating the filters... # Skip if there was an error validating the filters...
continue continue

View File

@ -22,8 +22,12 @@ class TestReportTests(InvenTreeAPITestCase):
list_url = reverse('api-stockitem-testreport-list') list_url = reverse('api-stockitem-testreport-list')
def do_list(self, filters={}): def do_list(self, filters=None):
"""Helper function to request list of labels with provided filters""" """Helper function to request list of labels with provided filters"""
# Set default - see B006
if filters is None:
filters = {}
response = self.client.get(self.list_url, filters, format='json') response = self.client.get(self.list_url, filters, format='json')
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)

View File

@ -295,7 +295,7 @@ class PurchaseOrderContextMixin:
# Pass the purchase order through to the serializer for validation # Pass the purchase order through to the serializer for validation
try: try:
context['order'] = models.PurchaseOrder.objects.get(pk=self.kwargs.get('pk', None)) context['order'] = models.PurchaseOrder.objects.get(pk=self.kwargs.get('pk', None))
except: except Exception:
pass pass
context['request'] = self.request context['request'] = self.request
@ -857,7 +857,7 @@ class SalesOrderContextMixin:
try: try:
ctx['order'] = models.SalesOrder.objects.get(pk=self.kwargs.get('pk', None)) ctx['order'] = models.SalesOrder.objects.get(pk=self.kwargs.get('pk', None))
except: except Exception:
pass pass
return ctx return ctx
@ -1050,7 +1050,7 @@ class SalesOrderShipmentComplete(generics.CreateAPIView):
ctx['shipment'] = models.SalesOrderShipment.objects.get( ctx['shipment'] = models.SalesOrderShipment.objects.get(
pk=self.kwargs.get('pk', None) pk=self.kwargs.get('pk', None)
) )
except: except Exception:
pass pass
return ctx return ctx

View File

@ -20,7 +20,7 @@ def build_refs(apps, schema_editor):
if result and len(result.groups()) == 1: if result and len(result.groups()) == 1:
try: try:
ref = int(result.groups()[0]) ref = int(result.groups()[0])
except: # pragma: no cover except Exception: # pragma: no cover
ref = 0 ref = 0
order.reference_int = ref order.reference_int = ref
@ -37,7 +37,7 @@ def build_refs(apps, schema_editor):
if result and len(result.groups()) == 1: if result and len(result.groups()) == 1:
try: try:
ref = int(result.groups()[0]) ref = int(result.groups()[0])
except: # pragma: no cover except Exception: # pragma: no cover
ref = 0 ref = 0
order.reference_int = ref order.reference_int = ref

View File

@ -154,7 +154,7 @@ class Order(MetadataMixin, ReferenceIndexingMixin):
notes = MarkdownxField(blank=True, verbose_name=_('Notes'), help_text=_('Order notes')) notes = MarkdownxField(blank=True, verbose_name=_('Notes'), help_text=_('Order notes'))
def get_total_price(self, target_currency=currency_code_default()): def get_total_price(self, target_currency=None):
"""Calculates the total price of all order lines, and converts to the specified target currency. """Calculates the total price of all order lines, and converts to the specified target currency.
If not specified, the default system currency is used. If not specified, the default system currency is used.
@ -162,6 +162,10 @@ class Order(MetadataMixin, ReferenceIndexingMixin):
If currency conversion fails (e.g. there are no valid conversion rates), If currency conversion fails (e.g. there are no valid conversion rates),
then we simply return zero, rather than attempting some other calculation. then we simply return zero, rather than attempting some other calculation.
""" """
# Set default - see B008
if target_currency is None:
target_currency = currency_code_default()
total = Money(0, target_currency) total = Money(0, target_currency)
# gather name reference # gather name reference

View File

@ -606,7 +606,7 @@ class PartCopyBOM(generics.CreateAPIView):
try: try:
ctx['part'] = Part.objects.get(pk=self.kwargs.get('pk', None)) ctx['part'] = Part.objects.get(pk=self.kwargs.get('pk', None))
except: except Exception:
pass pass
return ctx return ctx
@ -1042,12 +1042,12 @@ class PartList(APIDownloadMixin, generics.ListCreateAPIView):
try: try:
manufacturer = Company.objects.get(pk=request.data.get('manufacturer', None)) manufacturer = Company.objects.get(pk=request.data.get('manufacturer', None))
except: except Exception:
manufacturer = None manufacturer = None
try: try:
supplier = Company.objects.get(pk=request.data.get('supplier', None)) supplier = Company.objects.get(pk=request.data.get('supplier', None))
except: except Exception:
supplier = None supplier = None
mpn = str(request.data.get('MPN', '')).strip() mpn = str(request.data.get('MPN', '')).strip()

View File

@ -593,7 +593,7 @@ class Part(MetadataMixin, MPTTModel):
try: try:
latest = int(latest) latest = int(latest)
return latest return latest
except: except Exception:
# not an integer so 0 # not an integer so 0
return 0 return 0
@ -610,7 +610,7 @@ class Part(MetadataMixin, MPTTModel):
# Attempt to turn into an integer # Attempt to turn into an integer
try: try:
latest = int(latest) latest = int(latest)
except: except Exception:
pass pass
if type(latest) is int: if type(latest) is int:
@ -2283,7 +2283,7 @@ class PartTestTemplate(models.Model):
def validate_template_name(name): def validate_template_name(name):
"""Prevent illegal characters in "name" field for PartParameterTemplate.""" """Prevent illegal characters in "name" field for PartParameterTemplate."""
for c in "!@#$%^&*()<>{}[].,?/\\|~`_+-=\'\"": for c in "!@#$%^&*()<>{}[].,?/\\|~`_+-=\'\"": # noqa: P103
if c in str(name): if c in str(name):
raise ValidationError(_(f"Illegal character in template name ({c})")) raise ValidationError(_(f"Illegal character in template name ({c})"))

View File

@ -902,7 +902,7 @@ class BomImportExtractSerializer(DataFileExtractSerializer):
if level != 1: if level != 1:
# Skip this row # Skip this row
return None return None
except: except Exception:
pass pass
# Attempt to extract a valid part based on the provided data # Attempt to extract a valid part based on the provided data
@ -954,7 +954,7 @@ class BomImportExtractSerializer(DataFileExtractSerializer):
if quantity <= 0: if quantity <= 0:
row['errors']['quantity'] = _('Quantity must be greater than zero') row['errors']['quantity'] = _('Quantity must be greater than zero')
except: except Exception:
row['errors']['quantity'] = _('Invalid quantity') row['errors']['quantity'] = _('Invalid quantity')
return row return row

View File

@ -412,7 +412,7 @@ def primitive_to_javascript(primitive):
else: else:
# Wrap with quotes # Wrap with quotes
return format_html("'{}'", primitive) return format_html("'{}'", primitive) # noqa: P103
@register.filter @register.filter
@ -458,7 +458,7 @@ def authorized_owners(group):
def object_link(url_name, pk, ref): def object_link(url_name, pk, ref):
"""Return highlighted link to object.""" """Return highlighted link to object."""
ref_url = reverse(url_name, kwargs={'pk': pk}) ref_url = reverse(url_name, kwargs={'pk': pk})
return mark_safe('<b><a href="{}">{}</a></b>'.format(ref_url, ref)) return mark_safe(f'<b><a href="{ref_url}">{ref}</a></b>')
@register.simple_tag() @register.simple_tag()

View File

@ -1285,7 +1285,7 @@ class PartAPIAggregationTest(InvenTreeAPITestCase):
self.assertEqual(data['stock_item_count'], 4) self.assertEqual(data['stock_item_count'], 4)
# Add some more stock items!! # Add some more stock items!!
for i in range(100): for _ in range(100):
StockItem.objects.create(part=self.part, quantity=5) StockItem.objects.create(part=self.part, quantity=5)
# Add another stock item which is assigned to a customer (and shouldn't count) # Add another stock item which is assigned to a customer (and shouldn't count)
@ -1628,7 +1628,7 @@ class BomItemTest(InvenTreeAPITestCase):
Part.objects.rebuild() Part.objects.rebuild()
# Create some stock items for this new part # Create some stock items for this new part
for jj in range(ii): for _ in range(ii):
StockItem.objects.create( StockItem.objects.create(
part=variant, part=variant,
location=loc, location=loc,

View File

@ -228,7 +228,7 @@ class BomUploadTest(InvenTreeAPITestCase):
components = Part.objects.filter(component=True) components = Part.objects.filter(component=True)
for idx, cmp in enumerate(components): for idx, _ in enumerate(components):
dataset.append([ dataset.append([
f"Component {idx}", f"Component {idx}",
10, 10,
@ -257,7 +257,7 @@ class BomUploadTest(InvenTreeAPITestCase):
dataset.headers = ['part_ipn', 'quantity'] dataset.headers = ['part_ipn', 'quantity']
for idx, cmp in enumerate(components): for idx, _ in enumerate(components):
dataset.append([ dataset.append([
f"CMP_{idx}", f"CMP_{idx}",
10, 10,

View File

@ -190,7 +190,7 @@ class PartTest(TestCase):
try: try:
part.save() part.save()
self.assertTrue(False) # pragma: no cover self.assertTrue(False) # pragma: no cover
except: except Exception:
pass pass
self.assertEqual(Part.objects.count(), n + 1) self.assertEqual(Part.objects.count(), n + 1)

View File

@ -618,7 +618,7 @@ class PartImageDownloadFromURL(AjaxUpdateView):
try: try:
self.image = Image.open(response.raw).convert() self.image = Image.open(response.raw).convert()
self.image.verify() self.image.verify()
except: except Exception:
form.add_error('url', _("Supplied URL is not a valid image file")) form.add_error('url', _("Supplied URL is not a valid image file"))
return return

View File

@ -39,7 +39,7 @@ class PluginAppConfig(AppConfig):
if InvenTreeSetting.get_setting('PLUGIN_ON_STARTUP', create=False): if InvenTreeSetting.get_setting('PLUGIN_ON_STARTUP', create=False):
# make sure all plugins are installed # make sure all plugins are installed
registry.install_plugin_file() registry.install_plugin_file()
except: # pragma: no cover except Exception: # pragma: no cover
pass pass
# get plugins and init them # get plugins and init them

View File

@ -200,7 +200,7 @@ class ScheduleMixin:
try: try:
from django_q.models import Schedule from django_q.models import Schedule
for key, task in self.scheduled_tasks.items(): for key, _ in self.scheduled_tasks.items():
task_name = self.get_task_name(key) task_name = self.get_task_name(key)

View File

@ -169,7 +169,7 @@ class GitStatus:
def get_modules(pkg): def get_modules(pkg):
"""Get all modules in a package.""" """Get all modules in a package."""
context = {} context = {}
for loader, name, ispkg in pkgutil.walk_packages(pkg.__path__): for loader, name, _ in pkgutil.walk_packages(pkg.__path__):
try: try:
module = loader.find_module(name).load_module(name) module = loader.find_module(name).load_module(name)
pkg_names = getattr(module, '__all__', None) pkg_names = getattr(module, '__all__', None)

View File

@ -382,7 +382,7 @@ class PluginsRegistry:
if settings.PLUGIN_TESTING or InvenTreeSetting.get_setting('ENABLE_PLUGINS_SCHEDULE'): if settings.PLUGIN_TESTING or InvenTreeSetting.get_setting('ENABLE_PLUGINS_SCHEDULE'):
for slug, plugin in plugins: for _, plugin in plugins:
if plugin.mixin_enabled('schedule'): if plugin.mixin_enabled('schedule'):
config = plugin.plugin_config() config = plugin.plugin_config()
@ -437,7 +437,7 @@ class PluginsRegistry:
apps_changed = False apps_changed = False
# add them to the INSTALLED_APPS # add them to the INSTALLED_APPS
for slug, plugin in plugins: for _, plugin in plugins:
if plugin.mixin_enabled('app'): if plugin.mixin_enabled('app'):
plugin_path = self._get_plugin_path(plugin) plugin_path = self._get_plugin_path(plugin)
if plugin_path not in settings.INSTALLED_APPS: if plugin_path not in settings.INSTALLED_APPS:
@ -522,7 +522,7 @@ class PluginsRegistry:
# remove model from admin site # remove model from admin site
try: try:
admin.site.unregister(model) admin.site.unregister(model)
except: # pragma: no cover except Exception: # pragma: no cover
pass pass
models += [model._meta.model_name] models += [model._meta.model_name]
except LookupError: # pragma: no cover except LookupError: # pragma: no cover

View File

@ -113,7 +113,7 @@ class CustomPanelSample(PanelMixin, SettingsMixin, InvenTreePlugin):
'icon': 'fa-user', 'icon': 'fa-user',
'content_template': 'panel_demo/childless.html', # Note that the panel content is rendered using a template file! 'content_template': 'panel_demo/childless.html', # Note that the panel content is rendered using a template file!
}) })
except: # pragma: no cover except Exception: # pragma: no cover
pass pass
return panels return panels

View File

@ -57,7 +57,7 @@ def safe_url(view_name, *args, **kwargs):
""" """
try: try:
return reverse(view_name, args=args, kwargs=kwargs) return reverse(view_name, args=args, kwargs=kwargs)
except: except Exception:
return None return None

View File

@ -289,7 +289,7 @@ class StockItemTestReportList(ReportListView, StockItemReportMixin):
# Filter string defined for the report object # Filter string defined for the report object
try: try:
filters = InvenTree.helpers.validateFilterString(report.filters) filters = InvenTree.helpers.validateFilterString(report.filters)
except: except Exception:
continue continue
for item in items: for item in items:
@ -528,7 +528,7 @@ class PurchaseOrderReportList(ReportListView, OrderReportMixin):
# Filter string defined for the report object # Filter string defined for the report object
try: try:
filters = InvenTree.helpers.validateFilterString(report.filters) filters = InvenTree.helpers.validateFilterString(report.filters)
except: except Exception:
continue continue
for o in orders: for o in orders:
@ -607,7 +607,7 @@ class SalesOrderReportList(ReportListView, OrderReportMixin):
# Filter string defined for the report object # Filter string defined for the report object
try: try:
filters = InvenTree.helpers.validateFilterString(report.filters) filters = InvenTree.helpers.validateFilterString(report.filters)
except: except Exception:
continue continue
for o in orders: for o in orders:

View File

@ -75,14 +75,14 @@ class ReportConfig(AppConfig):
enabled=True enabled=True
) )
except: except Exception:
pass pass
def create_default_test_reports(self): def create_default_test_reports(self):
"""Create database entries for the default TestReport templates, if they do not already exist.""" """Create database entries for the default TestReport templates, if they do not already exist."""
try: try:
from .models import TestReport from .models import TestReport
except: # pragma: no cover except Exception: # pragma: no cover
# Database is not ready yet # Database is not ready yet
return return
@ -101,7 +101,7 @@ class ReportConfig(AppConfig):
"""Create database entries for the default BuildReport templates (if they do not already exist)""" """Create database entries for the default BuildReport templates (if they do not already exist)"""
try: try:
from .models import BuildReport from .models import BuildReport
except: # pragma: no cover except Exception: # pragma: no cover
# Database is not ready yet # Database is not ready yet
return return

View File

@ -99,7 +99,7 @@ class StockItemContextMixin:
try: try:
context['item'] = StockItem.objects.get(pk=self.kwargs.get('pk', None)) context['item'] = StockItem.objects.get(pk=self.kwargs.get('pk', None))
except: except Exception:
pass pass
return context return context
@ -830,7 +830,7 @@ class StockList(APIDownloadMixin, generics.ListCreateAPIView):
if part.tree_id is not None: if part.tree_id is not None:
queryset = queryset.filter(part__tree_id=part.tree_id) queryset = queryset.filter(part__tree_id=part.tree_id)
except: except Exception:
pass pass
# Filter by 'allocated' parts? # Filter by 'allocated' parts?
@ -1144,7 +1144,7 @@ class StockItemTestResultList(generics.ListCreateAPIView):
"""Set context before returning serializer.""" """Set context before returning serializer."""
try: try:
kwargs['user_detail'] = str2bool(self.request.query_params.get('user_detail', False)) kwargs['user_detail'] = str2bool(self.request.query_params.get('user_detail', False))
except: except Exception:
pass pass
kwargs['context'] = self.get_serializer_context() kwargs['context'] = self.get_serializer_context()
@ -1186,12 +1186,12 @@ class StockTrackingList(generics.ListAPIView):
"""Set context before returning serializer.""" """Set context before returning serializer."""
try: try:
kwargs['item_detail'] = str2bool(self.request.query_params.get('item_detail', False)) kwargs['item_detail'] = str2bool(self.request.query_params.get('item_detail', False))
except: except Exception:
pass pass
try: try:
kwargs['user_detail'] = str2bool(self.request.query_params.get('user_detail', False)) kwargs['user_detail'] = str2bool(self.request.query_params.get('user_detail', False))
except: except Exception:
pass pass
kwargs['context'] = self.get_serializer_context() kwargs['context'] = self.get_serializer_context()
@ -1219,7 +1219,7 @@ class StockTrackingList(generics.ListAPIView):
part = Part.objects.get(pk=deltas['part']) part = Part.objects.get(pk=deltas['part'])
serializer = PartBriefSerializer(part) serializer = PartBriefSerializer(part)
deltas['part_detail'] = serializer.data deltas['part_detail'] = serializer.data
except: except Exception:
pass pass
# Add location detail # Add location detail
@ -1228,7 +1228,7 @@ class StockTrackingList(generics.ListAPIView):
location = StockLocation.objects.get(pk=deltas['location']) location = StockLocation.objects.get(pk=deltas['location'])
serializer = StockSerializers.LocationSerializer(location) serializer = StockSerializers.LocationSerializer(location)
deltas['location_detail'] = serializer.data deltas['location_detail'] = serializer.data
except: except Exception:
pass pass
# Add stockitem detail # Add stockitem detail
@ -1237,7 +1237,7 @@ class StockTrackingList(generics.ListAPIView):
stockitem = StockItem.objects.get(pk=deltas['stockitem']) stockitem = StockItem.objects.get(pk=deltas['stockitem'])
serializer = StockSerializers.StockItemSerializer(stockitem) serializer = StockSerializers.StockItemSerializer(stockitem)
deltas['stockitem_detail'] = serializer.data deltas['stockitem_detail'] = serializer.data
except: except Exception:
pass pass
# Add customer detail # Add customer detail
@ -1246,7 +1246,7 @@ class StockTrackingList(generics.ListAPIView):
customer = Company.objects.get(pk=deltas['customer']) customer = Company.objects.get(pk=deltas['customer'])
serializer = CompanySerializer(customer) serializer = CompanySerializer(customer)
deltas['customer_detail'] = serializer.data deltas['customer_detail'] = serializer.data
except: except Exception:
pass pass
# Add purchaseorder detail # Add purchaseorder detail
@ -1255,7 +1255,7 @@ class StockTrackingList(generics.ListAPIView):
order = PurchaseOrder.objects.get(pk=deltas['purchaseorder']) order = PurchaseOrder.objects.get(pk=deltas['purchaseorder'])
serializer = PurchaseOrderSerializer(order) serializer = PurchaseOrderSerializer(order)
deltas['purchaseorder_detail'] = serializer.data deltas['purchaseorder_detail'] = serializer.data
except: except Exception:
pass pass
if request.is_ajax(): if request.is_ajax():

View File

@ -56,7 +56,7 @@ def update_history(apps, schema_editor):
try: try:
deltas['quantity']: float(q) deltas['quantity']: float(q)
updated = True updated = True
except: except Exception:
print(f"WARNING: Error converting quantity '{q}'") print(f"WARNING: Error converting quantity '{q}'")
@ -89,7 +89,7 @@ def update_history(apps, schema_editor):
# Ensure that 'quantity' is stored too in this case # Ensure that 'quantity' is stored too in this case
deltas['quantity'] = float(q) deltas['quantity'] = float(q)
except: except Exception:
print(f"WARNING: Error converting removed quantity '{removed}'") print(f"WARNING: Error converting removed quantity '{removed}'")
else: else:
print(f"Could not decode '{title}'") print(f"Could not decode '{title}'")
@ -168,7 +168,7 @@ def update_history(apps, schema_editor):
# Ensure that 'quantity' is stored too in this case # Ensure that 'quantity' is stored too in this case
deltas['quantity'] = float(q) deltas['quantity'] = float(q)
except: except Exception:
print(f"WARNING: Error converting added quantity '{added}'") print(f"WARNING: Error converting added quantity '{added}'")
else: else:

View File

@ -25,7 +25,7 @@ def update_serials(apps, schema_editor):
if result and len(result.groups()) == 1: if result and len(result.groups()) == 1:
try: try:
serial = int(result.groups()[0]) serial = int(result.groups()[0])
except: except Exception:
serial = 0 serial = 0

View File

@ -1300,8 +1300,12 @@ class StockItem(MetadataMixin, MPTTModel):
item.save() item.save()
@transaction.atomic @transaction.atomic
def copyTestResultsFrom(self, other, filters={}): def copyTestResultsFrom(self, other, filters=None):
"""Copy all test results from another StockItem.""" """Copy all test results from another StockItem."""
# Set default - see B006
if filters is None:
filters = {}
for result in other.test_results.all().filter(**filters): for result in other.test_results.all().filter(**filters):
# Create a copy of the test result by nulling-out the pk # Create a copy of the test result by nulling-out the pk

View File

@ -90,7 +90,7 @@ class StockTest(InvenTreeTestCase):
build = Build.objects.create(reference='12345', part=part, title='A test build', quantity=1) build = Build.objects.create(reference='12345', part=part, title='A test build', quantity=1)
# Add some stock items which are "building" # Add some stock items which are "building"
for i in range(10): for _ in range(10):
StockItem.objects.create( StockItem.objects.create(
part=part, build=build, part=part, build=build,
quantity=10, is_building=True quantity=10, is_building=True
@ -439,7 +439,7 @@ class StockTest(InvenTreeTestCase):
serial=i, serial=i,
quantity=1, quantity=1,
) )
except: except Exception:
pass pass
item_next = item.get_next_serialized_item() item_next = item.get_next_serialized_item()
@ -616,7 +616,7 @@ class StockTest(InvenTreeTestCase):
# - C32 should move directly under A # - C32 should move directly under A
# Add some stock items to B3 # Add some stock items to B3
for i in range(10): for _ in range(10):
StockItem.objects.create( StockItem.objects.create(
part=Part.objects.get(pk=1), part=Part.objects.get(pk=1),
quantity=10, quantity=10,

View File

@ -538,14 +538,14 @@ class Owner(models.Model):
try: try:
owners.append(cls.objects.get(owner_id=user.pk, owner_type=user_type)) owners.append(cls.objects.get(owner_id=user.pk, owner_type=user_type))
except: # pragma: no cover except Exception: # pragma: no cover
pass pass
for group in user.groups.all(): for group in user.groups.all():
try: try:
owner = cls.objects.get(owner_id=group.pk, owner_type=group_type) owner = cls.objects.get(owner_id=group.pk, owner_type=group_type)
owners.append(owner) owners.append(owner)
except: # pragma: no cover except Exception: # pragma: no cover
pass pass
return owners return owners

View File

@ -24,7 +24,7 @@ print("=================================")
def check_invalid_tag(data): def check_invalid_tag(data):
"""Check for invalid tags."""
pattern = r"{%(\w+)" pattern = r"{%(\w+)"
err_count = 0 err_count = 0
@ -42,7 +42,7 @@ def check_invalid_tag(data):
def check_prohibited_tags(data): def check_prohibited_tags(data):
"""Check for prohibited tags."""
allowed_tags = [ allowed_tags = [
'if', 'if',
'elif', 'elif',

View File

@ -1,6 +1,6 @@
""" """Ensure that the release tag matches the InvenTree version number.
Ensure that the release tag matches the InvenTree version number:
Behaviour:
master / main branch: master / main branch:
- version number must end with 'dev' - version number must end with 'dev'

View File

@ -1,3 +1,5 @@
"""Gunicorn configuration for InvenTree."""
import logging import logging
import multiprocessing import multiprocessing
import os import os

View File

@ -19,6 +19,8 @@ ignore =
D202, D202,
# - D415 - First line should end with a period, question mark, or exclamation point # - D415 - First line should end with a period, question mark, or exclamation point
D415, D415,
# - B009 - Do not call getattr with a constant attribute value
B009
exclude = .git,__pycache__,*/migrations/*,*/lib/*,*/bin/*,*/media/*,*/static/*,InvenTree/plugins/* exclude = .git,__pycache__,*/migrations/*,*/lib/*,*/bin/*,*/media/*,*/static/*,InvenTree/plugins/*
per-file-ignores = per-file-ignores =
# Do not enforce docstring on __init__ # Do not enforce docstring on __init__

View File

@ -1,3 +1,5 @@
"""Tasks for automating certain actions and interacting with InvenTree from the CLI."""
import json import json
import os import os
import pathlib import pathlib
@ -8,7 +10,7 @@ from invoke import task
def apps(): def apps():
"""Returns a list of installed apps""" """Returns a list of installed apps."""
return [ return [
'build', 'build',
'common', 'common',
@ -43,12 +45,13 @@ def managePyPath():
return os.path.join(managePyDir(), 'manage.py') return os.path.join(managePyDir(), 'manage.py')
def manage(c, cmd, pty=False): def manage(c, cmd, pty: bool = False):
"""Runs a given command against django's "manage.py" script. """Runs a given command against django's "manage.py" script.
Args: Args:
c - Command line context c: Command line context.
cmd - django command to run cmd: Django command to run.
pty (bool, optional): Run an interactive session. Defaults to False.
""" """
c.run('cd "{path}" && python3 manage.py {cmd}'.format( c.run('cd "{path}" && python3 manage.py {cmd}'.format(
path=managePyDir(), path=managePyDir(),