diff --git a/.gitignore b/.gitignore index 2c6f875..c057419 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ src/ docs/_build/ .eggs/ .python-version +.pytest_cache/ diff --git a/.travis.yml b/.travis.yml index 6c39c62..3d5c324 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,8 +10,11 @@ env: - DJANGO=1.9 - DJANGO=1.10 - DJANGO=1.11 + - DJANGO=2.0 matrix: exclude: + - python: "2.7" + env: DJANGO=2.0 - python: "3.5" env: DJANGO=1.7 - python: "3.6" diff --git a/CHANGELOG.md b/CHANGELOG.md index d377aae..2b7899a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,17 +2,24 @@ All notable changes to this project will be documented in this file. -### [Unreleased] +### Unreleased ##### Added -- Add pep8 compliance and checker +- Add pep8 compliance and checker. + +##### Changed +- Test suit now uses pytest. + +### [0.5.3] - 2018-03-09 + +##### Fixed +- Update project to support Django 2.0 ### [0.5.2] - 2017-08-22 ##### Fixed - Fix infinite login loop if "prompt=login" (#198) -- Fix Django 2.0 deprecation warnings (#185) - +- Fix Django 2.0 deprecation warnings (#185) ### [0.5.1] - 2017-07-11 diff --git a/docs/sections/installation.rst b/docs/sections/installation.rst index 3314d6a..bf18a0a 100644 --- a/docs/sections/installation.rst +++ b/docs/sections/installation.rst @@ -7,7 +7,7 @@ Requirements ============ * Python: ``2.7`` ``3.4`` ``3.5`` ``3.6`` -* Django: ``1.7`` ``1.8`` ``1.9`` ``1.10`` ``1.11`` +* Django: ``1.7`` ``1.8`` ``1.9`` ``1.10`` ``1.11`` ``2.0`` Quick Installation ================== diff --git a/example_project/myapp/settings.py b/example_project/myapp/settings.py index e97ad1d..8d531d9 100644 --- a/example_project/myapp/settings.py +++ b/example_project/myapp/settings.py @@ -29,11 +29,11 @@ MIDDLEWARE_CLASSES = [ 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'oidc_provider.middleware.SessionManagementMiddleware', ] +MIDDLEWARE = MIDDLEWARE_CLASSES TEMPLATES = [ { diff --git a/example_project/myapp/urls.py b/example_project/myapp/urls.py index aac3450..2b0a624 100644 --- a/example_project/myapp/urls.py +++ b/example_project/myapp/urls.py @@ -1,5 +1,8 @@ from django.contrib.auth import views as auth_views -from django.conf.urls import include, url +try: + from django.urls import include, url +except ImportError: + from django.conf.urls import include, url from django.contrib import admin from django.views.generic import TemplateView @@ -8,8 +11,6 @@ urlpatterns = [ url(r'^$', TemplateView.as_view(template_name='home.html'), name='home'), url(r'^accounts/login/$', auth_views.login, {'template_name': 'login.html'}, name='login'), url(r'^accounts/logout/$', auth_views.logout, {'next_page': '/'}, name='logout'), - url(r'^', include('oidc_provider.urls', namespace='oidc_provider')), - - url(r'^admin/', include(admin.site.urls)), + url(r'^admin/', admin.site.urls), ] diff --git a/oidc_provider/compat.py b/oidc_provider/compat.py new file mode 100644 index 0000000..13091df --- /dev/null +++ b/oidc_provider/compat.py @@ -0,0 +1,5 @@ +def get_attr_or_callable(obj, name): + target = getattr(obj, name) + if callable(target): + return target() + return target diff --git a/oidc_provider/tests/app/urls.py b/oidc_provider/tests/app/urls.py index 8c513fd..d09fad1 100644 --- a/oidc_provider/tests/app/urls.py +++ b/oidc_provider/tests/app/urls.py @@ -1,5 +1,8 @@ from django.contrib.auth import views as auth_views -from django.conf.urls import include, url +try: + from django.urls import include, url +except ImportError: + from django.conf.urls import include, url from django.contrib import admin from django.views.generic import TemplateView @@ -11,5 +14,5 @@ urlpatterns = [ url(r'^openid/', include('oidc_provider.urls', namespace='oidc_provider')), - url(r'^admin/', include(admin.site.urls)), + url(r'^admin/', admin.site.urls), ] diff --git a/oidc_provider/tests/test_authorize_endpoint.py b/oidc_provider/tests/cases/test_authorize_endpoint.py similarity index 99% rename from oidc_provider/tests/test_authorize_endpoint.py rename to oidc_provider/tests/cases/test_authorize_endpoint.py index b498425..55e333e 100644 --- a/oidc_provider/tests/test_authorize_endpoint.py +++ b/oidc_provider/tests/cases/test_authorize_endpoint.py @@ -13,7 +13,10 @@ from mock import patch, mock from django.contrib.auth.models import AnonymousUser from django.core.management import call_command -from django.core.urlresolvers import reverse +try: + from django.urls import reverse +except ImportError: + from django.core.urlresolvers import reverse from django.test import ( RequestFactory, override_settings, diff --git a/oidc_provider/tests/test_claims.py b/oidc_provider/tests/cases/test_claims.py similarity index 100% rename from oidc_provider/tests/test_claims.py rename to oidc_provider/tests/cases/test_claims.py diff --git a/oidc_provider/tests/test_commands.py b/oidc_provider/tests/cases/test_commands.py similarity index 100% rename from oidc_provider/tests/test_commands.py rename to oidc_provider/tests/cases/test_commands.py diff --git a/oidc_provider/tests/test_end_session_endpoint.py b/oidc_provider/tests/cases/test_end_session_endpoint.py similarity index 96% rename from oidc_provider/tests/test_end_session_endpoint.py rename to oidc_provider/tests/cases/test_end_session_endpoint.py index 636af8b..6125d19 100644 --- a/oidc_provider/tests/test_end_session_endpoint.py +++ b/oidc_provider/tests/cases/test_end_session_endpoint.py @@ -1,5 +1,8 @@ from django.core.management import call_command -from django.core.urlresolvers import reverse +try: + from django.urls import reverse +except ImportError: + from django.core.urlresolvers import reverse from django.test import TestCase from oidc_provider.lib.utils.token import ( diff --git a/oidc_provider/tests/test_middleware.py b/oidc_provider/tests/cases/test_middleware.py similarity index 93% rename from oidc_provider/tests/test_middleware.py rename to oidc_provider/tests/cases/test_middleware.py index 5a3cc5f..4c93b0c 100644 --- a/oidc_provider/tests/test_middleware.py +++ b/oidc_provider/tests/cases/test_middleware.py @@ -1,4 +1,7 @@ -from django.conf.urls import url +try: + from django.urls import url +except ImportError: + from django.conf.urls import url from django.test import TestCase, override_settings from django.views.generic import View from mock import mock diff --git a/oidc_provider/tests/test_provider_info_endpoint.py b/oidc_provider/tests/cases/test_provider_info_endpoint.py similarity index 87% rename from oidc_provider/tests/test_provider_info_endpoint.py rename to oidc_provider/tests/cases/test_provider_info_endpoint.py index 6e8da9d..2265ef6 100644 --- a/oidc_provider/tests/test_provider_info_endpoint.py +++ b/oidc_provider/tests/cases/test_provider_info_endpoint.py @@ -1,4 +1,7 @@ -from django.core.urlresolvers import reverse +try: + from django.urls import reverse +except ImportError: + from django.core.urlresolvers import reverse from django.test import RequestFactory from django.test import TestCase diff --git a/oidc_provider/tests/test_settings.py b/oidc_provider/tests/cases/test_settings.py similarity index 100% rename from oidc_provider/tests/test_settings.py rename to oidc_provider/tests/cases/test_settings.py diff --git a/oidc_provider/tests/test_token_endpoint.py b/oidc_provider/tests/cases/test_token_endpoint.py similarity index 99% rename from oidc_provider/tests/test_token_endpoint.py rename to oidc_provider/tests/cases/test_token_endpoint.py index 49b7598..8295056 100644 --- a/oidc_provider/tests/test_token_endpoint.py +++ b/oidc_provider/tests/cases/test_token_endpoint.py @@ -9,7 +9,10 @@ except ImportError: from urllib import urlencode from django.core.management import call_command -from django.core.urlresolvers import reverse +try: + from django.urls import reverse +except ImportError: + from django.core.urlresolvers import reverse from django.test import ( RequestFactory, override_settings, diff --git a/oidc_provider/tests/test_userinfo_endpoint.py b/oidc_provider/tests/cases/test_userinfo_endpoint.py similarity index 97% rename from oidc_provider/tests/test_userinfo_endpoint.py rename to oidc_provider/tests/cases/test_userinfo_endpoint.py index 8ac52c7..1c41cc0 100644 --- a/oidc_provider/tests/test_userinfo_endpoint.py +++ b/oidc_provider/tests/cases/test_userinfo_endpoint.py @@ -6,7 +6,10 @@ try: except ImportError: from urllib import urlencode -from django.core.urlresolvers import reverse +try: + from django.urls import reverse +except ImportError: + from django.core.urlresolvers import reverse from django.test import RequestFactory from django.test import TestCase from django.utils import timezone diff --git a/oidc_provider/tests/test_utils.py b/oidc_provider/tests/cases/test_utils.py similarity index 100% rename from oidc_provider/tests/test_utils.py rename to oidc_provider/tests/cases/test_utils.py diff --git a/oidc_provider/tests/settings.py b/oidc_provider/tests/settings.py new file mode 100644 index 0000000..ea61262 --- /dev/null +++ b/oidc_provider/tests/settings.py @@ -0,0 +1,79 @@ +DEBUG = False + +SECRET_KEY = 'this-should-be-top-secret' + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': ':memory:', + } +} + +SITE_ID = 1 + +MIDDLEWARE_CLASSES = [ + 'django.middleware.common.CommonMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', +] + +MIDDLEWARE = [ + 'django.middleware.common.CommonMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', +] + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + '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', + ], + }, + }, +] + +INSTALLED_APPS = [ + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.sites', + 'django.contrib.messages', + 'django.contrib.admin', + 'oidc_provider', +] + +ROOT_URLCONF = 'oidc_provider.tests.app.urls' + +TEMPLATE_DIRS = [ + 'oidc_provider/tests/templates', +] + +USE_TZ = True + +LOGGING = { + 'version': 1, + 'disable_existing_loggers': False, + 'handlers': { + 'console': { + 'class': 'logging.StreamHandler', + }, + }, + 'loggers': { + 'oidc_provider': { + 'handlers': ['console'], + 'level': 'DEBUG', + }, + }, +} + +# OIDC Provider settings. + +SITE_URL = 'http://localhost:8000' +OIDC_USERINFO = 'oidc_provider.tests.app.utils.userinfo' diff --git a/oidc_provider/urls.py b/oidc_provider/urls.py index d501e88..93033f3 100644 --- a/oidc_provider/urls.py +++ b/oidc_provider/urls.py @@ -1,4 +1,7 @@ -from django.conf.urls import url +try: + from django.urls import url +except ImportError: + from django.conf.urls import url from django.views.decorators.csrf import csrf_exempt from oidc_provider import ( diff --git a/oidc_provider/views.py b/oidc_provider/views.py index 6b66f9b..c82b428 100644 --- a/oidc_provider/views.py +++ b/oidc_provider/views.py @@ -11,13 +11,10 @@ from django.contrib.auth.views import ( redirect_to_login, logout, ) - -import django -if django.VERSION >= (1, 11): +try: from django.urls import reverse -else: +except ImportError: from django.core.urlresolvers import reverse - from django.contrib.auth import logout as django_user_logout from django.http import JsonResponse from django.shortcuts import render @@ -28,6 +25,7 @@ from django.views.decorators.http import require_http_methods from django.views.generic import View from jwkest import long_to_base64 +from oidc_provider.compat import get_attr_or_callable from oidc_provider.lib.claims import StandardScopeClaims from oidc_provider.lib.endpoints.authorize import AuthorizeEndpoint from oidc_provider.lib.endpoints.token import TokenEndpoint @@ -65,7 +63,7 @@ class AuthorizeView(View): try: authorize.validate_params() - if (request.user.is_authenticated if django.VERSION >= (1, 10) else request.user.is_authenticated()): + if get_attr_or_callable(request.user, 'is_authenticated'): # Check if there's a hook setted. hook_resp = settings.get('OIDC_AFTER_USERLOGIN_HOOK', import_str=True)( request=request, user=request.user, diff --git a/runtests.py b/runtests.py deleted file mode 100644 index a8576ce..0000000 --- a/runtests.py +++ /dev/null @@ -1,114 +0,0 @@ -#!/usr/bin/env python -import os -import sys - -import django - -from django.conf import settings - - -DEFAULT_SETTINGS = dict( - - DEBUG=False, - - DATABASES={ - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': ':memory:', - } - }, - - SITE_ID=1, - - MIDDLEWARE_CLASSES=[ - 'django.middleware.common.CommonMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - ], - - TEMPLATES=[ - { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [], - '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', - ], - }, - }, - ], - - LOGGING={ - 'version': 1, - 'disable_existing_loggers': False, - 'handlers': { - 'console': { - 'class': 'logging.StreamHandler', - }, - }, - 'loggers': { - 'oidc_provider': { - 'handlers': ['console'], - 'level': os.getenv('DJANGO_LOG_LEVEL', 'DEBUG'), - }, - }, - }, - - INSTALLED_APPS=[ - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.sites', - 'django.contrib.messages', - 'django.contrib.admin', - 'oidc_provider', - ], - - SECRET_KEY='this-should-be-top-secret', - - ROOT_URLCONF='oidc_provider.tests.app.urls', - - TEMPLATE_DIRS=[ - 'oidc_provider/tests/templates', - ], - - USE_TZ=True, - - # OIDC Provider settings. - - SITE_URL='http://localhost:8000', - OIDC_USERINFO='oidc_provider.tests.app.utils.userinfo', - -) - - -def runtests(*test_args): - if not settings.configured: - settings.configure(**DEFAULT_SETTINGS) - - django.setup() - - parent = os.path.dirname(os.path.abspath(__file__)) - sys.path.insert(0, parent) - - try: - from django.test.runner import DiscoverRunner - runner_class = DiscoverRunner - if not test_args: - test_args = ["oidc_provider.tests"] - except ImportError: - from django.test.simple import DjangoTestSuiteRunner - runner_class = DjangoTestSuiteRunner - if not test_args: - test_args = ["tests"] - - failures = runner_class(verbosity=1, interactive=True, failfast=False).run_tests(test_args) - sys.exit(failures) - - -if __name__ == "__main__": - runtests(*sys.argv[1:]) diff --git a/setup.py b/setup.py index 61ce8cc..02d7f45 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir))) setup( name='django-oidc-provider', - version='0.5.2', + version='0.5.3', packages=find_packages(), include_package_data=True, license='MIT License', diff --git a/tox.ini b/tox.ini index e3b52b1..4e65c94 100644 --- a/tox.ini +++ b/tox.ini @@ -1,39 +1,37 @@ [tox] - envlist= - clean, py27-django{17,18,19,110,111}, - py34-django{17,18,19,110,111}, - py35-django{18,19,110,111}, - py36-django{18,19,110,111}, - flake8 + py34-django{17,18,19,110,111,20}, + py35-django{18,19,110,111,20}, + py36-django{18,19,110,111,20}, [testenv] - +changedir= + oidc_provider/tests/cases deps = + mock + psycopg2 + pytest + pytest-django + pytest-flake8 + pytest-cov django17: django>=1.7,<1.8 django18: django>=1.8,<1.9 django19: django>=1.9,<1.10 django110: django>=1.10,<1.11 django111: django>=1.11,<1.12 - coverage - mock + django20: django>=2.0,<2.1 commands = - coverage run setup.py test + pytest --flake8 --cov=oidc_provider {posargs} -[testenv:clean] - -commands= - coverage erase - -[testenv:stats] - -commands= - coverage report -m - -[testenv:flake8] -basepython=python -deps=flake8 -commands = - flake8 --max-line-length=120 +[pytest] +DJANGO_SETTINGS_MODULE = oidc_provider.tests.settings +python_files = test_*.py +flake8-max-line-length = 99 +flake8-ignore = + .git ALL + __pycache__ ALL + .ropeproject ALL + */migrations ALL + manage.py ALL