From fc9566d42daf28cdaa25a5db1b5ade253ceb064f Mon Sep 17 00:00:00 2001 From: oliver Date: Thu, 25 Apr 2019 11:28:31 +0900 Subject: [PATCH] Fixed #30393 -- Added validation of startapp's directory option. --- django/core/management/templates.py | 14 +++++++++----- tests/admin_scripts/tests.py | 19 +++++++++++++++++++ 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/django/core/management/templates.py b/django/core/management/templates.py index 0e9adfeb09..c7252a5ad2 100644 --- a/django/core/management/templates.py +++ b/django/core/management/templates.py @@ -74,6 +74,8 @@ class TemplateCommand(BaseCommand): except OSError as e: raise CommandError(e) else: + if app_or_project == 'app': + self.validate_name(os.path.basename(target), 'directory') top_dir = os.path.abspath(path.expanduser(target)) if not os.path.exists(top_dir): raise CommandError("Destination directory '%s' does not " @@ -205,7 +207,7 @@ class TemplateCommand(BaseCommand): raise CommandError("couldn't handle %s template %s." % (self.app_or_project, template)) - def validate_name(self, name): + def validate_name(self, name, name_or_dir='name'): if name is None: raise CommandError('you must provide {an} {app} name'.format( an=self.a_or_an, @@ -214,10 +216,11 @@ class TemplateCommand(BaseCommand): # Check it's a valid directory name. if not name.isidentifier(): raise CommandError( - "'{name}' is not a valid {app} name. Please make sure the " - "name is a valid identifier.".format( + "'{name}' is not a valid {app} {type}. Please make sure the " + "{type} is a valid identifier.".format( name=name, app=self.app_or_project, + type=name_or_dir, ) ) # Check it cannot be imported. @@ -228,11 +231,12 @@ class TemplateCommand(BaseCommand): else: raise CommandError( "'{name}' conflicts with the name of an existing Python " - "module and cannot be used as {an} {app} name. Please try " - "another name.".format( + "module and cannot be used as {an} {app} {type}. Please try " + "another {type}.".format( name=name, an=self.a_or_an, app=self.app_or_project, + type=name_or_dir, ) ) diff --git a/tests/admin_scripts/tests.py b/tests/admin_scripts/tests.py index f6fb42b1aa..08d188e88a 100644 --- a/tests/admin_scripts/tests.py +++ b/tests/admin_scripts/tests.py @@ -2132,6 +2132,25 @@ class StartApp(AdminScriptTestCase): ) self.assertFalse(os.path.exists(testproject_dir)) + def test_invalid_target_name(self): + for bad_target in ('invalid.dir_name', '7invalid_dir_name', '.invalid_dir_name'): + with self.subTest(bad_target): + _, err = self.run_django_admin(['startapp', 'app', bad_target]) + self.assertOutput( + err, + "CommandError: '%s' is not a valid app directory. Please " + "make sure the directory is a valid identifier." % bad_target + ) + + def test_importable_target_name(self): + _, err = self.run_django_admin(['startapp', 'app', 'os']) + self.assertOutput( + err, + "CommandError: 'os' conflicts with the name of an existing Python " + "module and cannot be used as an app directory. Please try " + "another directory." + ) + def test_overlaying_app(self): self.run_django_admin(['startapp', 'app1']) out, err = self.run_django_admin(['startapp', 'app2', 'app1'])