diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3dfcf30..8eb2414 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,14 +11,14 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: fetch-depth: 0 - name: Set up Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: - python-version: 3.8 + python-version: "3.10" - name: Install dependencies run: | diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a3f0cce..d6f9e0e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -9,13 +9,13 @@ jobs: fail-fast: false max-parallel: 5 matrix: - python-version: ['3.6', '3.7', '3.8', '3.9', '3.10'] + python-version: ['3.7', '3.8', '3.9', '3.10', '3.11-dev'] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} @@ -25,7 +25,7 @@ jobs: echo "::set-output name=dir::$(pip cache dir)" - name: Cache - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ${{ steps.pip-cache.outputs.dir }} key: @@ -43,6 +43,6 @@ jobs: tox -v - name: Upload coverage - uses: codecov/codecov-action@v1 + uses: codecov/codecov-action@v2 with: name: Python ${{ matrix.python-version }} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..84f06c5 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,15 @@ +repos: + - repo: https://github.com/asottile/pyupgrade + rev: v2.34.0 + hooks: + - id: pyupgrade + args: [--py37-plus] + + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.3.0 + hooks: + - id: check-merge-conflict + - id: check-yaml + +ci: + autoupdate_schedule: quarterly diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..e0d5efa --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,46 @@ +# Code of Conduct + +As contributors and maintainers of the Jazzband projects, and in the interest of +fostering an open and welcoming community, we pledge to respect all people who +contribute through reporting issues, posting feature requests, updating documentation, +submitting pull requests or patches, and other activities. + +We are committed to making participation in the Jazzband a harassment-free experience +for everyone, regardless of the level of experience, gender, gender identity and +expression, sexual orientation, disability, personal appearance, body size, race, +ethnicity, age, religion, or nationality. + +Examples of unacceptable behavior by participants include: + +- The use of sexualized language or imagery +- Personal attacks +- Trolling or insulting/derogatory comments +- Public or private harassment +- Publishing other's private information, such as physical or electronic addresses, + without explicit permission +- Other unethical or unprofessional conduct + +The Jazzband roadies have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are not +aligned to this Code of Conduct, or to ban temporarily or permanently any contributor +for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +By adopting this Code of Conduct, the roadies commit themselves to fairly and +consistently applying these principles to every aspect of managing the jazzband +projects. Roadies who do not follow or enforce the Code of Conduct may be permanently +removed from the Jazzband roadies. + +This code of conduct applies both within project spaces and in public spaces when an +individual is representing the project or its community. + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by +contacting the roadies at `roadies@jazzband.co`. All complaints will be reviewed and +investigated and will result in a response that is deemed necessary and appropriate to +the circumstances. Roadies are obligated to maintain confidentiality with regard to the +reporter of an incident. + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version +1.3.0, available at [https://contributor-covenant.org/version/1/3/0/][version] + +[homepage]: https://contributor-covenant.org +[version]: https://contributor-covenant.org/version/1/3/0/ diff --git a/dbtemplates/admin.py b/dbtemplates/admin.py index 2e4486c..bb079bb 100644 --- a/dbtemplates/admin.py +++ b/dbtemplates/admin.py @@ -38,8 +38,8 @@ class CodeMirrorTextArea(forms.Textarea): def render(self, name, value, attrs=None, renderer=None): result = [] result.append( - super(CodeMirrorTextArea, self).render(name, value, attrs)) - result.append(u""" + super().render(name, value, attrs)) + result.append(""" """ % dict(media_prefix=settings.DBTEMPLATES_MEDIA_PREFIX, name=name)) - return mark_safe(u"".join(result)) + return mark_safe("".join(result)) if settings.DBTEMPLATES_USE_CODEMIRROR: @@ -147,7 +147,7 @@ class TemplateAdmin(TemplateModelAdmin): for template in queryset: valid, error = check_template_syntax(template) if not valid: - errors.append('%s: %s' % (template.name, error)) + errors.append(f'{template.name}: {error}') if errors: count = len(errors) message = ungettext( diff --git a/dbtemplates/loader.py b/dbtemplates/loader.py index 086a38b..403c460 100644 --- a/dbtemplates/loader.py +++ b/dbtemplates/loader.py @@ -33,7 +33,7 @@ class Loader(BaseLoader): def _load_and_store_template(self, template_name, cache_key, site, **params): template = Template.objects.get(name__exact=template_name, **params) db = router.db_for_read(Template, instance=template) - display_name = 'dbtemplates:%s:%s:%s' % (db, template_name, site.domain) + display_name = f'dbtemplates:{db}:{template_name}:{site.domain}' return set_and_return(cache_key, template.content, display_name) def _load_template_source(self, template_name, template_dirs=None): diff --git a/dbtemplates/management/commands/check_template_syntax.py b/dbtemplates/management/commands/check_template_syntax.py index c82ea96..3837e65 100644 --- a/dbtemplates/management/commands/check_template_syntax.py +++ b/dbtemplates/management/commands/check_template_syntax.py @@ -12,7 +12,7 @@ class Command(BaseCommand): for template in Template.objects.all(): valid, error = check_template_syntax(template) if not valid: - errors.append('%s: %s' % (template.name, error)) + errors.append(f'{template.name}: {error}') if errors: raise CommandError( 'Some templates contained errors\n%s' % '\n'.join(errors)) diff --git a/dbtemplates/management/commands/create_error_templates.py b/dbtemplates/management/commands/create_error_templates.py index f09fe48..3c53d24 100644 --- a/dbtemplates/management/commands/create_error_templates.py +++ b/dbtemplates/management/commands/create_error_templates.py @@ -43,7 +43,7 @@ class Command(BaseCommand): verbosity = int(options.get('verbosity', 1)) for error_code in (404, 500): template, created = Template.objects.get_or_create( - name="%s.html" % error_code) + name=f"{error_code}.html") if created or (not created and force): template.content = TEMPLATES.get(error_code, '') template.save() diff --git a/dbtemplates/management/commands/sync_templates.py b/dbtemplates/management/commands/sync_templates.py index 7d95429..b01e61e 100644 --- a/dbtemplates/management/commands/sync_templates.py +++ b/dbtemplates/management/commands/sync_templates.py @@ -1,4 +1,3 @@ -import io import os from django.contrib.sites.models import Site from django.core.management.base import CommandError, BaseCommand @@ -53,7 +52,7 @@ class Command(BaseCommand): delete = options.get('delete') if not extension.startswith("."): - extension = ".%s" % extension + extension = f".{extension}" try: site = Site.objects.get_current() @@ -84,7 +83,7 @@ class Command(BaseCommand): "database.\nCreate it with '%s'?" " (y/[n]): """ % (name, path)) if force or confirm.lower().startswith('y'): - with io.open(path, encoding='utf-8') as f: + with open(path, encoding='utf-8') as f: t = Template(name=name, content=f.read()) t.save() t.sites.add(site) @@ -102,7 +101,7 @@ class Command(BaseCommand): if confirm in ('', FILES_TO_DATABASE, DATABASE_TO_FILES): if confirm == FILES_TO_DATABASE: - with io.open(path, encoding='utf-8') as f: + with open(path, encoding='utf-8') as f: t.content = f.read() t.save() t.sites.add(site) @@ -111,9 +110,9 @@ class Command(BaseCommand): os.remove(path) except OSError: raise CommandError( - u"Couldn't delete %s" % path) + f"Couldn't delete {path}") elif confirm == DATABASE_TO_FILES: - with io.open(path, 'w', encoding='utf-8') as f: + with open(path, 'w', encoding='utf-8') as f: f.write(t.content) if delete: t.delete() diff --git a/dbtemplates/migrations/0001_initial.py b/dbtemplates/migrations/0001_initial.py index d5d3ed3..5d5b1f4 100644 --- a/dbtemplates/migrations/0001_initial.py +++ b/dbtemplates/migrations/0001_initial.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - import django from django.db import models, migrations import django.utils.timezone diff --git a/dbtemplates/models.py b/dbtemplates/models.py index f201ce4..2ca806b 100644 --- a/dbtemplates/models.py +++ b/dbtemplates/models.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from dbtemplates.conf import settings from dbtemplates.utils.cache import (add_template_to_cache, remove_cached_template) @@ -24,7 +23,7 @@ class Template(models.Model): name = models.CharField(_('name'), max_length=100, help_text=_("Example: 'flatpages/default.html'")) content = models.TextField(_('content'), blank=True) - sites = models.ManyToManyField(Site, verbose_name=_(u'sites'), + sites = models.ManyToManyField(Site, verbose_name=_('sites'), blank=True) creation_date = models.DateTimeField(_('creation date'), default=now) @@ -63,7 +62,7 @@ class Template(models.Model): # populate the template instance with its content. if settings.DBTEMPLATES_AUTO_POPULATE_CONTENT and not self.content: self.populate() - super(Template, self).save(*args, **kwargs) + super().save(*args, **kwargs) def add_default_site(instance, **kwargs): diff --git a/dbtemplates/test_cases.py b/dbtemplates/test_cases.py index e724f07..8dc1363 100644 --- a/dbtemplates/test_cases.py +++ b/dbtemplates/test_cases.py @@ -1,4 +1,3 @@ -import io import os import shutil import tempfile @@ -103,9 +102,9 @@ class DbTemplatesTestCase(TestCase): old_template_dirs = settings.TEMPLATES[0].get('DIRS', []) temp_template_dir = tempfile.mkdtemp('dbtemplates') temp_template_path = os.path.join(temp_template_dir, 'temp_test.html') - temp_template = io.open(temp_template_path, 'w', encoding='utf-8') + temp_template = open(temp_template_path, 'w', encoding='utf-8') try: - temp_template.write(u'temp test') + temp_template.write('temp test') settings.TEMPLATES[0]['DIRS'] = (temp_template_dir,) # these works well if is not settings patched at runtime # for supporting django < 1.7 tests we must patch dirs in runtime @@ -120,12 +119,12 @@ class DbTemplatesTestCase(TestCase): Template.objects.filter(name='temp_test.html').exists()) t = Template.objects.get(name='temp_test.html') - t.content = u'temp test modified' + t.content = 'temp test modified' t.save() call_command('sync_templates', force=True, verbosity=0, overwrite=DATABASE_TO_FILES) - self.assertEqual(u'temp test modified', - io.open(temp_template_path, + self.assertEqual('temp test modified', + open(temp_template_path, encoding='utf-8').read()) call_command('sync_templates', force=True, verbosity=0, diff --git a/dbtemplates/utils/cache.py b/dbtemplates/utils/cache.py index ddf37a6..dd9d00f 100644 --- a/dbtemplates/utils/cache.py +++ b/dbtemplates/utils/cache.py @@ -28,7 +28,7 @@ cache = get_cache_backend() def get_cache_key(name): current_site = Site.objects.get_current() - return 'dbtemplates::%s::%s' % (slugify(name), current_site.pk) + return f'dbtemplates::{slugify(name)}::{current_site.pk}' def get_cache_notfound_key(name): diff --git a/docs/conf.py b/docs/conf.py index bda62ab..2055241 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # # django-dbtemplates documentation build configuration file, created by # sphinx-quickstart on Fri Oct 9 14:52:11 2009. @@ -37,8 +36,8 @@ source_suffix = '.txt' master_doc = 'index' # General information about the project. -project = u'django-dbtemplates' -copyright = u'2007-2019, Jannis Leidel and contributors' +project = 'django-dbtemplates' +copyright = '2007-2019, Jannis Leidel and contributors' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -177,8 +176,8 @@ htmlhelp_basename = 'django-dbtemplatesdoc' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ - ('index', 'django-dbtemplates.tex', u'django-dbtemplates Documentation', - u'Jannis Leidel and contributors', 'manual'), + ('index', 'django-dbtemplates.tex', 'django-dbtemplates Documentation', + 'Jannis Leidel and contributors', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of diff --git a/setup.cfg b/setup.cfg index b731fa8..a5516f1 100644 --- a/setup.cfg +++ b/setup.cfg @@ -2,4 +2,3 @@ source-dir = docs/ build-dir = docs/_build all_files = 1 - diff --git a/setup.py b/setup.py index fe38595..aa1c549 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ from setuptools import setup, find_packages def read(*parts): filename = os.path.join(os.path.dirname(__file__), *parts) - with io.open(filename, encoding="utf-8") as fp: + with open(filename, encoding="utf-8") as fp: return fp.read() @@ -27,6 +27,7 @@ setup( "static/dbtemplates/js/*.js", ], }, + python_requires=">=3.7", classifiers=[ "Development Status :: 5 - Production/Stable", "Environment :: Web Environment", @@ -35,10 +36,11 @@ setup( "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.5", - "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", "Framework :: Django", ], python_requires='>=3.6', diff --git a/tox.ini b/tox.ini index d0b6715..773fe7a 100644 --- a/tox.ini +++ b/tox.ini @@ -4,27 +4,25 @@ usedevelop = True minversion = 1.8 envlist = flake8 - py{35,36}-dj111 - py{35,36,37}-dj21 - py{35,36,37,38,39}-dj22 - py{36,37,38,39,310}-dj{30,31,32} - py{38,39,310}-dj{40,41} + py3{7,8,9}-dj22 + py3{7,8,9,10,11}-dj32 [gh-actions] python = - 3.6: py36 3.7: py37 - 3.8: py38, flake8 + 3.8: py38 3.9: py39 3.10: py310 + 3.10: py310, flake8 + 3.11: py311 [testenv] basepython = - py36: python3.6 py37: python3.7 py38: python3.8 py39: python3.9 py310: python3.10 + py311: python3.11 usedevelop = true setenv = DJANGO_SETTINGS_MODULE = dbtemplates.test_settings @@ -45,7 +43,7 @@ commands = coverage xml [testenv:flake8] -basepython = python3.8 +basepython = python3.10 commands = flake8 dbtemplates deps = flake8