From 45428f1078cc48b65a46f061dd2db0d3dbdcd2ae Mon Sep 17 00:00:00 2001 From: "Vertliba.V" Date: Sat, 16 May 2020 22:21:44 +0300 Subject: [PATCH 01/16] switched CI to github actions, added linter, refactoring. --- .github/workflows/build.yml | 51 ++++ .github/workflows/codecov.yml | 26 ++ .github/workflows/pythonpublish.yml | 30 ++ .gitignore | 4 +- .travis.yml | 22 -- example/__init__.py | 0 example/albums/views.py | 14 +- example/example/settings.py | 13 +- requirements.txt | 1 + setup.py | 120 ++++---- tests/test_api.py | 409 +++++++++++++++++++++------- tests/test_editor.py | 14 +- tests/test_renderers.py | 52 ++-- tox.ini | 28 -- 14 files changed, 540 insertions(+), 244 deletions(-) create mode 100644 .github/workflows/build.yml create mode 100644 .github/workflows/codecov.yml create mode 100644 .github/workflows/pythonpublish.yml delete mode 100644 .travis.yml create mode 100644 example/__init__.py delete mode 100644 tox.ini diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..7817b93 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,51 @@ +name: build + +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: [3.6, 3.7, 3.8] + django-version: [1.9, 1.11, 2.0, 2.1, 2.2, 3.0] + drf-version: [3.9, 3.10, 3.11] + include: + - python-version: 2.7 + django-version: 1.11 + drf-version: 3.9 + - python-version: 2.7 + django-version: 1.9 + drf-version: 3.9 + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v1 + with: + python-version: ${{ matrix.python-version }} + - name: Install Dependencies + run: | + python -m pip install --upgrade pip + echo "Python ${{ matrix.python-version }} -> Django ${{ matrix.django-version }} -> DRF ${{ matrix.drf-version }}" + python -m pip install "Django~=${{ matrix.django-version }}.0" + python -m pip install "djangorestframework~=${{ matrix.drf-version }}.0" + pip install -q -e . + echo "Django: `django-admin --version`" + python --version + - name: Run Tests + run: | + python example\manage.py test tests -v 1 --noinput + + flake8-linter: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - uses: grantmcconnaughey/lintly-flake8-github-action@v1.0 + if: github.event_name == 'pull_request' + with: + # The GitHub API token to create reviews with + token: ${{ secrets.GITHUB_TOKEN }} + # Fail if "new" violations detected or "any", default "new" + failIf: new + # Additional arguments to pass to flake8, default "." (current directory) + args: "--extend-exclude=migrations ." diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml new file mode 100644 index 0000000..c1e310c --- /dev/null +++ b/.github/workflows/codecov.yml @@ -0,0 +1,26 @@ +name: codecov +on: [push, pull_request] +jobs: + run: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Setup Python + uses: actions/setup-python@master + with: + python-version: 3.8 + - name: Generate coverage report + run: | + pip install -r requirements.txt + pip install coverage + pip install -q -e . + coverage run example\manage.py test tests -v 1 --noinput + coverage xml + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v1 + with: + token: ${{ secrets.CODECOV_TOKEN }} + file: ./coverage.xml + flags: unittests + name: codecov-umbrella + fail_ci_if_error: true \ No newline at end of file diff --git a/.github/workflows/pythonpublish.yml b/.github/workflows/pythonpublish.yml new file mode 100644 index 0000000..ec2366e --- /dev/null +++ b/.github/workflows/pythonpublish.yml @@ -0,0 +1,30 @@ +# This workflow will upload a Python Package using Twine when a release is created + +name: Upload Python Package + +on: + release: + types: [published] + +jobs: + deploy: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up Python + uses: actions/setup-python@v1 + with: + python-version: '3.x' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install setuptools wheel twine + - name: Build and publish + env: + TWINE_USERNAME: '__token__' + TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} + run: | + python setup.py sdist bdist_wheel + twine upload --repository testpypi dist/* diff --git a/.gitignore b/.gitignore index 2547f94..34f131b 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,6 @@ dist/ *.egg-info/ MANIFEST docs/_build -/.idea \ No newline at end of file +/.idea +/venv* +/env* \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index d54343e..0000000 --- a/.travis.yml +++ /dev/null @@ -1,22 +0,0 @@ -language: python - -python: - - "2.7" - - "3.4" - - "3.5" - - "3.6" - -sudo: false - -matrix: - fast_finish: true - -install: - - pip install tox-travis - - pip install codecov - -script: - - tox - -after_success: - - codecov diff --git a/example/__init__.py b/example/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/example/albums/views.py b/example/albums/views.py index 92830ab..8dcb43d 100644 --- a/example/albums/views.py +++ b/example/albums/views.py @@ -3,9 +3,11 @@ from rest_framework.response import Response from rest_framework_datatables_editor.filters import DatatablesFilterBackend -from rest_framework_datatables_editor.pagination import DatatablesPageNumberPagination -from rest_framework_datatables_editor.renderers import DatatablesRenderer -from rest_framework_datatables_editor.viewsets import DatatablesEditorModelViewSet +from rest_framework_datatables_editor.pagination import ( + DatatablesPageNumberPagination) +from rest_framework_datatables_editor.renderers import (DatatablesRenderer) +from rest_framework_datatables_editor.viewsets import ( + DatatablesEditorModelViewSet) from .models import Album, Artist, Genre from .serializers import AlbumSerializer, ArtistSerializer @@ -16,8 +18,10 @@ def index(request): def get_album_options(): return "options", { - "artist.id": [{'label': obj.name, 'value': obj.pk} for obj in Artist.objects.all()], - "genre": [{'label': obj.name, 'value': obj.pk} for obj in Genre.objects.all()] + "artist.id": [{'label': obj.name, 'value': obj.pk} + for obj in Artist.objects.all()], + "genre": [{'label': obj.name, 'value': obj.pk} + for obj in Genre.objects.all()] } diff --git a/example/example/settings.py b/example/example/settings.py index 397533d..1679d7a 100644 --- a/example/example/settings.py +++ b/example/example/settings.py @@ -64,18 +64,20 @@ } } +validation = 'django.contrib.auth.password_validation' + AUTH_PASSWORD_VALIDATORS = [ { - 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + 'NAME': '%s.UserAttributeSimilarityValidator' % validation, }, { - 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + 'NAME': '%s.MinimumLengthValidator' % validation, }, { - 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + 'NAME': '%s.CommonPasswordValidator' % validation, }, { - 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + 'NAME': '%s.NumericPasswordValidator' % validation, }, ] @@ -105,6 +107,7 @@ 'DEFAULT_FILTER_BACKENDS': ( 'rest_framework_datatables_editor.filters.DatatablesFilterBackend', ), - 'DEFAULT_PAGINATION_CLASS': 'rest_framework_datatables_editor.pagination.DatatablesPageNumberPagination', + 'DEFAULT_PAGINATION_CLASS': 'rest_framework_datatables_editor.pagination.' + 'DatatablesPageNumberPagination', 'PAGE_SIZE': 50, } diff --git a/requirements.txt b/requirements.txt index 5174977..5cee6e6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,2 @@ +django>=1.9 djangorestframework>=3.9.1 diff --git a/setup.py b/setup.py index 47827c3..f145524 100644 --- a/setup.py +++ b/setup.py @@ -1,46 +1,31 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -import re import os -import sys -from setuptools import setup +import re +import subprocess +from pathlib import Path +from setuptools import setup -name = 'djangorestframework-datatables-editor' -package = 'rest_framework_datatables_editor' -description = 'Seamless integration between Django REST framework and Datatables (https://datatables.net) with supporting Datatables editor' +package_name = 'djangorestframework-datatables-editor' +folder_name = 'rest_framework_datatables_editor' +description = ('Seamless integration between Django REST framework and ' + 'Datatables (https://datatables.net) with supporting ' + 'Datatables editor') url = 'https://github.com/VVyacheslav/django-rest-framework-datatables-editor' author = 'Vyacheslav V.V.' author_email = 'vvvyacheslav23@gmail.com' license = 'MIT' - -def get_version(package): - """ - Return package version as listed in `__version__` in `init.py`. - """ - with open(os.path.join(package, '__init__.py')) as fh: - return re.search( - "^__version__ = ['\"]([^'\"]+)['\"]", - fh.read(), - re.MULTILINE - ).group(1) - init_py = open(os.path.join(package, '__init__.py')).read() +version_re = re.compile('^Version: (.+)$', re.M) def get_long_description(): - """ - Return rst formatted readme and changelog. - """ - ret = [] - with open('README.rst') as fh: - ret.append(fh.read()) - try: - with open('docs/changelog.rst') as fh: - ret.append(fh.read()) - except IOError: - pass - return '\n\n'.join(ret) + """ Return rst formatted readme and changelog. """ + files_to_join = ['README.rst', 'changelog.rst'] + description = [] + for file in files_to_join: + with open('README.rst') as f: + description.append(f.read()) + return '\n\n'.join(description) def get_packages(package): @@ -52,43 +37,62 @@ def get_packages(package): if os.path.exists(os.path.join(dirpath, '__init__.py'))] -def get_package_data(package): - """ - Return all files under the root package, that are not in a - package themselves. +def get_version(): """ - walk = [(dirpath.replace(package + os.sep, '', 1), filenames) - for dirpath, dirnames, filenames in os.walk(package) - if not os.path.exists(os.path.join(dirpath, '__init__.py'))] - - filepaths = [] - for base, filenames in walk: - filepaths.extend([os.path.join(base, filename) - for filename in filenames]) - return {package: filepaths} + Reads version from git status or PKG-INFO - -version = get_version(package) - -if sys.argv[-1] == 'publish': - os.system("python setup.py sdist upload") - os.system("python setup.py bdist_wheel upload") - print("You probably want to also tag the version now:") - print(" git tag -a {0} -m 'version {0}'".format(version)) - print(" git push --tags") - sys.exit() + https://gist.github.com/pwithnall/7bc5f320b3bdf418265a + """ + d: Path = Path(__file__).absolute().parent + git_dir = d.joinpath('.git') + if git_dir.is_dir(): + # Get the version using "git describe". + cmd = 'git describe --tags --match [0-9]*'.split() + try: + version = subprocess.check_output(cmd).decode().strip() + except subprocess.CalledProcessError: + return None + + # PEP 386 compatibility + if '-' in version: + version = '.post'.join(version.split('-')[:2]) + + # Don't declare a version "dirty" merely because a time stamp has + # changed. If it is dirty, append a ".dev1" suffix to indicate + # a development revision after the release. + with open(os.devnull, 'w') as fd_devnull: + subprocess.call(['git', 'status'], + stdout=fd_devnull, stderr=fd_devnull) + + cmd = 'git diff-index --name-only HEAD'.split() + try: + dirty = subprocess.check_output(cmd).decode().strip() + except subprocess.CalledProcessError: + return None + + if dirty != '': + version += '.dev1' + else: + # Extract the version from the PKG-INFO file. + try: + with open('PKG-INFO') as v: + version = version_re.search(v.read()).group(1) + except FileNotFoundError: + version = None + + return version setup( - name=name, - version=version, + name=package_name, + version=get_version() or 'dev', url=url, license=license, description=description, long_description=get_long_description(), author=author, author_email=author_email, - packages=get_packages(package), + packages=get_packages(folder_name), install_requires=[ 'djangorestframework>=3.9.1', ], diff --git a/tests/test_api.py b/tests/test_api.py index cff959b..92b1846 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -1,214 +1,419 @@ -from django.test import TestCase, override_settings, modify_settings -from django.conf import settings +from django.test import TestCase, override_settings from rest_framework.test import APIClient -from rest_framework.settings import api_settings +from albums.serializers import AlbumSerializer +from albums.views import AlbumViewSet from rest_framework_datatables_editor.pagination import ( - DatatablesLimitOffsetPagination, DatatablesPageNumberPagination + DatatablesLimitOffsetPagination, + DatatablesPageNumberPagination, ) -from albums.views import AlbumViewSet -from albums.serializers import AlbumSerializer +# flake8: noqa: E501 +# noinspection E501 class TestApiTestCase(TestCase): - fixtures = ['test_data'] + fixtures = ["test_data"] + ELVIS_PRESLEY = "Elvis Presley" + THE_BEATLES = "The Beatles" + LIMIT_OFFSET_PAGINATION = ( + "rest_framework_datatables_editor.pagination." "DatatablesLimitOffsetPagination" + ) def setUp(self): self.client = APIClient() AlbumViewSet.pagination_class = DatatablesPageNumberPagination def test_no_datatables(self): - response = self.client.get('/api/albums/') + response = self.client.get("/api/albums/") expected = 15 result = response.json() - self.assertEquals(result['count'], expected) + self.assertEquals(result["count"], expected) def test_datatables_query(self): - response = self.client.get('/api/albums/?format=datatables') + response = self.client.get("/api/albums/?format=datatables") expected = 15 result = response.json() - self.assertEquals('count' in result, False) - self.assertEquals('recordsTotal' in result, True) - self.assertEquals(result['recordsTotal'], expected) + self.assertEquals("count" in result, False) + self.assertEquals("recordsTotal" in result, True) + self.assertEquals(result["recordsTotal"], expected) def test_datatables_suffix(self): - response = self.client.get('/api/albums.datatables/') + response = self.client.get("/api/albums.datatables/") expected = 15 result = response.json() - self.assertEquals('count' in result, False) - self.assertEquals('recordsTotal' in result, True) - self.assertEquals(result['recordsTotal'], expected) + self.assertEquals("count" in result, False) + self.assertEquals("recordsTotal" in result, True) + self.assertEquals(result["recordsTotal"], expected) def test_pagenumber_pagination(self): - response = self.client.get('/api/albums/?format=datatables&length=10&start=10&columns[0][data]=name&columns[1][data]=artist_name&draw=1') - expected = (15, 15, 'Elvis Presley') + response = self.client.get( + "/api/albums/?format=datatables&length=10&" + "start=10&columns[0][data]=name&" + "columns[1][data]=artist_name&draw=1" + ) + expected = (15, 15, self.ELVIS_PRESLEY) result = response.json() - self.assertEquals((result['recordsFiltered'], result['recordsTotal'], result['data'][0]['artist_name']), expected) + self.assertEquals( + ( + result["recordsFiltered"], + result["recordsTotal"], + result["data"][0]["artist_name"], + ), + expected, + ) def test_pagenumber_pagination_invalid_page(self): - response = self.client.get('/api/albums/?format=datatables&length=10&start=20&columns[0][data]=name&columns[1][data]=artist_name&draw=1') + response = self.client.get( + "/api/albums/?format=datatables&length=10&" + "start=20&columns[0][data]=name&" + "columns[1][data]=artist_name&draw=1" + ) self.assertEquals(response.status_code, 404) - @override_settings(REST_FRAMEWORK={ - 'DEFAULT_PAGINATION_CLASS': 'rest_framework_datatables_editor.pagination.DatatablesLimitOffsetPagination', - }) + @override_settings( + REST_FRAMEWORK={"DEFAULT_PAGINATION_CLASS": LIMIT_OFFSET_PAGINATION, } + ) def test_limitoffset_pagination(self): AlbumViewSet.pagination_class = DatatablesLimitOffsetPagination client = APIClient() - response = client.get('/api/albums/?format=datatables&length=10&start=10&columns[0][data]=name&columns[1][data]=artist_name&draw=1') - expected = (15, 15, 'Elvis Presley') + response = client.get( + "/api/albums/?format=datatables&length=10&" + "start=10&columns[0][data]=name&" + "columns[1][data]=artist_name&draw=1" + ) + expected = (15, 15, self.ELVIS_PRESLEY) result = response.json() - self.assertEquals((result['recordsFiltered'], result['recordsTotal'], result['data'][0]['artist_name']), expected) - - @override_settings(REST_FRAMEWORK={ - 'DEFAULT_PAGINATION_CLASS': 'rest_framework_datatables_editor.pagination.DatatablesLimitOffsetPagination', - }) + self.assertEquals( + ( + result["recordsFiltered"], + result["recordsTotal"], + result["data"][0]["artist_name"], + ), + expected, + ) + + @override_settings( + REST_FRAMEWORK={"DEFAULT_PAGINATION_CLASS": LIMIT_OFFSET_PAGINATION, } + ) def test_limitoffset_pagination_no_length(self): AlbumViewSet.pagination_class = DatatablesLimitOffsetPagination client = APIClient() - response = client.get('/api/albums/?format=datatables&start=10&columns[0][data]=name&columns[1][data]=artist_name&draw=1') - expected = (15, 15, 'The Beatles') + response = client.get( + "/api/albums/?format=datatables&start=10&columns[0][data]=name&columns[1][data]=artist_name&draw=1" + ) + expected = (15, 15, self.THE_BEATLES) result = response.json() - self.assertEquals((result['recordsFiltered'], result['recordsTotal'], result['data'][0]['artist_name']), expected) - - @override_settings(REST_FRAMEWORK={ - 'DEFAULT_PAGINATION_CLASS': 'rest_framework_datatables_editor.pagination.DatatablesLimitOffsetPagination', - }) + self.assertEquals( + ( + result["recordsFiltered"], + result["recordsTotal"], + result["data"][0]["artist_name"], + ), + expected, + ) + + @override_settings( + REST_FRAMEWORK={"DEFAULT_PAGINATION_CLASS": LIMIT_OFFSET_PAGINATION, } + ) def test_limitoffset_pagination_no_datatables(self): AlbumViewSet.pagination_class = DatatablesLimitOffsetPagination client = APIClient() - response = client.get('/api/albums/?limit=10&offset=10') - expected = (15, 'Elvis Presley') + response = client.get("/api/albums/?limit=10&offset=10") + expected = (15, self.ELVIS_PRESLEY) result = response.json() - self.assertEquals((result['count'], result['results'][0]['artist_name']), expected) + self.assertEquals( + (result["count"], result["results"][0]["artist_name"]), expected + ) def test_column_column_data_null(self): - response = self.client.get('/api/albums/?format=datatables&length=10&start=10&columns[0][data]=&columns[1][data]=name') - expected = (15, 15, 'The Sun Sessions') + response = self.client.get( + "/api/albums/?format=datatables&length=10&start=10&columns[0][data]=&columns[1][data]=name" + ) + expected = (15, 15, "The Sun Sessions") result = response.json() - self.assertEquals((result['recordsFiltered'], result['recordsTotal'], result['data'][0]['name']), expected) + self.assertEquals( + ( + result["recordsFiltered"], + result["recordsTotal"], + result["data"][0]["name"], + ), + expected, + ) def test_dt_row_attrs_present(self): - response = self.client.get('/api/albums/?format=datatables&length=10&start=0&columns[0][data]=&columns[1][data]=name') + response = self.client.get( + "/api/albums/?format=datatables&length=10&start=0&columns[0][data]=&columns[1][data]=name" + ) result = response.json() - self.assertTrue('DT_RowId' in result['data'][0]) - self.assertTrue('DT_RowAttr' in result['data'][0]) + self.assertTrue("DT_RowId" in result["data"][0]) + self.assertTrue("DT_RowAttr" in result["data"][0]) def test_dt_force_serialize_class(self): - AlbumSerializer.Meta.datatables_always_serialize = ('year',) - response = self.client.get('/api/albums/?format=datatables&length=10&start=0&columns[0][data]=&columns[1][data]=name') + AlbumSerializer.Meta.datatables_always_serialize = ("year",) + response = self.client.get( + "/api/albums/?format=datatables&length=10&start=0&columns[0][data]=&columns[1][data]=name" + ) result = response.json() - self.assertTrue('year' in result['data'][0]) + self.assertTrue("year" in result["data"][0]) - delattr(AlbumSerializer.Meta, 'datatables_always_serialize') + delattr(AlbumSerializer.Meta, "datatables_always_serialize") def test_param_keep_field(self): response = self.client.get( - '/api/albums/?format=datatables&length=10&columns[0][data]=artist.name&columns[0][name]=artist.name&keep=year') + "/api/albums/?format=datatables&length=10&columns[0][data]=artist.name&columns[0][name]=artist.name&keep=year" + ) expected = (15, 15, 1967) result = response.json() - self.assertEquals((result['recordsFiltered'], result['recordsTotal'], result['data'][0]['year']), expected) + self.assertEquals( + ( + result["recordsFiltered"], + result["recordsTotal"], + result["data"][0]["year"], + ), + expected, + ) def test_param_keep_field_search(self): - response = self.client.get('/api/albums/?format=datatables&length=10&columns[0][data]=artist.name&columns[0][name]=artist.name,year&columns[0][searchable]=true&keep=year&search[value]=1968') - expected = (1, 15, 'The Beatles', 1968) + response = self.client.get( + "/api/albums/?format=datatables&length=10&columns[0][" + "data]=artist.name&columns[0][name]=artist.name,year&columns[0][" + "searchable]=true&keep=year&search[value]=1968" + ) + expected = (1, 15, self.THE_BEATLES, 1968) result = response.json() - self.assertEquals((result['recordsFiltered'], result['recordsTotal'], result['data'][0]['artist']['name'], result['data'][0]['year']), expected) + self.assertEquals( + ( + result["recordsFiltered"], + result["recordsTotal"], + result["data"][0]["artist"]["name"], + result["data"][0]["year"], + ), + expected, + ) def test_dt_force_serialize_generic(self): - response = self.client.get('/api/artists/?format=datatables&length=10&start=0&columns[0][data]=&columns[1][data]=name') + response = self.client.get( + "/api/artists/?format=datatables&length=10&start=0&columns[0][" + "data]=&columns[1][data]=name" + ) result = response.json() - self.assertTrue('id' in result['data'][0]) + self.assertTrue("id" in result["data"][0]) def test_filtering_simple(self): - response = self.client.get('/api/albums/?format=datatables&columns[0][data]=name&columns[0][searchable]=true&columns[1][data]=artist__name&columns[1][searchable]=true&search[value]=are+you+exp') - expected = (1, 15, 'Are You Experienced') + response = self.client.get( + "/api/albums/?format=datatables&columns[0][data]=name&columns[" + "0][searchable]=true&columns[1][data]=artist__name&columns[1][" + "searchable]=true&search[value]=are+you+exp" + ) + expected = (1, 15, "Are You Experienced") result = response.json() - self.assertEquals((result['recordsFiltered'], result['recordsTotal'], result['data'][0]['name']), expected) + self.assertEquals( + ( + result["recordsFiltered"], + result["recordsTotal"], + result["data"][0]["name"], + ), + expected, + ) def test_filtering_multiple_names(self): # Two asserts here to test searching on separate namespaces - api_call = '/api/albums/?format=datatables&columns[0][data]=name&columns[0][searchable]=true&columns[1][data]=artist__name&columns[1][name]=artist__name,year&columns[1][searchable]=true' + api_call = "/api/albums/?format=datatables&columns[0][data]=name&columns[0][searchable]=true&columns[1][data]=artist__name&columns[1][name]=artist__name,year&columns[1][searchable]=true" # First search. - response_1 = self.client.get(api_call + '&search[value]=Beatles') + response_1 = self.client.get(api_call + "&search[value]=Beatles") # Second search. - response_2 = self.client.get(api_call + '&search[value]=1968') - expected_1 = (5, 15, 'Sgt. Pepper\'s Lonely Hearts Club Band') + response_2 = self.client.get(api_call + "&search[value]=1968") + expected_1 = (5, 15, "Sgt. Pepper's Lonely Hearts Club Band") expected_2 = (1, 15, 'The Beatles ("The White Album")') result_1 = response_1.json() result_2 = response_2.json() - self.assertEquals((result_1['recordsFiltered'], result_1['recordsTotal'], result_1['data'][0]['name']), expected_1) - self.assertEquals((result_2['recordsFiltered'], result_2['recordsTotal'], result_2['data'][0]['name']), expected_2) + self.assertEquals( + ( + result_1["recordsFiltered"], + result_1["recordsTotal"], + result_1["data"][0]["name"], + ), + expected_1, + ) + self.assertEquals( + ( + result_2["recordsFiltered"], + result_2["recordsTotal"], + result_2["data"][0]["name"], + ), + expected_2, + ) def test_filtering_regex(self): - response = self.client.get('/api/albums/?format=datatables&length=10&columns[0][data]=name&columns[0][searchable]=true&search[regex]=true&search[value]=^Highway [0-9]{2} Revisited$') - expected = (1, 15, 'Highway 61 Revisited') + response = self.client.get( + "/api/albums/?format=datatables&length=10&columns[0][data]=name&columns[0][searchable]=true&search[regex]=true&search[value]=^Highway [0-9]{2} Revisited$" + ) + expected = (1, 15, "Highway 61 Revisited") result = response.json() - self.assertEquals((result['recordsFiltered'], result['recordsTotal'], result['data'][0]['name']), expected) + self.assertEquals( + ( + result["recordsFiltered"], + result["recordsTotal"], + result["data"][0]["name"], + ), + expected, + ) def test_filtering_bad_regex(self): - response = self.client.get('/api/albums/?format=datatables&length=10&columns[0][data]=name&columns[0][searchable]=true&search[regex]=true&search[value]=^Highway [0') - expected = (15, 15, 'Sgt. Pepper\'s Lonely Hearts Club Band') + response = self.client.get( + "/api/albums/?format=datatables&length=10&columns[0][data]=name&columns[0][searchable]=true&search[regex]=true&search[value]=^Highway [0" + ) + expected = (15, 15, "Sgt. Pepper's Lonely Hearts Club Band") result = response.json() - self.assertEquals((result['recordsFiltered'], result['recordsTotal'], result['data'][0]['name']), expected) + self.assertEquals( + ( + result["recordsFiltered"], + result["recordsTotal"], + result["data"][0]["name"], + ), + expected, + ) def test_filtering_foreignkey_without_nested_serializer(self): - response = self.client.get('/api/albums/?format=datatables&length=10&columns[0][data]=artist_name&columns[0][name]=artist__name&columns[0][searchable]=true&search[value]=Jimi') - expected = (1, 15, 'The Jimi Hendrix Experience') + response = self.client.get( + "/api/albums/?format=datatables&length=10&columns[0][data]=artist_name&columns[0][name]=artist__name&columns[0][searchable]=true&search[value]=Jimi" + ) + expected = (1, 15, "The Jimi Hendrix Experience") result = response.json() - self.assertEquals((result['recordsFiltered'], result['recordsTotal'], result['data'][0]['artist_name']), expected) + self.assertEquals( + ( + result["recordsFiltered"], + result["recordsTotal"], + result["data"][0]["artist_name"], + ), + expected, + ) def test_filtering_foreignkey_with_nested_serializer(self): response = self.client.get( - '/api/albums/?format=datatables&length=10&columns[0][data]=artist.name&columns[0][name]=artist.name&columns[0][searchable]=true&search[value]=Jimi') - expected = (1, 15, 'The Jimi Hendrix Experience') + "/api/albums/?format=datatables&length=10&columns[0][data]=artist.name&columns[0][name]=artist.name&columns[0][searchable]=true&search[value]=Jimi" + ) + expected = (1, 15, "The Jimi Hendrix Experience") result = response.json() - self.assertEquals((result['recordsFiltered'], result['recordsTotal'], result['data'][0]['artist']['name']), expected) + self.assertEquals( + ( + result["recordsFiltered"], + result["recordsTotal"], + result["data"][0]["artist"]["name"], + ), + expected, + ) def test_filtering_column(self): - response = self.client.get('/api/albums/?format=datatables&length=10&columns[0][data]=artist_name&columns[0][name]=artist__name&columns[0][searchable]=true&columns[0][search][value]=Beatles') - expected = (5, 15, 'The Beatles') + response = self.client.get( + "/api/albums/?format=datatables&length=10&columns[0][data]=artist_name&columns[0][name]=artist__name&columns[0][searchable]=true&columns[0][search][value]=Beatles" + ) + expected = (5, 15, self.THE_BEATLES) result = response.json() - self.assertEquals((result['recordsFiltered'], result['recordsTotal'], result['data'][0]['artist_name']), expected) + self.assertEquals( + ( + result["recordsFiltered"], + result["recordsTotal"], + result["data"][0]["artist_name"], + ), + expected, + ) def test_filtering_column_suffix(self): - response = self.client.get('/api/albums.datatables?length=10&columns[0][data]=artist_name&columns[0][name]=artist__name&columns[0][searchable]=true&columns[0][search][value]=Beatles') - expected = (5, 15, 'The Beatles') + response = self.client.get( + "/api/albums.datatables?length=10&columns[0][data]=artist_name&columns[0][name]=artist__name&columns[0][searchable]=true&columns[0][search][value]=Beatles" + ) + expected = (5, 15, self.THE_BEATLES) result = response.json() - self.assertEquals((result['recordsFiltered'], result['recordsTotal'], result['data'][0]['artist_name']), expected) + self.assertEquals( + ( + result["recordsFiltered"], + result["recordsTotal"], + result["data"][0]["artist_name"], + ), + expected, + ) def test_filtering_column_regex(self): - response = self.client.get('/api/albums/?format=datatables&length=10&columns[0][data]=artist_name&columns[0][name]=artist__name&columns[0][searchable]=true&columns[0][search][regex]=true&columns[0][search][value]=^bob') - expected = (2, 15, 'Bob Dylan') + response = self.client.get( + "/api/albums/?format=datatables&length=10&columns[0][data]=artist_name&columns[0][name]=artist__name&columns[0][searchable]=true&columns[0][search][regex]=true&columns[0][search][value]=^bob" + ) + expected = (2, 15, "Bob Dylan") result = response.json() - self.assertEquals((result['recordsFiltered'], result['recordsTotal'], result['data'][0]['artist_name']), expected) + self.assertEquals( + ( + result["recordsFiltered"], + result["recordsTotal"], + result["data"][0]["artist_name"], + ), + expected, + ) def test_filtering_multicolumn1(self): - response = self.client.get('/api/albums/?format=datatables&length=10&columns[0][data]=artist_name&columns[0][name]=artist__name&columns[0][searchable]=true&columns[0][search][value]=Beatles&columns[1][data]=year&columns[1][searchable]=true&columns[1][search][value]=1968') - expected = (1, 15, 'The Beatles') + response = self.client.get( + "/api/albums/?format=datatables&length=10&columns[0][data]=artist_name&columns[0][name]=artist__name&columns[0][searchable]=true&columns[0][search][value]=Beatles&columns[1][data]=year&columns[1][searchable]=true&columns[1][search][value]=1968" + ) + expected = (1, 15, self.THE_BEATLES) result = response.json() - self.assertEquals((result['recordsFiltered'], result['recordsTotal'], result['data'][0]['artist_name']), expected) + self.assertEquals( + ( + result["recordsFiltered"], + result["recordsTotal"], + result["data"][0]["artist_name"], + ), + expected, + ) def test_filtering_multicolumn2(self): - response = self.client.get('/api/albums/?format=datatables&length=10&columns[0][data]=artist_name&columns[0][name]=artist__name&columns[0][searchable]=true&columns[0][search][value]=Beatles&columns[1][data]=year&columns[1][searchable]=true&columns[1][search][value]=2018') + response = self.client.get( + "/api/albums/?format=datatables&length=10&columns[0][data]=artist_name&columns[0][name]=artist__name&columns[0][searchable]=true&columns[0][search][value]=Beatles&columns[1][data]=year&columns[1][searchable]=true&columns[1][search][value]=2018" + ) expected = (0, 15) result = response.json() - self.assertEquals((result['recordsFiltered'], result['recordsTotal']), expected) + self.assertEquals((result["recordsFiltered"], result["recordsTotal"]), + expected) def test_ordering_simple(self): - response = self.client.get('/api/albums/?format=datatables&length=10&columns[0][data]=artist_name&columns[0][name]=artist__name&columns[0][orderable]=true&order[0][column]=0&order[0][dir]=desc') - expected = (15, 15, 'The Velvet Underground') + response = self.client.get( + "/api/albums/?format=datatables&length=10&columns[0][data]=artist_name&columns[0][name]=artist__name&columns[0][orderable]=true&order[0][column]=0&order[0][dir]=desc" + ) + expected = (15, 15, "The Velvet Underground") result = response.json() - self.assertEquals((result['recordsFiltered'], result['recordsTotal'], result['data'][0]['artist_name']), expected) + self.assertEquals( + ( + result["recordsFiltered"], + result["recordsTotal"], + result["data"][0]["artist_name"], + ), + expected, + ) def test_ordering_but_not_orderable(self): - response = self.client.get('/api/albums/?format=datatables&length=10&columns[0][data]=artist_name&columns[0][name]=artist__name&columns[0][orderable]=false&order[0][column]=0&order[0][dir]=desc') - expected = (15, 15, 'The Beatles') + response = self.client.get( + "/api/albums/?format=datatables&length=10&columns[0][data]=artist_name&columns[0][name]=artist__name&columns[0][orderable]=false&order[0][column]=0&order[0][dir]=desc" + ) + expected = (15, 15, self.THE_BEATLES) result = response.json() - self.assertEquals((result['recordsFiltered'], result['recordsTotal'], result['data'][0]['artist_name']), expected) + self.assertEquals( + ( + result["recordsFiltered"], + result["recordsTotal"], + result["data"][0]["artist_name"], + ), + expected, + ) def test_ordering_bad_column_index(self): - response = self.client.get('/api/albums/?format=datatables&length=10&columns[0][data]=artist_name&columns[0][name]=artist__name&columns[0][orderable]=true&order[0][column]=8&order[0][dir]=desc') - expected = (15, 15, 'The Beatles') + response = self.client.get( + "/api/albums/?format=datatables&length=10&columns[0][data]=artist_name&columns[0][name]=artist__name&columns[0][orderable]=true&order[0][column]=8&order[0][dir]=desc" + ) + expected = (15, 15, self.THE_BEATLES) result = response.json() - self.assertEquals((result['recordsFiltered'], result['recordsTotal'], result['data'][0]['artist_name']), expected) + self.assertEquals( + ( + result["recordsFiltered"], + result["recordsTotal"], + result["data"][0]["artist_name"], + ), + expected, + ) diff --git a/tests/test_editor.py b/tests/test_editor.py index f761c81..1ec116b 100644 --- a/tests/test_editor.py +++ b/tests/test_editor.py @@ -41,13 +41,13 @@ def test_edit_two(self): result = response.json()['data'] order_flag = 0 if result[0]['name'] == 'New name1' else 1 - self.assertEqual(result[order_flag-0]['name'], 'New name1') - self.assertEqual(result[order_flag-0]['artist']['id'], 2) + self.assertEqual(result[order_flag - 0]['name'], 'New name1') + self.assertEqual(result[order_flag - 0]['artist']['id'], 2) album = Album.objects.get(pk=1) self.assertEqual([album.name, album.artist.id], ['New name1', 2]) - self.assertEqual(result[order_flag-1]['name'], 'New name4') - self.assertEqual(result[order_flag-1]['artist']['id'], 4) + self.assertEqual(result[order_flag - 1]['name'], 'New name4') + self.assertEqual(result[order_flag - 1]['artist']['id'], 4) album = Album.objects.get(pk=4) self.assertEqual([album.name, album.artist.id], ['New name4', 4]) @@ -139,7 +139,8 @@ def test_one_wrong_field_name(self): response = self.client.post('/api/albums/editor/', data) self.assertEquals(response.status_code, 400) result = response.json()[0] - expected = 'The following fields are present in the request, but they are not writable: incorrect_field' + expected = ('The following fields are present in the request, ' + 'but they are not writable: incorrect_field') self.assertEqual(result, expected) def test_two_wrong_field_name(self): @@ -149,7 +150,8 @@ def test_two_wrong_field_name(self): 'data[0][incorrect_field2]': 16, } response = self.client.post('/api/albums/editor/', data) - expected1 = 'The following fields are present in the request, but they are not writable:' + expected1 = ('The following fields are present in the request, ' + 'but they are not writable:') expected2 = 'incorrect_field1' expected3 = 'incorrect_field2' self.assertContains(response, expected1, count=1, status_code=400) diff --git a/tests/test_renderers.py b/tests/test_renderers.py index 0f3a99c..63e3f0d 100644 --- a/tests/test_renderers.py +++ b/tests/test_renderers.py @@ -1,9 +1,9 @@ import json from django.test import TestCase - from rest_framework.test import APIRequestFactory from rest_framework.views import APIView + from rest_framework_datatables_editor.renderers import DatatablesRenderer @@ -23,7 +23,8 @@ def test_render_no_pagination1(self): request = view.initialize_request( self.factory.get('/api/foo/?format=datatables&draw=1') ) - content = renderer.render(obj, 'application/json', {'request': request, 'view': view}) + content = renderer.render(obj, 'application/json', + {'request': request, 'view': view}) expected = { 'recordsTotal': 1, 'recordsFiltered': 1, @@ -39,7 +40,8 @@ def test_render_no_pagination1_1(self): request = view.initialize_request( self.factory.get('/api/foo.datatables?draw=1') ) - content = renderer.render(obj, 'application/json', {'request': request, 'view': view}) + content = renderer.render(obj, 'application/json', + {'request': request, 'view': view}) expected = { 'recordsTotal': 1, 'recordsFiltered': 1, @@ -55,7 +57,8 @@ def test_render_no_pagination2(self): request = view.initialize_request( self.factory.get('/api/foo/?format=datatables&draw=1') ) - content = renderer.render(obj, 'application/json', {'request': request, 'view': view}) + content = renderer.render(obj, 'application/json', + {'request': request, 'view': view}) expected = { 'recordsTotal': 2, 'recordsFiltered': 2, @@ -73,7 +76,8 @@ def test_render_no_pagination3(self): request = view.initialize_request( self.factory.get('/api/foo/?format=datatables&draw=1') ) - content = renderer.render(obj, 'application/json', {'request': request, 'view': view}) + content = renderer.render(obj, 'application/json', + {'request': request, 'view': view}) expected = { 'recordsTotal': 4, 'recordsFiltered': 2, @@ -83,13 +87,15 @@ def test_render_no_pagination3(self): self.assertEquals(json.loads(content.decode('utf-8')), expected) def test_render(self): - obj = {'recordsTotal': 4, 'recordsFiltered': 2, 'data': [{'foo': 'bar'}, {'spam': 'eggs'}]} + obj = {'recordsTotal': 4, 'recordsFiltered': 2, + 'data': [{'foo': 'bar'}, {'spam': 'eggs'}]} renderer = DatatablesRenderer() view = APIView() request = view.initialize_request( self.factory.get('/api/foo/?format=datatables&draw=2') ) - content = renderer.render(obj, 'application/json', {'request': request, 'view': view}) + content = renderer.render(obj, 'application/json', + {'request': request, 'view': view}) expected = { 'recordsTotal': 4, 'recordsFiltered': 2, @@ -106,13 +112,15 @@ def test_callback(self): class Meta: datatables_extra_json = ('test_callback',) - obj = {'recordsTotal': 4, 'recordsFiltered': 2, 'data': [{'foo': 'bar'}, {'spam': 'eggs'}]} + obj = {'recordsTotal': 4, 'recordsFiltered': 2, + 'data': [{'foo': 'bar'}, {'spam': 'eggs'}]} renderer = DatatablesRenderer() view = TestAPIView() request = view.initialize_request( self.factory.get('/api/foo/?format=datatables&draw=2') ) - content = renderer.render(obj, 'application/json', {'request': request, 'view': view}) + content = renderer.render(obj, 'application/json', + {'request': request, 'view': view}) expected = { 'recordsTotal': 4, 'recordsFiltered': 2, @@ -127,17 +135,22 @@ class TestAPIView(APIView): class Meta: datatables_extra_json = ('test_callback',) - obj = {'recordsTotal': 4, 'recordsFiltered': 2, 'data': [{'foo': 'bar'}, {'spam': 'eggs'}]} + obj = {'recordsTotal': 4, 'recordsFiltered': 2, + 'data': [{'foo': 'bar'}, {'spam': 'eggs'}]} renderer = DatatablesRenderer() view = TestAPIView() request = view.initialize_request( self.factory.get('/api/foo/?format=datatables&draw=2') ) try: - renderer.render(obj, 'application/json', {'request': request, 'view': view}) + renderer.render(obj, 'application/json', + {'request': request, 'view': view}) self.assertEqual(True, False, "TypeError expected; did not occur.") except TypeError as e: - self.assertEqual(e.__str__(), "extra_json_funcs: test_callback not a view method.") + self.assertEqual( + e.__str__(), + "extra_json_funcs: test_callback not a view method." + ) def test_render_extra_json_attr_not_callable(self): class TestAPIView(APIView): @@ -146,17 +159,20 @@ class TestAPIView(APIView): class Meta: datatables_extra_json = ('test_callback',) - obj = {'recordsTotal': 4, 'recordsFiltered': 2, 'data': [{'foo': 'bar'}, {'spam': 'eggs'}]} + obj = {'recordsTotal': 4, 'recordsFiltered': 2, + 'data': [{'foo': 'bar'}, {'spam': 'eggs'}]} renderer = DatatablesRenderer() view = TestAPIView() request = view.initialize_request( self.factory.get('/api/foo/?format=datatables&draw=2') ) try: - renderer.render(obj, 'application/json', {'request': request, 'view': view}) + renderer.render(obj, 'application/json', + {'request': request, 'view': view}) self.assertEqual(True, False, "TypeError expected; did not occur.") except TypeError as e: - self.assertEqual(e.__str__(), "extra_json_funcs: test_callback not callable.") + self.assertEqual(e.__str__(), + "extra_json_funcs: test_callback not callable.") def test_render_extra_json_clashes(self): class TestAPIView(APIView): @@ -166,14 +182,16 @@ def test_callback(self): class Meta: datatables_extra_json = ('test_callback',) - obj = {'recordsTotal': 4, 'recordsFiltered': 2, 'data': [{'foo': 'bar'}, {'spam': 'eggs'}]} + obj = {'recordsTotal': 4, 'recordsFiltered': 2, + 'data': [{'foo': 'bar'}, {'spam': 'eggs'}]} renderer = DatatablesRenderer() view = TestAPIView() request = view.initialize_request( self.factory.get('/api/foo/?format=datatables&draw=2') ) try: - renderer.render(obj, 'application/json', {'request': request, 'view': view}) + renderer.render(obj, 'application/json', + {'request': request, 'view': view}) self.assertEqual(True, False, "Value expected; did not occur.") except ValueError as e: self.assertEqual(e.__str__(), "Duplicate key found: recordsTotal") diff --git a/tox.ini b/tox.ini deleted file mode 100644 index 001a086..0000000 --- a/tox.ini +++ /dev/null @@ -1,28 +0,0 @@ -[tox] -envlist = - py{27,36}-lint, - py{27,36}-django1.11-drf3.9 - {py34,py35,py36}-django2.0-drf3.9 - {py36}-django2.1-drf3.9 - -[testenv] -commands = coverage run --source=rest_framework_datatables_editor example/manage.py test --noinput -setenv = - PYTHONDONTWRITEBYTECODE=1 -deps = - coverage - django1.9: Django>=1.9,<1.10 - django1.11: Django>=1.11,<2.0 - django2.0: Django>=2.0,<2.1 - django2.1: Django>=2.1,<2.2 - drf3.9: djangorestframework>=3.9,<3.10 - -[testenv:py27-lint] -commands = pycodestyle rest_framework_datatables_editor -deps = - pycodestyle>=2.3.0 - -[testenv:py36-lint] -commands = pycodestyle rest_framework_datatables_editor -deps = - pycodestyle>=2.3.0 From 29d2479fdbbd8264b48224c22f4f4a31435c8808 Mon Sep 17 00:00:00 2001 From: "Vertliba.V" Date: Sat, 16 May 2020 22:25:09 +0300 Subject: [PATCH 02/16] switched CI to github actions, added linter, refactoring. --- .github/workflows/build.yml | 2 +- .github/workflows/codecov.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7817b93..23dc5f6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -34,7 +34,7 @@ jobs: python --version - name: Run Tests run: | - python example\manage.py test tests -v 1 --noinput + python example/manage.py test tests -v 1 --noinput flake8-linter: runs-on: ubuntu-latest diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index c1e310c..05d91ad 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -14,7 +14,7 @@ jobs: pip install -r requirements.txt pip install coverage pip install -q -e . - coverage run example\manage.py test tests -v 1 --noinput + coverage run example/manage.py test tests -v 1 --noinput coverage xml - name: Upload coverage to Codecov uses: codecov/codecov-action@v1 From ecaf7324057dda865b4b544a4cba7766f6324e5a Mon Sep 17 00:00:00 2001 From: "Vertliba.V" Date: Sat, 16 May 2020 22:34:36 +0300 Subject: [PATCH 03/16] switched CI to github actions, added linter, refactoring. --- .github/workflows/build.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 23dc5f6..fec8492 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -29,7 +29,6 @@ jobs: echo "Python ${{ matrix.python-version }} -> Django ${{ matrix.django-version }} -> DRF ${{ matrix.drf-version }}" python -m pip install "Django~=${{ matrix.django-version }}.0" python -m pip install "djangorestframework~=${{ matrix.drf-version }}.0" - pip install -q -e . echo "Django: `django-admin --version`" python --version - name: Run Tests From f14703c198cfebe8e443b513d58fefaf107301c0 Mon Sep 17 00:00:00 2001 From: "Vertliba.V" Date: Sat, 16 May 2020 22:40:33 +0300 Subject: [PATCH 04/16] switched CI to github actions, added linter, refactoring. --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fec8492..1fc1d4b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,7 +8,7 @@ jobs: strategy: matrix: python-version: [3.6, 3.7, 3.8] - django-version: [1.9, 1.11, 2.0, 2.1, 2.2, 3.0] + django-version: [1.9] drf-version: [3.9, 3.10, 3.11] include: - python-version: 2.7 From 5e1c49c071b3ab29b1b20d7318b8fd0c2c548352 Mon Sep 17 00:00:00 2001 From: "Vertliba.V" Date: Sat, 16 May 2020 22:45:02 +0300 Subject: [PATCH 05/16] switched CI to github actions, added linter, refactoring. --- .github/workflows/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1fc1d4b..6f3653b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,6 +17,7 @@ jobs: - python-version: 2.7 django-version: 1.9 drf-version: 3.9 + fail-fast: False steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} From 76193f622b71fbea458dd44f6a268daec7078b25 Mon Sep 17 00:00:00 2001 From: "Vertliba.V" Date: Sat, 16 May 2020 22:46:30 +0300 Subject: [PATCH 06/16] switched CI to github actions, added linter, refactoring. --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6f3653b..44e44c6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -6,6 +6,7 @@ jobs: build: runs-on: ubuntu-latest strategy: + fail-fast: false matrix: python-version: [3.6, 3.7, 3.8] django-version: [1.9] @@ -17,7 +18,6 @@ jobs: - python-version: 2.7 django-version: 1.9 drf-version: 3.9 - fail-fast: False steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} From 456cf3a28110583aef96cf1bc1403cd9a4987a88 Mon Sep 17 00:00:00 2001 From: "Vertliba.V" Date: Sat, 16 May 2020 23:00:19 +0300 Subject: [PATCH 07/16] switched CI to github actions, added linter, refactoring. --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 44e44c6..0058348 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -29,7 +29,7 @@ jobs: python -m pip install --upgrade pip echo "Python ${{ matrix.python-version }} -> Django ${{ matrix.django-version }} -> DRF ${{ matrix.drf-version }}" python -m pip install "Django~=${{ matrix.django-version }}.0" - python -m pip install "djangorestframework~=${{ matrix.drf-version }}.0" + python -m pip install "djangorestframework~=${{ matrix.drf-version }}" echo "Django: `django-admin --version`" python --version - name: Run Tests From ba0ff05cf9e3ee48e32a40959ab98a3a49fae6c3 Mon Sep 17 00:00:00 2001 From: "Vertliba.V" Date: Sat, 16 May 2020 23:09:06 +0300 Subject: [PATCH 08/16] switched CI to github actions, added linter, refactoring. --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0058348..4a57767 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,7 +10,7 @@ jobs: matrix: python-version: [3.6, 3.7, 3.8] django-version: [1.9] - drf-version: [3.9, 3.10, 3.11] + drf-version: [3.9, '3.10', 3.11] include: - python-version: 2.7 django-version: 1.11 @@ -29,7 +29,7 @@ jobs: python -m pip install --upgrade pip echo "Python ${{ matrix.python-version }} -> Django ${{ matrix.django-version }} -> DRF ${{ matrix.drf-version }}" python -m pip install "Django~=${{ matrix.django-version }}.0" - python -m pip install "djangorestframework~=${{ matrix.drf-version }}" + python -m pip install "djangorestframework~=${{ matrix.drf-version }}.0" echo "Django: `django-admin --version`" python --version - name: Run Tests From 4f79abe9cc47a9f00138bb600f87edf3c7e1c77d Mon Sep 17 00:00:00 2001 From: "Vertliba.V" Date: Sat, 16 May 2020 23:17:59 +0300 Subject: [PATCH 09/16] switched CI to github actions, added linter, refactoring. --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4a57767..9ca5cfe 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -9,7 +9,7 @@ jobs: fail-fast: false matrix: python-version: [3.6, 3.7, 3.8] - django-version: [1.9] + django-version: [1.11, 2.0, 2.1, 2.2, 3.0] drf-version: [3.9, '3.10', 3.11] include: - python-version: 2.7 @@ -17,7 +17,7 @@ jobs: drf-version: 3.9 - python-version: 2.7 django-version: 1.9 - drf-version: 3.9 + drf-version: 3.11 steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} From 049c89c84fd2a2a3c8a8b19170fc66aab411709c Mon Sep 17 00:00:00 2001 From: "Vertliba.V" Date: Sat, 16 May 2020 23:27:05 +0300 Subject: [PATCH 10/16] switched CI to github actions, added linter, refactoring. --- .github/workflows/build.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9ca5cfe..3862be8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,16 +8,16 @@ jobs: strategy: fail-fast: false matrix: - python-version: [3.6, 3.7, 3.8] - django-version: [1.11, 2.0, 2.1, 2.2, 3.0] - drf-version: [3.9, '3.10', 3.11] + python-version: ['3.6', '3.7', '3.8'] + django-version: ['1.11', '2.0', '2.1', '2.2', '3.0'] + drf-version: ['3.9', '3.10', '3.11'] include: - - python-version: 2.7 - django-version: 1.11 - drf-version: 3.9 - - python-version: 2.7 - django-version: 1.9 - drf-version: 3.11 + - python-version: '2.7' + django-version: '1.11' + drf-version: '3.9' + exclude: + - django-version: '3.0' + drf-version: '3.9' steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} From 1bc6554970b6091aa8526eaa7d376618b70ffee5 Mon Sep 17 00:00:00 2001 From: "Vertliba.V" Date: Sat, 16 May 2020 23:30:57 +0300 Subject: [PATCH 11/16] switched CI to github actions, added linter, refactoring. --- tests/test_api.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_api.py b/tests/test_api.py index 92b1846..b9c34f2 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -18,7 +18,6 @@ class TestApiTestCase(TestCase): LIMIT_OFFSET_PAGINATION = ( "rest_framework_datatables_editor.pagination." "DatatablesLimitOffsetPagination" ) - def setUp(self): self.client = APIClient() AlbumViewSet.pagination_class = DatatablesPageNumberPagination From db607fe30c8cde16ab87dc20a2e66cf1f1e417a1 Mon Sep 17 00:00:00 2001 From: "Vertliba.V" Date: Sat, 16 May 2020 23:33:57 +0300 Subject: [PATCH 12/16] switched CI to github actions, added linter, refactoring. --- .github/workflows/build.yml | 66 ++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3862be8..73501cc 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,38 +3,38 @@ name: build on: [push, pull_request] jobs: - build: - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - python-version: ['3.6', '3.7', '3.8'] - django-version: ['1.11', '2.0', '2.1', '2.2', '3.0'] - drf-version: ['3.9', '3.10', '3.11'] - include: - - python-version: '2.7' - django-version: '1.11' - drf-version: '3.9' - exclude: - - django-version: '3.0' - drf-version: '3.9' - steps: - - uses: actions/checkout@v2 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v1 - with: - python-version: ${{ matrix.python-version }} - - name: Install Dependencies - run: | - python -m pip install --upgrade pip - echo "Python ${{ matrix.python-version }} -> Django ${{ matrix.django-version }} -> DRF ${{ matrix.drf-version }}" - python -m pip install "Django~=${{ matrix.django-version }}.0" - python -m pip install "djangorestframework~=${{ matrix.drf-version }}.0" - echo "Django: `django-admin --version`" - python --version - - name: Run Tests - run: | - python example/manage.py test tests -v 1 --noinput +# build: +# runs-on: ubuntu-latest +# strategy: +# fail-fast: false +# matrix: +# python-version: ['3.6', '3.7', '3.8'] +# django-version: ['1.11', '2.0', '2.1', '2.2', '3.0'] +# drf-version: ['3.9', '3.10', '3.11'] +# include: +# - python-version: '2.7' +# django-version: '1.11' +# drf-version: '3.9' +# exclude: +# - django-version: '3.0' +# drf-version: '3.9' +# steps: +# - uses: actions/checkout@v2 +# - name: Set up Python ${{ matrix.python-version }} +# uses: actions/setup-python@v1 +# with: +# python-version: ${{ matrix.python-version }} +# - name: Install Dependencies +# run: | +# python -m pip install --upgrade pip +# echo "Python ${{ matrix.python-version }} -> Django ${{ matrix.django-version }} -> DRF ${{ matrix.drf-version }}" +# python -m pip install "Django~=${{ matrix.django-version }}.0" +# python -m pip install "djangorestframework~=${{ matrix.drf-version }}.0" +# echo "Django: `django-admin --version`" +# python --version +# - name: Run Tests +# run: | +# python example/manage.py test tests -v 1 --noinput flake8-linter: runs-on: ubuntu-latest @@ -46,6 +46,6 @@ jobs: # The GitHub API token to create reviews with token: ${{ secrets.GITHUB_TOKEN }} # Fail if "new" violations detected or "any", default "new" - failIf: new + failIf: any # Additional arguments to pass to flake8, default "." (current directory) args: "--extend-exclude=migrations ." From 7d9614aa52173a86e33e53b4727e58ebfb99d678 Mon Sep 17 00:00:00 2001 From: "Vertliba.V" Date: Sat, 16 May 2020 23:48:55 +0300 Subject: [PATCH 13/16] switched CI to github actions, added linter, refactoring. --- setup.cfg | 2 ++ tests/test_api.py | 4 +--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/setup.cfg b/setup.cfg index 5e40900..076c817 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,2 +1,4 @@ [wheel] universal = 1 +[flake8] +per-file-ignores = tests/test_api.py: E501 \ No newline at end of file diff --git a/tests/test_api.py b/tests/test_api.py index b9c34f2..83eb022 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -9,13 +9,11 @@ ) -# flake8: noqa: E501 -# noinspection E501 class TestApiTestCase(TestCase): fixtures = ["test_data"] ELVIS_PRESLEY = "Elvis Presley" THE_BEATLES = "The Beatles" - LIMIT_OFFSET_PAGINATION = ( + LIMIT_OFFSET_PAGINATION = ( "rest_framework_datatables_editor.pagination." "DatatablesLimitOffsetPagination" ) def setUp(self): From f43b23cf0a9e581b018c436f39a81a9d09bae1a8 Mon Sep 17 00:00:00 2001 From: "Vertliba.V" Date: Sun, 17 May 2020 00:14:52 +0300 Subject: [PATCH 14/16] switched CI to github actions, added linter, refactoring. --- .github/workflows/build.yml | 65 ++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 33 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 73501cc..86c8310 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,39 +3,6 @@ name: build on: [push, pull_request] jobs: -# build: -# runs-on: ubuntu-latest -# strategy: -# fail-fast: false -# matrix: -# python-version: ['3.6', '3.7', '3.8'] -# django-version: ['1.11', '2.0', '2.1', '2.2', '3.0'] -# drf-version: ['3.9', '3.10', '3.11'] -# include: -# - python-version: '2.7' -# django-version: '1.11' -# drf-version: '3.9' -# exclude: -# - django-version: '3.0' -# drf-version: '3.9' -# steps: -# - uses: actions/checkout@v2 -# - name: Set up Python ${{ matrix.python-version }} -# uses: actions/setup-python@v1 -# with: -# python-version: ${{ matrix.python-version }} -# - name: Install Dependencies -# run: | -# python -m pip install --upgrade pip -# echo "Python ${{ matrix.python-version }} -> Django ${{ matrix.django-version }} -> DRF ${{ matrix.drf-version }}" -# python -m pip install "Django~=${{ matrix.django-version }}.0" -# python -m pip install "djangorestframework~=${{ matrix.drf-version }}.0" -# echo "Django: `django-admin --version`" -# python --version -# - name: Run Tests -# run: | -# python example/manage.py test tests -v 1 --noinput - flake8-linter: runs-on: ubuntu-latest steps: @@ -49,3 +16,35 @@ jobs: failIf: any # Additional arguments to pass to flake8, default "." (current directory) args: "--extend-exclude=migrations ." + build: + runs-on: ubuntu-latest + strategy: + fail-fast: true + matrix: + python-version: ['3.6', '3.7', '3.8'] + django-version: ['1.11', '2.0', '2.1', '2.2', '3.0'] + drf-version: ['3.9', '3.10', '3.11'] + include: + - python-version: '2.7' + django-version: '1.11' + drf-version: '3.9' + exclude: + - django-version: '3.0' + drf-version: '3.9' + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v1 + with: + python-version: ${{ matrix.python-version }} + - name: Install Dependencies + run: | + python -m pip install --upgrade pip + echo "Python ${{ matrix.python-version }} -> Django ${{ matrix.django-version }} -> DRF ${{ matrix.drf-version }}" + python -m pip install "Django~=${{ matrix.django-version }}.0" + python -m pip install "djangorestframework~=${{ matrix.drf-version }}.0" + echo "Django: `django-admin --version`" + python --version + - name: Run Tests + run: | + python example/manage.py test tests -v 1 --noinput From ed55dc210f8c007c24ccc1530cad8799c327c156 Mon Sep 17 00:00:00 2001 From: "Vertliba.V" Date: Sun, 17 May 2020 00:15:41 +0300 Subject: [PATCH 15/16] switched CI to github actions, added linter, refactoring. --- tests/test_api.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_api.py b/tests/test_api.py index 83eb022..8e9ab86 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -13,9 +13,10 @@ class TestApiTestCase(TestCase): fixtures = ["test_data"] ELVIS_PRESLEY = "Elvis Presley" THE_BEATLES = "The Beatles" - LIMIT_OFFSET_PAGINATION = ( + LIMIT_OFFSET_PAGINATION = ( "rest_framework_datatables_editor.pagination." "DatatablesLimitOffsetPagination" ) + def setUp(self): self.client = APIClient() AlbumViewSet.pagination_class = DatatablesPageNumberPagination From 21a8bb55de0956acf4102749affe1c29f6dc325d Mon Sep 17 00:00:00 2001 From: "Vertliba.V" Date: Sun, 17 May 2020 00:32:44 +0300 Subject: [PATCH 16/16] switched CI to github actions, added linter, refactoring. --- README.rst | 17 +++++++++-------- docs/changelog.rst | 6 ++++++ setup.py | 2 ++ 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/README.rst b/README.rst index 46c2d3c..bc81cec 100644 --- a/README.rst +++ b/README.rst @@ -1,7 +1,7 @@ django-rest-framework-datatables-editor ======================================= -|build-status-image| |codecov-image| |documentation-status-image| |pypi-version| |py-versions| +|build-status-image| |codecov-image| |documentation-status-image| |pypi-version| |py-versions| |dj-versions| Overview -------- @@ -212,21 +212,22 @@ If you want to check the coverage, use: :target: https://travis-ci.com/VVyacheslav/django-rest-framework-datatables-editor :alt: Travis build -.. |codecov-image| image:: https://codecov.io/gh/VVyacheslav/django-rest-framework-datatables-editor/branch/master/graph/badge.svg +.. |codecov-image| image:: https://codecov.io/gh/VVyacheslav/django-rest-framework-datatables-editor/branch/master/graph/badge.svg?style=flat-square :target: https://codecov.io/gh/VVyacheslav/django-rest-framework-datatables-editor -.. |pypi-version| image:: https://img.shields.io/pypi/v/djangorestframework-datatables-editor.svg +.. |pypi-version| image:: https://img.shields.io/pypi/v/djangorestframework-datatables-editor.svg?style=flat-square :target: https://pypi.python.org/pypi/djangorestframework-datatables-editor :alt: Pypi version -.. |documentation-status-image| image:: https://readthedocs.org/projects/drf-datatables-editor/badge/?version=latest +.. |documentation-status-image| image:: https://readthedocs.org/projects/drf-datatables-editor/badge/?version=latest&style=flat-square :target: https://drf-datatables-editor.readthedocs.io/en/latest/?badge=latest :alt: Documentation Status -.. |py-versions| image:: https://img.shields.io/pypi/pyversions/djangorestframework-datatables-editor.svg - :target: https://img.shields.io/pypi/pyversions/djangorestframework-datatables.svg +.. |py-versions| image:: https://img.shields.io/pypi/pyversions/djangorestframework-datatables-editor.svg?style=flat-square + :target: https://img.shields.io/pypi/pyversions/djangorestframework-datatables-editor.svg :alt: Python versions -.. |dj-versions| image:: https://img.shields.io/pypi/djversions/djangorestframework-datatables.svg - :target: https://img.shields.io/pypi/djversions/djangorestframework-datatables.svg +.. |dj-versions| image:: https://img.shields.io/pypi/djversions/djangorestframework-datatables-editor.svg?style=flat-square + :target: https://img.shields.io/pypi/djversions/djangorestframework-datatables-editor.svg :alt: Django versions + diff --git a/docs/changelog.rst b/docs/changelog.rst index afb3258..d0eb96d 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,6 +1,12 @@ Changelog ========= +Version 0.3.3 (2020-05-17): +--------------------------- + +- Added support for Django 3.0 + + Version 0.3.2 (2019-05-23): --------------------------- diff --git a/setup.py b/setup.py index f145524..002bf4d 100644 --- a/setup.py +++ b/setup.py @@ -105,6 +105,8 @@ def get_version(): 'Framework :: Django :: 1.11', 'Framework :: Django :: 2.0', 'Framework :: Django :: 2.1', + 'Framework :: Django :: 2.2', + 'Framework :: Django :: 3.0', 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', 'Operating System :: OS Independent',