Merge pull request #2913 from matmair/codebase-cleanup

Codebase cleanup to python 3.9 / django 3.2
This commit is contained in:
Oliver 2022-05-02 09:25:52 +10:00 committed by GitHub
commit ef52be82d9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
64 changed files with 478 additions and 456 deletions

View File

@ -44,6 +44,31 @@ The HEAD of the "stable" branch represents the latest stable release code.
- When approved, the branch is merged back *into* stable, with an incremented PATCH number (e.g. 0.4.1 -> 0.4.2)
- The bugfix *must* also be cherry picked into the *master* branch.
## Environment
#### Target version
We are currently targeting:
| Name | Minimum version |
|---|---|
| Python | 3.9 |
| Django | 3.2 |
### Auto creating updates
The following tools can be used to auto-upgrade syntax that was depreciated in new versions:
```bash
pip install pyupgrade
pip install django-upgrade
```
To update the codebase run the following script.
```bash
pyupgrade `find . -name "*.py"`
django-upgrade --target-version 3.2 `find . -name "*.py"`
```
### Credits
If you add any new dependencies / libraries, they need to be added to [the docs](https://github.com/inventree/inventree-docs/blob/master/docs/credits.md). Please try to do that as timely as possible.
## Migration Files
Any required migration files **must** be included in the commit, or the pull-request will be rejected. If you change the underlying database schema, make sure you run `invoke migrate` and commit the migration files before submitting the PR.

View File

@ -5,7 +5,7 @@ Main JSON interface views
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from django.conf import settings
from django.http import JsonResponse

View File

@ -6,7 +6,7 @@ import sys
from .validators import allowable_url_schemes
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from django.forms.fields import URLField as FormURLField
from django.db import models as models

View File

@ -7,7 +7,7 @@ from __future__ import unicode_literals
from urllib.parse import urlencode
import logging
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from django import forms
from django.contrib.auth.models import User, Group
from django.conf import settings
@ -319,7 +319,7 @@ class CustomSocialAccountAdapter(RegistratonMixin, DefaultSocialAccountAdapter):
redirect_url = reverse('two-factor-authenticate')
# Add GET parameters to the URL if they exist.
if request.GET:
redirect_url += u'?' + urlencode(request.GET)
redirect_url += '?' + urlencode(request.GET)
raise ImmediateHttpResponse(
response=HttpResponseRedirect(redirect_url)

View File

@ -13,7 +13,7 @@ from decimal import Decimal, InvalidOperation
from wsgiref.util import FileWrapper
from django.http import StreamingHttpResponse
from django.core.exceptions import ValidationError, FieldError
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from django.contrib.auth.models import Permission
@ -432,7 +432,7 @@ def extract_serial_numbers(serials, expected_quantity, next_number: int):
next_number += 1
# Split input string by whitespace or comma (,) characters
groups = re.split("[\s,]+", serials)
groups = re.split(r"[\s,]+", serials)
numbers = []
errors = []

View File

@ -1,7 +1,7 @@
from django.shortcuts import HttpResponseRedirect
from django.urls import reverse_lazy, Resolver404
from django.shortcuts import redirect
from django.conf.urls import include, url
from django.urls import include, re_path
from django.conf import settings
from django.contrib.auth.middleware import PersistentRemoteUserMiddleware
@ -85,14 +85,14 @@ class AuthRequiredMiddleware(object):
if path not in urls and not path.startswith('/api/'):
# Save the 'next' parameter to pass through to the login view
return redirect('%s?next=%s' % (reverse_lazy('account_login'), request.path))
return redirect('{}?next={}'.format(reverse_lazy('account_login'), request.path))
response = self.get_response(request)
return response
url_matcher = url('', include(frontendpatterns))
url_matcher = re_path('', include(frontendpatterns))
class Check2FAMiddleware(BaseRequire2FAMiddleware):

View File

@ -15,7 +15,7 @@ from collections import OrderedDict
from django.conf import settings
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError as DjangoValidationError
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from django.db import models
from djmoney.contrib.django_rest_framework.fields import MoneyField

View File

@ -3,7 +3,7 @@ Provides system status functionality checks.
"""
# -*- coding: utf-8 -*-
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from django.utils import timezone
import logging

View File

@ -1,4 +1,4 @@
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
class StatusCode:

View File

@ -1,4 +1,3 @@
import json
from test.support import EnvironmentVarGuard
@ -186,7 +185,7 @@ class TestDownloadFile(TestCase):
def test_download(self):
helpers.DownloadFile("hello world", "out.txt")
helpers.DownloadFile(bytes("hello world".encode("utf8")), "out.bin")
helpers.DownloadFile(bytes(b"hello world"), "out.bin")
class TestMPTT(TestCase):

View File

@ -4,8 +4,7 @@ Top-level URL lookup for InvenTree application.
Passes URL lookup downstream to each app as required.
"""
from django.conf.urls import url, include
from django.urls import path
from django.urls import include, path, re_path
from django.contrib import admin
from company.urls import company_urls
@ -56,144 +55,144 @@ apipatterns = []
if settings.PLUGINS_ENABLED:
apipatterns.append(
url(r'^plugin/', include(plugin_api_urls))
re_path(r'^plugin/', include(plugin_api_urls))
)
apipatterns += [
url(r'^barcode/', include(barcode_api_urls)),
url(r'^settings/', include(settings_api_urls)),
url(r'^part/', include(part_api_urls)),
url(r'^bom/', include(bom_api_urls)),
url(r'^company/', include(company_api_urls)),
url(r'^stock/', include(stock_api_urls)),
url(r'^build/', include(build_api_urls)),
url(r'^order/', include(order_api_urls)),
url(r'^label/', include(label_api_urls)),
url(r'^report/', include(report_api_urls)),
re_path(r'^barcode/', include(barcode_api_urls)),
re_path(r'^settings/', include(settings_api_urls)),
re_path(r'^part/', include(part_api_urls)),
re_path(r'^bom/', include(bom_api_urls)),
re_path(r'^company/', include(company_api_urls)),
re_path(r'^stock/', include(stock_api_urls)),
re_path(r'^build/', include(build_api_urls)),
re_path(r'^order/', include(order_api_urls)),
re_path(r'^label/', include(label_api_urls)),
re_path(r'^report/', include(report_api_urls)),
# User URLs
url(r'^user/', include(user_urls)),
re_path(r'^user/', include(user_urls)),
# Plugin endpoints
url(r'^action/', ActionPluginView.as_view(), name='api-action-plugin'),
re_path(r'^action/', ActionPluginView.as_view(), name='api-action-plugin'),
# Webhook enpoint
path('', include(common_api_urls)),
# InvenTree information endpoint
url(r'^$', InfoView.as_view(), name='api-inventree-info'),
path('', InfoView.as_view(), name='api-inventree-info'),
# Unknown endpoint
url(r'^.*$', NotFoundView.as_view(), name='api-404'),
re_path(r'^.*$', NotFoundView.as_view(), name='api-404'),
]
settings_urls = [
url(r'^i18n/?', include('django.conf.urls.i18n')),
re_path(r'^i18n/?', include('django.conf.urls.i18n')),
url(r'^appearance/?', AppearanceSelectView.as_view(), name='settings-appearance'),
url(r'^currencies-refresh/', CurrencyRefreshView.as_view(), name='settings-currencies-refresh'),
re_path(r'^appearance/?', AppearanceSelectView.as_view(), name='settings-appearance'),
re_path(r'^currencies-refresh/', CurrencyRefreshView.as_view(), name='settings-currencies-refresh'),
url(r'^category/', SettingCategorySelectView.as_view(), name='settings-category'),
re_path(r'^category/', SettingCategorySelectView.as_view(), name='settings-category'),
# Catch any other urls
url(r'^.*$', SettingsView.as_view(template_name='InvenTree/settings/settings.html'), name='settings'),
re_path(r'^.*$', SettingsView.as_view(template_name='InvenTree/settings/settings.html'), name='settings'),
]
notifications_urls = [
# Catch any other urls
url(r'^.*$', NotificationsView.as_view(), name='notifications'),
re_path(r'^.*$', NotificationsView.as_view(), name='notifications'),
]
# These javascript files are served "dynamically" - i.e. rendered on demand
dynamic_javascript_urls = [
url(r'^calendar.js', DynamicJsView.as_view(template_name='js/dynamic/calendar.js'), name='calendar.js'),
url(r'^nav.js', DynamicJsView.as_view(template_name='js/dynamic/nav.js'), name='nav.js'),
url(r'^settings.js', DynamicJsView.as_view(template_name='js/dynamic/settings.js'), name='settings.js'),
re_path(r'^calendar.js', DynamicJsView.as_view(template_name='js/dynamic/calendar.js'), name='calendar.js'),
re_path(r'^nav.js', DynamicJsView.as_view(template_name='js/dynamic/nav.js'), name='nav.js'),
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
translated_javascript_urls = [
url(r'^api.js', DynamicJsView.as_view(template_name='js/translated/api.js'), name='api.js'),
url(r'^attachment.js', DynamicJsView.as_view(template_name='js/translated/attachment.js'), name='attachment.js'),
url(r'^barcode.js', DynamicJsView.as_view(template_name='js/translated/barcode.js'), name='barcode.js'),
url(r'^bom.js', DynamicJsView.as_view(template_name='js/translated/bom.js'), name='bom.js'),
url(r'^build.js', DynamicJsView.as_view(template_name='js/translated/build.js'), name='build.js'),
url(r'^company.js', DynamicJsView.as_view(template_name='js/translated/company.js'), name='company.js'),
url(r'^filters.js', DynamicJsView.as_view(template_name='js/translated/filters.js'), name='filters.js'),
url(r'^forms.js', DynamicJsView.as_view(template_name='js/translated/forms.js'), name='forms.js'),
url(r'^helpers.js', DynamicJsView.as_view(template_name='js/translated/helpers.js'), name='helpers.js'),
url(r'^label.js', DynamicJsView.as_view(template_name='js/translated/label.js'), name='label.js'),
url(r'^model_renderers.js', DynamicJsView.as_view(template_name='js/translated/model_renderers.js'), name='model_renderers.js'),
url(r'^modals.js', DynamicJsView.as_view(template_name='js/translated/modals.js'), name='modals.js'),
url(r'^order.js', DynamicJsView.as_view(template_name='js/translated/order.js'), name='order.js'),
url(r'^part.js', DynamicJsView.as_view(template_name='js/translated/part.js'), name='part.js'),
url(r'^report.js', DynamicJsView.as_view(template_name='js/translated/report.js'), name='report.js'),
url(r'^search.js', DynamicJsView.as_view(template_name='js/translated/search.js'), name='search.js'),
url(r'^stock.js', DynamicJsView.as_view(template_name='js/translated/stock.js'), name='stock.js'),
url(r'^plugin.js', DynamicJsView.as_view(template_name='js/translated/plugin.js'), name='plugin.js'),
url(r'^tables.js', DynamicJsView.as_view(template_name='js/translated/tables.js'), name='tables.js'),
url(r'^table_filters.js', DynamicJsView.as_view(template_name='js/translated/table_filters.js'), name='table_filters.js'),
url(r'^notification.js', DynamicJsView.as_view(template_name='js/translated/notification.js'), name='notification.js'),
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'),
re_path(r'^barcode.js', DynamicJsView.as_view(template_name='js/translated/barcode.js'), name='barcode.js'),
re_path(r'^bom.js', DynamicJsView.as_view(template_name='js/translated/bom.js'), name='bom.js'),
re_path(r'^build.js', DynamicJsView.as_view(template_name='js/translated/build.js'), name='build.js'),
re_path(r'^company.js', DynamicJsView.as_view(template_name='js/translated/company.js'), name='company.js'),
re_path(r'^filters.js', DynamicJsView.as_view(template_name='js/translated/filters.js'), name='filters.js'),
re_path(r'^forms.js', DynamicJsView.as_view(template_name='js/translated/forms.js'), name='forms.js'),
re_path(r'^helpers.js', DynamicJsView.as_view(template_name='js/translated/helpers.js'), name='helpers.js'),
re_path(r'^label.js', DynamicJsView.as_view(template_name='js/translated/label.js'), name='label.js'),
re_path(r'^model_renderers.js', DynamicJsView.as_view(template_name='js/translated/model_renderers.js'), name='model_renderers.js'),
re_path(r'^modals.js', DynamicJsView.as_view(template_name='js/translated/modals.js'), name='modals.js'),
re_path(r'^order.js', DynamicJsView.as_view(template_name='js/translated/order.js'), name='order.js'),
re_path(r'^part.js', DynamicJsView.as_view(template_name='js/translated/part.js'), name='part.js'),
re_path(r'^report.js', DynamicJsView.as_view(template_name='js/translated/report.js'), name='report.js'),
re_path(r'^search.js', DynamicJsView.as_view(template_name='js/translated/search.js'), name='search.js'),
re_path(r'^stock.js', DynamicJsView.as_view(template_name='js/translated/stock.js'), name='stock.js'),
re_path(r'^plugin.js', DynamicJsView.as_view(template_name='js/translated/plugin.js'), name='plugin.js'),
re_path(r'^tables.js', DynamicJsView.as_view(template_name='js/translated/tables.js'), name='tables.js'),
re_path(r'^table_filters.js', DynamicJsView.as_view(template_name='js/translated/table_filters.js'), name='table_filters.js'),
re_path(r'^notification.js', DynamicJsView.as_view(template_name='js/translated/notification.js'), name='notification.js'),
]
backendpatterns = [
# "Dynamic" javascript files which are rendered using InvenTree templating.
url(r'^js/dynamic/', include(dynamic_javascript_urls)),
url(r'^js/i18n/', include(translated_javascript_urls)),
re_path(r'^js/dynamic/', include(dynamic_javascript_urls)),
re_path(r'^js/i18n/', include(translated_javascript_urls)),
url(r'^auth/', include('rest_framework.urls', namespace='rest_framework')),
url(r'^auth/?', auth_request),
re_path(r'^auth/', include('rest_framework.urls', namespace='rest_framework')),
re_path(r'^auth/?', auth_request),
url(r'^api/', include(apipatterns)),
url(r'^api-doc/', include_docs_urls(title='InvenTree API')),
re_path(r'^api/', include(apipatterns)),
re_path(r'^api-doc/', include_docs_urls(title='InvenTree API')),
# 3rd party endpoints
url(r'^markdownx/', include('markdownx.urls')),
re_path(r'^markdownx/', include('markdownx.urls')),
]
frontendpatterns = [
url(r'^part/', include(part_urls)),
url(r'^manufacturer-part/', include(manufacturer_part_urls)),
url(r'^supplier-part/', include(supplier_part_urls)),
re_path(r'^part/', include(part_urls)),
re_path(r'^manufacturer-part/', include(manufacturer_part_urls)),
re_path(r'^supplier-part/', include(supplier_part_urls)),
url(r'^common/', include(common_urls)),
re_path(r'^common/', include(common_urls)),
url(r'^stock/', include(stock_urls)),
re_path(r'^stock/', include(stock_urls)),
url(r'^company/', include(company_urls)),
url(r'^order/', include(order_urls)),
re_path(r'^company/', include(company_urls)),
re_path(r'^order/', include(order_urls)),
url(r'^build/', include(build_urls)),
re_path(r'^build/', include(build_urls)),
url(r'^settings/', include(settings_urls)),
re_path(r'^settings/', include(settings_urls)),
url(r'^notifications/', include(notifications_urls)),
re_path(r'^notifications/', include(notifications_urls)),
url(r'^edit-user/', EditUserView.as_view(), name='edit-user'),
url(r'^set-password/', SetPasswordView.as_view(), name='set-password'),
re_path(r'^edit-user/', EditUserView.as_view(), name='edit-user'),
re_path(r'^set-password/', SetPasswordView.as_view(), name='set-password'),
url(r'^index/', IndexView.as_view(), name='index'),
url(r'^search/', SearchView.as_view(), name='search'),
url(r'^stats/', DatabaseStatsView.as_view(), name='stats'),
re_path(r'^index/', IndexView.as_view(), name='index'),
re_path(r'^search/', SearchView.as_view(), name='search'),
re_path(r'^stats/', DatabaseStatsView.as_view(), name='stats'),
# admin sites
url(f'^{settings.INVENTREE_ADMIN_URL}/error_log/', include('error_report.urls')),
url(f'^{settings.INVENTREE_ADMIN_URL}/shell/', include('django_admin_shell.urls')),
url(f'^{settings.INVENTREE_ADMIN_URL}/', admin.site.urls, name='inventree-admin'),
re_path(f'^{settings.INVENTREE_ADMIN_URL}/error_log/', include('error_report.urls')),
re_path(f'^{settings.INVENTREE_ADMIN_URL}/shell/', include('django_admin_shell.urls')),
re_path(f'^{settings.INVENTREE_ADMIN_URL}/', admin.site.urls, name='inventree-admin'),
# DB user sessions
url(r'^accounts/sessions/other/delete/$', view=CustomSessionDeleteOtherView.as_view(), name='session_delete_other', ),
url(r'^accounts/sessions/(?P<pk>\w+)/delete/$', view=CustomSessionDeleteView.as_view(), name='session_delete', ),
path('accounts/sessions/other/delete/', view=CustomSessionDeleteOtherView.as_view(), name='session_delete_other', ),
re_path(r'^accounts/sessions/(?P<pk>\w+)/delete/$', view=CustomSessionDeleteView.as_view(), name='session_delete', ),
# Single Sign On / allauth
# overrides of urlpatterns
url(r'^accounts/email/', CustomEmailView.as_view(), name='account_email'),
url(r'^accounts/social/connections/', CustomConnectionsView.as_view(), name='socialaccount_connections'),
url(r"^accounts/password/reset/key/(?P<uidb36>[0-9A-Za-z]+)-(?P<key>.+)/$", CustomPasswordResetFromKeyView.as_view(), name="account_reset_password_from_key"),
url(r'^accounts/', include('allauth_2fa.urls')), # MFA support
url(r'^accounts/', include('allauth.urls')), # included urlpatterns
re_path(r'^accounts/email/', CustomEmailView.as_view(), name='account_email'),
re_path(r'^accounts/social/connections/', CustomConnectionsView.as_view(), name='socialaccount_connections'),
re_path(r"^accounts/password/reset/key/(?P<uidb36>[0-9A-Za-z]+)-(?P<key>.+)/$", CustomPasswordResetFromKeyView.as_view(), name="account_reset_password_from_key"),
re_path(r'^accounts/', include('allauth_2fa.urls')), # MFA support
re_path(r'^accounts/', include('allauth.urls')), # included urlpatterns
]
# Append custom plugin URLs (if plugin support is enabled)
@ -201,8 +200,8 @@ if settings.PLUGINS_ENABLED:
frontendpatterns.append(get_plugin_urls())
urlpatterns = [
url('', include(frontendpatterns)),
url('', include(backendpatterns)),
re_path('', include(frontendpatterns)),
re_path('', include(backendpatterns)),
]
# Server running in "DEBUG" mode?
@ -221,4 +220,4 @@ if settings.DEBUG:
] + urlpatterns
# Send any unknown URLs to the parts page
urlpatterns += [url(r'^.*$', RedirectView.as_view(url='/index/', permanent=False), name='index')]
urlpatterns += [re_path(r'^.*$', RedirectView.as_view(url='/index/', permanent=False), name='index')]

View File

@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
from django.urls import reverse
from django.conf.urls import url
from django.utils.translation import ugettext_lazy as _
from django.urls import path, re_path
from django.utils.translation import gettext_lazy as _
from rest_framework.exceptions import ValidationError
from rest_framework import permissions
@ -240,8 +240,8 @@ class BarcodeAssign(APIView):
barcode_api_urls = [
url(r'^link/$', BarcodeAssign.as_view(), name='api-barcode-link'),
path('link/', BarcodeAssign.as_view(), name='api-barcode-link'),
# Catch-all performs barcode 'scan'
url(r'^.*$', BarcodeScan.as_view(), name='api-barcode-scan'),
re_path(r'^.*$', BarcodeScan.as_view(), name='api-barcode-scan'),
]

View File

@ -5,7 +5,7 @@ JSON API for the Build app
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.conf.urls import url, include
from django.urls import include, re_path
from rest_framework import filters, generics
@ -508,29 +508,29 @@ class BuildAttachmentDetail(generics.RetrieveUpdateDestroyAPIView, AttachmentMix
build_api_urls = [
# Attachments
url(r'^attachment/', include([
url(r'^(?P<pk>\d+)/', BuildAttachmentDetail.as_view(), name='api-build-attachment-detail'),
url(r'^.*$', BuildAttachmentList.as_view(), name='api-build-attachment-list'),
re_path(r'^attachment/', include([
re_path(r'^(?P<pk>\d+)/', BuildAttachmentDetail.as_view(), name='api-build-attachment-detail'),
re_path(r'^.*$', BuildAttachmentList.as_view(), name='api-build-attachment-list'),
])),
# Build Items
url(r'^item/', include([
url(r'^(?P<pk>\d+)/', BuildItemDetail.as_view(), name='api-build-item-detail'),
url(r'^.*$', BuildItemList.as_view(), name='api-build-item-list'),
re_path(r'^item/', include([
re_path(r'^(?P<pk>\d+)/', BuildItemDetail.as_view(), name='api-build-item-detail'),
re_path(r'^.*$', BuildItemList.as_view(), name='api-build-item-list'),
])),
# Build Detail
url(r'^(?P<pk>\d+)/', include([
url(r'^allocate/', BuildAllocate.as_view(), name='api-build-allocate'),
url(r'^auto-allocate/', BuildAutoAllocate.as_view(), name='api-build-auto-allocate'),
url(r'^complete/', BuildOutputComplete.as_view(), name='api-build-output-complete'),
url(r'^create-output/', BuildOutputCreate.as_view(), name='api-build-output-create'),
url(r'^delete-outputs/', BuildOutputDelete.as_view(), name='api-build-output-delete'),
url(r'^finish/', BuildFinish.as_view(), name='api-build-finish'),
url(r'^unallocate/', BuildUnallocate.as_view(), name='api-build-unallocate'),
url(r'^.*$', BuildDetail.as_view(), name='api-build-detail'),
re_path(r'^(?P<pk>\d+)/', include([
re_path(r'^allocate/', BuildAllocate.as_view(), name='api-build-allocate'),
re_path(r'^auto-allocate/', BuildAutoAllocate.as_view(), name='api-build-auto-allocate'),
re_path(r'^complete/', BuildOutputComplete.as_view(), name='api-build-output-complete'),
re_path(r'^create-output/', BuildOutputCreate.as_view(), name='api-build-output-create'),
re_path(r'^delete-outputs/', BuildOutputDelete.as_view(), name='api-build-output-delete'),
re_path(r'^finish/', BuildFinish.as_view(), name='api-build-finish'),
re_path(r'^unallocate/', BuildUnallocate.as_view(), name='api-build-unallocate'),
re_path(r'^.*$', BuildDetail.as_view(), name='api-build-detail'),
])),
# Build List
url(r'^.*$', BuildList.as_view(), name='api-build-list'),
re_path(r'^.*$', BuildList.as_view(), name='api-build-list'),
]

View File

@ -6,7 +6,7 @@ Django Forms for interacting with Build objects
from __future__ import unicode_literals
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from django import forms
from InvenTree.forms import HelperForm

View File

@ -18,7 +18,7 @@ from django.db.models.functions import Coalesce
from django.db.models.signals import post_save
from django.dispatch.dispatcher import receiver
from django.urls import reverse
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from markdownx.models import MarkdownxField
@ -53,7 +53,7 @@ def get_next_build_number():
build = Build.objects.exclude(reference=None).last()
attempts = set([build.reference])
attempts = {build.reference}
reference = build.reference

View File

@ -7,7 +7,7 @@ from __future__ import unicode_literals
from django.db import transaction
from django.core.exceptions import ValidationError as DjangoValidationError
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from django.db.models import Case, When, Value
from django.db.models import BooleanField

View File

@ -4,7 +4,7 @@ from __future__ import unicode_literals
from decimal import Decimal
import logging
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from django.template.loader import render_to_string
from allauth.account.models import EmailAddress

View File

@ -2,20 +2,20 @@
URL lookup for Build app
"""
from django.conf.urls import url, include
from django.urls import include, re_path
from . import views
build_detail_urls = [
url(r'^cancel/', views.BuildCancel.as_view(), name='build-cancel'),
url(r'^delete/', views.BuildDelete.as_view(), name='build-delete'),
re_path(r'^cancel/', views.BuildCancel.as_view(), name='build-cancel'),
re_path(r'^delete/', views.BuildDelete.as_view(), name='build-delete'),
url(r'^.*$', views.BuildDetail.as_view(), name='build-detail'),
re_path(r'^.*$', views.BuildDetail.as_view(), name='build-detail'),
]
build_urls = [
url(r'^(?P<pk>\d+)/', include(build_detail_urls)),
re_path(r'^(?P<pk>\d+)/', include(build_detail_urls)),
url(r'.*$', views.BuildIndex.as_view(), name='build-index'),
re_path(r'.*$', views.BuildIndex.as_view(), name='build-index'),
]

View File

@ -5,7 +5,7 @@ Django views for interacting with Build objects
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from django.views.generic import DetailView, ListView
from .models import Build

View File

@ -11,7 +11,7 @@ from django.http.response import HttpResponse
from django.utils.decorators import method_decorator
from django.urls import path
from django.views.decorators.csrf import csrf_exempt
from django.conf.urls import url, include
from django.urls import include, re_path
from rest_framework.views import APIView
from rest_framework.response import Response
@ -336,21 +336,21 @@ class NotificationReadAll(generics.RetrieveAPIView):
settings_api_urls = [
# User settings
url(r'^user/', include([
re_path(r'^user/', include([
# User Settings Detail
url(r'^(?P<pk>\d+)/', UserSettingsDetail.as_view(), name='api-user-setting-detail'),
re_path(r'^(?P<pk>\d+)/', UserSettingsDetail.as_view(), name='api-user-setting-detail'),
# User Settings List
url(r'^.*$', UserSettingsList.as_view(), name='api-user-setting-list'),
re_path(r'^.*$', UserSettingsList.as_view(), name='api-user-setting-list'),
])),
# Global settings
url(r'^global/', include([
re_path(r'^global/', include([
# Global Settings Detail
url(r'^(?P<pk>\d+)/', GlobalSettingsDetail.as_view(), name='api-global-setting-detail'),
re_path(r'^(?P<pk>\d+)/', GlobalSettingsDetail.as_view(), name='api-global-setting-detail'),
# Global Settings List
url(r'^.*$', GlobalSettingsList.as_view(), name='api-global-setting-list'),
re_path(r'^.*$', GlobalSettingsList.as_view(), name='api-global-setting-list'),
])),
]
@ -359,18 +359,18 @@ common_api_urls = [
path('webhook/<slug:endpoint>/', WebhookView.as_view(), name='api-webhook'),
# Notifications
url(r'^notifications/', include([
re_path(r'^notifications/', include([
# Individual purchase order detail URLs
url(r'^(?P<pk>\d+)/', include([
url(r'^read/', NotificationRead.as_view(), name='api-notifications-read'),
url(r'^unread/', NotificationUnread.as_view(), name='api-notifications-unread'),
url(r'.*$', NotificationDetail.as_view(), name='api-notifications-detail'),
re_path(r'^(?P<pk>\d+)/', include([
re_path(r'^read/', NotificationRead.as_view(), name='api-notifications-read'),
re_path(r'^unread/', NotificationUnread.as_view(), name='api-notifications-unread'),
re_path(r'.*$', NotificationDetail.as_view(), name='api-notifications-detail'),
])),
# Read all
url(r'^readall/', NotificationReadAll.as_view(), name='api-notifications-readall'),
re_path(r'^readall/', NotificationReadAll.as_view(), name='api-notifications-readall'),
# Notification messages list
url(r'^.*$', NotificationList.as_view(), name='api-notifications-list'),
re_path(r'^.*$', NotificationList.as_view(), name='api-notifications-list'),
])),
]

View File

@ -33,7 +33,7 @@ from djmoney.contrib.exchange.exceptions import MissingRate
from rest_framework.exceptions import PermissionDenied
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from django.core.validators import MinValueValidator, URLValidator
from django.core.exceptions import ValidationError

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
from django.test import TestCase

View File

@ -7,7 +7,7 @@ from __future__ import unicode_literals
import os
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from django.conf import settings
from django.core.files.storage import FileSystemStorage

View File

@ -11,7 +11,7 @@ from django_filters import rest_framework as rest_filters
from rest_framework import filters
from rest_framework import generics
from django.conf.urls import url, include
from django.urls import include, re_path
from django.db.models import Q
from InvenTree.helpers import str2bool
@ -390,42 +390,42 @@ class SupplierPriceBreakDetail(generics.RetrieveUpdateDestroyAPIView):
manufacturer_part_api_urls = [
url(r'^parameter/', include([
url(r'^(?P<pk>\d+)/', ManufacturerPartParameterDetail.as_view(), name='api-manufacturer-part-parameter-detail'),
re_path(r'^parameter/', include([
re_path(r'^(?P<pk>\d+)/', ManufacturerPartParameterDetail.as_view(), name='api-manufacturer-part-parameter-detail'),
# Catch anything else
url(r'^.*$', ManufacturerPartParameterList.as_view(), name='api-manufacturer-part-parameter-list'),
re_path(r'^.*$', ManufacturerPartParameterList.as_view(), name='api-manufacturer-part-parameter-list'),
])),
url(r'^(?P<pk>\d+)/?', ManufacturerPartDetail.as_view(), name='api-manufacturer-part-detail'),
re_path(r'^(?P<pk>\d+)/?', ManufacturerPartDetail.as_view(), name='api-manufacturer-part-detail'),
# Catch anything else
url(r'^.*$', ManufacturerPartList.as_view(), name='api-manufacturer-part-list'),
re_path(r'^.*$', ManufacturerPartList.as_view(), name='api-manufacturer-part-list'),
]
supplier_part_api_urls = [
url(r'^(?P<pk>\d+)/?', SupplierPartDetail.as_view(), name='api-supplier-part-detail'),
re_path(r'^(?P<pk>\d+)/?', SupplierPartDetail.as_view(), name='api-supplier-part-detail'),
# Catch anything else
url(r'^.*$', SupplierPartList.as_view(), name='api-supplier-part-list'),
re_path(r'^.*$', SupplierPartList.as_view(), name='api-supplier-part-list'),
]
company_api_urls = [
url(r'^part/manufacturer/', include(manufacturer_part_api_urls)),
re_path(r'^part/manufacturer/', include(manufacturer_part_api_urls)),
url(r'^part/', include(supplier_part_api_urls)),
re_path(r'^part/', include(supplier_part_api_urls)),
# Supplier price breaks
url(r'^price-break/', include([
re_path(r'^price-break/', include([
url(r'^(?P<pk>\d+)/?', SupplierPriceBreakDetail.as_view(), name='api-part-supplier-price-detail'),
url(r'^.*$', SupplierPriceBreakList.as_view(), name='api-part-supplier-price-list'),
re_path(r'^(?P<pk>\d+)/?', SupplierPriceBreakDetail.as_view(), name='api-part-supplier-price-detail'),
re_path(r'^.*$', SupplierPriceBreakList.as_view(), name='api-part-supplier-price-list'),
])),
url(r'^(?P<pk>\d+)/?', CompanyDetail.as_view(), name='api-company-detail'),
re_path(r'^(?P<pk>\d+)/?', CompanyDetail.as_view(), name='api-company-detail'),
url(r'^.*$', CompanyList.as_view(), name='api-company-list'),
re_path(r'^.*$', CompanyList.as_view(), name='api-company-list'),
]

View File

@ -8,7 +8,7 @@ from __future__ import unicode_literals
from InvenTree.forms import HelperForm
from InvenTree.fields import RoundingDecimalFormField
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
import django.forms
from .models import Company

View File

@ -7,7 +7,7 @@ from __future__ import unicode_literals
import os
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from django.core.validators import MinValueValidator
from django.core.exceptions import ValidationError

View File

@ -2,7 +2,7 @@
JSON serializers for Company app
"""
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from rest_framework import serializers

View File

@ -2,37 +2,37 @@
URL lookup for Company app
"""
from django.conf.urls import url, include
from django.urls import include, re_path
from . import views
company_detail_urls = [
url(r'^thumb-download/', views.CompanyImageDownloadFromURL.as_view(), name='company-image-download'),
re_path(r'^thumb-download/', views.CompanyImageDownloadFromURL.as_view(), name='company-image-download'),
# Any other URL
url(r'^.*$', views.CompanyDetail.as_view(), name='company-detail'),
re_path(r'^.*$', views.CompanyDetail.as_view(), name='company-detail'),
]
company_urls = [
url(r'^(?P<pk>\d+)/', include(company_detail_urls)),
re_path(r'^(?P<pk>\d+)/', include(company_detail_urls)),
url(r'suppliers/', views.CompanyIndex.as_view(), name='supplier-index'),
url(r'manufacturers/', views.CompanyIndex.as_view(), name='manufacturer-index'),
url(r'customers/', views.CompanyIndex.as_view(), name='customer-index'),
re_path(r'suppliers/', views.CompanyIndex.as_view(), name='supplier-index'),
re_path(r'manufacturers/', views.CompanyIndex.as_view(), name='manufacturer-index'),
re_path(r'customers/', views.CompanyIndex.as_view(), name='customer-index'),
# Redirect any other patterns to the 'company' index which displays all companies
url(r'^.*$', views.CompanyIndex.as_view(), name='company-index'),
re_path(r'^.*$', views.CompanyIndex.as_view(), name='company-index'),
]
manufacturer_part_urls = [
url(r'^(?P<pk>\d+)/', views.ManufacturerPartDetail.as_view(template_name='company/manufacturer_part.html'), name='manufacturer-part-detail'),
re_path(r'^(?P<pk>\d+)/', views.ManufacturerPartDetail.as_view(template_name='company/manufacturer_part.html'), name='manufacturer-part-detail'),
]
supplier_part_urls = [
url(r'^(?P<pk>\d+)/', views.SupplierPartDetail.as_view(template_name='company/supplier_part.html'), name='supplier-part-detail'),
re_path(r'^(?P<pk>\d+)/', views.SupplierPartDetail.as_view(template_name='company/supplier_part.html'), name='supplier-part-detail'),
]

View File

@ -6,7 +6,7 @@ Django views for interacting with Company app
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from django.views.generic import DetailView, ListView
from django.urls import reverse

View File

@ -4,10 +4,10 @@ from __future__ import unicode_literals
from io import BytesIO
from PIL import Image
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from django.conf import settings
from django.conf.urls import url, include
from django.urls import include, re_path
from django.core.exceptions import ValidationError, FieldError
from django.http import HttpResponse, JsonResponse
@ -579,38 +579,38 @@ class PartLabelPrint(generics.RetrieveAPIView, PartLabelMixin, LabelPrintMixin):
label_api_urls = [
# Stock item labels
url(r'stock/', include([
re_path(r'stock/', include([
# Detail views
url(r'^(?P<pk>\d+)/', include([
url(r'print/?', StockItemLabelPrint.as_view(), name='api-stockitem-label-print'),
url(r'^.*$', StockItemLabelDetail.as_view(), name='api-stockitem-label-detail'),
re_path(r'^(?P<pk>\d+)/', include([
re_path(r'print/?', StockItemLabelPrint.as_view(), name='api-stockitem-label-print'),
re_path(r'^.*$', StockItemLabelDetail.as_view(), name='api-stockitem-label-detail'),
])),
# List view
url(r'^.*$', StockItemLabelList.as_view(), name='api-stockitem-label-list'),
re_path(r'^.*$', StockItemLabelList.as_view(), name='api-stockitem-label-list'),
])),
# Stock location labels
url(r'location/', include([
re_path(r'location/', include([
# Detail views
url(r'^(?P<pk>\d+)/', include([
url(r'print/?', StockLocationLabelPrint.as_view(), name='api-stocklocation-label-print'),
url(r'^.*$', StockLocationLabelDetail.as_view(), name='api-stocklocation-label-detail'),
re_path(r'^(?P<pk>\d+)/', include([
re_path(r'print/?', StockLocationLabelPrint.as_view(), name='api-stocklocation-label-print'),
re_path(r'^.*$', StockLocationLabelDetail.as_view(), name='api-stocklocation-label-detail'),
])),
# List view
url(r'^.*$', StockLocationLabelList.as_view(), name='api-stocklocation-label-list'),
re_path(r'^.*$', StockLocationLabelList.as_view(), name='api-stocklocation-label-list'),
])),
# Part labels
url(r'^part/', include([
re_path(r'^part/', include([
# Detail views
url(r'^(?P<pk>\d+)/', include([
url(r'^print/', PartLabelPrint.as_view(), name='api-part-label-print'),
url(r'^.*$', PartLabelDetail.as_view(), name='api-part-label-detail'),
re_path(r'^(?P<pk>\d+)/', include([
re_path(r'^print/', PartLabelPrint.as_view(), name='api-part-label-print'),
re_path(r'^.*$', PartLabelDetail.as_view(), name='api-part-label-detail'),
])),
# List view
url(r'^.*$', PartLabelList.as_view(), name='api-part-label-list'),
re_path(r'^.*$', PartLabelList.as_view(), name='api-part-label-list'),
])),
]

View File

@ -5,7 +5,7 @@ JSON API for the Order app
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.conf.urls import url, include
from django.urls import include, path, re_path
from django.db.models import Q, F
from django_filters import rest_framework as rest_filters
@ -1096,78 +1096,78 @@ class PurchaseOrderAttachmentDetail(generics.RetrieveUpdateDestroyAPIView, Attac
order_api_urls = [
# API endpoints for purchase orders
url(r'^po/', include([
re_path(r'^po/', include([
# Purchase order attachments
url(r'attachment/', include([
url(r'^(?P<pk>\d+)/$', PurchaseOrderAttachmentDetail.as_view(), name='api-po-attachment-detail'),
url(r'^.*$', PurchaseOrderAttachmentList.as_view(), name='api-po-attachment-list'),
re_path(r'attachment/', include([
path('<int:pk>/', PurchaseOrderAttachmentDetail.as_view(), name='api-po-attachment-detail'),
re_path(r'^.*$', PurchaseOrderAttachmentList.as_view(), name='api-po-attachment-list'),
])),
# Individual purchase order detail URLs
url(r'^(?P<pk>\d+)/', include([
url(r'^receive/', PurchaseOrderReceive.as_view(), name='api-po-receive'),
url(r'.*$', PurchaseOrderDetail.as_view(), name='api-po-detail'),
re_path(r'^(?P<pk>\d+)/', include([
re_path(r'^receive/', PurchaseOrderReceive.as_view(), name='api-po-receive'),
re_path(r'.*$', PurchaseOrderDetail.as_view(), name='api-po-detail'),
])),
# Purchase order list
url(r'^.*$', PurchaseOrderList.as_view(), name='api-po-list'),
re_path(r'^.*$', PurchaseOrderList.as_view(), name='api-po-list'),
])),
# API endpoints for purchase order line items
url(r'^po-line/', include([
url(r'^(?P<pk>\d+)/$', PurchaseOrderLineItemDetail.as_view(), name='api-po-line-detail'),
url(r'^.*$', PurchaseOrderLineItemList.as_view(), name='api-po-line-list'),
re_path(r'^po-line/', include([
path('<int:pk>/', PurchaseOrderLineItemDetail.as_view(), name='api-po-line-detail'),
re_path(r'^.*$', PurchaseOrderLineItemList.as_view(), name='api-po-line-list'),
])),
# API endpoints for purchase order extra line
url(r'^po-extra-line/', include([
url(r'^(?P<pk>\d+)/$', PurchaseOrderExtraLineDetail.as_view(), name='api-po-extra-line-detail'),
url(r'^$', PurchaseOrderExtraLineList.as_view(), name='api-po-extra-line-list'),
re_path(r'^po-extra-line/', include([
path('<int:pk>/', PurchaseOrderExtraLineDetail.as_view(), name='api-po-extra-line-detail'),
path('', PurchaseOrderExtraLineList.as_view(), name='api-po-extra-line-list'),
])),
# API endpoints for sales ordesr
url(r'^so/', include([
url(r'attachment/', include([
url(r'^(?P<pk>\d+)/$', SalesOrderAttachmentDetail.as_view(), name='api-so-attachment-detail'),
url(r'^.*$', SalesOrderAttachmentList.as_view(), name='api-so-attachment-list'),
re_path(r'^so/', include([
re_path(r'attachment/', include([
path('<int:pk>/', SalesOrderAttachmentDetail.as_view(), name='api-so-attachment-detail'),
re_path(r'^.*$', SalesOrderAttachmentList.as_view(), name='api-so-attachment-list'),
])),
url(r'^shipment/', include([
url(r'^(?P<pk>\d+)/', include([
url(r'^ship/$', SalesOrderShipmentComplete.as_view(), name='api-so-shipment-ship'),
url(r'^.*$', SalesOrderShipmentDetail.as_view(), name='api-so-shipment-detail'),
re_path(r'^shipment/', include([
re_path(r'^(?P<pk>\d+)/', include([
path('ship/', SalesOrderShipmentComplete.as_view(), name='api-so-shipment-ship'),
re_path(r'^.*$', SalesOrderShipmentDetail.as_view(), name='api-so-shipment-detail'),
])),
url(r'^.*$', SalesOrderShipmentList.as_view(), name='api-so-shipment-list'),
re_path(r'^.*$', SalesOrderShipmentList.as_view(), name='api-so-shipment-list'),
])),
# Sales order detail view
url(r'^(?P<pk>\d+)/', include([
url(r'^complete/', SalesOrderComplete.as_view(), name='api-so-complete'),
url(r'^allocate/', SalesOrderAllocate.as_view(), name='api-so-allocate'),
url(r'^allocate-serials/', SalesOrderAllocateSerials.as_view(), name='api-so-allocate-serials'),
url(r'^.*$', SalesOrderDetail.as_view(), name='api-so-detail'),
re_path(r'^(?P<pk>\d+)/', include([
re_path(r'^complete/', SalesOrderComplete.as_view(), name='api-so-complete'),
re_path(r'^allocate/', SalesOrderAllocate.as_view(), name='api-so-allocate'),
re_path(r'^allocate-serials/', SalesOrderAllocateSerials.as_view(), name='api-so-allocate-serials'),
re_path(r'^.*$', SalesOrderDetail.as_view(), name='api-so-detail'),
])),
# Sales order list view
url(r'^.*$', SalesOrderList.as_view(), name='api-so-list'),
re_path(r'^.*$', SalesOrderList.as_view(), name='api-so-list'),
])),
# API endpoints for sales order line items
url(r'^so-line/', include([
url(r'^(?P<pk>\d+)/$', SalesOrderLineItemDetail.as_view(), name='api-so-line-detail'),
url(r'^$', SalesOrderLineItemList.as_view(), name='api-so-line-list'),
re_path(r'^so-line/', include([
path('<int:pk>/', SalesOrderLineItemDetail.as_view(), name='api-so-line-detail'),
path('', SalesOrderLineItemList.as_view(), name='api-so-line-list'),
])),
# API endpoints for sales order extra line
url(r'^so-extra-line/', include([
url(r'^(?P<pk>\d+)/$', SalesOrderExtraLineDetail.as_view(), name='api-so-extra-line-detail'),
url(r'^$', SalesOrderExtraLineList.as_view(), name='api-so-extra-line-list'),
re_path(r'^so-extra-line/', include([
path('<int:pk>/', SalesOrderExtraLineDetail.as_view(), name='api-so-extra-line-detail'),
path('', SalesOrderExtraLineList.as_view(), name='api-so-extra-line-list'),
])),
# API endpoints for sales order allocations
url(r'^so-allocation/', include([
url(r'^(?P<pk>\d+)/$', SalesOrderAllocationDetail.as_view(), name='api-so-allocation-detail'),
url(r'^.*$', SalesOrderAllocationList.as_view(), name='api-so-allocation-list'),
re_path(r'^so-allocation/', include([
path('<int:pk>/', SalesOrderAllocationDetail.as_view(), name='api-so-allocation-detail'),
re_path(r'^.*$', SalesOrderAllocationList.as_view(), name='api-so-allocation-list'),
])),
]

View File

@ -6,7 +6,7 @@ Django Forms for interacting with Order objects
from __future__ import unicode_literals
from django import forms
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from InvenTree.forms import HelperForm
from InvenTree.fields import InvenTreeMoneyField

View File

@ -33,7 +33,7 @@ def calculate_shipped_quantity(apps, schema_editor):
part=item.part
)
q = sum([item.quantity for item in items])
q = sum(item.quantity for item in items)
item.shipped = q

View File

@ -17,7 +17,7 @@ from django.core.validators import MinValueValidator
from django.core.exceptions import ValidationError
from django.contrib.auth.models import User
from django.urls import reverse
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from markdownx.models import MarkdownxField
from mptt.models import TreeForeignKey
@ -49,7 +49,7 @@ def get_next_po_number():
order = PurchaseOrder.objects.exclude(reference=None).last()
attempts = set([order.reference])
attempts = {order.reference}
reference = order.reference
@ -78,7 +78,7 @@ def get_next_so_number():
order = SalesOrder.objects.exclude(reference=None).last()
attempts = set([order.reference])
attempts = {order.reference}
reference = order.reference
@ -161,10 +161,10 @@ class Order(ReferenceIndexingMixin):
# gather name reference
price_ref = 'sale_price' if isinstance(self, SalesOrder) else 'purchase_price'
# order items
total += sum([a.quantity * convert_money(getattr(a, price_ref), target_currency) for a in self.lines.all() if getattr(a, price_ref)])
total += sum(a.quantity * convert_money(getattr(a, price_ref), target_currency) for a in self.lines.all() if getattr(a, price_ref))
# extra lines
total += sum([a.quantity * convert_money(a.price, target_currency) for a in self.extra_lines.all() if a.price])
total += sum(a.quantity * convert_money(a.price, target_currency) for a in self.extra_lines.all() if a.price)
# set decimal-places
total.decimal_places = 4

View File

@ -7,7 +7,7 @@ from __future__ import unicode_literals
from decimal import Decimal
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from django.core.exceptions import ValidationError as DjangoValidationError
from django.db import models, transaction

View File

@ -5,50 +5,50 @@ URL lookup for the Order app. Provides URL endpoints for:
- Detail view of Purchase Orders
"""
from django.conf.urls import url, include
from django.urls import include, re_path
from . import views
purchase_order_detail_urls = [
url(r'^cancel/', views.PurchaseOrderCancel.as_view(), name='po-cancel'),
url(r'^issue/', views.PurchaseOrderIssue.as_view(), name='po-issue'),
url(r'^complete/', views.PurchaseOrderComplete.as_view(), name='po-complete'),
re_path(r'^cancel/', views.PurchaseOrderCancel.as_view(), name='po-cancel'),
re_path(r'^issue/', views.PurchaseOrderIssue.as_view(), name='po-issue'),
re_path(r'^complete/', views.PurchaseOrderComplete.as_view(), name='po-complete'),
url(r'^upload/', views.PurchaseOrderUpload.as_view(), name='po-upload'),
url(r'^export/', views.PurchaseOrderExport.as_view(), name='po-export'),
re_path(r'^upload/', views.PurchaseOrderUpload.as_view(), name='po-upload'),
re_path(r'^export/', views.PurchaseOrderExport.as_view(), name='po-export'),
url(r'^.*$', views.PurchaseOrderDetail.as_view(), name='po-detail'),
re_path(r'^.*$', views.PurchaseOrderDetail.as_view(), name='po-detail'),
]
purchase_order_urls = [
url(r'^order-parts/', views.OrderParts.as_view(), name='order-parts'),
url(r'^pricing/', views.LineItemPricing.as_view(), name='line-pricing'),
re_path(r'^order-parts/', views.OrderParts.as_view(), name='order-parts'),
re_path(r'^pricing/', views.LineItemPricing.as_view(), name='line-pricing'),
# Display detail view for a single purchase order
url(r'^(?P<pk>\d+)/', include(purchase_order_detail_urls)),
re_path(r'^(?P<pk>\d+)/', include(purchase_order_detail_urls)),
# Display complete list of purchase orders
url(r'^.*$', views.PurchaseOrderIndex.as_view(), name='po-index'),
re_path(r'^.*$', views.PurchaseOrderIndex.as_view(), name='po-index'),
]
sales_order_detail_urls = [
url(r'^cancel/', views.SalesOrderCancel.as_view(), name='so-cancel'),
url(r'^export/', views.SalesOrderExport.as_view(), name='so-export'),
re_path(r'^cancel/', views.SalesOrderCancel.as_view(), name='so-cancel'),
re_path(r'^export/', views.SalesOrderExport.as_view(), name='so-export'),
url(r'^.*$', views.SalesOrderDetail.as_view(), name='so-detail'),
re_path(r'^.*$', views.SalesOrderDetail.as_view(), name='so-detail'),
]
sales_order_urls = [
# Display detail view for a single SalesOrder
url(r'^(?P<pk>\d+)/', include(sales_order_detail_urls)),
re_path(r'^(?P<pk>\d+)/', include(sales_order_detail_urls)),
# Display list of all sales orders
url(r'^.*$', views.SalesOrderIndex.as_view(), name='so-index'),
re_path(r'^.*$', views.SalesOrderIndex.as_view(), name='so-index'),
]
order_urls = [
url(r'^purchase-order/', include(purchase_order_urls)),
url(r'^sales-order/', include(sales_order_urls)),
re_path(r'^purchase-order/', include(purchase_order_urls)),
re_path(r'^sales-order/', include(sales_order_urls)),
]

View File

@ -11,7 +11,7 @@ from django.http.response import JsonResponse
from django.shortcuts import get_object_or_404
from django.urls import reverse
from django.http import HttpResponseRedirect
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from django.views.generic import DetailView, ListView
from django.forms import HiddenInput, IntegerField

View File

@ -7,11 +7,11 @@ from __future__ import unicode_literals
import datetime
from django.conf.urls import url, include
from django.urls import include, path, re_path
from django.http import JsonResponse
from django.db.models import Q, F, Count, Min, Max, Avg
from django.db import transaction
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from rest_framework import status
from rest_framework.response import Response
@ -1916,100 +1916,100 @@ class BomItemSubstituteDetail(generics.RetrieveUpdateDestroyAPIView):
part_api_urls = [
# Base URL for PartCategory API endpoints
url(r'^category/', include([
url(r'^tree/', CategoryTree.as_view(), name='api-part-category-tree'),
url(r'^parameters/', CategoryParameterList.as_view(), name='api-part-category-parameter-list'),
re_path(r'^category/', include([
re_path(r'^tree/', CategoryTree.as_view(), name='api-part-category-tree'),
re_path(r'^parameters/', CategoryParameterList.as_view(), name='api-part-category-parameter-list'),
url(r'^(?P<pk>\d+)/?', CategoryDetail.as_view(), name='api-part-category-detail'),
url(r'^$', CategoryList.as_view(), name='api-part-category-list'),
re_path(r'^(?P<pk>\d+)/?', CategoryDetail.as_view(), name='api-part-category-detail'),
path('', CategoryList.as_view(), name='api-part-category-list'),
])),
# Base URL for PartTestTemplate API endpoints
url(r'^test-template/', include([
url(r'^(?P<pk>\d+)/', PartTestTemplateDetail.as_view(), name='api-part-test-template-detail'),
url(r'^$', PartTestTemplateList.as_view(), name='api-part-test-template-list'),
re_path(r'^test-template/', include([
re_path(r'^(?P<pk>\d+)/', PartTestTemplateDetail.as_view(), name='api-part-test-template-detail'),
path('', PartTestTemplateList.as_view(), name='api-part-test-template-list'),
])),
# Base URL for PartAttachment API endpoints
url(r'^attachment/', include([
url(r'^(?P<pk>\d+)/', PartAttachmentDetail.as_view(), name='api-part-attachment-detail'),
url(r'^$', PartAttachmentList.as_view(), name='api-part-attachment-list'),
re_path(r'^attachment/', include([
re_path(r'^(?P<pk>\d+)/', PartAttachmentDetail.as_view(), name='api-part-attachment-detail'),
path('', PartAttachmentList.as_view(), name='api-part-attachment-list'),
])),
# Base URL for part sale pricing
url(r'^sale-price/', include([
url(r'^(?P<pk>\d+)/', PartSalePriceDetail.as_view(), name='api-part-sale-price-detail'),
url(r'^.*$', PartSalePriceList.as_view(), name='api-part-sale-price-list'),
re_path(r'^sale-price/', include([
re_path(r'^(?P<pk>\d+)/', PartSalePriceDetail.as_view(), name='api-part-sale-price-detail'),
re_path(r'^.*$', PartSalePriceList.as_view(), name='api-part-sale-price-list'),
])),
# Base URL for part internal pricing
url(r'^internal-price/', include([
url(r'^(?P<pk>\d+)/', PartInternalPriceDetail.as_view(), name='api-part-internal-price-detail'),
url(r'^.*$', PartInternalPriceList.as_view(), name='api-part-internal-price-list'),
re_path(r'^internal-price/', include([
re_path(r'^(?P<pk>\d+)/', PartInternalPriceDetail.as_view(), name='api-part-internal-price-detail'),
re_path(r'^.*$', PartInternalPriceList.as_view(), name='api-part-internal-price-list'),
])),
# Base URL for PartRelated API endpoints
url(r'^related/', include([
url(r'^(?P<pk>\d+)/', PartRelatedDetail.as_view(), name='api-part-related-detail'),
url(r'^.*$', PartRelatedList.as_view(), name='api-part-related-list'),
re_path(r'^related/', include([
re_path(r'^(?P<pk>\d+)/', PartRelatedDetail.as_view(), name='api-part-related-detail'),
re_path(r'^.*$', PartRelatedList.as_view(), name='api-part-related-list'),
])),
# Base URL for PartParameter API endpoints
url(r'^parameter/', include([
url(r'^template/$', PartParameterTemplateList.as_view(), name='api-part-parameter-template-list'),
re_path(r'^parameter/', include([
path('template/', PartParameterTemplateList.as_view(), name='api-part-parameter-template-list'),
url(r'^(?P<pk>\d+)/', PartParameterDetail.as_view(), name='api-part-parameter-detail'),
url(r'^.*$', PartParameterList.as_view(), name='api-part-parameter-list'),
re_path(r'^(?P<pk>\d+)/', PartParameterDetail.as_view(), name='api-part-parameter-detail'),
re_path(r'^.*$', PartParameterList.as_view(), name='api-part-parameter-list'),
])),
url(r'^thumbs/', include([
url(r'^$', PartThumbs.as_view(), name='api-part-thumbs'),
url(r'^(?P<pk>\d+)/?', PartThumbsUpdate.as_view(), name='api-part-thumbs-update'),
re_path(r'^thumbs/', include([
path('', PartThumbs.as_view(), name='api-part-thumbs'),
re_path(r'^(?P<pk>\d+)/?', PartThumbsUpdate.as_view(), name='api-part-thumbs-update'),
])),
url(r'^(?P<pk>\d+)/', include([
re_path(r'^(?P<pk>\d+)/', include([
# Endpoint for extra serial number information
url(r'^serial-numbers/', PartSerialNumberDetail.as_view(), name='api-part-serial-number-detail'),
re_path(r'^serial-numbers/', PartSerialNumberDetail.as_view(), name='api-part-serial-number-detail'),
# Endpoint for future scheduling information
url(r'^scheduling/', PartScheduling.as_view(), name='api-part-scheduling'),
re_path(r'^scheduling/', PartScheduling.as_view(), name='api-part-scheduling'),
# Endpoint for duplicating a BOM for the specific Part
url(r'^bom-copy/', PartCopyBOM.as_view(), name='api-part-bom-copy'),
re_path(r'^bom-copy/', PartCopyBOM.as_view(), name='api-part-bom-copy'),
# Endpoint for validating a BOM for the specific Part
url(r'^bom-validate/', PartValidateBOM.as_view(), name='api-part-bom-validate'),
re_path(r'^bom-validate/', PartValidateBOM.as_view(), name='api-part-bom-validate'),
# Part detail endpoint
url(r'^.*$', PartDetail.as_view(), name='api-part-detail'),
re_path(r'^.*$', PartDetail.as_view(), name='api-part-detail'),
])),
url(r'^.*$', PartList.as_view(), name='api-part-list'),
re_path(r'^.*$', PartList.as_view(), name='api-part-list'),
]
bom_api_urls = [
url(r'^substitute/', include([
re_path(r'^substitute/', include([
# Detail view
url(r'^(?P<pk>\d+)/', BomItemSubstituteDetail.as_view(), name='api-bom-substitute-detail'),
re_path(r'^(?P<pk>\d+)/', BomItemSubstituteDetail.as_view(), name='api-bom-substitute-detail'),
# Catch all
url(r'^.*$', BomItemSubstituteList.as_view(), name='api-bom-substitute-list'),
re_path(r'^.*$', BomItemSubstituteList.as_view(), name='api-bom-substitute-list'),
])),
# BOM Item Detail
url(r'^(?P<pk>\d+)/', include([
url(r'^validate/?', BomItemValidate.as_view(), name='api-bom-item-validate'),
url(r'^.*$', BomDetail.as_view(), name='api-bom-item-detail'),
re_path(r'^(?P<pk>\d+)/', include([
re_path(r'^validate/?', BomItemValidate.as_view(), name='api-bom-item-validate'),
re_path(r'^.*$', BomDetail.as_view(), name='api-bom-item-detail'),
])),
# API endpoint URLs for importing BOM data
url(r'^import/upload/', BomImportUpload.as_view(), name='api-bom-import-upload'),
url(r'^import/extract/', BomImportExtract.as_view(), name='api-bom-import-extract'),
url(r'^import/submit/', BomImportSubmit.as_view(), name='api-bom-import-submit'),
re_path(r'^import/upload/', BomImportUpload.as_view(), name='api-bom-import-upload'),
re_path(r'^import/extract/', BomImportExtract.as_view(), name='api-bom-import-extract'),
re_path(r'^import/submit/', BomImportSubmit.as_view(), name='api-bom-import-submit'),
# Catch-all
url(r'^.*$', BomList.as_view(), name='api-bom-list'),
re_path(r'^.*$', BomList.as_view(), name='api-bom-list'),
]

View File

@ -6,7 +6,7 @@ Django Forms for interacting with Part objects
from __future__ import unicode_literals
from django import forms
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from mptt.fields import TreeNodeChoiceField

View File

@ -2510,7 +2510,7 @@ def validate_template_name(name):
Prevent illegal characters in "name" field for PartParameterTemplate
"""
for c in "!@#$%^&*()<>{}[].,?/\|~`_+-=\'\"":
for c in "!@#$%^&*()<>{}[].,?/\\|~`_+-=\'\"":
if c in str(name):
raise ValidationError(_(f"Illegal character in template name ({c})"))

View File

@ -11,7 +11,7 @@ from django.db.models import ExpressionWrapper, F, Q, Func
from django.db.models import Subquery, OuterRef, FloatField
from django.db.models.functions import Coalesce
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from rest_framework import serializers
from sql_util.utils import SubqueryCount, SubquerySum

View File

@ -3,7 +3,7 @@ from __future__ import unicode_literals
import logging
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
import InvenTree.helpers
import InvenTree.tasks

View File

@ -12,7 +12,7 @@ import logging
from django.utils.html import format_html
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from django.conf import settings as djangosettings
from django import template

View File

@ -8,53 +8,53 @@ URL lookup for Part app. Provides URL endpoints for:
"""
from django.conf.urls import url, include
from django.urls import include, re_path
from . import views
part_parameter_urls = [
url(r'^template/new/', views.PartParameterTemplateCreate.as_view(), name='part-param-template-create'),
url(r'^template/(?P<pk>\d+)/edit/', views.PartParameterTemplateEdit.as_view(), name='part-param-template-edit'),
url(r'^template/(?P<pk>\d+)/delete/', views.PartParameterTemplateDelete.as_view(), name='part-param-template-edit'),
re_path(r'^template/new/', views.PartParameterTemplateCreate.as_view(), name='part-param-template-create'),
re_path(r'^template/(?P<pk>\d+)/edit/', views.PartParameterTemplateEdit.as_view(), name='part-param-template-edit'),
re_path(r'^template/(?P<pk>\d+)/delete/', views.PartParameterTemplateDelete.as_view(), name='part-param-template-edit'),
]
part_detail_urls = [
url(r'^delete/?', views.PartDelete.as_view(), name='part-delete'),
url(r'^bom-download/?', views.BomDownload.as_view(), name='bom-download'),
re_path(r'^delete/?', views.PartDelete.as_view(), name='part-delete'),
re_path(r'^bom-download/?', views.BomDownload.as_view(), name='bom-download'),
url(r'^pricing/', views.PartPricing.as_view(), name='part-pricing'),
re_path(r'^pricing/', views.PartPricing.as_view(), name='part-pricing'),
url(r'^bom-upload/?', views.BomUpload.as_view(), name='upload-bom'),
re_path(r'^bom-upload/?', views.BomUpload.as_view(), name='upload-bom'),
url(r'^qr_code/?', views.PartQRCode.as_view(), name='part-qr'),
re_path(r'^qr_code/?', views.PartQRCode.as_view(), name='part-qr'),
# Normal thumbnail with form
url(r'^thumb-select/?', views.PartImageSelect.as_view(), name='part-image-select'),
url(r'^thumb-download/', views.PartImageDownloadFromURL.as_view(), name='part-image-download'),
re_path(r'^thumb-select/?', views.PartImageSelect.as_view(), name='part-image-select'),
re_path(r'^thumb-download/', views.PartImageDownloadFromURL.as_view(), name='part-image-download'),
# Any other URLs go to the part detail page
url(r'^.*$', views.PartDetail.as_view(), name='part-detail'),
re_path(r'^.*$', views.PartDetail.as_view(), name='part-detail'),
]
category_parameter_urls = [
url(r'^new/', views.CategoryParameterTemplateCreate.as_view(), name='category-param-template-create'),
url(r'^(?P<pid>\d+)/edit/', views.CategoryParameterTemplateEdit.as_view(), name='category-param-template-edit'),
url(r'^(?P<pid>\d+)/delete/', views.CategoryParameterTemplateDelete.as_view(), name='category-param-template-delete'),
re_path(r'^new/', views.CategoryParameterTemplateCreate.as_view(), name='category-param-template-create'),
re_path(r'^(?P<pid>\d+)/edit/', views.CategoryParameterTemplateEdit.as_view(), name='category-param-template-edit'),
re_path(r'^(?P<pid>\d+)/delete/', views.CategoryParameterTemplateDelete.as_view(), name='category-param-template-delete'),
]
category_urls = [
# Top level subcategory display
url(r'^subcategory/', views.PartIndex.as_view(template_name='part/subcategory.html'), name='category-index-subcategory'),
re_path(r'^subcategory/', views.PartIndex.as_view(template_name='part/subcategory.html'), name='category-index-subcategory'),
# Category detail views
url(r'(?P<pk>\d+)/', include([
url(r'^delete/', views.CategoryDelete.as_view(), name='category-delete'),
url(r'^parameters/', include(category_parameter_urls)),
re_path(r'(?P<pk>\d+)/', include([
re_path(r'^delete/', views.CategoryDelete.as_view(), name='category-delete'),
re_path(r'^parameters/', include(category_parameter_urls)),
# Anything else
url(r'^.*$', views.CategoryDetail.as_view(), name='category-detail'),
re_path(r'^.*$', views.CategoryDetail.as_view(), name='category-detail'),
]))
]
@ -62,27 +62,27 @@ category_urls = [
part_urls = [
# Upload a part
url(r'^import/', views.PartImport.as_view(), name='part-import'),
url(r'^import-api/', views.PartImportAjax.as_view(), name='api-part-import'),
re_path(r'^import/', views.PartImport.as_view(), name='part-import'),
re_path(r'^import-api/', views.PartImportAjax.as_view(), name='api-part-import'),
# Download a BOM upload template
url(r'^bom_template/?', views.BomUploadTemplate.as_view(), name='bom-upload-template'),
re_path(r'^bom_template/?', views.BomUploadTemplate.as_view(), name='bom-upload-template'),
# Individual part using pk
url(r'^(?P<pk>\d+)/', include(part_detail_urls)),
re_path(r'^(?P<pk>\d+)/', include(part_detail_urls)),
# Part category
url(r'^category/', include(category_urls)),
re_path(r'^category/', include(category_urls)),
# Part parameters
url(r'^parameter/', include(part_parameter_urls)),
re_path(r'^parameter/', include(part_parameter_urls)),
# Change category for multiple parts
url(r'^set-category/?', views.PartSetCategory.as_view(), name='part-set-category'),
re_path(r'^set-category/?', views.PartSetCategory.as_view(), name='part-set-category'),
# Individual part using IPN as slug
url(r'^(?P<slug>[-\w]+)/', views.PartDetailFromIPN.as_view(), name='part-detail-from-ipn'),
re_path(r'^(?P<slug>[-\w]+)/', views.PartDetailFromIPN.as_view(), name='part-detail-from-ipn'),
# Top level part list (display top level parts and categories)
url(r'^.*$', views.PartIndex.as_view(), name='part-index'),
re_path(r'^.*$', views.PartIndex.as_view(), name='part-index'),
]

View File

@ -5,7 +5,7 @@ JSON API for the plugin app
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.conf.urls import url, include
from django.urls import include, re_path
from rest_framework import generics
from rest_framework import status
@ -118,18 +118,18 @@ class PluginSettingDetail(generics.RetrieveUpdateAPIView):
plugin_api_urls = [
# Plugin settings URLs
url(r'^settings/', include([
url(r'^(?P<pk>\d+)/', PluginSettingDetail.as_view(), name='api-plugin-setting-detail'),
url(r'^.*$', PluginSettingList.as_view(), name='api-plugin-setting-list'),
re_path(r'^settings/', include([
re_path(r'^(?P<pk>\d+)/', PluginSettingDetail.as_view(), name='api-plugin-setting-detail'),
re_path(r'^.*$', PluginSettingList.as_view(), name='api-plugin-setting-list'),
])),
# Detail views for a single PluginConfig item
url(r'^(?P<pk>\d+)/', include([
url(r'^.*$', PluginDetail.as_view(), name='api-plugin-detail'),
re_path(r'^(?P<pk>\d+)/', include([
re_path(r'^.*$', PluginDetail.as_view(), name='api-plugin-detail'),
])),
url(r'^install/', PluginInstall.as_view(), name='api-plugin-install'),
re_path(r'^install/', PluginInstall.as_view(), name='api-plugin-install'),
# Anything else
url(r'^.*$', PluginList.as_view(), name='api-plugin-list'),
re_path(r'^.*$', PluginList.as_view(), name='api-plugin-list'),
]

View File

@ -5,7 +5,7 @@ import logging
from django.apps import AppConfig
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from maintenance_mode.core import set_maintenance_mode

View File

@ -6,7 +6,7 @@ import logging
import json
import requests
from django.conf.urls import url, include
from django.urls import include, re_path
from django.db.utils import OperationalError, ProgrammingError
from plugin.models import PluginConfig, PluginSetting
@ -303,7 +303,7 @@ class UrlsMixin:
Urlpatterns for this plugin
"""
if self.has_urls:
return url(f'^{self.slug}/', include((self.urls, self.slug)), name=self.slug)
return re_path(f'^{self.slug}/', include((self.urls, self.slug)), name=self.slug)
return None
@property

View File

@ -7,7 +7,7 @@ from __future__ import unicode_literals
import logging
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from django.conf import settings
from django.db import transaction

View File

@ -11,7 +11,7 @@ import pathlib
from django.urls.base import reverse
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
import plugin.plugin as plugin_base
from plugin.helpers import get_git_log, GitStatus

View File

@ -17,7 +17,7 @@ from importlib import reload
from django.apps import apps
from django.conf import settings
from django.db.utils import OperationalError, ProgrammingError, IntegrityError
from django.conf.urls import url, include
from django.urls import include, re_path
from django.urls import clear_url_caches
from django.contrib import admin
from django.utils.text import slugify
@ -570,12 +570,12 @@ class PluginsRegistry:
for index, a in enumerate(urlpatterns):
if hasattr(a, 'app_name'):
if a.app_name == 'admin':
urlpatterns[index] = url(r'^admin/', admin.site.urls, name='inventree-admin')
urlpatterns[index] = re_path(r'^admin/', admin.site.urls, name='inventree-admin')
elif a.app_name == 'plugin':
urlpatterns[index] = get_plugin_urls()
# replace frontendpatterns
global_pattern[0] = url('', include(urlpatterns))
global_pattern[0] = re_path('', include(urlpatterns))
clear_url_caches()
def _reload_apps(self, force_reload: bool = False):

View File

@ -6,8 +6,8 @@ from plugin import IntegrationPluginBase
from plugin.mixins import AppMixin, SettingsMixin, UrlsMixin, NavigationMixin
from django.http import HttpResponse
from django.utils.translation import ugettext_lazy as _
from django.conf.urls import url, include
from django.utils.translation import gettext_lazy as _
from django.urls import include, re_path
class SampleIntegrationPlugin(AppMixin, SettingsMixin, UrlsMixin, NavigationMixin, IntegrationPluginBase):
@ -28,13 +28,13 @@ class SampleIntegrationPlugin(AppMixin, SettingsMixin, UrlsMixin, NavigationMixi
def setup_urls(self):
he_urls = [
url(r'^he/', self.view_test, name='he'),
url(r'^ha/', self.view_test, name='ha'),
re_path(r'^he/', self.view_test, name='he'),
re_path(r'^ha/', self.view_test, name='ha'),
]
return [
url(r'^hi/', self.view_test, name='hi'),
url(r'^ho/', include(he_urls), name='ho'),
re_path(r'^hi/', self.view_test, name='hi'),
re_path(r'^ho/', include(he_urls), name='ho'),
]
SETTINGS = {

View File

@ -10,7 +10,7 @@ import subprocess
from django.core.exceptions import ValidationError
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from django.utils import timezone
from rest_framework import serializers

View File

@ -2,7 +2,7 @@
from django.test import TestCase
from django.conf import settings
from django.conf.urls import url, include
from django.urls import include, re_path
from django.contrib.auth import get_user_model
from datetime import datetime
@ -66,7 +66,7 @@ class UrlsMixinTest(BaseMixinDefinition, TestCase):
class UrlsCls(UrlsMixin, IntegrationPluginBase):
def test():
return 'ccc'
URLS = [url('testpath', test, name='test'), ]
URLS = [re_path('testpath', test, name='test'), ]
self.mixin = UrlsCls()
class NoUrlsCls(UrlsMixin, IntegrationPluginBase):
@ -81,7 +81,7 @@ class UrlsMixinTest(BaseMixinDefinition, TestCase):
self.assertEqual(self.mixin.base_url, target_url)
# urlpattern
target_pattern = url(f'^{plg_name}/', include((self.mixin.urls, plg_name)), name=plg_name)
target_pattern = re_path(f'^{plg_name}/', include((self.mixin.urls, plg_name)), name=plg_name)
self.assertEqual(self.mixin.urlpatterns.reverse_dict, target_pattern.reverse_dict)
# resolve the view

View File

@ -2,7 +2,7 @@
URL lookup for plugin app
"""
from django.conf.urls import url, include
from django.urls import include, re_path
from plugin import registry
@ -21,4 +21,4 @@ def get_plugin_urls():
if plugin.mixin_enabled('urls'):
urls.append(plugin.urlpatterns)
return url(f'^{PLUGIN_BASE}/', include((urls, 'plugin')))
return re_path(f'^{PLUGIN_BASE}/', include((urls, 'plugin')))

View File

@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.utils.translation import ugettext_lazy as _
from django.conf.urls import url, include
from django.utils.translation import gettext_lazy as _
from django.urls import include, path, re_path
from django.core.exceptions import ValidationError, FieldError
from django.http import HttpResponse
@ -730,62 +730,62 @@ class SalesOrderReportPrint(generics.RetrieveAPIView, OrderReportMixin, ReportPr
report_api_urls = [
# Purchase order reports
url(r'po/', include([
re_path(r'po/', include([
# Detail views
url(r'^(?P<pk>\d+)/', include([
url(r'print/', PurchaseOrderReportPrint.as_view(), name='api-po-report-print'),
url(r'^$', PurchaseOrderReportDetail.as_view(), name='api-po-report-detail'),
re_path(r'^(?P<pk>\d+)/', include([
re_path(r'print/', PurchaseOrderReportPrint.as_view(), name='api-po-report-print'),
path('', PurchaseOrderReportDetail.as_view(), name='api-po-report-detail'),
])),
# List view
url(r'^$', PurchaseOrderReportList.as_view(), name='api-po-report-list'),
path('', PurchaseOrderReportList.as_view(), name='api-po-report-list'),
])),
# Sales order reports
url(r'so/', include([
re_path(r'so/', include([
# Detail views
url(r'^(?P<pk>\d+)/', include([
url(r'print/', SalesOrderReportPrint.as_view(), name='api-so-report-print'),
url(r'^$', SalesOrderReportDetail.as_view(), name='api-so-report-detail'),
re_path(r'^(?P<pk>\d+)/', include([
re_path(r'print/', SalesOrderReportPrint.as_view(), name='api-so-report-print'),
path('', SalesOrderReportDetail.as_view(), name='api-so-report-detail'),
])),
url(r'^$', SalesOrderReportList.as_view(), name='api-so-report-list'),
path('', SalesOrderReportList.as_view(), name='api-so-report-list'),
])),
# Build reports
url(r'build/', include([
re_path(r'build/', include([
# Detail views
url(r'^(?P<pk>\d+)/', include([
url(r'print/?', BuildReportPrint.as_view(), name='api-build-report-print'),
url(r'^.$', BuildReportDetail.as_view(), name='api-build-report-detail'),
re_path(r'^(?P<pk>\d+)/', include([
re_path(r'print/?', BuildReportPrint.as_view(), name='api-build-report-print'),
re_path(r'^.$', BuildReportDetail.as_view(), name='api-build-report-detail'),
])),
# List view
url(r'^.*$', BuildReportList.as_view(), name='api-build-report-list'),
re_path(r'^.*$', BuildReportList.as_view(), name='api-build-report-list'),
])),
# Bill of Material reports
url(r'bom/', include([
re_path(r'bom/', include([
# Detail views
url(r'^(?P<pk>\d+)/', include([
url(r'print/?', BOMReportPrint.as_view(), name='api-bom-report-print'),
url(r'^.*$', BOMReportDetail.as_view(), name='api-bom-report-detail'),
re_path(r'^(?P<pk>\d+)/', include([
re_path(r'print/?', BOMReportPrint.as_view(), name='api-bom-report-print'),
re_path(r'^.*$', BOMReportDetail.as_view(), name='api-bom-report-detail'),
])),
# List view
url(r'^.*$', BOMReportList.as_view(), name='api-bom-report-list'),
re_path(r'^.*$', BOMReportList.as_view(), name='api-bom-report-list'),
])),
# Stock item test reports
url(r'test/', include([
re_path(r'test/', include([
# Detail views
url(r'^(?P<pk>\d+)/', include([
url(r'print/?', StockItemTestReportPrint.as_view(), name='api-stockitem-testreport-print'),
url(r'^.*$', StockItemTestReportDetail.as_view(), name='api-stockitem-testreport-detail'),
re_path(r'^(?P<pk>\d+)/', include([
re_path(r'print/?', StockItemTestReportPrint.as_view(), name='api-stockitem-testreport-print'),
re_path(r'^.*$', StockItemTestReportDetail.as_view(), name='api-stockitem-testreport-detail'),
])),
# List view
url(r'^.*$', StockItemTestReportList.as_view(), name='api-stockitem-testreport-list'),
re_path(r'^.*$', StockItemTestReportList.as_view(), name='api-stockitem-testreport-list'),
])),
]

View File

@ -9,11 +9,11 @@ from collections import OrderedDict
from datetime import datetime, timedelta
from django.core.exceptions import ValidationError as DjangoValidationError
from django.conf.urls import url, include
from django.urls import include, path, re_path
from django.http import JsonResponse
from django.db.models import Q, F
from django.db import transaction
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from django_filters.rest_framework import DjangoFilterBackend
from django_filters import rest_framework as rest_filters
@ -1383,47 +1383,47 @@ class LocationDetail(generics.RetrieveUpdateDestroyAPIView):
stock_api_urls = [
url(r'^location/', include([
re_path(r'^location/', include([
url(r'^tree/', StockLocationTree.as_view(), name='api-location-tree'),
re_path(r'^tree/', StockLocationTree.as_view(), name='api-location-tree'),
url(r'^(?P<pk>\d+)/', LocationDetail.as_view(), name='api-location-detail'),
url(r'^.*$', StockLocationList.as_view(), name='api-location-list'),
re_path(r'^(?P<pk>\d+)/', LocationDetail.as_view(), name='api-location-detail'),
re_path(r'^.*$', StockLocationList.as_view(), name='api-location-list'),
])),
# Endpoints for bulk stock adjustment actions
url(r'^count/', StockCount.as_view(), name='api-stock-count'),
url(r'^add/', StockAdd.as_view(), name='api-stock-add'),
url(r'^remove/', StockRemove.as_view(), name='api-stock-remove'),
url(r'^transfer/', StockTransfer.as_view(), name='api-stock-transfer'),
url(r'^assign/', StockAssign.as_view(), name='api-stock-assign'),
url(r'^merge/', StockMerge.as_view(), name='api-stock-merge'),
re_path(r'^count/', StockCount.as_view(), name='api-stock-count'),
re_path(r'^add/', StockAdd.as_view(), name='api-stock-add'),
re_path(r'^remove/', StockRemove.as_view(), name='api-stock-remove'),
re_path(r'^transfer/', StockTransfer.as_view(), name='api-stock-transfer'),
re_path(r'^assign/', StockAssign.as_view(), name='api-stock-assign'),
re_path(r'^merge/', StockMerge.as_view(), name='api-stock-merge'),
# StockItemAttachment API endpoints
url(r'^attachment/', include([
url(r'^(?P<pk>\d+)/', StockAttachmentDetail.as_view(), name='api-stock-attachment-detail'),
url(r'^$', StockAttachmentList.as_view(), name='api-stock-attachment-list'),
re_path(r'^attachment/', include([
re_path(r'^(?P<pk>\d+)/', StockAttachmentDetail.as_view(), name='api-stock-attachment-detail'),
path('', StockAttachmentList.as_view(), name='api-stock-attachment-list'),
])),
# StockItemTestResult API endpoints
url(r'^test/', include([
url(r'^(?P<pk>\d+)/', StockItemTestResultDetail.as_view(), name='api-stock-test-result-detail'),
url(r'^.*$', StockItemTestResultList.as_view(), name='api-stock-test-result-list'),
re_path(r'^test/', include([
re_path(r'^(?P<pk>\d+)/', StockItemTestResultDetail.as_view(), name='api-stock-test-result-detail'),
re_path(r'^.*$', StockItemTestResultList.as_view(), name='api-stock-test-result-list'),
])),
# StockItemTracking API endpoints
url(r'^track/', include([
url(r'^(?P<pk>\d+)/', StockTrackingDetail.as_view(), name='api-stock-tracking-detail'),
url(r'^.*$', StockTrackingList.as_view(), name='api-stock-tracking-list'),
re_path(r'^track/', include([
re_path(r'^(?P<pk>\d+)/', StockTrackingDetail.as_view(), name='api-stock-tracking-detail'),
re_path(r'^.*$', StockTrackingList.as_view(), name='api-stock-tracking-list'),
])),
# Detail views for a single stock item
url(r'^(?P<pk>\d+)/', include([
url(r'^serialize/', StockItemSerialize.as_view(), name='api-stock-item-serialize'),
url(r'^install/', StockItemInstall.as_view(), name='api-stock-item-install'),
url(r'^.*$', StockDetail.as_view(), name='api-stock-detail'),
re_path(r'^(?P<pk>\d+)/', include([
re_path(r'^serialize/', StockItemSerialize.as_view(), name='api-stock-item-serialize'),
re_path(r'^install/', StockItemInstall.as_view(), name='api-stock-item-install'),
re_path(r'^.*$', StockDetail.as_view(), name='api-stock-detail'),
])),
# Anything else
url(r'^.*$', StockList.as_view(), name='api-stock-list'),
re_path(r'^.*$', StockList.as_view(), name='api-stock-list'),
]

View File

@ -7,7 +7,7 @@ from __future__ import unicode_literals
from django import forms
from django.forms.utils import ErrorDict
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from mptt.fields import TreeNodeChoiceField

View File

@ -78,7 +78,7 @@ def update_history(apps, schema_editor):
tracking_type = StockHistoryCode.STOCK_REMOVE
# Extract the number of removed items
result = re.search("^removed ([\d\.]+) items", title)
result = re.search(r"^removed ([\d\.]+) items", title)
if result:
@ -102,7 +102,7 @@ def update_history(apps, schema_editor):
elif 'moved to' in title:
tracking_type = StockHistoryCode.STOCK_MOVE
result = re.search('^Moved to (.*)( - )*(.*) \(from.*$', entry.title)
result = re.search(r'^Moved to (.*)( - )*(.*) \(from.*$', entry.title)
if result:
# Legacy tracking entries recorded the location in multiple ways, because.. why not?
@ -157,7 +157,7 @@ def update_history(apps, schema_editor):
tracking_type = StockHistoryCode.STOCK_ADD
# Extract the number of added items
result = re.search("^added ([\d\.]+) items", title)
result = re.search(r"^added ([\d\.]+) items", title)
if result:

View File

@ -10,7 +10,7 @@ from datetime import datetime, timedelta
from django.db import transaction
from django.core.exceptions import ValidationError as DjangoValidationError
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from django.db.models.functions import Coalesce
from django.db.models import Case, When, Value
from django.db.models import BooleanField

View File

@ -2,55 +2,55 @@
URL lookup for Stock app
"""
from django.conf.urls import url, include
from django.urls import include, re_path
from stock import views
location_urls = [
url(r'^(?P<pk>\d+)/', include([
url(r'^delete/?', views.StockLocationDelete.as_view(), name='stock-location-delete'),
url(r'^qr_code/?', views.StockLocationQRCode.as_view(), name='stock-location-qr'),
re_path(r'^(?P<pk>\d+)/', include([
re_path(r'^delete/?', views.StockLocationDelete.as_view(), name='stock-location-delete'),
re_path(r'^qr_code/?', views.StockLocationQRCode.as_view(), name='stock-location-qr'),
# Anything else
url('^.*$', views.StockLocationDetail.as_view(), name='stock-location-detail'),
re_path('^.*$', views.StockLocationDetail.as_view(), name='stock-location-detail'),
])),
]
stock_item_detail_urls = [
url(r'^convert/', views.StockItemConvert.as_view(), name='stock-item-convert'),
url(r'^delete/', views.StockItemDelete.as_view(), name='stock-item-delete'),
url(r'^qr_code/', views.StockItemQRCode.as_view(), name='stock-item-qr'),
url(r'^delete_test_data/', views.StockItemDeleteTestData.as_view(), name='stock-item-delete-test-data'),
url(r'^return/', views.StockItemReturnToStock.as_view(), name='stock-item-return'),
re_path(r'^convert/', views.StockItemConvert.as_view(), name='stock-item-convert'),
re_path(r'^delete/', views.StockItemDelete.as_view(), name='stock-item-delete'),
re_path(r'^qr_code/', views.StockItemQRCode.as_view(), name='stock-item-qr'),
re_path(r'^delete_test_data/', views.StockItemDeleteTestData.as_view(), name='stock-item-delete-test-data'),
re_path(r'^return/', views.StockItemReturnToStock.as_view(), name='stock-item-return'),
url(r'^add_tracking/', views.StockItemTrackingCreate.as_view(), name='stock-tracking-create'),
re_path(r'^add_tracking/', views.StockItemTrackingCreate.as_view(), name='stock-tracking-create'),
url('^.*$', views.StockItemDetail.as_view(), name='stock-item-detail'),
re_path('^.*$', views.StockItemDetail.as_view(), name='stock-item-detail'),
]
stock_tracking_urls = [
# edit
url(r'^(?P<pk>\d+)/edit/', views.StockItemTrackingEdit.as_view(), name='stock-tracking-edit'),
re_path(r'^(?P<pk>\d+)/edit/', views.StockItemTrackingEdit.as_view(), name='stock-tracking-edit'),
# delete
url(r'^(?P<pk>\d+)/delete', views.StockItemTrackingDelete.as_view(), name='stock-tracking-delete'),
re_path(r'^(?P<pk>\d+)/delete', views.StockItemTrackingDelete.as_view(), name='stock-tracking-delete'),
]
stock_urls = [
# Stock location
url(r'^location/', include(location_urls)),
re_path(r'^location/', include(location_urls)),
url(r'^item/uninstall/', views.StockItemUninstall.as_view(), name='stock-item-uninstall'),
re_path(r'^item/uninstall/', views.StockItemUninstall.as_view(), name='stock-item-uninstall'),
url(r'^track/', include(stock_tracking_urls)),
re_path(r'^track/', include(stock_tracking_urls)),
# Individual stock items
url(r'^item/(?P<pk>\d+)/', include(stock_item_detail_urls)),
re_path(r'^item/(?P<pk>\d+)/', include(stock_item_detail_urls)),
url(r'^sublocations/', views.StockIndex.as_view(template_name='stock/sublocation.html'), name='stock-sublocations'),
re_path(r'^sublocations/', views.StockIndex.as_view(template_name='stock/sublocation.html'), name='stock-sublocations'),
url(r'^.*$', views.StockIndex.as_view(), name='stock-index'),
re_path(r'^.*$', views.StockIndex.as_view(), name='stock-index'),
]

View File

@ -15,7 +15,7 @@ from django.http import HttpResponseRedirect
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from moneyed import CURRENCIES

View File

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from django.contrib import admin, messages
from django import forms

View File

@ -5,7 +5,7 @@ from __future__ import unicode_literals
from django.contrib.auth.models import User
from django.core.exceptions import ObjectDoesNotExist
from django.conf.urls import url, include
from django.urls import include, path, re_path
from django_filters.rest_framework import DjangoFilterBackend
@ -174,14 +174,14 @@ class GetAuthToken(APIView):
user_urls = [
url(r'roles/?$', RoleDetails.as_view(), name='api-user-roles'),
url(r'token/?$', GetAuthToken.as_view(), name='api-token'),
re_path(r'roles/?$', RoleDetails.as_view(), name='api-user-roles'),
re_path(r'token/?$', GetAuthToken.as_view(), name='api-token'),
url(r'^owner/', include([
url(r'^(?P<pk>[0-9]+)/$', OwnerDetail.as_view(), name='api-owner-detail'),
url(r'^.*$', OwnerList.as_view(), name='api-owner-list'),
re_path(r'^owner/', include([
path('<int:pk>/', OwnerDetail.as_view(), name='api-owner-detail'),
re_path(r'^.*$', OwnerList.as_view(), name='api-owner-list'),
])),
url(r'^(?P<pk>[0-9]+)/?$', UserDetail.as_view(), name='user-detail'),
url(r'^$', UserList.as_view()),
re_path(r'^(?P<pk>[0-9]+)/?$', UserDetail.as_view(), name='user-detail'),
path('', UserList.as_view()),
]

View File

@ -66,7 +66,7 @@ if __name__ == '__main__':
print("Checking development branch")
pattern = "^\d+(\.\d+)+ dev$"
pattern = r"^\d+(\.\d+)+ dev$"
result = re.match(pattern, version)
@ -82,7 +82,7 @@ if __name__ == '__main__':
print("Checking release branch")
pattern = "^\d+(\.\d+)+$"
pattern = r"^\d+(\.\d+)+$"
result = re.match(pattern, version)