Merged parent repo and configured refurbished tests

This commit is contained in:
Andrew-Chen-Wang 2020-03-14 13:29:08 -04:00
commit 9cf72849e6
28 changed files with 173 additions and 174 deletions

4
.github/FUNDING.yml vendored
View File

@ -1,7 +1,7 @@
# These are supported funding model platforms # These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] github: pydanny
patreon: danielroygreenfeld patreon: roygreenfeld
open_collective: # Replace with a single Open Collective username open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel

View File

@ -15,10 +15,6 @@ matrix:
include: include:
- name: Test results - name: Test results
script: tox -e py37 script: tox -e py37
- name: Run flake8 on result
script: tox -e flake8
- name: Run black on result
script: tox -e black
- name: Black template - name: Black template
script: tox -e black-template script: tox -e black-template
- name: Basic Docker - name: Basic Docker

View File

@ -88,6 +88,7 @@ Listed in alphabetical order.
Chris Pappalardo `@ChrisPappalardo`_ Chris Pappalardo `@ChrisPappalardo`_
Christopher Clarke `@chrisdev`_ Christopher Clarke `@chrisdev`_
Cole Mackenzie `@cmackenzie1`_ Cole Mackenzie `@cmackenzie1`_
Cole Maclean `@cole`_ @cole
Collederas `@Collederas`_ Collederas `@Collederas`_
Craig Margieson `@cmargieson`_ Craig Margieson `@cmargieson`_
Cristian Vargas `@cdvv7788`_ Cristian Vargas `@cdvv7788`_
@ -176,6 +177,7 @@ Listed in alphabetical order.
Oleg Russkin `@rolep`_ Oleg Russkin `@rolep`_
Pablo `@oubiga`_ Pablo `@oubiga`_
Parbhat Puri `@parbhat`_ Parbhat Puri `@parbhat`_
Pawan Chaurasia `@rjsnh1522`_
Peter Bittner `@bittner`_ Peter Bittner `@bittner`_
Peter Coles `@mrcoles`_ Peter Coles `@mrcoles`_
Philipp Matthies `@canonnervio`_ Philipp Matthies `@canonnervio`_
@ -206,6 +208,7 @@ Listed in alphabetical order.
Tubo Shi `@Tubo`_ Tubo Shi `@Tubo`_
Umair Ashraf `@umrashrf`_ @fabumair Umair Ashraf `@umrashrf`_ @fabumair
Vadim Iskuchekov `@Egregors`_ @egregors Vadim Iskuchekov `@Egregors`_ @egregors
Vicente G. Reyes `@reyesvicente`_ @highcenburg
Vitaly Babiy Vitaly Babiy
Vivian Guillen `@viviangb`_ Vivian Guillen `@viviangb`_
Vlad Doster `@vladdoster`_ Vlad Doster `@vladdoster`_
@ -260,6 +263,7 @@ Listed in alphabetical order.
.. _@chuckus: https://github.com/chuckus .. _@chuckus: https://github.com/chuckus
.. _@cmackenzie1: https://github.com/cmackenzie1 .. _@cmackenzie1: https://github.com/cmackenzie1
.. _@cmargieson: https://github.com/cmargieson .. _@cmargieson: https://github.com/cmargieson
.. _@cole: https://github.com/cole
.. _@Collederas: https://github.com/Collederas .. _@Collederas: https://github.com/Collederas
.. _@curtisstpierre: https://github.com/curtisstpierre .. _@curtisstpierre: https://github.com/curtisstpierre
.. _@dadokkio: https://github.com/dadokkio .. _@dadokkio: https://github.com/dadokkio
@ -337,11 +341,13 @@ Listed in alphabetical order.
.. _@originell: https://github.com/originell .. _@originell: https://github.com/originell
.. _@oubiga: https://github.com/oubiga .. _@oubiga: https://github.com/oubiga
.. _@parbhat: https://github.com/parbhat .. _@parbhat: https://github.com/parbhat
.. _@rjsnh1522: https://github.com/rjsnh1522
.. _@pchiquet: https://github.com/pchiquet .. _@pchiquet: https://github.com/pchiquet
.. _@phiberjenz: https://github.com/phiberjenz .. _@phiberjenz: https://github.com/phiberjenz
.. _@purplediane: https://github.com/purplediane .. _@purplediane: https://github.com/purplediane
.. _@raonyguimaraes: https://github.com/raonyguimaraes .. _@raonyguimaraes: https://github.com/raonyguimaraes
.. _@reggieriser: https://github.com/reggieriser .. _@reggieriser: https://github.com/reggieriser
.. _@reyesvicente: https://github.com/reyesvicente
.. _@rm--: https://github.com/rm-- .. _@rm--: https://github.com/rm--
.. _@rolep: https://github.com/rolep .. _@rolep: https://github.com/rolep
.. _@romanosipenko: https://github.com/romanosipenko .. _@romanosipenko: https://github.com/romanosipenko

View File

@ -105,16 +105,16 @@ This project is run by volunteers. Please support them in their efforts to maint
Projects that provide financial support to the maintainers: Projects that provide financial support to the maintainers:
Two Scoops of Django 1.11 Django Crash Course
~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~
.. image:: https://cdn.shopify.com/s/files/1/0304/6901/products/2017-06-29-tsd11-sticker-02.png .. image:: https://cdn.shopify.com/s/files/1/0304/6901/files/Django-Crash-Course-300x436.jpg
:name: Two Scoops of Django 1.11 Cover :name: Django Crash Course: Covers Django 3.0 and Python 3.8
:align: center :align: center
:alt: Two Scoops of Django :alt: Django Crash Course
:target: http://twoscoopspress.com/products/two-scoops-of-django-1-11 :target: https://www.roygreenfeld.com/products/django-crash-course
Two Scoops of Django is the best dessert-themed Django reference in the universe Django Crash Course for Django 3.0 and Python 3.8 is the best cheese-themed Django reference in the universe!
pyup pyup
~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~
@ -135,7 +135,7 @@ and then editing the results to include your name, email, and various configurat
First, get Cookiecutter. Trust me, it's awesome:: First, get Cookiecutter. Trust me, it's awesome::
$ pip install "cookiecutter>=1.4.0" $ pip install "cookiecutter>=1.7.0"
Now run it against this repo:: Now run it against this repo::

View File

@ -25,7 +25,9 @@ Provided you have opted for Celery (via setting ``use_celery`` to ``y``) there a
* ``celeryworker`` running a Celery worker process; * ``celeryworker`` running a Celery worker process;
* ``celerybeat`` running a Celery beat process; * ``celerybeat`` running a Celery beat process;
* ``flower`` running Flower_ (for more info, check out :ref:`CeleryFlower` instructions for local environment). * ``flower`` running Flower_.
The ``flower`` service is served by Traefik over HTTPS, through the port ``5555``. For more information about Flower and its login credentials, check out :ref:`CeleryFlower` instructions for local environment.
.. _`Flower`: https://github.com/mher/flower .. _`Flower`: https://github.com/mher/flower

View File

@ -1,7 +1,4 @@
[pytest] [pytest]
addopts = -x --tb=short addopts = -v --tb=short
python_paths = . python_paths = .
norecursedirs = .tox .git */migrations/* */static/* docs venv */{{cookiecutter.project_slug}}/* norecursedirs = .tox .git */migrations/* */static/* docs venv */{{cookiecutter.project_slug}}/*
markers =
flake8: Run flake8 on all possible template combinations
black: Run black on all possible template combinations

View File

@ -6,12 +6,12 @@ binaryornot==0.4.4
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
black==19.10b0 black==19.10b0
flake8==3.7.9 flake8==3.7.9
flake8-isort==2.8.0
# Testing # Testing
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
tox==3.14.3 tox==3.14.5
pytest==5.3.5 pytest==5.4.1
pytest_cases==1.12.1 pytest-cookies==0.5.1
pytest-cookies==0.5.0 pytest-instafail==0.4.1.post0
pytest-xdist==1.31.0
pyyaml==5.3 pyyaml==5.3

View File

@ -3,7 +3,6 @@ import re
import pytest import pytest
from cookiecutter.exceptions import FailedHookException from cookiecutter.exceptions import FailedHookException
from pytest_cases import fixture_plus
import sh import sh
import yaml import yaml
from binaryornot.check import is_binary from binaryornot.check import is_binary
@ -26,67 +25,75 @@ def context():
} }
@fixture_plus SUPPORTED_COMBINATIONS = [
@pytest.mark.parametrize("windows", ["y", "n"], ids=lambda yn: f"win:{yn}") {"open_source_license": "MIT"},
@pytest.mark.parametrize("use_docker", ["y", "n"], ids=lambda yn: f"docker:{yn}") {"open_source_license": "BSD"},
@pytest.mark.parametrize("use_celery", ["y", "n"], ids=lambda yn: f"celery:{yn}") {"open_source_license": "GPLv3"},
@pytest.mark.parametrize("use_mailhog", ["y", "n"], ids=lambda yn: f"mailhog:{yn}") {"open_source_license": "Apache Software License 2.0"},
@pytest.mark.parametrize("use_sentry", ["y", "n"], ids=lambda yn: f"sentry:{yn}") {"open_source_license": "Not open source"},
@pytest.mark.parametrize("use_compressor", ["y", "n"], ids=lambda yn: f"cmpr:{yn}") {"windows": "y"},
@pytest.mark.parametrize("use_drf", ["y", "n"], ids=lambda yn: f"drf:{yn}") {"windows": "n"},
@pytest.mark.parametrize( {"use_pycharm": "y"},
"use_whitenoise,cloud_provider", {"use_pycharm": "n"},
[ {"use_docker": "y"},
("y", "AWS"), {"use_docker": "n"},
("y", "GCP"), {"postgresql_version": "11.3"},
("y", "None"), {"postgresql_version": "10.8"},
("n", "AWS"), {"postgresql_version": "9.6"},
("n", "GCP"), {"postgresql_version": "9.5"},
# no whitenoise + no cloud provider is not supported {"postgresql_version": "9.4"},
], {"cloud_provider": "AWS", "use_whitenoise": "y"},
ids=lambda id: f"wnoise:{id[0]}-cloud:{id[1]}", {"cloud_provider": "AWS", "use_whitenoise": "n"},
) {"cloud_provider": "GCP", "use_whitenoise": "y"},
@pytest.mark.parametrize( {"cloud_provider": "GCP", "use_whitenoise": "n"},
"mail_service", {"cloud_provider": "None", "use_whitenoise": "y"},
[ # Note: cloud_provider=None AND use_whitenoise=n is not supported
"Amazon SES", {"use_drf": "y"},
"Mailgun", {"use_drf": "n"},
"MailJet", {"js_task_runner": "None"},
"Mandrill", {"js_task_runner": "Gulp"},
"Postmark", {"custom_bootstrap_compilation": "y"},
"Sendgrid", {"custom_bootstrap_compilation": "n"},
"SendinBlue", {"use_compressor": "y"},
"SparkPost", {"use_compressor": "n"},
"Plain/Vanilla Django-Anymail" {"use_celery": "y"},
# GCP or None (i.e. no cloud provider) + Amazon SES is not supported {"use_celery": "n"},
], {"use_mailhog": "y"},
ids=lambda id: f"mail:{id[0]}", {"use_mailhog": "n"},
) {"use_sentry": "y"},
def context_combination( {"use_sentry": "n"},
windows, {"use_whitenoise": "y"},
use_docker, {"use_whitenoise": "n"},
use_celery, {"use_heroku": "y"},
use_mailhog, {"use_heroku": "n"},
use_sentry, {"ci_tool": "None"},
use_compressor, {"ci_tool": "Travis"},
use_whitenoise, {"ci_tool": "Gitlab"},
use_drf, {"keep_local_envs_in_vcs": "y"},
cloud_provider, {"keep_local_envs_in_vcs": "n"},
mail_service, {"debug": "y"},
): {"debug": "n"},
"""Fixture that parametrize the function where it's used.""" {"mail_service", "AWS SES"},
return { {"mail_service", "Mailgun"},
"windows": windows, {"mail_service", "Mailjet"},
"use_docker": use_docker, {"mail_service", "Mandrill"},
"use_compressor": use_compressor, {"mail_service", "Postmark"},
"use_celery": use_celery, {"mail_service", "Sendgrid"},
"use_mailhog": use_mailhog, {"mail_service", "SendinBlue"},
"use_sentry": use_sentry, {"mail_service", "SparkPost"},
"use_whitenoise": use_whitenoise, {"mail_service", "Other SMTP"},
"use_drf": use_drf, ]
"cloud_provider": cloud_provider,
"mail_service": mail_service, UNSUPPORTED_COMBINATIONS = [
} {"cloud_provider": "None", "use_whitenoise": "n"},
{"cloud_provider": "GCP", "mail_service": "Amazon SES"},
{"cloud_provider": "None", "mail_service": "Amazon SES"}
]
def _fixture_id(ctx):
"""Helper to get a user friendly test name from the parametrized context."""
return "-".join(f"{key}:{value}" for key, value in ctx.items())
def build_files_list(root_dir): def build_files_list(root_dir):
@ -99,9 +106,7 @@ def build_files_list(root_dir):
def check_paths(paths): def check_paths(paths):
"""Method to check all paths have correct substitutions, """Method to check all paths have correct substitutions."""
used by other tests cases
"""
# Assert that no match is found in any of the files # Assert that no match is found in any of the files
for path in paths: for path in paths:
if is_binary(path): if is_binary(path):
@ -113,13 +118,10 @@ def check_paths(paths):
assert match is None, msg.format(path) assert match is None, msg.format(path)
def test_project_generation(cookies, context, context_combination): @pytest.mark.parametrize("context_override", SUPPORTED_COMBINATIONS, ids=_fixture_id)
""" def test_project_generation(cookies, context, context_override):
Test that project is generated and fully rendered. """Test that project is generated and fully rendered."""
result = cookies.bake(extra_context={**context, **context_override})
This is parametrized for each combination from ``context_combination`` fixture
"""
result = cookies.bake(extra_context={**context, **context_combination})
assert result.exit_code == 0 assert result.exit_code == 0
assert result.exception is None assert result.exception is None
assert result.project.basename == context["project_slug"] assert result.project.basename == context["project_slug"]
@ -130,34 +132,26 @@ def test_project_generation(cookies, context, context_combination):
check_paths(paths) check_paths(paths)
@pytest.mark.flake8 @pytest.mark.parametrize("context_override", SUPPORTED_COMBINATIONS, ids=_fixture_id)
def test_flake8_passes(cookies, context_combination): def test_flake8_passes(cookies, context_override):
""" """Generated project should pass flake8."""
Generated project should pass flake8. result = cookies.bake(extra_context=context_override)
This is parametrized for each combination from ``context_combination`` fixture
"""
result = cookies.bake(extra_context=context_combination)
try: try:
sh.flake8(str(result.project)) sh.flake8(str(result.project))
except sh.ErrorReturnCode as e: except sh.ErrorReturnCode as e:
pytest.fail(e) pytest.fail(e.stdout.decode())
@pytest.mark.black @pytest.mark.parametrize("context_override", SUPPORTED_COMBINATIONS, ids=_fixture_id)
def test_black_passes(cookies, context_combination): def test_black_passes(cookies, context_override):
""" """Generated project should pass black."""
Generated project should pass black. result = cookies.bake(extra_context=context_override)
This is parametrized for each combination from ``context_combination`` fixture
"""
result = cookies.bake(extra_context=context_combination)
try: try:
sh.black("--check", "--diff", "--exclude", "migrations", f"{result.project}/") sh.black("--check", "--diff", "--exclude", "migrations", f"{result.project}/")
except sh.ErrorReturnCode as e: except sh.ErrorReturnCode as e:
pytest.fail(e) pytest.fail(e.stdout.decode())
def test_travis_invokes_pytest(cookies, context): def test_travis_invokes_pytest(cookies, context):
@ -205,27 +199,10 @@ def test_invalid_slug(cookies, context, slug):
assert isinstance(result.exception, FailedHookException) assert isinstance(result.exception, FailedHookException)
def test_no_whitenoise_and_no_cloud_provider(cookies, context): @pytest.mark.parametrize("invalid_context", UNSUPPORTED_COMBINATIONS)
"""It should not generate project if neither whitenoise or cloud provider are set""" def test_error_if_incompatible(cookies, context, invalid_context):
context.update({"use_whitenoise": "n", "cloud_provider": "None"}) """It should not generate project an incompatible combination is selected."""
result = cookies.bake(extra_context=context) context.update(invalid_context)
assert result.exit_code != 0
assert isinstance(result.exception, FailedHookException)
def test_gcp_with_aws_ses_mail_service(cookies, context):
"""It should not generate project if SES is set with GCP cloud provider"""
context.update({"cloud_provider": "GCP", "mail_service": "Amazon SES"})
result = cookies.bake(extra_context=context)
assert result.exit_code != 0
assert isinstance(result.exception, FailedHookException)
def test_no_cloud_provider_with_aws_ses_mail_service(cookies, context):
"""It should not generate project if SES is set with no cloud provider"""
context.update({"cloud_provider": "None", "mail_service": "Amazon SES"})
result = cookies.bake(extra_context=context) result = cookies.bake(extra_context=context)
assert result.exit_code != 0 assert result.exit_code != 0

12
tox.ini
View File

@ -1,18 +1,10 @@
[tox] [tox]
skipsdist = true skipsdist = true
envlist = py37,flake8,black,black-template envlist = py37,black-template
[testenv] [testenv]
deps = -rrequirements.txt deps = -rrequirements.txt
commands = pytest -m "not flake8" -m "not black" {posargs:./tests} commands = pytest {posargs:./tests}
[testenv:flake8]
deps = -rrequirements.txt
commands = pytest -m flake8 {posargs:./tests}
[testenv:black]
deps = -rrequirements.txt
commands = pytest -m black {posargs:./tests}
[testenv:black-template] [testenv:black-template]
deps = black deps = black

View File

@ -13,8 +13,8 @@ indent_style = space
indent_size = 4 indent_size = 4
[*.py] [*.py]
line_length = 120 line_length = 88
known_first_party = {{ cookiecutter.project_slug }} known_first_party = {{cookiecutter.project_slug}},config
multi_line_output = 3 multi_line_output = 3
default_section = THIRDPARTY default_section = THIRDPARTY
recursive = true recursive = true

View File

@ -16,4 +16,5 @@ repos:
entry: flake8 entry: flake8
language: python language: python
types: [python] types: [python]
args: ['--config=setup.cfg']

View File

@ -2,4 +2,5 @@ release: python manage.py migrate
web: gunicorn config.wsgi:application web: gunicorn config.wsgi:application
{% if cookiecutter.use_celery == "y" -%} {% if cookiecutter.use_celery == "y" -%}
worker: celery worker --app=config.celery_app --loglevel=info worker: celery worker --app=config.celery_app --loglevel=info
beat: celery beat --app=config.celery_app --loglevel=info
{%- endif %} {%- endif %}

View File

@ -9,6 +9,11 @@ entryPoints:
web-secure: web-secure:
# https # https
address: ":443" address: ":443"
{%- if cookiecutter.use_celery == 'y' %}
flower:
address: ":5555"
{%- endif %}
certificatesResolvers: certificatesResolvers:
letsencrypt: letsencrypt:
@ -41,6 +46,17 @@ http:
tls: tls:
# https://docs.traefik.io/master/routing/routers/#certresolver # https://docs.traefik.io/master/routing/routers/#certresolver
certResolver: letsencrypt certResolver: letsencrypt
{%- if cookiecutter.use_celery == 'y' %}
flower-secure-router:
rule: "Host(`{{ cookiecutter.domain_name }}`)"
entryPoints:
- flower
service: flower
tls:
# https://docs.traefik.io/master/routing/routers/#certresolver
certResolver: letsencrypt
{%- endif %}
middlewares: middlewares:
redirect: redirect:
@ -52,13 +68,20 @@ http:
# https://docs.traefik.io/master/middlewares/headers/#hostsproxyheaders # https://docs.traefik.io/master/middlewares/headers/#hostsproxyheaders
# https://docs.djangoproject.com/en/dev/ref/csrf/#ajax # https://docs.djangoproject.com/en/dev/ref/csrf/#ajax
headers: headers:
hostsProxyHeaders: ['X-CSRFToken'] hostsProxyHeaders: ["X-CSRFToken"]
services: services:
django: django:
loadBalancer: loadBalancer:
servers: servers:
- url: http://django:5000 - url: http://django:5000
{%- if cookiecutter.use_celery == 'y' %}
flower:
loadBalancer:
servers:
- url: http://flower:5555
{%- endif %}
providers: providers:
# https://docs.traefik.io/master/providers/file/ # https://docs.traefik.io/master/providers/file/

View File

@ -1,5 +1,6 @@
from rest_framework.routers import DefaultRouter, SimpleRouter
from django.conf import settings from django.conf import settings
from rest_framework.routers import DefaultRouter, SimpleRouter
from {{ cookiecutter.project_slug }}.users.api.views import UserViewSet from {{ cookiecutter.project_slug }}.users.api.views import UserViewSet
if settings.DEBUG: if settings.DEBUG:

View File

@ -1,4 +1,5 @@
import os import os
from celery import Celery from celery import Celery
# set the default Django settings module for the 'celery' program. # set the default Django settings module for the 'celery' program.

View File

@ -1,3 +1,4 @@
"""isort:skip_file"""
{% if cookiecutter.use_sentry == 'y' -%} {% if cookiecutter.use_sentry == 'y' -%}
import logging import logging

View File

@ -1,10 +1,10 @@
from django.conf import settings from django.conf import settings
from django.urls import include, path
from django.conf.urls.static import static from django.conf.urls.static import static
from django.contrib import admin from django.contrib import admin
from django.views.generic import TemplateView from django.urls import include, path
from django.views import defaults as default_views from django.views import defaults as default_views
{% if cookiecutter.use_drf == 'y' -%} from django.views.generic import TemplateView
{%- if cookiecutter.use_drf == 'y' %}
from rest_framework.authtoken.views import obtain_auth_token from rest_framework.authtoken.views import obtain_auth_token
{%- endif %} {%- endif %}

View File

@ -42,6 +42,9 @@ services:
ports: ports:
- "0.0.0.0:80:80" - "0.0.0.0:80:80"
- "0.0.0.0:443:443" - "0.0.0.0:443:443"
{%- if cookiecutter.use_celery == 'y' %}
- "0.0.0.0:5555:5555"
{%- endif %}
redis: redis:
image: redis:5.0 image: redis:5.0
@ -60,8 +63,6 @@ services:
flower: flower:
<<: *django <<: *django
image: {{ cookiecutter.project_slug }}_production_flower image: {{ cookiecutter.project_slug }}_production_flower
ports:
- "5555:5555"
command: /start-flower command: /start-flower
{%- endif %} {%- endif %}

View File

@ -10,8 +10,8 @@ whitenoise==5.0.1 # https://github.com/evansd/whitenoise
{%- endif %} {%- endif %}
redis==3.4.1 # https://github.com/andymccurdy/redis-py redis==3.4.1 # https://github.com/andymccurdy/redis-py
{%- if cookiecutter.use_celery == "y" %} {%- if cookiecutter.use_celery == "y" %}
celery==4.4.0 # pyup: < 5.0 # https://github.com/celery/celery celery==4.4.1 # pyup: < 5.0 # https://github.com/celery/celery
django-celery-beat==1.6.0 # https://github.com/celery/django-celery-beat django-celery-beat==2.0.0 # https://github.com/celery/django-celery-beat
{%- if cookiecutter.use_docker == 'y' %} {%- if cookiecutter.use_docker == 'y' %}
flower==0.9.3 # https://github.com/mher/flower flower==0.9.3 # https://github.com/mher/flower
{%- endif %} {%- endif %}
@ -19,11 +19,11 @@ flower==0.9.3 # https://github.com/mher/flower
# Django # Django
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
django==2.2.10 # pyup: < 3.0 # https://www.djangoproject.com/ django==2.2.11 # pyup: < 3.0 # https://www.djangoproject.com/
django-environ==0.4.5 # https://github.com/joke2k/django-environ django-environ==0.4.5 # https://github.com/joke2k/django-environ
django-model-utils==4.0.0 # https://github.com/jazzband/django-model-utils django-model-utils==4.0.0 # https://github.com/jazzband/django-model-utils
django-allauth==0.41.0 # https://github.com/pennersr/django-allauth django-allauth==0.41.0 # https://github.com/pennersr/django-allauth
django-crispy-forms==1.8.1 # https://github.com/django-crispy-forms/django-crispy-forms django-crispy-forms==1.9.0 # https://github.com/django-crispy-forms/django-crispy-forms
{%- if cookiecutter.use_compressor == "y" %} {%- if cookiecutter.use_compressor == "y" %}
django-compressor==2.4 # https://github.com/django-compressor/django-compressor django-compressor==2.4 # https://github.com/django-compressor/django-compressor
{%- endif %} {%- endif %}
@ -31,4 +31,3 @@ django-redis==4.11.0 # https://github.com/niwinz/django-redis
# Django REST Framework # Django REST Framework
djangorestframework==3.11.0 # https://github.com/encode/django-rest-framework djangorestframework==3.11.0 # https://github.com/encode/django-rest-framework
coreapi==2.3.3 # https://github.com/core-api/python-client

View File

@ -1,8 +1,8 @@
-r ./base.txt -r ./base.txt
Werkzeug==0.16.1 # https://github.com/pallets/werkzeug Werkzeug==1.0.0 # https://github.com/pallets/werkzeug
ipdb==0.12.3 # https://github.com/gotcha/ipdb ipdb==0.13.2 # https://github.com/gotcha/ipdb
Sphinx==2.3.1 # https://github.com/sphinx-doc/sphinx Sphinx==2.4.4 # https://github.com/sphinx-doc/sphinx
{%- if cookiecutter.use_docker == 'y' %} {%- if cookiecutter.use_docker == 'y' %}
psycopg2==2.8.4 --no-binary psycopg2 # https://github.com/psycopg/psycopg2 psycopg2==2.8.4 --no-binary psycopg2 # https://github.com/psycopg/psycopg2
{%- else %} {%- else %}
@ -11,7 +11,7 @@ psycopg2-binary==2.8.4 # https://github.com/psycopg/psycopg2
# Testing # Testing
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
mypy==0.761 # https://github.com/python/mypy mypy==0.770 # https://github.com/python/mypy
django-stubs==1.4.0 # https://github.com/typeddjango/django-stubs django-stubs==1.4.0 # https://github.com/typeddjango/django-stubs
pytest==5.3.5 # https://github.com/pytest-dev/pytest pytest==5.3.5 # https://github.com/pytest-dev/pytest
pytest-sugar==0.9.2 # https://github.com/Frozenball/pytest-sugar pytest-sugar==0.9.2 # https://github.com/Frozenball/pytest-sugar
@ -19,19 +19,20 @@ pytest-sugar==0.9.2 # https://github.com/Frozenball/pytest-sugar
# Code quality # Code quality
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
flake8==3.7.9 # https://github.com/PyCQA/flake8 flake8==3.7.9 # https://github.com/PyCQA/flake8
flake8-isort==2.8.0 # https://github.com/gforcada/flake8-isort
coverage==5.0.3 # https://github.com/nedbat/coveragepy coverage==5.0.3 # https://github.com/nedbat/coveragepy
black==19.10b0 # https://github.com/ambv/black black==19.10b0 # https://github.com/ambv/black
pylint-django==2.0.13 # https://github.com/PyCQA/pylint-django pylint-django==2.0.14 # https://github.com/PyCQA/pylint-django
{%- if cookiecutter.use_celery == 'y' %} {%- if cookiecutter.use_celery == 'y' %}
pylint-celery==0.3 # https://github.com/PyCQA/pylint-celery pylint-celery==0.3 # https://github.com/PyCQA/pylint-celery
{%- endif %} {%- endif %}
pre-commit==2.0.1 # https://github.com/pre-commit/pre-commit pre-commit==2.2.0 # https://github.com/pre-commit/pre-commit
# Django # Django
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
factory-boy==2.12.0 # https://github.com/FactoryBoy/factory_boy factory-boy==2.12.0 # https://github.com/FactoryBoy/factory_boy
django-debug-toolbar==2.2 # https://github.com/jazzband/django-debug-toolbar django-debug-toolbar==2.2 # https://github.com/jazzband/django-debug-toolbar
django-extensions==2.2.6 # https://github.com/django-extensions/django-extensions django-extensions==2.2.8 # https://github.com/django-extensions/django-extensions
django-coverage-plugin==1.8.0 # https://github.com/nedbat/django_coverage_plugin django-coverage-plugin==1.8.0 # https://github.com/nedbat/django_coverage_plugin
pytest-django==3.8.0 # https://github.com/pytest-dev/pytest-django pytest-django==3.8.0 # https://github.com/pytest-dev/pytest-django

View File

@ -5,10 +5,10 @@
gunicorn==20.0.4 # https://github.com/benoitc/gunicorn gunicorn==20.0.4 # https://github.com/benoitc/gunicorn
psycopg2==2.8.4 --no-binary psycopg2 # https://github.com/psycopg/psycopg2 psycopg2==2.8.4 --no-binary psycopg2 # https://github.com/psycopg/psycopg2
{%- if cookiecutter.use_whitenoise == 'n' %} {%- if cookiecutter.use_whitenoise == 'n' %}
Collectfast==1.3.1 # https://github.com/antonagestam/collectfast Collectfast==2.1.0 # https://github.com/antonagestam/collectfast
{%- endif %} {%- endif %}
{%- if cookiecutter.use_sentry == "y" %} {%- if cookiecutter.use_sentry == "y" %}
sentry-sdk==0.14.1 # https://github.com/getsentry/sentry-python sentry-sdk==0.14.2 # https://github.com/getsentry/sentry-python
{%- endif %} {%- endif %}
# Django # Django

View File

@ -1,4 +1,5 @@
from rest_framework import serializers from rest_framework import serializers
from {{ cookiecutter.project_slug }}.users.models import User from {{ cookiecutter.project_slug }}.users.models import User

View File

@ -1,7 +1,7 @@
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from rest_framework import status from rest_framework import status
from rest_framework.decorators import action from rest_framework.decorators import action
from rest_framework.mixins import RetrieveModelMixin, ListModelMixin, UpdateModelMixin from rest_framework.mixins import ListModelMixin, RetrieveModelMixin, UpdateModelMixin
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.viewsets import GenericViewSet from rest_framework.viewsets import GenericViewSet

View File

@ -1,4 +1,4 @@
from django.contrib.auth import get_user_model, forms from django.contrib.auth import forms, get_user_model
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _

View File

@ -1,7 +1,6 @@
import pytest import pytest
from celery.result import EagerResult from celery.result import EagerResult
from {{ cookiecutter.project_slug }}.users.tasks import get_users_count from {{ cookiecutter.project_slug }}.users.tasks import get_users_count
from {{ cookiecutter.project_slug }}.users.tests.factories import UserFactory from {{ cookiecutter.project_slug }}.users.tests.factories import UserFactory

View File

@ -1,5 +1,5 @@
import pytest import pytest
from django.urls import reverse, resolve from django.urls import resolve, reverse
from {{ cookiecutter.project_slug }}.users.models import User from {{ cookiecutter.project_slug }}.users.models import User

View File

@ -1,9 +1,9 @@
from django.urls import path from django.urls import path
from {{ cookiecutter.project_slug }}.users.views import ( from {{ cookiecutter.project_slug }}.users.views import (
user_detail_view,
user_redirect_view, user_redirect_view,
user_update_view, user_update_view,
user_detail_view,
) )
app_name = "users" app_name = "users"

View File

@ -1,9 +1,9 @@
from django.contrib import messages
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
from django.urls import reverse from django.urls import reverse
from django.views.generic import DetailView, RedirectView, UpdateView
from django.contrib import messages
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.views.generic import DetailView, RedirectView, UpdateView
User = get_user_model() User = get_user_model()