diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6f4fc563b..f97540b1d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,6 +5,11 @@ on: branches: - main workflow_call: + inputs: + attest-package: + description: "Create GitHub provenance attestation for the package." + default: "false" + type: string outputs: artifact-name: description: "Name of the uploaded artifact; use for artifact retrieval." @@ -32,10 +37,24 @@ jobs: uses: beeware/.github/.github/workflows/towncrier-run.yml@main package: - name: Python package + name: Package Briefcase + permissions: + id-token: write + contents: read + attestations: write uses: beeware/.github/.github/workflows/python-package-create.yml@main with: - tox-factors: -with-automation + attest: ${{ inputs.attest-package }} + + package-automation: + name: Package Automation + permissions: + id-token: write + contents: read + attestations: write + uses: beeware/.github/.github/workflows/python-package-create.yml@main + with: + build-subdirectory: "automation" unit-tests: name: Unit tests @@ -82,12 +101,11 @@ jobs: name: ${{ needs.package.outputs.artifact-name }} path: dist - - name: Install dev Dependencies - run: | - python -m pip install --upgrade pip - python -m pip install --upgrade setuptools build wheel - # Utility script installs tox as defined in pyproject.toml - python -m install_requirement tox --extra dev + - name: Install Tox + uses: beeware/.github/.github/actions/install-requirement@main + with: + requirements: tox + extra: dev - name: Test id: test @@ -129,12 +147,11 @@ jobs: # https://github.com/nedbat/coveragepy/issues/1572#issuecomment-1522546425 python-version: "3.8" - - name: Install dev Dependencies - run: | - python -m pip install --upgrade pip - python -m pip install --upgrade setuptools build wheel - # Utility script installs tox as defined in pyproject.toml - python -m install_requirement tox --extra dev + - name: Install Tox + uses: beeware/.github/.github/actions/install-requirement@main + with: + requirements: tox + extra: dev - name: Retrieve Coverage Data uses: actions/download-artifact@v4.1.7 @@ -162,7 +179,7 @@ jobs: verify-projects: name: Verify project - needs: unit-tests + needs: [ package, package-automation, unit-tests ] uses: beeware/.github/.github/workflows/app-create-verify.yml@main with: runner-os: ${{ matrix.runner-os }} @@ -175,7 +192,7 @@ jobs: verify-apps: name: Build app - needs: unit-tests + needs: [ package, package-automation, unit-tests ] uses: beeware/.github/.github/workflows/app-build-verify.yml@main with: # This *must* be the version of Python that is the system Python on the diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1866b45bd..17a345a6e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,6 +9,8 @@ jobs: ci: name: CI uses: ./.github/workflows/ci.yml + with: + attest-package: "true" docs: name: Verify Docs Build @@ -29,7 +31,7 @@ jobs: steps: - name: Set build variables run: | - echo "VERSION=${GITHUB_REF_NAME#v}" >> $GITHUB_ENV + echo "VERSION=${GITHUB_REF_NAME#v}" | tee -a $GITHUB_ENV - name: Set up Python uses: actions/setup-python@v5.1.0 diff --git a/changes/1807.doc.rst b/changes/1807.doc.rst new file mode 100644 index 000000000..2fd1d62a3 --- /dev/null +++ b/changes/1807.doc.rst @@ -0,0 +1 @@ +Documentation on Briefcase's plug-in interfaces was added. diff --git a/changes/1807.feature.rst b/changes/1807.feature.rst new file mode 100644 index 000000000..6b600ec11 --- /dev/null +++ b/changes/1807.feature.rst @@ -0,0 +1 @@ +The new project wizard now includes links to known third-party GUI bootstraps. diff --git a/changes/1843.misc.rst b/changes/1843.misc.rst new file mode 100644 index 000000000..3f31ce711 --- /dev/null +++ b/changes/1843.misc.rst @@ -0,0 +1 @@ +``hynek/build-and-inspect-python-package`` is now used to create the Python package. diff --git a/changes/1847.misc.rst b/changes/1847.misc.rst new file mode 100644 index 000000000..0efa6b852 --- /dev/null +++ b/changes/1847.misc.rst @@ -0,0 +1 @@ +The ``install_requirement.py`` script was removed. diff --git a/changes/1850.misc.rst b/changes/1850.misc.rst new file mode 100644 index 000000000..a96b93dea --- /dev/null +++ b/changes/1850.misc.rst @@ -0,0 +1 @@ +A UUID cookiecutter extension was added to support Windows MSI templating. diff --git a/changes/1851.misc.rst b/changes/1851.misc.rst new file mode 100644 index 000000000..55b6ae7fb --- /dev/null +++ b/changes/1851.misc.rst @@ -0,0 +1 @@ +The warning for specifying the license in pyproject.toml was updated to include additional information. diff --git a/changes/1853.misc.rst b/changes/1853.misc.rst new file mode 100644 index 000000000..2ad4d7d4d --- /dev/null +++ b/changes/1853.misc.rst @@ -0,0 +1 @@ +Updated coverage[toml] from 7.5.2 to 7.5.3. diff --git a/docs/reference/commands/new.rst b/docs/reference/commands/new.rst index d4fbeefe2..6007de67c 100644 --- a/docs/reference/commands/new.rst +++ b/docs/reference/commands/new.rst @@ -49,3 +49,31 @@ The expected keys are specified by the cookiecutter template being used to create the new project. Therefore, the set of possible keys is not listed here but should be expected to remain consistent for any specific version of Briefcase; with version changes, though, the keys may change. + +Third-party Bootstraps +====================== + +When you run new project wizard, you are asked to select a GUI toolkit. Briefcase +includes bootstraps for `Toga `__ (BeeWare's cross-platform +GUI framework), `PySide6 `__ (Python bindings for the +Qt GUI toolkit) and `Pygame `__ (a common Python game +development toolkit), as well as an "empty" bootstrap that doesn't include any GUI code. +However, Briefcase provides a :ref:`plug-in interface ` that allows +GUI toolkits to provide a their own bootstrap implementation. + +The following third-party bootstraps are known to exist: + +=================================== ============== =================================================== +Bootstrap Package name Description +=================================== ============== =================================================== +`PursuedPyBear `__ ``ppb`` "Unbearably fun game development". A game toolkit + with a focus on being education friendly and + exposing an idiomatic Python interface. +----------------------------------- -------------- --------------------------------------------------- +`Pygame-ce `__ ``pygame-ce`` A fork of pygame, the classic library for making + games in Python. +=================================== ============== =================================================== + +To add a third-party bootstrap, ``pip install`` the named package into the virtual +environment that contains Briefcase, then run ``briefcase new``. The new bootstrap +option should be added to the list of GUI toolkits. diff --git a/docs/reference/configuration.rst b/docs/reference/configuration.rst index efca6c704..022fe8b13 100644 --- a/docs/reference/configuration.rst +++ b/docs/reference/configuration.rst @@ -241,8 +241,11 @@ on an app with a formal name of "My App" would remove: ~~~~~~~~~~~~~~~ A Boolean describing if the app is a console app, or a GUI app. Defaults to ``False`` -(producing a GUI app). This setting has no effect on platforms that do not support -a console mode (e.g., web or mobile platforms). +(producing a GUI app). This setting has no effect on platforms that do not support a +console mode (e.g., web or mobile platforms). On platforms that do support console apps, +the resulting app will write output directly to ``stdout``/``stderr`` (rather than +writing to a system log), creating a terminal window to display this output (if the +platform allows). ``exit_regex`` ~~~~~~~~~~~~~~ diff --git a/docs/reference/index.rst b/docs/reference/index.rst index 0b0b958ef..812006ae3 100644 --- a/docs/reference/index.rst +++ b/docs/reference/index.rst @@ -14,3 +14,4 @@ This is the technical reference for public APIs provided by Briefcase. configuration commands/index platforms/index + plugins diff --git a/docs/reference/platforms/macOS/app.rst b/docs/reference/platforms/macOS/app.rst index 692b512ce..ed10ad44b 100644 --- a/docs/reference/platforms/macOS/app.rst +++ b/docs/reference/platforms/macOS/app.rst @@ -24,15 +24,14 @@ By default, apps will be both signed and notarized when they are packaged. Packaging format ================ -Briefcase supports three packaging formats for a macOS ``.app`` bundle: +Briefcase supports three packaging formats for a macOS app: -1. A DMG that contains the ``.app`` bundle (using ``briefcase package macOS -p dmg``); - or +1. A DMG that contains the ``.app`` bundle (using ``briefcase package macOS -p dmg``). 2. A zipped ``.app`` folder (using ``briefcase package macOS -p zip``). 3. A ``.pkg`` installer (using ``briefcase package macOS -p pkg``). -The ``.pkg`` format is the *required* format for console apps. ``.dmg`` format is the -default format GUI apps. +``.pkg`` is the *required* format for console apps. ``.dmg`` is the +default format for GUI apps. Icon format =========== diff --git a/docs/reference/platforms/macOS/xcode.rst b/docs/reference/platforms/macOS/xcode.rst index 4f919da66..18850b4ec 100644 --- a/docs/reference/platforms/macOS/xcode.rst +++ b/docs/reference/platforms/macOS/xcode.rst @@ -24,12 +24,12 @@ Packaging format Briefcase supports three packaging formats for a macOS Xcode project: 1. A DMG that contains the ``.app`` bundle (using ``briefcase package macOS Xcode -p - dmg``); or + dmg``). 2. A zipped ``.app`` folder (using ``briefcase package macOS Xcode -p zip``). 3. A ``.pkg`` installer (using ``briefcase package macOS Xcode -p pkg``). -The ``.pkg`` format is the *required* format for console apps. ``.dmg`` format is the -default format GUI apps. +``.pkg`` is the *required* format for console apps. ``.dmg`` is the +default format for GUI apps. Icon format =========== diff --git a/docs/reference/plugins.rst b/docs/reference/plugins.rst new file mode 100644 index 000000000..187190ed1 --- /dev/null +++ b/docs/reference/plugins.rst @@ -0,0 +1,70 @@ +======== +Plug-ins +======== + +Briefcase ships with support for a range of platforms, output formats and GUI toolkits. +Internally, these features are implemented using a plug-in interface; as a result, it is +possible for third-party projects to add their own features to Briefcase by implementing +plug-ins that satisfy those interfaces. + +Each plug-in is defined using an `entry point +`__ definition in +``pyproject.toml``. + +.. _bootstrap-interface: + +``briefcase.bootstraps`` +======================== + +The Briefcase :doc:`new project wizard ` asks users to select a +GUI toolkit. The option selected at this step alters the content of the code generated +by the wizard, generating framework-specific requirements, system packages, and stub +code for a new application using that GUI framework. These additions are configured +using a ``briefcase.bootstrap`` plug-in. + +To add a custom ``briefcase.bootstrap`` plug-in, add a +``[project.entry-points."briefcase.platforms"]`` section to your ``pyproject.toml`` +file; each name/value pair under that section will be interpreted as a bootstrap. The +name of each bootstrap setting is the label that will be surfaced to the user in the +wizard. The value is a string identifying a class that implements the +``briefcase.bootstraps.base.BaseGuiBootstrap`` abstract base class. + +For example, the Toga bootstrap is implemented using the following configuration:: + + [project.entry-points."briefcase.bootstraps"] + Toga = "briefcase.bootstraps.toga:TogaGuiBootstrap" + +``briefcase.platforms`` and ``briefcase.formats.*`` +=================================================== + +Each command implemented by Briefcase is specialized by a platform and output format. +This implementation is defined using a pair of plug-ins - a ``briefcase.platforms`` +definition describing a platform, and a ``briefcase.format.`` definition that +defines the output formats for that platform. + +The ``briefcase.platforms`` entry point defines the existence of a platform. Each name +in this section is name of a platform that can be used when invoking Briefcase commands. +The value is a fully-qualified Python module name that must defines a single constant +``DEFAULT_OUTPUT_FORMAT``. + +Each platform name is then incorporated into the name of a separate ``format`` entry +point. Each entry in the ``format`` section for a platform is the name of an output +format that can be used when invoking Briefcase commands. The value is a fully-qualified +Python module name that defines 7 symbols: + +* ``create`` - a subclass of ``briefcase.commands.create.CreateCommand`` +* ``update`` - a subclass of ``briefcase.commands.create.UpdateCommand`` +* ``open`` - a subclass of ``briefcase.commands.create.OpenCommand`` +* ``build`` - a subclass of ``briefcase.commands.create.BuildCommand`` +* ``run`` - a subclass of ``briefcase.commands.create.RunCommand`` +* ``package`` - a subclass of ``briefcase.commands.create.PackageCommand`` +* ``publish`` - a subclass of ``briefcase.commands.create.PublishCommand`` + +For example, the definition for the macOS Xcode output format is controlled by the +following:: + + [project.entry-points."briefcase.platforms"] + macOS = "briefcase.platforms.macOS" + + [project.entry-points."briefcase.formats.macOS"] + xcode = "briefcase.platforms.macOS.xcode" diff --git a/docs/spelling_wordlist b/docs/spelling_wordlist index 45bc9a116..82949e195 100644 --- a/docs/spelling_wordlist +++ b/docs/spelling_wordlist @@ -11,6 +11,7 @@ backported BeeWare Bugfix Bugfixes +ce checkmarks codebase Cookiecutter @@ -66,6 +67,7 @@ proxied Proxied proxying px +pygame Pygame Pyodide PyScript @@ -87,6 +89,7 @@ submodule subprocesses tl toml +toolkits towncrier tox TTY diff --git a/install_requirement.py b/install_requirement.py deleted file mode 100644 index 11f08cf2f..000000000 --- a/install_requirement.py +++ /dev/null @@ -1,179 +0,0 @@ -# install_requirement.py - Install a requirement from a PEP 517 project -# -# Usage -# ----- -# $ python install_requirement.py [-h] [--extra EXTRA] [--project-root PROJECT_ROOT] [requirements ...] -# -# Install one or more PEP 517 project defined requirements -# -# positional arguments: -# requirements List of project requirements to install. Any project -# requirements that start with any of these values will -# be installed. For instance, including 'pytest' in this -# list would install both pytest and pytest-xdist. -# -# options: -# -h, --help show this help message and exit -# --extra EXTRA Name of the extra where the requirements are defined -# --project-root PROJECT_ROOT -# File path to the root of the project. The current -# directory is used by default. -# -# Purpose -# ------- -# Installs one or more requested requirements as defined for the project. -# -# In certain workflows, such as automated coverage reporting, the coverage -# dependencies must be installed first. Since a project's requirements are often -# pinned to specific versions to ensure consistency for the project regardless of the -# environment, the coverage dependencies that are installed should match those pinned -# for the project. -# -# A simple method to accomplish this is ``pip install .[dev]`` in which ``pip`` will -# build the source and install the project with all its defined requirements. However, -# this is very inefficient when only one or a few specific requirements are needed. -# -# Therefore, this script will evaluate the requirements defined in the project's -# metadata and install the ones matching those being requested to be installed. -# -# Dependencies -# ------------ -# The ``build``, ``setuptools``, and ``wheel`` packages must be installed to run. - -from __future__ import annotations - -import subprocess -import sys -from argparse import ArgumentParser, RawDescriptionHelpFormatter -from pathlib import Path -from shutil import get_terminal_size - -from build.util import project_wheel_metadata -from packaging.requirements import Requirement - - -class RequirementsInstallerError(Exception): - def __init__(self, msg: str, error_no: int): - self.msg = msg - self.error_no = error_no - - -class HelpText(RequirementsInstallerError): - """Shows script's help text.""" - - -class NoRequirementsFound(RequirementsInstallerError): - """No project requirements were found to install.""" - - -def parse_args(): - width = max(min(get_terminal_size().columns, 80) - 2, 20) - parser = ArgumentParser( - description="Installs one or more PEP 517 project defined requirements", - formatter_class=lambda prog: RawDescriptionHelpFormatter(prog, width=width), - ) - parser.add_argument( - "requirements", - type=str, - nargs="*", - help=( - "List of project requirements to install. If the project defines extras for " - "a requirement, do not include them in this list; they will be included " - "automatically when the requirement is installed. For instance, if " - "coverage[toml] is a project requirement, just include coverage in this list." - ), - ) - parser.add_argument( - "--extra", - type=str, - default="", - help="Name of the extra where the requirements are defined", - ) - parser.add_argument( - "--project-root", - type=Path, - default=".", - help=( - "File path to the root of the project. The current directory is used by " - "default." - ), - ) - - args = parser.parse_args() - - if not args.requirements: - raise HelpText(parser.format_help(), error_no=-1) - - return args - - -def gather_requirements( - project_root: str | Path, - requested_requirements: list[str], - extra_name: str = "", -) -> list[Requirement]: - """Identifies one or more matching requirements from a project.""" - project_root = Path(project_root).resolve() - project_metadata = project_wheel_metadata(project_root, isolated=False) - project_requirements = [ - requirement - for requirement in map(Requirement, project_metadata.get_all("Requires-Dist")) - if not requirement.marker or requirement.marker.evaluate({"extra": extra_name}) - ] - - matching_requirements = [ - requirement - for requirement in project_requirements - if requirement.name in requested_requirements - ] - - if not matching_requirements: - raise NoRequirementsFound( - f"No requirements matched requested requirements: " - f"{', '.join(requested_requirements)}\n\n" - f"The requirements below were evaluated for matching:\n " - f"{f'{chr(10)} '.join(req.name for req in project_requirements)}", - error_no=1, - ) - - return matching_requirements - - -def install_requirements(requirements: list[Requirement]): - """Install requirements from PyPI.""" - for requirement in requirements: - extras = f"[{','.join(requirement.extras)}]" if requirement.extras else "" - requirement_str = f"{requirement.name}{extras}{requirement.specifier}" - print(f"Installing {requirement_str}...") - subprocess.run( - [ - sys.executable, - "-m", - "pip", - "install", - "--upgrade", - requirement_str, - ], - check=True, - ) - - -def main(): - ret_code = 0 - try: - args = parse_args() - requirements_to_install = gather_requirements( - project_root=args.project_root, - requested_requirements=args.requirements, - extra_name=args.extra, - ) - install_requirements(requirements=requirements_to_install) - except RequirementsInstallerError as e: - print(e.msg) - ret_code = e.error_no - - return ret_code - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/pyproject.toml b/pyproject.toml index 3b0b5dcb8..ef5d476e6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -96,13 +96,14 @@ dependencies = [ # Extras used by developers *of* briefcase are pinned to specific versions to # ensure environment consistency. dev = [ - "coverage[toml] == 7.5.2", + "coverage[toml] == 7.5.3", "coverage-conditional-plugin == 0.9.0", # Pre-commit 3.6.0 deprecated support for Python 3.8 "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/commands/new.py b/src/briefcase/commands/new.py index 2bb7c74be..4e4997855 100644 --- a/src/briefcase/commands/new.py +++ b/src/briefcase/commands/new.py @@ -621,7 +621,13 @@ def build_gui_context( bootstrap_override = reverse_lookup[bootstraps[bootstrap_override]] selected_bootstrap = self.select_option( - intro="What GUI toolkit do you want to use for this project?", + intro=( + "What GUI toolkit do you want to use for this project?\n" + "\n" + "Additional GUI bootstraps are available; visit " + "https://beeware.org/bee/briefcase-bootstraps " + "for a full list of known GUI bootstraps." + ), variable="GUI Framework", default=None, options=bootstrap_options.keys(), diff --git a/src/briefcase/config.py b/src/briefcase/config.py index 5a35e4871..14cc2ac00 100644 --- a/src/briefcase/config.py +++ b/src/briefcase/config.py @@ -480,6 +480,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 = {} @@ -552,17 +583,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 diff --git a/src/briefcase/platforms/macOS/__init__.py b/src/briefcase/platforms/macOS/__init__.py index f6d857ea1..02e828c9c 100644 --- a/src/briefcase/platforms/macOS/__init__.py +++ b/src/briefcase/platforms/macOS/__init__.py @@ -1004,7 +1004,8 @@ def package_pkg( + install_args + [ installer_packages_path / f"{app.app_name}.pkg", - ] + ], + check=True, ) # Build package @@ -1019,7 +1020,8 @@ def package_pkg( "--resources", installer_path / "resources", dist_path, - ] + ], + check=True, ) def package_dmg( diff --git a/tests/config/test_parse_config.py b/tests/config/test_parse_config.py index 45b0bae9d..b48caee95 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" + +************************************************************************* +""" + ), + ] ) diff --git a/tests/platforms/macOS/app/package/test_package_pkg.py b/tests/platforms/macOS/app/package/test_package_pkg.py index 2db2b0266..5f8e400ed 100644 --- a/tests/platforms/macOS/app/package/test_package_pkg.py +++ b/tests/platforms/macOS/app/package/test_package_pkg.py @@ -90,7 +90,8 @@ def test_gui_app( "--install-location", "/Applications", bundle_path / "installer/packages/first-app.pkg", - ] + ], + check=True, ), mock.call( [ @@ -102,7 +103,8 @@ def test_gui_app( "--resources", bundle_path / "installer/resources", tmp_path / "base_path/dist/First App-0.0.1.pkg", - ] + ], + check=True, ), ] @@ -183,7 +185,8 @@ def test_gui_app_adhoc_identity( "--install-location", "/Applications", bundle_path / "installer/packages/first-app.pkg", - ] + ], + check=True, ), mock.call( [ @@ -195,7 +198,8 @@ def test_gui_app_adhoc_identity( "--resources", bundle_path / "installer/resources", tmp_path / "base_path/dist/First App-0.0.1.pkg", - ] + ], + check=True, ), ] @@ -260,7 +264,8 @@ def test_console_app( "--scripts", bundle_path / "installer/scripts", bundle_path / "installer/packages/first-app.pkg", - ] + ], + check=True, ), mock.call( [ @@ -272,7 +277,8 @@ def test_console_app( "--resources", bundle_path / "installer/resources", tmp_path / "base_path/dist/First App-0.0.1.pkg", - ] + ], + check=True, ), ] @@ -338,7 +344,8 @@ def test_console_app_adhoc_signed( "--scripts", bundle_path / "installer/scripts", bundle_path / "installer/packages/first-app.pkg", - ] + ], + check=True, ), mock.call( [ @@ -350,7 +357,8 @@ def test_console_app_adhoc_signed( "--resources", bundle_path / "installer/resources", tmp_path / "base_path/dist/First App-0.0.1.pkg", - ] + ], + check=True, ), ] @@ -466,7 +474,8 @@ def test_package_pkg_previously_built( "--install-location", "/Applications", bundle_path / "installer/packages/first-app.pkg", - ] + ], + check=True, ), mock.call( [ @@ -478,6 +487,7 @@ def test_package_pkg_previously_built( "--resources", bundle_path / "installer/resources", tmp_path / "base_path/dist/First App-0.0.1.pkg", - ] + ], + check=True, ), ] diff --git a/tox.ini b/tox.ini index be9bbba55..1b1543e66 100644 --- a/tox.ini +++ b/tox.ini @@ -31,12 +31,9 @@ labels = skip_missing_interpreters = True [testenv:pre-commit] -skip_install = True -deps = - build==1.2.1 - setuptools==70.0.0 - wheel==0.43.0 -commands_pre = python -m install_requirement pre-commit --extra dev --project-root "{tox_root}" +package = wheel +wheel_build_env = .pkg +extras = dev commands = pre-commit run --all-files --show-diff-on-failure --color=always [testenv:py{,38,39,310,311,312,313}{,-fast,-cov}] @@ -54,8 +51,9 @@ commands = fast : python -m pytest {posargs:-vv --color yes -n auto} [testenv:coverage{,38,39,310,311,312,313}{,-ci}{,-platform,-platform-linux,-platform-macos,-platform-windows,-project}{,-keep}{,-html}] +package = wheel +wheel_build_env = .pkg depends = pre-commit,py{,38,39,310,311,312,313}{,-cov} -skip_install = True # by default, coverage should run on oldest supported Python for testing platform coverage. # however, coverage for a particular Python version should match the version used for pytest. base_python = @@ -81,13 +79,9 @@ setenv = {platform,project}: COVERAGE_EXCLUDE_PYTHON_VERSION=disable # disable conditional coverage exclusions for host platform to test entire project project: COVERAGE_EXCLUDE_PLATFORM=disable -deps = - build==1.2.1 - setuptools==70.0.0 - wheel==0.43.0 +extras = dev commands_pre = python --version - python -m install_requirement coverage coverage-conditional-plugin --extra dev --project-root "{tox_root}" commands = -python -m coverage combine {env:COMBINE_FLAGS} html: python -m coverage html --skip-covered --skip-empty @@ -128,14 +122,3 @@ commands = lint : python -m sphinx {[docs]sphinx_args} {posargs} -b linkcheck {[docs]docs_dir} {[docs]build_dir}{/}links all : python -m sphinx {[docs]sphinx_args} {posargs} -v -a -E -b html {[docs]docs_dir} {[docs]build_dir}{/}html live : sphinx-autobuild {[docs]sphinx_args} {posargs} -b html {[docs]docs_dir} {[docs]build_dir}{/}live - -[testenv:package{,-with-automation}] -skip_install = True -passenv = FORCE_COLOR -deps = - build==1.2.1 - twine==5.1.0 -commands = - python -m build . --outdir dist{/} - with-automation: python -m build automation --outdir dist{/} - python -m twine check dist{/}*