From fe98feebc06a320f789ec77a9f8e74f08469d316 Mon Sep 17 00:00:00 2001 From: Andrew Coffey Date: Mon, 20 May 2024 10:52:58 -0500 Subject: [PATCH 01/22] Added docs for externally supported entry points --- docs/reference/index.rst | 1 + docs/reference/known-external-hooks.rst | 21 +++++++++++++++++++++ src/briefcase/commands/new.py | 9 +++++++++ 3 files changed, 31 insertions(+) create mode 100644 docs/reference/known-external-hooks.rst diff --git a/docs/reference/index.rst b/docs/reference/index.rst index 0b0b958ef..90c24a560 100644 --- a/docs/reference/index.rst +++ b/docs/reference/index.rst @@ -12,5 +12,6 @@ This is the technical reference for public APIs provided by Briefcase. environment configuration + known-external-hooks commands/index platforms/index diff --git a/docs/reference/known-external-hooks.rst b/docs/reference/known-external-hooks.rst new file mode 100644 index 000000000..3130311d7 --- /dev/null +++ b/docs/reference/known-external-hooks.rst @@ -0,0 +1,21 @@ +Known External Projects with Briefcase Entry Points +=================================================== + +If you would like to document your project that has Briefcase entry points, +follow the `doc contributing guide`_ to update this page. + +.. _doc contributing guide: https://briefcase.readthedocs.io/en/latest/how-to/contribute-docs.html + +Briefcase provides entry points for several projects, but the ideal scenario +is for the projects themselves to implement entry points that briefcase can use. + +A sample pull request that implements this type of entry point can be found at +this `pygame-ce pull request`_ + +.. _pygame-ce pull request: https://github.com/pygame-community/pygame-ce/pull/2862 + +`pygame-ce`_ +--------------------- +Pygame-ce is a modern fork of pygame, the classic library for making games in Python. + +.. _pygame-ce: https://github.com/pygame-community/pygame-ce diff --git a/src/briefcase/commands/new.py b/src/briefcase/commands/new.py index ef52b0409..0a271d8ff 100644 --- a/src/briefcase/commands/new.py +++ b/src/briefcase/commands/new.py @@ -378,6 +378,7 @@ def select_option( default: str | None, options: Sequence[str], override_value: str | None, + external_hooks: str | None = None, ) -> str: variable = titlecase(variable) self.prompt_divider(title=variable) @@ -396,6 +397,8 @@ def select_option( default = "1" self.prompt_intro(intro=intro) + if external_hooks is not None: + self.prompt_intro(intro=external_hooks) return _select_option( prompt=f"{variable} [{default}]:", input=self.input, @@ -599,12 +602,18 @@ def build_gui_context( if self.validate_selection_override(bootstraps.keys(), bootstrap_override): bootstrap_override = reverse_lookup[bootstraps[bootstrap_override]] + EXTERNAL_HOOKS_SUPPORT = ( + "Known external entry points documented " + "at https://briefcase.readthedocs.io/en/latest/reference/known-external-hooks.html" + ) + selected_bootstrap = self.select_option( intro="What GUI toolkit do you want to use for this project?", variable="GUI Framework", default=None, options=bootstrap_options.keys(), override_value=bootstrap_override, + external_hooks=EXTERNAL_HOOKS_SUPPORT, ) bootstrap_class = bootstrap_options[selected_bootstrap] From 2e96448b6d5b38dbf7845a03cdf8fe9ed9f5ed97 Mon Sep 17 00:00:00 2001 From: Andrew Coffey Date: Mon, 20 May 2024 10:56:12 -0500 Subject: [PATCH 02/22] Added changelog --- changes/1807.misc.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 changes/1807.misc.rst diff --git a/changes/1807.misc.rst b/changes/1807.misc.rst new file mode 100644 index 000000000..debd9bcb1 --- /dev/null +++ b/changes/1807.misc.rst @@ -0,0 +1 @@ +Added documentation for externally supported entry points From 51793afc48b3fa65e0ad07ff01631c25f2022e93 Mon Sep 17 00:00:00 2001 From: Andrew Coffey Date: Mon, 20 May 2024 11:00:26 -0500 Subject: [PATCH 03/22] fix spellcheck --- docs/spelling_wordlist | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/spelling_wordlist b/docs/spelling_wordlist index 45bc9a116..993f5dc2e 100644 --- a/docs/spelling_wordlist +++ b/docs/spelling_wordlist @@ -67,6 +67,7 @@ Proxied proxying px Pygame +Pygame-ce Pyodide PyScript PySide From 36a0d379bfbdbde1fe67e561d7bd13fc56243ecb Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Mon, 20 May 2024 12:07:37 -0400 Subject: [PATCH 04/22] Add pygame variants to dictionary. --- docs/spelling_wordlist | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/spelling_wordlist b/docs/spelling_wordlist index 993f5dc2e..0b466fcf5 100644 --- a/docs/spelling_wordlist +++ b/docs/spelling_wordlist @@ -11,6 +11,7 @@ backported BeeWare Bugfix Bugfixes +ce checkmarks codebase Cookiecutter @@ -66,8 +67,8 @@ proxied Proxied proxying px +pygame Pygame -Pygame-ce Pyodide PyScript PySide From 2d6a9d4384df81c10e89c725efec1d6910649932 Mon Sep 17 00:00:00 2001 From: Andrew Coffey Date: Mon, 20 May 2024 17:10:19 -0500 Subject: [PATCH 05/22] Removed unnecessary argument from NewCommand.select_option --- src/briefcase/commands/new.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/briefcase/commands/new.py b/src/briefcase/commands/new.py index 0a271d8ff..8f99dcac7 100644 --- a/src/briefcase/commands/new.py +++ b/src/briefcase/commands/new.py @@ -378,7 +378,6 @@ def select_option( default: str | None, options: Sequence[str], override_value: str | None, - external_hooks: str | None = None, ) -> str: variable = titlecase(variable) self.prompt_divider(title=variable) @@ -397,8 +396,6 @@ def select_option( default = "1" self.prompt_intro(intro=intro) - if external_hooks is not None: - self.prompt_intro(intro=external_hooks) return _select_option( prompt=f"{variable} [{default}]:", input=self.input, @@ -608,12 +605,11 @@ def build_gui_context( ) selected_bootstrap = self.select_option( - intro="What GUI toolkit do you want to use for this project?", + intro=f"What GUI toolkit do you want to use for this project?\n{EXTERNAL_HOOKS_SUPPORT}", variable="GUI Framework", default=None, options=bootstrap_options.keys(), override_value=bootstrap_override, - external_hooks=EXTERNAL_HOOKS_SUPPORT, ) bootstrap_class = bootstrap_options[selected_bootstrap] From 57534b71dd606fa6a6d9ef83fb8270af69b86e7d Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Tue, 28 May 2024 09:51:19 +0800 Subject: [PATCH 06/22] Rework documentation for plugins. --- changes/1807.doc.rst | 1 + changes/1807.feature.rst | 1 + changes/1807.misc.rst | 1 - docs/reference/commands/new.rst | 28 ++++++++++ docs/reference/index.rst | 2 +- docs/reference/known-external-hooks.rst | 21 -------- docs/reference/plugins.rst | 70 +++++++++++++++++++++++++ docs/spelling_wordlist | 1 + src/briefcase/commands/new.py | 13 ++--- 9 files changed, 109 insertions(+), 29 deletions(-) create mode 100644 changes/1807.doc.rst create mode 100644 changes/1807.feature.rst delete mode 100644 changes/1807.misc.rst delete mode 100644 docs/reference/known-external-hooks.rst create mode 100644 docs/reference/plugins.rst 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/1807.misc.rst b/changes/1807.misc.rst deleted file mode 100644 index debd9bcb1..000000000 --- a/changes/1807.misc.rst +++ /dev/null @@ -1 +0,0 @@ -Added documentation for externally supported entry points 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/index.rst b/docs/reference/index.rst index 90c24a560..812006ae3 100644 --- a/docs/reference/index.rst +++ b/docs/reference/index.rst @@ -12,6 +12,6 @@ This is the technical reference for public APIs provided by Briefcase. environment configuration - known-external-hooks commands/index platforms/index + plugins diff --git a/docs/reference/known-external-hooks.rst b/docs/reference/known-external-hooks.rst deleted file mode 100644 index 3130311d7..000000000 --- a/docs/reference/known-external-hooks.rst +++ /dev/null @@ -1,21 +0,0 @@ -Known External Projects with Briefcase Entry Points -=================================================== - -If you would like to document your project that has Briefcase entry points, -follow the `doc contributing guide`_ to update this page. - -.. _doc contributing guide: https://briefcase.readthedocs.io/en/latest/how-to/contribute-docs.html - -Briefcase provides entry points for several projects, but the ideal scenario -is for the projects themselves to implement entry points that briefcase can use. - -A sample pull request that implements this type of entry point can be found at -this `pygame-ce pull request`_ - -.. _pygame-ce pull request: https://github.com/pygame-community/pygame-ce/pull/2862 - -`pygame-ce`_ ---------------------- -Pygame-ce is a modern fork of pygame, the classic library for making games in Python. - -.. _pygame-ce: https://github.com/pygame-community/pygame-ce 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 0b466fcf5..82949e195 100644 --- a/docs/spelling_wordlist +++ b/docs/spelling_wordlist @@ -89,6 +89,7 @@ submodule subprocesses tl toml +toolkits towncrier tox TTY diff --git a/src/briefcase/commands/new.py b/src/briefcase/commands/new.py index 8f99dcac7..65f32da97 100644 --- a/src/briefcase/commands/new.py +++ b/src/briefcase/commands/new.py @@ -599,13 +599,14 @@ def build_gui_context( if self.validate_selection_override(bootstraps.keys(), bootstrap_override): bootstrap_override = reverse_lookup[bootstraps[bootstrap_override]] - EXTERNAL_HOOKS_SUPPORT = ( - "Known external entry points documented " - "at https://briefcase.readthedocs.io/en/latest/reference/known-external-hooks.html" - ) - selected_bootstrap = self.select_option( - intro=f"What GUI toolkit do you want to use for this project?\n{EXTERNAL_HOOKS_SUPPORT}", + 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(), From b43102c47aa2ed5a6c954bd8aac94f4ed917aa26 Mon Sep 17 00:00:00 2001 From: Russell Martin Date: Tue, 28 May 2024 19:42:03 -0400 Subject: [PATCH 07/22] Defer to `install_requirement.py` in `beeware/.github` --- .github/workflows/ci.yml | 22 +++-- changes/1847.misc.rst | 1 + install_requirement.py | 179 --------------------------------------- tox.ini | 14 +-- 4 files changed, 13 insertions(+), 203 deletions(-) create mode 100644 changes/1847.misc.rst delete mode 100644 install_requirement.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6f4fc563b..e8e9afad8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -82,12 +82,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 +128,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 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/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/tox.ini b/tox.ini index be9bbba55..f6073c7d5 100644 --- a/tox.ini +++ b/tox.ini @@ -31,12 +31,7 @@ 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}" +extras = dev commands = pre-commit run --all-files --show-diff-on-failure --color=always [testenv:py{,38,39,310,311,312,313}{,-fast,-cov}] @@ -55,7 +50,6 @@ commands = [testenv:coverage{,38,39,310,311,312,313}{,-ci}{,-platform,-platform-linux,-platform-macos,-platform-windows,-project}{,-keep}{,-html}] 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 +75,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 From 6a6b120476a892ad9f147b311582d0a488103428 Mon Sep 17 00:00:00 2001 From: Russell Martin Date: Tue, 28 May 2024 21:00:06 -0400 Subject: [PATCH 08/22] Build wheels in tox --- tox.ini | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tox.ini b/tox.ini index f6073c7d5..964aa1052 100644 --- a/tox.ini +++ b/tox.ini @@ -31,6 +31,8 @@ labels = skip_missing_interpreters = True [testenv:pre-commit] +package = wheel +wheel_build_env = .pkg extras = dev commands = pre-commit run --all-files --show-diff-on-failure --color=always @@ -49,6 +51,8 @@ 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} # 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. From 46d88649780bf993f187f30ca99e6697ae17e12d Mon Sep 17 00:00:00 2001 From: Russell Martin Date: Mon, 27 May 2024 15:30:05 -0400 Subject: [PATCH 09/22] Use new create package action with attestation (forked repo action) --- .github/workflows/ci.yml | 37 ++++++++++++++++++++++++++++------- .github/workflows/release.yml | 4 +++- changes/1843.misc.rst | 1 + tox.ini | 11 ----------- 4 files changed, 34 insertions(+), 19 deletions(-) create mode 100644 changes/1843.misc.rst diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e8e9afad8..5809d409c 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,26 @@ jobs: uses: beeware/.github/.github/workflows/towncrier-run.yml@main package: - name: Python package - uses: beeware/.github/.github/workflows/python-package-create.yml@main + name: Package Briefcase + permissions: + id-token: write + contents: read + attestations: write +# uses: beeware/.github/.github/workflows/python-package-create.yml@main + uses: rmartin16/.github-beeware/.github/workflows/python-package-create.yml@hynek-build 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 + uses: rmartin16/.github-beeware/.github/workflows/python-package-create.yml@hynek-build + with: + build-subdirectory: "automation" unit-tests: name: Unit tests @@ -160,8 +181,9 @@ jobs: verify-projects: name: Verify project - needs: unit-tests - uses: beeware/.github/.github/workflows/app-create-verify.yml@main + needs: [ package, package-automation, unit-tests ] +# uses: beeware/.github/.github/workflows/app-create-verify.yml@main + uses: rmartin16/.github-beeware/.github/workflows/app-create-verify.yml@hynek-build with: runner-os: ${{ matrix.runner-os }} framework: ${{ matrix.framework }} @@ -173,8 +195,9 @@ jobs: verify-apps: name: Build app - needs: unit-tests - uses: beeware/.github/.github/workflows/app-build-verify.yml@main + needs: [ package, package-automation, unit-tests ] +# uses: beeware/.github/.github/workflows/app-build-verify.yml@main + uses: rmartin16/.github-beeware/.github/workflows/app-build-verify.yml@hynek-build with: # This *must* be the version of Python that is the system Python on the # Ubuntu version used to run Linux tests. We use a fixed ubuntu-22.04 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/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/tox.ini b/tox.ini index 964aa1052..1b1543e66 100644 --- a/tox.ini +++ b/tox.ini @@ -122,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{/}* From 8825689bb4a1853d34ae08fcff6b18503f815a4d Mon Sep 17 00:00:00 2001 From: Russell Martin Date: Wed, 29 May 2024 09:32:41 -0400 Subject: [PATCH 10/22] Restore `python-package-create.yml` back to `beeware:main` --- .github/workflows/ci.yml | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5809d409c..f97540b1d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,8 +42,7 @@ jobs: id-token: write contents: read attestations: write -# uses: beeware/.github/.github/workflows/python-package-create.yml@main - uses: rmartin16/.github-beeware/.github/workflows/python-package-create.yml@hynek-build + uses: beeware/.github/.github/workflows/python-package-create.yml@main with: attest: ${{ inputs.attest-package }} @@ -53,8 +52,7 @@ jobs: id-token: write contents: read attestations: write -# uses: beeware/.github/.github/workflows/python-package-create.yml@main - uses: rmartin16/.github-beeware/.github/workflows/python-package-create.yml@hynek-build + uses: beeware/.github/.github/workflows/python-package-create.yml@main with: build-subdirectory: "automation" @@ -182,8 +180,7 @@ jobs: verify-projects: name: Verify project needs: [ package, package-automation, unit-tests ] -# uses: beeware/.github/.github/workflows/app-create-verify.yml@main - uses: rmartin16/.github-beeware/.github/workflows/app-create-verify.yml@hynek-build + uses: beeware/.github/.github/workflows/app-create-verify.yml@main with: runner-os: ${{ matrix.runner-os }} framework: ${{ matrix.framework }} @@ -196,8 +193,7 @@ jobs: verify-apps: name: Build app needs: [ package, package-automation, unit-tests ] -# uses: beeware/.github/.github/workflows/app-build-verify.yml@main - uses: rmartin16/.github-beeware/.github/workflows/app-build-verify.yml@hynek-build + 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 # Ubuntu version used to run Linux tests. We use a fixed ubuntu-22.04 From aff0c970333944fd2a443ecc4353c60aa2374a8c Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Thu, 30 May 2024 13:58:53 +0800 Subject: [PATCH 11/22] Apply suggestions from code review Co-authored-by: Malcolm Smith --- docs/reference/platforms/macOS/app.rst | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) 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 =========== From b402e32ea579d3514969ab29108bfbaf0d9b600e Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Thu, 30 May 2024 13:53:56 +0800 Subject: [PATCH 12/22] Clarify the effect of enabling console_app --- docs/reference/configuration.rst | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/reference/configuration.rst b/docs/reference/configuration.rst index 9d043db64..4b11b28b1 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`` ~~~~~~~~~~~~~~ From c2b72906ce6fa10895d334e3739d803cda1ac1e8 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Thu, 30 May 2024 14:01:17 +0800 Subject: [PATCH 13/22] Add a UUID cookiecutter extension. --- src/briefcase/integrations/cookiecutter.py | 16 ++++++++++++++++ .../cookiecutter/test_UUIDExtension.py | 19 +++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 tests/integrations/cookiecutter/test_UUIDExtension.py diff --git a/src/briefcase/integrations/cookiecutter.py b/src/briefcase/integrations/cookiecutter.py index 3c66ffd06..8367b94c7 100644 --- a/src/briefcase/integrations/cookiecutter.py +++ b/src/briefcase/integrations/cookiecutter.py @@ -1,5 +1,7 @@ """Jinja2 extensions.""" +import uuid + from jinja2.ext import Extension @@ -116,3 +118,17 @@ def bool_attr(obj): return "true" if obj else "false" environment.filters["bool_attr"] = bool_attr + + +class UUIDExtension(Extension): + """Extensions for generating UUIDs.""" + + def __init__(self, environment): + """Initialize the extension with the given environment.""" + super().__init__(environment) + + def dns_uuid5(obj): + """A DNS-based UUID5 object generated from the provided content.""" + return str(uuid.uuid5(uuid.NAMESPACE_DNS, obj)) + + environment.filters["dns_uuid5"] = dns_uuid5 diff --git a/tests/integrations/cookiecutter/test_UUIDExtension.py b/tests/integrations/cookiecutter/test_UUIDExtension.py new file mode 100644 index 000000000..6be2ebd28 --- /dev/null +++ b/tests/integrations/cookiecutter/test_UUIDExtension.py @@ -0,0 +1,19 @@ +from unittest.mock import MagicMock + +import pytest + +from briefcase.integrations.cookiecutter import UUIDExtension + + +@pytest.mark.parametrize( + "value, expected", + [ + ("example.com", "cfbff0d1-9375-5685-968c-48ce8b15ae17"), + ("foobar.example.com", "941bbcd9-03e1-568a-a728-8434055bc338"), + ], +) +def test_dns_uuid5_value(value, expected): + env = MagicMock() + env.filters = {} + UUIDExtension(env) + assert env.filters["dns_uuid5"](value) == expected From ba536544727150519893cf1e6c9e7b1c72b0c200 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Thu, 30 May 2024 14:03:24 +0800 Subject: [PATCH 14/22] Added a changenote. --- changes/1850.misc.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 changes/1850.misc.rst 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. From dfef1842f422b80ce8bee398ac36e6204a4a6640 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 2 Jun 2024 20:25:45 +0000 Subject: [PATCH 15/22] Bump coverage[toml] from 7.5.2 to 7.5.3 Bumps [coverage[toml]](https://github.com/nedbat/coveragepy) from 7.5.2 to 7.5.3. - [Release notes](https://github.com/nedbat/coveragepy/releases) - [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst) - [Commits](https://github.com/nedbat/coveragepy/compare/7.5.2...7.5.3) --- updated-dependencies: - dependency-name: coverage[toml] dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 7a3141eb7..47e37ac27 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -96,7 +96,7 @@ 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'", From a098c2f5b0391b6dbd2726680eed106bfe27520d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 2 Jun 2024 20:25:57 +0000 Subject: [PATCH 16/22] Add changenote. [dependabot skip] --- changes/1853.misc.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 changes/1853.misc.rst 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. From 66ce674afb59068d8197d75f5a8631c8f379a722 Mon Sep 17 00:00:00 2001 From: Russell Martin Date: Thu, 30 May 2024 12:07:14 -0400 Subject: [PATCH 17/22] Update warning for pyproject.toml license spec --- changes/1851.misc.rst | 1 + src/briefcase/config.py | 44 +++++++---- tests/config/test_parse_config.py | 119 ++++++++++++++++++++++++++++-- 3 files changed, 146 insertions(+), 18 deletions(-) create mode 100644 changes/1851.misc.rst 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/src/briefcase/config.py b/src/briefcase/config.py index e100e93cd..c1d793642 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 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" + +************************************************************************* +""" + ), + ] ) From ee6eebdd231f011c3110545fe79db4c487b4a0e3 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Mon, 3 Jun 2024 10:58:12 +0800 Subject: [PATCH 18/22] Normalize the Xcode docs. --- docs/reference/platforms/macOS/xcode.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 =========== From 53e69586911d8acca362a6953ac1013b08e36e67 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Mon, 3 Jun 2024 11:06:54 +0800 Subject: [PATCH 19/22] Speculation... is xdist the problem? --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 47e37ac27..863696553 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -102,7 +102,6 @@ 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", "setuptools_scm == 8.1.0", "tox == 4.15.0", ] From 23810b0ee80a9aa548edbad5e4decf450492460f Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Mon, 3 Jun 2024 11:25:41 +0800 Subject: [PATCH 20/22] Revert to previous xdist release. --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 863696553..a58eb8acd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -102,6 +102,7 @@ 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.5.0", "setuptools_scm == 8.1.0", "tox == 4.15.0", ] From bb3ad799c0da80a7e84d69f83f058ae74da684be Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Mon, 3 Jun 2024 12:12:28 +0800 Subject: [PATCH 21/22] Only disable pytest for Python 3.13 (for now). --- pyproject.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index a58eb8acd..9b57e6c20 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.5.0", + # 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", ] From 9c0f09c1a94b8b9cc4ce378c7b5736013f576151 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Wed, 5 Jun 2024 06:57:28 +0800 Subject: [PATCH 22/22] Ensure return status of subprocesses is checked. --- src/briefcase/platforms/macOS/__init__.py | 6 ++-- .../macOS/app/package/test_package_pkg.py | 30 ++++++++++++------- 2 files changed, 24 insertions(+), 12 deletions(-) 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/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, ), ]