Kaydet (Commit) abc0777b authored tarafından Chris Lamb's avatar Chris Lamb Kaydeden (comit) Tim Graham

Fixed #25968 -- Changed project/app templates to use a "py-tpl" suffix.

Debian packages unconditionally byte-compile .py files on installation and
do not silence errors by design. Therefore, we need a way of shipping these
invalid .py files without a .py extension but ensuring that when we
template them, they end up as .py.

We don't special-case .py files so that the all the TemplateCommand
command-line options (eg. extra_files and extensions) still work entirely
as expected and it may even be useful for other formats too.
üst 9c43d825
...@@ -42,6 +42,11 @@ class TemplateCommand(BaseCommand): ...@@ -42,6 +42,11 @@ class TemplateCommand(BaseCommand):
# Can't perform any active locale changes during this command, because # Can't perform any active locale changes during this command, because
# setting might not be available at all. # setting might not be available at all.
leave_locale_alone = True leave_locale_alone = True
# Rewrite the following suffixes when determining the target filename.
rewrite_template_suffixes = (
# Allow shipping invalid .py files without byte-compilation.
('.py-tpl', '.py'),
)
def add_arguments(self, parser): def add_arguments(self, parser):
parser.add_argument('name', help='Name of the application or project.') parser.add_argument('name', help='Name of the application or project.')
...@@ -139,6 +144,11 @@ class TemplateCommand(BaseCommand): ...@@ -139,6 +144,11 @@ class TemplateCommand(BaseCommand):
old_path = path.join(root, filename) old_path = path.join(root, filename)
new_path = path.join(top_dir, relative_dir, new_path = path.join(top_dir, relative_dir,
filename.replace(base_name, name)) filename.replace(base_name, name))
for old_suffix, new_suffix in self.rewrite_template_suffixes:
if new_path.endswith(old_suffix):
new_path = new_path[:-len(old_suffix)] + new_suffix
break # Only rewrite once
if path.exists(new_path): if path.exists(new_path):
raise CommandError("%s already exists, overlaying a " raise CommandError("%s already exists, overlaying a "
"project or app into an existing " "project or app into an existing "
...@@ -149,7 +159,7 @@ class TemplateCommand(BaseCommand): ...@@ -149,7 +159,7 @@ class TemplateCommand(BaseCommand):
# accidentally render Django templates files # accidentally render Django templates files
with open(old_path, 'rb') as template_file: with open(old_path, 'rb') as template_file:
content = template_file.read() content = template_file.read()
if filename.endswith(extensions) or filename in extra_files: if new_path.endswith(extensions) or filename in extra_files:
content = content.decode('utf-8') content = content.decode('utf-8')
template = Engine().from_string(content) template = Engine().from_string(content)
content = template.render(context) content = template.render(context)
......
...@@ -1175,6 +1175,15 @@ files is: ...@@ -1175,6 +1175,15 @@ files is:
To work around this problem, you can use the :ttag:`templatetag` To work around this problem, you can use the :ttag:`templatetag`
templatetag to "escape" the various parts of the template syntax. templatetag to "escape" the various parts of the template syntax.
In addition, to allow Python template files that contain Django template
language syntax while also preventing packaging systems from trying to
byte-compile invalid ``*.py`` files, template files ending with ``.py-tpl``
will be renamed to ``.py``.
.. versionchanged:: 1.9.2
Renaming of ``.py-tpl`` to ``.py`` was added.
.. _source: https://github.com/django/django/tree/master/django/conf/app_template/ .. _source: https://github.com/django/django/tree/master/django/conf/app_template/
startproject startproject
......
...@@ -4,7 +4,24 @@ Django 1.9.2 release notes ...@@ -4,7 +4,24 @@ Django 1.9.2 release notes
*Under development* *Under development*
Django 1.9.2 fixes several bugs in 1.9.1. Django 1.9.2 fixes several bugs in 1.9.1 and makes a small backwards
incompatible change that hopefully doesn't affect any users.
Backwards incompatible change: ``.py-tpl`` files rewritten in project/app templates
===================================================================================
The addition of some Django template language syntax to the default app
template in Django 1.9 means those files now have some invalid Python syntax.
This causes difficulties for packaging systems that unconditionally
byte-compile ``*.py`` files.
To remedy this, a ``.py-tpl`` suffix is now used for the project and app
template files included in Django. The ``.py-tpl`` suffix is replaced with
``.py`` by the ``startproject`` and ``startapp`` commands. For example, a
template with the filename ``manage.py-tpl`` will be created as ``manage.py``.
Please file a ticket if you have a custom project template containing
``.py-tpl`` files and find this behavior problematic.
Bugfixes Bugfixes
======== ========
......
...@@ -1017,7 +1017,7 @@ a Django application with this structure:: ...@@ -1017,7 +1017,7 @@ a Django application with this structure::
``SyntaxError`` when installing Django setuptools 5.5.x ``SyntaxError`` when installing Django setuptools 5.5.x
------------------------------------------------------- -------------------------------------------------------
When installing Django 1.9+ with setuptools 5.5.x, you'll see:: When installing Django 1.9 or 1.9.1 with setuptools 5.5.x, you'll see::
Compiling django/conf/app_template/apps.py ... Compiling django/conf/app_template/apps.py ...
File "django/conf/app_template/apps.py", line 4 File "django/conf/app_template/apps.py", line 4
...@@ -1034,7 +1034,8 @@ When installing Django 1.9+ with setuptools 5.5.x, you'll see:: ...@@ -1034,7 +1034,8 @@ When installing Django 1.9+ with setuptools 5.5.x, you'll see::
It's safe to ignore these errors (Django will still install just fine), but you It's safe to ignore these errors (Django will still install just fine), but you
can avoid them by upgrading setuptools to a more recent version. If you're can avoid them by upgrading setuptools to a more recent version. If you're
using pip, you can upgrade pip using ``pip install -U pip`` which will also using pip, you can upgrade pip using ``pip install -U pip`` which will also
upgrade setuptools. upgrade setuptools. This is resolved in later versions of Django as described
in the :doc:`/releases/1.9.2`.
Miscellaneous Miscellaneous
------------- -------------
......
...@@ -165,8 +165,7 @@ This is the recommended way to install Django. ...@@ -165,8 +165,7 @@ This is the recommended way to install Django.
1. Install pip_. The easiest is to use the `standalone pip installer`_. If your 1. Install pip_. The easiest is to use the `standalone pip installer`_. If your
distribution already has ``pip`` installed, you might need to update it if distribution already has ``pip`` installed, you might need to update it if
it's outdated. If it's outdated, you'll know because installation won't it's outdated. If it's outdated, you'll know because installation won't
work. If you're using an old version of setuptools, you might see some work.
:ref:`harmless SyntaxErrors <syntax-error-old-setuptools-django-19>` also.
2. Take a look at virtualenv_ and virtualenvwrapper_. These tools provide 2. Take a look at virtualenv_ and virtualenvwrapper_. These tools provide
isolated Python environments, which are more practical than installing isolated Python environments, which are more practical than installing
......
...@@ -181,7 +181,7 @@ class AdminScriptTestCase(unittest.TestCase): ...@@ -181,7 +181,7 @@ class AdminScriptTestCase(unittest.TestCase):
pass pass
conf_dir = os.path.dirname(upath(conf.__file__)) conf_dir = os.path.dirname(upath(conf.__file__))
template_manage_py = os.path.join(conf_dir, 'project_template', 'manage.py') template_manage_py = os.path.join(conf_dir, 'project_template', 'manage.py-tpl')
test_manage_py = os.path.join(self.test_dir, 'manage.py') test_manage_py = os.path.join(self.test_dir, 'manage.py')
shutil.copyfile(template_manage_py, test_manage_py) shutil.copyfile(template_manage_py, test_manage_py)
......
import os
import shutil
import unittest import unittest
from django import conf
from django.test import TestCase from django.test import TestCase
from django.utils import six from django.utils import six
from django.utils._os import upath
@unittest.skipIf(six.PY2, @unittest.skipIf(six.PY2,
'Python 2 cannot import the project template because ' 'Python 2 cannot import the project template because '
'django/conf/project_template doesn\'t have an __init__.py file.') 'django/conf/project_template doesn\'t have an __init__.py file.')
class TestStartProjectSettings(TestCase): class TestStartProjectSettings(TestCase):
def setUp(self):
# Ensure settings.py exists
project_dir = os.path.join(
os.path.dirname(upath(conf.__file__)),
'project_template',
'project_name',
)
template_settings_py = os.path.join(project_dir, 'settings.py-tpl')
test_settings_py = os.path.join(project_dir, 'settings.py')
shutil.copyfile(template_settings_py, test_settings_py)
self.addCleanup(os.remove, test_settings_py)
def test_middleware_classes_headers(self): def test_middleware_classes_headers(self):
""" """
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment