diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 00000000000..27fd5ce7c6e --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,42 @@ +name: "CodeQL" + +on: + push: + branches: [ "develop", "develop-4", "release/0.10.x", "release/2.1.x", "release/2.2.x", "release/2.3.x", "release/2.4.x", "release/3.0.x", "release/3.1.x", "release/3.2.x", "release/3.3.x", "release/3.4.x", "release/3.5.x", "release/3.6.x", "release/3.7.x", "release/3.8.x", "release/3.9.x", "release/3.10.x", "release/3.11.x", "release/4.0.x", "release/4.0.0.x", "release/4.0.1.x", "release/4.1.x" ] + pull_request: + branches: [ "develop" ] + schedule: + - cron: "40 4 * * 6" + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ python, javascript ] + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + queries: +security-and-quality + + - name: Autobuild + uses: github/codeql-action/autobuild@v2 + if: ${{ matrix.language == 'python' || matrix.language == 'javascript' }} + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 + with: + category: "/language:${{ matrix.language }}" diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 28f47cae1d3..d6960759ea2 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -12,20 +12,23 @@ jobs: name: docs steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Set up Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v3 with: - python-version: '3.9' + python-version: "3.12" cache: 'pip' - name: Cache dependencies - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ hashFiles('docs/requirements.txt') }} restore-keys: | ${{ runner.os }}-pip- - run: python -m pip install -r docs/requirements.txt + - run: python setup.py install + - run: codespell -w *.rst + - run: codespell -w --skip docs/spelling_wordlist docs - name: Build docs run: | cd docs diff --git a/.github/workflows/frontend.yml b/.github/workflows/frontend.yml index 1277040bf11..ffba12b0f00 100644 --- a/.github/workflows/frontend.yml +++ b/.github/workflows/frontend.yml @@ -14,9 +14,9 @@ jobs: node-version: ['18'] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v2 + uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} - run: npm install diff --git a/.github/workflows/lint-pr.yml b/.github/workflows/lint-pr.yml new file mode 100644 index 00000000000..fc5d65d7cfb --- /dev/null +++ b/.github/workflows/lint-pr.yml @@ -0,0 +1,20 @@ +name: "Lint PR" + +# Validates PR titles against the conventional commit spec +# https://github.com/commitizen/conventional-commit-types + +on: + pull_request_target: + types: + - opened + - edited + - synchronize + +jobs: + main: + name: Validate PR title + runs-on: ubuntu-latest + steps: + - uses: amannn/action-semantic-pull-request@v4 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/linters.yml b/.github/workflows/linters.yml index e3696c0f371..92e6c73df5a 100644 --- a/.github/workflows/linters.yml +++ b/.github/workflows/linters.yml @@ -17,7 +17,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v4 with: - python-version: "3.11" + python-version: "3.12" cache: 'pip' - run: | python -m pip install --upgrade pip diff --git a/.github/workflows/publish-to-live-pypi.yml b/.github/workflows/publish-to-live-pypi.yml index 52f112f8dc7..efafc715270 100644 --- a/.github/workflows/publish-to-live-pypi.yml +++ b/.github/workflows/publish-to-live-pypi.yml @@ -11,10 +11,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - name: Set up Python 3.10 + - name: Set up Python 3.12 uses: actions/setup-python@v3 with: - python-version: '3.10' + python-version: '3.12' - name: Install pypa/build run: >- diff --git a/.github/workflows/publish-to-test-pypi.yml b/.github/workflows/publish-to-test-pypi.yml index d56b6da5113..04989836709 100644 --- a/.github/workflows/publish-to-test-pypi.yml +++ b/.github/workflows/publish-to-test-pypi.yml @@ -12,10 +12,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - name: Set up Python 3.10 + - name: Set up Python 3.12 uses: actions/setup-python@v3 with: - python-version: '3.10' + python-version: '3.12' - name: Install pypa/build run: >- diff --git a/.github/workflows/spelling.yml b/.github/workflows/spelling.yml new file mode 100644 index 00000000000..71995b9291a --- /dev/null +++ b/.github/workflows/spelling.yml @@ -0,0 +1,16 @@ +name: django CMS spelling + +on: [push, pull_request] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + codespell: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: codespell + uses: codespell-project/actions-codespell@master diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index af71b75ce55..ceb4b69160f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,7 +12,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: [ 3.8, 3.9, '3.10', '3.11' ] # latest release minus two + python-version: [ 3.9, '3.10', '3.11', '3.12' ] # latest release minus two requirements-file: [ django-2.2.txt, django-3.2.txt, @@ -57,6 +57,7 @@ jobs: pip install pytest pip install -r test_requirements/${{ matrix.requirements-file }} pip install -r test_requirements/databases.txt + pip install -r docs/requirements.txt python setup.py install - name: Test with django test runner @@ -71,7 +72,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: [ 3.8, 3.9, '3.10', '3.11' ] # latest release minus two + python-version: [ 3.9, '3.10', '3.11', '3.12' ] # latest release minus two requirements-file: [ django-2.2.txt, django-3.2.txt, @@ -115,6 +116,7 @@ jobs: pip install pytest pip install -r test_requirements/${{ matrix.requirements-file }} pip install -r test_requirements/databases.txt + pip install -r docs/requirements.txt python setup.py install @@ -129,7 +131,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: [ 3.8, 3.9, '3.10', '3.11' ] # latest release minus two + python-version: [ 3.9, '3.10', '3.11', '3.12' ] # latest release minus two requirements-file: [ django-2.2.txt, django-3.2.txt, @@ -142,8 +144,6 @@ jobs: ubuntu-20.04, ] exclude: - - requirements-file: django-5.0.txt - python-version: 3.8 - requirements-file: django-5.0.txt python-version: 3.9 @@ -161,6 +161,7 @@ jobs: python -m pip install --upgrade pip pip install pytest pip install -r test_requirements/${{ matrix.requirements-file }} + pip install -r docs/requirements.txt python setup.py install - name: Test with django test runner @@ -173,7 +174,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ['3.11'] + python-version: ['3.12'] requirements-file: ['requirements_base.txt'] django-version: [ 'https://github.com/django/django/archive/main.tar.gz' @@ -195,6 +196,7 @@ jobs: python -m pip install --upgrade pip pip install -r test_requirements/${{ matrix.requirements-file }} pip install pytest ${{ matrix.django-version }} + pip install --upgrade setuptools python setup.py install - name: Test with django test runner @@ -208,7 +210,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ['3.11'] + python-version: ['3.12'] requirements-file: ['requirements_base.txt'] django-version: [ 'https://github.com/django/django/archive/main.tar.gz' @@ -244,6 +246,7 @@ jobs: pip install -r test_requirements/${{ matrix.requirements-file }} pip install pytest ${{ matrix.django-version }} pip install -r test_requirements/databases.txt + pip install -r docs/requirements.txt python setup.py install - name: Test with django test runner @@ -259,7 +262,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ['3.11'] + python-version: ['3.12'] requirements-file: ['requirements_base.txt'] django-version: [ 'https://github.com/django/django/archive/main.tar.gz' @@ -294,6 +297,7 @@ jobs: pip install -r test_requirements/${{ matrix.requirements-file }} pip install pytest ${{ matrix.django-version }} pip install -r test_requirements/databases.txt + pip install -r docs/requirements.txt python setup.py install - name: Test with django test runner diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a2834231819..d306d46ab5f 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -936,7 +936,7 @@ Thanks to all contributors for their efforts! - Fix issue on django >= 1.6 with page form fields. - Resolve jQuery namespace issues in admin page tree and changeform - Fix issues for PageField in Firefox/Safari -- Fix some Python 3.4 compatibility issue when using proxy modles +- Fix some Python 3.4 compatibility issue when using proxy models - Fix corner case in plugin copy - Documentation fixes - Minor code cleanups diff --git a/cms/admin/forms.py b/cms/admin/forms.py index d11a673e99b..dfe3271a825 100644 --- a/cms/admin/forms.py +++ b/cms/admin/forms.py @@ -1154,7 +1154,7 @@ class Meta: class GenericCmsPermissionForm(forms.ModelForm): - """Generic form for User & Grup permissions in cms + """Generic form for User & Group permissions in cms """ _current_user = None diff --git a/cms/api.py b/cms/api.py index 6a2f61c3a0c..a32a2095cc7 100644 --- a/cms/api.py +++ b/cms/api.py @@ -3,7 +3,7 @@ on the models and managers, because the direct API via models and managers is slightly counterintuitive for developers. -Teh api for both Pages and Plugins has changed significantly since django CMS +The api for both Pages and Plugins has changed significantly since django CMS Version 4. Also, the functions defined in this module do sanity checks on arguments. diff --git a/cms/app_base.py b/cms/app_base.py index 502523d7f18..73a4a1246e7 100644 --- a/cms/app_base.py +++ b/cms/app_base.py @@ -6,7 +6,7 @@ class CMSApp: To create an AppHook subclass ``CMSApp`` in ``cms_apps.py`` :: class MyAppHook(CMSApp): - name = "Problem sovler" + name = "Problem solver" """ #: list of urlconfs: example: ``_urls = ["myapp.urls"]`` _urls = [] @@ -126,7 +126,7 @@ class CMSAppConfig(): CMSAppConfig live in a file called ``cms_config.py``. Apps subclassing ``CMSAppConfig`` can set ``cms_enabled = True`` for their app config to - use django CMS' wizzard functionality. Additional wizzwards are listed in the app config's + use django CMS' wizard functionality. Additional wizzwards are listed in the app config's ``cms_wizzards`` property. The second functionality that django CMS offers is attaching Model objects to the toolbar. To use diff --git a/cms/cms_menus.py b/cms/cms_menus.py index 52e5dc7aeb4..c05cda453af 100644 --- a/cms/cms_menus.py +++ b/cms/cms_menus.py @@ -79,7 +79,7 @@ def get_menu_node_for_page(renderer, page, language, fallbacks=None): if fallbacks is None: fallbacks = [] - # Theses are simple to port over, since they are not calculated. + # These are simple to port over, since they are not calculated. # Other attributes will be added conditionally later. attr = { 'is_page': True, diff --git a/cms/models/managers.py b/cms/models/managers.py index b2a1b771b11..813b780cf55 100644 --- a/cms/models/managers.py +++ b/cms/models/managers.py @@ -133,7 +133,7 @@ def current_content(self, **kwargs): def latest_content(self, **kwargs): """If a versioning package is installed, returns the latest version that matches the - filter given in kwargs including discared or unpublished page content. Without versioning + filter given in kwargs including discarded or unpublished page content. Without versioning every page content is the latest.""" return self.filter(**kwargs) diff --git a/cms/models/permissionmodels.py b/cms/models/permissionmodels.py index bdb5d677395..64502c37f6b 100644 --- a/cms/models/permissionmodels.py +++ b/cms/models/permissionmodels.py @@ -39,10 +39,10 @@ #: Access to page itself and immediate children (1 level) ACCESS_PAGE_AND_CHILDREN = 3 -#: Access to all children (first level and allso their children) +#: Access to all children (first level and also their children) ACCESS_DESCENDANTS = 4 -#: Access to page itself and all children (first level and allso their children) +#: Access to page itself and all children (first level and also their children) ACCESS_PAGE_AND_DESCENDANTS = 5 # binary masks for ACCESS permissions diff --git a/cms/models/pluginmodel.py b/cms/models/pluginmodel.py index 7104cd68ca1..ad77f99f431 100644 --- a/cms/models/pluginmodel.py +++ b/cms/models/pluginmodel.py @@ -63,7 +63,7 @@ def _get_database_cursor(action): @lru_cache(maxsize=None) def plugin_supports_cte(): # This has to be as function because when it's a var it evaluates before - # db is connected and we get OperationalError. MySQL version is retrived + # db is connected and we get OperationalError. MySQL version is retrieved # from db, and it's cached_property. connection = _get_database_connection('write') db_vendor = _get_database_vendor('write') @@ -480,7 +480,7 @@ def get_plugin_media_path(instance, filename): Django requires that unbound function used in fields' definitions to be defined outside the parent class. (see https://docs.djangoproject.com/en/dev/topics/migrations/#serializing-values) - This function is used withing field definition: + This function is used within field definition: file = models.FileField(_("file"), upload_to=get_plugin_media_path) diff --git a/cms/signals/apphook.py b/cms/signals/apphook.py index 97eaf3b613a..5253d8beace 100644 --- a/cms/signals/apphook.py +++ b/cms/signals/apphook.py @@ -39,7 +39,7 @@ def debug_server_restart(**kwargs): try: reload(cms.urls) except NameError: # python3 - from imp import reload + from importlib import reload reload(cms.urls) if 'test' not in sys.argv: msg = 'Application url changed and urls_need_reloading signal fired. ' \ diff --git a/cms/static/cms/js/select2/LICENSE b/cms/static/cms/js/select2/LICENSE index 0247cc76273..49f61fcf343 100644 --- a/cms/static/cms/js/select2/LICENSE +++ b/cms/static/cms/js/select2/LICENSE @@ -13,6 +13,6 @@ http://www.apache.org/licenses/LICENSE-2.0 http://www.gnu.org/licenses/gpl-2.0.html Unless required by applicable law or agreed to in writing, software distributed under the Apache License -or the GPL Licesnse is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +or the GPL License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the Apache License and the GPL License for the specific language governing permissions and limitations under the Apache License and the GPL License. diff --git a/cms/templatetags/cms_admin.py b/cms/templatetags/cms_admin.py index 4c236a9c72d..05abf2f229a 100644 --- a/cms/templatetags/cms_admin.py +++ b/cms/templatetags/cms_admin.py @@ -124,7 +124,7 @@ def get_page_display_name(cms_page): class TreePublishRow(Tag): - """New template tag that renders a pontential menu to be offered with the + """New template tag that renders a potential menu to be offered with the dirty indicators. The core will not display a menu.""" name = "tree_publish_row" options = Options( diff --git a/cms/templatetags/cms_tags.py b/cms/templatetags/cms_tags.py index 57b08bea727..f9a01cb6fb4 100644 --- a/cms/templatetags/cms_tags.py +++ b/cms/templatetags/cms_tags.py @@ -212,7 +212,7 @@ def get_value_for_context(self, context, **kwargs): # return Exceptions regardless of the setting of settings.DEBUG. # # We wish to maintain backwards functionality where the non-as-variant - # of using this tag will raise DNE exceptions only when + # of using this tag will raise DoesNotExist exceptions only when # settings.DEBUG=False. # try: @@ -491,7 +491,7 @@ def render_tag(self, context, **kwargs): def _get_editable_context(self, context, instance, language, edit_fields, view_method, view_url, querystring, editmode=True): """ - Populate the contex with the requested attributes to trigger the changeform + Populate the context with the requested attributes to trigger the changeform """ request = context['request'] if hasattr(request, 'toolbar'): @@ -660,7 +660,7 @@ def _get_empty_context(self, context, instance, edit_fields, language, if edit_fields: extra_context['edit_fields'] = edit_fields.strip().split(",") # If the toolbar is not enabled the following part is just skipped: it - # would cause a perfomance hit for no reason + # would cause a performance hit for no reason if self._is_editable(context.get('request', None)): extra_context.update(self._get_editable_context( extra_context, instance, language, edit_fields, view_method, diff --git a/cms/test_utils/project/app_using_non_feature/cms_config.py b/cms/test_utils/project/app_using_non_feature/cms_config.py index 193f5bf6815..34e73d61b26 100644 --- a/cms/test_utils/project/app_using_non_feature/cms_config.py +++ b/cms/test_utils/project/app_using_non_feature/cms_config.py @@ -2,6 +2,6 @@ class NonFeatureCMSConfig(CMSAppConfig): - # Attempting to use features from a cms app that doesnt define a + # Attempting to use features from a cms app that doesn't define a # configure_app method app_with_feature_not_implemented_enabled = True diff --git a/cms/test_utils/project/emailuserapp/forms.py b/cms/test_utils/project/emailuserapp/forms.py index 127aee2b429..1530dd2903e 100644 --- a/cms/test_utils/project/emailuserapp/forms.py +++ b/cms/test_utils/project/emailuserapp/forms.py @@ -108,6 +108,6 @@ def clean_password(self): """ Regardless of what the user provides, return the initial value. This is done here, rather than on the field, because the - field does not have access to the inital value. + field does not have access to the initial value. """ return self.initial["password"] diff --git a/cms/test_utils/project/mti_pluginapp/models.py b/cms/test_utils/project/mti_pluginapp/models.py index bfcf8cb7102..146bda8f460 100644 --- a/cms/test_utils/project/mti_pluginapp/models.py +++ b/cms/test_utils/project/mti_pluginapp/models.py @@ -40,7 +40,7 @@ class Meta: class TestPluginBetaModel(TestPluginAlphaModel): """ NOTE: This is the subject of our test. A plugin which inherits from - another concrete plugin via MTI or Multi-Table Inheritence. + another concrete plugin via MTI or Multi-Table Inheritance. """ beta = models.CharField('name', blank=False, default='test plugin beta', max_length=32) diff --git a/cms/test_utils/project/sampleapp/cms_apps.py b/cms/test_utils/project/sampleapp/cms_apps.py index 5d1b47ba531..303c9e8b02b 100644 --- a/cms/test_utils/project/sampleapp/cms_apps.py +++ b/cms/test_utils/project/sampleapp/cms_apps.py @@ -72,7 +72,7 @@ def get_urls(self, page=None, language=None, **kwargs): class SampleApp3(CMSApp): - # CMSApp which returns the url directly rather than trough another Python module + # CMSApp which returns the url directly rather than through another Python module name = _("Sample App 3") def get_urls(self, page=None, language=None, **kwargs): diff --git a/cms/test_utils/project/templates/placeholder_tests/outside.html b/cms/test_utils/project/templates/placeholder_tests/outside.html index b265561bc80..827d8e426e4 100644 --- a/cms/test_utils/project/templates/placeholder_tests/outside.html +++ b/cms/test_utils/project/templates/placeholder_tests/outside.html @@ -2,7 +2,7 @@ {% load cms_tags %} {% comment %} -This files hould result in following placeholders: +This files should result in following placeholders: - new_one (from this) - two (from base.html) diff --git a/cms/test_utils/project/templates/placeholder_tests/outside_sekizai.html b/cms/test_utils/project/templates/placeholder_tests/outside_sekizai.html index 5c908b1116b..6ada4bd6b11 100644 --- a/cms/test_utils/project/templates/placeholder_tests/outside_sekizai.html +++ b/cms/test_utils/project/templates/placeholder_tests/outside_sekizai.html @@ -2,7 +2,7 @@ {% load cms_tags %} {% comment %} -This files hould result in following placeholders: +This files should result in following placeholders: - new_one (from this) - two (from base.html) diff --git a/cms/test_utils/project/templates/placeholder_tests/test_one.html b/cms/test_utils/project/templates/placeholder_tests/test_one.html index a04faba93ad..b123332bbdb 100644 --- a/cms/test_utils/project/templates/placeholder_tests/test_one.html +++ b/cms/test_utils/project/templates/placeholder_tests/test_one.html @@ -3,7 +3,7 @@ {% load cms_tags %} {% comment %} -This files hould result in following placeholders: +This files should result in following placeholders: - new_one (from this) - two (from base.html) diff --git a/cms/test_utils/project/templates/placeholder_tests/test_one_sekizai.html b/cms/test_utils/project/templates/placeholder_tests/test_one_sekizai.html index cf9d8cd3546..84e6ee66d99 100644 --- a/cms/test_utils/project/templates/placeholder_tests/test_one_sekizai.html +++ b/cms/test_utils/project/templates/placeholder_tests/test_one_sekizai.html @@ -3,7 +3,7 @@ {% load cms_tags %} {% comment %} -This files hould result in following placeholders: +This files should result in following placeholders: - new_one (from this) - two (from base.html) diff --git a/cms/test_utils/project/templates/placeholder_tests/test_two.html b/cms/test_utils/project/templates/placeholder_tests/test_two.html index cf1a6d77ae8..76465ec8fc8 100644 --- a/cms/test_utils/project/templates/placeholder_tests/test_two.html +++ b/cms/test_utils/project/templates/placeholder_tests/test_two.html @@ -3,7 +3,7 @@ {% load cms_tags %} {% comment %} -This files hould result in following placeholders: +This files should result in following placeholders: - child (from child.html) - three (from base.html) @@ -14,4 +14,4 @@ {% include "placeholder_tests/child.html" %} {% endblock %} -{% block two %}{% endblock %} \ No newline at end of file +{% block two %}{% endblock %} diff --git a/cms/test_utils/util/context_managers.py b/cms/test_utils/util/context_managers.py index ddcd5e7fc0b..5e5792f0c7f 100644 --- a/cms/test_utils/util/context_managers.py +++ b/cms/test_utils/util/context_managers.py @@ -62,7 +62,7 @@ class TemporaryDirectory: with TemporaryDirectory() as tmpdir: ... - Upon exiting the context, the directory and everthing contained + Upon exiting the context, the directory and everything contained in it are removed. """ diff --git a/cms/tests/test_admin.py b/cms/tests/test_admin.py index a7f435b88b6..03a28def8de 100644 --- a/cms/tests/test_admin.py +++ b/cms/tests/test_admin.py @@ -828,7 +828,7 @@ def test_editpage_contentsize(self): self.assertEqual(response.status_code, 200) old_response_size = len(response.content) old_user_count = get_user_model().objects.count() - # create additionals user and reload the page + # create additional user and reload the page get_user_model().objects.create_user(username=USER_NAME, email=USER_NAME + '@django-cms.org', password=USER_NAME) user_count = get_user_model().objects.count() @@ -1065,12 +1065,12 @@ def test_move_node(self): def test_create_page_language(self): """tests if the New Page button creates a page content object in the language specified by the language selectors. The creates pages in all languages and checks if the "+" button - creats a child in the same language""" + creates a child in the same language""" admin_user, staff = self._get_guys() pagecontent_admin = self.pagecontent_admin_class - languages = get_language_list() # Run trough all languages + languages = get_language_list() # Run through all languages url = admin_reverse("cms_pagecontent_changelist") add_url = admin_reverse("cms_pagecontent_add") # "Add page" button self.assertIn("/en/", add_url + "?language=en") # English admin (default in tests) diff --git a/cms/tests/test_management.py b/cms/tests/test_management.py index 3310570e06b..fbd2fe2b9b5 100644 --- a/cms/tests/test_management.py +++ b/cms/tests/test_management.py @@ -470,7 +470,7 @@ def test_copy_sites(self): def test_copy_existing_title(self): """ - Even if a title already exists the copy is successfull, the original + Even if a title already exists the copy is successful, the original title remains untouched """ site = 1 diff --git a/cms/tests/test_menu.py b/cms/tests/test_menu.py index cdfaedd904c..b1accefac3b 100644 --- a/cms/tests/test_menu.py +++ b/cms/tests/test_menu.py @@ -873,7 +873,7 @@ def test_build_nodes_inner_for_broken_menu(self): node4 node3 - + node2 node1 ''' diff --git a/cms/tests/test_nested_plugins.py b/cms/tests/test_nested_plugins.py index bd6657b48ad..0fe66fd66ea 100644 --- a/cms/tests/test_nested_plugins.py +++ b/cms/tests/test_nested_plugins.py @@ -460,7 +460,7 @@ def test_nested_plugin_on_page(self): # add a plugin pre_nesting_body = "

the nested text plugin with a link inside

" text_plugin = add_plugin(page_one_ph_two, "TextPlugin", "en", body=pre_nesting_body) - # prepare nestin plugin + # prepare nesting plugin page_one_ph_two = self.reload(page_one_ph_two) text_plugin = self.reload(text_plugin) link_plugin = add_plugin(page_one_ph_two, "LinkPlugin", "en", target=text_plugin) @@ -607,13 +607,13 @@ def test_copy_page_nested_plugin(self): # check the stored placeholders org vs copy msg = 'placehoder ids copy:%s org:%s copied page %s are identical - tree broken' % ( page_two_ph_one.pk, page_one_ph_one.pk, page_two.pk) - self.assertNotEquals(page_two_ph_one.pk, page_one_ph_one.pk, msg) + self.assertNotEqual(page_two_ph_one.pk, page_one_ph_one.pk, msg) msg = 'placehoder ids copy:%s org:%s copied page %s are identical - tree broken' % ( page_two_ph_two.pk, page_one_ph_two.pk, page_two.pk) - self.assertNotEquals(page_two_ph_two.pk, page_one_ph_two.pk, msg) + self.assertNotEqual(page_two_ph_two.pk, page_one_ph_two.pk, msg) msg = 'placehoder ids copy:%s org:%s copied page %s are identical - tree broken' % ( page_two_ph_three.pk, page_one_ph_three.pk, page_two.pk) - self.assertNotEquals(page_two_ph_three.pk, page_one_ph_three.pk, msg) + self.assertNotEqual(page_two_ph_three.pk, page_one_ph_three.pk, msg) # get the plugins from the original page org_placeholder_one_plugins = page_one_ph_one.get_plugins() self.assertEqual(len(org_placeholder_one_plugins), 1) @@ -663,12 +663,12 @@ def test_copy_page_nested_plugin(self): if instance.body.startswith(pre_nesting_body): copied_nested_text_plugin = instance break - msg = "orginal nested text plugin not found" - self.assertNotEquals(org_nested_text_plugin, None, msg=msg) + msg = "original nested text plugin not found" + self.assertNotEqual(org_nested_text_plugin, None, msg=msg) msg = "copied nested text plugin not found" - self.assertNotEquals(copied_nested_text_plugin, None, msg=msg) + self.assertNotEqual(copied_nested_text_plugin, None, msg=msg) # get the children ids of the texplugin with a nested link - # to check if the body of the text is genrated correctly + # to check if the body of the text is generated correctly org_link_child_plugin = org_nested_text_plugin.get_children()[0] copied_link_child_plugin = copied_nested_text_plugin.get_children()[0] # validate the textplugin body texts @@ -688,7 +688,7 @@ def test_copy_page_nested_plugin(self): # now reverse lookup the placeholders from the plugins org_placeholder = org_link_child_plugin.placeholder copied_placeholder = copied_link_child_plugin.placeholder - msg = "placeholder of the orginal plugin and copied plugin are the same" + msg = "placeholder of the original plugin and copied plugin are the same" ok = ((org_placeholder.id != copied_placeholder.id)) self.assertTrue(ok, msg) @@ -726,7 +726,7 @@ def test_copy_page_nested_plugin_moved_parent_plugin(self): pre_nesting_body = "

the nested text plugin with a link inside

" text_plugin_two = add_plugin(page_one_ph_two, "TextPlugin", "en", body=pre_nesting_body) text_plugin_two = self.reload(text_plugin_two) - # prepare nestin plugin + # prepare nesting plugin page_one_ph_two = self.reload(page_one_ph_two) text_plugin_two = self.reload(text_plugin_two) link_plugin = add_plugin(page_one_ph_two, "LinkPlugin", "en", target=text_plugin_two) @@ -813,7 +813,7 @@ def test_copy_page_nested_plugin_moved_parent_plugin(self): "placeholder count is not grown") self.assertEqual(after_copy_page_count, 3, "no new page after copy") # validate the structure - # orginal placeholder + # original placeholder page_one = self.reload(page_one) page_one_ph_one = page_one.get_placeholders("en").get(slot="col_sidebar") page_one_ph_two = page_one.get_placeholders("en").get(slot="col_left") @@ -839,13 +839,13 @@ def test_copy_page_nested_plugin_moved_parent_plugin(self): # check the stored placeholders org vs copy msg = u'placehoder ids copy:%s org:%s copied page %s are identical - tree broken' % ( page_two_ph_one.pk, page_one_ph_one.pk, page_two.pk) - self.assertNotEquals(page_two_ph_one.pk, page_one_ph_one.pk, msg) + self.assertNotEqual(page_two_ph_one.pk, page_one_ph_one.pk, msg) msg = u'placehoder ids copy:%s org:%s copied page %s are identical - tree broken' % ( page_two_ph_two.pk, page_one_ph_two.pk, page_two.pk) - self.assertNotEquals(page_two_ph_two.pk, page_one_ph_two.pk, msg) + self.assertNotEqual(page_two_ph_two.pk, page_one_ph_two.pk, msg) msg = u'placehoder ids copy:%s org:%s copied page %s are identical - tree broken' % ( page_two_ph_three.pk, page_one_ph_three.pk, page_two.pk) - self.assertNotEquals(page_two_ph_three.pk, page_one_ph_three.pk, msg) + self.assertNotEqual(page_two_ph_three.pk, page_one_ph_three.pk, msg) # get the plugins from the original page org_placeholder_one_plugins = page_one_ph_one.get_plugins() self.assertEqual(len(org_placeholder_one_plugins), 1) @@ -895,10 +895,10 @@ def test_copy_page_nested_plugin_moved_parent_plugin(self): if instance.body.startswith(pre_nesting_body): copied_nested_text_plugin = instance break - msg = "orginal nested text plugin not found" - self.assertNotEquals(org_nested_text_plugin, None, msg=msg) + msg = "original nested text plugin not found" + self.assertNotEqual(org_nested_text_plugin, None, msg=msg) msg = "copied nested text plugin not found" - self.assertNotEquals(copied_nested_text_plugin, None, msg=msg) + self.assertNotEqual(copied_nested_text_plugin, None, msg=msg) # get the children ids of the texplugin with a nested link # to check if the body of the text is generated correctly org_link_child_plugin = org_nested_text_plugin.get_children()[0] @@ -920,7 +920,7 @@ def test_copy_page_nested_plugin_moved_parent_plugin(self): # now reverse lookup the placeholders from the plugins org_placeholder = org_link_child_plugin.placeholder copied_placeholder = copied_link_child_plugin.placeholder - msg = "placeholder of the orginal plugin and copied plugin are the same" + msg = "placeholder of the original plugin and copied plugin are the same" self.assertNotEqual(org_placeholder.id, copied_placeholder.id, msg) def test_add_child_plugin(self): diff --git a/cms/tests/test_permmod.py b/cms/tests/test_permmod.py index 0b278cc0178..7b57fd2395b 100644 --- a/cms/tests/test_permmod.py +++ b/cms/tests/test_permmod.py @@ -560,7 +560,7 @@ def test_emulate_admin_index(self): ] for user in USERS: user.set_password('staff') - # re-use the same methods the UserPage form does. + # reuse the same methods the UserPage form does. # Note that it internally calls .save(), as we've not done so. save_permissions({ 'can_add_page': True, diff --git a/cms/tests/test_placeholder.py b/cms/tests/test_placeholder.py index 1d7a473b287..20295a09536 100644 --- a/cms/tests/test_placeholder.py +++ b/cms/tests/test_placeholder.py @@ -213,7 +213,7 @@ def test_inter_placeholder_nested_plugin_move(self): # language_fun = ('en', 'de', 'it', 'de-formal') # symmetric and asymmetric plugin numbers in target placeholder, source placeholder - # (1, 10) One plugin in the target palceholder, 10 plugins to be moved + # (1, 10) One plugin in the target placeholder, 10 plugins to be moved # (5, 5) Same size situation # (10, 1) Ten plugins in the target placeholder, 1 plugin to be moved for n1, n2 in ((1, 10), (10, 1), (5, 5)): @@ -252,7 +252,7 @@ def test_inter_placeholder_nested_plugin_move(self): ) # The result in theory: # Parent Target Placeholder - # Parent Source Palceholder <-- Moved plugin parent + # Parent Source Placeholder <-- Moved plugin parent # Children Source Placeholder <-- Moved plugin children # Children Target Placeholder left = ( diff --git a/cms/tests/test_plugins.py b/cms/tests/test_plugins.py index 736db350a7e..a342e2e78a4 100644 --- a/cms/tests/test_plugins.py +++ b/cms/tests/test_plugins.py @@ -1080,7 +1080,7 @@ class PluginsMetaOptionsTests(TestCase): # these plugins are inlined because, due to the nature of the #992 # ticket, we cannot actually import a single file with all the # plugin variants in, because that calls __new__, at which point the - # error with splitted occurs. + # error with split occurs. def test_meta_options_as_defaults(self): ''' handling when a CMSPlugin meta options are computed defaults ''' diff --git a/cms/tests/test_signals.py b/cms/tests/test_signals.py index 19301446475..850e189aec2 100644 --- a/cms/tests/test_signals.py +++ b/cms/tests/test_signals.py @@ -41,7 +41,7 @@ def test_urls_need_reloading_signal_set_apphook(self): self.assertRedirects(response, redirect_to) self.assertEqual(env.call_count, 1) new_revision, _ = UrlconfRevision.get_or_create_revision() - self.assertNotEquals(current_revision, new_revision) + self.assertNotEqual(current_revision, new_revision) def test_urls_need_reloading_signal_delete(self): superuser = self.get_superuser() @@ -63,7 +63,7 @@ def test_urls_need_reloading_signal_delete(self): self.client.post(endpoint, {'post': 'yes'}) self.assertEqual(env.call_count, 1) new_revision, _ = UrlconfRevision.get_or_create_revision() - self.assertNotEquals(current_revision, new_revision) + self.assertNotEqual(current_revision, new_revision) def test_urls_need_reloading_signal_change_slug(self): superuser = self.get_superuser() @@ -92,4 +92,4 @@ def test_urls_need_reloading_signal_change_slug(self): self.assertRedirects(response, redirect_to) self.assertEqual(env.call_count, 1) new_revision, _ = UrlconfRevision.get_or_create_revision() - self.assertNotEquals(current_revision, new_revision) + self.assertNotEqual(current_revision, new_revision) diff --git a/cms/tests/test_templates.py b/cms/tests/test_templates.py index c8f8ed652a0..1be081f0bca 100644 --- a/cms/tests/test_templates.py +++ b/cms/tests/test_templates.py @@ -1,5 +1,5 @@ import os.path -from imp import PY_SOURCE, load_module +from importlib.machinery import SourceFileLoader from django.conf import settings from django.template import TemplateDoesNotExist, loader @@ -39,19 +39,25 @@ def test_custom_templates(self): Test that using CMS_TEMPLATES_DIR both template list and template labels are extracted from the new directory """ config_path = os.path.join(settings.CMS_TEMPLATES_DIR, '__init__.py') - with open(config_path, 'r') as openfile: - mod = load_module("mod", openfile, config_path, ('m', 'r', PY_SOURCE)) - original_labels = [force_str(_(template[1])) for template in mod.TEMPLATES.items()] - original_files = [os.path.join(PATH_PREFIX, template[0].strip()) for template in mod.TEMPLATES.items()] - templates = get_cms_setting('TEMPLATES') - self.assertEqual(len(templates), 3) - labels = [force_str(template[1]) for template in templates] - files = [template[0] for template in templates] - if get_cms_setting('TEMPLATE_INHERITANCE'): - original_labels.append(force_str(_('Inherit the template of the nearest ancestor'))) - original_files.append(constants.TEMPLATE_INHERITANCE_MAGIC) - self.assertEqual(set(labels), set(original_labels)) - self.assertEqual(set(files), set(original_files)) + mod = None + try: + mod = SourceFileLoader("mod", config_path).load_module() + except FileNotFoundError: + print(f"file not found at {config_path}") + except Exception as e: + print(f"An error occurred: {e}") + if mod: + original_labels = [force_str(_(template[1])) for template in mod.TEMPLATES.items()] + original_files = [os.path.join(PATH_PREFIX, template[0].strip()) for template in mod.TEMPLATES.items()] + templates = get_cms_setting('TEMPLATES') + self.assertEqual(len(templates), 3) + labels = [force_str(template[1]) for template in templates] + files = [template[0] for template in templates] + if get_cms_setting('TEMPLATE_INHERITANCE'): + original_labels.append(force_str(_('Inherit the template of the nearest ancestor'))) + original_files.append(constants.TEMPLATE_INHERITANCE_MAGIC) + self.assertEqual(set(labels), set(original_labels)) + self.assertEqual(set(files), set(original_files)) @override_settings(CMS_TEMPLATES_DIR=GOOD_PATH) def test_custom_templates_loading(self): diff --git a/cms/tests/test_templatetags.py b/cms/tests/test_templatetags.py index fce02948d38..23f02c88e23 100644 --- a/cms/tests/test_templatetags.py +++ b/cms/tests/test_templatetags.py @@ -319,7 +319,7 @@ def test_untranslated_language_url(self): def test_create_placeholder_if_not_exist_in_template(self): """ - Tests that adding a new placeholder to a an exising page's template + Tests that adding a new placeholder to a an existing page's template creates the placeholder. """ page = create_page('Test', 'col_two.html', 'en') diff --git a/cms/tests/test_toolbar.py b/cms/tests/test_toolbar.py index 2cfc7149d3f..c9ba00751da 100644 --- a/cms/tests/test_toolbar.py +++ b/cms/tests/test_toolbar.py @@ -989,13 +989,13 @@ def test_toolbar_logout_redirect(self): response = self.client.get(page3_edit_url) toolbar = response.context['request'].toolbar admin_menu = toolbar.get_or_create_menu(ADMIN_MENU_IDENTIFIER) - self.assertEquals(admin_menu.find_first(AjaxItem, name=menu_name).item.on_success, '/') + self.assertEqual(admin_menu.find_first(AjaxItem, name=menu_name).item.on_success, '/') # Published page with view permissions, redirect response = self.client.get(page4_edit_url) toolbar = response.context['request'].toolbar admin_menu = toolbar.get_or_create_menu(ADMIN_MENU_IDENTIFIER) - self.assertEquals(admin_menu.find_first(AjaxItem, name=menu_name).item.on_success, '/') + self.assertEqual(admin_menu.find_first(AjaxItem, name=menu_name).item.on_success, '/') @override_settings(ROOT_URLCONF='cms.test_utils.project.placeholderapp_urls') diff --git a/cms/tests/test_wizards.py b/cms/tests/test_wizards.py index 9694ef97d11..0cb870d7e1c 100644 --- a/cms/tests/test_wizards.py +++ b/cms/tests/test_wizards.py @@ -206,7 +206,7 @@ def test_unregister_registered_wizard(self): def test_unregister_unregistered_wizard(self): """ Test for backwards compatibility of the unregister method. - Returns False if wizard not fount. + Returns False if wizard not found. """ was_unregistered = wizard_pool.unregister(self.page_wizard) self.assertFalse(was_unregistered) @@ -248,7 +248,7 @@ def test_old_registration_still_works(self): # NOTE: Because of how the override_settings decorator works, # we can't use it for this test as the app registry first # gets loaded with the default apps and then again with - # the overriden ones. + # the overridden ones. INSTALLED_APPS = [ 'cms', 'treebeard', diff --git a/cms/utils/__init__.py b/cms/utils/__init__.py index 14d30681056..8f3b19a350b 100644 --- a/cms/utils/__init__.py +++ b/cms/utils/__init__.py @@ -1,4 +1,4 @@ -# TODO: this is just stuff from utils.py - should be splitted / moved +# TODO: this is just stuff from utils.py - should be split / moved from cms.utils.i18n import ( get_default_language, diff --git a/cms/utils/apphook_reload.py b/cms/utils/apphook_reload.py index 0be32bb3596..de4f51867c8 100644 --- a/cms/utils/apphook_reload.py +++ b/cms/utils/apphook_reload.py @@ -3,7 +3,7 @@ import uuid # Py2 and Py3 compatible reload -from imp import reload +from importlib import reload from threading import local from django.conf import settings diff --git a/cms/utils/compat/response.py b/cms/utils/compat/response.py index c4e69d6a635..afc533dde25 100644 --- a/cms/utils/compat/response.py +++ b/cms/utils/compat/response.py @@ -1,6 +1,6 @@ def get_response_headers(response): """ - Django 3.2+ comes with changes to the repsonse headers and the _headers is not present + Django 3.2+ comes with changes to the response headers and the _headers is not present in the newer versions. So this method checks if it's present in the response or not, else returns the newer attribute headers from the response. """ diff --git a/cms/utils/conf.py b/cms/utils/conf.py index c2174c8028d..76789dff869 100644 --- a/cms/utils/conf.py +++ b/cms/utils/conf.py @@ -21,12 +21,11 @@ def _load_from_file(module_path): """ Load a python module from its absolute filesystem path """ - from imp import PY_SOURCE, load_module + from importlib.machinery import SourceFileLoader imported = None if module_path: - with open(module_path, 'r') as openfile: - imported = load_module("mod", openfile, module_path, ('imported', 'r', PY_SOURCE)) + imported = SourceFileLoader("mod", module_path).load_module() return imported @@ -132,12 +131,12 @@ def get_toolbar_url__enable(): def get_templates(): if getattr(settings, 'CMS_TEMPLATES_DIR', False): tpldir = getattr(settings, 'CMS_TEMPLATES_DIR', False) - # CMS_TEMPLATES_DIR can either be a string poiting to the templates directory + # CMS_TEMPLATES_DIR can either be a string pointing to the templates directory # or a dictionary holding 'site: template dir' entries if isinstance(tpldir, dict): tpldir = tpldir[settings.SITE_ID] - # We must extract the relative path of CMS_TEMPLATES_DIR to the neares - # valid templates directory. Here we mimick what the filesystem and + # We must extract the relative path of CMS_TEMPLATES_DIR to the nearest + # valid templates directory. Here we mimic what the filesystem and # app_directories template loaders do prefix = '' # Relative to TEMPLATE['DIRS'] for filesystem loader diff --git a/cms/utils/helpers.py b/cms/utils/helpers.py index 3a122731da6..5d2c2904ee7 100644 --- a/cms/utils/helpers.py +++ b/cms/utils/helpers.py @@ -41,7 +41,7 @@ def __get__(self, owner_self, owner_cls): def normalize_name(name): """ - Converts camel-case style names into underscore seperated words. Example:: + Converts camel-case style names into underscore separated words. Example:: >>> normalize_name('oneTwoThree') 'one_two_three' diff --git a/cms/utils/placeholder.py b/cms/utils/placeholder.py index a815b372777..73c07affae4 100644 --- a/cms/utils/placeholder.py +++ b/cms/utils/placeholder.py @@ -187,7 +187,7 @@ def _scan_placeholders(nodelist, node_class=None, current_block=None, ignore_blo if ignore_blocks is None: # List of BlockNode instances to ignore. - # This is important to avoid processing overriden block nodes. + # This is important to avoid processing overridden block nodes. ignore_blocks = [] for node in nodelist: @@ -375,7 +375,7 @@ def get_declared_placeholders_for_obj(obj): def get_placeholder_from_slot(placeholder_relation: models.Manager, slot: str, template_obj=None) -> Placeholder: - """Retrieves the placeholder instance for a PlaceholderRelationField either by scaning the template + """Retrieves the placeholder instance for a PlaceholderRelationField either by scanning the template of the template_obj (if given) or by creating or getting a Placeholder in the database""" if hasattr(template_obj, "get_template"): # Tries to get a placeholder (based on the template for the template_obj diff --git a/cms/views.py b/cms/views.py index f299edd1e70..84e8fca32de 100644 --- a/cms/views.py +++ b/cms/views.py @@ -289,7 +289,7 @@ def render_object_endpoint(request, content_type_id, object_id, require_editable absolute_url = content_type_obj.get_absolute_url() from cms.toolbar.toolbar import CMSToolbar request.toolbar = CMSToolbar(request, request_path=absolute_url) - # Resovle the apphook's url to get its view function + # Resolve the apphook's url to get its view function view_func, args, kwargs = resolve(absolute_url) return view_func(request, *args, **kwargs) except Resolver404: diff --git a/docs/conf.py b/docs/conf.py index 9b4e427d74c..299a73f7ae6 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -127,26 +127,17 @@ # on_rtd is whether we are on readthedocs.org on_rtd = os.environ.get('READTHEDOCS', None) == 'True' + try: - import divio_docs_theme - html_theme = 'divio_docs_theme' - html_theme_path = [divio_docs_theme.get_html_theme_path()] + import furo + + html_theme = 'furo' html_theme_options = { - 'show_cloud_banner': True, - 'cloud_banner_markup': """ -
- The django CMS Association -

The django CMS Association is a non-profit organisation that funds and - steers the development of django CMS, and nurtures its world-wide - community of developers and users.

- Join us -
- """, + "navigation_with_keys": True, } -except: # NOQA +except ImportError: html_theme = 'default' - show_cloud_banner = True # The theme to use for HTML and HTML Help pages. Major themes that come with diff --git a/docs/contributing/development-community.rst b/docs/contributing/development-community.rst index b5d8905de89..ceaf2639346 100644 --- a/docs/contributing/development-community.rst +++ b/docs/contributing/development-community.rst @@ -45,7 +45,7 @@ and as one of the founding members of the dCA, next to `What `_. The dCA’s role in steering the project’s development is formalised in the -`django CMS technical comittee `_, +`django CMS technical committee `_, whose members are drawn from the django CMS community and the dCA. The dCA maintains overall control of the `django CMS repository `_. diff --git a/docs/how_to/frontend_models.rst b/docs/how_to/frontend_models.rst index 1a9b501f09a..a29d1a3217e 100644 --- a/docs/how_to/frontend_models.rst +++ b/docs/how_to/frontend_models.rst @@ -95,13 +95,13 @@ Will render to: .. code-block:: html+django -