diff --git a/.travis.yml b/.travis.yml index c2bcdf42..925d82e7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ services: language: python -python: 3.6 +python: 3.7 before_install: - docker-compose -v @@ -14,7 +14,7 @@ before_install: matrix: include: - name: Test results - script: tox -e py36 + script: tox -e py37 - name: Run flake8 on result script: tox -e flake8 - name: Run black on result diff --git a/CHANGELOG.md b/CHANGELOG.md index 5df2d3a3..2e7d9220 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,18 @@ All enhancements and patches to Cookiecutter Django will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +## [2019-10-06] +### Changed +- Default Python version is now 3.7 (@nicolas471) + +## [2019-10-04] +### Fixed +- Fix static files handling on GCP (@caioariede) + +## [2019-10-03] +### Fixed +- Fix incompatible combination between Whitenoise and no cloud provider (@caioariede) + ## [2019-07-09] ### Fixed - Always use test settings in pytest (@danihodovic) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index cfe16740..cb59ae5f 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -39,9 +39,9 @@ To run all tests using various versions of python in virtualenvs defined in tox. It is possible to test with a specific version of python. To do this, the command is:: - $ tox -e py36 + $ tox -e py37 -This will run py.test with the python3.6 interpreter, for example. +This will run py.test with the python3.7 interpreter, for example. To run a particular test with tox for against your current Python version:: diff --git a/CONTRIBUTORS.rst b/CONTRIBUTORS.rst index 4c3ad8a0..3a3930b2 100644 --- a/CONTRIBUTORS.rst +++ b/CONTRIBUTORS.rst @@ -74,6 +74,7 @@ Listed in alphabetical order. Bouke Haarsma Brent Payne `@brentpayne`_ @brentpayne Burhan Khalid            `@burhan`_                   @burhan + Caio Ariede `@caioariede`_ @caioariede Carl Johnson `@carlmjohnson`_ @carlmjohnson Catherine Devlin `@catherinedevlin`_ Cédric Gaspoz `@cgaspoz`_ @@ -158,6 +159,7 @@ Listed in alphabetical order. Michael Gecht `@mimischi`_ @_mischi Min ho Kim `@minho42`_ mozillazg `@mozillazg`_ + Nico Stefani `@nicolas471`_ @moby_dick91 Oleg Russkin `@rolep`_ Pablo `@oubiga`_ Parbhat Puri `@parbhat`_ @@ -229,6 +231,7 @@ Listed in alphabetical order. .. _@c-rhodes: https://github.com/c-rhodes .. _@caffodian: https://github.com/caffodian .. _@canonnervio: https://github.com/canonnervio +.. _@caioariede: https://github.com/caioariede .. _@carlmjohnson: https://github.com/carlmjohnson .. _@catherinedevlin: https://github.com/catherinedevlin .. _@ccurvey: https://github.com/ccurvey @@ -301,6 +304,7 @@ Listed in alphabetical order. .. _@mrcoles: https://github.com/mrcoles .. _@msaizar: https://github.com/msaizar .. _@myilmaz: https://github.com/myilmaz +.. _@nicolas471: https://github.com/nicolas471 .. _@noisy: https://github.com/noisy .. _@originell: https://github.com/originell .. _@oubiga: https://github.com/oubiga diff --git a/README.rst b/README.rst index 30a3a2db..e4f47351 100644 --- a/README.rst +++ b/README.rst @@ -37,7 +37,7 @@ Features --------- * For Django 2.2 -* Works with Python 3.6 +* Works with Python 3.7 * Renders Django projects with 100% starting test coverage * Twitter Bootstrap_ v4 (`maintained Foundation fork`_ also available) * 12-Factor_ based settings via django-environ_ diff --git a/docs/deployment-on-pythonanywhere.rst b/docs/deployment-on-pythonanywhere.rst index 83b23b27..4738d5a5 100644 --- a/docs/deployment-on-pythonanywhere.rst +++ b/docs/deployment-on-pythonanywhere.rst @@ -35,7 +35,7 @@ Make sure your project is fully committed and pushed up to Bitbucket or Github o git clone # you can also use hg cd my-project-name - mkvirtualenv --python=/usr/bin/python3.6 my-project-name + mkvirtualenv --python=/usr/bin/python3.7 my-project-name pip install -r requirements/production.txt # may take a few minutes diff --git a/docs/developing-locally.rst b/docs/developing-locally.rst index 8694dde7..fdab5a90 100644 --- a/docs/developing-locally.rst +++ b/docs/developing-locally.rst @@ -9,7 +9,7 @@ Setting Up Development Environment Make sure to have the following on your host: -* Python 3.6 +* Python 3.7 * PostgreSQL_. * Redis_, if using Celery @@ -17,7 +17,7 @@ First things first. #. Create a virtualenv: :: - $ python3.6 -m venv + $ python3.7 -m venv #. Activate the virtualenv you have just created: :: diff --git a/hooks/pre_gen_project.py b/hooks/pre_gen_project.py index 7f9bd3ea..668a6e27 100644 --- a/hooks/pre_gen_project.py +++ b/hooks/pre_gen_project.py @@ -35,7 +35,7 @@ if "{{ cookiecutter.use_docker }}".lower() == "n": if python_major_version == 2: print( WARNING + "You're running cookiecutter under Python 2, but the generated " - "project requires Python 3.6+. Do you want to proceed (y/n)? " + TERMINATOR + "project requires Python 3.7+. Do you want to proceed (y/n)? " + TERMINATOR ) yes_options, no_options = frozenset(["y"]), frozenset(["n"]) while True: diff --git a/requirements.txt b/requirements.txt index e9d2afb2..efc3d117 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,7 +10,7 @@ flake8==3.7.8 # Testing # ------------------------------------------------------------------------------ tox==3.14.0 -pytest==5.2.0 +pytest==5.2.1 pytest_cases==1.11.3 pytest-cookies==0.4.0 pytest-xdist==1.30.0 diff --git a/setup.py b/setup.py index 46c84b71..33032009 100644 --- a/setup.py +++ b/setup.py @@ -40,7 +40,7 @@ setup( "License :: OSI Approved :: BSD License", "Programming Language :: Python", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", "Programming Language :: Python :: Implementation :: CPython", "Topic :: Software Development", ], diff --git a/tests/test_cookiecutter_generation.py b/tests/test_cookiecutter_generation.py index 20e4f9ed..f931bce0 100755 --- a/tests/test_cookiecutter_generation.py +++ b/tests/test_cookiecutter_generation.py @@ -11,9 +11,6 @@ from binaryornot.check import is_binary PATTERN = r"{{(\s?cookiecutter)[.](.*?)}}" RE_OBJ = re.compile(PATTERN) -YN_CHOICES = ["y", "n"] -CLOUD_CHOICES = ["AWS", "GCE", "None"] - @pytest.fixture def context(): @@ -30,14 +27,24 @@ def context(): @pytest_fixture_plus -@pytest.mark.parametrize("windows", YN_CHOICES, ids=lambda yn: f"win:{yn}") -@pytest.mark.parametrize("use_docker", YN_CHOICES, ids=lambda yn: f"docker:{yn}") -@pytest.mark.parametrize("use_celery", YN_CHOICES, ids=lambda yn: f"celery:{yn}") -@pytest.mark.parametrize("use_mailhog", YN_CHOICES, ids=lambda yn: f"mailhog:{yn}") -@pytest.mark.parametrize("use_sentry", YN_CHOICES, ids=lambda yn: f"sentry:{yn}") -@pytest.mark.parametrize("use_compressor", YN_CHOICES, ids=lambda yn: f"cmpr:{yn}") -@pytest.mark.parametrize("use_whitenoise", YN_CHOICES, ids=lambda yn: f"wnoise:{yn}") -@pytest.mark.parametrize("cloud_provider", CLOUD_CHOICES, ids=lambda yn: f"cloud:{yn}") +@pytest.mark.parametrize("windows", ["y", "n"], ids=lambda yn: f"win:{yn}") +@pytest.mark.parametrize("use_docker", ["y", "n"], ids=lambda yn: f"docker:{yn}") +@pytest.mark.parametrize("use_celery", ["y", "n"], ids=lambda yn: f"celery:{yn}") +@pytest.mark.parametrize("use_mailhog", ["y", "n"], ids=lambda yn: f"mailhog:{yn}") +@pytest.mark.parametrize("use_sentry", ["y", "n"], ids=lambda yn: f"sentry:{yn}") +@pytest.mark.parametrize("use_compressor", ["y", "n"], ids=lambda yn: f"cmpr:{yn}") +@pytest.mark.parametrize( + "use_whitenoise,cloud_provider", + [ + ("y", "AWS"), + ("y", "GCP"), + ("y", "None"), + ("n", "AWS"), + ("n", "GCP"), + # no whitenoise + co cloud provider is not supported + ], + ids=lambda id: f"wnoise:{id[0]}-cloud:{id[1]}", +) def context_combination( windows, use_docker, @@ -49,11 +56,6 @@ def context_combination( cloud_provider, ): """Fixture that parametrize the function where it's used.""" - if cloud_provider == "None": - # Either of the two should be set for serving static files, so if cloud provider - # is not set, we force Whitenoise to be set - use_whitenoise = "y" - return { "windows": windows, "use_docker": use_docker, diff --git a/tox.ini b/tox.ini index 7ee93915..1c83465c 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] skipsdist = true -envlist = py36,flake8,black,black-template +envlist = py37,flake8,black,black-template [testenv] deps = -rrequirements.txt diff --git a/{{cookiecutter.project_slug}}/.travis.yml b/{{cookiecutter.project_slug}}/.travis.yml index 2d86ac31..31695e41 100644 --- a/{{cookiecutter.project_slug}}/.travis.yml +++ b/{{cookiecutter.project_slug}}/.travis.yml @@ -10,7 +10,7 @@ before_install: - sudo apt-get install -qq libsqlite3-dev libxml2 libxml2-dev libssl-dev libbz2-dev wget curl llvm language: python python: - - "3.6" + - "3.7" install: - pip install -r requirements/local.txt script: diff --git a/{{cookiecutter.project_slug}}/compose/local/django/Dockerfile b/{{cookiecutter.project_slug}}/compose/local/django/Dockerfile index 67937822..a98547bd 100644 --- a/{{cookiecutter.project_slug}}/compose/local/django/Dockerfile +++ b/{{cookiecutter.project_slug}}/compose/local/django/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.6-alpine +FROM python:3.7-alpine ENV PYTHONUNBUFFERED 1 diff --git a/{{cookiecutter.project_slug}}/compose/production/django/Dockerfile b/{{cookiecutter.project_slug}}/compose/production/django/Dockerfile index 37f66ec7..b0861d60 100644 --- a/{{cookiecutter.project_slug}}/compose/production/django/Dockerfile +++ b/{{cookiecutter.project_slug}}/compose/production/django/Dockerfile @@ -9,7 +9,7 @@ RUN npm run build # Python build stage {%- endif %} -FROM python:3.6-alpine +FROM python:3.7-alpine ENV PYTHONUNBUFFERED 1 diff --git a/{{cookiecutter.project_slug}}/config/settings/production.py b/{{cookiecutter.project_slug}}/config/settings/production.py index e3741165..7a5d5454 100644 --- a/{{cookiecutter.project_slug}}/config/settings/production.py +++ b/{{cookiecutter.project_slug}}/config/settings/production.py @@ -92,7 +92,6 @@ AWS_DEFAULT_ACL = None # https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#settings AWS_S3_REGION_NAME = env("DJANGO_AWS_S3_REGION_NAME", default=None) {% elif cookiecutter.cloud_provider == 'GCP' %} -DEFAULT_FILE_STORAGE = "storages.backends.gcloud.GoogleCloudStorage" GS_BUCKET_NAME = env("DJANGO_GCP_STORAGE_BUCKET_NAME") GS_DEFAULT_ACL = "publicRead" {% endif -%} @@ -107,6 +106,7 @@ STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage" STATICFILES_STORAGE = "config.settings.production.StaticRootS3Boto3Storage" STATIC_URL = f"https://{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com/static/" {% elif cookiecutter.cloud_provider == 'GCP' -%} +STATICFILES_STORAGE = "config.settings.production.StaticRootGoogleCloudStorage" STATIC_URL = f"https://storage.googleapis.com/{GS_BUCKET_NAME}/static/" {% endif -%} @@ -132,8 +132,21 @@ class MediaRootS3Boto3Storage(S3Boto3Storage): DEFAULT_FILE_STORAGE = "config.settings.production.MediaRootS3Boto3Storage" MEDIA_URL = f"https://{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com/media/" {%- elif cookiecutter.cloud_provider == 'GCP' %} +from storages.backends.gcloud import GoogleCloudStorage # noqa E402 + + +class StaticRootGoogleCloudStorage(GoogleCloudStorage): + location = "static" + default_acl = "publicRead" + + +class MediaRootGoogleCloudStorage(GoogleCloudStorage): + location = "media" + file_overwrite = False + + +DEFAULT_FILE_STORAGE = "config.settings.production.MediaRootGoogleCloudStorage" MEDIA_URL = f"https://storage.googleapis.com/{GS_BUCKET_NAME}/media/" -MEDIA_ROOT = f"https://storage.googleapis.com/{GS_BUCKET_NAME}/media/" {%- endif %} # TEMPLATES diff --git a/{{cookiecutter.project_slug}}/requirements/base.txt b/{{cookiecutter.project_slug}}/requirements/base.txt index d0bce155..01791e8c 100644 --- a/{{cookiecutter.project_slug}}/requirements/base.txt +++ b/{{cookiecutter.project_slug}}/requirements/base.txt @@ -1,4 +1,4 @@ -pytz==2019.2 # https://github.com/stub42/pytz +pytz==2019.3 # https://github.com/stub42/pytz python-slugify==3.0.4 # https://github.com/un33k/python-slugify Pillow==6.2.0 # https://github.com/python-pillow/Pillow {%- if cookiecutter.use_compressor == "y" %} diff --git a/{{cookiecutter.project_slug}}/requirements/local.txt b/{{cookiecutter.project_slug}}/requirements/local.txt index 41813c47..daa4870c 100644 --- a/{{cookiecutter.project_slug}}/requirements/local.txt +++ b/{{cookiecutter.project_slug}}/requirements/local.txt @@ -12,7 +12,7 @@ psycopg2-binary==2.8.3 # https://github.com/psycopg/psycopg2 # Testing # ------------------------------------------------------------------------------ mypy==0.730 # https://github.com/python/mypy -pytest==5.2.0 # https://github.com/pytest-dev/pytest +pytest==5.2.1 # https://github.com/pytest-dev/pytest pytest-sugar==0.9.2 # https://github.com/Frozenball/pytest-sugar # Code quality diff --git a/{{cookiecutter.project_slug}}/requirements/production.txt b/{{cookiecutter.project_slug}}/requirements/production.txt index 46c1a89e..e59644ff 100644 --- a/{{cookiecutter.project_slug}}/requirements/production.txt +++ b/{{cookiecutter.project_slug}}/requirements/production.txt @@ -5,7 +5,7 @@ gunicorn==19.9.0 # https://github.com/benoitc/gunicorn psycopg2==2.8.3 --no-binary psycopg2 # https://github.com/psycopg/psycopg2 {%- if cookiecutter.use_whitenoise == 'n' %} -Collectfast==1.0.0 # https://github.com/antonagestam/collectfast +Collectfast==1.2.0 # https://github.com/antonagestam/collectfast {%- endif %} {%- if cookiecutter.use_sentry == "y" %} sentry-sdk==0.12.3 # https://github.com/getsentry/sentry-python diff --git a/{{cookiecutter.project_slug}}/runtime.txt b/{{cookiecutter.project_slug}}/runtime.txt index 9fbd3bf0..42731f2f 100644 --- a/{{cookiecutter.project_slug}}/runtime.txt +++ b/{{cookiecutter.project_slug}}/runtime.txt @@ -1 +1 @@ -python-3.6.8 +python-3.7.4 diff --git a/{{cookiecutter.project_slug}}/setup.cfg b/{{cookiecutter.project_slug}}/setup.cfg index c2139f1d..42b63861 100644 --- a/{{cookiecutter.project_slug}}/setup.cfg +++ b/{{cookiecutter.project_slug}}/setup.cfg @@ -7,7 +7,7 @@ max-line-length = 120 exclude = .tox,.git,*/migrations/*,*/static/CACHE/*,docs,node_modules [mypy] -python_version = 3.6 +python_version = 3.7 check_untyped_defs = True ignore_errors = False ignore_missing_imports = True