Skip to content

Commit

Permalink
Modify pip handling to use platform tag for iOS. (#2101)
Browse files Browse the repository at this point in the history
* Modify pip handling to use platform tag for iOS.

* Add documentation note about requiring wheels.

* Add changenote.
  • Loading branch information
freakboy3742 authored Jan 6, 2025
1 parent 5311423 commit c83c495
Show file tree
Hide file tree
Showing 8 changed files with 93 additions and 88 deletions.
1 change: 1 addition & 0 deletions changes/2101.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Briefcase now uses native pip handling for cross-platform installs, rather than the site-based shim.
35 changes: 29 additions & 6 deletions docs/reference/platforms/iOS/xcode.rst
Original file line number Diff line number Diff line change
Expand Up @@ -133,13 +133,12 @@ PyPI to provide those wheels. Briefcase uses a `secondary repository

This repository is maintained by the BeeWare project, and as a result, it does not have
binary wheels for *every* package that is available on PyPI, or even every *version* of
every package that is on PyPI. If you see any of the following messages when building an
app for a mobile platform, then the package (or this version of it) probably isn't
supported yet:
every package that is on PyPI. If you see the message::

* The error "Cannot compile native modules"
* A reference to downloading a ``.tar.gz`` version of the package
* A reference to ``Building wheels for collected packages: <package>``
ERROR: Could not find a version that satisfies the requirement <package name> (from versions: none)
ERROR: No matching distribution found for <package name>

then the package (or the version that you've specified) probably isn't supported yet.

It is *usually* possible to compile any binary package wheels for iOS, depending on the
requirements of the package itself. If the package has a dependency on other binary
Expand All @@ -157,3 +156,27 @@ Contributions of new package recipes are welcome, and can be submitted as pull r
Or, if you have a particular package that you'd like us to support, please visit the
`issue tracker <https://github.com/beeware/mobile-forge/issues>`__ and provide details
about that package.

Requirements cannot be provided as source tarballs
--------------------------------------------------

Briefcase *cannot* install packages published as source tarballs into an iOS 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.

If you need to install a package in an iOS 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'll need to use `Mobile Forge
<https://github.com/beeware/mobile-forge>`__ (or similar tooling) to compile compatible
wheels.

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.
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ dependencies = [
#
# limited to <=3.9 for the `group` argument for `entry_points()`
"importlib_metadata >= 4.4; python_version <= '3.9'",
"packaging >= 22.0",
"pip >= 23.1.2",
"packaging >= 24.2",
"pip >= 24.3",
"setuptools >= 60",
"wheel >= 0.37",
"build >= 0.10",
Expand Down
7 changes: 6 additions & 1 deletion src/briefcase/commands/create.py
Original file line number Diff line number Diff line change
Expand Up @@ -622,6 +622,7 @@ def _install_app_requirements(
requires: list[str],
app_packages_path: Path,
progress_message: str = "Installing app requirements...",
pip_args: list[str] | None = None,
pip_kwargs: dict[str, str] | None = None,
):
"""Install requirements for the app with pip.
Expand All @@ -631,6 +632,7 @@ def _install_app_requirements(
:param app_packages_path: The full path of the app_packages folder into which
requirements should be installed.
:param progress_message: The waitbar progress message to display to the user.
:param pip_args: Any additional command line arguments to use when invoking pip.
:param pip_kwargs: Any additional keyword arguments to pass to the subprocess
when invoking pip.
"""
Expand All @@ -645,7 +647,10 @@ def _install_app_requirements(
self._pip_install(
app,
app_packages_path=app_packages_path,
pip_args=self._pip_requires(app, requires),
pip_args=(
([] if pip_args is None else pip_args)
+ self._pip_requires(app, requires)
),
**(pip_kwargs if pip_kwargs else {}),
)
else:
Expand Down
36 changes: 19 additions & 17 deletions src/briefcase/platforms/iOS/xcode.py
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ def _extra_pip_args(self, app: AppConfig):
:returns: A list of additional arguments
"""
return super()._extra_pip_args(app) + [
"--prefer-binary",
"--only-binary=:all:",
"--extra-index-url",
"https://pypi.anaconda.org/beeware/simple",
]
Expand All @@ -317,19 +317,27 @@ def _install_app_requirements(
requires: list[str],
app_packages_path: Path,
):
# Determine the min iOS 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
)
ios_min_tag = versions.get("Min iOS version", "13.0").replace(".", "_")

# Perform the initial install pass targeting the "iphoneos" platform
super()._install_app_requirements(
app,
requires=requires,
app_packages_path=app_packages_path.parent / "app_packages.iphoneos",
progress_message="Installing app requirements for iPhone device...",
pip_kwargs={
"env": {
"PYTHONPATH": str(
self.support_path(app) / "platform-site/iphoneos.arm64"
),
}
},
pip_args=[
f"--platform=ios_{ios_min_tag}_arm64_iphoneos",
],
)

# Perform a second install pass targeting the "iphonesimulator" platform for the
Expand All @@ -339,15 +347,9 @@ def _install_app_requirements(
requires=requires,
app_packages_path=app_packages_path.parent / "app_packages.iphonesimulator",
progress_message="Installing app requirements for iPhone simulator...",
pip_kwargs={
"env": {
"PYTHONPATH": str(
self.support_path(app)
/ "platform-site"
/ f"iphonesimulator.{self.tools.host_arch}"
),
}
},
pip_args=[
f"--platform=ios_{ios_min_tag}_{self.tools.host_arch}_iphonesimulator",
],
)


Expand Down
34 changes: 28 additions & 6 deletions tests/platforms/iOS/xcode/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,15 @@ def first_app_generated(first_app_config, tmp_path):
/ "ios"
/ "xcode"
/ "briefcase.toml",
"""
[paths]
app_packages_path="app_packages"
support_path="support"
info_plist_path="Info.plist"
""",
"\n".join(
[
"[paths]",
'app_packages_path="app_packages"',
'support_path="Support"',
'info_plist_path="Info.plist"',
"",
],
),
)

create_plist_file(
Expand All @@ -28,4 +31,23 @@ def first_app_generated(first_app_config, tmp_path):
"MainModule": "first_app",
},
)

# Create the support package VERSIONS file
# with a deliberately weird min iOS version
create_file(
tmp_path / "base_path/build/first-app/ios/xcode/Support/VERSIONS",
"\n".join(
[
"Python version: 3.10.15",
"Build: b11",
"Min iOS version: 14.2",
"---------------------",
"BZip2: 1.0.8-1",
"libFFI: 3.4.6-1",
"OpenSSL: 3.0.15-1",
"XZ: 5.6.2-1",
"",
]
),
)
return first_app_config
32 changes: 4 additions & 28 deletions tests/platforms/iOS/xcode/test_create.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,27 +61,15 @@ def test_extra_pip_args(create_command, first_app_generated, tmp_path):
"--upgrade",
"--no-user",
f"--target={bundle_path / 'app_packages.iphoneos'}",
"--prefer-binary",
"--only-binary=:all:",
"--extra-index-url",
"https://pypi.anaconda.org/beeware/simple",
"--platform=ios_14_2_arm64_iphoneos",
"something==1.2.3",
"other>=2.3.4",
],
check=True,
encoding="UTF-8",
env={
"PYTHONPATH": str(
tmp_path
/ "base_path"
/ "build"
/ "first-app"
/ "ios"
/ "xcode"
/ "support"
/ "platform-site"
/ "iphoneos.arm64"
)
},
),
call(
[
Expand All @@ -97,27 +85,15 @@ def test_extra_pip_args(create_command, first_app_generated, tmp_path):
"--upgrade",
"--no-user",
f"--target={bundle_path / 'app_packages.iphonesimulator'}",
"--prefer-binary",
"--only-binary=:all:",
"--extra-index-url",
"https://pypi.anaconda.org/beeware/simple",
"--platform=ios_14_2_wonky_iphonesimulator",
"something==1.2.3",
"other>=2.3.4",
],
check=True,
encoding="UTF-8",
env={
"PYTHONPATH": str(
tmp_path
/ "base_path"
/ "build"
/ "first-app"
/ "ios"
/ "xcode"
/ "support"
/ "platform-site"
/ "iphonesimulator.wonky"
)
},
),
]

Expand Down
32 changes: 4 additions & 28 deletions tests/platforms/iOS/xcode/test_update.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,27 +48,15 @@ def test_extra_pip_args(update_command, first_app_generated, tmp_path):
"--upgrade",
"--no-user",
f"--target={bundle_path / 'app_packages.iphoneos'}",
"--prefer-binary",
"--only-binary=:all:",
"--extra-index-url",
"https://pypi.anaconda.org/beeware/simple",
"--platform=ios_14_2_arm64_iphoneos",
"something==1.2.3",
"other>=2.3.4",
],
check=True,
encoding="UTF-8",
env={
"PYTHONPATH": str(
tmp_path
/ "base_path"
/ "build"
/ "first-app"
/ "ios"
/ "xcode"
/ "support"
/ "platform-site"
/ "iphoneos.arm64"
)
},
),
call(
[
Expand All @@ -84,26 +72,14 @@ def test_extra_pip_args(update_command, first_app_generated, tmp_path):
"--upgrade",
"--no-user",
f"--target={bundle_path / 'app_packages.iphonesimulator'}",
"--prefer-binary",
"--only-binary=:all:",
"--extra-index-url",
"https://pypi.anaconda.org/beeware/simple",
"--platform=ios_14_2_wonky_iphonesimulator",
"something==1.2.3",
"other>=2.3.4",
],
check=True,
encoding="UTF-8",
env={
"PYTHONPATH": str(
tmp_path
/ "base_path"
/ "build"
/ "first-app"
/ "ios"
/ "xcode"
/ "support"
/ "platform-site"
/ "iphonesimulator.wonky"
)
},
),
]

0 comments on commit c83c495

Please sign in to comment.