diff --git a/.darglint b/.darglint new file mode 100644 index 0000000..2b03755 --- /dev/null +++ b/.darglint @@ -0,0 +1,2 @@ +[darglint] +strictness = short diff --git a/.flake8 b/.flake8 index 891336c..37cca8f 100644 --- a/.flake8 +++ b/.flake8 @@ -1,5 +1,5 @@ [flake8] -select = ANN,B,B9,BLK,C,D,DAR,E,F,S,W +select = ANN,B,B9,BLK,C,E,F,S,W ignore = E203,E501,W503,C901,S308 max-line-length = 80 max-complexity = 10 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 25c5720..59a30bc 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -15,16 +15,16 @@ repos: rev: 19.10b0 hooks: - id: black - # - repo: https://gitlab.com/pycqa/flake8 - # rev: 3.7.9 - # hooks: - # - id: flake8 - # additional_dependencies: - # - flake8-bandit==2.1.2 - # - flake8-bugbear==20.1.4 - # - flake8-docstrings==1.5.0 - # - pep8-naming==0.10.0 - # - darglint==1.2.3 + - repo: https://gitlab.com/pycqa/flake8 + rev: 3.8.1 + hooks: + - id: flake8 + additional_dependencies: + - flake8-bandit==2.1.2 + - flake8-bugbear==20.1.4 + - flake8-docstrings==1.5.0 + - pep8-naming==0.10.0 + - darglint==1.3.0 - repo: https://github.com/asottile/reorder_python_imports rev: v2.3.0 hooks: diff --git a/noxfile.py b/noxfile.py index dfed133..a569e31 100644 --- a/noxfile.py +++ b/noxfile.py @@ -1,6 +1,5 @@ """Nox sessions.""" import contextlib -import shutil import tempfile from pathlib import Path from typing import cast @@ -140,8 +139,18 @@ def tests(session: Session) -> None: """Run the test suite.""" install_package(session) install(session, "coverage[toml]", "pytest") - session.run("coverage", "run", "-m", "pytest", *session.posargs) - session.run("coverage", "report") + session.run("coverage", "run", "--parallel", "-m", "pytest", *session.posargs) + session.notify("coverage") + + +@nox.session +def coverage(session: Session) -> None: + """Produce the coverage report.""" + args = session.posargs or ["report"] + install(session, "coverage[toml]") + if not session.posargs and any(Path().glob(".coverage.*")): + session.run("coverage", "combine") + session.run("coverage", *args) @nox.session(python=python_versions) diff --git a/sample/mysite/manage.py b/sample/mysite/manage.py deleted file mode 100755 index be146f8..0000000 --- a/sample/mysite/manage.py +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env python -"""Django's command-line utility for administrative tasks.""" -import os -import sys - - -def main(): - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") - try: - from django.core.management import execute_from_command_line - except ImportError as exc: - raise ImportError( - "Couldn't import Django. Are you sure it's installed and " - "available on your PYTHONPATH environment variable? Did you " - "forget to activate a virtual environment?" - ) from exc - execute_from_command_line(sys.argv) - - -if __name__ == "__main__": - main() diff --git a/sample/mysite/mysite/__init__.py b/sample/mysite/mysite/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/sample/mysite/mysite/settings.py b/sample/mysite/mysite/settings.py deleted file mode 100644 index 94c9625..0000000 --- a/sample/mysite/mysite/settings.py +++ /dev/null @@ -1,115 +0,0 @@ -""" -Django settings for mysite project. - -Generated by 'django-admin startproject' using Django 2.2.11. - -For more information on this file, see -https://docs.djangoproject.com/en/2.2/topics/settings/ - -For the full list of settings and their values, see -https://docs.djangoproject.com/en/2.2/ref/settings/ -""" -import os - -# Build paths inside the project like this: os.path.join(BASE_DIR, ...) -BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) - - -# Quick-start development settings - unsuitable for production -# See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/ - -# SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = "2ub524wek9yr4-#hf7))&l_@26s&eusy)lw&n=dv7wat=^d8ke" - -# SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True - -ALLOWED_HOSTS = [] - - -# Application definition - -INSTALLED_APPS = [ - "django_sorting_bootstrap", - "polls.apps.PollsConfig", - "django.contrib.admin", - "django.contrib.auth", - "django.contrib.contenttypes", - "django.contrib.sessions", - "django.contrib.messages", - "django.contrib.staticfiles", -] - -MIDDLEWARE = [ - "django.middleware.security.SecurityMiddleware", - "django.contrib.sessions.middleware.SessionMiddleware", - "django.middleware.common.CommonMiddleware", - "django.middleware.csrf.CsrfViewMiddleware", - "django.contrib.auth.middleware.AuthenticationMiddleware", - "django.contrib.messages.middleware.MessageMiddleware", - "django.middleware.clickjacking.XFrameOptionsMiddleware", -] - -ROOT_URLCONF = "mysite.urls" - -TEMPLATES = [ - { - "BACKEND": "django.template.backends.django.DjangoTemplates", - "DIRS": [os.path.join(BASE_DIR, "templates")], - "APP_DIRS": True, - "OPTIONS": { - "context_processors": [ - "django.template.context_processors.debug", - "django.template.context_processors.request", - "django.contrib.auth.context_processors.auth", - "django.contrib.messages.context_processors.messages", - ], - }, - }, -] - -WSGI_APPLICATION = "mysite.wsgi.application" - - -# Database -# https://docs.djangoproject.com/en/2.2/ref/settings/#databases - -DATABASES = { - "default": { - "ENGINE": "django.db.backends.sqlite3", - "NAME": os.path.join(BASE_DIR, "db.sqlite3"), - } -} - - -# Password validation -# https://docs.djangoproject.com/en/2.2/ref/settings/#auth-password-validators - -AUTH_PASSWORD_VALIDATORS = [ - { - "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", - }, - {"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",}, - {"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",}, - {"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",}, -] - - -# Internationalization -# https://docs.djangoproject.com/en/2.2/topics/i18n/ - -LANGUAGE_CODE = "en-us" - -TIME_ZONE = "UTC" - -USE_I18N = True - -USE_L10N = True - -USE_TZ = True - - -# Static files (CSS, JavaScript, Images) -# https://docs.djangoproject.com/en/2.2/howto/static-files/ - -STATIC_URL = "/static/" diff --git a/sample/mysite/mysite/urls.py b/sample/mysite/mysite/urls.py deleted file mode 100644 index 37e7e22..0000000 --- a/sample/mysite/mysite/urls.py +++ /dev/null @@ -1,23 +0,0 @@ -"""mysite URL Configuration - -The `urlpatterns` list routes URLs to views. For more information please see: - https://docs.djangoproject.com/en/2.2/topics/http/urls/ -Examples: -Function views - 1. Add an import: from my_app import views - 2. Add a URL to urlpatterns: path('', views.home, name='home') -Class-based views - 1. Add an import: from other_app.views import Home - 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') -Including another URLconf - 1. Import the include() function: from django.urls import include, path - 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) -""" -from django.contrib import admin -from django.urls import include -from django.urls import path - -urlpatterns = [ - path("polls/", include("polls.urls")), - path("admin/", admin.site.urls), -] diff --git a/sample/mysite/mysite/wsgi.py b/sample/mysite/mysite/wsgi.py deleted file mode 100644 index 8fde7d1..0000000 --- a/sample/mysite/mysite/wsgi.py +++ /dev/null @@ -1,15 +0,0 @@ -""" -WSGI config for mysite project. - -It exposes the WSGI callable as a module-level variable named ``application``. - -For more information on this file, see -https://docs.djangoproject.com/en/2.2/howto/deployment/wsgi/ -""" -import os - -from django.core.wsgi import get_wsgi_application - -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") - -application = get_wsgi_application() diff --git a/sample/mysite/polls/__init__.py b/sample/mysite/polls/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/sample/mysite/polls/admin.py b/sample/mysite/polls/admin.py deleted file mode 100644 index 85b58fb..0000000 --- a/sample/mysite/polls/admin.py +++ /dev/null @@ -1,23 +0,0 @@ -from django.contrib import admin - -from .models import Choice -from .models import Question - - -class ChoiceInline(admin.TabularInline): - model = Choice - extra = 3 - - -class QuestionAdmin(admin.ModelAdmin): - fieldsets = [ - (None, {"fields": ["question_text"]}), - ("Date information", {"fields": ["pub_date"]}), - ] - list_display = ("question_text", "pub_date", "was_published_recently") - list_filter = ["pub_date"] - search_fields = ["question_text"] - - -admin.site.register(Choice) -admin.site.register(Question, QuestionAdmin) diff --git a/sample/mysite/polls/apps.py b/sample/mysite/polls/apps.py deleted file mode 100644 index 292f00d..0000000 --- a/sample/mysite/polls/apps.py +++ /dev/null @@ -1,5 +0,0 @@ -from django.apps import AppConfig - - -class PollsConfig(AppConfig): - name = "polls" diff --git a/sample/mysite/polls/migrations/0001_initial.py b/sample/mysite/polls/migrations/0001_initial.py deleted file mode 100644 index c7fb2b9..0000000 --- a/sample/mysite/polls/migrations/0001_initial.py +++ /dev/null @@ -1,52 +0,0 @@ -# Generated by Django 2.2.11 on 2020-03-16 13:43 -import django.db.models.deletion -from django.db import migrations -from django.db import models - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [] - - operations = [ - migrations.CreateModel( - name="Question", - fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("question_text", models.CharField(max_length=200)), - ("pub_date", models.DateTimeField(verbose_name="date published")), - ], - ), - migrations.CreateModel( - name="Choice", - fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("choice_text", models.CharField(max_length=200)), - ("votes", models.IntegerField(default=0)), - ( - "question", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="polls.Question" - ), - ), - ], - ), - ] diff --git a/sample/mysite/polls/migrations/__init__.py b/sample/mysite/polls/migrations/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/sample/mysite/polls/models.py b/sample/mysite/polls/models.py deleted file mode 100644 index a0639e4..0000000 --- a/sample/mysite/polls/models.py +++ /dev/null @@ -1,29 +0,0 @@ -import datetime - -from django.db import models -from django.utils import timezone - - -class Question(models.Model): - question_text = models.CharField(max_length=200) - pub_date = models.DateTimeField("date published") - - def __str__(self): - return self.question_text - - def was_published_recently(self): - now = timezone.now() - return now - datetime.timedelta(days=1) <= self.pub_date <= now - - was_published_recently.admin_order_field = "pub_date" - was_published_recently.boolean = True - was_published_recently.short_description = "Published recently?" - - -class Choice(models.Model): - question = models.ForeignKey(Question, on_delete=models.CASCADE) - choice_text = models.CharField(max_length=200) - votes = models.IntegerField(default=0) - - def __str__(self): - return self.choice_text diff --git a/sample/mysite/polls/static/polls/images/background.gif b/sample/mysite/polls/static/polls/images/background.gif deleted file mode 100644 index 6d69c70..0000000 Binary files a/sample/mysite/polls/static/polls/images/background.gif and /dev/null differ diff --git a/sample/mysite/polls/static/polls/style.css b/sample/mysite/polls/static/polls/style.css deleted file mode 100644 index 9237035..0000000 --- a/sample/mysite/polls/static/polls/style.css +++ /dev/null @@ -1,7 +0,0 @@ -li a { - color: green; -} - -body { - background: white url("images/background.gif") no-repeat; -} diff --git a/sample/mysite/polls/templates/admin/base_site.html b/sample/mysite/polls/templates/admin/base_site.html deleted file mode 100644 index 626e5b7..0000000 --- a/sample/mysite/polls/templates/admin/base_site.html +++ /dev/null @@ -1,6 +0,0 @@ -{% extends "admin/base.html" %} {% block title %}{{ title }} | {{ -site_title|default:_('Django site admin') }}{% endblock %} {% block branding %} -

- Polls Administration -

-{% endblock %} {% block nav-global %}{% endblock %} diff --git a/sample/mysite/polls/templates/polls/detail.html b/sample/mysite/polls/templates/polls/detail.html deleted file mode 100644 index fff5625..0000000 --- a/sample/mysite/polls/templates/polls/detail.html +++ /dev/null @@ -1,19 +0,0 @@ -

{{ question.question_text }}

- -{% if error_message %} -

{{ error_message }}

-{% endif %} - -
- {% csrf_token %} {% for choice in question.choice_set.all %} - -
- {% endfor %} - -
diff --git a/sample/mysite/polls/templates/polls/index.html b/sample/mysite/polls/templates/polls/index.html deleted file mode 100644 index 2b75aa8..0000000 --- a/sample/mysite/polls/templates/polls/index.html +++ /dev/null @@ -1,17 +0,0 @@ -{% load static %} - - - -{% if latest_question_list %} - -{% else %} -

No polls are available.

-{% endif %} diff --git a/sample/mysite/polls/templates/polls/results.html b/sample/mysite/polls/templates/polls/results.html deleted file mode 100644 index dfe4f4f..0000000 --- a/sample/mysite/polls/templates/polls/results.html +++ /dev/null @@ -1,12 +0,0 @@ -

{{ question.question_text }}

- - - -Vote again? diff --git a/sample/mysite/polls/tests.py b/sample/mysite/polls/tests.py deleted file mode 100644 index de15bf1..0000000 --- a/sample/mysite/polls/tests.py +++ /dev/null @@ -1,124 +0,0 @@ -import datetime - -from django.test import TestCase -from django.urls import reverse -from django.utils import timezone - -from .models import Question - - -class QuestionModelTests(TestCase): - def test_was_published_recently_with_future_question(self): - """ - was_published_recently() returns False for questions whose pub_date - is in the future. - """ - time = timezone.now() + datetime.timedelta(days=30) - future_question = Question(pub_date=time) - self.assertIs(future_question.was_published_recently(), False) - - def test_was_published_recently_with_old_question(self): - """ - was_published_recently() returns False for questions whose pub_date - is older than 1 day. - """ - time = timezone.now() - datetime.timedelta(days=1, seconds=1) - old_question = Question(pub_date=time) - self.assertIs(old_question.was_published_recently(), False) - - def test_was_published_recently_with_recent_question(self): - """ - was_published_recently() returns True for questions whose pub_date - is within the last day. - """ - time = timezone.now() - datetime.timedelta(hours=23, minutes=59, seconds=59) - recent_question = Question(pub_date=time) - self.assertIs(recent_question.was_published_recently(), True) - - -def create_question(question_text, days): - """ - Create a question with the given `question_text` and published the - given number of `days` offset to now (negative for questions published - in the past, positive for questions that have yet to be published). - """ - time = timezone.now() + datetime.timedelta(days=days) - return Question.objects.create(question_text=question_text, pub_date=time) - - -class QuestionIndexViewTests(TestCase): - def test_no_questions(self): - """ - If no questions exist, an appropriate message is displayed. - """ - response = self.client.get(reverse("polls:index")) - self.assertEqual(response.status_code, 200) - self.assertContains(response, "No polls are available.") - self.assertQuerysetEqual(response.context["latest_question_list"], []) - - def test_past_question(self): - """ - Questions with a pub_date in the past are displayed on the - index page. - """ - create_question(question_text="Past question.", days=-30) - response = self.client.get(reverse("polls:index")) - self.assertQuerysetEqual( - response.context["latest_question_list"], [""] - ) - - def test_future_question(self): - """ - Questions with a pub_date in the future aren't displayed on - the index page. - """ - create_question(question_text="Future question.", days=30) - response = self.client.get(reverse("polls:index")) - self.assertContains(response, "No polls are available.") - self.assertQuerysetEqual(response.context["latest_question_list"], []) - - def test_future_question_and_past_question(self): - """ - Even if both past and future questions exist, only past questions - are displayed. - """ - create_question(question_text="Past question.", days=-30) - create_question(question_text="Future question.", days=30) - response = self.client.get(reverse("polls:index")) - self.assertQuerysetEqual( - response.context["latest_question_list"], [""] - ) - - def test_two_past_questions(self): - """ - The questions index page may display multiple questions. - """ - create_question(question_text="Past question 1.", days=-30) - create_question(question_text="Past question 2.", days=-5) - response = self.client.get(reverse("polls:index")) - self.assertQuerysetEqual( - response.context["latest_question_list"], - ["", ""], - ) - - -class QuestionDetailViewTests(TestCase): - def test_future_question(self): - """ - The detail view of a question with a pub_date in the future - returns a 404 not found. - """ - future_question = create_question(question_text="Future question.", days=5) - url = reverse("polls:detail", args=(future_question.id,)) - response = self.client.get(url) - self.assertEqual(response.status_code, 404) - - def test_past_question(self): - """ - The detail view of a question with a pub_date in the past - displays the question's text. - """ - past_question = create_question(question_text="Past Question.", days=-5) - url = reverse("polls:detail", args=(past_question.id,)) - response = self.client.get(url) - self.assertContains(response, past_question.question_text) diff --git a/sample/mysite/polls/urls.py b/sample/mysite/polls/urls.py deleted file mode 100644 index 45ebddd..0000000 --- a/sample/mysite/polls/urls.py +++ /dev/null @@ -1,11 +0,0 @@ -from django.urls import path - -from . import views - -app_name = "polls" -urlpatterns = [ - path("", views.IndexView.as_view(), name="index"), - path("/", views.DetailView.as_view(), name="detail"), - path("/results/", views.ResultsView.as_view(), name="results"), - path("/vote/", views.vote, name="vote"), -] diff --git a/sample/mysite/polls/views.py b/sample/mysite/polls/views.py deleted file mode 100644 index cca76ea..0000000 --- a/sample/mysite/polls/views.py +++ /dev/null @@ -1,59 +0,0 @@ -from django.http import HttpResponseRedirect -from django.shortcuts import get_object_or_404 -from django.shortcuts import render -from django.urls import reverse -from django.utils import timezone -from django.views import generic - -from .models import Choice -from .models import Question - - -class IndexView(generic.ListView): - template_name = "polls/index.html" - context_object_name = "latest_question_list" - - def get_queryset(self): - """ - Return the last five published questions (not including those set to be - published in the future). - """ - return Question.objects.filter(pub_date__lte=timezone.now()).order_by( - "-pub_date" - )[:5] - - -class DetailView(generic.DetailView): - model = Question - template_name = "polls/detail.html" - - def get_queryset(self): - """ - Excludes any questions that aren't published yet. - """ - return Question.objects.filter(pub_date__lte=timezone.now()) - - -class ResultsView(generic.DetailView): - model = Question - template_name = "polls/results.html" - - -def vote(request, question_id): - question = get_object_or_404(Question, pk=question_id) - try: - selected_choice = question.choice_set.get(pk=request.POST["choice"]) - except (KeyError, Choice.DoesNotExist): - # Redisplay the question voting form. - return render( - request, - "polls/detail.html", - {"question": question, "error_message": "You didn't select a choice.",}, - ) - else: - selected_choice.votes += 1 - selected_choice.save() - # Always return an HttpResponseRedirect after successfully dealing - # with POST data. This prevents data from being posted twice if a - # user hits the Back button. - return HttpResponseRedirect(reverse("polls:results", args=(question.id,))) diff --git a/sample/mysite/templates/admin/base_site.html b/sample/mysite/templates/admin/base_site.html deleted file mode 100644 index 9fe5a41..0000000 --- a/sample/mysite/templates/admin/base_site.html +++ /dev/null @@ -1,5 +0,0 @@ -{% block branding %} -

- Polls Administration -

-{% endblock %} diff --git a/src/django_sorting_bootstrap/models.py b/src/django_sorting_bootstrap/models.py deleted file mode 100644 index 6b20219..0000000 --- a/src/django_sorting_bootstrap/models.py +++ /dev/null @@ -1 +0,0 @@ -# Create your models here. diff --git a/src/django_sorting_bootstrap/sort.py b/src/django_sorting_bootstrap/sort.py index ee9e857..9080566 100644 --- a/src/django_sorting_bootstrap/sort.py +++ b/src/django_sorting_bootstrap/sort.py @@ -1,5 +1,9 @@ +"""Sort module.""" + + def sort_queryset(queryset, request, context=None): - """ Returns a sorted queryset + """Returns a sorted queryset. + The context argument is only used in the template tag """ sort_by = request.GET.get("sort_by") diff --git a/src/django_sorting_bootstrap/templatetags/__init__.py b/src/django_sorting_bootstrap/templatetags/__init__.py index e69de29..1cbe04c 100644 --- a/src/django_sorting_bootstrap/templatetags/__init__.py +++ b/src/django_sorting_bootstrap/templatetags/__init__.py @@ -0,0 +1 @@ +"""Templatetags.""" diff --git a/src/django_sorting_bootstrap/templatetags/sorting_tags.py b/src/django_sorting_bootstrap/templatetags/sorting_tags.py index 9e1b380..f6904b5 100644 --- a/src/django_sorting_bootstrap/templatetags/sorting_tags.py +++ b/src/django_sorting_bootstrap/templatetags/sorting_tags.py @@ -1,3 +1,4 @@ +"""Sorting templatetags.""" from django import template from django.utils.html import format_html from django.utils.safestring import mark_safe @@ -10,9 +11,7 @@ # based on contrib.admin.templatetags.admin_list.result_headers def result_headers(context, cl): - """ - Generates the list column headers. - """ + """Generates the list column headers.""" for i, field_name in enumerate(cl.list_display): text, attr = label_for_field(field_name, cl.model, return_attr=True) if attr: @@ -85,9 +84,7 @@ def result_headers(context, cl): @register.inclusion_tag("sorting_bootstrap/sort_headers_frag.html", takes_context=True) def sort_headers(context, cl): - """ - Displays the headers and data list together - """ + """Displays the headers and data list together.""" headers = list(result_headers(context, cl)) sorted_fields = False for h in headers: @@ -97,7 +94,9 @@ def sort_headers(context, cl): def sort_link(context, text, sort_field, visible_name=None): - """Usage: {% sort_link "text" "field_name" %} + """Sorts links. + + Usage: {% sort_link "text" "field_name" %} Usage: {% sort_link "text" "field_name" "Visible name" %} """ sorted_fields = False @@ -170,7 +169,10 @@ def sort_link(context, text, sort_field, visible_name=None): @register.tag def auto_sort(parser, token): - "usage: {% auto_sort queryset %}" + """Auto sort. + + Usage: {% auto_sort queryset %} + """ try: tag_name, queryset = token.split_contents() except ValueError: @@ -181,7 +183,10 @@ def auto_sort(parser, token): class SortedQuerysetNode(template.Node): + """Sorted Queryset Node class.""" + def __init__(self, queryset): + """Initialize.""" self.queryset_var = queryset self.queryset = template.Variable(queryset) diff --git a/src/django_sorting_bootstrap/tests.py b/src/django_sorting_bootstrap/tests.py deleted file mode 100644 index 2a56a95..0000000 --- a/src/django_sorting_bootstrap/tests.py +++ /dev/null @@ -1,25 +0,0 @@ -""" -This file demonstrates two different styles of tests (one doctest and one -unittest). These will both pass when you run "manage.py test". - -Replace these with more appropriate tests for your application. -""" -from django.test import TestCase - - -class SimpleTest(TestCase): - def test_basic_addition(self): - """ - Tests that 1 + 1 always equals 2. - """ - self.failUnlessEqual(1 + 1, 2) - - -__test__ = { - "doctest": """ -Another way to test that 1 + 1 is equal to 2. - ->>> 1 + 1 == 2 -True -""" -} diff --git a/src/django_sorting_bootstrap/util.py b/src/django_sorting_bootstrap/util.py index 0091361..1e18cf6 100644 --- a/src/django_sorting_bootstrap/util.py +++ b/src/django_sorting_bootstrap/util.py @@ -1,3 +1,4 @@ +"""Util module.""" import six from django.db import models from django.db.models.fields.related import ForeignObjectRel as RelatedObject @@ -7,12 +8,12 @@ def label_for_field(name, model, return_attr=False): - """ - Returns a sensible label for a field name. The name can be a callable, - property (but not created with @property decorator) or the name of an - object's attribute, as well as a genuine fields. If return_attr is - True, the resolved attribute (which could be a callable) is also returned. - This will be None if (and only if) the name refers to a field. + """Returns a sensible label for a field name. + + The name can be a callable, property (but not created with @property decorator) + or the name of an object's attribute, as well as a genuine fields. + If return_attr is True, the resolved attribute (which could be a callable) + is also returned. This will be None if (and only if) the name refers to a field. """ attr = None try: diff --git a/src/django_sorting_bootstrap/views.py b/src/django_sorting_bootstrap/views.py index b3de49d..092bfdd 100644 --- a/src/django_sorting_bootstrap/views.py +++ b/src/django_sorting_bootstrap/views.py @@ -1,3 +1,4 @@ +"""Views module.""" from collections import namedtuple SimpleChangeList = namedtuple("SimpleChangeList", ["request", "model", "list_display"])