Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove use of platform-site for other-arch macOS wheel installs. #2163

Merged
merged 6 commits into from
Feb 18, 2025
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changes/2163.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The iOS log filter was improved to hide an ignorable message about ``getpwuid_r``.
1 change: 1 addition & 0 deletions changes/2163.removal.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Briefcase can no longer install pure Python macOS packages from a source archive (i.e., a ``.tar.gz`` file published on PyPI). If a package is pure Python, it *must* be provided as a ``py3-none-any`` wheel. Briefcase's `macOS platform documentation <https://briefcase.readthedocs.io/en/latest/reference/platforms/macOS/index.html>`__ contains details on how to provide a ``py3-none-any`` wheel when PyPI does not provide one.
26 changes: 26 additions & 0 deletions docs/reference/platforms/macOS/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,29 @@ signed app bundle.

app
xcode

Platform quirks
===============

Requirements cannot be provided as source tarballs
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Briefcase *cannot* install packages published as source tarballs into a macOS app, even
if the package is a pure Python package that would produce a ``py3-none-any`` wheel.
This is an inherent limitation in the use of source tarballs as a distribution format.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's not really true; it's a limitation in Briefcase.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll stand by this statement. It's not possible to tell purely from a tarball whether a package will produce a binary or non-binary wheel, or to establish anything about the build environments that are supported by the project. That's an inherent limitation in source tarballs as a distribution format for Python artefacts.


If you need to install a package in a macOS app that is only published as a source
tarball, you'll need to compile that package into a wheel first. If the package is pure
Python, you can generate a ``py3-none-any`` wheel using ``pip wheel <package name>``. If
the project has a binary component, you will need to consult the documentation of the
package to determine how to compile a wheel.

You can then directly add the wheel file to the ``requires`` definition for your app, or
put the wheel in a folder and add:

.. code-block:: TOML

requirement_installer_args = ["--find-links", "<path-to-wheel-folder>"]

to your ``pyproject.toml``. This will instruct Briefcase to search that folder for
compatible wheels during the installation process.
23 changes: 16 additions & 7 deletions src/briefcase/platforms/macOS/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ def _install_app_requirements(
app,
requires=requires,
app_packages_path=host_app_packages_path,
pip_args=["--only-binary", ":all:"],
)

# Find all the packages with binary components.
Expand All @@ -108,6 +109,18 @@ def _install_app_requirements(
universal_suffix="_universal2",
)

# Determine the min macOS version from the VERSIONS file in the support package.
versions = dict(
[part.strip() for part in line.split(": ", 1)]
for line in (
(self.support_path(app) / "VERSIONS")
.read_text(encoding="UTF-8")
.split("\n")
)
if ": " in line
)
macOS_min_tag = versions.get("Min macOS version", "11.0").replace(".", "_")

# Now install dependencies for the architecture that isn't the host architecture.
other_arch = {
"arm64": "x86_64",
Expand All @@ -131,6 +144,8 @@ def _install_app_requirements(
app_packages_path=other_app_packages_path,
pip_args=[
"--no-deps",
"--platform",
f"macosx_{macOS_min_tag}_{other_arch}",
"--only-binary",
":all:",
]
Expand All @@ -147,13 +162,6 @@ def _install_app_requirements(

in the macOS configuration section of your pyproject.toml.
""",
env={
"PYTHONPATH": str(
self.support_path(app)
/ "platform-site"
/ f"macosx.{other_arch}"
)
},
)
else:
self.console.info("All packages are pure Python, or universal.")
Expand Down Expand Up @@ -185,6 +193,7 @@ def _install_app_requirements(
app,
requires=requires,
app_packages_path=app_packages_path,
pip_args=["--only-binary", ":all:"],
)

# Since we're only targeting 1 architecture, we can strip any universal
Expand Down
3 changes: 2 additions & 1 deletion src/briefcase/platforms/macOS/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ def macOS_log_clean_filter(line):
line.startswith("Filtering the log data using "),
# Log stream outputs barely useful column headers on startup
line.startswith("Timestamp "),
# iOS reports an ignorable error on startup
# iOS reports ignorable errors on startup
line.startswith("Error from getpwuid_r:"),
line.startswith("getpwuid_r did not find a match "),
]
):
return None
Expand Down
14 changes: 14 additions & 0 deletions tests/platforms/macOS/app/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,20 @@ def first_app_templated(first_app_config, tmp_path):
"""<?xml?>\n<installer-script></installer-script>""",
)

# Create the support package VERSIONS file
# with a deliberately weird min macOS version
create_file(
tmp_path / "base_path/build/first-app/macos/app/support/VERSIONS",
"\n".join(
[
"Python version: 3.10.15",
"Build: b11",
"Min macOS version: 15.2",
"",
]
),
)

# Select dmg packaging by default
first_app_config.packaging_format = "dmg"

Expand Down
20 changes: 12 additions & 8 deletions tests/platforms/macOS/app/test_create.py
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,8 @@ def test_install_app_packages(
"--upgrade",
"--no-user",
f"--target={bundle_path / ('app_packages.' + host_arch)}",
"--only-binary",
":all:",
"first",
"second==1.2.3",
"third>=3.2.1",
Expand All @@ -395,18 +397,15 @@ def test_install_app_packages(
"--no-user",
f"--target={bundle_path / ('app_packages.' + other_arch)}",
"--no-deps",
"--platform",
f"macosx_15_2_{other_arch}",
"--only-binary",
":all:",
"second==1.2.3",
"third==3.4.5",
],
check=True,
encoding="UTF-8",
env={
"PYTHONPATH": str(
bundle_path / "support/platform-site" / f"macosx.{other_arch}"
)
},
),
]

Expand Down Expand Up @@ -490,6 +489,8 @@ def test_install_app_packages_no_binary(
"--upgrade",
"--no-user",
f"--target={bundle_path / ('app_packages.' + host_arch)}",
"--only-binary",
":all:",
"first",
"second==1.2.3",
"third>=3.2.1",
Expand Down Expand Up @@ -586,6 +587,8 @@ def test_install_app_packages_failure(create_command, first_app_templated, tmp_p
"--upgrade",
"--no-user",
f"--target={bundle_path / 'app_packages.arm64'}",
"--only-binary",
":all:",
"first",
"second==1.2.3",
"third>=3.2.1",
Expand All @@ -609,16 +612,15 @@ def test_install_app_packages_failure(create_command, first_app_templated, tmp_p
"--no-user",
f"--target={bundle_path / 'app_packages.x86_64'}",
"--no-deps",
"--platform",
"macosx_15_2_x86_64",
"--only-binary",
":all:",
"second==1.2.3",
"third==3.4.5",
],
check=True,
encoding="UTF-8",
env={
"PYTHONPATH": str(bundle_path / "support/platform-site/macosx.x86_64")
},
),
]

Expand Down Expand Up @@ -683,6 +685,8 @@ def test_install_app_packages_non_universal(
"--upgrade",
"--no-user",
f"--target={bundle_path / 'First App.app' / 'Contents' / 'Resources' / 'app_packages'}",
"--only-binary",
":all:",
"first",
"second==1.2.3",
"third>=3.2.1",
Expand Down
4 changes: 4 additions & 0 deletions tests/platforms/macOS/test_macOS_log_clean_filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@
"Error from getpwuid_r: 0 (Undefined error: 0)",
None,
),
(
"getpwuid_r did not find a match for uid 501",
None,
),
(
'Filtering the log data using "senderImagePath ENDSWITH "/Toga Test!" '
'OR (processImagePath ENDSWITH "/Toga Test!" '
Expand Down
Loading