diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a4883639..a791ff58 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -21,6 +21,10 @@ are used for versioning (schema follows below): - Tested against Python 3.9, Django 3.2 and 4.0. +.. note:: + + Release dedicated to my dear son, Tigran, who turned 10 recently. + 0.17.1 ------ 2021-01-25 diff --git a/README.rst b/README.rst index ccc5983b..47829e49 100644 --- a/README.rst +++ b/README.rst @@ -34,8 +34,8 @@ handling the submitted form data). Prerequisites ============= -- Django 2.2, 3.0 and 3.1. -- Python 3.5, 3.6, 3.7, 3.8 and 3.9. +- Django 2.2, 3.0, 3.1, 3.2 and 4.0. +- Python 3.6, 3.7, 3.8 and 3.9. Key concepts ============ diff --git a/examples/mezzanine_example/urls.py b/examples/mezzanine_example/urls.py index 02b7a737..6ef2df1a 100644 --- a/examples/mezzanine_example/urls.py +++ b/examples/mezzanine_example/urls.py @@ -1,6 +1,6 @@ from __future__ import unicode_literals -from django.conf.urls import include, url +from django.urls import include, re_path as url from django.conf.urls.i18n import i18n_patterns from django.contrib import admin diff --git a/examples/quick_start/quick_start/urls.py b/examples/quick_start/quick_start/urls.py index 8e3a230f..1d9bb652 100644 --- a/examples/quick_start/quick_start/urls.py +++ b/examples/quick_start/quick_start/urls.py @@ -1,4 +1,4 @@ -from django.conf.urls import include, url +from django.urls import include, re_path as url from django.contrib import admin urlpatterns = [ diff --git a/examples/simple/bar/urls.py b/examples/simple/bar/urls.py index dc720569..b89ef10e 100644 --- a/examples/simple/bar/urls.py +++ b/examples/simple/bar/urls.py @@ -1,4 +1,4 @@ -from django.conf.urls import include, url +from django.urls import include, re_path as url from django.utils.translation import gettext_lazy as _ from .views import my_view diff --git a/examples/simple/foo/urls.py b/examples/simple/foo/urls.py index 767366cd..46b71b2f 100644 --- a/examples/simple/foo/urls.py +++ b/examples/simple/foo/urls.py @@ -1,4 +1,4 @@ -from django.conf.urls import url +from django.urls import re_path as url from .views import ( endpoint as foo_views_endpoint, diff --git a/examples/simple/urls.py b/examples/simple/urls.py index 8c5c2c95..0d88b1bf 100644 --- a/examples/simple/urls.py +++ b/examples/simple/urls.py @@ -1,4 +1,4 @@ -from django.conf.urls import include, url +from django.urls import include, re_path as url from django.conf.urls.i18n import i18n_patterns from django.conf import settings from django.contrib import admin diff --git a/examples/tutorial/urls.py b/examples/tutorial/urls.py index d0a6fea4..4bac12e8 100644 --- a/examples/tutorial/urls.py +++ b/examples/tutorial/urls.py @@ -1,4 +1,4 @@ -from django.conf.urls import include, url +from django.urls import include, re_path as url from django.conf import settings from django.contrib import admin diff --git a/setup.py b/setup.py index e14682f7..f2db0d89 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ import os from distutils.version import LooseVersion from setuptools import setup, find_packages -version = '0.18.1' +version = '0.18' # *************************************************************************** # ************************** Django version ********************************* diff --git a/src/fobi/__init__.py b/src/fobi/__init__.py index ac7c0737..16ac919c 100644 --- a/src/fobi/__init__.py +++ b/src/fobi/__init__.py @@ -1,7 +1,7 @@ __title__ = 'django-fobi' -__version__ = '0.17.1' +__version__ = '0.18' __author__ = 'Artur Barseghyan ' -__copyright__ = '2014-2020 Artur Barseghyan' +__copyright__ = '2014-2022 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' default_app_config = 'fobi.apps.Config' diff --git a/src/fobi/admin.py b/src/fobi/admin.py index 7ec0a720..8ad6d9f6 100644 --- a/src/fobi/admin.py +++ b/src/fobi/admin.py @@ -1,4 +1,4 @@ -from django.conf.urls import url +from django.urls import re_path as url from django.contrib import admin from django.contrib import messages from django.contrib.admin import helpers diff --git a/src/fobi/contrib/apps/drf_integration/form_elements/fields/duration/base.py b/src/fobi/contrib/apps/drf_integration/form_elements/fields/duration/base.py index 790a2136..c19c22f8 100644 --- a/src/fobi/contrib/apps/drf_integration/form_elements/fields/duration/base.py +++ b/src/fobi/contrib/apps/drf_integration/form_elements/fields/duration/base.py @@ -2,7 +2,7 @@ import copy import datetime from django.utils.dateparse import parse_duration -from django.utils.encoding import force_text +from django.utils.encoding import force_str from django.utils.translation import gettext_lazy as _ from rest_framework.fields import DurationField @@ -47,7 +47,7 @@ class DurationInputPlugin(IntegrationFormFieldPlugin, } if form_element_plugin.data.initial: - data_initial = force_text(form_element_plugin.data.initial) + data_initial = force_str(form_element_plugin.data.initial) if not isinstance(data_initial, datetime.timedelta): parsed_initial = parse_duration(data_initial) if parsed_initial is not None: diff --git a/src/fobi/contrib/plugins/form_elements/fields/duration/forms.py b/src/fobi/contrib/plugins/form_elements/fields/duration/forms.py index e5a9b3a9..8fdb7031 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/duration/forms.py +++ b/src/fobi/contrib/plugins/form_elements/fields/duration/forms.py @@ -4,7 +4,7 @@ from django import forms from django.utils.translation import gettext_lazy as _ from django.utils.dateparse import parse_duration from django.utils.duration import duration_string -from django.utils.encoding import force_text +from django.utils.encoding import force_str from fobi.base import BaseFormFieldPluginForm, get_theme @@ -90,7 +90,7 @@ class DurationInputForm(forms.Form, BaseFormFieldPluginForm): if initial not in forms.Field.empty_values: if not isinstance(initial, datetime.timedelta): - if parse_duration(force_text(initial)) is None: + if parse_duration(force_str(initial)) is None: self.add_error( 'initial', _("Enter a valid duration.") diff --git a/src/fobi/form_utils.py b/src/fobi/form_utils.py index 63967fc1..86bae934 100644 --- a/src/fobi/form_utils.py +++ b/src/fobi/form_utils.py @@ -2,7 +2,7 @@ from django.forms.utils import ( ErrorDict as DjangoErrorDict, ErrorList as DjangoErrorList, ) -from django.utils.encoding import force_text +from django.utils.encoding import force_str __title__ = 'fobi.form_utils' __author__ = 'Artur Barseghyan ' @@ -20,7 +20,7 @@ class ErrorDict(DjangoErrorDict): def as_text(self): """As text.""" return '\n'.join( - [' %s\n%s' % (k, '\n'.join([' %s' % force_text(i) for i in v])) + [' %s\n%s' % (k, '\n'.join([' %s' % force_str(i) for i in v])) for k, v in self.items()] ) @@ -32,4 +32,4 @@ class ErrorList(DjangoErrorList): """As text.""" if not self: return '' - return '\n'.join([' %s' % force_text(e) for e in self]) + return '\n'.join([' %s' % force_str(e) for e in self]) diff --git a/src/fobi/helpers.py b/src/fobi/helpers.py index 65c2ab7d..7aeb6e43 100644 --- a/src/fobi/helpers.py +++ b/src/fobi/helpers.py @@ -23,7 +23,7 @@ from django.urls import reverse from django.http import HttpResponse from django.templatetags.static import static from django.test.client import RequestFactory -from django.utils.encoding import force_text, smart_text +from django.utils.encoding import force_str, smart_str from django.utils.html import format_html_join from django.utils.translation import gettext_lazy as _ @@ -99,11 +99,11 @@ def safe_text(text): :return str: """ - return smart_text(text) + return smart_str(text) # if PY3: - # return force_text(text, encoding='utf-8') + # return force_str(text, encoding='utf-8') # else: - # return force_text(text, encoding='utf-8').encode('utf-8') + # return force_str(text, encoding='utf-8').encode('utf-8') def lists_overlap(sub, main): diff --git a/src/fobi/templatetags/future_compat.py b/src/fobi/templatetags/future_compat.py index fc5e0a90..2cc6750d 100644 --- a/src/fobi/templatetags/future_compat.py +++ b/src/fobi/templatetags/future_compat.py @@ -18,7 +18,7 @@ except ImportError: from django.template import Library from django.template.base import Node, TemplateSyntaxError - from django.utils.encoding import force_text + from django.utils.encoding import force_str from django.utils.formats import localize from django.utils.html import escape as html_escape from django.utils.safestring import mark_safe, EscapeData, SafeData @@ -35,7 +35,7 @@ except ImportError: """ value = template_localtime(value, use_tz=context.use_tz) value = localize(value, use_l10n=context.use_l10n) - value = force_text(value) + value = force_str(value) if ((context.autoescape and not isinstance(value, SafeData)) or isinstance(value, EscapeData)): return html_escape(value) diff --git a/src/fobi/tests/data.py b/src/fobi/tests/data.py index 4d6c7d06..1d0d3248 100644 --- a/src/fobi/tests/data.py +++ b/src/fobi/tests/data.py @@ -5,7 +5,7 @@ import os # from decimal import Decimal from django.conf import settings -from django.utils.encoding import force_str as force_text +from django.utils.encoding import force_str from faker import Faker @@ -90,42 +90,42 @@ __all__ = ( TEST_FORM_ELEMENT_PLUGIN_DATA = { # Add a "Boolean (checkbox)" plugin. - force_text(BooleanSelectPlugin.name): { + force_str(BooleanSelectPlugin.name): { 'label': "Test boolean", 'help_text': "Lorem ipsum boolean", 'required': False, }, # Add a "Date" input form element - force_text(DateInputPlugin.name): { + force_str(DateInputPlugin.name): { 'label': "Test date input", 'help_text': "Lorem ipsum select multiple input", 'required': False, }, # Add a "DateTime" input form element - force_text(DateTimeInputPlugin.name): { + force_str(DateTimeInputPlugin.name): { 'label': "Test datetime input", 'help_text': "Lorem ipsum select multiple input", 'required': False, }, # Add an decimal input plugin - force_text(DecimalInputPlugin.name): { + force_str(DecimalInputPlugin.name): { 'label': "Test decimal input", 'help_text': "Lorem ipsum email", 'required': True, }, # Add an email input plugin - force_text(EmailInputPlugin.name): { + force_str(EmailInputPlugin.name): { 'label': "Test email input", 'help_text': "Lorem ipsum email", 'required': True, }, # Add a "File" (file) form element - force_text(FileInputPlugin.name): { + force_str(FileInputPlugin.name): { 'label': "Test file input", # 'name': "test_file_input", 'help_text': "Lorem ipsum file", @@ -133,7 +133,7 @@ TEST_FORM_ELEMENT_PLUGIN_DATA = { }, # Add an float input plugin - force_text(FloatInputPlugin.name): { + force_str(FloatInputPlugin.name): { 'label': "Test float input", 'help_text': "Lorem ipsum email", 'required': True, @@ -141,7 +141,7 @@ TEST_FORM_ELEMENT_PLUGIN_DATA = { # TODO: Find out why selenium fails here! # Add a "Hidden" (boolean) form element - # force_text(HiddenInputPlugin.name): { + # force_str(HiddenInputPlugin.name): { # 'label': "Test hidden input", # #'name': "test_hidden_input", # 'help_text': "Lorem ipsum hidden", @@ -149,28 +149,28 @@ TEST_FORM_ELEMENT_PLUGIN_DATA = { # }, # Add a "Integer" (text input) form element - force_text(IntegerInputPlugin.name): { + force_str(IntegerInputPlugin.name): { 'label': "Test integer", 'help_text': "Lorem ipsum text input", 'required': True, }, # Add a "IP address" (text input) form element - force_text(IPAddressInputPlugin.name): { + force_str(IPAddressInputPlugin.name): { 'label': "Test IP address", 'help_text': "Lorem ipsum text input", 'required': True, }, # Add a "null boolean" form element - force_text(NullBooleanSelectPlugin.name): { + force_str(NullBooleanSelectPlugin.name): { 'label': "Test null boolean", 'help_text': "Lorem ipsum text input", 'required': True, }, # Add a "Select Input" (select input) form element - force_text(SelectInputPlugin.name): { + force_str(SelectInputPlugin.name): { 'label': "Test select", 'help_text': "Lorem ipsum text input", 'required': False, @@ -178,14 +178,14 @@ TEST_FORM_ELEMENT_PLUGIN_DATA = { }, # Add a "Select model object" (select input) form element - force_text(SelectModelObjectInputPlugin.name): { + force_str(SelectModelObjectInputPlugin.name): { 'label': "Test select model object", 'help_text': "Lorem ipsum select model object input", 'required': False, }, # Add a "Select multiple" (select multiple input) form element - force_text(SelectMultipleInputPlugin.name): { + force_str(SelectMultipleInputPlugin.name): { 'label': "Test select multiple input", 'help_text': "Lorem ipsum select multiple input", 'required': False, @@ -194,7 +194,7 @@ TEST_FORM_ELEMENT_PLUGIN_DATA = { # Add a "Select multiple with max" (select multiple with max input) form # element - force_text(SelectMultipleWithMaxInputPlugin.name): { + force_str(SelectMultipleWithMaxInputPlugin.name): { 'label': "Test select multiple with max input", 'help_text': "Lorem ipsum select multiple with max input", 'required': False, @@ -203,7 +203,7 @@ TEST_FORM_ELEMENT_PLUGIN_DATA = { # Add a "Checkbox select multiple" (checkbox select multiple input) form # element - force_text(CheckboxSelectMultipleInputPlugin.name): { + force_str(CheckboxSelectMultipleInputPlugin.name): { 'label': "Test checkbox select multiple input", 'help_text': "Lorem ipsum checkbox select multiple input", 'required': False, @@ -211,35 +211,35 @@ TEST_FORM_ELEMENT_PLUGIN_DATA = { }, # Add a "Slug" (slug input) form element - force_text(SlugInputPlugin.name): { + force_str(SlugInputPlugin.name): { 'label': "Test slug input", 'help_text': "Lorem ipsum select multiple input", 'required': False, }, # Add a "Text" (text input) form element - force_text(TextInputPlugin.name): { + force_str(TextInputPlugin.name): { 'label': "Test text", 'help_text': "Lorem ipsum text input", 'required': True, }, # Add a "Textarea" (text area) form element - force_text(TextareaPlugin.name): { + force_str(TextareaPlugin.name): { 'label': "Test text area", 'help_text': "Lorem ipsum text area", 'required': True, }, # Add a "URL input" form element - force_text(URLInputPlugin.name): { + force_str(URLInputPlugin.name): { 'label': "Test URL input", 'help_text': "Lorem ipsum text area", 'required': True, }, # Add a "Text" (text input) form element - # force_text(TextInputPlugin.name): { + # force_str(TextInputPlugin.name): { # 'label': u"Անուն", # 'help_text': u"Անուն", # 'required': True, @@ -281,8 +281,8 @@ TEST_FORM_FIELD_DATA = { # Therefore, an ordered dict. Note that `MailSenderHandlerPlugin` shall # be placed before the `MailHandlerPlugin`. TEST_FORM_HANDLER_PLUGIN_DATA = OrderedDict([ - (force_text(DBStoreHandlerPlugin.name), None), - (force_text(MailSenderHandlerPlugin.name), { + (force_str(DBStoreHandlerPlugin.name), None), + (force_str(MailSenderHandlerPlugin.name), { 'from_name': "From me", 'from_email': "from@example.com", 'to_name': "To you", @@ -290,7 +290,7 @@ TEST_FORM_HANDLER_PLUGIN_DATA = OrderedDict([ 'subject': "Test email subject", 'body': "Test email body", }), - (force_text(MailHandlerPlugin.name), { + (force_str(MailHandlerPlugin.name), { 'from_name': "From me", 'from_email': "from@example.com", 'to_name': "To you", @@ -298,7 +298,7 @@ TEST_FORM_HANDLER_PLUGIN_DATA = OrderedDict([ 'subject': "Test email subject", 'body': "Test email body", }), - (force_text(HTTPRepostHandlerPlugin.name), { + (force_str(HTTPRepostHandlerPlugin.name), { 'endpoint_url': 'http://dev.example.com' }), ]) diff --git a/src/fobi/tests/test_browser_build_dynamic_forms.py b/src/fobi/tests/test_browser_build_dynamic_forms.py index 53980a75..7296bf49 100644 --- a/src/fobi/tests/test_browser_build_dynamic_forms.py +++ b/src/fobi/tests/test_browser_build_dynamic_forms.py @@ -250,7 +250,7 @@ class FobiBrowserBuldDynamicFormsTest(BaseFobiBrowserBuldDynamicFormsTest): # Example follows: # # self._add_form_element( - # force_text(BooleanSelectPlugin.name), + # force_str(BooleanSelectPlugin.name), # { # 'label': "Test boolean", # 'name': "test_boolean", @@ -412,7 +412,7 @@ class FobiBrowserBuldDynamicFormsTest(BaseFobiBrowserBuldDynamicFormsTest): # Example follows: # # self._add_form_element( - # force_text(BooleanSelectPlugin.name), + # force_str(BooleanSelectPlugin.name), # { # 'label': "Test boolean", # 'name': "test_boolean", diff --git a/src/fobi/urls/edit.py b/src/fobi/urls/edit.py index a8329c97..8ca19efc 100644 --- a/src/fobi/urls/edit.py +++ b/src/fobi/urls/edit.py @@ -1,4 +1,4 @@ -from django.conf.urls import url +from django.urls import re_path as url from django.utils.translation import gettext_lazy as _ from fobi.views import ( diff --git a/src/fobi/urls/view.py b/src/fobi/urls/view.py index 1f314038..49f2a3a1 100644 --- a/src/fobi/urls/view.py +++ b/src/fobi/urls/view.py @@ -1,4 +1,4 @@ -from django.conf.urls import url +from django.urls import re_path as url from django.utils.translation import gettext_lazy as _ from fobi.views import ( form_entry_submitted, diff --git a/src/fobi/utils.py b/src/fobi/utils.py index 7deee2e7..87046ea6 100644 --- a/src/fobi/utils.py +++ b/src/fobi/utils.py @@ -11,7 +11,7 @@ from collections import OrderedDict from django.conf import settings from django.contrib import messages from django.forms.widgets import TextInput -from django.utils.encoding import force_text +from django.utils.encoding import force_str from django.utils.translation import gettext from django.urls import reverse @@ -189,9 +189,9 @@ def get_user_plugins(get_allowed_plugin_uids_func, if uid in allowed_plugin_uids: plugin_name = safe_text(plugin.name) # if PY3: - # plugin_name = force_text(plugin.name, encoding='utf-8') + # plugin_name = force_str(plugin.name, encoding='utf-8') # else: - # plugin_name = force_text( + # plugin_name = force_str( # plugin.name, encoding='utf-8' # ).encode('utf-8') registered_plugins.append((uid, plugin_name)) @@ -233,13 +233,13 @@ def get_user_plugins_grouped(get_allowed_plugin_uids_func, for uid, plugin in registry._registry.items(): if uid in allowed_plugin_uids: if PY3: - plugin_name = force_text(plugin.name, encoding='utf-8') - plugin_group = force_text(plugin.group, encoding='utf-8') + plugin_name = force_str(plugin.name, encoding='utf-8') + plugin_group = force_str(plugin.group, encoding='utf-8') else: - plugin_name = force_text( + plugin_name = force_str( plugin.name, encoding='utf-8' ).encode('utf-8') - plugin_group = force_text( + plugin_group = force_str( plugin.group, encoding='utf-8' ).encode('utf-8')