diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000..e932ebc --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,98 @@ +version: 2.1 + +aliases: + - &environ + run: + name: setup virtual environment + # The below ensures the venv is activated for every subsequent step + command: | + virtualenv venv + echo "source /home/circleci/project/venv/bin/activate" >> $BASH_ENV + + - &install + run: + name: install dependencies + command: | + pip install -U pip setuptools wheel tox tox-factor codecov + + - &test-steps + steps: + - checkout + - *environ + - *install + - run: tox -- -v 2 + - run: coverage combine + - run: coverage report + - run: codecov + +jobs: + lint: + steps: + - checkout + - *environ + - *install + - run: tox -e lint + docker: + - image: circleci/python:3.7 + + test-py37: + <<: *test-steps + docker: + - image: circleci/python:3.7 + environment: + TOXFACTOR: py37 + + test-py36: + <<: *test-steps + docker: + - image: circleci/python:3.6 + environment: + TOXFACTOR: py36 + + test-py35: + <<: *test-steps + docker: + - image: circleci/python:3.5 + environment: + TOXFACTOR: py35 + + test-py27: + <<: *test-steps + docker: + - image: circleci/python:2.7 + environment: + TOXFACTOR: py27 + + +workflows: + version: 2 + commit: &test-workflow + jobs: + - lint + + - test-py37: + requires: + - lint + + - test-py36: + requires: + - lint + + - test-py35: + requires: + - lint + + - test-py27: + requires: + - lint + + weekly: + <<: *test-workflow + triggers: + - schedule: + # 8/9 AM PST/PDT every Monday + cron: "0 16 * * 1" + filters: + branches: + only: + - master diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index b059c1e..0000000 --- a/.travis.yml +++ /dev/null @@ -1,26 +0,0 @@ -language: python -python: - - "2.7" - - "3.5" - - "3.6" -env: - - DJANGO=1.11.* DRF=3.7.* - - DJANGO=1.11.* DRF=3.8.* - - DJANGO=2.0.* DRF=3.7.* - - DJANGO=2.0.* DRF=3.8.* -install: - - pip install -q Django==$DJANGO djangorestframework==$DRF - - pip install coveralls - - pip install -r rest_auth/tests/requirements.pip -script: - - coverage run --source=rest_auth setup.py test -after_success: - - coveralls -before_script: - - flake8 . --config=flake8 -matrix: - exclude: - - python: "2.7" - env: DJANGO=2.0.* DRF=3.7.* - - python: "2.7" - env: DJANGO=2.0.* DRF=3.8.* diff --git a/MANIFEST.in b/MANIFEST.in index 01a589f..1918442 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,5 +1,11 @@ include AUTHORS include LICENSE -include MANIFEST.in -include README.md +include README.rst graft rest_auth + +include tox.ini +include manage.py +recursive-include tests *.py +recursive-include demo * +recursive-include docs * +prune docs/_build diff --git a/README.rst b/README.rst index 2395717..951c1fe 100644 --- a/README.rst +++ b/README.rst @@ -7,17 +7,22 @@ Please use https://github.com/iMerica/dj-rest-auth as this project is no longer Welcome to django-rest-auth =========================== -.. image:: https://travis-ci.org/Tivix/django-rest-auth.svg - :target: https://travis-ci.org/Tivix/django-rest-auth +.. image:: https://circleci.com/gh/Tivix/django-rest-auth.svg?style=shield + :target: https://circleci.com/gh/Tivix/django-rest-auth -.. image:: https://coveralls.io/repos/Tivix/django-rest-auth/badge.svg - :target: https://coveralls.io/r/Tivix/django-rest-auth?branch=master +.. image:: https://codecov.io/gh/Tivix/django-rest-auth/branch/master/graph/badge.svg + :target: https://codecov.io/gh/Tivix/django-rest-auth .. image:: https://readthedocs.org/projects/django-rest-auth/badge/?version=latest - :target: https://readthedocs.org/projects/django-rest-auth/?badge=latest + :target: https://readthedocs.org/projects/django-rest-auth/?badge=latest +.. image:: https://img.shields.io/pypi/v/django-rest-auth.svg + :target: https://pypi.python.org/pypi/django-rest-auth + +.. image:: https://img.shields.io/pypi/l/django-rest-auth.svg + :target: https://pypi.python.org/pypi/django-rest-auth Django-rest-auth provides a set of REST API endpoints for Authentication and Registration diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 0000000..5de63f9 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,2 @@ +comment: + layout: "reach" diff --git a/manage.py b/manage.py new file mode 100644 index 0000000..38a919f --- /dev/null +++ b/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +import os +import sys + +if __name__ == "__main__": + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tests.settings") + try: + from django.core.management import execute_from_command_line + except ImportError: + # The above import may fail for some other reason. Ensure that the + # issue is really that Django is missing to avoid masking other + # exceptions on Python 2. + try: + import django + except ImportError: + 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?" + ) + raise + execute_from_command_line(sys.argv) diff --git a/rest_auth/registration/serializers.py b/rest_auth/registration/serializers.py index 4f99c18..d62d701 100644 --- a/rest_auth/registration/serializers.py +++ b/rest_auth/registration/serializers.py @@ -58,7 +58,7 @@ class SocialLoginSerializer(serializers.Serializer): social_login.token = token return social_login - def validate(self, attrs): + def validate(self, attrs): # noqa: C901 view = self.context.get('view') request = self._get_request() diff --git a/rest_auth/serializers.py b/rest_auth/serializers.py index b645231..33bbfde 100644 --- a/rest_auth/serializers.py +++ b/rest_auth/serializers.py @@ -59,7 +59,7 @@ class LoginSerializer(serializers.Serializer): return user - def validate(self, attrs): + def validate(self, attrs): # noqa: C901 username = attrs.get('username') email = attrs.get('email') password = attrs.get('password') diff --git a/rest_auth/tests/django_urls.py b/rest_auth/tests/django_urls.py deleted file mode 100644 index c1fb050..0000000 --- a/rest_auth/tests/django_urls.py +++ /dev/null @@ -1,30 +0,0 @@ -# Moved in Django 1.8 from django to tests/auth_tests/urls.py - -from django.conf.urls import url -from django.contrib.auth import views -from django.contrib.auth.decorators import login_required -from django.contrib.auth.urls import urlpatterns - - -# special urls for auth test cases -urlpatterns += [ - url(r'^logout/custom_query/$', views.logout, dict(redirect_field_name='follow')), - url(r'^logout/next_page/$', views.logout, dict(next_page='/somewhere/')), - url(r'^logout/next_page/named/$', views.logout, dict(next_page='password_reset')), - url(r'^password_reset_from_email/$', views.password_reset, dict(from_email='staffmember@example.com')), - url(r'^password_reset/custom_redirect/$', views.password_reset, dict(post_reset_redirect='/custom/')), - url(r'^password_reset/custom_redirect/named/$', views.password_reset, dict(post_reset_redirect='password_reset')), - url(r'^password_reset/html_email_template/$', views.password_reset, - dict(html_email_template_name='registration/html_password_reset_email.html')), - url(r'^reset/custom/(?P[0-9A-Za-z_\-]+)/(?P[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$', - views.password_reset_confirm, - dict(post_reset_redirect='/custom/')), - url(r'^reset/custom/named/(?P[0-9A-Za-z_\-]+)/(?P[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$', - views.password_reset_confirm, - dict(post_reset_redirect='password_reset')), - url(r'^password_change/custom/$', views.password_change, dict(post_change_redirect='/custom/')), - url(r'^password_change/custom/named/$', views.password_change, dict(post_change_redirect='password_reset')), - url(r'^admin_password_reset/$', views.password_reset, dict(is_admin_site=True)), - url(r'^login_required/$', login_required(views.password_reset)), - url(r'^login_required_login_url/$', login_required(views.password_reset, login_url='/somewhere/')), -] diff --git a/rest_auth/tests/requirements.pip b/rest_auth/tests/requirements.pip deleted file mode 100644 index f48ee3c..0000000 --- a/rest_auth/tests/requirements.pip +++ /dev/null @@ -1,5 +0,0 @@ -django-allauth>=0.25.0 -responses>=0.3.0 -flake8==2.4.0 -djangorestframework-jwt>=1.7.2 -djangorestframework>=3.6.4 diff --git a/rest_auth/utils.py b/rest_auth/utils.py index 800f184..764edb9 100644 --- a/rest_auth/utils.py +++ b/rest_auth/utils.py @@ -1,4 +1,4 @@ -from six import string_types +from django.utils.six import string_types from importlib import import_module diff --git a/runtests.py b/runtests.py deleted file mode 100644 index 8b7ede2..0000000 --- a/runtests.py +++ /dev/null @@ -1,24 +0,0 @@ -# This file mainly exists to allow python setup.py test to work. -# flake8: noqa -import os -import sys - -os.environ['DJANGO_SETTINGS_MODULE'] = 'tests.settings' -test_dir = os.path.join(os.path.dirname(__file__), 'rest_auth') -sys.path.insert(0, test_dir) - -import django -from django.test.utils import get_runner -from django.conf import settings - - -def runtests(): - TestRunner = get_runner(settings) - test_runner = TestRunner(verbosity=1, interactive=True) - if hasattr(django, 'setup'): - django.setup() - failures = test_runner.run_tests(['rest_auth']) - sys.exit(bool(failures)) - -if __name__ == '__main__': - runtests() diff --git a/setup.cfg b/setup.cfg index 8d915a7..90bb081 100644 --- a/setup.cfg +++ b/setup.cfg @@ -2,38 +2,69 @@ universal = 1 -[metadata] -license_file = LICENSE - - [flake8] -max-line-length = 120 -exclude = docs/*,demo/* -ignore = F403 +max_line_length = 120 +max_complexity = 10 +exclude = migrations [coverage:run] -omit=*site-packages*,*distutils*,*migrations* +branch = true +source = . +include = rest_auth/* [coverage:report] -# Regexes for lines to exclude from consideration -exclude_lines = - # Have to re-enable the standard pragma - pragma: no cover +include = rest_auth/* +omit = + *migrations* + tests - # Don't complain about missing debug-only code: - def __repr__ - if self\.debug - # Don't complain if tests don't hit defensive assertion code: - raise AssertionError - raise NotImplementedError +[metadata] +name = django-rest-auth +version = 0.9.5 +keywords = django, rest, auth, registration, rest-framework, django-registration, api +description = Create a set of REST API endpoints for Authentication and Registration +long_description = file: README.rst +license = MIT +license_file = LICENSE - # Don't complain if non-runnable code isn't run: - if 0: - if __name__ == .__main__.: +author = Sumit Chachra +author_email = chachra@tivix.com +url = http://github.com/Tivix/django-rest-auth -ignore_errors = True +classifiers = + Development Status :: 4 - Beta + Framework :: Django + Framework :: Django :: 1.11 + Framework :: Django :: 2.0 + Framework :: Django :: 2.1 + Framework :: Django :: 2.2 + Intended Audience :: Developers + Intended Audience :: System Administrators + License :: OSI Approved :: BSD License + Operating System :: OS Independent + Programming Language :: Python + Programming Language :: Python :: 2 + Programming Language :: Python :: 2.7 + Programming Language :: Python :: 3 + Programming Language :: Python :: 3.5 + Programming Language :: Python :: 3.6 + Programming Language :: Python :: 3.7 + Topic :: Software Development -[coverage:html] -directory = coverage_html +[options] +zip_safe = False +include_package_data = True +packages = find: +install_requires = + Django >= 1.8.0 + djangorestframework >= 3.1.3 + +[options.extras_require] +with_social = + django-allauth >= 0.25.0 + +[options.packages.find] +exclude = + tests diff --git a/setup.py b/setup.py index 675b99d..2598061 100644 --- a/setup.py +++ b/setup.py @@ -1,46 +1,5 @@ #!/usr/bin/env python - -import os -from setuptools import setup, find_packages +from setuptools import setup -here = os.path.dirname(os.path.abspath(__file__)) -f = open(os.path.join(here, 'README.rst')) -long_description = f.read().strip() -f.close() - - -setup( - name='django-rest-auth', - version='0.9.5', - author='Sumit Chachra', - author_email='chachra@tivix.com', - url='http://github.com/Tivix/django-rest-auth', - description='Create a set of REST API endpoints for Authentication and Registration', - packages=find_packages(), - long_description=long_description, - keywords='django rest auth registration rest-framework django-registration api', - zip_safe=False, - install_requires=[ - 'Django>=1.8.0', - 'djangorestframework>=3.1.3', - 'six>=1.9.0', - ], - extras_require={ - 'with_social': ['django-allauth>=0.25.0'], - }, - tests_require=[ - 'responses>=0.5.0', - 'django-allauth>=0.25.0', - 'djangorestframework-jwt>=1.9.0', - ], - test_suite='runtests.runtests', - include_package_data=True, - classifiers=[ - 'Framework :: Django', - 'Intended Audience :: Developers', - 'Intended Audience :: System Administrators', - 'Operating System :: OS Independent', - 'Topic :: Software Development' - ], -) +setup() diff --git a/rest_auth/tests/__init__.py b/tests/__init__.py similarity index 100% rename from rest_auth/tests/__init__.py rename to tests/__init__.py diff --git a/tests/django_urls.py b/tests/django_urls.py new file mode 100644 index 0000000..559c753 --- /dev/null +++ b/tests/django_urls.py @@ -0,0 +1,28 @@ +# Moved in Django 1.8 from django to tests/auth_tests/urls.py + +from django.conf.urls import url +from django.contrib.auth import views +from django.contrib.auth.decorators import login_required +from django.contrib.auth.urls import urlpatterns + + +# special urls for auth test cases +urlpatterns += [ + url(r'^logout/custom_query/$', views.LogoutView.as_view(redirect_field_name='follow')), + url(r'^logout/next_page/$', views.LogoutView.as_view(next_page='/somewhere/')), + url(r'^logout/next_page/named/$', views.LogoutView.as_view(next_page='password_reset')), + url(r'^password_reset_from_email/$', views.PasswordResetView.as_view(from_email='staffmember@example.com')), + url(r'^password_reset/custom_redirect/$', views.PasswordResetView.as_view(success_url='/custom/')), + url(r'^password_reset/custom_redirect/named/$', views.PasswordResetView.as_view(success_url='password_reset')), + url(r'^password_reset/html_email_template/$', views.PasswordResetView.as_view( + html_email_template_name='registration/html_password_reset_email.html')), + url(r'^reset/custom/(?P[0-9A-Za-z_\-]+)/(?P[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$', + views.PasswordResetConfirmView.as_view(success_url='/custom/')), + url(r'^reset/custom/named/(?P[0-9A-Za-z_\-]+)/(?P[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$', + views.PasswordResetConfirmView.as_view(success_url='password_reset')), + url(r'^password_change/custom/$', views.PasswordChangeView.as_view(success_url='/custom/')), + url(r'^password_change/custom/named/$', views.PasswordChangeView.as_view(success_url='password_reset')), + url(r'^admin_password_reset/$', views.PasswordResetView.as_view()), + url(r'^login_required/$', login_required(views.PasswordResetView.as_view())), + url(r'^login_required_login_url/$', login_required(views.PasswordResetView.as_view(), login_url='/somewhere/')), +] diff --git a/rest_auth/tests/mixins.py b/tests/mixins.py similarity index 100% rename from rest_auth/tests/mixins.py rename to tests/mixins.py diff --git a/rest_auth/tests/settings.py b/tests/settings.py similarity index 58% rename from rest_auth/tests/settings.py rename to tests/settings.py index e353fb0..3f22fee 100644 --- a/rest_auth/tests/settings.py +++ b/tests/settings.py @@ -1,23 +1,3 @@ -import os -import sys - -PROJECT_ROOT = os.path.abspath(os.path.split(os.path.split(__file__)[0])[0]) - -ROOT_URLCONF = 'urls' -STATIC_URL = '/static/' -STATIC_ROOT = '%s/staticserve' % PROJECT_ROOT -STATICFILES_DIRS = ( - ('global', '%s/static' % PROJECT_ROOT), -) -UPLOADS_DIR_NAME = 'uploads' -MEDIA_URL = '/%s/' % UPLOADS_DIR_NAME -MEDIA_ROOT = os.path.join(PROJECT_ROOT, '%s' % UPLOADS_DIR_NAME) - -IS_DEV = False -IS_STAGING = False -IS_PROD = False -IS_TEST = 'test' in sys.argv or 'test_coverage' in sys.argv - DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', @@ -33,31 +13,22 @@ MIDDLEWARE = [ 'django.contrib.messages.middleware.MessageMiddleware' ] -# Adding for backwards compatibility for Django 1.8 tests -MIDDLEWARE_CLASSES = MIDDLEWARE - -TEMPLATE_CONTEXT_PROCESSORS = [ - 'django.contrib.auth.context_processors.auth', - 'django.core.context_processors.debug', - 'django.core.context_processors.media', - 'django.core.context_processors.request', - 'django.contrib.messages.context_processors.messages', - 'django.core.context_processors.static', - - "allauth.account.context_processors.account", - "allauth.socialaccount.context_processors.socialaccount", -] - -# avoid deprecation warnings during tests TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [ - # insert your TEMPLATE_DIRS here - ], 'APP_DIRS': True, 'OPTIONS': { - 'context_processors': TEMPLATE_CONTEXT_PROCESSORS, + 'context_processors': [ + 'django.contrib.auth.context_processors.auth', + 'django.core.context_processors.debug', + 'django.core.context_processors.media', + 'django.core.context_processors.request', + 'django.contrib.messages.context_processors.messages', + 'django.core.context_processors.static', + + "allauth.account.context_processors.account", + "allauth.socialaccount.context_processors.socialaccount", + ], }, }, ] @@ -75,6 +46,7 @@ INSTALLED_APPS = [ 'django.contrib.humanize', 'django.contrib.contenttypes', 'django.contrib.sessions', + 'django.contrib.messages', 'django.contrib.sites', 'django.contrib.sitemaps', 'django.contrib.staticfiles', diff --git a/rest_auth/tests/test_api.py b/tests/test_api.py similarity index 100% rename from rest_auth/tests/test_api.py rename to tests/test_api.py diff --git a/rest_auth/tests/test_social.py b/tests/test_social.py similarity index 100% rename from rest_auth/tests/test_social.py rename to tests/test_social.py diff --git a/rest_auth/tests/urls.py b/tests/urls.py similarity index 100% rename from rest_auth/tests/urls.py rename to tests/urls.py diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..a212b74 --- /dev/null +++ b/tox.ini @@ -0,0 +1,31 @@ +[tox] +envlist = + py{27,35,36}-django111-drf{38,39}, + py{35,36,37}-django20-drf{38,39}, + py{35,36,37}-django21-drf{38,39}, + py{35,36,37}-django22-drf{38,39}, + lint, + +[testenv] +commands = coverage run --parallel-mode manage.py test {posargs} +usedevelop = True +setenv = + PYTHONDONTWRITEBYTECODE=1 +deps = + django111: Django ~= 1.11.0 + django20: Django ~= 2.0.0 + django21: Django ~= 2.1.0 + django22: Django ~= 2.2.0 + drf38: djangorestframework ~= 3.8.0 + drf39: djangorestframework ~= 3.9.0 + djangorestframework-jwt >= 1.9.0 + django-allauth >= 0.25.0 + responses >= 0.5.0 + coverage + +parallel_show_output = True + +[testenv:lint] +commands = flake8 rest_auth tests {posargs} +deps = + flake8