From 629269d416928a4077d19c461eb009cf74bdcfec Mon Sep 17 00:00:00 2001 From: Xing Yang Date: Tue, 26 Oct 2021 13:41:20 -0700 Subject: [PATCH 01/30] test change --- src/briefcase/commands/new.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/briefcase/commands/new.py b/src/briefcase/commands/new.py index ca18e1368..eba8be560 100644 --- a/src/briefcase/commands/new.py +++ b/src/briefcase/commands/new.py @@ -93,7 +93,7 @@ def make_app_name(self, formal_name): :param formal_name: The formal name :returns: The candidate app name """ - return re.sub('[^0-9a-zA-Z_]+', '', formal_name).lstrip('_').lower() + return re.sub('[^0-9a-zA-Z_]+', 'x', formal_name).lstrip('_').lower() def validate_app_name(self, candidate): """ From b5747a7db4d377528efaba8411860a07e8d644ba Mon Sep 17 00:00:00 2001 From: Xing Yang Date: Tue, 26 Oct 2021 13:48:22 -0700 Subject: [PATCH 02/30] edited the regex for make_app_name to remove leading digits from the formal name when making the default app name. --- src/briefcase/commands/new.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/briefcase/commands/new.py b/src/briefcase/commands/new.py index eba8be560..0b727c65c 100644 --- a/src/briefcase/commands/new.py +++ b/src/briefcase/commands/new.py @@ -93,7 +93,7 @@ def make_app_name(self, formal_name): :param formal_name: The formal name :returns: The candidate app name """ - return re.sub('[^0-9a-zA-Z_]+', 'x', formal_name).lstrip('_').lower() + return re.sub('[^a-zA-Z]*[^0-9a-zA-Z_]+', '', formal_name).lstrip('_').lower() def validate_app_name(self, candidate): """ From 171dada4e26ad54a3a96eec3b302f388bfe86ce0 Mon Sep 17 00:00:00 2001 From: Xing Yang Date: Tue, 26 Oct 2021 14:56:38 -0700 Subject: [PATCH 03/30] Changed PEP508 regex in command.py to prevent names starting with a number. Also updated the value error to reflect this. git status --- src/briefcase/commands/new.py | 2 +- src/briefcase/config.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/briefcase/commands/new.py b/src/briefcase/commands/new.py index 0b727c65c..cd7057eaa 100644 --- a/src/briefcase/commands/new.py +++ b/src/briefcase/commands/new.py @@ -106,7 +106,7 @@ def validate_app_name(self, candidate): if not PEP508_NAME_RE.match(candidate): raise ValueError( "App name may only contain letters, numbers, hypens and " - "underscores, and may not start with a hyphen or underscore." + "underscores, and may not start with a number, hyphen or underscore." ) if (self.base_path / candidate).exists(): raise ValueError( diff --git a/src/briefcase/config.py b/src/briefcase/config.py index cbe46ecb3..fa9692992 100644 --- a/src/briefcase/config.py +++ b/src/briefcase/config.py @@ -10,7 +10,7 @@ # The restriction on application naming comes from PEP508 PEP508_NAME_RE = re.compile( - r'^([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])$', + r'^([A-Z][A-Z0-9][A-Z0-9._-]*[A-Z0-9])$', re.IGNORECASE ) From 4bab13a1ecdf178e86b016268b40e1aee9804069 Mon Sep 17 00:00:00 2001 From: Xing Yang Date: Tue, 26 Oct 2021 15:11:32 -0700 Subject: [PATCH 04/30] Changed class name to be derived from app name instead of formal name, due to the restrictions in the naming scheme. Removed make_class_name as additional formatting is not needed from the app name to make a valid class name. Also moved the instantiation of class_name to appear below validation of the app_name. --- src/briefcase/commands/new.py | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/src/briefcase/commands/new.py b/src/briefcase/commands/new.py index cd7057eaa..05b45c314 100644 --- a/src/briefcase/commands/new.py +++ b/src/briefcase/commands/new.py @@ -74,18 +74,6 @@ def add_options(self, parser): help='The cookiecutter template to use for the new project' ) - def make_class_name(self, formal_name): - """ - Construct a valid class name from a formal name. - - :param formal_name: The formal name - :returns: The app's class name - """ - class_name = re.sub('[^0-9a-zA-Z_]+', '', formal_name) - if class_name[0].isdigit(): - class_name = '_' + class_name - return class_name - def make_app_name(self, formal_name): """ Construct a candidate app name from a formal name. @@ -317,9 +305,6 @@ def build_app_context(self): default='Hello World', ) - # The class name can be completely derived from the formal name. - class_name = self.make_class_name(formal_name) - default_app_name = self.make_app_name(formal_name) app_name = self.input_text( intro=""" @@ -337,6 +322,9 @@ def build_app_context(self): validator=self.validate_app_name, ) + # The class name can be completely derived from the app name. + class_name = app_name + # The module name can be completely derived from the app name. module_name = self.make_module_name(app_name) From d3127978516624f6f7dd1574a8f95f458766d3aa Mon Sep 17 00:00:00 2001 From: Xing Yang Date: Tue, 26 Oct 2021 15:21:17 -0700 Subject: [PATCH 05/30] Made changes to the make_default_app_name function by adding a conditional if a blank string is created from the regex, which may happen if the formal name was entered with only non-latin characters. Will return a statement that an example cannot be given, which will require the user to type in a candidate name into the command line. --- src/briefcase/commands/new.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/briefcase/commands/new.py b/src/briefcase/commands/new.py index 05b45c314..952009e8f 100644 --- a/src/briefcase/commands/new.py +++ b/src/briefcase/commands/new.py @@ -81,7 +81,10 @@ def make_app_name(self, formal_name): :param formal_name: The formal name :returns: The candidate app name """ - return re.sub('[^a-zA-Z]*[^0-9a-zA-Z_]+', '', formal_name).lstrip('_').lower() + app_name = re.sub('[^a-zA-Z]*[^0-9a-zA-Z_]+', '', formal_name).lstrip('_').lower() + if app_name == "": + app_name = "I can't suggest an app name" + return app_name def validate_app_name(self, candidate): """ From 12339f930dd851a21188fbcc01a800a33b01954d Mon Sep 17 00:00:00 2001 From: Xing Yang Date: Thu, 28 Oct 2021 14:54:36 -0700 Subject: [PATCH 06/30] Changed how class_name is derived. Now ask user for a class name, and validates input in the validate_class_name method. --- src/briefcase/commands/new.py | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/briefcase/commands/new.py b/src/briefcase/commands/new.py index 952009e8f..bfe042cee 100644 --- a/src/briefcase/commands/new.py +++ b/src/briefcase/commands/new.py @@ -108,6 +108,22 @@ def validate_app_name(self, candidate): return True + def validate_class_name(self, candidate): + """ + Determine if class name is valid + + :param candidate: The candidate name + :returns: True. If there are any validation problems, raises ValueError + with a diagnostic message. + """ + if not re.match('^[A-Z][a-zA-Z0-9]+$', candidate): + raise ValueError( + "The class name must start with a capital letter in the CapWords format." + "It can't contain spaces and punctuation." + ) + + return True + def make_module_name(self, app_name): """ Construct a valid module name from an app name. @@ -325,8 +341,14 @@ def build_app_context(self): validator=self.validate_app_name, ) - # The class name can be completely derived from the app name. - class_name = app_name + class_name = self.input_text( + intro=""" +Next, we need a name that will serve as a class name. The class name must start with +a capital letter in the CapWords format. It can't contain spaces or punctuation""", + variable="class name", + default="", + validator=self.validate_class_name, + ) # The module name can be completely derived from the app name. module_name = self.make_module_name(app_name) From 3865150a3627ecfc5439ba69fdc587da4bd4b278 Mon Sep 17 00:00:00 2001 From: Xing Yang Date: Thu, 28 Oct 2021 15:10:02 -0700 Subject: [PATCH 07/30] Removed pep508 regex from config.py as it isn't sufficient for the restrictions of app_name. Replaced in new.py with regex to only allow app_names that start with a lowercase letter. --- src/briefcase/commands/new.py | 4 ++-- src/briefcase/config.py | 6 ------ 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/briefcase/commands/new.py b/src/briefcase/commands/new.py index bfe042cee..6f9975515 100644 --- a/src/briefcase/commands/new.py +++ b/src/briefcase/commands/new.py @@ -94,9 +94,9 @@ def validate_app_name(self, candidate): :returns: True. If there are any validation problems, raises ValueError with a diagnostic message. """ - if not PEP508_NAME_RE.match(candidate): + if not re.match('^[a-z][a-zA-Z0-9._-]+$', candidate): raise ValueError( - "App name may only contain letters, numbers, hypens and " + "App name may only contain letters, numbers, hyphens and " "underscores, and may not start with a number, hyphen or underscore." ) if (self.base_path / candidate).exists(): diff --git a/src/briefcase/config.py b/src/briefcase/config.py index fa9692992..8266e4824 100644 --- a/src/briefcase/config.py +++ b/src/briefcase/config.py @@ -8,12 +8,6 @@ from .exceptions import BriefcaseConfigError -# The restriction on application naming comes from PEP508 -PEP508_NAME_RE = re.compile( - r'^([A-Z][A-Z0-9][A-Z0-9._-]*[A-Z0-9])$', - re.IGNORECASE -) - # This is the canonical definition from PEP440, modified to include # named groups PEP440_CANONICAL_VERSION_PATTERN_RE = re.compile( From f01ac41789d3b7204a3b145ab56a714864413d40 Mon Sep 17 00:00:00 2001 From: Xing Yang Date: Thu, 28 Oct 2021 15:26:20 -0700 Subject: [PATCH 08/30] Remoed import statement for pep508 regex --- src/briefcase/commands/new.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/briefcase/commands/new.py b/src/briefcase/commands/new.py index 6f9975515..51105c57e 100644 --- a/src/briefcase/commands/new.py +++ b/src/briefcase/commands/new.py @@ -7,7 +7,7 @@ from cookiecutter import exceptions as cookiecutter_exceptions -from briefcase.config import PEP508_NAME_RE + from briefcase.exceptions import NetworkFailure from .base import BaseCommand, BriefcaseCommandError From 11c3b47ce0aa09b45ffe04bdb2e4f19edfc43808 Mon Sep 17 00:00:00 2001 From: Xing Yang Date: Thu, 28 Oct 2021 15:28:54 -0700 Subject: [PATCH 09/30] Added back the pep508 regex in the config.py file, as this is required for integration. --- src/briefcase/config.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/briefcase/config.py b/src/briefcase/config.py index 8266e4824..cbe46ecb3 100644 --- a/src/briefcase/config.py +++ b/src/briefcase/config.py @@ -8,6 +8,12 @@ from .exceptions import BriefcaseConfigError +# The restriction on application naming comes from PEP508 +PEP508_NAME_RE = re.compile( + r'^([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])$', + re.IGNORECASE +) + # This is the canonical definition from PEP440, modified to include # named groups PEP440_CANONICAL_VERSION_PATTERN_RE = re.compile( From ddad887232ee3741164753cd26c63e6f47d466d7 Mon Sep 17 00:00:00 2001 From: Xing Yang Date: Thu, 28 Oct 2021 15:43:24 -0700 Subject: [PATCH 10/30] - removed an entry from the valid testing that had a leading digit - added test to invalid testing: name with a leading digit, blank, non-latin character, leading capital letter. Changes passed all tests. --- tests/commands/new/test_validate_app_name.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/commands/new/test_validate_app_name.py b/tests/commands/new/test_validate_app_name.py index fa817ab35..06318cde9 100644 --- a/tests/commands/new/test_validate_app_name.py +++ b/tests/commands/new/test_validate_app_name.py @@ -7,7 +7,6 @@ 'helloworld', 'helloWorld', 'hello42world', - '42helloworld', # ?? Are we sure this is correct? 'hello_world', 'hello-world', ] @@ -25,6 +24,10 @@ def test_valid_app_name(new_command, name): '_helloworld', # leading underscore '-helloworld', # leading hyphen 'existing', # pre-existing directory + '98helloworld', # leading digit + '', # blank + '学口算', # non-latin character + 'Helloworld' # start with capital letter ] ) def test_invalid_app_name(new_command, name, tmp_path): From 2e9df934ca3dd809e3692ed4831d506b8fdca974 Mon Sep 17 00:00:00 2001 From: Xing Yang Date: Thu, 28 Oct 2021 15:44:03 -0700 Subject: [PATCH 11/30] Changed wording of the suggested app_name if the formal_name contained non-latin charaters. --- src/briefcase/commands/new.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/briefcase/commands/new.py b/src/briefcase/commands/new.py index 51105c57e..d2f0e7898 100644 --- a/src/briefcase/commands/new.py +++ b/src/briefcase/commands/new.py @@ -83,7 +83,7 @@ def make_app_name(self, formal_name): """ app_name = re.sub('[^a-zA-Z]*[^0-9a-zA-Z_]+', '', formal_name).lstrip('_').lower() if app_name == "": - app_name = "I can't suggest an app name" + app_name = "Unable to suggest a default name based on the formal name." return app_name def validate_app_name(self, candidate): From d535e199b3f968df0653c0352fabb415411aad95 Mon Sep 17 00:00:00 2001 From: Xing Yang Date: Thu, 28 Oct 2021 16:18:41 -0700 Subject: [PATCH 12/30] Added a make_class_name so that there is a default value that can be generated, just like with the app_name. This should help with the testing that requires some default value. --- src/briefcase/commands/new.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/briefcase/commands/new.py b/src/briefcase/commands/new.py index d2f0e7898..cadf437ef 100644 --- a/src/briefcase/commands/new.py +++ b/src/briefcase/commands/new.py @@ -108,6 +108,16 @@ def validate_app_name(self, candidate): return True + def make_class_name(self, formal_name): + """ + Construct a candidate class name from a formal name. + + :param formal_name: The formal name + :returns: The candidate app name; will appear blank if only non-latin characters + were entered in the formal_name + """ + return re.sub('[^a-zA-Z]*[^0-9a-zA-Z_]+', '', formal_name) + def validate_class_name(self, candidate): """ Determine if class name is valid @@ -341,12 +351,12 @@ def build_app_context(self): validator=self.validate_app_name, ) + default_class_name = self.make_class_name(formal_name) class_name = self.input_text( intro=""" Next, we need a name that will serve as a class name. The class name must start with a capital letter in the CapWords format. It can't contain spaces or punctuation""", - variable="class name", - default="", + variable=default_class_name, validator=self.validate_class_name, ) From 93d9598d94e74a754b900f4a79ffb64b37e34db8 Mon Sep 17 00:00:00 2001 From: Xing Yang Date: Thu, 28 Oct 2021 16:23:35 -0700 Subject: [PATCH 13/30] Added function to convert default_class_name to title case. --- src/briefcase/commands/new.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/briefcase/commands/new.py b/src/briefcase/commands/new.py index cadf437ef..ff5db5812 100644 --- a/src/briefcase/commands/new.py +++ b/src/briefcase/commands/new.py @@ -82,8 +82,6 @@ def make_app_name(self, formal_name): :returns: The candidate app name """ app_name = re.sub('[^a-zA-Z]*[^0-9a-zA-Z_]+', '', formal_name).lstrip('_').lower() - if app_name == "": - app_name = "Unable to suggest a default name based on the formal name." return app_name def validate_app_name(self, candidate): @@ -351,12 +349,13 @@ def build_app_context(self): validator=self.validate_app_name, ) - default_class_name = self.make_class_name(formal_name) + default_class_name = self.make_class_name(formal_name).title() class_name = self.input_text( intro=""" -Next, we need a name that will serve as a class name. The class name must start with +Next, we need a name that will serve as the App class name. The class name must start with a capital letter in the CapWords format. It can't contain spaces or punctuation""", - variable=default_class_name, + variable="class name", + default=default_class_name, validator=self.validate_class_name, ) From 6a1e25a9e7a4e15d08c150b7cf1fbb081e7fc15c Mon Sep 17 00:00:00 2001 From: Xing Yang Date: Thu, 28 Oct 2021 16:26:18 -0700 Subject: [PATCH 14/30] Included test for class name now that it is being explicitly asked. Test passed. --- tests/commands/new/test_build_app_context.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/commands/new/test_build_app_context.py b/tests/commands/new/test_build_app_context.py index 193615918..9beca5cdf 100644 --- a/tests/commands/new/test_build_app_context.py +++ b/tests/commands/new/test_build_app_context.py @@ -6,6 +6,7 @@ def test_question_sequence(new_command): new_command.input.values = [ 'My Application', # formal name '', # app name - accept the default + '', # class name 'org.beeware', # bundle ID 'My Project', # project name 'Cool stuff', # description @@ -18,8 +19,8 @@ def test_question_sequence(new_command): assert new_command.build_app_context() == { 'formal_name': 'My Application', - 'class_name': 'MyApplication', 'app_name': 'myapplication', + 'class_name': 'Myapplication', 'module_name': 'myapplication', 'bundle': 'org.beeware', 'project_name': 'My Project', @@ -39,6 +40,7 @@ def test_question_sequence_with_nondefault_gui(new_command): new_command.input.values = [ 'My Application', # formal name '', # app name - accept the default + '', # class name 'org.beeware', # bundle ID 'My Project', # project name 'Cool stuff', # description @@ -51,8 +53,8 @@ def test_question_sequence_with_nondefault_gui(new_command): assert new_command.build_app_context() == { 'formal_name': 'My Application', - 'class_name': 'MyApplication', 'app_name': 'myapplication', + 'class_name': 'Myapplication', 'module_name': 'myapplication', 'bundle': 'org.beeware', 'project_name': 'My Project', @@ -75,7 +77,7 @@ def test_question_sequence_with_no_user_input(new_command): 'author': 'Jane Developer', 'author_email': 'jane@example.com', 'bundle': 'com.example', - 'class_name': 'HelloWorld', + 'class_name': 'Helloworld', 'description': 'My first application', 'formal_name': 'Hello World', 'gui_framework': 'Toga', From e91d9b3a4054315aff65f7fd39168beaf873976c Mon Sep 17 00:00:00 2001 From: Xing Yang Date: Thu, 28 Oct 2021 16:43:04 -0700 Subject: [PATCH 15/30] Changed the final test candidate to remove leading digit. Adding an if statement to evaluate if the first character is a digit will throw an error if the formal name is non-latin. --- tests/commands/new/test_make_class_name.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/commands/new/test_make_class_name.py b/tests/commands/new/test_make_class_name.py index 79d2eee76..336415e04 100644 --- a/tests/commands/new/test_make_class_name.py +++ b/tests/commands/new/test_make_class_name.py @@ -9,7 +9,7 @@ ('Hello! World', 'HelloWorld'), ('Hello_World', 'Hello_World'), ('Hello-World', 'HelloWorld'), - ('24 Jump Street', '_24JumpStreet'), + ('24 Jump Street', 'JumpStreet'), ] ) def test_make_class_name(new_command, formal_name, candidate): From 2857cff93d26dd1c5f7b9074fa5dc18e646b3f0a Mon Sep 17 00:00:00 2001 From: Xing Yang Date: Thu, 28 Oct 2021 16:49:54 -0700 Subject: [PATCH 16/30] Added a test page for valid_class_name. Uses a lot of the criteria in the validate_app_name, with some differences. --- tests/commands/new/test_valid_class_name.py | 36 +++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 tests/commands/new/test_valid_class_name.py diff --git a/tests/commands/new/test_valid_class_name.py b/tests/commands/new/test_valid_class_name.py new file mode 100644 index 000000000..468464fd4 --- /dev/null +++ b/tests/commands/new/test_valid_class_name.py @@ -0,0 +1,36 @@ +import pytest + + +@pytest.mark.parametrize( + 'name', + [ + 'HelloWorld', + 'HelloWorld98', + 'Hello42World', + 'Hello_World', + ] +) +def test_valid_class_name(new_command, name): + "Test that valid app names are accepted" + assert new_command.validate_class_name(name) + + +@pytest.mark.parametrize( + 'name', + [ + 'hello world', # space + 'helloworld!', # punctuation + '_helloworld', # leading underscore + '-helloworld', # leading hyphen + '98helloworld', # leading digit + '', # blank + '学口算', # non-latin character + 'helloworld', # no capitalized letter + ] +) +def test_invalid_class_name(new_command, name, tmp_path): + "Test that invalid app names are rejected" + (tmp_path / 'existing').mkdir() + + with pytest.raises(ValueError): + new_command.validate_class_name(name) From a4e3370e2b538b320f674162cc938e565b32281b Mon Sep 17 00:00:00 2001 From: Xing Yang Date: Thu, 28 Oct 2021 16:50:36 -0700 Subject: [PATCH 17/30] Allow non-leading underscores in the class name. --- src/briefcase/commands/new.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/briefcase/commands/new.py b/src/briefcase/commands/new.py index ff5db5812..c26aee299 100644 --- a/src/briefcase/commands/new.py +++ b/src/briefcase/commands/new.py @@ -114,6 +114,7 @@ def make_class_name(self, formal_name): :returns: The candidate app name; will appear blank if only non-latin characters were entered in the formal_name """ + formal_name.title() return re.sub('[^a-zA-Z]*[^0-9a-zA-Z_]+', '', formal_name) def validate_class_name(self, candidate): @@ -124,10 +125,10 @@ def validate_class_name(self, candidate): :returns: True. If there are any validation problems, raises ValueError with a diagnostic message. """ - if not re.match('^[A-Z][a-zA-Z0-9]+$', candidate): + if not re.match('^[A-Z][a-zA-Z0-9_]+$', candidate): raise ValueError( "The class name must start with a capital letter in the CapWords format." - "It can't contain spaces and punctuation." + "It should not contain spaces." ) return True @@ -349,11 +350,11 @@ def build_app_context(self): validator=self.validate_app_name, ) - default_class_name = self.make_class_name(formal_name).title() + default_class_name = self.make_class_name(formal_name) class_name = self.input_text( intro=""" Next, we need a name that will serve as the App class name. The class name must start with -a capital letter in the CapWords format. It can't contain spaces or punctuation""", +a capital letter in the CapWords format. It should not contain spaces.""", variable="class name", default=default_class_name, validator=self.validate_class_name, From 120d2e522e30eb0b4e517a638cf1c3ba564ffce3 Mon Sep 17 00:00:00 2001 From: Xing Yang Date: Fri, 29 Oct 2021 09:10:56 -0700 Subject: [PATCH 18/30] Cleaned up some code. --- src/briefcase/commands/new.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/briefcase/commands/new.py b/src/briefcase/commands/new.py index c26aee299..56513fd28 100644 --- a/src/briefcase/commands/new.py +++ b/src/briefcase/commands/new.py @@ -81,8 +81,7 @@ def make_app_name(self, formal_name): :param formal_name: The formal name :returns: The candidate app name """ - app_name = re.sub('[^a-zA-Z]*[^0-9a-zA-Z_]+', '', formal_name).lstrip('_').lower() - return app_name + return re.sub('[^a-zA-Z]*[^0-9a-zA-Z_]+', '', formal_name).lstrip('_').lower() def validate_app_name(self, candidate): """ @@ -115,7 +114,7 @@ def make_class_name(self, formal_name): were entered in the formal_name """ formal_name.title() - return re.sub('[^a-zA-Z]*[^0-9a-zA-Z_]+', '', formal_name) + return re.sub('[^a-zA-Z]*[^a-zA-Z0-9_]+', '', formal_name) def validate_class_name(self, candidate): """ @@ -125,7 +124,7 @@ def validate_class_name(self, candidate): :returns: True. If there are any validation problems, raises ValueError with a diagnostic message. """ - if not re.match('^[A-Z][a-zA-Z0-9_]+$', candidate): + if not re.match('^[A-Z]+[a-zA-Z0-9_]+$', candidate): raise ValueError( "The class name must start with a capital letter in the CapWords format." "It should not contain spaces." From f6ed116ee357cdfe5bfa7cefb3e4f4e7a8cc722d Mon Sep 17 00:00:00 2001 From: Xing Yang Date: Fri, 29 Oct 2021 09:11:07 -0700 Subject: [PATCH 19/30] Renamed test file name --- .../new/{test_valid_class_name.py => test_validate_class_name.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/commands/new/{test_valid_class_name.py => test_validate_class_name.py} (100%) diff --git a/tests/commands/new/test_valid_class_name.py b/tests/commands/new/test_validate_class_name.py similarity index 100% rename from tests/commands/new/test_valid_class_name.py rename to tests/commands/new/test_validate_class_name.py From 91d0d722fc48692e366de7b6a70fe36e6d1e9315 Mon Sep 17 00:00:00 2001 From: Xing Yang Date: Fri, 29 Oct 2021 09:14:05 -0700 Subject: [PATCH 20/30] Changed class_name result to reflect camel case (My Application --> MyApplication instead of Myapplication) --- tests/commands/new/test_build_app_context.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/commands/new/test_build_app_context.py b/tests/commands/new/test_build_app_context.py index 9beca5cdf..13e0d6f2b 100644 --- a/tests/commands/new/test_build_app_context.py +++ b/tests/commands/new/test_build_app_context.py @@ -20,7 +20,7 @@ def test_question_sequence(new_command): assert new_command.build_app_context() == { 'formal_name': 'My Application', 'app_name': 'myapplication', - 'class_name': 'Myapplication', + 'class_name': 'MyApplication', 'module_name': 'myapplication', 'bundle': 'org.beeware', 'project_name': 'My Project', @@ -54,7 +54,7 @@ def test_question_sequence_with_nondefault_gui(new_command): assert new_command.build_app_context() == { 'formal_name': 'My Application', 'app_name': 'myapplication', - 'class_name': 'Myapplication', + 'class_name': 'MyApplication', 'module_name': 'myapplication', 'bundle': 'org.beeware', 'project_name': 'My Project', @@ -77,7 +77,7 @@ def test_question_sequence_with_no_user_input(new_command): 'author': 'Jane Developer', 'author_email': 'jane@example.com', 'bundle': 'com.example', - 'class_name': 'Helloworld', + 'class_name': 'HelloWorld', 'description': 'My first application', 'formal_name': 'Hello World', 'gui_framework': 'Toga', From aa348c913cf98b34f7c3af7adee9630ab83b3216 Mon Sep 17 00:00:00 2001 From: Xing Yang Date: Fri, 29 Oct 2021 09:15:52 -0700 Subject: [PATCH 21/30] Added a test for a formal name that starts with a digit. --- tests/commands/new/test_make_app_name.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/commands/new/test_make_app_name.py b/tests/commands/new/test_make_app_name.py index 0e3144130..bac6330d7 100644 --- a/tests/commands/new/test_make_app_name.py +++ b/tests/commands/new/test_make_app_name.py @@ -8,6 +8,7 @@ ('Hello World!', 'helloworld'), ('Hello! World', 'helloworld'), ('Hello-World', 'helloworld'), + ('98 Hello World', 'helloworld') ] ) def test_make_app_name(new_command, formal_name, candidate): From 2457ae635f7cbf1a7c890d84a7ae680e18add50f Mon Sep 17 00:00:00 2001 From: Xing Yang Date: Fri, 29 Oct 2021 09:53:12 -0700 Subject: [PATCH 22/30] Added a test that uses underscores in the beginning and end of the formal name. --- tests/commands/new/test_make_app_name.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/commands/new/test_make_app_name.py b/tests/commands/new/test_make_app_name.py index bac6330d7..899ed8e39 100644 --- a/tests/commands/new/test_make_app_name.py +++ b/tests/commands/new/test_make_app_name.py @@ -8,7 +8,10 @@ ('Hello World!', 'helloworld'), ('Hello! World', 'helloworld'), ('Hello-World', 'helloworld'), - ('98 Hello World', 'helloworld') + ('98 Hello World', 'helloworld'), + ('Hello World_', 'helloworld'), + ('Hello world.', 'helloworld'), + ('_HelloWorld_', 'helloworld') ] ) def test_make_app_name(new_command, formal_name, candidate): From 88451f92632adaea9a5d3461342dcc2034201a4f Mon Sep 17 00:00:00 2001 From: Xing Yang Date: Fri, 29 Oct 2021 09:56:17 -0700 Subject: [PATCH 23/30] Added tests that includes hyphens. --- tests/commands/new/test_make_app_name.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/commands/new/test_make_app_name.py b/tests/commands/new/test_make_app_name.py index 899ed8e39..37b094a33 100644 --- a/tests/commands/new/test_make_app_name.py +++ b/tests/commands/new/test_make_app_name.py @@ -11,7 +11,9 @@ ('98 Hello World', 'helloworld'), ('Hello World_', 'helloworld'), ('Hello world.', 'helloworld'), - ('_HelloWorld_', 'helloworld') + ('_HelloWorld_', 'helloworld'), + ('Hello_World_', 'hello_world'), + ('Hello World-', 'helloworld'), ] ) def test_make_app_name(new_command, formal_name, candidate): From 3cb58383f390cba1eba8a0b13bc5a512bc20fac7 Mon Sep 17 00:00:00 2001 From: Xing Yang Date: Fri, 29 Oct 2021 09:57:12 -0700 Subject: [PATCH 24/30] Changed some formatting, and also the text for the value error when validating the app_name. --- src/briefcase/commands/new.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/briefcase/commands/new.py b/src/briefcase/commands/new.py index 56513fd28..e3d77dc38 100644 --- a/src/briefcase/commands/new.py +++ b/src/briefcase/commands/new.py @@ -81,7 +81,7 @@ def make_app_name(self, formal_name): :param formal_name: The formal name :returns: The candidate app name """ - return re.sub('[^a-zA-Z]*[^0-9a-zA-Z_]+', '', formal_name).lstrip('_').lower() + return re.sub('[^a-zA-Z]*[^a-zA-Z0-9_]+', '', formal_name).lstrip('_').rstrip('_').lower() def validate_app_name(self, candidate): """ @@ -91,10 +91,11 @@ def validate_app_name(self, candidate): :returns: True. If there are any validation problems, raises ValueError with a diagnostic message. """ - if not re.match('^[a-z][a-zA-Z0-9._-]+$', candidate): + if not re.match('^[a-z][a-zA-Z0-9._-]*[a-zA-Z0-9]$', candidate): raise ValueError( - "App name may only contain letters, numbers, hyphens and " - "underscores, and may not start with a number, hyphen or underscore." + "App names must be PEP508 compliant (i.e., they can only " + "include letters, numbers, '-' and '_'; must start with a " + "letter; and cannot end with '-' or '_'." ) if (self.base_path / candidate).exists(): raise ValueError( From 5256f75a7b4cb1439f29138fb0b99e8534e7874e Mon Sep 17 00:00:00 2001 From: Xing Yang Date: Mon, 1 Nov 2021 15:24:28 -0400 Subject: [PATCH 25/30] Updated the pep508_name_re in the config file instead of introducing a new regex. --- src/briefcase/commands/new.py | 3 ++- src/briefcase/config.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/briefcase/commands/new.py b/src/briefcase/commands/new.py index e3d77dc38..80fcdd1e9 100644 --- a/src/briefcase/commands/new.py +++ b/src/briefcase/commands/new.py @@ -12,6 +12,7 @@ from .base import BaseCommand, BriefcaseCommandError from .create import InvalidTemplateRepository +from ..config import PEP508_NAME_RE VALID_BUNDLE_RE = re.compile(r'[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)+$') @@ -91,7 +92,7 @@ def validate_app_name(self, candidate): :returns: True. If there are any validation problems, raises ValueError with a diagnostic message. """ - if not re.match('^[a-z][a-zA-Z0-9._-]*[a-zA-Z0-9]$', candidate): + if not PEP508_NAME_RE.match(candidate): raise ValueError( "App names must be PEP508 compliant (i.e., they can only " "include letters, numbers, '-' and '_'; must start with a " diff --git a/src/briefcase/config.py b/src/briefcase/config.py index cbe46ecb3..07b1004d0 100644 --- a/src/briefcase/config.py +++ b/src/briefcase/config.py @@ -10,7 +10,7 @@ # The restriction on application naming comes from PEP508 PEP508_NAME_RE = re.compile( - r'^([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])$', + r'^[a-z][a-zA-Z0-9._-]*[a-zA-Z0-9]$', re.IGNORECASE ) From 9b7105b0ffcbc8ee341c56a3e87e7ef1bc4b80a5 Mon Sep 17 00:00:00 2001 From: Xing Yang Date: Mon, 1 Nov 2021 15:28:45 -0400 Subject: [PATCH 26/30] the title() method for the formal_name was combined in the return statement. This is to create camel case of words that were otherwise in lower case. Updated test scenario, which this passes. --- src/briefcase/commands/new.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/briefcase/commands/new.py b/src/briefcase/commands/new.py index 80fcdd1e9..d36cce63c 100644 --- a/src/briefcase/commands/new.py +++ b/src/briefcase/commands/new.py @@ -115,8 +115,7 @@ def make_class_name(self, formal_name): :returns: The candidate app name; will appear blank if only non-latin characters were entered in the formal_name """ - formal_name.title() - return re.sub('[^a-zA-Z]*[^a-zA-Z0-9_]+', '', formal_name) + return re.sub('[^a-zA-Z]*[^a-zA-Z0-9_]+', '', formal_name.title()) def validate_class_name(self, candidate): """ @@ -128,7 +127,7 @@ def validate_class_name(self, candidate): """ if not re.match('^[A-Z]+[a-zA-Z0-9_]+$', candidate): raise ValueError( - "The class name must start with a capital letter in the CapWords format." + "The class name must start with a capital letter in the camel case format." "It should not contain spaces." ) From 8ba62d789d24d2bca58fca3ba4f738087355d4f8 Mon Sep 17 00:00:00 2001 From: Xing Yang Date: Mon, 1 Nov 2021 15:29:21 -0400 Subject: [PATCH 27/30] added a test where the formal names are written in lower case letters. Class names should be in camel case, so created a test where it converts from lower case words to camel case. --- tests/commands/new/test_make_class_name.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/commands/new/test_make_class_name.py b/tests/commands/new/test_make_class_name.py index 336415e04..2a9270b03 100644 --- a/tests/commands/new/test_make_class_name.py +++ b/tests/commands/new/test_make_class_name.py @@ -10,6 +10,7 @@ ('Hello_World', 'Hello_World'), ('Hello-World', 'HelloWorld'), ('24 Jump Street', 'JumpStreet'), + ('hello world', 'HelloWorld') ] ) def test_make_class_name(new_command, formal_name, candidate): From 6dfb30d9e3edc05d0f2bf83d7db3fbe15034e089 Mon Sep 17 00:00:00 2001 From: Xing Yang Date: Mon, 1 Nov 2021 15:38:29 -0400 Subject: [PATCH 28/30] Corrected spelling mistake. --- src/briefcase/commands/new.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/briefcase/commands/new.py b/src/briefcase/commands/new.py index d36cce63c..90ee93983 100644 --- a/src/briefcase/commands/new.py +++ b/src/briefcase/commands/new.py @@ -127,7 +127,7 @@ def validate_class_name(self, candidate): """ if not re.match('^[A-Z]+[a-zA-Z0-9_]+$', candidate): raise ValueError( - "The class name must start with a capital letter in the camel case format." + "The class name must start with a capital letter in the CamelCase format." "It should not contain spaces." ) From cf86ed915bbde25b1ec350f0b2f25248cb041817 Mon Sep 17 00:00:00 2001 From: Xing Yang Date: Mon, 1 Nov 2021 15:38:50 -0400 Subject: [PATCH 29/30] Added a test to include non-latin characters only, and a combination of latin and non-latin characters. Passes test. --- tests/commands/new/test_make_class_name.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/commands/new/test_make_class_name.py b/tests/commands/new/test_make_class_name.py index 2a9270b03..644b803a7 100644 --- a/tests/commands/new/test_make_class_name.py +++ b/tests/commands/new/test_make_class_name.py @@ -10,7 +10,9 @@ ('Hello_World', 'Hello_World'), ('Hello-World', 'HelloWorld'), ('24 Jump Street', 'JumpStreet'), - ('hello world', 'HelloWorld') + ('hello world', 'HelloWorld'), + ('学口算', ''), + ('学口算 Hello World', 'HelloWorld') ] ) def test_make_class_name(new_command, formal_name, candidate): From 3626b52b3a79ea16303dcbd8e940ae66bb4238c5 Mon Sep 17 00:00:00 2001 From: Xing Yang Date: Mon, 1 Nov 2021 15:55:00 -0400 Subject: [PATCH 30/30] Removed the 'ignore cases' since it is important that app name is in lowercase. --- src/briefcase/config.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/briefcase/config.py b/src/briefcase/config.py index 07b1004d0..5b55e7db4 100644 --- a/src/briefcase/config.py +++ b/src/briefcase/config.py @@ -10,8 +10,7 @@ # The restriction on application naming comes from PEP508 PEP508_NAME_RE = re.compile( - r'^[a-z][a-zA-Z0-9._-]*[a-zA-Z0-9]$', - re.IGNORECASE + r'^[a-z][a-zA-Z0-9._-]*[a-zA-Z0-9]$' ) # This is the canonical definition from PEP440, modified to include