Repository: beeware/briefcase
Pull request #1851 (2024-05-30 16:17:37)

Update warning for pyproject.toml license spec
## Changes
- Rework a bit the license warning from https://github.com/beeware/briefcase/pull/1812 to include additional information
- This change also drops a warning for each time the `license` field is specified in `pyproject.toml`

## Notes
- The presentation of the original warning was a little jarring to me since it spread across my entire terminal. Additionally, though, it wasn't using the "WARNING" banner typically reserved for messages like this.
- Moreover, I didn't really understand the change I was being asked to make.

## PR Checklist:
<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
- [X] All new features have been tested
- [X] All new features have been documented
- [X] I have read the **CONTRIBUTING.md** file
- [X] I will abide by the code of conduct


Patch:
diff --git a/changes/1851.misc.rst b/changes/1851.misc.rst
new file mode 100644
index 00000000..55b6ae7f
--- /dev/null
+++ b/changes/1851.misc.rst
@@ -0,0 +1,1 @@
+The warning for specifying the license in pyproject.toml was updated to include additional information.
diff --git a/pyproject.toml b/pyproject.toml
index 47e37ac2..9b57e6c2 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -102,7 +102,8 @@ dev = [
     "pre-commit == 3.5.0 ; python_version < '3.9'",
     "pre-commit == 3.7.1 ; python_version >= '3.9'",
     "pytest == 8.2.1",
-    "pytest-xdist == 3.6.1",
+    # Having xdist in the pytest environment causes some weird failures on Windows with Py3.13
+    "pytest-xdist == 3.6.1 ; python_version < '3.13'",
     "setuptools_scm == 8.1.0",
     "tox == 4.15.0",
 ]
diff --git a/src/briefcase/config.py b/src/briefcase/config.py
index e100e93c..c1d79364 100644
--- a/src/briefcase/config.py
+++ b/src/briefcase/config.py
@@ -478,6 +478,37 @@ def parse_config(config_file, platform, output_format, logger):
     except KeyError as e:
         raise BriefcaseConfigError("No Briefcase apps defined in pyproject.toml") from e
 
+    for name, config in [("project", global_config)] + list(all_apps.items()):
+        if isinstance(config.get("license"), str):
+            section_name = "the Project" if name == "project" else f"{name!r}"
+            logger.warning(
+                f"""
+*************************************************************************
+** {f"WARNING: License Definition for {section_name} is Deprecated":67} **
+*************************************************************************
+
+    Briefcase now uses PEP 621 format for license definitions.
+
+    Previously, the name of the license was assigned to the 'license'
+    field in pyproject.toml. For PEP 621, the name of the license is
+    assigned to 'license.text' or the name of the file containing the
+    license is assigned to 'license.file'.
+
+    The current configuration for {section_name} has a 'license' field
+    that is specified as a string:
+
+        license = "{config['license']}"
+
+    To use the PEP 621 format (and to remove this warning), specify that
+    the LICENSE file contains the license for {section_name}:
+
+        license.file = "LICENSE"
+
+*************************************************************************
+"""
+            )
+            config["license"] = {"file": "LICENSE"}
+
     # Build the flat configuration for each app,
     # based on the requested platform and output format
     app_configs = {}
@@ -550,17 +581,4 @@ def parse_config(config_file, platform, output_format, logger):
         # of configurations that are being handled.
         app_configs[app_name] = config
 
-    old_license_format = False
-    for config in [global_config, *app_configs.values()]:
-        if isinstance(config.get("license"), str):
-            config["license"] = {"file": "LICENSE"}
-            old_license_format = True
-
-    if old_license_format:
-        logger.warning(
-            "Your app configuration has a `license` field that is specified as a string. "
-            "Briefcase now uses PEP 621 format for license definitions. To silence this "
-            'warning, replace the `license` declaration with `license.file = "LICENSE".'
-        )
-
     return global_config, app_configs


Test patch:
diff --git a/tests/config/test_parse_config.py b/tests/config/test_parse_config.py
index 45b0bae9..b48caee9 100644
--- a/tests/config/test_parse_config.py
+++ b/tests/config/test_parse_config.py
@@ -1,5 +1,5 @@
 from io import BytesIO
-from unittest.mock import Mock
+from unittest.mock import Mock, call
 
 import pytest
 
@@ -701,7 +701,8 @@ def test_pep621_defaults():
     }
 
 
-def test_license_is_string():
+def test_license_is_string_project():
+    """The project definition contains a string definition for 'license'."""
     config_file = BytesIO(
         b"""
         [tool.briefcase]
@@ -729,7 +730,115 @@ def test_license_is_string():
         "license": {"file": "LICENSE"},
     }
     logger.warning.assert_called_once_with(
-        "Your app configuration has a `license` field that is specified as a string. "
-        "Briefcase now uses PEP 621 format for license definitions. To silence this "
-        'warning, replace the `license` declaration with `license.file = "LICENSE".'
+        """
+*************************************************************************
+** WARNING: License Definition for the Project is Deprecated           **
+*************************************************************************
+
+    Briefcase now uses PEP 621 format for license definitions.
+
+    Previously, the name of the license was assigned to the 'license'
+    field in pyproject.toml. For PEP 621, the name of the license is
+    assigned to 'license.text' or the name of the file containing the
+    license is assigned to 'license.file'.
+
+    The current configuration for the Project has a 'license' field
+    that is specified as a string:
+
+        license = "Some license"
+
+    To use the PEP 621 format (and to remove this warning), specify that
+    the LICENSE file contains the license for the Project:
+
+        license.file = "LICENSE"
+
+*************************************************************************
+"""
+    )
+
+
+def test_license_is_string_project_and_app():
+    """The project and app definition contain a string definition for 'license'."""
+    config_file = BytesIO(
+        b"""
+        [tool.briefcase]
+        value = 0
+        license = "Some license"
+
+        [tool.briefcase.app.my_app]
+        appvalue = "the app"
+        license = "Another license"
+        """
+    )
+
+    logger = Mock()
+    global_options, apps = parse_config(
+        config_file, platform="macOS", output_format="app", logger=logger
+    )
+
+    assert global_options == {
+        "value": 0,
+        "license": {"file": "LICENSE"},
+    }
+    assert apps["my_app"] == {
+        "app_name": "my_app",
+        "value": 0,
+        "appvalue": "the app",
+        "license": {"file": "LICENSE"},
+    }
+    logger.warning.assert_has_calls(
+        [
+            call(
+                """
+*************************************************************************
+** WARNING: License Definition for the Project is Deprecated           **
+*************************************************************************
+
+    Briefcase now uses PEP 621 format for license definitions.
+
+    Previously, the name of the license was assigned to the 'license'
+    field in pyproject.toml. For PEP 621, the name of the license is
+    assigned to 'license.text' or the name of the file containing the
+    license is assigned to 'license.file'.
+
+    The current configuration for the Project has a 'license' field
+    that is specified as a string:
+
+        license = "Some license"
+
+    To use the PEP 621 format (and to remove this warning), specify that
+    the LICENSE file contains the license for the Project:
+
+        license.file = "LICENSE"
+
+*************************************************************************
+"""
+            ),
+            call(
+                """
+*************************************************************************
+** WARNING: License Definition for 'my_app' is Deprecated              **
+*************************************************************************
+
+    Briefcase now uses PEP 621 format for license definitions.
+
+    Previously, the name of the license was assigned to the 'license'
+    field in pyproject.toml. For PEP 621, the name of the license is
+    assigned to 'license.text' or the name of the file containing the
+    license is assigned to 'license.file'.
+
+    The current configuration for 'my_app' has a 'license' field
+    that is specified as a string:
+
+        license = "Another license"
+
+    To use the PEP 621 format (and to remove this warning), specify that
+    the LICENSE file contains the license for 'my_app':
+
+        license.file = "LICENSE"
+
+*************************************************************************
+"""
+            ),
+        ]
     )