2
0
mirror of https://github.com/inventree/InvenTree.git synced 2026-04-28 22:04:25 +00:00

Fix common spelling mistakes (#4956)

* add codespell

* first fixes

* doc fixes

* fix docstrings and comments

* functional changes

* docstrings again

* and docs again

* rename args

* add ignore

* use pre-commit for filtering instead

* ups

* fix typo in filter
This commit is contained in:
Matthias Mair
2023-06-03 16:04:52 +02:00
committed by GitHub
parent 5e2bfaa43a
commit 21ed4b2081
161 changed files with 344 additions and 334 deletions
+1 -1
View File
@@ -60,7 +60,7 @@ class NotFoundView(AjaxView):
permission_classes = [permissions.AllowAny]
def get(self, request, *args, **kwargs):
"""Proces an `not found` event on the API."""
"""Process an `not found` event on the API."""
data = {
'details': _('API endpoint not found'),
'url': request.build_absolute_uri(),
+1 -1
View File
@@ -210,7 +210,7 @@ v64 -> 2022-07-08 : https://github.com/inventree/InvenTree/pull/3310
- Allow BOM List API endpoint to be filtered by "on_order" parameter
v63 -> 2022-07-06 : https://github.com/inventree/InvenTree/pull/3301
- Allow BOM List API endpoint to be filtered by "available_stock" paramater
- Allow BOM List API endpoint to be filtered by "available_stock" parameter
v62 -> 2022-07-05 : https://github.com/inventree/InvenTree/pull/3296
- Allows search on BOM List API endpoint
+3 -3
View File
@@ -30,8 +30,8 @@ class InvenTreeConfig(AppConfig):
- Checking if migrations should be run
- Cleaning up tasks
- Starting regular tasks
- Updateing exchange rates
- Collecting notification mehods
- Updating exchange rates
- Collecting notification methods
- Adding users set in the current environment
"""
if canAppAccessDatabase() or settings.TESTING_ENV:
@@ -84,7 +84,7 @@ class InvenTreeConfig(AppConfig):
minutes=task.minutes,
)
# Put at least one task onto the backround worker stack,
# Put at least one task onto the background worker stack,
# which will be processed as soon as the worker comes online
InvenTree.tasks.offload_task(
InvenTree.tasks.heartbeat,
+2 -2
View File
@@ -1,6 +1,6 @@
"""Pull rendered copies of the templated.
Only used for testing the js files! - This file is omited from coverage.
Only used for testing the js files! - This file is omitted from coverage.
"""
import os # pragma: no cover
@@ -17,7 +17,7 @@ class RenderJavascriptFiles(InvenTreeTestCase): # pragma: no cover
"""
def download_file(self, filename, prefix):
"""Function to `download`(copy) a file to a temporay firectory."""
"""Function to `download`(copy) a file to a temporary firectory."""
url = os.path.join(prefix, filename)
response = self.client.get(url)
+1 -1
View File
@@ -200,7 +200,7 @@ def get_setting(env_var=None, config_key=None, default_value=None, typecast=None
def get_boolean_setting(env_var=None, config_key=None, default_value=False):
"""Helper function for retreiving a boolean configuration setting"""
"""Helper function for retrieving a boolean configuration setting"""
return is_true(get_setting(env_var, config_key, default_value))
+1 -1
View File
@@ -34,7 +34,7 @@ def log_error(path):
kind, info, data = sys.exc_info()
# Check if the eror is on the ignore list
# Check if the error is on the ignore list
if kind in settings.IGNORED_ERRORS:
return
+1 -1
View File
@@ -13,7 +13,7 @@ class InvenTreeSearchFilter(filters.SearchFilter):
"""Return a set of search fields for the request, adjusted based on request params.
The following query params are available to 'augment' the search (in decreasing order of priority)
- search_regex: If True, search is perfomed on 'regex' comparison
- search_regex: If True, search is performed on 'regex' comparison
"""
regex = InvenTree.helpers.str2bool(request.query_params.get('search_regex', False))
+1 -1
View File
@@ -91,7 +91,7 @@ def construct_format_regex(fmt_string: str) -> str:
# Add a named capture group for the format entry
if name:
# Check if integer values are requried
# Check if integer values are required
if format.endswith('d'):
chr = '\d'
else:
+3 -3
View File
@@ -212,7 +212,7 @@ class RegistratonMixin:
def is_open_for_signup(self, request, *args, **kwargs):
"""Check if signup is enabled in settings.
Configure the class variable `REGISTRATION_SETTING` to set which setting should be used, defualt: `LOGIN_ENABLE_REG`.
Configure the class variable `REGISTRATION_SETTING` to set which setting should be used, default: `LOGIN_ENABLE_REG`.
"""
if settings.EMAIL_HOST and (InvenTreeSetting.get_setting('LOGIN_ENABLE_REG') or InvenTreeSetting.get_setting('LOGIN_ENABLE_SSO_REG')):
return super().is_open_for_signup(request, *args, **kwargs)
@@ -253,7 +253,7 @@ class RegistratonMixin:
group = Group.objects.get(id=start_group)
user.groups.add(group)
except Group.DoesNotExist:
logger.error('The setting `SIGNUP_GROUP` contains an non existant group', start_group)
logger.error('The setting `SIGNUP_GROUP` contains an non existent group', start_group)
user.save()
return user
@@ -276,7 +276,7 @@ class CustomAccountAdapter(CustomUrlMixin, RegistratonMixin, OTPAdapter, Default
try:
result = super().send_mail(template_prefix, email, context)
except Exception:
# An exception ocurred while attempting to send email
# An exception occurred while attempting to send email
# Log it (for admin users) and return silently
log_error('account email')
result = False
+1 -1
View File
@@ -492,7 +492,7 @@ def extract_serial_numbers(input_string, expected_quantity: int, starting_value=
serial = serial.strip()
# Ignore blank / emtpy serials
# Ignore blank / empty serials
if len(serial) == 0:
return
+4 -4
View File
@@ -36,7 +36,7 @@ def construct_absolute_url(*arg, **kwargs):
This is useful when (for example) sending an email to a user with a link
to something in the InvenTree web framework.
A URL is constructed in the following order:
1. If setings.SITE_URL is set (e.g. in the Django settings), use that
1. If settings.SITE_URL is set (e.g. in the Django settings), use that
2. If the InvenTree setting INVENTREE_BASE_URL is set, use that
3. Otherwise, use the current request URL (if available)
"""
@@ -150,7 +150,7 @@ def download_image_from_url(remote_url, timeout=2.5):
raise ValueError(_("Image size is too large"))
# Download the file, ensuring we do not exceed the reported size
fo = io.BytesIO()
file = io.BytesIO()
dl_size = 0
chunk_size = 64 * 1024
@@ -161,7 +161,7 @@ def download_image_from_url(remote_url, timeout=2.5):
if dl_size > max_size:
raise ValueError(_("Image download exceeded maximum size"))
fo.write(chunk)
file.write(chunk)
if dl_size == 0:
raise ValueError(_("Remote server returned empty response"))
@@ -169,7 +169,7 @@ def download_image_from_url(remote_url, timeout=2.5):
# Now, attempt to convert the downloaded data to a valid image file
# img.verify() will throw an exception if the image is not valid
try:
img = Image.open(fo).convert()
img = Image.open(file).convert()
img.verify()
except Exception:
raise TypeError(_("Supplied URL is not a valid image file"))
@@ -23,8 +23,8 @@ def render_file(file_name, source, target, locales, ctx):
with open(target_file, 'w') as localised_file:
with lang_over(locale):
renderd = render_to_string(os.path.join(source, file_name), ctx)
localised_file.write(renderd)
rendered = render_to_string(os.path.join(source, file_name), ctx)
localised_file.write(rendered)
class Command(BaseCommand):
@@ -34,4 +34,4 @@ class Command(BaseCommand):
self.stdout.write("Database configuration is not usable")
if connected:
self.stdout.write("Database connection sucessful!")
self.stdout.write("Database connection successful!")
+2 -2
View File
@@ -28,7 +28,7 @@ class InvenTreeMetadata(SimpleMetadata):
"""
def determine_metadata(self, request, view):
"""Overwrite the metadata to adapt to hte request user."""
"""Overwrite the metadata to adapt to the request user."""
self.request = request
self.view = view
@@ -36,7 +36,7 @@ class InvenTreeMetadata(SimpleMetadata):
"""
Custom context information to pass through to the OPTIONS endpoint,
if the "context=True" is supplied to the OPTIONS requst
if the "context=True" is supplied to the OPTIONS request
Serializer class can supply context data by defining a get_context_data() method (no arguments)
"""
+2 -2
View File
@@ -158,10 +158,10 @@ class InvenTreeExceptionProcessor(ExceptionProcessor):
"""Custom exception processor that respects blocked errors."""
def process_exception(self, request, exception):
"""Check if kind is ignored before procesing."""
"""Check if kind is ignored before processing."""
kind, info, data = sys.exc_info()
# Check if the eror is on the ignore list
# Check if the error is on the ignore list
if kind in settings.IGNORED_ERRORS:
return
+1 -1
View File
@@ -125,7 +125,7 @@ class CreateAPI(CleanMixin, generics.CreateAPIView):
class RetrieveAPI(generics.RetrieveAPIView):
"""View for retreive API."""
"""View for retrieve API."""
pass
+3 -3
View File
@@ -125,7 +125,7 @@ class DataImportMixin(object):
Models which implement this mixin should provide information on the fields available for import
"""
# Define a map of fields avaialble for import
# Define a map of fields available for import
IMPORT_FIELDS = {}
@classmethod
@@ -712,12 +712,12 @@ class InvenTreeTree(MPTTModel):
available = contents.get_all_objects_for_this_type()
# List of child IDs
childs = self.getUniqueChildren()
children = self.getUniqueChildren()
acceptable = [None]
for a in available:
if a.id not in childs:
if a.id not in children:
acceptable.append(a)
return acceptable
+3 -3
View File
@@ -34,7 +34,7 @@ class InvenTreeMoneySerializer(MoneyField):
"""
def __init__(self, *args, **kwargs):
"""Overrite default values."""
"""Override default values."""
kwargs["max_digits"] = kwargs.get("max_digits", 19)
self.decimal_places = kwargs["decimal_places"] = kwargs.get("decimal_places", 6)
kwargs["required"] = kwargs.get("required", False)
@@ -269,13 +269,13 @@ class InvenTreeTaggitSerializer(TaggitSerializer):
"""Updated from https://github.com/glemmaPaul/django-taggit-serializer."""
def update(self, instance, validated_data):
"""Overriden update method to readd the tagmanager."""
"""Overridden update method to re-add the tagmanager."""
to_be_tagged, validated_data = self._pop_tags(validated_data)
tag_object = super().update(instance, validated_data)
for key in to_be_tagged.keys():
# readd the tagmanager
# re-add the tagmanager
new_tagobject = tag_object.__class__.objects.get(id=tag_object.id)
setattr(tag_object, key, getattr(new_tagobject, key))
+4 -4
View File
@@ -480,7 +480,7 @@ if "postgres" in db_engine: # pragma: no cover
if "connect_timeout" not in db_options:
# The DB server is in the same data center, it should not take very
# long to connect to the database server
# # seconds, 2 is minium allowed by libpq
# # seconds, 2 is minimum allowed by libpq
db_options["connect_timeout"] = int(
get_setting('INVENTREE_DB_TIMEOUT', 'database.timeout', 2)
)
@@ -576,7 +576,7 @@ REMOTE_LOGIN_HEADER = get_setting('INVENTREE_REMOTE_LOGIN_HEADER', 'remote_login
# sentry.io integration for error reporting
SENTRY_ENABLED = get_boolean_setting('INVENTREE_SENTRY_ENABLED', 'sentry_enabled', False)
# Default Sentry DSN (can be overriden if user wants custom sentry integration)
# Default Sentry DSN (can be overridden if user wants custom sentry integration)
SENTRY_DSN = get_setting('INVENTREE_SENTRY_DSN', 'sentry_dsn', default_sentry_dsn())
SENTRY_SAMPLE_RATE = float(get_setting('INVENTREE_SENTRY_SAMPLE_RATE', 'sentry_sample_rate', 0.1))
@@ -598,7 +598,7 @@ cache_port = get_setting('INVENTREE_CACHE_PORT', 'cache.port', '6379', typecast=
if cache_host: # pragma: no cover
# We are going to rely upon a possibly non-localhost for our cache,
# so don't wait too long for the cache as nothing in the cache should be
# irreplacable.
# irreplaceable.
_cache_options = {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
"SOCKET_CONNECT_TIMEOUT": int(os.getenv("CACHE_CONNECT_TIMEOUT", "2")),
@@ -910,7 +910,7 @@ PLUGINS_ENABLED = get_boolean_setting('INVENTREE_PLUGINS_ENABLED', 'plugins_enab
PLUGIN_FILE = config.get_plugin_file()
# Plugin test settings
PLUGIN_TESTING = get_setting('INVENTREE_PLUGIN_TESTING', 'PLUGIN_TESTING', TESTING) # Are plugins beeing tested?
PLUGIN_TESTING = get_setting('INVENTREE_PLUGIN_TESTING', 'PLUGIN_TESTING', TESTING) # Are plugins being tested?
PLUGIN_TESTING_SETUP = get_setting('INVENTREE_PLUGIN_TESTING_SETUP', 'PLUGIN_TESTING_SETUP', False) # Load plugins from setup hooks in testing?
PLUGIN_TESTING_EVENTS = False # Flag if events are tested right now
PLUGIN_RETRY = get_setting('INVENTREE_PLUGIN_RETRY', 'PLUGIN_RETRY', 5) # How often should plugin loading be tried?
+2 -2
View File
@@ -249,7 +249,7 @@ class ScheduledTask:
class TaskRegister:
"""Registery for periodicall tasks."""
"""Registry for periodicall tasks."""
task_list: List[ScheduledTask] = []
def register(self, task, schedule, minutes: int = None):
@@ -562,7 +562,7 @@ def run_backup():
def check_for_migrations(worker: bool = True):
"""Checks if migrations are needed.
If the setting auto_update is enabled we will start updateing.
If the setting auto_update is enabled we will start updating.
"""
# Test if auto-updates are enabled
if not get_setting('INVENTREE_AUTO_UPDATE', 'auto_update'):
+2 -2
View File
@@ -28,13 +28,13 @@ class MiddlewareTests(InvenTreeTestCase):
self.client.logout()
# check that static files go through
# TODO @matmair reenable this check
# TODO @matmair re-enable this check
# self.check_path('/static/css/inventree.css', 302)
# check that account things go through
self.check_path(reverse('account_login'))
# logout goes diretly to login
# logout goes directly to login
self.check_path(reverse('account_logout'))
# check that frontend code is redirected to login
+2 -2
View File
@@ -70,11 +70,11 @@ class InvenTreeTaskTests(TestCase):
with self.assertWarnsMessage(UserWarning, "WARNING: 'InvenTree' not started - Malformed function path"):
InvenTree.tasks.offload_task('InvenTree')
# Non exsistent app
# Non existent app
with self.assertWarnsMessage(UserWarning, "WARNING: 'InvenTreeABC.test_tasks.doesnotmatter' not started - No module named 'InvenTreeABC.test_tasks'"):
InvenTree.tasks.offload_task('InvenTreeABC.test_tasks.doesnotmatter')
# Non exsistent function
# Non existent function
with self.assertWarnsMessage(UserWarning, "WARNING: 'InvenTree.test_tasks.doesnotexsist' not started - No function named 'doesnotexsist'"):
InvenTree.tasks.offload_task('InvenTree.test_tasks.doesnotexsist')
+3 -3
View File
@@ -288,7 +288,7 @@ class TestHelpers(TestCase):
def dl_helper(url, expected_error, timeout=2.5, retries=3):
"""Helper function for unit testing downloads.
As the httpstat.us service occassionaly refuses a connection,
As the httpstat.us service occasionally refuses a connection,
we will simply try multiple times
"""
@@ -542,7 +542,7 @@ class TestSerialNumberExtraction(TestCase):
self.assertEqual(sn, ['5', '6', '7', '8'])
def test_failures(self):
"""Test wron serial numbers."""
"""Test wrong serial numbers."""
e = helpers.extract_serial_numbers
# Test duplicates
@@ -1033,7 +1033,7 @@ class SanitizerTest(TestCase):
"""Simple tests for sanitizer functions."""
def test_svg_sanitizer(self):
"""Test that SVGs are sanitized acordingly."""
"""Test that SVGs are sanitized accordingly."""
valid_string = """<svg xmlns="http://www.w3.org/2000/svg" version="1.1" id="svg2" height="400" width="400">{0}
<path id="path1" d="m -151.78571,359.62883 v 112.76373 l 97.068507,-56.04253 V 303.14815 Z" style="fill:#ddbc91;"></path>
</svg>"""
+12 -12
View File
@@ -354,27 +354,27 @@ class InvenTreeAPITestCase(ExchangeRateMixin, UserMixin, APITestCase):
if decode:
# Decode data and return as StringIO file object
fo = io.StringIO()
fo.name = fo
fo.write(response.getvalue().decode('UTF-8'))
file = io.StringIO()
file.name = file
file.write(response.getvalue().decode('UTF-8'))
else:
# Return a a BytesIO file object
fo = io.BytesIO()
fo.name = fn
fo.write(response.getvalue())
file = io.BytesIO()
file.name = fn
file.write(response.getvalue())
fo.seek(0)
file.seek(0)
return fo
return file
def process_csv(self, fo, delimiter=',', required_cols=None, excluded_cols=None, required_rows=None):
def process_csv(self, file_object, delimiter=',', required_cols=None, excluded_cols=None, required_rows=None):
"""Helper function to process and validate a downloaded csv file."""
# Check that the correct object type has been passed
self.assertTrue(isinstance(fo, io.StringIO))
self.assertTrue(isinstance(file_object, io.StringIO))
fo.seek(0)
file_object.seek(0)
reader = csv.reader(fo, delimiter=delimiter)
reader = csv.reader(file_object, delimiter=delimiter)
headers = []
rows = []
+2 -2
View File
@@ -62,7 +62,7 @@ apipatterns = [
# Plugin endpoints
path('', include(plugin_api_urls)),
# Common endpoints enpoint
# Common endpoints endpoint
path('', include(common_api_urls)),
# OpenAPI Schema
@@ -98,7 +98,7 @@ dynamic_javascript_urls = [
re_path(r'^settings.js', DynamicJsView.as_view(template_name='js/dynamic/settings.js'), name='settings.js'),
]
# These javascript files are pased through the Django translation layer
# These javascript files are passed through the Django translation layer
translated_javascript_urls = [
re_path(r'^api.js', DynamicJsView.as_view(template_name='js/translated/api.js'), name='api.js'),
re_path(r'^attachment.js', DynamicJsView.as_view(template_name='js/translated/attachment.js'), name='attachment.js'),
+2 -2
View File
@@ -357,7 +357,7 @@ class AjaxUpdateView(AjaxMixin, UpdateView):
- Updates model with POST field data
- Performs form and object validation
- If errors exist, re-render the form
- Otherwise, return sucess status
- Otherwise, return success status
"""
self.request = request
@@ -386,7 +386,7 @@ class AjaxUpdateView(AjaxMixin, UpdateView):
if valid:
# Save the updated objec to the database
# Save the updated object to the database
self.save(self.object, form)
self.object = self.get_object()
+2 -2
View File
@@ -131,7 +131,7 @@ class Build(MPTTModel, InvenTree.models.InvenTreeBarcodeMixin, InvenTree.models.
# Order was completed within the specified range
completed = Q(status=BuildStatus.COMPLETE) & Q(completion_date__gte=min_date) & Q(completion_date__lte=max_date)
# Order target date falls witin specified range
# Order target date falls within specified range
pending = Q(status__in=BuildStatus.ACTIVE_CODES) & ~Q(target_date=None) & Q(target_date__gte=min_date) & Q(target_date__lte=max_date)
# TODO - Construct a queryset for "overdue" orders
@@ -310,7 +310,7 @@ class Build(MPTTModel, InvenTree.models.InvenTreeBarcodeMixin, InvenTree.models.
"""Return the number of sub builds under this one.
Args:
cascade: If True (defualt), include cascading builds under sub builds
cascade: If True (default), include cascading builds under sub builds
"""
return self.sub_builds(cascade=cascade).count()
+1 -1
View File
@@ -91,7 +91,7 @@ class BuildSerializer(InvenTreeModelSerializer):
def annotate_queryset(queryset):
"""Add custom annotations to the BuildSerializer queryset, performing database queries as efficiently as possible.
The following annoted fields are added:
The following annotated fields are added:
- overdue: True if the build is outstanding *and* the completion date has past
"""
+2 -2
View File
@@ -541,10 +541,10 @@ class BuildTest(BuildAPITest):
{
'export': 'csv',
}
) as fo:
) as file:
data = self.process_csv(
fo,
file,
required_cols=required_cols,
excluded_cols=excluded_cols,
required_rows=Build.objects.count()
+1 -1
View File
@@ -679,7 +679,7 @@ class AutoAllocationTests(BuildTestBase):
self.assertEqual(self.build.unallocated_quantity(self.bom_item_1), 0)
self.assertEqual(self.build.unallocated_quantity(self.bom_item_2), 5)
# This time, allow substitue parts to be used!
# This time, allow substitute parts to be used!
self.build.auto_allocate_stock(
interchangeable=True,
substitutes=True,
+2 -2
View File
@@ -45,7 +45,7 @@ class WebhookView(CsrfExemptMixin, APIView):
run_async = False
def post(self, request, endpoint, *args, **kwargs):
"""Process incomming webhook."""
"""Process incoming webhook."""
# get webhook definition
self._get_webhook(endpoint, request, *args, **kwargs)
@@ -164,7 +164,7 @@ class CurrencyRefreshView(APIView):
class SettingsList(ListAPI):
"""Generic ListView for settings.
This is inheritted by all list views for settings.
This is inherited by all list views for settings.
"""
filter_backends = SEARCH_ORDER_FILTER
+1 -1
View File
@@ -84,7 +84,7 @@ class FileManager:
self.HEADERS = self.REQUIRED_HEADERS + self.ITEM_MATCH_HEADERS + self.OPTIONAL_MATCH_HEADERS + self.OPTIONAL_HEADERS
def setup(self):
"""Setup headers should be overriden in usage to set the Different Headers."""
"""Setup headers should be overridden in usage to set the Different Headers."""
if not self.name:
return
+3 -3
View File
@@ -46,7 +46,7 @@ class MatchFieldForm(forms.Form):
"""Step 2 of FileManagementFormView."""
def __init__(self, *args, **kwargs):
"""Setup filemanager and check columsn."""
"""Setup filemanager and check columns."""
# Get FileManager
file_manager = None
if 'file_manager' in kwargs:
@@ -106,7 +106,7 @@ class MatchItemForm(forms.Form):
# Set field name
field_name = col_guess.lower() + '-' + str(row['index'])
# check if field def was overriden
# check if field def was overridden
overriden_field = self.get_special_field(col_guess, row, file_manager)
if overriden_field:
self.fields[field_name] = overriden_field
@@ -174,5 +174,5 @@ class MatchItemForm(forms.Form):
)
def get_special_field(self, col_guess, row, file_manager):
"""Function to be overriden in inherited forms to add specific form settings."""
"""Function to be overridden in inherited forms to add specific form settings."""
return None
+2 -2
View File
@@ -2395,7 +2395,7 @@ class WebhookEndpoint(models.Model):
self.verify = self.VERIFICATION_METHOD
def process_webhook(self):
"""Process the webhook incomming.
"""Process the webhook incoming.
This does not deal with the data itself - that happens in process_payload.
Do not touch or pickle data here - it was not verified to be safe.
@@ -2532,7 +2532,7 @@ class WebhookMessage(models.Model):
class NotificationEntry(MetaMixin):
"""A NotificationEntry records the last time a particular notifaction was sent out.
"""A NotificationEntry records the last time a particular notification was sent out.
It is recorded to ensure that notifications are not sent out "too often" to users.
+7 -7
View File
@@ -62,11 +62,11 @@ class NotificationMethod:
def check_context(self, context):
"""Check that all values defined in the methods CONTEXT were provided in the current context."""
def check(ref, obj):
# the obj is not accesible so we are on the end
# the obj is not accessible so we are on the end
if not isinstance(obj, (list, dict, tuple, )):
return ref
# check if the ref exsists
# check if the ref exists
if isinstance(ref, str):
if not obj.get(ref):
return ref
@@ -150,16 +150,16 @@ class SingleNotificationMethod(NotificationMethod):
"""NotificationMethod that sends notifications one by one."""
def send(self, target):
"""This function must be overriden."""
raise NotImplementedError('The `send` method must be overriden!')
"""This function must be overridden."""
raise NotImplementedError('The `send` method must be overridden!')
class BulkNotificationMethod(NotificationMethod):
"""NotificationMethod that sends all notifications in bulk."""
def send_bulk(self):
"""This function must be overriden."""
raise NotImplementedError('The `send` method must be overriden!')
"""This function must be overridden."""
raise NotImplementedError('The `send` method must be overridden!')
# endregion
@@ -268,7 +268,7 @@ class NotificationBody:
message (str): Notification message as text. Should not be longer than 120 chars.
template (str): Reference to the html template for the notification.
The strings support f-string sytle fomratting with context variables parsed at runtime.
The strings support f-string style formatting with context variables parsed at runtime.
Context variables:
instance: Text representing the instance
+1 -1
View File
@@ -57,7 +57,7 @@ def update_news_feed():
# Iterate over entries
for entry in d.entries:
# Check if id already exsists
# Check if id already exists
if entry.id in id_list:
continue
+2 -2
View File
@@ -47,7 +47,7 @@ class BaseNotificationTests(BaseNotificationIntegrationTest):
with self.assertRaises(NotImplementedError):
NoNameNotificationMethod('', '', '', '', )
# a not existant context check
# a not existent context check
with self.assertRaises(NotImplementedError):
WrongContextNotificationMethod('', '', '', '', )
@@ -149,7 +149,7 @@ class NotificationUserSettingTests(BaseNotificationIntegrationTest):
def send_bulk(self):
return True
# run thorugh notification
# run through notification
self._notification_run(SampleImplementation)
# make sure the array fits
array = storage.get_usersettings(self.user)
+3 -3
View File
@@ -272,7 +272,7 @@ class GlobalSettingsApiTest(InvenTreeAPITestCase):
self.assertEqual(len(response.data), len(InvenTreeSetting.SETTINGS.keys()))
def test_company_name(self):
"""Test a settings object lifecyle e2e."""
"""Test a settings object lifecycle e2e."""
setting = InvenTreeSetting.get_setting_object('INVENTREE_COMPANY_NAME')
# Check default value
@@ -781,7 +781,7 @@ class NotificationTest(InvenTreeAPITestCase):
for _ii in range(10):
Error.objects.create()
# Check that messsages have been created
# Check that messages have been created
messages = NotificationMessage.objects.all()
# As there are three staff users (including the 'test' user) we expect 30 notifications
@@ -860,7 +860,7 @@ class CommonTest(InvenTreeAPITestCase):
self.user.is_superuser = True
self.user.save()
# Successfull checks
# Successful checks
data = [
self.get(reverse('api-config-list'), expected_code=200).data[0], # list endpoint
self.get(reverse('api-config-detail', kwargs={'key': 'INVENTREE_DEBUG'}), expected_code=200).data, # detail endpoint
+1 -1
View File
@@ -363,7 +363,7 @@ class ManufacturerPartAttachment(InvenTreeAttachment):
class ManufacturerPartParameter(models.Model):
"""A ManufacturerPartParameter represents a key:value parameter for a MnaufacturerPart.
This is used to represent parmeters / properties for a particular manufacturer part.
This is used to represent parameters / properties for a particular manufacturer part.
Each parameter is a simple string (text) value.
"""
+1 -1
View File
@@ -88,7 +88,7 @@ class SupplierPartPackUnitsTests(InvenTreeTestCase):
}
# All these values are invalid for a part with dimension 'm'
# Either the values are invalid, or the units are incomaptible
# Either the values are invalid, or the units are incompatible
fail_tests = [
'-1',
'-1m',
+2 -2
View File
@@ -125,7 +125,7 @@ class LabelConfig(AppConfig):
logger.info(f"Creating required directory: '{dst_dir}'")
dst_dir.mkdir(parents=True, exist_ok=True)
# Create lables
# Create labels
for label in labels:
self.create_template_label(model, src_dir, ref_name, label)
@@ -156,7 +156,7 @@ class LabelConfig(AppConfig):
if to_copy:
logger.info(f"Copying label template '{dst_file}'")
# Ensure destionation dir exists
# Ensure destination dir exists
dst_file.parent.mkdir(parents=True, exist_ok=True)
# Copy file
+2 -2
View File
@@ -315,7 +315,7 @@ class PurchaseOrder(TotalPriceMixin, Order):
- Specified as min_date, max_date
- Both must be specified for filter to be applied
- Determine which "interesting" orders exist bewteen these dates
- Determine which "interesting" orders exist between these dates
To be "interesting":
- A "received" order where the received date lies within the date range
@@ -1225,7 +1225,7 @@ class PurchaseOrderLineItem(OrderLineItem):
def get_destination(self):
"""Show where the line item is or should be placed.
NOTE: If a line item gets split when recieved, only an arbitrary
NOTE: If a line item gets split when received, only an arbitrary
stock items location will be reported as the location for the
entire line.
"""
+10 -10
View File
@@ -697,10 +697,10 @@ class PurchaseOrderDownloadTest(OrderTest):
},
expected_code=200,
expected_fn='InvenTree_PurchaseOrders.csv',
) as fo:
) as file:
data = self.process_csv(
fo,
file,
required_cols=self.required_cols,
excluded_cols=self.excluded_cols,
required_rows=models.PurchaseOrder.objects.count()
@@ -722,9 +722,9 @@ class PurchaseOrderDownloadTest(OrderTest):
decode=False,
expected_code=200,
expected_fn='InvenTree_PurchaseOrderItems.xlsx',
) as fo:
) as file:
self.assertTrue(isinstance(fo, io.BytesIO))
self.assertTrue(isinstance(file, io.BytesIO))
class PurchaseOrderReceiveTest(OrderTest):
@@ -1558,8 +1558,8 @@ class SalesOrderDownloadTest(OrderTest):
expected_code=200,
expected_fn='InvenTree_SalesOrders.xls',
decode=False,
) as fo:
self.assertTrue(isinstance(fo, io.BytesIO))
) as file:
self.assertTrue(isinstance(file, io.BytesIO))
def test_download_csv(self):
"""Tesst that the list of sales orders can be downloaded as a .csv file"""
@@ -1589,10 +1589,10 @@ class SalesOrderDownloadTest(OrderTest):
expected_code=200,
expected_fn='InvenTree_SalesOrders.csv',
decode=True
) as fo:
) as file:
data = self.process_csv(
fo,
file,
required_cols=required_cols,
excluded_cols=excluded_cols,
required_rows=models.SalesOrder.objects.count()
@@ -1615,10 +1615,10 @@ class SalesOrderDownloadTest(OrderTest):
expected_code=200,
expected_fn='InvenTree_SalesOrders.tsv',
decode=True,
) as fo:
) as file:
self.process_csv(
fo,
file,
required_cols=required_cols,
excluded_cols=excluded_cols,
required_rows=models.SalesOrder.objects.filter(status__in=SalesOrderStatus.OPEN).count(),
+11 -11
View File
@@ -268,7 +268,7 @@ class CategoryParameterList(ListCreateAPI):
class CategoryParameterDetail(RetrieveUpdateDestroyAPI):
"""Detail endpoint fro the PartCategoryParameterTemplate model"""
"""Detail endpoint for the PartCategoryParameterTemplate model"""
queryset = PartCategoryParameterTemplate.objects.all()
serializer_class = part_serializers.CategoryParameterTemplateSerializer
@@ -550,7 +550,7 @@ class PartScheduling(RetrieveAPI):
This assumes that the user is responsible for correctly allocating parts.
However, it has the added benefit of side-stepping the various BOM substition options,
However, it has the added benefit of side-stepping the various BOM substitution options,
and just looking at what stock items the user has actually allocated against the Build.
"""
@@ -565,10 +565,10 @@ class PartScheduling(RetrieveAPI):
if bom_item.inherited:
# An "inherited" BOM item filters down to variant parts also
childs = bom_item.part.get_descendants(include_self=True)
children = bom_item.part.get_descendants(include_self=True)
builds = Build.objects.filter(
status__in=BuildStatus.ACTIVE_CODES,
part__in=childs,
part__in=children,
)
else:
builds = Build.objects.filter(
@@ -591,7 +591,7 @@ class PartScheduling(RetrieveAPI):
# Non-trackable parts are allocated against the build itself
required_quantity = build.quantity * bom_item.quantity
# Grab all allocations against the spefied BomItem
# Grab all allocations against the specified BomItem
allocations = BuildItem.objects.filter(
bom_item=bom_item,
build=build,
@@ -1032,7 +1032,7 @@ class PartList(PartMixin, APIDownloadMixin, ListCreateAPI):
return DownloadFile(filedata, filename)
def list(self, request, *args, **kwargs):
"""Overide the 'list' method, as the PartCategory objects are very expensive to serialize!
"""Override the 'list' method, as the PartCategory objects are very expensive to serialize!
So we will serialize them first, and keep them in memory, so that they do not have to be serialized multiple times...
"""
@@ -1049,7 +1049,7 @@ class PartList(PartMixin, APIDownloadMixin, ListCreateAPI):
"""
Determine the response type based on the request.
a) For HTTP requests (e.g. via the browseable API) return a DRF response
a) For HTTP requests (e.g. via the browsable API) return a DRF response
b) For AJAX requests, simply return a JSON rendered response.
"""
if page is not None:
@@ -1213,7 +1213,7 @@ class PartList(PartMixin, APIDownloadMixin, ListCreateAPI):
def filter_parameteric_data(self, queryset):
"""Filter queryset against part parameters.
Here we can perfom a number of different functions:
Here we can perform a number of different functions:
Ordering Based on Parameter Value:
- Used if the 'ordering' query param points to a parameter
@@ -1492,7 +1492,7 @@ class PartParameterDetail(RetrieveUpdateDestroyAPI):
class PartStocktakeFilter(rest_filters.FilterSet):
"""Custom fitler for the PartStocktakeList endpoint"""
"""Custom filter for the PartStocktakeList endpoint"""
class Meta:
"""Metaclass options"""
@@ -1702,7 +1702,7 @@ class BomList(BomMixin, ListCreateDestroyAPIView):
"""
Determine the response type based on the request.
a) For HTTP requests (e.g. via the browseable API) return a DRF response
a) For HTTP requests (e.g. via the browsable API) return a DRF response
b) For AJAX requests, simply return a JSON rendered response.
"""
if page is not None:
@@ -1748,7 +1748,7 @@ class BomList(BomMixin, ListCreateDestroyAPIView):
There are multiple ways that an assembly can "use" a sub-part:
A) Directly specifying the sub_part in a BomItem field
B) Specifing a "template" part with inherited=True
B) Specifying a "template" part with inherited=True
C) Allowing variant parts to be substituted
D) Allowing direct substitute parts to be specified
+4 -4
View File
@@ -53,10 +53,10 @@ def ExportBom(part: Part, fmt='csv', cascade: bool = False, max_levels: int = No
max_levels (int, optional): Levels of items that should be included. None for np sublevels. Defaults to None.
kwargs:
parameter_data (bool, optional): Additonal data that should be added. Defaults to False.
stock_data (bool, optional): Additonal data that should be added. Defaults to False.
supplier_data (bool, optional): Additonal data that should be added. Defaults to False.
manufacturer_data (bool, optional): Additonal data that should be added. Defaults to False.
parameter_data (bool, optional): Additional data that should be added. Defaults to False.
stock_data (bool, optional): Additional data that should be added. Defaults to False.
supplier_data (bool, optional): Additional data that should be added. Defaults to False.
manufacturer_data (bool, optional): Additional data that should be added. Defaults to False.
pricing_data (bool, optional): Include pricing data in exported BOM. Defaults to False
substitute_part_data (bool, optional): Include substitute part numbers in exported BOM. Defaults to False
+3 -3
View File
@@ -78,7 +78,7 @@ def annotate_total_stock(reference: str = ''):
- This function calculates the 'total stock' for a given part
- Finds all stock items associated with each part (using the provided filter)
- Aggregates the 'quantity' of each relevent stock item
- Aggregates the 'quantity' of each relevant stock item
Args:
reference: The relationship reference of the part from the current model e.g. 'part'
@@ -103,7 +103,7 @@ def annotate_build_order_allocations(reference: str = ''):
- This function calculates the total part quantity allocated to open build orders
- Finds all build order allocations for each part (using the provided filter)
- Aggregates the 'allocated quantity' for each relevent build order allocation item
- Aggregates the 'allocated quantity' for each relevant build order allocation item
Args:
reference: The relationship reference of the part from the current model
@@ -128,7 +128,7 @@ def annotate_sales_order_allocations(reference: str = ''):
- This function calculates the total part quantity allocated to open sales orders"
- Finds all sales order allocations for each part (using the provided filter)
- Aggregates the 'allocated quantity' for each relevent sales order allocation item
- Aggregates the 'allocated quantity' for each relevant sales order allocation item
Args:
reference: The relationship reference of the part from the current model
+1 -1
View File
@@ -76,7 +76,7 @@
pk: 7
fields:
name: Mechanical
description: Mechanical componenets
description: Mechanical components
default_location: null
level: 0
tree_id: 2
+1 -1
View File
@@ -54,7 +54,7 @@ class Migration(migrations.Migration):
('description', models.CharField(help_text='Part description', max_length=250)),
('keywords', models.CharField(blank=True, help_text='Part keywords to improve visibility in search results', max_length=250)),
('IPN', models.CharField(blank=True, help_text='Internal Part Number', max_length=100)),
('URL', models.URLField(blank=True, help_text='Link to extenal URL')),
('URL', models.URLField(blank=True, help_text='Link to external URL')),
('image', models.ImageField(blank=True, max_length=255, null=True, upload_to=part.models.rename_part_image)),
('minimum_stock', models.PositiveIntegerField(default=0, help_text='Minimum allowed stock level', validators=[django.core.validators.MinValueValidator(0)])),
('units', models.CharField(blank=True, default='pcs', help_text='Stock keeping units for this part', max_length=20)),
@@ -14,6 +14,6 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='part',
name='URL',
field=InvenTree.fields.InvenTreeURLField(blank=True, help_text='Link to extenal URL'),
field=InvenTree.fields.InvenTreeURLField(blank=True, help_text='Link to external URL'),
),
]
@@ -25,7 +25,7 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='part',
name='link',
field=InvenTree.fields.InvenTreeURLField(blank=True, help_text='Link to extenal URL', null=True),
field=InvenTree.fields.InvenTreeURLField(blank=True, help_text='Link to external URL', null=True),
),
migrations.AlterField(
model_name='part',
+3 -3
View File
@@ -1543,7 +1543,7 @@ class Part(InvenTreeBarcodeMixin, InvenTreeNotesMixin, MetadataMixin, MPTTModel)
A) This part may be directly specified in a BomItem instance
B) This part may be a *variant* of a part which is directly specified in a BomItem instance
C) This part may be a *substitute* for a part which is directly specifed in a BomItem instance
C) This part may be a *substitute* for a part which is directly specified in a BomItem instance
So we construct a query for each case, and combine them...
"""
@@ -2173,7 +2173,7 @@ class Part(InvenTreeBarcodeMixin, InvenTreeNotesMixin, MetadataMixin, MPTTModel)
return self.parameters.order_by('template__name')
def parameters_map(self):
"""Return a map (dict) of parameter values assocaited with this Part instance, of the form.
"""Return a map (dict) of parameter values associated with this Part instance, of the form.
Example:
{
@@ -3198,7 +3198,7 @@ class PartTestTemplate(MetadataMixin, models.Model):
"""A PartTestTemplate defines a 'template' for a test which is required to be run against a StockItem (an instance of the Part).
The test template applies "recursively" to part variants, allowing tests to be
defined in a heirarchy.
defined in a hierarchy.
Test names are simply strings, rather than enforcing any sort of structure or pattern.
It is up to the user to determine what tests are defined (and how they are run).
+1 -1
View File
@@ -189,7 +189,7 @@ def perform_stocktake(target: part.models.Part, user: User, note: str = '', comm
total_cost_max += pp
has_pricing = True
except MissingRate:
logger.warning(f"MissingRate exception occured converting {entry.purchase_price} to {base_currency}")
logger.warning(f"MissingRate exception occurred converting {entry.purchase_price} to {base_currency}")
if not has_pricing:
# Fall back to the part pricing data
@@ -295,7 +295,7 @@ def inventree_github_url(*args, **kwargs):
@register.simple_tag()
def inventree_docs_url(*args, **kwargs):
"""Return URL for InvenTree documenation site."""
"""Return URL for InvenTree documentation site."""
tag = version.inventreeDocsVersion()
return f"https://docs.inventree.org/en/{tag}"
@@ -605,7 +605,7 @@ else: # pragma: no cover
bits = token.split_contents()
loc_name = settings.STATICFILES_I18_PREFIX
# change path to called ressource
# change path to called resource
bits[1] = f"'{loc_name}/{{lng}}.{bits[1][1:-1]}'"
token.contents = ' '.join(bits)
+2 -2
View File
@@ -1078,10 +1078,10 @@ class PartAPITest(PartAPITestBase):
'export': 'csv',
},
expected_fn='InvenTree_Parts.csv',
) as fo:
) as file:
data = self.process_csv(
fo,
file,
excluded_cols=excluded_cols,
required_cols=required_cols,
required_rows=Part.objects.count(),
+1 -1
View File
@@ -141,7 +141,7 @@ class BomItemTest(TestCase):
def test_substitutes(self):
"""Tests for BOM item substitutes."""
# We will make some subtitute parts for the "orphan" part
# We will make some substitute parts for the "orphan" part
bom_item = BomItem.objects.get(
part=self.bob,
sub_part=self.orphan
+6 -6
View File
@@ -49,14 +49,14 @@ class CategoryTest(TestCase):
self.assertEqual(len(self.electronics.children.all()), 3)
self.assertEqual(len(self.mechanical.children.all()), 1)
def test_unique_childs(self):
def test_unique_children(self):
"""Test the 'unique_children' functionality."""
childs = [item.pk for item in self.electronics.getUniqueChildren()]
children = [item.pk for item in self.electronics.getUniqueChildren()]
self.assertIn(self.transceivers.id, childs)
self.assertIn(self.ic.id, childs)
self.assertIn(self.transceivers.id, children)
self.assertIn(self.ic.id, children)
self.assertNotIn(self.fasteners.id, childs)
self.assertNotIn(self.fasteners.id, children)
def test_unique_parents(self):
"""Test the 'unique_parents' functionality."""
@@ -168,7 +168,7 @@ class CategoryTest(TestCase):
parts_parameters = self.fasteners.get_parts_parameters(prefetch=fasteners)
part_infos = ['pk', 'name', 'description']
for part_parameter in parts_parameters:
# Remove part informations
# Remove part information
for item in part_infos:
part_parameter.pop(item)
self.assertEqual(len(part_parameter), 1)
+1 -1
View File
@@ -55,7 +55,7 @@ class TestBomItemMigrations(MigratorTestCase):
migrate_to = ('part', unit_test.getNewestMigrationFile('part'))
def prepare(self):
"""Create intial dataset"""
"""Create initial dataset"""
Part = self.old_state.apps.get_model('part', 'part')
BomItem = self.old_state.apps.get_model('part', 'bomitem')
+1 -1
View File
@@ -515,7 +515,7 @@ class PartSettingsTest(InvenTreeTestCase):
Part.objects.create(name='zyx', description='A part', IPN='UNIQUE')
# However, *blank* / empty IPN values should be allowed, even if duplicates are not
# Note that leading / trailling whitespace characters are trimmed, too
# Note that leading / trailing whitespace characters are trimmed, too
Part.objects.create(name='abc', revision='1', description='A part', IPN=None)
Part.objects.create(name='abc', revision='2', description='A part', IPN='')
Part.objects.create(name='abc', revision='3', description='A part', IPN=None)
+2 -2
View File
@@ -233,7 +233,7 @@ class PartImport(FileManagementFormView):
image=part_data.get('image', None),
)
# check if theres a category assigned, if not skip this part or else bad things happen
# check if there's a category assigned, if not skip this part or else bad things happen
if not optional_matches['Category']:
import_error.append(_("Can't import part {name} because there is no category assigned").format(name=new_part.name))
continue
@@ -260,7 +260,7 @@ class PartImport(FileManagementFormView):
messages.success(self.request, alert)
if import_error:
error_text = '\n'.join([f'<li><strong>{import_error.count(a)}</strong>: {a}</li>' for a in set(import_error)])
messages.error(self.request, f"<strong>{_('Some errors occured:')}</strong><br><ul>{error_text}</ul>")
messages.error(self.request, f"<strong>{_('Some errors occurred:')}</strong><br><ul>{error_text}</ul>")
return HttpResponseRedirect(reverse('part-index'))
+1 -1
View File
@@ -1,6 +1,6 @@
"""Apps file for plugin app.
This initializes the plugin mechanisms and handles reloading throught the lifecycle.
This initializes the plugin mechanisms and handles reloading throughout the lifecycle.
The main code for plugin special sauce is in the plugin registry in `InvenTree/plugin/registry.py`.
"""
+1 -1
View File
@@ -59,7 +59,7 @@ class ActionMixinTests(TestCase):
"info": None,
})
# overriden functions
# overridden functions
self.assertEqual(self.action_plugin.perform_action(), self.ACTION_RETURN + 'action')
self.assertEqual(self.action_plugin.get_result(), self.ACTION_RETURN + 'result')
self.assertEqual(self.action_plugin.get_info(), self.ACTION_RETURN + 'info')
@@ -48,7 +48,7 @@ class BarcodeAPITest(InvenTreeAPITestCase):
def test_empty(self):
"""Test an empty barcode scan.
Ensure that all required data is in teh respomse.
Ensure that all required data is in the respomse.
"""
response = self.postBarcode(self.scan_url, '')
+1 -1
View File
@@ -24,7 +24,7 @@ def trigger_event(event, *args, **kwargs):
# Do nothing if plugins are not enabled
return # pragma: no cover
# Make sure the database can be accessed and is not beeing tested rn
# Make sure the database can be accessed and is not being tested rn
if not canAppAccessDatabase() and not settings.PLUGIN_TESTING_EVENTS:
logger.debug(f"Ignoring triggered event '{event}' - database not ready")
return
@@ -71,7 +71,7 @@ class AppMixin:
"""
# unregister models from admin
for plugin_path in registry.installed_apps:
models = [] # the modelrefs need to be collected as poping an item in a iter is not welcomed
models = [] # the modelrefs need to be collected as popping an item in a iter is not welcomed
app_name = plugin_path.split('.')[-1]
try:
app_config = apps.get_app_config(app_name)
@@ -128,7 +128,7 @@ class AppMixin:
# reload models if they were set
# models_module gets set if models were defined - even after multiple loads
# on a reload the models registery is empty but models_module is not
# on a reload the models registry is empty but models_module is not
if app_config.models_module and len(app_config.models) == 0:
reload(app_config.models_module)
@@ -140,7 +140,7 @@ class AppMixin:
# reload admin if at least one model is not registered
# models are registered with admin in the 'admin.py' file - so we check
# if the app_config has an admin module before trying to laod it
# if the app_config has an admin module before trying to load it
if model_not_reg and hasattr(app_config.module, 'admin'):
reload(app_config.module.admin)
@@ -148,7 +148,7 @@ class AppMixin:
def _get_plugin_path(cls, plugin):
"""Parse plugin path.
The input can be eiter:
The input can be either:
- a local file / dir
- a package
"""
+1 -1
View File
@@ -218,7 +218,7 @@ class APICallMixin:
Steps to set up:
1. Add this mixin before (left of) SettingsMixin and PluginBase
2. Add two settings for the required url and token/passowrd (use `SettingsMixin`)
2. Add two settings for the required url and token/password (use `SettingsMixin`)
3. Save the references to keys of the settings in `API_URL_SETTING` and `API_TOKEN_SETTING`
4. (Optional) Set `API_TOKEN` to the name required for the token by the external API - Defaults to `Bearer`
5. (Optional) Override the `api_url` property method if the setting needs to be extended
+1 -1
View File
@@ -43,7 +43,7 @@ class LocateMixin:
An attempt is only made if the StockItem is *in stock*
Note: A custom implemenation could always change this behaviour
Note: A custom implementation could always change this behaviour
"""
logger.info(f"LocateMixin: Attempting to locate StockItem pk={item_pk}")
@@ -20,7 +20,7 @@ class TestInvenTreeBarcode(InvenTreeAPITestCase):
]
def test_assign_errors(self):
"""Test error cases for assigment action."""
"""Test error cases for assignment action."""
def test_assert_error(barcode_data):
response = self.post(
@@ -44,7 +44,7 @@ class TestInvenTreeBarcode(InvenTreeAPITestCase):
test_assert_error('{"part": 10004}')
def assign(self, data, expected_code=None):
"""Peform a 'barcode assign' request"""
"""Perform a 'barcode assign' request"""
return self.post(
reverse('api-barcode-link'),
@@ -32,7 +32,7 @@ class InvenTreeCoreNotificationsPlugin(SettingsContentMixin, SettingsMixin, Inve
NAME = "InvenTreeCoreNotificationsPlugin"
TITLE = _("InvenTree Notifications")
AUTHOR = _('InvenTree contributors')
DESCRIPTION = _('Integrated outgoing notificaton methods')
DESCRIPTION = _('Integrated outgoing notification methods')
VERSION = "1.0.0"
SETTINGS = {
+1 -1
View File
@@ -25,7 +25,7 @@ class IntegrationPluginError(Exception):
"""Init a plugin error.
Args:
path: Path on which the error occured - used to find out which plugin it was
path: Path on which the error occurred - used to find out which plugin it was
message: The original error message
"""
self.path = path
+1 -1
View File
@@ -32,7 +32,7 @@ class MetaBase:
Args:
key (str): key for the value
old_key (str, optional): depreceated key - will throw warning
old_key (str, optional): deprecated key - will throw warning
__default (optional): Value if nothing with key can be found. Defaults to None.
Returns:
+3 -3
View File
@@ -58,7 +58,7 @@ class PluginsRegistry:
self.errors = {} # Holds discovering errors
# flags
self.is_loading = False # Are plugins beeing loaded right now
self.is_loading = False # Are plugins being loaded right now
self.apps_loading = True # Marks if apps were reloaded yet
self.git_is_modern = True # Is a modern version of git available
@@ -152,7 +152,7 @@ class PluginsRegistry:
print('[PLUGIN] Max retries, breaking loading')
break
if settings.PLUGIN_TESTING:
print(f'[PLUGIN] Above error occured during testing - {retry_counter}/{settings.PLUGIN_RETRY} retries left')
print(f'[PLUGIN] Above error occurred during testing - {retry_counter}/{settings.PLUGIN_RETRY} retries left')
# now the loading will re-start up with init
@@ -199,7 +199,7 @@ class PluginsRegistry:
full_reload (bool, optional): Reload everything - including plugin mechanism. Defaults to False.
force_reload (bool, optional): Also reload base apps. Defaults to False.
"""
# Do not reload whe currently loading
# Do not reload when currently loading
if self.is_loading:
return # pragma: no cover
@@ -10,6 +10,6 @@ class NoIntegrationPlugin(InvenTreePlugin):
class WrongIntegrationPlugin(UrlsMixin, InvenTreePlugin):
"""A basic wron plugin with urls."""
"""A basic wrong plugin with urls."""
NAME = "WrongIntegrationPlugin"
+1 -1
View File
@@ -152,7 +152,7 @@ class PluginConfigInstallSerializer(serializers.Serializer):
ret['result'] = str(error.output, 'utf-8')
ret['error'] = True
# save plugin to plugin_file if installed successfull
# save plugin to plugin_file if installed successful
if success:
# Read content of plugin file
plg_lines = open(settings.PLUGIN_FILE).readlines()
@@ -1,4 +1,4 @@
"""This module provides template tags for handeling plugins."""
"""This module provides template tags for handling plugins."""
from django import template
from django.conf import settings as djangosettings
@@ -40,7 +40,7 @@ def plugin_settings_content(context, plugin, *args, **kwargs):
@register.simple_tag()
def mixin_enabled(plugin, key, *args, **kwargs):
"""Is the mixin registerd and configured in the plugin?"""
"""Is the mixin registered and configured in the plugin?"""
return plugin.mixin_enabled(key)
+1 -1
View File
@@ -139,7 +139,7 @@ class PluginDetailAPITest(PluginMixin, InvenTreeAPITestCase):
}, follow=True)
self.assertEqual(response.status_code, 200)
# deactivate plugin - deactivate again -> nothing will hapen but the nothing 'changed' function is triggered
# deactivate plugin - deactivate again -> nothing will happen but the nothing 'changed' function is triggered
response = self.client.post(url, {
'action': 'plugin_deactivate',
'index': 0,
+1 -1
View File
@@ -202,7 +202,7 @@ class RegistryTests(TestCase):
def run_package_test(self, directory):
"""General runner for testing package based installs."""
# Patch environment varible to add dir
# Patch environment variable to add dir
envs = {'INVENTREE_PLUGIN_TEST_DIR': directory}
with mock.patch.dict(os.environ, envs):
# Reload to redicsover plugins
+1 -1
View File
@@ -34,7 +34,7 @@ class ReportConfig(AppConfig):
self.create_default_return_order_reports()
def create_default_reports(self, model, reports):
"""Copy defualt report files across to the media directory."""
"""Copy default report files across to the media directory."""
# Source directory for report templates
src_dir = Path(__file__).parent.joinpath(
'templates',
+2 -2
View File
@@ -409,7 +409,7 @@ class BillOfMaterialsReport(ReportTemplateBase):
@classmethod
def getSubdir(cls):
"""Retun the directory where BillOfMaterialsReport templates are located"""
"""Return the directory where BillOfMaterialsReport templates are located"""
return 'bom'
filters = models.CharField(
@@ -481,7 +481,7 @@ class SalesOrderReport(ReportTemplateBase):
@classmethod
def getSubdir(cls):
"""Retun the subdirectory where SalesOrderReport templates are located"""
"""Return the subdirectory where SalesOrderReport templates are located"""
return 'salesorder'
filters = models.CharField(
+1 -1
View File
@@ -418,7 +418,7 @@ class BuildReportTest(ReportTest):
class BOMReportTest(ReportTest):
"""Unit test class fot the BillOfMaterialsReport model"""
"""Unit test class for the BillOfMaterialsReport model"""
model = report_models.BillOfMaterialsReport
list_url = 'api-bom-report-list'
+2 -2
View File
@@ -364,7 +364,7 @@ class StockFilter(rest_filters.FilterSet):
]
# Relationship filters
manufactuer = rest_filters.ModelChoiceFilter(label='Manufacturer', queryset=Company.objects.filter(is_manufacturer=True), field_name='manufacturer_part__manufacturer')
manufacturer = rest_filters.ModelChoiceFilter(label='Manufacturer', queryset=Company.objects.filter(is_manufacturer=True), field_name='manufacturer_part__manufacturer')
supplier = rest_filters.ModelChoiceFilter(label='Supplier', queryset=Company.objects.filter(is_supplier=True), field_name='supplier_part__supplier')
# Part name filters
@@ -827,7 +827,7 @@ class StockList(APIDownloadMixin, ListCreateDestroyAPIView):
"""
Determine the response type based on the request.
a) For HTTP requests (e.g. via the browseable API) return a DRF response
a) For HTTP requests (e.g. via the browsable API) return a DRF response
b) For AJAX requests, simply return a JSON rendered response.
Note: b) is about 100x quicker than a), because the DRF framework adds a lot of cruft
@@ -25,8 +25,8 @@ def delete_scheduled(apps, schema_editor):
# Ensure any parent / child relationships are updated!
for item in items:
childs = StockItem.objects.filter(parent=item)
childs.update(parent=item.parent)
children = StockItem.objects.filter(parent=item)
children.update(parent=item.parent)
item.delete()
@@ -26,7 +26,7 @@ def update_stock_history(apps, schema_editor):
n = 0
for item in items:
# Find newest relevent history
# Find newest relevant history
history = StockItemTracking.objects.filter(
item=item,
tracking_type__in=[StockHistoryCode.SENT_TO_CUSTOMER, StockHistoryCode.SHIPPED_AGAINST_SALES_ORDER]
+3 -3
View File
@@ -256,7 +256,7 @@ def generate_batch_code():
now = datetime.now()
# Pass context data through to the template randering.
# The folowing context variables are availble for custom batch code generation
# The following context variables are available for custom batch code generation
context = {
'date': now,
'year': now.year,
@@ -624,7 +624,7 @@ class StockItem(InvenTreeBarcodeMixin, InvenTreeNotesMixin, MetadataMixin, commo
except PartModels.Part.DoesNotExist:
# This gets thrown if self.supplier_part is null
# TODO - Find a test than can be perfomed...
# TODO - Find a test than can be performed...
pass
# Ensure that the item cannot be assigned to itself
@@ -2109,7 +2109,7 @@ class StockItemTracking(models.Model):
"""Stock tracking entry - used for tracking history of a particular StockItem.
Note: 2021-05-11
The legacy StockTrackingItem model contained very litle information about the "history" of the item.
The legacy StockTrackingItem model contained very little information about the "history" of the item.
In fact, only the "quantity" of the item was recorded at each interaction.
Also, the "title" was translated at time of generation, and thus was not really translateable.
The "new" system tracks all 'delta' changes to the model,
+1 -1
View File
@@ -1241,7 +1241,7 @@ class StockTestResultTest(StockAPITestCase):
"""Tests for StockTestResult APIs."""
def get_url(self):
"""Helper funtion to get test-result api url."""
"""Helper function to get test-result api url."""
return reverse('api-stock-test-result-list')
def test_list(self):
+3 -3
View File
@@ -97,16 +97,16 @@ class StockOwnershipTest(StockViewTestCase):
InvenTreeSetting.set_setting('STOCK_OWNERSHIP_CONTROL', True, self.user)
self.assertEqual(True, InvenTreeSetting.get_setting('STOCK_OWNERSHIP_CONTROL'))
def assert_ownership(self, assertio: bool = True, user=None):
def assert_ownership(self, assertion: bool = True, user=None):
"""Helper function to check ownership control."""
if user is None:
user = self.user
item = StockItem.objects.get(pk=self.test_item_id)
self.assertEqual(assertio, item.check_ownership(user))
self.assertEqual(assertion, item.check_ownership(user))
location = StockLocation.objects.get(pk=self.test_location_id)
self.assertEqual(assertio, location.check_ownership(user))
self.assertEqual(assertion, location.check_ownership(user))
def assert_api_change(self):
"""Helper function to get response to API change."""
+9 -9
View File
@@ -51,7 +51,7 @@ class StockTestBase(InvenTreeTestCase):
class StockTest(StockTestBase):
"""Tests to ensure that the stock location tree functions correcly."""
"""Tests to ensure that the stock location tree functions correctly."""
def test_pathstring(self):
"""Check that pathstring updates occur as expected"""
@@ -145,7 +145,7 @@ class StockTest(StockTestBase):
item.save()
item.full_clean()
# Check that valid URLs pass - and check custon schemes
# Check that valid URLs pass - and check custom schemes
for good_url in [
'https://test.com',
'https://digikey.com/datasheets?file=1010101010101.bin',
@@ -309,12 +309,12 @@ class StockTest(StockTestBase):
self.assertFalse(self.drawer2.has_children)
childs = [item.pk for item in self.office.getUniqueChildren()]
children = [item.pk for item in self.office.getUniqueChildren()]
self.assertIn(self.drawer1.id, childs)
self.assertIn(self.drawer2.id, childs)
self.assertIn(self.drawer1.id, children)
self.assertIn(self.drawer2.id, children)
self.assertNotIn(self.bathroom.id, childs)
self.assertNotIn(self.bathroom.id, children)
def test_items(self):
"""Test has_items."""
@@ -646,7 +646,7 @@ class StockTest(StockTestBase):
self.assertEqual(item.serial_int, 0)
# Next, test for incremenet / decrement functionality
# Next, test for increment / decrement functionality
item.serial = 100
item.save()
@@ -754,7 +754,7 @@ class StockTest(StockTestBase):
"""Unit tests for stock location tree structure (MPTT).
Ensure that the MPTT structure is rebuilt correctly,
and the corrent ancestor tree is observed.
and the current ancestor tree is observed.
Ref: https://github.com/inventree/InvenTree/issues/2636
Ref: https://github.com/inventree/InvenTree/issues/2733
@@ -1185,7 +1185,7 @@ class TestResultTest(StockTestBase):
tests = item.testResultMap(include_installed=False)
self.assertEqual(len(tests), 3)
# There are no "sub items" intalled at this stage
# There are no "sub items" installed at this stage
tests = item.testResultMap(include_installed=False)
self.assertEqual(len(tests), 3)
@@ -44,7 +44,7 @@
{% endif %}
</td>
<td>{{ plugin_key }}</td>
{% trans "Unvailable" as no_info %}
{% trans "Unavailable" as no_info %}
<td>
{% if plugin.author %}
{{ plugin.author }}
@@ -94,7 +94,7 @@
</div>
<p>{% trans "Some languages are not complete" %}
{% if ALL_LANG %}
. <a href="{% url 'settings' %}">{% trans "Show only sufficent" %}</a>
. <a href="{% url 'settings' %}">{% trans "Show only sufficient" %}</a>
{% else %}
{% trans "and hidden." %} <a href="?alllang">{% trans "Show them too" %}</a>
{% endif %}
+1 -1
View File
@@ -95,7 +95,7 @@ $(document).ready(function () {
{% if messages %}
{% for message in messages %}
showMessage("{{ messsage }}");
showMessage("{{ message }}");
{% endfor %}
{% endif %}
+1 -1
View File
@@ -226,7 +226,7 @@ function enableBreadcrumbTree(options) {
$('#breadcrumb-tree-toggle').click(function() {
// Add callback to "collapse" and "expand" the sidebar
// Toggle treeview visibilty
// Toggle treeview visibility
$('#breadcrumb-tree-collapse').toggle();
});
+1 -1
View File
@@ -111,7 +111,7 @@ function onBarcodeScanClicked(e) {
function onCameraAvailable(hasCamera, options) {
if (hasCamera && global_settings.BARCODE_WEBCAM_SUPPORT) {
// Camera is only acccessible if page is served over secure connection
// Camera is only accessible if page is served over secure connection
if (window.isSecureContext == true) {
qrScanner = new Html5Qrcode('barcode_scan_video', {
useBarCodeDetectorIfSupported: true,
+4 -4
View File
@@ -1076,7 +1076,7 @@ function loadBuildOutputTable(build_info, options={}) {
}
});
// Callack for the "unallocate" button
// Callback for the "unallocate" button
$(table).find('.button-output-unallocate').click(function() {
var pk = $(this).attr('pk');
@@ -1738,7 +1738,7 @@ function loadBuildOutputAllocationTable(buildInfo, output, options={}) {
// Reload table data
$(table).bootstrapTable('load', bom_items);
// Find the top-level progess bar for this build output
// Find the top-level progress bar for this build output
var output_progress_bar = $(`#output-progress-${outputId}`);
if (output_progress_bar.exists()) {
@@ -1789,7 +1789,7 @@ function loadBuildOutputAllocationTable(buildInfo, output, options={}) {
}
function requiredQuantity(row) {
// Return the requied quantity for a given row
// Return the required quantity for a given row
var quantity = 0;
@@ -1946,7 +1946,7 @@ function loadBuildOutputAllocationTable(buildInfo, output, options={}) {
},
buttons: constructExpandCollapseButtons(table),
detailFormatter: function(index, row, element) {
// Contruct an 'inner table' which shows which stock items have been allocated
// Construct an 'inner table' which shows which stock items have been allocated
var subTableId = `allocation-table-${outputId}-${row.pk}`;
+2 -2
View File
@@ -289,7 +289,7 @@ function editSupplierPart(part, options={}) {
/*
* Delete one or more SupplierPart objects from the database.
* - User will be provided with a modal form, showing all the parts to be deleted.
* - Delete operations are performed sequentialy, not simultaneously
* - Delete operations are performed sequentially, not simultaneously
*/
function deleteSupplierParts(parts, options={}) {
@@ -785,7 +785,7 @@ function loadContactTable(table, options={}) {
/* Delete one or more ManufacturerPart objects from the database.
* - User will be provided with a modal form, showing all the parts to be deleted.
* - Delete operations are performed sequentialy, not simultaneously
* - Delete operations are performed sequentially, not simultaneously
*/
function deleteManufacturerParts(selections, options={}) {
+5 -5
View File
@@ -1183,7 +1183,7 @@ function handleFormSuccess(response, options) {
var msg_target = null;
if (persist) {
// If the modal is persistant, the target for any messages should be the modal!
// If the modal is persistent, the target for any messages should be the modal!
msg_target = $(options.modal).find('#pre-form-content');
}
@@ -1944,7 +1944,7 @@ function initializeRelatedField(field, fields, options={}) {
var html = renderModelData(name, field.model, data, field);
return $(html);
} else {
// Return a simple renderering
// Return a simple rendering
console.warn(`templateResult() missing 'field.model' for '${name}'`);
return `${name} - ${item.id}`;
}
@@ -1974,7 +1974,7 @@ function initializeRelatedField(field, fields, options={}) {
var html = renderModelData(name, field.model, data, field);
return $(html);
} else {
// Return a simple renderering
// Return a simple rendering
console.warn(`templateSelection() missing 'field.model' for '${name}'`);
return `${name} - ${item.id}`;
}
@@ -2026,7 +2026,7 @@ function initializeRelatedField(field, fields, options={}) {
/*
* Set the value of a select2 instace for a "related field",
* Set the value of a select2 instance for a "related field",
* e.g. with data returned from a secondary modal
*
* arguments:
@@ -2431,7 +2431,7 @@ function constructInputOptions(name, classes, type, parameters, options={}) {
opts.push(`value='${parameters.value}'`);
}
} else if (parameters.default != null) {
// Otherwise, a defualt value?
// Otherwise, a default value?
opts.push(`value='${parameters.default}'`);
}
+1 -1
View File
@@ -322,7 +322,7 @@ function makeRemoveButton(cls, pk, title, options={}) {
/*
* Render a progessbar!
* Render a progressbar!
*
* @param value is the current value of the progress bar
* @param maximum is the maximum value of the progress bar
+4 -4
View File
@@ -193,7 +193,7 @@ function makeOption(text, value, title, selected) {
}
/*
* Programatically generate a list of <option> elements,
* Programmatically generate a list of <option> elements,
* from the (assumed array) of elements.
* For each element, we pass the element to the supplied functions,
* which (in turn) generate display / value / title values.
@@ -272,7 +272,7 @@ function setFieldOptions(fieldName, optionList, options={}) {
/**
* Clear (emtpy) the options list for a particular field
* Clear (empty) the options list for a particular field
*/
function clearFieldOptions(fieldName) {
@@ -369,7 +369,7 @@ function getFieldValue(fieldName, options={}) {
/* Replacement function for the 'matcher' parameter for a select2 dropdown.
Intead of performing an exact match search, a partial match search is performed.
Instead of performing an exact match search, a partial match search is performed.
This splits the search term by the space ' ' character and matches each segment.
Segments can appear out of order and are not case sensitive
@@ -669,7 +669,7 @@ function showQuestionDialog(title, content, options={}) {
* accept_text - Text for the accept button (default = 'Accept')
* cancel_text - Text for the cancel button (default = 'Cancel')
* accept - Function to run if the user presses 'Accept'
* cancel - Functino to run if the user presses 'Cancel'
* cancel - Function to run if the user presses 'Cancel'
*/
options.title = title;
+4 -4
View File
@@ -286,7 +286,7 @@ function partFields(options={}) {
/*
* Construct a set of fields for a PartCategory intance
* Construct a set of fields for a PartCategory instance
*/
function categoryFields(options={}) {
let fields = {
@@ -687,7 +687,7 @@ function partStockLabel(part, options={}) {
elements.push(`{% trans "On Order" %}: ${part.ordering}`);
}
// Check for items beeing built
// Check for items being built
if (part.building) {
elements.push(`{% trans "Building" %}: ${part.building}`);
}
@@ -1287,7 +1287,7 @@ function loadSimplePartTable(table, url, options={}) {
/*
* Construct a set of fields for the PartParameter model.
* Note that the 'data' field changes based on the seleted parameter template
* Note that the 'data' field changes based on the selected parameter template
*/
function partParameterFields(options={}) {
@@ -1868,7 +1868,7 @@ function loadPartPurchaseOrderTable(table, part_id, options={}) {
formatter: function(value, row) {
if (row.received >= row.quantity) {
// Already recevied
// Already received
return `<span class='badge bg-success rounded-pill'>{% trans "Received" %}</span>`;
} else if (row.order_detail && row.order_detail.status == {{ PurchaseOrderStatus.PLACED }}) {
let html = '';
+1 -1
View File
@@ -65,7 +65,7 @@ function formatCurrency(value, options={}) {
// Extract default currency information
let currency = options.currency || global_settings.INVENTREE_DEFAULT_CURRENCY || 'USD';
// Exctract locale information
// Extract locale information
let locale = options.locale || navigator.language || 'en-US';
let formatter = new Intl.NumberFormat(
@@ -1912,7 +1912,7 @@ function loadPurchaseOrderLineItemTable(table, options={}) {
});
});
// Callback for bulk deleting mutliple lines
// Callback for bulk deleting multiple lines
$('#po-lines-bulk-delete').off('click').on('click', function() {
var rows = getTableData(' #po-line-table');
@@ -1522,7 +1522,7 @@ function loadSalesOrderAllocationTable(table, options={}) {
/**
* Display an "allocations" sub table, showing stock items allocated againt a sales order
* Display an "allocations" sub table, showing stock items allocated against a sales order
* @param {*} index
* @param {*} row
* @param {*} element
@@ -1545,7 +1545,7 @@ function showAllocationSubTable(index, row, element, options) {
var pk = $(this).attr('pk');
// Edit the sales order alloction
// Edit the sales order allocation
constructForm(
`/api/order/so-allocation/${pk}/`,
{

Some files were not shown because too many files have changed in this diff Show More