diff --git a/.checkignore b/.checkignore index d6ab65a..ba3e351 100644 --- a/.checkignore +++ b/.checkignore @@ -1,3 +1,4 @@ tests/* +docs/* djangocms_page_tags/migrations/* djangocms_page_tags/south_migrations/* diff --git a/.codeclimate.yml b/.codeclimate.yml new file mode 100644 index 0000000..189a096 --- /dev/null +++ b/.codeclimate.yml @@ -0,0 +1,8 @@ +languages: + Ruby: false + JavaScript: false + PHP: false + Python: true +exclude_paths: + - 'djangocms_page_tags/migrations/*' + - 'tests/*' diff --git a/.coveragerc b/.coveragerc index 0486d69..9bc1e9a 100644 --- a/.coveragerc +++ b/.coveragerc @@ -3,7 +3,7 @@ branch = True source = djangocms_page_tags [report] -omit = ../*migrations*,../*tests* +omit = *migrations*,*tests*,*test_utils* # Regexes for lines to exclude from consideration exclude_lines = # Have to re-enable the standard pragma diff --git a/.csslintrc b/.csslintrc new file mode 100644 index 0000000..aacba95 --- /dev/null +++ b/.csslintrc @@ -0,0 +1,2 @@ +--exclude-exts=.min.css +--ignore=adjoining-classes,box-model,ids,order-alphabetical,unqualified-attributes diff --git a/.editorconfig b/.editorconfig index 68928cd..d979ee9 100644 --- a/.editorconfig +++ b/.editorconfig @@ -8,27 +8,27 @@ end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true -max_line_length = 80 +max_line_length = 120 [*.md] trim_trailing_whitespace = false [*.rst] -max_line_length = 80 +max_line_length = 120 [*.py] -max_line_length = 100 +max_line_length = 120 [*.{scss,html}] -indent_size = 4 +indent_size = 2 indent_style = space max_line_length = 120 -[*.js] +[*.{js,vue,json}] indent_size = 2 max_line_length = 120 -[*.yml] +[*.{yml,yaml}] indent_size = 2 [Makefile] diff --git a/.github/ISSUE_TEMPLATE/---bug-report.md b/.github/ISSUE_TEMPLATE/---bug-report.md new file mode 100644 index 0000000..19d08d8 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/---bug-report.md @@ -0,0 +1,48 @@ +--- +name: "\U0001F41B Bug report" +about: Create a report to help us improve +title: '' +labels: 'type: bug' +assignees: '' + +--- + + + +## Description + + + +## Steps to reproduce + + + +## Versions + + + +## Expected behaviour + + + +## Actual behaviour + + + +## Additional information + + diff --git a/.github/ISSUE_TEMPLATE/---feature-request.md b/.github/ISSUE_TEMPLATE/---feature-request.md new file mode 100644 index 0000000..5b74e5f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/---feature-request.md @@ -0,0 +1,42 @@ +--- +name: "\U0001F389 Feature request" +about: Share your idea, let's discuss it! +title: '' +labels: 'type: feature' +assignees: '' + +--- + + + +## Description + + + +## Use cases + + + +## Proposed solution + + + +## Alternatives + + + +## Additional information + + diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..3148143 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,18 @@ +# Description + +Describe: + +* Content of the pull request +* Feature added / Problem fixed + +## References + +Provide any github issue fixed (as in ``Fix #XYZ``) + +# Checklist + +* [ ] I have read the [contribution guide](https://djangocms-page-tags.readthedocs.io/en/latest/contributing.html) +* [ ] Code lint checked via `inv lint` +* [ ] ``changes`` file included (see [docs](https://djangocms-page-tags.readthedocs.io/en/latest/contributing.html#pull-request-guidelines)) +* [ ] Usage documentation added in case of new features +* [ ] Tests added diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..d03bb3c --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,41 @@ +name: Code quality + +on: [push, pull_request] + +jobs: + lint: + runs-on: ubuntu-latest + if: "!contains(github.event.head_commit.message, '[skip ci]')" + strategy: + matrix: + python-version: [3.8] + toxenv: [pep8, isort, black, pypi-description, docs, towncrier] + steps: + - uses: actions/checkout@v2 + with: + repository: ${{ github.event.pull_request.head.repo.full_name }} + ref: ${{ github.event.pull_request.head.ref }} + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Cache pip + uses: actions/cache@v1 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ matrix.toxenv }} + restore-keys: | + ${{ runner.os }}-pip-${{ matrix.toxenv }} + - name: Cache tox + uses: actions/cache@v1 + with: + path: .tox + key: ${{ runner.os }}-lint-${{ matrix.toxenv }}-${{ hashFiles('setup.cfg') }} + restore-keys: | + ${{ runner.os }}-lint-${{ matrix.toxenv }}- + - name: Install dependencies + run: | + python -m pip install --upgrade pip setuptools tox>=1.8 + - name: Test with tox + run: | + tox -e${{ matrix.toxenv }} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..07b9e64 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,38 @@ +name: Upload Python Package + +on: + release: + types: [published,prereleased] + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: '3.x' + - name: Cache pip + uses: actions/cache@v1 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ matrix.toxenv }} + restore-keys: | + ${{ runner.os }}-pip-${{ matrix.toxenv }} + - name: Cache tox + uses: actions/cache@v1 + with: + path: .tox + key: ${{ runner.os }}-tox-release-${{ hashFiles('setup.cfg') }} + restore-keys: | + ${{ runner.os }}-tox-release- + - name: Install dependencies + run: | + python -m pip install --upgrade pip setuptools tox>=1.8 + - name: Build and publish + env: + TWINE_USERNAME: __token__ + TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} + run: | + tox -erelease diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..bac4618 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,61 @@ +name: Tox tests + +on: [push, pull_request] + +jobs: + test: + if: "!contains(github.event.head_commit.message, '[skip ci]')" + runs-on: ubuntu-latest + strategy: + matrix: + python-version: [3.8, 3.7, 3.6] + django: [31, 30, 22] + cms: [38, 37] + exclude: + - django: 31 + cms: 37 + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Cache pip + uses: actions/cache@v1 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ matrix.toxenv }} + restore-keys: | + ${{ runner.os }}-pip-${{ matrix.toxenv }} + - name: Cache tox + uses: actions/cache@v1 + with: + path: .tox + key: ${{ runner.os }}-tox-${{ format('{{py{0}-django{1}-cms{2}}}', matrix.python-version, matrix.django, matrix.cms) }}-${{ hashFiles('setup.cfg') }} + restore-keys: | + ${{ runner.os }}-tox-${{ format('{{py{0}-django{1}-cms{2}}}', matrix.python-version, matrix.django, matrix.cms) }}- + - name: Install dependencies + run: | + sudo apt-get install gettext + python -m pip install --upgrade pip tox>=3.5 + - name: Test with tox + env: + TOX_ENV: ${{ format('py-django{1}-cms{2}', matrix.python-version, matrix.django, matrix.cms) }} + COMMAND: coverage run + COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }} + COVERALLS_SERVICE_NAME: github + run: | + tox -e$TOX_ENV + .tox/$TOX_ENV/bin/coverage xml + .tox/$TOX_ENV/bin/coveralls + - uses: codecov/codecov-action@v1 + with: + token: ${{ secrets.CODECOV_TOKEN }} + flags: unittests + file: ./coverage.xml + fail_ci_if_error: false + services: + redis: + image: redis + ports: + - 6379:6379 diff --git a/.gitignore b/.gitignore index 0284a56..479c695 100644 --- a/.gitignore +++ b/.gitignore @@ -1,42 +1,527 @@ + +# Created by https://www.gitignore.io/api/vim,node,sass,vuejs,linux,macos,django,python,pycharm,windows,virtualenv,sublimetext,visualstudiocode +# Edit at https://www.gitignore.io/?templates=vim,node,sass,vuejs,linux,macos,django,python,pycharm,windows,virtualenv,sublimetext,visualstudiocode + +### Django ### +*.log +*.pot +*.pyc +__pycache__/ +local_settings.py +db.sqlite3 +db.sqlite3-journal +media + +# If your build process includes running collectstatic, then you probably don't need or want to include staticfiles/ +# in your Git repository. Update and uncomment the following line accordingly. +# /staticfiles/ + +### Django.Python Stack ### +# Byte-compiled / optimized / DLL files + *.py[cod] +*$py.class # C extensions *.so -# Packages -*.egg -*.egg-info -dist -build -eggs -parts -bin -var -sdist -develop-eggs +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ .installed.cfg -lib -lib64 +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec # Installer logs pip-log.txt +pip-delete-this-directory.txt # Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ .coverage -.tox +.coverage.* +.cache + nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject # Mr Developer .mr.developer.cfg .project .pydevproject -# Complexity -output/*.html -output/*/index.html -# Sphinx -docs/_build +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Node ### +# Logs +logs +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test + +# parcel-bundler cache (https://parceljs.org/) + +# next.js build output +.next + +# nuxt.js build output +.nuxt + +# rollup.js default build output + +# Uncomment the public line if your project uses Gatsby +# https://nextjs.org/blog/next-9-1#public-directory-support +# https://create-react-app.dev/docs/using-the-public-folder/#docsNav +# public + +# Storybook build outputs +.out +.storybook-out + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# Temporary folders +tmp/ +temp/ + +### PyCharm ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### PyCharm Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +.idea/**/sonarlint/ + +# SonarQube Plugin +.idea/**/sonarIssues.xml + +# Markdown Navigator plugin +.idea/**/markdown-navigator.xml +.idea/**/markdown-navigator/ + +### Python ### +# Byte-compiled / optimized / DLL files + +# C extensions + +# Distribution / packaging + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. + +# Installer logs + +# Unit test / coverage reports + +# Translations + +# Scrapy stuff: + +# Sphinx documentation + +# PyBuilder + +# pyenv + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. + +# celery beat schedule file + +# SageMath parsed files + +# Spyder project settings + +# Rope project settings + +# Mr Developer + +# mkdocs documentation + +# mypy + +# Pyre type checker + +### Sass ### +.sass-cache/ +*.css.map +*.sass.map +*.scss.map + +### SublimeText ### +# Cache files for Sublime Text +*.tmlanguage.cache +*.tmPreferences.cache +*.stTheme.cache + +# Workspace files are user-specific +*.sublime-workspace + +# Project files should be checked into the repository, unless a significant +# proportion of contributors will probably not be using Sublime Text +# *.sublime-project + +# SFTP configuration file +sftp-config.json + +# Package control specific files +Package Control.last-run +Package Control.ca-list +Package Control.ca-bundle +Package Control.system-ca-bundle +Package Control.cache/ +Package Control.ca-certs/ +Package Control.merged-ca-bundle +Package Control.user-ca-bundle +oscrypto-ca-bundle.crt +bh_unicode_properties.cache + +# Sublime-github package stores a github token in this file +# https://packagecontrol.io/packages/sublime-github +GitHub.sublime-settings + +### Vim ### +# Swap +[._]*.s[a-v][a-z] +[._]*.sw[a-p] +[._]s[a-rt-v][a-z] +[._]ss[a-gi-z] +[._]sw[a-p] + +# Session +Session.vim +Sessionx.vim + +# Temporary +.netrwhist + +# Auto-generated tag files +tags + +# Persistent undo +[._]*.un~ + +# Coc configuration directory +.vim + +### VirtualEnv ### +# Virtualenv +# http://iamzed.com/2009/05/07/a-primer-on-virtualenv/ +pyvenv.cfg +.venv + +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ +pip-selfcheck.json + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history + +### Vuejs ### +# Recommended template: Node.gitignore + +npm-debug.log +yarn-error.log + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# End of https://www.gitignore.io/api/vim,node,sass,vuejs,linux,macos,django,python,pycharm,windows,virtualenv,sublimetext,visualstudiocode + *.sqlite -.eggs* +data diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..30dc5aa --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,62 @@ +# See https://pre-commit.com for more information +# See https://pre-commit.com/hooks.html for more hooks +exclude: "(.idea|node_modules|.tox)" +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v3.3.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-added-large-files + - id: check-builtin-literals + - id: check-executables-have-shebangs + - id: check-merge-conflict + - id: check-toml + - id: fix-encoding-pragma + args: + - --remove + - repo: https://github.com/timothycrosley/isort + rev: "5.6.4" + hooks: + - id: isort + - repo: https://github.com/psf/black + rev: 20.8b1 + hooks: + - id: black + - repo: https://gitlab.com/pycqa/flake8 + rev: 3.8.4 + 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/econchick/interrogate + rev: 1.3.1 + hooks: + - id: interrogate + args: + - "-cpyproject.toml" + - "--quiet" + - repo: https://github.com/asottile/pyupgrade + rev: v2.7.3 + hooks: + - id: pyupgrade + args: + - --py3-plus + - repo: local + hooks: + - id: towncrier + name: towncrier + entry: inv towncrier-check + language: system + pass_filenames: false + always_run: true diff --git a/.pyup.yml b/.pyup.yml new file mode 100644 index 0000000..2809577 --- /dev/null +++ b/.pyup.yml @@ -0,0 +1,7 @@ +update: all +pin: False +branch: +schedule: "every day" +search: True +branch_prefix: pyup/ +close_prs: True diff --git a/.readthedocs.yml b/.readthedocs.yml new file mode 100644 index 0000000..bbd8063 --- /dev/null +++ b/.readthedocs.yml @@ -0,0 +1,19 @@ +version: 2 + +sphinx: + configuration: docs/conf.py + fail_on_warning: false + +formats: + - epub + - pdf + +python: + version: 3.7 + install: + - requirements: requirements-test.txt + - method: pip + path: . + extra_requirements: + - docs + system_packages: false diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 8385ead..0000000 --- a/.travis.yml +++ /dev/null @@ -1,78 +0,0 @@ -language: python -dist: xenial - -python: - - 3.7 - - 3.6 - - 3.5 - - 2.7 - -env: - matrix: - - TOXENV='pep8' - - TOXENV='docs' - - TOXENV='isort' - - DJANGO='django22' CMS='cms37' - - DJANGO='django21' CMS='cms36' - - DJANGO='django20' CMS='cms36' - - DJANGO='django111' CMS='cms37' - - DJANGO='django111' CMS='cms36' - -# command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors -install: - - pip install -U setuptools tox>=1.8 coveralls - - "if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then export PYVER=py27; fi" - - "if [[ $TRAVIS_PYTHON_VERSION == '3.5' ]]; then export PYVER=py35; fi" - - "if [[ $TRAVIS_PYTHON_VERSION == '3.6' ]]; then export PYVER=py36; fi" - - "if [[ $TRAVIS_PYTHON_VERSION == '3.7' ]]; then export PYVER=py37; fi" - - "if [[ ${DJANGO}z != 'z' ]]; then export TOXENV=$PYVER-$DJANGO-$CMS; fi" - -# command to run tests, e.g. python setup.py test -script: COMMAND='coverage run' tox -e$TOXENV - -before_install: - - pip install codecov -after_success: - - codecov - - coveralls - -matrix: - exclude: - - python: 2.7 - env: TOXENV='pep8' - - python: 2.7 - env: TOXENV='isort' - - python: 2.7 - env: TOXENV='docs' - - python: 2.7 - env: DJANGO='django20' CMS='cms36' - - python: 2.7 - env: DJANGO='django21' CMS='cms36' - - python: 2.7 - env: DJANGO='django22' CMS='cms36' - - python: 2.7 - env: DJANGO='django22' CMS='cms37' - - python: 3.5 - env: DJANGO='django111' CMS='cms36' - - python: 3.5 - env: DJANGO='django20' CMS='cms36' - - python: 3.5 - env: DJANGO='django21' CMS='cms36' - - python: 3.4 - env: TOXENV='pep8' - - python: 3.4 - env: TOXENV='isort' - - python: 3.4 - env: TOXENV='docs' - - python: 3.5 - env: TOXENV='pep8' - - python: 3.5 - env: TOXENV='isort' - - python: 3.5 - env: TOXENV='docs' - - python: 3.6 - env: TOXENV='pep8' - - python: 3.6 - env: TOXENV='isort' - - python: 3.6 - env: TOXENV='docs' diff --git a/.tx/config b/.tx/config index a7a9e1e..a041b94 100644 --- a/.tx/config +++ b/.tx/config @@ -5,4 +5,3 @@ host = https://www.transifex.com file_filter = djangocms_page_tags/locale//LC_MESSAGES/django.po source_file = djangocms_page_tags/locale/en/LC_MESSAGES/django.po source_lang = en - diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index bc2ffc3..592bc71 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -1,17 +1,17 @@ -============ +############ Contributing -============ +############ Contributions are welcome, and they are greatly appreciated! Every -little bit helps, and credit will always be given. +little bit helps, and credit will always be given. You can contribute in many ways: Types of Contributions ----------------------- +********************** Report Bugs -~~~~~~~~~~~ +=========== Report bugs at https://github.com/nephila/djangocms-page-tags/issues. @@ -22,32 +22,26 @@ If you are reporting a bug, please include: * Detailed steps to reproduce the bug. Fix Bugs -~~~~~~~~ +======== Look through the GitHub issues for bugs. Anything tagged with "bug" is open to whoever wants to implement it. Implement Features -~~~~~~~~~~~~~~~~~~ +================== Look through the GitHub issues for features. Anything tagged with "feature" is open to whoever wants to implement it. -Translations -~~~~~~~~~~~~ - -Any translation is welcome. Please use Transifex https://www.transifex.com/projects/p/djangocms-page-tags/ -to help with translations. - Write Documentation -~~~~~~~~~~~~~~~~~~~ +=================== -djangocms-page-tags could always use more documentation, whether as part of the +djangocms-page-tags could always use more documentation, whether as part of the official djangocms-page-tags docs, in docstrings, or even on the web in blog posts, articles, and such. Submit Feedback -~~~~~~~~~~~~~~~ +=============== The best way to send feedback is to file an issue at https://github.com/nephila/djangocms-page-tags/issues. @@ -58,21 +52,24 @@ If you are proposing a feature: * Remember that this is a volunteer-driven project, and that contributions are welcome :) +************ Get Started! ------------- +************ -Ready to contribute? Here's how to set up `djangocms-page-tags` for local development. +Ready to contribute? Here's how to set up ``djangocms-page-tags`` for local development. -1. Fork the `djangocms-page-tags` repo on GitHub. +1. Fork the ``djangocms-page-tags`` repo on GitHub. 2. Clone your fork locally:: $ git clone git@github.com:your_name_here/djangocms-page-tags.git -3. Install your local copy into a virtualenv. Assuming you have virtualenvwrapper installed, this is how you set up your fork for local development:: +3. Install your local copy into a virtualenv. Assuming you have virtualenvwrapper + installed, this is how you set up your fork for local development:: $ mkvirtualenv djangocms-page-tags $ cd djangocms-page-tags/ - $ python setup.py develop + $ pip install -r requirements-test.txt + $ pip install -e . 4. Create a branch for local development:: @@ -83,11 +80,9 @@ Now you can make your changes locally. 5. When you're done making changes, check that your changes pass flake8 and the tests, including testing other Python versions with tox:: - $ flake8 djangocms_page_tags tests - $ python setup.py test $ tox -To get flake8 and tox, just pip install them into your virtualenv. +To get tox, pip install it into your virtualenv. 6. Commit your changes and push your branch to GitHub:: @@ -97,22 +92,75 @@ To get flake8 and tox, just pip install them into your virtualenv. 7. Submit a pull request through the GitHub website. -Pull Request Guidelines ------------------------ +Development tips +---------------- -Before you submit a pull request, check that it meets these guidelines: +This project allows you to use `pre-commit `_ to ensure an easy compliance +to the project code styles. + +If you want to use it, install it globally (for example with ``pip3 install --user precommit``, +but check `installation instruction `_. +When first cloning the project ensure you install the git hooks by running ``pre-commit install``. + +From now on every commit will be checked against our code style. -1. The pull request should include tests. -2. If the pull request adds functionality, the docs should be updated. Put - your new functionality into a function with a docstring, and add the - feature to the list in README.rst. -3. The pull request should work for Python 2.6, 2.7, and 3.3, and for PyPy. Check - https://travis-ci.org/nephila/djangocms-page-tags/pull_requests - and make sure that the tests pass for all supported Python versions. +Check also the available tox environments with ``tox -l``: the ones not marked with a python version number are tools +to help you work on the project buy checking / formatting code style, running docs etc. -Tips ----- +Testing tips +---------------- +You can test your project using any specific combination of python, django and django cms. -To run a subset of tests:: +For example ``tox -epy3.7-django30-cms37`` runs the tests on python 3.7, Django 3.0 and django CMS 3.7. + + +Pull Request Guidelines +======================= + +Before you submit a pull request, check that it meets these guidelines: - $ python runtests.py +#. Pull request must be named with the following naming scheme: + + ``/(-)-description`` + + See below for available types. + +#. The pull request should include tests. +#. If the pull request adds functionality, the docs should be updated. + Documentation must be added in ``docs`` directory, and must include usage + information for the end user. + In case of public API method, add extended docstrings with full parameters + description and usage example. +#. Add a changes file in ``changes`` directory describing the contribution in + one line. It will be added automatically to the history file upon release. + File must be named as ``.`` with type being: + + * ``.feature``: For new features. + * ``.bugfix``: For bug fixes. + * ``.doc``: For documentation improvement. + * ``.removal``: For deprecation or removal of public API. + * ``.misc``: For general issues. + + Check `towncrier`_ documentation for more details. + +#. The pull request should work for all python / django / django CMS versions + declared in tox.ini. + Check the CI and make sure that the tests pass for all supported versions. + +Release a version +================= + +#. Update authors file +#. Merge ``develop`` on ``master`` branch +#. Bump release via task: ``inv tag-release (major|minor|patch)`` +#. Update changelog via towncrier: ``towncrier --yes`` +#. Commit changelog with ``git commit --amend`` to merge with bumpversion commit +#. Create tag ``git tag `` +#. Push tag to github +#. Publish the release from the tags page +#. If pipeline succeeds, push ``master`` +#. Merge ``master`` back on ``develop`` +#. Bump developement version via task: ``inv tag-dev -l (major|minor|patch)`` +#. Push ``develop`` + +.. _towncrier: https://pypi.org/project/towncrier/#news-fragments diff --git a/LICENSE b/LICENSE index 202378a..b7ccab0 100644 --- a/LICENSE +++ b/LICENSE @@ -9,4 +9,4 @@ Redistribution and use in source and binary forms, with or without modification, * Neither the name of djangocms-page-tags nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/MANIFEST.in b/MANIFEST.in index 1a3c3ca..3caabc4 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -4,4 +4,4 @@ include HISTORY.rst include LICENSE include README.rst include requirements.txt -recursive-include djangocms_page_tags *.html *.png *.gif *js *jpg *jpeg *svg *py *mo *po +recursive-include djangocms_page_tags *.html *.png *.gif *js *jpg *jpeg *svg *py *mo *po *css diff --git a/Makefile b/Makefile deleted file mode 100644 index a60f029..0000000 --- a/Makefile +++ /dev/null @@ -1,46 +0,0 @@ -.PHONY: clean-pyc clean-build docs - -help: - @echo "clean-build - remove build artifacts" - @echo "clean-pyc - remove Python file artifacts" - @echo "lint - check style with flake8" - @echo "test - run tests quickly with the default Python" - @echo "test-all - run tests on every Python version with tox" - @echo "coverage - check code coverage quickly with the default Python" - @echo "release - package and upload a release" - @echo "sdist - package" - -clean: clean-build clean-pyc - -clean-build: - python setup.py clean --all - rm -fr build/ - rm -fr dist/ - rm -fr *.egg-info - -clean-pyc: - find . -name '*.pyc' -exec rm -f {} + - find . -name '*.pyo' -exec rm -f {} + - find . -name '*~' -exec rm -f {} + - -lint: - tox -epep8,isort - -test: - python setup.py test - -test-all: - tox - -coverage: - coverage erase - coverage run setup.py test - coverage report -m - -release: clean - python setup.py clean --all sdist bdist_wheel - twine upload dist/* - -sdist: clean - python setup.py sdist - ls -l dist diff --git a/README.rst b/README.rst index c261e96..5ffa7d2 100644 --- a/README.rst +++ b/README.rst @@ -2,15 +2,18 @@ djangocms-page-tags =================== -|Gitter| |PyPiVersion| |PyVersion| |Status| |TestCoverage| |CodeClimate| |License| +|Gitter| |PyPiVersion| |PyVersion| |GAStatus| |TestCoverage| |CodeClimate| |License| Tagged pages for django CMS 3 -Python: 2.7, 3.5, 3.6, 3.7 +Python: 3.6, 3.7, 3.8 -Django: 1.11 to 2.2 +Django: 2.2, 3.0, 3.1 -django CMS: 3.6 to 3.7 +django CMS: 3.7, 3.8 + +.. warning:: Since version 0.9, the support for Python < 3.5, django CMS < 3.7 + has been dropped. .. warning:: Since version 0.8, the support for Python 3.4, django CMS < 3.6 has been dropped. @@ -85,9 +88,9 @@ For further documentation see https://djangocms-page-tags.readthedocs.io/ :target: https://pypi.python.org/pypi/djangocms-page-sitemap :alt: Python versions -.. |Status| image:: https://img.shields.io/travis/nephila/djangocms-page-sitemap.svg?style=flat-square - :target: https://travis-ci.org/nephila/djangocms-page-sitemap - :alt: Latest Travis CI build status +.. |GAStatus| image:: https://github.com/nephila/djangocms-redirect/workflows/Tox%20tests/badge.svg + :target: https://github.com/nephila/djangocms-redirect + :alt: Latest CI build status .. |TestCoverage| image:: https://img.shields.io/coveralls/nephila/djangocms-page-sitemap/master.svg?style=flat-square :target: https://coveralls.io/r/nephila/djangocms-page-sitemap?branch=master diff --git a/changes/10210.feature b/changes/10210.feature new file mode 100644 index 0000000..1219a43 --- /dev/null +++ b/changes/10210.feature @@ -0,0 +1 @@ +migrate from travis, drop Python 2/Django Cms 3.6 support diff --git a/cms_helper.py b/cms_helper.py index 48e384a..5d8cbfc 100755 --- a/cms_helper.py +++ b/cms_helper.py @@ -1,6 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- -from __future__ import absolute_import, print_function, unicode_literals from tempfile import mkdtemp @@ -10,55 +8,54 @@ def gettext(s): HELPER_SETTINGS = { - 'NOSE_ARGS': [ - '-s', + "NOSE_ARGS": [ + "-s", ], - 'ROOT_URLCONF': 'tests.test_utils.urls', - 'INSTALLED_APPS': [ - 'taggit', - 'taggit_autosuggest', - 'djangocms_page_tags', - 'tests.test_utils', + "ROOT_URLCONF": "tests.test_utils.urls", + "INSTALLED_APPS": [ + "taggit", + "taggit_autosuggest", + "djangocms_page_tags", + "tests.test_utils", ], - 'LANGUAGE_CODE': 'en', - 'LANGUAGES': ( - ('en', gettext('English')), - ('fr_FR', gettext('French')), - ('it', gettext('Italiano')), + "LANGUAGE_CODE": "en", + "LANGUAGES": ( + ("en", gettext("English")), + ("fr", gettext("French")), + ("it", gettext("Italiano")), ), - 'CMS_LANGUAGES': { + "CMS_LANGUAGES": { 1: [ { - 'code': 'en', - 'name': gettext('English'), - 'public': True, + "code": "en", + "name": gettext("English"), + "public": True, }, { - 'code': 'it', - 'name': gettext('Italiano'), - 'public': True, + "code": "it", + "name": gettext("Italiano"), + "public": True, }, { - 'code': 'fr', - 'name': gettext('French'), - 'public': True, + "code": "fr", + "name": gettext("French"), + "public": True, }, ], - 'default': { - 'hide_untranslated': False, + "default": { + "hide_untranslated": False, }, }, - 'CMS_TEMPLATES': ( - ('page_tags.html', 'page'), - ), - 'FILE_UPLOAD_TEMP_DIR': mkdtemp() - + "CMS_TEMPLATES": (("page_tags.html", "page"),), + "FILE_UPLOAD_TEMP_DIR": mkdtemp(), } def run(): from djangocms_helper import runner - runner.cms('djangocms_page_tags') + + runner.cms("djangocms_page_tags") + if __name__ == "__main__": run() diff --git a/djangocms_page_tags/__init__.py b/djangocms_page_tags/__init__.py index 8e2c734..e51015d 100644 --- a/djangocms_page_tags/__init__.py +++ b/djangocms_page_tags/__init__.py @@ -1,5 +1,2 @@ -# -*- coding: utf-8 -*- -from __future__ import absolute_import, print_function, unicode_literals - -__version__ = '0.8.1.dev1' -__author__ = 'Iacopo Spalletti ' +__version__ = "0.8.1.dev1" +__author__ = "Iacopo Spalletti " diff --git a/djangocms_page_tags/admin.py b/djangocms_page_tags/admin.py index 9430221..a2637ef 100644 --- a/djangocms_page_tags/admin.py +++ b/djangocms_page_tags/admin.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- -from __future__ import absolute_import, print_function, unicode_literals - from cms.extensions import PageExtensionAdmin, TitleExtensionAdmin from django.conf import settings from django.contrib import admin @@ -10,19 +7,11 @@ @admin.register(PageTags) class PageTagsAdmin(PageExtensionAdmin): - class Media: - css = { - 'all': ('%sdjangocms_page_tags/css/%s' % ( - settings.STATIC_URL, 'djangocms_page_tags_admin.css'),) - } + css = {"all": ("{}djangocms_page_tags/css/{}".format(settings.STATIC_URL, "djangocms_page_tags_admin.css"),)} @admin.register(TitleTags) class TitleTagsAdmin(TitleExtensionAdmin): - class Media: - css = { - 'all': ('%sdjangocms_page_tags/css/%s' % ( - settings.STATIC_URL, 'djangocms_page_tags_admin.css'),) - } + css = {"all": ("{}djangocms_page_tags/css/{}".format(settings.STATIC_URL, "djangocms_page_tags_admin.css"),)} diff --git a/djangocms_page_tags/cms_toolbars.py b/djangocms_page_tags/cms_toolbars.py index 11ebca9..6fa9c6d 100644 --- a/djangocms_page_tags/cms_toolbars.py +++ b/djangocms_page_tags/cms_toolbars.py @@ -1,11 +1,9 @@ -# -*- coding: utf-8 -*- -from __future__ import absolute_import, print_function, unicode_literals - from cms.api import get_page_draft from cms.cms_toolbars import PAGE_MENU_SECOND_BREAK from cms.toolbar.items import Break from cms.toolbar_base import CMSToolbar from cms.toolbar_pool import toolbar_pool +from cms.utils.conf import get_cms_setting from cms.utils.i18n import get_language_list, get_language_object from cms.utils.permissions import has_page_permission from django.urls import NoReverseMatch, reverse @@ -13,14 +11,8 @@ from .models import PageTags, TitleTags -try: - from cms.utils import get_cms_setting -except ImportError: - from cms.utils.conf import get_cms_setting - - -PAGE_TAGS_MENU_TITLE = _('Tags') -PAGE_TAGS_ITEM_TITLE = _('Common') +PAGE_TAGS_MENU_TITLE = _("Tags") +PAGE_TAGS_ITEM_TITLE = _("Common") @toolbar_pool.register @@ -36,26 +28,24 @@ def populate(self): return # check global permissions if CMS_PERMISSIONS is active - if get_cms_setting('PERMISSION'): + if get_cms_setting("PERMISSION"): has_global_current_page_change_permission = has_page_permission( - self.request.user, self.request.current_page, 'change' + self.request.user, self.request.current_page, "change" ) else: has_global_current_page_change_permission = False # check if user has page edit permission has_change_permission = self.request.current_page.has_change_permission(self.request.user) - can_change = (self.request.current_page and has_change_permission) + can_change = self.request.current_page and has_change_permission if has_global_current_page_change_permission or can_change: try: not_edit_mode = not self.toolbar.edit_mode except AttributeError: not_edit_mode = not self.toolbar.edit_mode_active - tags_menu = self.toolbar.get_or_create_menu('page') + tags_menu = self.toolbar.get_or_create_menu("page") super_item = tags_menu.find_first(Break, identifier=PAGE_MENU_SECOND_BREAK) + 1 - tags_menu = tags_menu.get_or_create_menu( - 'pagetags', PAGE_TAGS_MENU_TITLE, position=super_item - ) + tags_menu = tags_menu.get_or_create_menu("pagetags", PAGE_TAGS_MENU_TITLE, position=super_item) position = 0 # Page tags try: @@ -64,41 +54,34 @@ def populate(self): page_extension = None try: if page_extension: - url = reverse('admin:djangocms_page_tags_pagetags_change', - args=(page_extension.pk,)) + url = reverse("admin:djangocms_page_tags_pagetags_change", args=(page_extension.pk,)) else: - url = '%s?extended_object=%s' % ( - reverse('admin:djangocms_page_tags_pagetags_add'), - self.page.pk + url = "{}?extended_object={}".format( + reverse("admin:djangocms_page_tags_pagetags_add"), self.page.pk ) except NoReverseMatch: # pragma: no cover # not in urls pass else: - tags_menu.add_modal_item(PAGE_TAGS_ITEM_TITLE, url=url, disabled=not_edit_mode, - position=position) + tags_menu.add_modal_item(PAGE_TAGS_ITEM_TITLE, url=url, disabled=not_edit_mode, position=position) # Title tags site_id = self.page.node.site_id - for title in self.page.title_set.filter( - language__in=get_language_list(site_id) - ): + for title in self.page.title_set.filter(language__in=get_language_list(site_id)): try: title_extension = TitleTags.objects.get(extended_object_id=title.pk) except TitleTags.DoesNotExist: title_extension = None try: if title_extension: - url = reverse('admin:djangocms_page_tags_titletags_change', - args=(title_extension.pk,)) + url = reverse("admin:djangocms_page_tags_titletags_change", args=(title_extension.pk,)) else: - url = '%s?extended_object=%s' % ( - reverse('admin:djangocms_page_tags_titletags_add'), - title.pk) + url = "{}?extended_object={}".format( + reverse("admin:djangocms_page_tags_titletags_add"), title.pk + ) except NoReverseMatch: # pragma: no cover # not in urls pass else: position += 1 language = get_language_object(title.language) - tags_menu.add_modal_item(language['name'], url=url, disabled=not_edit_mode, - position=position) + tags_menu.add_modal_item(language["name"], url=url, disabled=not_edit_mode, position=position) diff --git a/djangocms_page_tags/locale/ar/LC_MESSAGES/django.po b/djangocms_page_tags/locale/ar/LC_MESSAGES/django.po index caa5f30..15bc289 100644 --- a/djangocms_page_tags/locale/ar/LC_MESSAGES/django.po +++ b/djangocms_page_tags/locale/ar/LC_MESSAGES/django.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# +# # Translators: # Bashar Al-Abdulhadi, 2016 msgid "" diff --git a/djangocms_page_tags/locale/de/LC_MESSAGES/django.po b/djangocms_page_tags/locale/de/LC_MESSAGES/django.po index a23930f..bb10fdd 100644 --- a/djangocms_page_tags/locale/de/LC_MESSAGES/django.po +++ b/djangocms_page_tags/locale/de/LC_MESSAGES/django.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# +# # Translators: # fsbraun , 2016 # djangoger , 2014 diff --git a/djangocms_page_tags/locale/en/LC_MESSAGES/django.po b/djangocms_page_tags/locale/en/LC_MESSAGES/django.po index 5cb5346..a6b1d36 100644 --- a/djangocms_page_tags/locale/en/LC_MESSAGES/django.po +++ b/djangocms_page_tags/locale/en/LC_MESSAGES/django.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# +# # Translators: msgid "" msgstr "" diff --git a/djangocms_page_tags/locale/es/LC_MESSAGES/django.po b/djangocms_page_tags/locale/es/LC_MESSAGES/django.po index bc33f16..457f292 100644 --- a/djangocms_page_tags/locale/es/LC_MESSAGES/django.po +++ b/djangocms_page_tags/locale/es/LC_MESSAGES/django.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# +# # Translators: # David , 2015 msgid "" diff --git a/djangocms_page_tags/locale/it/LC_MESSAGES/django.po b/djangocms_page_tags/locale/it/LC_MESSAGES/django.po index 4089b0d..f832797 100644 --- a/djangocms_page_tags/locale/it/LC_MESSAGES/django.po +++ b/djangocms_page_tags/locale/it/LC_MESSAGES/django.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# +# # Translators: # yakky , 2014 msgid "" diff --git a/djangocms_page_tags/locale/lt/LC_MESSAGES/django.po b/djangocms_page_tags/locale/lt/LC_MESSAGES/django.po index f49cf37..fc8223b 100644 --- a/djangocms_page_tags/locale/lt/LC_MESSAGES/django.po +++ b/djangocms_page_tags/locale/lt/LC_MESSAGES/django.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# +# # Translators: # Matas Dailyda , 2015 msgid "" diff --git a/djangocms_page_tags/locale/pt_BR/LC_MESSAGES/django.po b/djangocms_page_tags/locale/pt_BR/LC_MESSAGES/django.po index 25947e2..87c0519 100644 --- a/djangocms_page_tags/locale/pt_BR/LC_MESSAGES/django.po +++ b/djangocms_page_tags/locale/pt_BR/LC_MESSAGES/django.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# +# # Translators: msgid "" msgstr "" diff --git a/djangocms_page_tags/locale/ru/LC_MESSAGES/django.po b/djangocms_page_tags/locale/ru/LC_MESSAGES/django.po index 1eb1a8d..fa74300 100644 --- a/djangocms_page_tags/locale/ru/LC_MESSAGES/django.po +++ b/djangocms_page_tags/locale/ru/LC_MESSAGES/django.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# +# # Translators: # Rustam Mirzaev , 2015 msgid "" diff --git a/djangocms_page_tags/locale/tr/LC_MESSAGES/django.po b/djangocms_page_tags/locale/tr/LC_MESSAGES/django.po index 5377e8f..188a6c2 100644 --- a/djangocms_page_tags/locale/tr/LC_MESSAGES/django.po +++ b/djangocms_page_tags/locale/tr/LC_MESSAGES/django.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# +# # Translators: # Rustam Mirzaev , 2015 msgid "" diff --git a/djangocms_page_tags/migrations/0001_initial.py b/djangocms_page_tags/migrations/0001_initial.py index 00dc197..e1a1b97 100644 --- a/djangocms_page_tags/migrations/0001_initial.py +++ b/djangocms_page_tags/migrations/0001_initial.py @@ -1,40 +1,71 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - -from django.db import models, migrations import taggit_autosuggest.managers +from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('taggit', '0002_auto_20150616_2121'), - ('cms', '0003_auto_20140926_2347'), + ("taggit", "0002_auto_20150616_2121"), + ("cms", "0003_auto_20140926_2347"), ] operations = [ migrations.CreateModel( - name='PageTags', + name="PageTags", fields=[ - ('id', models.AutoField(verbose_name='ID', auto_created=True, serialize=False, primary_key=True)), - ('extended_object', models.OneToOneField(to='cms.Page', editable=False, on_delete=models.CASCADE)), - ('public_extension', models.OneToOneField(to='djangocms_page_tags.PageTags', related_name='draft_extension', null=True, editable=False, on_delete=models.CASCADE)), - ('tags', taggit_autosuggest.managers.TaggableManager(through='taggit.TaggedItem', to='taggit.Tag', verbose_name='Tags', help_text='A comma-separated list of tags.')), + ("id", models.AutoField(verbose_name="ID", auto_created=True, serialize=False, primary_key=True)), + ("extended_object", models.OneToOneField(to="cms.Page", editable=False, on_delete=models.CASCADE)), + ( + "public_extension", + models.OneToOneField( + to="djangocms_page_tags.PageTags", + related_name="draft_extension", + null=True, + editable=False, + on_delete=models.CASCADE, + ), + ), + ( + "tags", + taggit_autosuggest.managers.TaggableManager( + through="taggit.TaggedItem", + to="taggit.Tag", + verbose_name="Tags", + help_text="A comma-separated list of tags.", + ), + ), ], options={ - 'verbose_name': 'Page tags (all languages)', + "verbose_name": "Page tags (all languages)", }, ), migrations.CreateModel( - name='TitleTags', + name="TitleTags", fields=[ - ('id', models.AutoField(verbose_name='ID', auto_created=True, serialize=False, primary_key=True)), - ('extended_object', models.OneToOneField(to='cms.Title', editable=False, on_delete=models.CASCADE)), - ('public_extension', models.OneToOneField(to='djangocms_page_tags.TitleTags', related_name='draft_extension', null=True, editable=False, on_delete=models.CASCADE)), - ('tags', taggit_autosuggest.managers.TaggableManager(through='taggit.TaggedItem', to='taggit.Tag', verbose_name='Tags', help_text='A comma-separated list of tags.')), + ("id", models.AutoField(verbose_name="ID", auto_created=True, serialize=False, primary_key=True)), + ("extended_object", models.OneToOneField(to="cms.Title", editable=False, on_delete=models.CASCADE)), + ( + "public_extension", + models.OneToOneField( + to="djangocms_page_tags.TitleTags", + related_name="draft_extension", + null=True, + editable=False, + on_delete=models.CASCADE, + ), + ), + ( + "tags", + taggit_autosuggest.managers.TaggableManager( + through="taggit.TaggedItem", + to="taggit.Tag", + verbose_name="Tags", + help_text="A comma-separated list of tags.", + ), + ), ], options={ - 'verbose_name': 'Page tags (language-dependent)', + "verbose_name": "Page tags (language-dependent)", }, ), ] diff --git a/djangocms_page_tags/models.py b/djangocms_page_tags/models.py index d93936c..52b21cc 100644 --- a/djangocms_page_tags/models.py +++ b/djangocms_page_tags/models.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- -from __future__ import absolute_import, print_function, unicode_literals - from cms.extensions import PageExtension, TitleExtension from cms.extensions.extension_pool import extension_pool from cms.models import Page, Title @@ -22,7 +19,7 @@ def copy_relations(self, oldinstance, language): self.tags.set(*oldinstance.tags.all()) class Meta: - verbose_name = _('Page tags (all languages)') + verbose_name = _("Page tags (all languages)") @extension_pool.register @@ -34,42 +31,33 @@ def copy_relations(self, oldinstance, language): self.tags.set(*oldinstance.tags.all()) class Meta: - verbose_name = _('Page tags (language-dependent)') + verbose_name = _("Page tags (language-dependent)") # Cache cleanup when deleting pages / editing page extensions @receiver(pre_delete, sender=Page) def cleanup_page(sender, instance, **kwargs): site_id = instance.node.site_id - key = get_cache_key( - None, instance, '', site_id, False - ) + key = get_cache_key(None, instance, "", site_id, False) cache.delete(key) @receiver(pre_delete, sender=Title) def cleanup_title(sender, instance, **kwargs): site_id = instance.page.node.site_id - key = get_cache_key( - None, instance.page, instance.language, site_id, True - ) + key = get_cache_key(None, instance.page, instance.language, site_id, True) cache.delete(key) @receiver(post_save, sender=PageTags) def cleanup_pagetags(sender, instance, **kwargs): site_id = instance.extended_object.node.site_id - key = get_cache_key( - None, instance.extended_object, '', site_id, False - ) + key = get_cache_key(None, instance.extended_object, "", site_id, False) cache.delete(key) @receiver(post_save, sender=TitleTags) def cleanup_titletags(sender, instance, **kwargs): site_id = instance.extended_object.page.node.site_id - key = get_cache_key( - None, instance.extended_object.page, instance.extended_object.language, - site_id, True - ) + key = get_cache_key(None, instance.extended_object.page, instance.extended_object.language, site_id, True) cache.delete(key) diff --git a/djangocms_page_tags/static/djangocms_page_tags/css/djangocms_page_tags_admin.css b/djangocms_page_tags/static/djangocms_page_tags/css/djangocms_page_tags_admin.css index 2705ace..a8cdb60 100644 --- a/djangocms_page_tags/static/djangocms_page_tags/css/djangocms_page_tags_admin.css +++ b/djangocms_page_tags/static/djangocms_page_tags/css/djangocms_page_tags_admin.css @@ -18,4 +18,4 @@ ul.as-selections.vTextField { ul.as-selections li { list-style: none; -} \ No newline at end of file +} diff --git a/djangocms_page_tags/templates/djangocms_page_tags/templatetags/page_tags.html b/djangocms_page_tags/templates/djangocms_page_tags/templatetags/page_tags.html index 569b470..9baf1cf 100644 --- a/djangocms_page_tags/templates/djangocms_page_tags/templatetags/page_tags.html +++ b/djangocms_page_tags/templates/djangocms_page_tags/templatetags/page_tags.html @@ -4,4 +4,4 @@ {% trans "Page tags:"%}
    {% for tag in tags_list %}
  • {{ tag }}
  • {% endfor %}
-{% endif %} \ No newline at end of file +{% endif %} diff --git a/djangocms_page_tags/templates/djangocms_page_tags/templatetags/title_tags.html b/djangocms_page_tags/templates/djangocms_page_tags/templatetags/title_tags.html index 743f6d2..079f89b 100644 --- a/djangocms_page_tags/templates/djangocms_page_tags/templatetags/title_tags.html +++ b/djangocms_page_tags/templates/djangocms_page_tags/templatetags/title_tags.html @@ -4,4 +4,4 @@ {% trans "Title tags:"%}
    {% for tag in tags_list %}
  • {{ tag }}
  • {% endfor %}
-{% endif %} \ No newline at end of file +{% endif %} diff --git a/djangocms_page_tags/templatetags/__init__.py b/djangocms_page_tags/templatetags/__init__.py index 40a96af..e69de29 100644 --- a/djangocms_page_tags/templatetags/__init__.py +++ b/djangocms_page_tags/templatetags/__init__.py @@ -1 +0,0 @@ -# -*- coding: utf-8 -*- diff --git a/djangocms_page_tags/templatetags/page_tags.py b/djangocms_page_tags/templatetags/page_tags.py index 852f096..51a23a3 100644 --- a/djangocms_page_tags/templatetags/page_tags.py +++ b/djangocms_page_tags/templatetags/page_tags.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- -from __future__ import absolute_import, print_function, unicode_literals - from classytags.arguments import Argument from classytags.core import Options from classytags.helpers import AsTag, InclusionTag @@ -12,57 +9,63 @@ class IncludePageTagsList(InclusionTag): - template = 'djangocms_page_tags/templatetags/page_tags.html' - name = 'include_page_tags' + template = "djangocms_page_tags/templatetags/page_tags.html" + name = "include_page_tags" title = False options = Options( - Argument('page_lookup'), - Argument('lang', required=False, default=None), - Argument('site', required=False, default=None), + Argument("page_lookup"), + Argument("lang", required=False, default=None), + Argument("site", required=False, default=None), ) def get_context(self, context, page_lookup, lang, site): - request = context.get('request', False) + request = context.get("request", False) if not request: # pragma: no cover - return {'tags_list': ''} - tags_list = get_page_tags_from_request(request, page_lookup, lang, site, - self.title) + return {"tags_list": ""} + tags_list = get_page_tags_from_request(request, page_lookup, lang, site, self.title) if tags_list: - return {'tags_list': tags_list} - return {'tags_list': ''} + return {"tags_list": tags_list} + return {"tags_list": ""} + + register.tag(IncludePageTagsList) class IncludeTitleTagsList(IncludePageTagsList): - template = 'djangocms_page_tags/templatetags/title_tags.html' - name = 'include_title_tags' + template = "djangocms_page_tags/templatetags/title_tags.html" + name = "include_title_tags" title = True + + register.tag(IncludeTitleTagsList) class PageTagsList(AsTag): - name = 'page_tags' + name = "page_tags" title = False options = Options( - Argument('page_lookup'), - Argument('lang', required=False, default=None), - Argument('site', required=False, default=None), - 'as', - Argument('varname', required=True, resolve=False) + Argument("page_lookup"), + Argument("lang", required=False, default=None), + Argument("site", required=False, default=None), + "as", + Argument("varname", required=True, resolve=False), ) def get_value(self, context, page_lookup, lang, site): - request = context.get('request', False) + request = context.get("request", False) if not request: # pragma: no cover - return '' - return get_page_tags_from_request(request, page_lookup, lang, site, - self.title) + return "" + return get_page_tags_from_request(request, page_lookup, lang, site, self.title) + + register.tag(PageTagsList) class TitleTagsList(PageTagsList): - name = 'title_tags' + name = "title_tags" title = True + + register.tag(TitleTagsList) diff --git a/djangocms_page_tags/utils.py b/djangocms_page_tags/utils.py index ddeefcf..9ed8f6a 100644 --- a/djangocms_page_tags/utils.py +++ b/djangocms_page_tags/utils.py @@ -1,23 +1,19 @@ -# -*- coding: utf-8 -*- -from __future__ import absolute_import, print_function, unicode_literals - - def get_cache_key(request, page, lang, site_id, title): """ Create the cache key for the current page and tag type """ from cms.cache import _get_cache_key + from cms.models import Page from cms.templatetags.cms_tags import _get_page_by_untyped_arg - from cms.models import Page if not isinstance(page, Page): page = _get_page_by_untyped_arg(page, request, site_id) if not site_id: site_id = page.node.site_id if not title: - return _get_cache_key('page_tags', page, '', site_id) + '_type:tags_list' + return _get_cache_key("page_tags", page, "", site_id) + "_type:tags_list" else: - return _get_cache_key('title_tags', page, lang, site_id) + '_type:tags_list' + return _get_cache_key("title_tags", page, lang, site_id) + "_type:tags_list" def get_page_tags(page): @@ -30,6 +26,7 @@ def get_page_tags(page): :type: List """ from .models import PageTags + try: return page.pagetags.tags.all() except PageTags.DoesNotExist: @@ -48,7 +45,8 @@ def page_has_tag(page, tag): :type: Boolean """ from .models import PageTags - if hasattr(tag, 'slug'): + + if hasattr(tag, "slug"): slug = tag.slug else: slug = tag @@ -70,6 +68,7 @@ def get_title_tags(page, lang): :type: List """ from .models import TitleTags + try: return page.get_title_obj(language=lang, fallback=False).titletags.tags.all() except TitleTags.DoesNotExist: @@ -90,14 +89,13 @@ def title_has_tag(page, lang, tag): :type: Boolean """ from .models import TitleTags - if hasattr(tag, 'slug'): + + if hasattr(tag, "slug"): slug = tag.slug else: slug = tag try: - return page.get_title_obj( - language=lang, fallback=False - ).titletags.tags.filter(slug=slug).exists() + return page.get_title_obj(language=lang, fallback=False).titletags.tags.filter(slug=slug).exists() except TitleTags.DoesNotExist: return False @@ -118,13 +116,9 @@ def get_page_tags_from_request(request, page_lookup, lang, site, title=False): """ from cms.templatetags.cms_tags import _get_page_by_untyped_arg from cms.utils import get_language_from_request, get_site_id + from cms.utils.conf import get_cms_setting from django.core.cache import cache - try: - from cms.utils import get_cms_setting - except ImportError: - from cms.utils.conf import get_cms_setting - site_id = get_site_id(site) if lang is None: lang = get_language_from_request(request) @@ -137,7 +131,7 @@ def get_page_tags_from_request(request, page_lookup, lang, site, title=False): tags_list = get_title_tags(page, lang) else: tags_list = get_page_tags(page) - cache.set(cache_key, tags_list, timeout=get_cms_setting('CACHE_DURATIONS')['content']) + cache.set(cache_key, tags_list, timeout=get_cms_setting("CACHE_DURATIONS")["content"]) if not tags_list: tags_list = () return tags_list diff --git a/docs/Makefile b/docs/Makefile index 1005e26..0e35bee 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -174,4 +174,4 @@ xml: pseudoxml: $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml @echo - @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." \ No newline at end of file + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/docs/authors.rst b/docs/authors.rst index 94292d0..e122f91 100644 --- a/docs/authors.rst +++ b/docs/authors.rst @@ -1 +1 @@ -.. include:: ../AUTHORS.rst \ No newline at end of file +.. include:: ../AUTHORS.rst diff --git a/docs/conf.py b/docs/conf.py index 025e437..489e729 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # # complexity documentation build configuration file, created by # sphinx-quickstart on Tue Jul 9 22:26:36 2013. @@ -17,48 +16,49 @@ import sphinx.environment from docutils.utils import get_source_line +import djangocms_page_tags # isort:skip + # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) +# sys.path.insert(0, os.path.abspath('.')) cwd = os.getcwd() parent = os.path.dirname(cwd) sys.path.append(parent) -import djangocms_page_tags # isort:skip - def _warn_node(self, msg, node, *args, **kwargs): - if not msg.startswith('nonlocal image URI found:'): - self._warnfunc(msg, '%s:%s' % get_source_line(node)) + if not msg.startswith("nonlocal image URI found:"): + self._warnfunc(msg, "%s:%s" % get_source_line(node)) + sphinx.environment.BuildEnvironment.warn_node = _warn_node # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' +# needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode'] +extensions = ["sphinx.ext.autodoc", "sphinx.ext.viewcode"] # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # The suffix of source filenames. -source_suffix = '.rst' +source_suffix = ".rst" # The encoding of source files. -#source_encoding = 'utf-8-sig' +# source_encoding = 'utf-8-sig' # The master toctree document. -master_doc = 'index' +master_doc = "index" # General information about the project. -project = u'djangocms-page-tags' -copyright = u'2014, Iacopo Spalletti' +project = "djangocms-page-tags" +copyright = "2014, Iacopo Spalletti" # NOQA # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -71,174 +71,170 @@ def _warn_node(self, msg, node, *args, **kwargs): # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. -#language = None +# language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: -#today = '' +# today = '' # Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' +# today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. -exclude_patterns = ['_build'] +exclude_patterns = ["_build"] # The reST default role (used for this markup: `text`) to use for all documents. -#default_role = None +# default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True +# add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). -#add_module_names = True +# add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. -#show_authors = False +# show_authors = False # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" # A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] +# modindex_common_prefix = [] # If true, keep warnings as "system message" paragraphs in the built documents. -#keep_warnings = False +# keep_warnings = False # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'default' +html_theme = "default" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. -#html_theme_options = {} +# html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] +# html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". -#html_title = None +# html_title = None # A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None +# html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. -#html_logo = None +# html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. -#html_favicon = None +# html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -#html_static_path = ['_static'] +# html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' +# html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. -#html_use_smartypants = True +# html_use_smartypants = True # Custom sidebar templates, maps document names to template names. -#html_sidebars = {} +# html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. -#html_additional_pages = {} +# html_additional_pages = {} # If false, no module index is generated. -#html_domain_indices = True +# html_domain_indices = True # If false, no index is generated. -#html_use_index = True +# html_use_index = True # If true, the index is split into individual pages for each letter. -#html_split_index = False +# html_split_index = False # If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True +# html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True +# html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True +# html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. -#html_use_opensearch = '' +# html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None +# html_file_suffix = None # Output file base name for HTML help builder. -htmlhelp_basename = 'djangocms-page-tagsdoc' +htmlhelp_basename = "djangocms-page-tagsdoc" # -- Options for LaTeX output -------------------------------------------------- -latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -#'papersize': 'letterpaper', - -# The font size ('10pt', '11pt' or '12pt'). -#'pointsize': '10pt', +# latex_elements = { +# # The paper size ('letterpaper' or 'a4paper'). +# 'papersize': 'letterpaper', +# # The font size ('10pt', '11pt' or '12pt'). +# 'pointsize': '10pt', +# # Additional stuff for the LaTeX preamble. +# 'preamble': '', +# } -# Additional stuff for the LaTeX preamble. -#'preamble': '', -} +latex_elements = {} # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ - ('index', 'djangocms-page-tags.tex', u'djangocms-page-tags Documentation', - u'Iacopo Spalletti', 'manual'), + ("index", "djangocms-page-tags.tex", "djangocms-page-tags Documentation", "Iacopo Spalletti", "manual"), ] # The name of an image file (relative to this directory) to place at the top of # the title page. -#latex_logo = None +# latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. -#latex_use_parts = False +# latex_use_parts = False # If true, show page references after internal links. -#latex_show_pagerefs = False +# latex_show_pagerefs = False # If true, show URL addresses after external links. -#latex_show_urls = False +# latex_show_urls = False # Documents to append as an appendix to all manuals. -#latex_appendices = [] +# latex_appendices = [] # If false, no module index is generated. -#latex_domain_indices = True +# latex_domain_indices = True # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [ - ('index', 'djangocms-page-tags', u'djangocms-page-tags Documentation', - [u'Iacopo Spalletti'], 1) -] +man_pages = [("index", "djangocms-page-tags", "djangocms-page-tags Documentation", ["Iacopo Spalletti"], 1)] # If true, show URL addresses after external links. -#man_show_urls = False +# man_show_urls = False # -- Options for Texinfo output ------------------------------------------------ @@ -247,19 +243,25 @@ def _warn_node(self, msg, node, *args, **kwargs): # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - ('index', 'djangocms-page-tags', u'djangocms-page-tags Documentation', - u'Iacopo Spalletti', 'djangocms-page-tags', 'One line description of project.', - 'Miscellaneous'), + ( + "index", + "djangocms-page-tags", + "djangocms-page-tags Documentation", + "Iacopo Spalletti", + "djangocms-page-tags", + "One line description of project.", + "Miscellaneous", + ), ] # Documents to append as an appendix to all manuals. -#texinfo_appendices = [] +# texinfo_appendices = [] # If false, no module index is generated. -#texinfo_domain_indices = True +# texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. -#texinfo_show_urls = 'footnote' +# texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. -#texinfo_no_detailmenu = False +# texinfo_no_detailmenu = False diff --git a/docs/contributing.rst b/docs/contributing.rst index 3bdd7dc..e582053 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -1 +1 @@ -.. include:: ../CONTRIBUTING.rst \ No newline at end of file +.. include:: ../CONTRIBUTING.rst diff --git a/docs/history.rst b/docs/history.rst index bec23d8..2506499 100644 --- a/docs/history.rst +++ b/docs/history.rst @@ -1 +1 @@ -.. include:: ../HISTORY.rst \ No newline at end of file +.. include:: ../HISTORY.rst diff --git a/docs/installation.rst b/docs/installation.rst index 36a139c..54170f8 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -44,4 +44,4 @@ management in the template. .. _django-taggit: https://pypi.python.org/pypi/django-taggit .. _django-taggit-autosuggest: https://pypi.python.org/pypi/django-taggit-autosugges -.. _django-taggit-templatetags: https://pypi.python.org/pypi/django-taggit-templatetags \ No newline at end of file +.. _django-taggit-templatetags: https://pypi.python.org/pypi/django-taggit-templatetags diff --git a/docs/make.bat b/docs/make.bat index 2b44764..2df9a8c 100644 --- a/docs/make.bat +++ b/docs/make.bat @@ -239,4 +239,4 @@ if "%1" == "pseudoxml" ( goto end ) -:end \ No newline at end of file +:end diff --git a/docs/readme.rst b/docs/readme.rst index 6b2b3ec..72a3355 100644 --- a/docs/readme.rst +++ b/docs/readme.rst @@ -1 +1 @@ -.. include:: ../README.rst \ No newline at end of file +.. include:: ../README.rst diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..8445095 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,30 @@ +[build-system] +requires = ["setuptools>=40.6.0", "wheel"] +build-backend = "setuptools.build_meta" + +[tool.black] +line-length = 119 +target-version = ["py36"] +include = 'meta/*py' + +[tool.towncrier] +package = "djangocms-page-tags" +directory = "changes" +filename = "HISTORY.rst" +title_format = "{version} ({project_date})" + +[tool.interrogate] +ignore-init-method = true +ignore-init-module = true +ignore-magic = false +ignore-semiprivate = false +ignore-private = false +ignore-module = true +ignore-nested-functions = true +fail-under = 0 +exclude = ["docs", ".tox"] +ignore-regex = ["^get$", "^mock_.*", ".*BaseClass.*"] +verbose = 0 +quiet = false +whitelist-regex = [] +color = true diff --git a/requirements-test.txt b/requirements-test.txt index a3a5717..514438c 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -3,4 +3,4 @@ coverage<5.0 coveralls mock>=1.0.1 flake8 -djangocms-helper>=1.1 +django-app-helper>=2.2.2 diff --git a/setup.cfg b/setup.cfg index f18adc3..89a758d 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,20 +1,82 @@ -[flake8] -exclude = *.egg-info,*.eggs,.git,.settings,.tox,build,dist,docs,requirements,tmp,*migrations*,*south_migrations*,tests,data -ignore = E305 -max-line-length = 99 +[bumpversion] +current_version = 0.8.1.dev1 +parse = (?P\d+)\.(?P\d+)\.(?P\d+)(\.?)(?P[a-z]*)(?P\d*) +serialize = + {major}.{minor}.{patch}.{release}{relver} + {major}.{minor}.{patch} +commit = True +tag = True +sign_tags = True +tag_name = {new_version} +message = Release {new_version} + +[bumpversion:part:release] +optional_value = gamma +values = + dev + a + b + rc + gamma + +[bumpversion:file:meta/__init__.py] [metadata] -license-file = LICENSE +name = djangocms-page-tags +version = attr: djangocms_page_tags.__version__ +url = https://github.com/nephila/djangocms-page-tags +project_urls = + Documentation = https://djangocms-page-tags.readthedocs.io/ +author = Iacopo Spalletti +author_email = i.spalletti@nephila.it +description = Tagged pages for django CMS 3 +long_description = file: README.rst, HISTORY.rst +long_description_content_type = text/x-rst +license = BSD +license_file = LICENSE +keywords = djangocms-page-tags +classifiers = + Development Status :: 5 - Production/Stable + Framework :: Django + Intended Audience :: Developers + License :: OSI Approved :: BSD License + Natural Language :: English + Framework :: Django + Framework :: Django :: 2.2 + Framework :: Django :: 3.0 + Framework :: Django :: 3.1 + Programming Language :: Python :: 3.6 + Programming Language :: Python :: 3.7 + Programming Language :: Python :: 3.8 -[wheel] -universal = 1 +[options] +include_package_data = True +install_requires = + django-cms>=3.7 + django-taggit>=0.11.2 + django-taggit-autosuggest + django-classy-tags>=0.3.4.1 +setup_requires = + setuptools +packages = djangocms_page_tags +python_requires = >=3.6 +test_suite = cms_helper.run +zip_safe = False + +[options.package_data] +* = *.txt, *.rst +meta = *.html *.png *.gif *js *jpg *jpeg *svg *py *mo *po -[isort] -line_length = 99 -skip = migrations, south_migrations, data -combine_as_imports = true -default_section = THIRDPARTY -include_trailing_comma = true -known_first_party = djangocms_page_tags -multi_line_output = 5 -not_skip = __init__.py +[options.extras_require] +docs = + django<3.1 + djangocms-page-tags + +[upload] +repository = https://upload.pypi.org/legacy/ + +[sdist] +formats = zip + +[bdist_wheel] +universal = 1 diff --git a/setup.py b/setup.py old mode 100755 new mode 100644 index df7edc4..b908cbe --- a/setup.py +++ b/setup.py @@ -1,64 +1,3 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- +import setuptools -import os -import sys - -from setuptools import setup - -import djangocms_page_tags - -version = djangocms_page_tags.__version__ - -if sys.argv[-1] == 'publish': - os.system('python setup.py sdist upload') - print('You probably want to also tag the version now:') - print(' git tag -a %s -m "version %s"' % (version, version)) - print(' git push --tags') - sys.exit() - -readme = open('README.rst').read() -history = open('HISTORY.rst').read().replace('.. :changelog:', '') - -setup( - name='djangocms-page-tags', - version=version, - description='Tagged pages for django CMS 3', - long_description=readme + '\n\n' + history, - author='Iacopo Spalletti', - author_email='i.spalletti@nephila.it', - url='https://github.com/nephila/djangocms-page-tags', - packages=[ - 'djangocms_page_tags', - ], - include_package_data=True, - install_requires=( - 'django-cms>=3.6', - 'django-taggit>=0.11.2', - 'django-taggit-autosuggest', - 'django-classy-tags>=0.3.4.1', - ), - license='BSD', - zip_safe=False, - test_suite='cms_helper.run', - keywords='djangocms-page-tags', - classifiers=[ - 'Development Status :: 5 - Production/Stable', - 'Framework :: Django', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: BSD License', - 'Natural Language :: English', - 'Framework :: Django', - 'Framework :: Django :: 1.11', - 'Framework :: Django :: 2.0', - 'Framework :: Django :: 2.1', - 'Framework :: Django :: 2.2', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - ], -) +setuptools.setup() diff --git a/tasks.py b/tasks.py new file mode 100644 index 0000000..82261dd --- /dev/null +++ b/tasks.py @@ -0,0 +1,140 @@ +import io +import os +import re +import sys +from glob import glob + +from invoke import task + +DOCS_PORT = os.environ.get("DOCS_PORT", 8000) +#: branch prefixes for which some checks are skipped +SPECIAL_BRANCHES = ("master", "develop", "release") + + +@task +def clean(c): + """ Remove artifacts and binary files. """ + c.run("python setup.py clean --all") + patterns = ["build", "dist"] + patterns.extend(glob("*.egg*")) + patterns.append("docs/_build") + patterns.append("**/*.pyc") + for pattern in patterns: + c.run("rm -rf {}".format(pattern)) + + +@task +def lint(c): + """ Run linting tox environments. """ + c.run("tox -epep8,isort,black,pypi-description") + + +@task # NOQA +def format(c): # NOQA + """ Run code formatting tasks. """ + c.run("tox -eblacken,isort_format") + + +@task +def towncrier_check(c): # NOQA + """ Check towncrier files. """ + output = io.StringIO() + c.run("git branch --contains HEAD", out_stream=output) + skipped_branch_prefix = ["pull/", "develop", "master", "HEAD"] + # cleanup branch names by removing PR-only names in local, remote and disconnected branches to ensure the current + # (i.e. user defined) branch name is used + branches = list( + filter( + lambda x: x and all(not x.startswith(part) for part in skipped_branch_prefix), + ( + branch.replace("origin/", "").replace("remotes/", "").strip("* (") + for branch in output.getvalue().split("\n") + ), + ) + ) + print("Candidate branches", ", ".join(output.getvalue().split("\n"))) + if not branches: + # if no branch name matches, we are in one of the excluded branches above, so we just exit + print("Skip check, branch excluded by configuration") + return + branch = branches[0] + towncrier_file = None + for branch in branches: + if any(branch.startswith(prefix) for prefix in SPECIAL_BRANCHES): + sys.exit(0) + try: + parts = re.search(r"(?P\w+)/\D*(?P\d+)\D*", branch).groups() + towncrier_file = os.path.join("changes", "{1}.{0}".format(*parts)) + if not os.path.exists(towncrier_file) or os.path.getsize(towncrier_file) == 0: + print( + "=========================\n" + "Current tree does not contain the towncrier file {} or file is empty\n" + "please check CONTRIBUTING documentation.\n" + "=========================" + "".format(towncrier_file) + ) + sys.exit(2) + else: + break + except AttributeError: + pass + if not towncrier_file: + print( + "=========================\n" + "Branch {} does not respect the '/(-)-description' format\n" + "=========================\n" + "".format(branch) + ) + sys.exit(1) + + +@task +def test(c): + """ Run test in local environment. """ + c.run("python setup.py test") + + +@task +def test_all(c): + """ Run all tox environments. """ + c.run("tox") + + +@task +def coverage(c): + """ Run test with coverage in local environment. """ + c.run("coverage erase") + c.run("run setup.py test") + c.run("report -m") + + +@task +def tag_release(c, level): + """ Tag release version. """ + c.run("bumpversion --list %s --no-tag" % level) + + +@task +def tag_dev(c, level="patch"): + """ Tag development version. """ + c.run("bumpversion --list %s --message='Bump develop version [ci skip]' --no-tag" % level) + + +@task(pre=[clean]) +def docbuild(c): + """ Build documentation. """ + os.chdir("docs") + build_dir = os.environ.get("BUILD_DIR", "_build/html") + c.run("python -msphinx -W -b html -d _build/doctrees . %s" % build_dir) + + +@task(docbuild) +def docserve(c): + """ Serve docs at http://localhost:$DOCS_PORT/ (default port is 8000). """ + from livereload import Server + + server = Server() + server.watch("docs/conf.py", lambda: docbuild(c)) + server.watch("CONTRIBUTING.rst", lambda: docbuild(c)) + server.watch("docs/*.rst", lambda: docbuild(c)) + server.serve(port=DOCS_PORT, root="_build/html") diff --git a/tests/__init__.py b/tests/__init__.py index 81653a4..a09f24f 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,9 +1,6 @@ -# -*- coding: utf-8 -*- """ Tests for `djangocms_page_tags` module. """ -from __future__ import absolute_import, print_function, unicode_literals - from django.core.cache import cache from djangocms_helper.base_test import BaseTestCase @@ -12,15 +9,20 @@ class BaseTest(BaseTestCase): """ Base class with utility function """ + _pages_data = ( - {'en': {'title': 'page one', 'template': 'page_tags.html', 'publish': True}, - 'fr': {'title': 'page un', 'publish': True}, - 'it': {'title': 'pagina uno', 'publish': True}}, - {'en': {'title': 'page two', 'template': 'page_tags.html', 'publish': True}, - 'fr': {'title': 'page deux', 'publish': True}, - 'it': {'title': 'pagina due', 'publish': True}}, + { + "en": {"title": "page one", "template": "page_tags.html", "publish": True}, + "fr": {"title": "page un", "publish": True}, + "it": {"title": "pagina uno", "publish": True}, + }, + { + "en": {"title": "page two", "template": "page_tags.html", "publish": True}, + "fr": {"title": "page deux", "publish": True}, + "it": {"title": "pagina due", "publish": True}, + }, ) def setUp(self): - super(BaseTest, self).setUp() + super().setUp() cache.clear() diff --git a/tests/test_general.py b/tests/test_general.py index 1c65586..d864ffe 100644 --- a/tests/test_general.py +++ b/tests/test_general.py @@ -1,23 +1,25 @@ -# -*- coding: utf-8 -*- -from __future__ import absolute_import, print_function, unicode_literals - from django.core.cache import cache from django.template.defaultfilters import slugify from taggit.models import Tag from djangocms_page_tags import models from djangocms_page_tags.utils import ( - get_cache_key, get_page_tags, get_page_tags_from_request, get_title_tags, - get_title_tags_from_request, page_has_tag, title_has_tag, + get_cache_key, + get_page_tags, + get_page_tags_from_request, + get_title_tags, + get_title_tags_from_request, + page_has_tag, + title_has_tag, ) from . import BaseTest class PageTagsUtilsTest(BaseTest): - tag_strings = ['tag one', 'tag two', 'tag three'] - tag_strings_fr = ['tag un', 'tag deux', 'tag trois'] - tag_strings_it = ['tag uno', 'tag due', 'tag tre'] + tag_strings = ["tag one", "tag two", "tag three"] + tag_strings_fr = ["tag un", "tag deux", "tag trois"] + tag_strings_it = ["tag uno", "tag due", "tag tre"] def test_page_tags(self): """ @@ -29,10 +31,10 @@ def test_page_tags(self): self.assertTrue(page_has_tag(page, slugify(self.tag_strings[0]))) self.assertTrue(page_has_tag(page, Tag.objects.get(slug=slugify(self.tag_strings[0])))) - self.assertEqual(set(self.tag_strings), set([tag.name for tag in get_page_tags(page)])) + self.assertEqual(set(self.tag_strings), {tag.name for tag in get_page_tags(page)}) self.assertFalse(page_has_tag(page_2, slugify(self.tag_strings[0]))) - self.assertEqual(set(), set([tag.name for tag in get_page_tags(page_2)])) + self.assertEqual(set(), {tag.name for tag in get_page_tags(page_2)}) def test_title_tags(self): """ @@ -41,23 +43,23 @@ def test_title_tags(self): page, page_2 = self.get_pages() # Assign and test english tags - title_en = page.get_title_obj(language='en') + title_en = page.get_title_obj(language="en") title_en_tags = models.TitleTags.objects.create(extended_object=title_en) title_en_tags.tags.add(*self.tag_strings) - self.assertTrue(title_has_tag(page, 'en', slugify(self.tag_strings[0]))) - self.assertTrue(title_has_tag(page, 'en', Tag.objects.get(slug=slugify(self.tag_strings[0])))) - self.assertEqual(set(self.tag_strings), set([tag.name for tag in get_title_tags(page, 'en')])) + self.assertTrue(title_has_tag(page, "en", slugify(self.tag_strings[0]))) + self.assertTrue(title_has_tag(page, "en", Tag.objects.get(slug=slugify(self.tag_strings[0])))) + self.assertEqual(set(self.tag_strings), {tag.name for tag in get_title_tags(page, "en")}) # Assign and test french tags - title_fr = page.get_title_obj(language='fr', fallback=False) + title_fr = page.get_title_obj(language="fr", fallback=False) title_fr_tags = models.TitleTags.objects.create(extended_object=title_fr) title_fr_tags.tags.add(*self.tag_strings_fr) - self.assertTrue(title_has_tag(page, 'fr', slugify(self.tag_strings_fr[0]))) - self.assertEqual(set(self.tag_strings_fr), set([tag.name for tag in get_title_tags(page, 'fr')])) + self.assertTrue(title_has_tag(page, "fr", slugify(self.tag_strings_fr[0]))) + self.assertEqual(set(self.tag_strings_fr), {tag.name for tag in get_title_tags(page, "fr")}) - self.assertFalse(title_has_tag(page, 'it', slugify(self.tag_strings_fr[0]))) - self.assertEqual(set(), set([tag.name for tag in get_title_tags(page, 'it')])) + self.assertFalse(title_has_tag(page, "it", slugify(self.tag_strings_fr[0]))) + self.assertEqual(set(), {tag.name for tag in get_title_tags(page, "it")}) def test_tags_request_page(self): """ @@ -73,26 +75,24 @@ def test_tags_request_page(self): cache.clear() # Reload page from request and extract tags from it - request = self.get_request(page, 'en') - try: - site_id = page.node.site_id - except AttributeError: # CMS_3_4 - site_id = page.site_id + request = self.get_request(page, "en") + site_id = page.node.site_id + with self.assertNumQueries(4): # 1st query to get the page for the key lookup # 2st query to get the page in get_page_tags_from_request # 3nd query to get the page extension # 4rd query to extract tags data - tags_list = get_page_tags_from_request(request, page.get_public_object().pk, 'en', site_id) - self.assertEqual(set(self.tag_strings), set([tag.name for tag in tags_list])) + tags_list = get_page_tags_from_request(request, page.get_public_object().pk, "en", site_id) + self.assertEqual(set(self.tag_strings), {tag.name for tag in tags_list}) with self.assertNumQueries(1): # Second run executes exactly 1 query as data is fetched from cache # 1st query to get the page for the key lookup - tags_list = get_page_tags_from_request(request, page.get_public_object().pk, 'en', site_id) + tags_list = get_page_tags_from_request(request, page.get_public_object().pk, "en", site_id) # Empty page has no tags - tags_list = get_page_tags_from_request(request, 40, 'en', 1) + tags_list = get_page_tags_from_request(request, 40, "en", 1) self.assertEqual(set(), set(tags_list)) def test_tags_request_title(self): @@ -102,19 +102,17 @@ def test_tags_request_title(self): page, page_2 = self.get_pages() # Assign tags to title - title_tags = models.TitleTags.objects.create(extended_object=page.get_title_obj('en')) + title_tags = models.TitleTags.objects.create(extended_object=page.get_title_obj("en")) title_tags.tags.add(*self.tag_strings) for lang in self.languages: page.publish(lang) - try: - site_id = page.node.site_id - except AttributeError: # CMS_3_4 - site_id = page.site_id + site_id = page.node.site_id + # Reload page from request and extract tags from it - request = self.get_request(page, 'en') - tags_list = get_title_tags_from_request(request, page.get_public_object().pk, 'en', site_id) - self.assertEqual(set(self.tag_strings), set([tag.name for tag in tags_list])) + request = self.get_request(page, "en") + tags_list = get_title_tags_from_request(request, page.get_public_object().pk, "en", site_id) + self.assertEqual(set(self.tag_strings), {tag.name for tag in tags_list}) def test_cache_cleanup(self): """ @@ -123,28 +121,26 @@ def test_cache_cleanup(self): page, page_2 = self.get_pages() # Assign tags to title - title_tags = models.TitleTags.objects.create(extended_object=page.get_title_obj('en')) + title_tags = models.TitleTags.objects.create(extended_object=page.get_title_obj("en")) title_tags.tags.add(*self.tag_strings) page_tags = models.PageTags.objects.create(extended_object=page) page_tags.tags.add(*self.tag_strings) for lang in self.languages: page.publish(lang) - try: - site_id = page.node.site_id - except AttributeError: # CMS_3_4 - site_id = page.site_id + site_id = page.node.site_id + # Reload page from request and extract tags from it - request = self.get_request(page, 'en') - title_tags_list = get_title_tags_from_request(request, page.get_public_object().pk, 'en', site_id) - page_tags_list = get_page_tags_from_request(request, page.get_public_object().pk, 'en', site_id) + request = self.get_request(page, "en") + title_tags_list = get_title_tags_from_request(request, page.get_public_object().pk, "en", site_id) + page_tags_list = get_page_tags_from_request(request, page.get_public_object().pk, "en", site_id) try: site_id = page.get_public_object().node.site_id except AttributeError: # CMS_3_4 site_id = page.get_public_object().site_id - title_key = get_cache_key(None, page.get_public_object(), 'en', site_id, True) - page_key = get_cache_key(None, page.get_public_object(), '', site_id, False) + title_key = get_cache_key(None, page.get_public_object(), "en", site_id, True) + page_key = get_cache_key(None, page.get_public_object(), "", site_id, False) title_cache = cache.get(title_key) page_cache = cache.get(page_key) @@ -152,7 +148,7 @@ def test_cache_cleanup(self): self.assertEqual(set(title_tags_list), set(title_cache)) self.assertEqual(set(page_tags_list), set(page_cache)) - page.get_public_object().get_title_obj('en').delete() + page.get_public_object().get_title_obj("en").delete() self.assertIsNone(cache.get(title_key)) page.get_public_object().delete() diff --git a/tests/test_templatetags.py b/tests/test_templatetags.py index 518f55b..c02c847 100644 --- a/tests/test_templatetags.py +++ b/tests/test_templatetags.py @@ -1,9 +1,5 @@ -# -*- coding: utf-8 -*- -from __future__ import absolute_import, print_function, unicode_literals - from cms.views import details from django.contrib.auth.models import AnonymousUser -from taggit.models import Tag from djangocms_page_tags.models import PageTags, TitleTags @@ -11,35 +7,34 @@ class TemplateTagsTest(BaseTest): - def test_page_tags(self): """ Test page-level templatetags """ page1, page2 = self.get_pages() page_ext = PageTags.objects.create(extended_object=page1) - page_ext.tags.add('pagetag.1', 'pagetag.2') + page_ext.tags.add("pagetag.1", "pagetag.2") for lang in self.languages: page1.publish(lang) - tags = Tag.objects.filter(name__in=('pagetag.1', 'pagetag.2')) + # tags = Tag.objects.filter(name__in=("pagetag.1", "pagetag.2")) request = self.get_page_request(page1.get_public_object(), AnonymousUser()) response = details(request, None) - self.assertContains(response, '
  • pagetag.1
  • ') - self.assertContains(response, '
  • pagetag.2
  • ') + self.assertContains(response, "
  • pagetag.1
  • ") + self.assertContains(response, "
  • pagetag.2
  • ") def test_title_tags(self): """ Test title-level templatetags """ page1, page2 = self.get_pages() - title_ext = TitleTags.objects.create(extended_object=page2.get_title_obj('en')) - title_ext.tags.add('titletag.1', 'titletag.2') + title_ext = TitleTags.objects.create(extended_object=page2.get_title_obj("en")) + title_ext.tags.add("titletag.1", "titletag.2") for lang in self.languages: page2.publish(lang) - tags = Tag.objects.filter(name__in=('titletag.1', 'titletag.2')) + # tags = Tag.objects.filter(name__in=("titletag.1", "titletag.2")) request = self.get_page_request(page2.get_public_object(), AnonymousUser()) response = details(request, None) - self.assertContains(response, '
  • titletag.2
  • ') - self.assertContains(response, '
  • titletag.1
  • ') + self.assertContains(response, "
  • titletag.2
  • ") + self.assertContains(response, "
  • titletag.1
  • ") diff --git a/tests/test_toolbar.py b/tests/test_toolbar.py index f331fbe..0d581f0 100644 --- a/tests/test_toolbar.py +++ b/tests/test_toolbar.py @@ -1,9 +1,6 @@ -# -*- coding: utf-8 -*- """ Tests for `djangocms_page_tags` modules module. """ -from __future__ import absolute_import, print_function, unicode_literals - from cms.toolbar.items import Menu, ModalItem, SubMenu from cms.utils.i18n import get_language_object from django.contrib.auth.models import Permission, User @@ -18,16 +15,16 @@ class ToolbarTest(BaseTest): - def test_no_page(self): """ Test that no page menu is present if request not in a page """ from cms.toolbar.toolbar import CMSToolbar - request = self.get_page_request(None, self.user, '/', edit=True) + + request = self.get_page_request(None, self.user, "/", edit=True) toolbar = CMSToolbar(request) toolbar.get_left_items() - page_menu = toolbar.find_items(Menu, name='Page') + page_menu = toolbar.find_items(Menu, name="Page") self.assertEqual(page_menu, []) def test_no_perm(self): @@ -35,11 +32,12 @@ def test_no_perm(self): Test that no page menu is present if user has no perm """ from cms.toolbar.toolbar import CMSToolbar + page1, page2 = self.get_pages() - request = self.get_page_request(page1, self.user_staff, '/', edit=True) + request = self.get_page_request(page1, self.user_staff, "/", edit=True) toolbar = CMSToolbar(request) toolbar.get_left_items() - page_menu = toolbar.find_items(Menu, name='Page') + page_menu = toolbar.find_items(Menu, name="Page") try: self.assertEqual(page_menu, []) except AssertionError: @@ -51,15 +49,18 @@ def test_perm(self): Test that page tags menu is present if user has Page.change_perm """ from cms.toolbar.toolbar import CMSToolbar + page1, page2 = self.get_pages() - self.user_staff.user_permissions.add(Permission.objects.get(codename='change_page')) + self.user_staff.user_permissions.add(Permission.objects.get(codename="change_page")) self.user_staff = User.objects.get(pk=self.user_staff.pk) - request = self.get_page_request(page1, self.user_staff, '/', edit=True) + request = self.get_page_request(page1, self.user_staff, "/", edit=True) toolbar = CMSToolbar(request) toolbar.get_left_items() - page_menu = toolbar.find_items(Menu, name='Page')[0].item + page_menu = toolbar.find_items(Menu, name="Page")[0].item tags_menu = page_menu.find_items(SubMenu, name=force_text(PAGE_TAGS_MENU_TITLE))[0].item - self.assertEqual(len(tags_menu.find_items(ModalItem, name="{0}...".format(force_text(PAGE_TAGS_ITEM_TITLE)))), 1) + self.assertEqual( + len(tags_menu.find_items(ModalItem, name="{}...".format(force_text(PAGE_TAGS_ITEM_TITLE)))), 1 + ) @override_settings(CMS_PERMISSION=True) def test_perm_permissions(self): @@ -67,13 +68,14 @@ def test_perm_permissions(self): Test that no page menu is present if user has general page Page.change_perm but not permission on current page """ from cms.toolbar.toolbar import CMSToolbar + page1, page2 = self.get_pages() - self.user_staff.user_permissions.add(Permission.objects.get(codename='change_page')) + self.user_staff.user_permissions.add(Permission.objects.get(codename="change_page")) self.user_staff = User.objects.get(pk=self.user_staff.pk) - request = self.get_page_request(page1, self.user_staff, '/', edit=True) + request = self.get_page_request(page1, self.user_staff, "/", edit=True) toolbar = CMSToolbar(request) toolbar.get_left_items() - page_menu = toolbar.find_items(Menu, name='Page') + page_menu = toolbar.find_items(Menu, name="Page") try: self.assertEqual(page_menu, []) except AssertionError: @@ -85,63 +87,77 @@ def test_toolbar(self): Test that PageTags/TitleTags items are present for superuser """ from cms.toolbar.toolbar import CMSToolbar - NEW_CMS_LANGS = { + + NEW_CMS_LANGS = { # noqa: N806 1: [ { - 'code': 'en', - 'name': 'English', - 'public': True, + "code": "en", + "name": "English", + "public": True, }, { - 'code': 'it', - 'name': 'Italiano', - 'public': True, + "code": "it", + "name": "Italiano", + "public": True, }, ], - 'default': { - 'hide_untranslated': False, + "default": { + "hide_untranslated": False, }, } page1, page2 = self.get_pages() with self.settings(CMS_LANGUAGES=NEW_CMS_LANGS): - request = self.get_page_request(page1, self.user, '/', edit=True) + request = self.get_page_request(page1, self.user, "/", edit=True) toolbar = CMSToolbar(request) toolbar.get_left_items() - page_menu = toolbar.find_items(Menu, name='Page')[0].item + page_menu = toolbar.find_items(Menu, name="Page")[0].item tags_menu = page_menu.find_items(SubMenu, name=force_text(PAGE_TAGS_MENU_TITLE))[0].item - self.assertEqual(len(tags_menu.find_items(ModalItem, name="{0}...".format(force_text(PAGE_TAGS_ITEM_TITLE)))), 1) - self.assertEqual(len(tags_menu.find_items(ModalItem)), len(NEW_CMS_LANGS[1])+1) + self.assertEqual( + len(tags_menu.find_items(ModalItem, name="{}...".format(force_text(PAGE_TAGS_ITEM_TITLE)))), 1 + ) + self.assertEqual(len(tags_menu.find_items(ModalItem)), len(NEW_CMS_LANGS[1]) + 1) def test_toolbar_with_items(self): """ Test that PageTags/TitleTags items are present for superuser if PageTags/TitleTags exists for current page """ from cms.toolbar.toolbar import CMSToolbar + page1, page2 = self.get_pages() page_ext = PageTags.objects.create(extended_object=page1) - title_tags = TitleTags.objects.create(extended_object=page1.get_title_obj('en')) - request = self.get_page_request(page1, self.user, '/', edit=True) + title_tags = TitleTags.objects.create(extended_object=page1.get_title_obj("en")) + request = self.get_page_request(page1, self.user, "/", edit=True) toolbar = CMSToolbar(request) toolbar.get_left_items() - page_menu = toolbar.find_items(Menu, name='Page')[0].item + page_menu = toolbar.find_items(Menu, name="Page")[0].item tags_menu = page_menu.find_items(SubMenu, name=force_text(PAGE_TAGS_MENU_TITLE))[0].item - pagetags_menu = tags_menu.find_items(ModalItem, name="{0}...".format(force_text(PAGE_TAGS_ITEM_TITLE))) + pagetags_menu = tags_menu.find_items(ModalItem, name="{}...".format(force_text(PAGE_TAGS_ITEM_TITLE))) self.assertEqual(len(pagetags_menu), 1) self.assertEqual(len(pagetags_menu), 1) - self.assertTrue(pagetags_menu[0].item.url.startswith(reverse('admin:djangocms_page_tags_pagetags_change', args=(page_ext.pk,)))) + self.assertTrue( + pagetags_menu[0].item.url.startswith( + reverse("admin:djangocms_page_tags_pagetags_change", args=(page_ext.pk,)) + ) + ) url_change = False url_add = False for title in page1.title_set.all(): language = get_language_object(title.language) - titletags_menu = tags_menu.find_items(ModalItem, name='{0}...'.format(language['name'])) + titletags_menu = tags_menu.find_items(ModalItem, name="{}...".format(language["name"])) self.assertEqual(len(titletags_menu), 1) try: title_ext = TitleTags.objects.get(extended_object_id=title.pk) self.assertEqual(title_ext, title_tags) - self.assertTrue(titletags_menu[0].item.url.startswith(reverse('admin:djangocms_page_tags_titletags_change', args=(title_ext.pk,)))) + self.assertTrue( + titletags_menu[0].item.url.startswith( + reverse("admin:djangocms_page_tags_titletags_change", args=(title_ext.pk,)) + ) + ) url_change = True except TitleTags.DoesNotExist: - self.assertTrue(titletags_menu[0].item.url.startswith(reverse('admin:djangocms_page_tags_titletags_add'))) + self.assertTrue( + titletags_menu[0].item.url.startswith(reverse("admin:djangocms_page_tags_titletags_add")) + ) url_add = True self.assertTrue(url_change and url_add) diff --git a/tests/test_utils/__init__.py b/tests/test_utils/__init__.py index 40a96af..e69de29 100644 --- a/tests/test_utils/__init__.py +++ b/tests/test_utils/__init__.py @@ -1 +0,0 @@ -# -*- coding: utf-8 -*- diff --git a/tests/test_utils/templates/page_tags.html b/tests/test_utils/templates/page_tags.html index 4504901..479b84c 100644 --- a/tests/test_utils/templates/page_tags.html +++ b/tests/test_utils/templates/page_tags.html @@ -7,4 +7,4 @@ {% title_tags request.current_page as ttags_list %} {% include_page_tags request.current_page %} {% include_title_tags request.current_page %} -{% render_block "js" %} \ No newline at end of file +{% render_block "js" %} diff --git a/tests/test_utils/urls.py b/tests/test_utils/urls.py index c7c2fd8..09cb871 100644 --- a/tests/test_utils/urls.py +++ b/tests/test_utils/urls.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- -from __future__ import absolute_import, print_function, unicode_literals - from cms.utils.conf import get_cms_setting from django.conf import settings from django.conf.urls import include, url @@ -13,22 +10,20 @@ admin.autodiscover() urlpatterns = [ - url(r'^taggit_autosuggest/', include('taggit_autosuggest.urls')), - url(r'^media/(?P.*)$', serve, - {'document_root': settings.MEDIA_ROOT, 'show_indexes': True}), - url(r'^media/cms/(?P.*)$', serve, - {'document_root': get_cms_setting('MEDIA_ROOT'), 'show_indexes': True}), + url(r"^taggit_autosuggest/", include("taggit_autosuggest.urls")), + url(r"^media/(?P.*)$", serve, {"document_root": settings.MEDIA_ROOT, "show_indexes": True}), + url(r"^media/cms/(?P.*)$", serve, {"document_root": get_cms_setting("MEDIA_ROOT"), "show_indexes": True}), ] urlpatterns += staticfiles_urlpatterns() if not DJANGO_1_11: urlpatterns += i18n_patterns( - url(r'^admin/', admin.site.urls), - url(r'^', include('cms.urls')), + url(r"^admin/", admin.site.urls), + url(r"^", include("cms.urls")), ) else: urlpatterns += i18n_patterns( - url(r'^admin/', include(admin.site.urls)), - url(r'^', include('cms.urls')), + url(r"^admin/", include(admin.site.urls)), + url(r"^", include("cms.urls")), ) diff --git a/tox.ini b/tox.ini index 0565bbe..42b5476 100644 --- a/tox.ini +++ b/tox.ini @@ -1,39 +1,161 @@ [tox] -envlist = docs,pep8,isort,py{36,35,27}-django{22,21,20,111}-cms{37,36} +envlist = + black + blacken + docs + isort + isort_format + pep8 + pypi-description + towncrier + py{38,37,36}-django{31}-cms{38} + py{38,37,36}-django{30}-cms{38,37} + py{38,37,36}-django{22}-cms{38,37} [testenv] -commands = {env:COMMAND:python} setup.py test +commands = {env:COMMAND:python} cms_helper.py djangocms_page_tags test {posargs} deps = - django111: Django>=1.11,<2.0 - django111: django-taggit>=0.18 - django111: django-formtools>=2.1,<2.2 - django20: Django>=2.0,<2.1 - django20: django-taggit>=0.18 - django21: Django>=2.1,<2.2 - django21: django-taggit>=0.18 django22: Django>=2.2,<3.0 - django22: django-taggit>=0.18 - cms36: https://github.com/divio/django-cms/archive/release/3.6.x.zip + django30: Django>=3.0,<3.1 + django31: Django>=3.1,<3.2 cms37: https://github.com/divio/django-cms/archive/release/3.7.x.zip + cms38: https://github.com/divio/django-cms/archive/release/3.8.x.zip -r{toxinidir}/requirements-test.txt +passenv = + COMMAND + PYTEST_* [testenv:pep8] -deps = flake8 -commands = flake8 +commands = + {envpython} -m flake8 + {envpython} -minterrogate -c pyproject.toml djangocms_page_tags tests +deps = + interrogate + flake8 + flake8-broken-line + flake8-bugbear + flake8-builtins + flake8-coding + flake8-commas + flake8-comprehensions + flake8-eradicate + flake8-quotes + flake8-tidy-imports + pep8-naming skip_install = true [testenv:isort] -deps = isort -commands = isort -c -rc -df djangocms_page_tags tests +commands = + {envpython} -m isort -c --df djangocms_page_tags tests +deps = isort>5,<6 +skip_install = true + +[testenv:isort_format] +commands = + {envpython} -m isort djangocms_page_tags tests +deps = {[testenv:isort]deps} +skip_install = true + +[testenv:black] +commands = + {envpython} -m black --check --diff . +deps = black +skip_install = true + +[testenv:blacken] +commands = + {envpython} -m black . +deps = {[testenv:black]deps} skip_install = true [testenv:docs] +commands = + {envpython} -m invoke docbuild deps = + invoke sphinx sphinx-rtd-theme - Django<2.0 + sphinx-autobuild + livereload~=2.6 + .[docs] -rrequirements-test.txt -changedir=docs skip_install = true -commands= - sphinx-build -W -b html -d {envtmpdir}/doctrees . {toxinidir}/docs/_build/html + +[testenv:towncrier] +commands = + {envpython} -m invoke towncrier-check +deps = + invoke +skip_install = true + +[testenv:pypi-description] +commands = + {envpython} -m invoke clean + {envpython} -m check_manifest + {envpython} -m pep517.build . + {envpython} -m twine check dist/* +deps = + invoke + check-manifest + pep517 + twine +skip_install = true + +[testenv:release] +commands = + {envpython} -m invoke clean + {envpython} -m check_manifest + {envpython} -m pep517.build . + {envpython} -m twine upload {posargs} dist/* +deps = {[testenv:pypi-description]deps} +passenv = + TWINE_* +skip_install = true + +[flake8] +exclude = *.egg-info,.git,.settings,.tox,build,dist,docs,requirements,tmp,*migrations*,tests,data +ignore = E800, W503, C812, C813, C815, C818, C819, C408 +max-line-length = 119 +# flake8-quotes +inline-quotes = double +# flake8-coding +no-accept-encodings = True +# flake8-tidy-imports +banned-modules = __future__ = this project supports python3 only + +[isort] +combine_as_imports = true +default_section = THIRDPARTY +force_grid_wrap = 0 +include_trailing_comma = true +known_first_party = djangocms_page_tags +line_length = 119 +multi_line_output = 3 +skip = data, .tox +use_parentheses = True + +[check-manifest] +ignore = + .* + *.ini + *.toml + *.json + *.txt + *.yml + *.yaml + .tx/** + changes/** + docs/** + cms_helper.py + aldryn_config.py + tasks.py + tests/** + *.mo +ignore-bad-ideas = + *.mo + +[pytest] +DJANGO_SETTINGS_MODULE = cms_helper +python_files = test_*.py +traceback = short +addopts = --reuse-db