diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 503fd83f8..1089cf25a 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -20,8 +20,7 @@ jobs:
uses: liskin/gh-problem-matcher-wrap@v1
with:
linters: flake8
- run: |
- flake8 --exit-zero
+ run: flake8
isort:
runs-on: ubuntu-latest
@@ -37,4 +36,4 @@ jobs:
uses: liskin/gh-problem-matcher-wrap@v1
with:
linters: isort
- run: isort -c -rc -df djangocms_text_ckeditor
+ run: isort -c -df djangocms_text_ckeditor
diff --git a/.github/workflows/publish-to-live-pypi.yml b/.github/workflows/publish-to-live-pypi.yml
new file mode 100644
index 000000000..1607f7724
--- /dev/null
+++ b/.github/workflows/publish-to-live-pypi.yml
@@ -0,0 +1,39 @@
+name: Publish Python 🐍 distributions 📦 to pypi
+
+on:
+ release:
+ types:
+ - published
+
+jobs:
+ build-n-publish:
+ name: Build and publish Python 🐍 distributions 📦 to pypi
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@master
+ - name: Set up Python 3.9
+ uses: actions/setup-python@v1
+ with:
+ python-version: 3.9
+
+ - name: Install pypa/build
+ run: >-
+ python -m
+ pip install
+ build
+ --user
+ - name: Build a binary wheel and a source tarball
+ run: >-
+ python -m
+ build
+ --sdist
+ --wheel
+ --outdir dist/
+ .
+
+ - name: Publish distribution 📦 to PyPI
+ if: startsWith(github.ref, 'refs/tags')
+ uses: pypa/gh-action-pypi-publish@master
+ with:
+ user: __token__
+ password: ${{ secrets.PYPI_API_TOKEN }}
diff --git a/.github/workflows/publish-to-test-pypi.yml b/.github/workflows/publish-to-test-pypi.yml
new file mode 100644
index 000000000..d590f480e
--- /dev/null
+++ b/.github/workflows/publish-to-test-pypi.yml
@@ -0,0 +1,40 @@
+name: Publish Python 🐍 distributions 📦 to TestPyPI
+
+on:
+ push:
+ branches:
+ - master
+
+jobs:
+ build-n-publish:
+ name: Build and publish Python 🐍 distributions 📦 to TestPyPI
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@master
+ - name: Set up Python 3.9
+ uses: actions/setup-python@v1
+ with:
+ python-version: 3.9
+
+ - name: Install pypa/build
+ run: >-
+ python -m
+ pip install
+ build
+ --user
+ - name: Build a binary wheel and a source tarball
+ run: >-
+ python -m
+ build
+ --sdist
+ --wheel
+ --outdir dist/
+ .
+
+ - name: Publish distribution 📦 to Test PyPI
+ uses: pypa/gh-action-pypi-publish@master
+ with:
+ user: __token__
+ password: ${{ secrets.TEST_PYPI_API_TOKEN }}
+ repository_url: https://test.pypi.org/legacy/
+ skip_existing: true
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 3c1d30d80..d0b06e2b7 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -8,13 +8,12 @@ jobs:
strategy:
fail-fast: false
matrix:
- python-version: [ 3.7, 3.8, 3.9, ] # latest release minus two
+ python-version: [ 3.7, 3.8, 3.9, '3.10']
requirements-file: [
dj22_cms37.txt,
dj22_cms38.txt,
- dj30_cms37.txt,
- dj30_cms38.txt,
dj31_cms38.txt,
+ dj32_cms39.txt
]
os: [
ubuntu-20.04,
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
new file mode 100644
index 000000000..643759625
--- /dev/null
+++ b/.pre-commit-config.yaml
@@ -0,0 +1,33 @@
+repos:
+ - repo: https://github.com/asottile/pyupgrade
+ rev: v2.31.0
+ hooks:
+ - id: pyupgrade
+ args: ["--py37-plus"]
+
+ - repo: https://github.com/adamchainz/django-upgrade
+ rev: '1.4.0'
+ hooks:
+ - id: django-upgrade
+ args: [--target-version, "2.2"]
+
+ - repo: https://github.com/PyCQA/flake8
+ rev: 4.0.1
+ hooks:
+ - id: flake8
+ additional_dependencies:
+ - flake8-broken-line
+ - flake8-bugbear
+ - flake8-builtins
+ - flake8-coding
+ - flake8-commas
+ - flake8-comprehensions
+ - flake8-eradicate
+ - flake8-quotes
+ - flake8-tidy-imports
+ - pep8-naming
+
+ - repo: https://github.com/pycqa/isort
+ rev: 5.10.1
+ hooks:
+ - id: isort
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index c3f3e51a4..bf2c32515 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -6,11 +6,9 @@ Unreleased
==========
* Add dark mode feature and dark mode patch for skin moono-lisa
-
-4.0.1 (unreleased)
-==================
-
* Added support for Django 3.2
+* Drop support for python 3.5, 3.6 and django 3.0
+* Added pre-commit hooks for developer workflow to ensure code quality
4.0.0 (2020-09-15)
diff --git a/MANIFEST.in b/MANIFEST.in
index c91def169..241ff3e07 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -3,4 +3,20 @@ include README.rst
recursive-include djangocms_text_ckeditor/locale *
recursive-include djangocms_text_ckeditor/static *
recursive-include djangocms_text_ckeditor/templates *
+recursive-include private/moono-lisa/dev *.png
+recursive-include private/moono-lisa/dev *.svg
+recursive-include private/moono-lisa/dev *.json
+recursive-include private/moono-lisa/images/hidpi *.png
+recursive-include private/moono-lisa/iamges *.gif
+recursive-include private/moono-lisa/images *.png
+recursive-include private/moono-lisa *.css
+recursive-include private/moono-lisa *.js
+recursive-include private/moono-lisa *.md
+recursive-include private *.md
+recursive-include private *.py
+recursive-include tests .eslintrc
+recursive-include tests *.html
+recursive-include tests *.js
+recursive-include tests *.py
+recursive-include tests *.txt
recursive-exclude * *.py[co]
diff --git a/README.rst b/README.rst
index a186dc984..3e26975a3 100644
--- a/README.rst
+++ b/README.rst
@@ -10,10 +10,10 @@ directly to your web pages. Enhance your website experience with our community
maintained editor. This package aims to integrate CKEditor into django CMS as
a text plugin.
-.. note::
-
+.. note::
+
This project is endorsed by the `django CMS Association `_.
- That means that it is officially accepted by the dCA as being in line with our roadmap vision and development/plugin policy.
+ That means that it is officially accepted by the dCA as being in line with our roadmap vision and development/plugin policy.
Join us on `Slack `_.
@@ -32,8 +32,8 @@ Contribute to this project and win rewards
Because this is a an open-source project, we welcome everyone to
`get involved in the project `_ and
-`receive a reward `_ for their contribution.
-Become part of a fantastic community and help us make django CMS the best CMS in the world.
+`receive a reward `_ for their contribution.
+Become part of a fantastic community and help us make django CMS the best CMS in the world.
We'll be delighted to receive your
feedback in the form of issues and pull requests. Before submitting your
@@ -441,6 +441,13 @@ to make text content using Haystack.
Development
===========
+pre-commit hooks
+----------------
+
+The repo uses pre-commit git hooks to run tools which ensure code quality.
+
+To utilise this, run ``pip install pre-commit`` and then ``pre-commit install``.
+
Building the JavaScript
-----------------------
@@ -455,8 +462,7 @@ This command also updates the file name loaded based on the file contents.
Updating the CKEditor
---------------------
-Make sure to use the url in `build config
-_`.
+Make sure to use the url in `build config `_.
Running Tests
diff --git a/aldryn_config.py b/aldryn_config.py
index 292271cb9..9cb04a0d9 100644
--- a/aldryn_config.py
+++ b/aldryn_config.py
@@ -12,7 +12,7 @@ class Form(forms.BaseForm):
)
def clean(self):
- data = super(Form, self).clean()
+ data = super().clean()
if data.get('content_css'):
files = data['content_css'].split(',')
@@ -20,7 +20,7 @@ def clean(self):
return data
def to_settings(self, data, settings):
- CKEDITOR_SETTINGS = {
+ ckeditor_settings = {
'height': 300,
'language': '{{ language }}',
'toolbar': 'CMS',
@@ -28,16 +28,16 @@ def to_settings(self, data, settings):
}
if data.get('content_css'):
- CKEDITOR_SETTINGS['contentsCss'] = data['content_css']
+ ckeditor_settings['contentsCss'] = data['content_css']
else:
- CKEDITOR_SETTINGS['contentsCss'] = ['/static/css/base.css']
+ ckeditor_settings['contentsCss'] = ['/static/css/base.css']
if data.get('style_set'):
style_set = data['style_set']
else:
style_set = ''
- CKEDITOR_SETTINGS['stylesSet'] = 'default:{}'.format(style_set)
+ ckeditor_settings['stylesSet'] = f'default:{style_set}'
- settings['CKEDITOR_SETTINGS'] = CKEDITOR_SETTINGS
+ settings['CKEDITOR_SETTINGS'] = ckeditor_settings
return settings
diff --git a/djangocms_text_ckeditor/cms_plugins.py b/djangocms_text_ckeditor/cms_plugins.py
index 3bc0020a5..6bb048996 100644
--- a/djangocms_text_ckeditor/cms_plugins.py
+++ b/djangocms_text_ckeditor/cms_plugins.py
@@ -7,10 +7,7 @@
from django.core.exceptions import PermissionDenied, ValidationError
from django.db import transaction
from django.forms.fields import CharField
-from django.http import (
- Http404, HttpResponse, HttpResponseBadRequest, HttpResponseForbidden,
- HttpResponseRedirect,
-)
+from django.http import Http404, HttpResponse, HttpResponseBadRequest, HttpResponseForbidden, HttpResponseRedirect
from django.shortcuts import get_object_or_404
from django.template import RequestContext
from django.urls import re_path, reverse
@@ -28,15 +25,11 @@
from cms.utils.urlutils import admin_reverse
from . import settings
-from .forms import (
- ActionTokenValidationForm, DeleteOnCancelForm, RenderPluginForm, TextForm,
-)
+from .forms import ActionTokenValidationForm, DeleteOnCancelForm, RenderPluginForm, TextForm
from .models import Text
from .utils import (
- OBJ_ADMIN_WITH_CONTENT_RE_PATTERN, _plugin_tags_to_html,
- plugin_tags_to_admin_html, plugin_tags_to_id_list,
- plugin_tags_to_user_html, plugin_to_tag, random_comment_exempt,
- replace_plugin_tags,
+ OBJ_ADMIN_WITH_CONTENT_RE_PATTERN, _plugin_tags_to_html, plugin_tags_to_admin_html, plugin_tags_to_id_list,
+ plugin_tags_to_user_html, plugin_to_tag, random_comment_exempt, replace_plugin_tags,
)
from .widgets import TextEditorWidget
@@ -193,11 +186,11 @@ class TextPlugin(CMSPluginBase):
_has_do_post_copy = True
@classmethod
- def do_post_copy(self, instance, source_map):
+ def do_post_copy(cls, instance, source_map):
ids = plugin_tags_to_id_list(instance.body)
ids_map = {pk: source_map[pk].pk for pk in ids if pk in source_map}
new_text = replace_plugin_tags(instance.body, ids_map)
- self.model.objects.filter(pk=instance.pk).update(body=new_text)
+ cls.model.objects.filter(pk=instance.pk).update(body=new_text)
@staticmethod
def get_translation_export_content(field, plugin_data):
@@ -329,7 +322,7 @@ def add_view(self, request, form_url='', extra_context=None):
# The instance is a record that points to the Text plugin
# but is not a real text plugin instance.
return super().add_view(
- request, form_url, extra_context
+ request, form_url, extra_context,
)
if not self.has_add_permission(request):
@@ -395,7 +388,7 @@ def pattern(regex, func):
def get_admin_url_name(self, name):
plugin_type = self.__class__.__name__.lower()
- url_name = '%s_%s_%s' % (self.model._meta.app_label, plugin_type, name)
+ url_name = f'{self.model._meta.app_label}_{plugin_type}_{name}'
return url_name
def _get_text_plugin_from_request(self, request, data):
@@ -513,7 +506,7 @@ def render(self, context, instance, placeholder):
context,
),
'placeholder': placeholder,
- 'object': instance
+ 'object': instance,
})
return context
diff --git a/djangocms_text_ckeditor/html.py b/djangocms_text_ckeditor/html.py
index 42581c105..da9f48606 100644
--- a/djangocms_text_ckeditor/html.py
+++ b/djangocms_text_ckeditor/html.py
@@ -34,7 +34,7 @@ def _filter_kwargs():
for attr in settings.TEXT_ADDITIONAL_ATTRIBUTES
),
'allowed_protocols': sanitizer.allowed_protocols | frozenset(
- settings.TEXT_ADDITIONAL_PROTOCOLS
+ settings.TEXT_ADDITIONAL_PROTOCOLS,
),
})
return kwargs
@@ -46,7 +46,7 @@ def _get_default_parser():
for parser_class in settings.ALLOW_TOKEN_PARSERS:
parser_classes.append(import_string(parser_class))
TextSanitizer.allow_token_parsers = parser_classes
- return html5lib.HTMLParser(tree=treebuilders.getTreeBuilder("dom"))
+ return html5lib.HTMLParser(tree=treebuilders.getTreeBuilder('dom'))
DEFAULT_PARSER = _get_default_parser()
@@ -73,7 +73,7 @@ def clean_html(data, full=True, parser=DEFAULT_PARSER):
omit_optional_tags=False,
quote_attr_values='always',
)
- return u''.join(s.serialize(stream))
+ return ''.join(s.serialize(stream))
def extract_images(data, plugin):
@@ -127,10 +127,10 @@ def extract_images(data, plugin):
im.save(new_image, 'JPEG')
new_image.seek(0)
image = new_image
- filename = u'%s.%s' % (uuid.uuid4(), file_ending)
+ filename = f'{uuid.uuid4()}.{file_ending}'
# transform image into a cms plugin
image_plugin = img_data_to_plugin(
- filename, image, parent_plugin=plugin, width=width, height=height
+ filename, image, parent_plugin=plugin, width=width, height=height,
)
# render the new html for the plugin
new_img_html = plugin_to_tag(image_plugin)
@@ -138,7 +138,7 @@ def extract_images(data, plugin):
img.parentNode.replaceChild(parser.parseFragment(new_img_html).childNodes[0], img)
found = True
if found:
- return u''.join([y.toxml() for y in dom.getElementsByTagName('body')[0].childNodes])
+ return ''.join([y.toxml() for y in dom.getElementsByTagName('body')[0].childNodes])
else:
return data
@@ -146,7 +146,7 @@ def extract_images(data, plugin):
def img_data_to_plugin(filename, image, parent_plugin, width=None, height=None):
func_name = settings.TEXT_SAVE_IMAGE_FUNCTION.split('.')[-1]
module = __import__(
- '.'.join(settings.TEXT_SAVE_IMAGE_FUNCTION.split('.')[:-1]), fromlist=[func_name]
+ '.'.join(settings.TEXT_SAVE_IMAGE_FUNCTION.split('.')[:-1]), fromlist=[func_name],
)
func = getattr(module, func_name)
return func(filename, image, parent_plugin, width=width, height=height)
diff --git a/djangocms_text_ckeditor/models.py b/djangocms_text_ckeditor/models.py
index 9dee41e7c..845610e74 100644
--- a/djangocms_text_ckeditor/models.py
+++ b/djangocms_text_ckeditor/models.py
@@ -9,10 +9,7 @@
from . import settings
from .html import clean_html, extract_images
-from .utils import (
- plugin_tags_to_db, plugin_tags_to_id_list, plugin_to_tag,
- replace_plugin_tags,
-)
+from .utils import plugin_tags_to_db, plugin_tags_to_id_list, plugin_to_tag, replace_plugin_tags
try:
@@ -48,7 +45,7 @@ class Meta:
abstract = True
def __str__(self):
- return Truncator(strip_tags(self.body).replace('', '')).words(3, truncate="...")
+ return Truncator(strip_tags(self.body).replace('', '')).words(3, truncate='...')
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -89,7 +86,7 @@ def copy_referenced_plugins(self):
referenced_plugins,
self.placeholder,
to_language=self.language,
- parent_plugin_id=self.id
+ parent_plugin_id=self.id,
))
self.add_existing_child_plugins_to_pairs(plugins_pairs)
self.post_copy(self, plugins_pairs)
@@ -126,7 +123,7 @@ def notify_on_autoadd_children(self, request, conf, children):
we must replace some strings with child tag for the CKEDITOR.
Strings are "%(_tag_child_)s" with the inserted order of chidren
"""
- replacements = dict()
+ replacements = {}
order = 1
for child in children:
replacements['_tag_child_' + str(order)] = plugin_to_tag(child)
diff --git a/djangocms_text_ckeditor/settings.py b/djangocms_text_ckeditor/settings.py
index 335213c83..627bf8e62 100644
--- a/djangocms_text_ckeditor/settings.py
+++ b/djangocms_text_ckeditor/settings.py
@@ -28,11 +28,11 @@
# This would make sure correct urls are created for
# when static files are hosted on django and on a CDN. Old code was working fine for Django but not for CDNs.
TEXT_CKEDITOR_BASE_PATH = getattr(
- settings, 'TEXT_CKEDITOR_BASE_PATH', static('djangocms_text_ckeditor/ckeditor/')
+ settings, 'TEXT_CKEDITOR_BASE_PATH', static('djangocms_text_ckeditor/ckeditor/'),
)
TEXT_AUTO_HYPHENATE = getattr(settings, 'TEXT_AUTO_HYPHENATE', True)
-TEXT_PLUGIN_NAME = getattr(settings, 'TEXT_PLUGIN_NAME', _("Text"))
-TEXT_PLUGIN_MODULE_NAME = getattr(settings, 'TEXT_PLUGIN_MODULE_NAME', _("Generic"))
+TEXT_PLUGIN_NAME = getattr(settings, 'TEXT_PLUGIN_NAME', _('Text'))
+TEXT_PLUGIN_MODULE_NAME = getattr(settings, 'TEXT_PLUGIN_MODULE_NAME', _('Generic'))
ALLOW_TOKEN_PARSERS = (
'djangocms_text_ckeditor.attribute_parsers.DataAttributeParser',
diff --git a/djangocms_text_ckeditor/utils.py b/djangocms_text_ckeditor/utils.py
index f0f6064dd..f9bcc468a 100644
--- a/djangocms_text_ckeditor/utils.py
+++ b/djangocms_text_ckeditor/utils.py
@@ -64,14 +64,14 @@ def plugin_to_tag(obj, content='', admin=False):
plugin_class = obj.get_plugin_class()
preview = getattr(plugin_class, 'text_editor_preview', True)
plugin_tag = (
- u'%(content)s'
+ '%(content)s'
)
plugin_attrs['preview'] = 'true' if preview else 'false'
else:
plugin_tag = (
- u'%(content)s'
+ '%(content)s'
)
return plugin_tag % plugin_attrs
@@ -83,7 +83,7 @@ def _find_plugins():
if plugin_id:
yield plugin_id
- return [int(id) for id in _find_plugins()]
+ return [int(_id) for _id in _find_plugins()]
def _plugin_tags_to_html(text, output_func):
@@ -101,7 +101,7 @@ def _render_tag(m):
except KeyError:
# Object must have been deleted. It cannot be rendered to
# end user so just remove it from the HTML altogether
- return u''
+ return ''
else:
obj._render_meta.text_enabled = True
return output_func(obj, m)
@@ -139,7 +139,7 @@ def _replace_tag(m):
# Object must have been deleted. It cannot be rendered to
# end user, or edited, so just remove it from the HTML
# altogether
- return u''
+ return ''
return plugin_to_tag(plugin)
return regex.sub(_replace_tag, text)
@@ -150,7 +150,7 @@ def get_plugins_from_text(text, regex=OBJ_ADMIN_RE):
plugin_ids = plugin_tags_to_id_list(text, regex)
plugins = CMSPlugin.objects.filter(pk__in=plugin_ids).select_related('placeholder')
plugin_list = downcast_plugins(plugins, select_placeholder=True)
- return dict((plugin.pk, plugin) for plugin in plugin_list)
+ return {plugin.pk: plugin for plugin in plugin_list}
"""
@@ -171,9 +171,9 @@ def _setup(self):
def static_url(path):
- '''
+ """
Helper that prefixes a URL with STATIC_URL and cms
- '''
+ """
if not path:
return ''
return configured_storage.url(os.path.join('', path))
diff --git a/djangocms_text_ckeditor/widgets.py b/djangocms_text_ckeditor/widgets.py
index c629b507e..d27b0b9c2 100644
--- a/djangocms_text_ckeditor/widgets.py
+++ b/djangocms_text_ckeditor/widgets.py
@@ -35,10 +35,10 @@ def __init__(self, attrs=None, installed_plugins=None, pk=None,
if self.ckeditor_class not in attrs.get('class', '').join(' '):
new_class = attrs.get('class', '') + ' %s' % self.ckeditor_class
attrs.update({
- 'class': new_class.strip()
+ 'class': new_class.strip(),
})
attrs.update({
- 'data-ckeditor-basepath': text_settings.TEXT_CKEDITOR_BASE_PATH
+ 'data-ckeditor-basepath': text_settings.TEXT_CKEDITOR_BASE_PATH,
})
super().__init__(attrs)
self.installed_plugins = installed_plugins
@@ -61,12 +61,12 @@ def __init__(self, attrs=None, installed_plugins=None, pk=None,
def media(self):
return forms.Media(
css={
- 'all': ('djangocms_text_ckeditor/css/cms.ckeditor.css',)
+ 'all': ('djangocms_text_ckeditor/css/cms.ckeditor.css',),
},
js=(
static_with_version('cms/js/dist/bundle.admin.base.min.js'),
static(PATH_TO_JS),
- )
+ ),
)
def render_textarea(self, name, value, attrs=None, renderer=None):
diff --git a/private/patch_moono_lisa.py b/private/patch_moono_lisa.py
index 66fcae464..33168ea40 100644
--- a/private/patch_moono_lisa.py
+++ b/private/patch_moono_lisa.py
@@ -48,7 +48,7 @@ def update_contents(contents):
for css in glob.glob(f"{src_folder}/*.css"):
- with open(css, "r") as rd:
+ with open(css) as rd:
with open(f"{dst_folder}/{css}", "w") as wt:
print("Patching", css)
contents = update_contents(rd.read())
diff --git a/setup.cfg b/setup.cfg
index 79fd5aaf5..772b20ac9 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,5 +1,5 @@
[flake8]
-ignore = E251,E128,E501
+ignore = C101,E251,E128,E501,E800
max-line-length = 119
exclude =
*.egg-info,
@@ -7,24 +7,36 @@ exclude =
.git,
.settings,
.tox,
+ .env,
+ .venv,
build,
data,
dist,
docs,
+ private/patch_moono_lisa.py,
*migrations*,
+ node_modules,
requirements,
tmp,
*node_modules*
[isort]
-line_length = 79
-skip = manage.py, *migrations*, .tox, .eggs, data
+line_length = 119
+skip =
+ .eggs,
+ .env,
+ .tox,
+ .venv,
+ data,
+ manage.py,
+ *migrations*,
+ node_modules,
+ private
include_trailing_comma = true
multi_line_output = 5
-not_skip = __init__.py
lines_after_imports = 2
default_section = THIRDPARTY
-sections = FUTURE, STDLIB, DJANGO, CMS, THIRDPARTY, FIRSTPARTY, LIB, LOCALFOLDER
+sections = FUTURE, STDLIB, DJANGO, CMS, THIRDPARTY, FIRSTPARTY, LOCALFOLDER
known_first_party = djangocms_text_ckeditor
known_cms = cms, menus
known_django = django
diff --git a/setup.py b/setup.py
index 46530ef78..055d1a15b 100644
--- a/setup.py
+++ b/setup.py
@@ -1,4 +1,6 @@
#!/usr/bin/env python
+from pathlib import Path
+
from setuptools import find_packages, setup
from djangocms_text_ckeditor import __version__
@@ -19,13 +21,12 @@
'Operating System :: OS Independent',
'Programming Language :: Python',
'Programming Language :: Python :: 3',
- 'Programming Language :: Python :: 3.5',
- 'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
+ 'Programming Language :: Python :: 3.9',
+ 'Programming Language :: Python :: 3.10',
'Framework :: Django',
'Framework :: Django :: 2.2',
- 'Framework :: Django :: 3.0',
'Framework :: Django :: 3.1',
'Framework :: Django :: 3.2',
'Framework :: Django CMS',
@@ -39,6 +40,8 @@
'Topic :: Software Development :: Libraries',
]
+this_directory = Path(__file__).parent
+long_description = (this_directory / 'README.rst').read_text()
setup(
name='djangocms-text-ckeditor',
@@ -50,11 +53,13 @@
url='https://github.com/django-cms/djangocms-text-ckeditor',
license='BSD-3-Clause',
description='Text Plugin for django CMS with CKEditor support',
- long_description=open('README.rst').read(),
- packages=find_packages(),
+ long_description=long_description,
+ long_description_content_type='text/x-rst',
+ packages=find_packages(exclude=['tests']),
include_package_data=True,
zip_safe=False,
install_requires=REQUIREMENTS,
classifiers=CLASSIFIERS,
+ python_requires='>=3.7',
test_suite='tests.settings.test',
)
diff --git a/tests/requirements/base.txt b/tests/requirements/base.txt
index 5fc183591..4f9988177 100644
--- a/tests/requirements/base.txt
+++ b/tests/requirements/base.txt
@@ -11,7 +11,6 @@ coverage
django-treebeard<4.5
django-app-helper
tox
-wheel
# IMPORTANT: latest easy-thumbnails causes error since it returns with floating point, but the tests are not prepared for this and even the lib
easy-thumbnails==2.7.1
diff --git a/tests/requirements/dj30_cms37.txt b/tests/requirements/dj30_cms37.txt
deleted file mode 100644
index edcfd450e..000000000
--- a/tests/requirements/dj30_cms37.txt
+++ /dev/null
@@ -1,4 +0,0 @@
--r base.txt
-
-Django>=3.0,<3.1
-django-cms>=3.7,<3.8
diff --git a/tests/requirements/dj30_cms38.txt b/tests/requirements/dj30_cms38.txt
deleted file mode 100644
index 7bc3c0bee..000000000
--- a/tests/requirements/dj30_cms38.txt
+++ /dev/null
@@ -1,4 +0,0 @@
--r base.txt
-
-Django>=3.0,<3.1
-django-cms>=3.8,<3.9
diff --git a/tests/requirements/dj32_cms38.txt b/tests/requirements/dj32_cms38.txt
deleted file mode 100644
index 4c2ed206f..000000000
--- a/tests/requirements/dj32_cms38.txt
+++ /dev/null
@@ -1,4 +0,0 @@
--r base.txt
-
-Django>=3.2,<3.3
-django-cms>=3.8,<3.9
diff --git a/tests/settings.py b/tests/settings.py
index 4965f359c..ff790f5a7 100644
--- a/tests/settings.py
+++ b/tests/settings.py
@@ -24,6 +24,7 @@ def __getitem__(self, item):
HELPER_SETTINGS = {
+ 'SECRET_KEY': 'djangocms-text-ckeditor-test-suite',
'INSTALLED_APPS': [
'easy_thumbnails',
'filer',
@@ -89,7 +90,7 @@ def __getitem__(self, item):
},
'plugin_labels': {
'LinkPlugin': 'Add a link',
- }
+ },
},
},
'FILE_UPLOAD_TEMP_DIR': mkdtemp(),
@@ -120,7 +121,7 @@ def _helper_patch(*args, **kwargs):
def test():
from app_helper import runner
- runner.cms('djangocms_text_ckeditor')
+ runner.cms('djangocms_text_ckeditor', extra_args=[])
def run():
diff --git a/tests/test_app/admin.py b/tests/test_app/admin.py
index 6bfd458a5..32ccadfb0 100644
--- a/tests/test_app/admin.py
+++ b/tests/test_app/admin.py
@@ -17,7 +17,7 @@ class PizzaAdmin(admin.ModelAdmin):
# NOTE: Disabled because when PizzaAdmin uses a collapsed
# class then the order of javascript libs is incorrect.
# 'classes': ('collapse',),
- 'fields': ('allergens',)
+ 'fields': ('allergens',),
}),
)
inlines = [ToppingInlineAdmin]
diff --git a/tests/test_app/cms_plugins.py b/tests/test_app/cms_plugins.py
index 3a80fc00c..ac7e3af16 100644
--- a/tests/test_app/cms_plugins.py
+++ b/tests/test_app/cms_plugins.py
@@ -5,9 +5,8 @@
from cms.plugin_pool import plugin_pool
from cms.utils.plugins import get_plugin_model
-from tests.test_app.models import DummyLink, DummySpacer
-
from djangocms_text_ckeditor.cms_plugins import TextPlugin
+from tests.test_app.models import DummyLink, DummySpacer
@plugin_pool.register_plugin
diff --git a/tests/test_field.py b/tests/test_field.py
index e788564a6..679a31831 100644
--- a/tests/test_field.py
+++ b/tests/test_field.py
@@ -2,10 +2,10 @@
from django.utils.safestring import SafeData
from djangocms_helper.base_test import BaseTestCase
-from tests.test_app.forms import SimpleTextForm
-from tests.test_app.models import SimpleText
from djangocms_text_ckeditor.fields import HTMLFormField
+from tests.test_app.forms import SimpleTextForm
+from tests.test_app.models import SimpleText
class HtmlFieldTestCase(BaseTestCase):
@@ -24,8 +24,8 @@ class FieldTestCase(BaseTestCase):
'src="http://www.w3schools.com"></iframe>')
text_with_script = ('some non malicious text
'
'')
- text_with_script_escaped = (u'some non malicious text
<script>'
- u'alert("Hello! I am an alert box!");</script>')
+ text_with_script_escaped = ('some non malicious text
<script>'
+ 'alert("Hello! I am an alert box!");</script>')
def test_model_field_text_is_safe(self):
original = 'Hello There
'
diff --git a/tests/test_html.py b/tests/test_html.py
index 87dc48679..c59bc280d 100644
--- a/tests/test_html.py
+++ b/tests/test_html.py
@@ -78,7 +78,7 @@ def test_custom_protocol_enabled(self):
self.assertEqual('', text)
def test_clean_html_with_sanitize_enabled(self):
- old_TEXT_HTML_SANITIZE = settings.TEXT_HTML_SANITIZE
+ old_text_html_sanitize = settings.TEXT_HTML_SANITIZE
settings.TEXT_HTML_SANITIZE = True
parser = html._get_default_parser()
@@ -91,10 +91,10 @@ def test_clean_html_with_sanitize_enabled(self):
try:
self.assertHTMLEqual('foo', cleaned)
finally:
- settings.TEXT_HTML_SANITIZE = old_TEXT_HTML_SANITIZE
+ settings.TEXT_HTML_SANITIZE = old_text_html_sanitize
def test_clean_html_with_sanitize_disabled(self):
- old_TEXT_HTML_SANITIZE = settings.TEXT_HTML_SANITIZE
+ old_text_html_sanitize = settings.TEXT_HTML_SANITIZE
settings.TEXT_HTML_SANITIZE = False
parser = html._get_default_parser()
@@ -107,4 +107,4 @@ def test_clean_html_with_sanitize_disabled(self):
try:
self.assertHTMLEqual(original, cleaned)
finally:
- settings.TEXT_HTML_SANITIZE = old_TEXT_HTML_SANITIZE
+ settings.TEXT_HTML_SANITIZE = old_text_html_sanitize
diff --git a/tests/test_migrations.py b/tests/test_migrations.py
index e87a35649..57624cb0b 100644
--- a/tests/test_migrations.py
+++ b/tests/test_migrations.py
@@ -27,4 +27,4 @@ def test_for_missing_migrations(self):
status_code = '0'
if status_code == '1':
- self.fail('There are missing migrations:\n {}'.format(output.getvalue()))
+ self.fail(f'There are missing migrations:\n {output.getvalue()}')
diff --git a/tests/test_plugin.py b/tests/test_plugin.py
index 4d7cee3cd..1a5a89bae 100644
--- a/tests/test_plugin.py
+++ b/tests/test_plugin.py
@@ -15,15 +15,13 @@
from cms.models import CMSPlugin, Page, Title
from cms.utils.urlutils import admin_reverse
-from tests.test_app.cms_plugins import DummyChildPlugin, DummyParentPlugin
-
from djangocms_text_ckeditor.cms_plugins import TextPlugin
from djangocms_text_ckeditor.compat import get_page_placeholders
from djangocms_text_ckeditor.models import Text
from djangocms_text_ckeditor.utils import (
- _plugin_tags_to_html, _render_cms_plugin, plugin_tags_to_admin_html,
- plugin_tags_to_id_list, plugin_to_tag,
+ _plugin_tags_to_html, _render_cms_plugin, plugin_tags_to_admin_html, plugin_tags_to_id_list, plugin_to_tag,
)
+from tests.test_app.cms_plugins import DummyChildPlugin, DummyParentPlugin
from .base import BaseTestCase
@@ -45,14 +43,14 @@ class PluginActionsTestCase(BaseTestCase):
def get_custom_admin_url(self, plugin_class, name):
plugin_type = plugin_class.__name__.lower()
- url_name = '%s_%s_%s' % (plugin_class.model._meta.app_label, plugin_type, name)
+ url_name = f'{plugin_class.model._meta.app_label}_{plugin_type}_{name}'
return admin_reverse(url_name)
def _add_child_plugin(self, text_plugin, plugin_type='PicturePlugin', data_suffix=None):
- name = '{} record'.format(plugin_type)
+ name = f'{plugin_type} record'
if data_suffix is not None:
- name = '{} {}'.format(name, data_suffix)
+ name = f'{name} {data_suffix}'
basic_plugins = {
'LinkPlugin': {
@@ -73,7 +71,7 @@ def _add_child_plugin(self, text_plugin, plugin_type='PicturePlugin', data_suffi
plugin_type,
'en',
target=text_plugin,
- **data
+ **data,
)
return plugin
@@ -92,7 +90,7 @@ def _do_replace(obj, match):
return _plugin_tags_to_html(text, output_func=_do_replace)
def add_plugin_to_text(self, text_plugin, plugin):
- text_plugin.body = '%s %s' % (text_plugin.body, plugin_to_tag(plugin))
+ text_plugin.body = f'{text_plugin.body} {plugin_to_tag(plugin)}'
text_plugin.save()
return text_plugin
@@ -236,7 +234,7 @@ def _get_text_plugin_with_children():
simple_placeholder,
'TextPlugin',
'en',
- body='Text plugin we copy child plugins to'
+ body='Text plugin we copy child plugins to',
)
_add_child_plugins_to_text_plugin(text_plugin)
return text_plugin
@@ -550,7 +548,7 @@ def test_render_child_plugin_endpoint(self):
request = self.get_request()
action_token = text_plugin_class.get_action_token(request, text_plugin)
endpoint = self.get_custom_admin_url(TextPlugin, 'render_plugin')
- endpoint += '?token={}&plugin={}'.format(action_token, child_plugin.pk)
+ endpoint += f'?token={action_token}&plugin={child_plugin.pk}'
response = self.client.get(endpoint)
self.assertEqual(response.status_code, 200)
@@ -573,7 +571,7 @@ def test_render_child_plugin_endpoint(self):
request = self.get_request()
action_token = text_plugin_class.get_action_token(request, text_plugin)
endpoint = self.get_custom_admin_url(TextPlugin, 'render_plugin')
- endpoint += '?token={}&plugin={}'.format(action_token, child_plugin.pk)
+ endpoint += f'?token={action_token}&plugin={child_plugin.pk}'
response = self.client.get(endpoint)
self.assertEqual(response.status_code, 200)
@@ -608,7 +606,7 @@ def test_render_child_plugin_endpoint_calls_context_processors(self):
request = self.get_request()
action_token = text_plugin_class.get_action_token(request, text_plugin)
endpoint = self.get_custom_admin_url(TextPlugin, 'render_plugin')
- endpoint += '?token={}&plugin={}'.format(action_token, child_plugin.pk)
+ endpoint += f'?token={action_token}&plugin={child_plugin.pk}'
response = self.client.get(endpoint)
self.assertEqual(response.status_code, 200)
@@ -645,7 +643,7 @@ def test_render_child_plugin_permissions(self):
request = self.get_request()
action_token = text_plugin_class.get_action_token(request, text_plugin)
endpoint = self.get_custom_admin_url(TextPlugin, 'render_plugin')
- endpoint += '?token={}&plugin={}'.format(action_token, child_plugin.pk)
+ endpoint += f'?token={action_token}&plugin={child_plugin.pk}'
response = self.client.get(endpoint)
self.assertContains(response, '403 Forbidden
', status_code=403, html=True)
@@ -678,7 +676,7 @@ def test_render_child_plugin_token_validation(self):
with self.login_user_context(self.get_superuser()):
action_token = text_plugin_class.get_action_token(request, text_plugin)
endpoint = self.get_custom_admin_url(TextPlugin, 'render_plugin')
- endpoint += '?token={}&plugin={}'.format(action_token, child_plugin.pk)
+ endpoint += f'?token={action_token}&plugin={child_plugin.pk}'
response = self.client.get(endpoint)
self.assertEqual(response.status_code, 400)
@@ -698,7 +696,7 @@ def test_render_child_plugin_token_validation(self):
request = self.get_request()
action_token = text_plugin_class.get_action_token(request, text_plugin_2)
endpoint = self.get_custom_admin_url(TextPlugin, 'render_plugin')
- endpoint += '?token={}&plugin={}'.format(action_token, child_plugin.pk)
+ endpoint += f'?token={action_token}&plugin={child_plugin.pk}'
response = self.client.get(endpoint)
self.assertEqual(response.status_code, 400)
@@ -724,7 +722,7 @@ def test_custom_ckeditor_body_css_classes(self):
simple_placeholder,
'TextPlugin',
'en',
- body="Content",
+ body='Content',
target=child_plugin,
)
@@ -743,7 +741,7 @@ def test_render_plugin(self):
plugin = self._add_child_plugin(
text_plugin,
plugin_type='LinkPlugin',
- data_suffix=i
+ data_suffix=i,
)
text_plugin = self.add_plugin_to_text(text_plugin, plugin)
@@ -766,7 +764,7 @@ def test_render_extended_plugin(self):
plugin = self._add_child_plugin(
text_plugin,
plugin_type='LinkPlugin',
- data_suffix=i
+ data_suffix=i,
)
text_plugin = self.add_plugin_to_text(text_plugin, plugin)
@@ -808,7 +806,7 @@ def test_copy_plugin_integrity(self):
'fr',
'test-page-fr',
simple_page,
- slug='test-page-fr'
+ slug='test-page-fr',
)
self.assertEqual(CMSPlugin.objects.filter(language='en').count(), 3)
@@ -899,7 +897,7 @@ def test_text_plugin_xss(self):
data = {
'body': (
'divcontent
acontent'
- )
+ ),
}
response = self.client.post(endpoint, data)
self.assertEqual(response.status_code, 200)
@@ -908,7 +906,7 @@ def test_text_plugin_xss(self):
@unittest.skipUnless(
HAS_DJANGOCMS_TRANSLATIONS and HAS_DJANGOCMS_TRANSFER,
- 'Optional dependencies for tests are not installed.'
+ 'Optional dependencies for tests are not installed.',
)
class DjangoCMSTranslationsIntegrationTestCase(BaseTestCase):
def setUp(self):
diff --git a/tests/test_widget.py b/tests/test_widget.py
index bd697c4d4..488d0e18e 100644
--- a/tests/test_widget.py
+++ b/tests/test_widget.py
@@ -22,7 +22,7 @@ def tearDown(self):
def test_sub_plugin_config(self):
page = create_page(title='home', template='page.html', language='en')
plugin = add_plugin(
- get_page_placeholders(page, 'en').get(slot='content'), 'TextPlugin', 'en', body='some text'
+ get_page_placeholders(page, 'en').get(slot='content'), 'TextPlugin', 'en', body='some text',
)
endpoint = self.get_change_plugin_uri(plugin)
@@ -47,9 +47,9 @@ def test_child_plugin(self):
plugin = add_plugin(placeholder, 'TextPlugin', 'en', body='Lorem ipsum')
test_image = self.create_filer_image_object()
pic_plugin = add_plugin(
- placeholder, 'PicturePlugin', 'en', target=plugin, picture=test_image
+ placeholder, 'PicturePlugin', 'en', target=plugin, picture=test_image,
)
- plugin.body = '%s %s' % (plugin.body, plugin_to_tag(pic_plugin))
+ plugin.body = f'{plugin.body} {plugin_to_tag(pic_plugin)}'
plugin.save()
page.publish('en')
response = self.client.get(page.get_absolute_url('en'))
@@ -71,7 +71,7 @@ def test_text_sanitizer(self):
placeholder = get_page_placeholders(page, 'en').get(slot='content')
add_plugin(
placeholder, 'TextPlugin', 'en',
- body='some text'
+ body='some text',
)
language = 'en'
page.publish(language)
@@ -87,7 +87,7 @@ def test_text_sanitizer_no_settings(self):
placeholder = get_page_placeholders(page, 'en').get(slot='content')
add_plugin(
placeholder, 'TextPlugin', 'en',
- body='some text'
+ body='some text',
)
language = 'en'
page.publish(language)
diff --git a/tox.ini b/tox.ini
index 60555a665..adb9950ad 100644
--- a/tox.ini
+++ b/tox.ini
@@ -3,49 +3,16 @@ envlist =
flake8
isort
frontend
- py{35,36,37,38}-dj{22}-cms{37,38}
- py{36,37,38}-dj{30}-cms{37,38}
- py{36,37,38}-dj{31}-cms{38}
- py{36,37,38}-dj{32}-cms{38,39}
+ py{37,38}-dj{22}-cms{37,38}
+ py{37,38}-dj{31}-cms{38,39}
+ py{38,39,310}-dj{32}-cms{39}
skip_missing_interpreters=True
-[flake8]
-ignore = E251,E128,E501
-max-line-length = 119
-exclude =
- *.egg-info,
- .eggs,
- .git,
- .settings,
- .tox,
- build,
- data,
- dist,
- docs,
- *migrations*,
- requirements,
- tmp,
- *node_modules*
-
-[isort]
-line_length = 79
-skip = manage.py, *migrations*, .tox, .eggs, data
-include_trailing_comma = true
-multi_line_output = 5
-not_skip = __init__.py
-lines_after_imports = 2
-default_section = THIRDPARTY
-sections = FUTURE, STDLIB, DJANGO, CMS, THIRDPARTY, FIRSTPARTY, LIB, LOCALFOLDER
-known_first_party = djangocms_text_ckeditor
-known_cms = cms, menus
-known_django = django
-
[testenv]
deps =
-r{toxinidir}/tests/requirements/base.txt
dj22: Django>=2.2,<3.0
- dj30: Django>=3.0,<3.1
dj31: Django>=3.1,<3.2
dj32: Django>=3.2,<3.3
cms37: django-cms>=3.7,<3.8
@@ -63,8 +30,8 @@ commands = flake8
[testenv:isort]
deps = isort
-commands = isort -c -rc -df djangocms_text_ckeditor
-skip_install = true
+commands = isort --check-only --diff {toxinidir}
+basepython = python3.9
[testenv:frontend]
whitelist_externals =