diff --git a/Doc/library/urllib.parse.rst b/Doc/library/urllib.parse.rst index 9de30a182f4778..8c5400e1143964 100644 --- a/Doc/library/urllib.parse.rst +++ b/Doc/library/urllib.parse.rst @@ -27,6 +27,14 @@ Resource Locators. It supports the following URL schemes: ``file``, ``ftp``, ``shttp``, ``sip``, ``sips``, ``snews``, ``svn``, ``svn+ssh``, ``telnet``, ``wais``, ``ws``, ``wss``. +.. impl-detail:: + + The inclusion of the ``itms-services`` URL scheme can prevent an app from + passing Apple's App Store review process for the macOS and iOS App Stores. + Handling for the ``itms-services`` scheme is always removed on iOS; on + macOS, it *may* be removed if CPython has been built with the + :option:`--with-app-store-compliance` option. + The :mod:`urllib.parse` module defines functions that fall into two broad categories: URL parsing and URL quoting. These are covered in detail in the following sections. diff --git a/Doc/using/mac.rst b/Doc/using/mac.rst index f7db038430b6d3..e218fe3116045a 100644 --- a/Doc/using/mac.rst +++ b/Doc/using/mac.rst @@ -163,6 +163,28 @@ The standard tool for deploying standalone Python applications on the Mac is at https://pypi.org/project/py2app/. +App Store Compliance +-------------------- + +Apps submitted for distribution through the macOS App Store must pass Apple's +app review process. This process includes a set of automated validation rules +that inspect the submitted application bundle for problematic code. + +The Python standard library contains some code that is known to violate these +automated rules. While these violations appear to be false positives, Apple's +review rules cannot be challenged. Therefore, it is necessary to modify the +Python standard library for an app to pass App Store review. + +The Python source tree contains +:source:`a patch file ` that will remove +all code that is known to cause issues with the App Store review process. This +patch is applied automatically when CPython is configured with the +:option:`--with-app-store-compliance` option. + +This patch is not normally required to use CPython on a Mac; nor is it required +if you are distributing an app *outside* the macOS App Store. It is *only* +required if you are using the macOS App Store as a distribution channel. + Other Resources =============== diff --git a/Mac/Resources/app-store-compliance.patch b/Mac/Resources/app-store-compliance.patch new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/Makefile.pre.in b/Makefile.pre.in index 54fbca3b3ef84e..4da3462959e4fb 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -168,6 +168,9 @@ EXPORTSFROM= @EXPORTSFROM@ EXE= @EXEEXT@ BUILDEXE= @BUILDEXEEXT@ +# Name of the patch file to apply for app store compliance +APP_STORE_COMPLIANCE_PATCH=@APP_STORE_COMPLIANCE_PATCH@ + # Short name and location for Mac OS X Python framework UNIVERSALSDK=@UNIVERSALSDK@ PYTHONFRAMEWORK= @PYTHONFRAMEWORK@ @@ -483,7 +486,7 @@ DTRACE_DEPS = \ # Default target all: @DEF_MAKE_ALL_RULE@ -build_all: check-clean-src $(BUILDPYTHON) oldsharedmods sharedmods gdbhooks \ +build_all: check-clean-src check-app-store-compliance $(BUILDPYTHON) oldsharedmods sharedmods gdbhooks \ Programs/_testembed python-config # Check that the source is clean when building out of source. @@ -495,6 +498,16 @@ check-clean-src: exit 1; \ fi +# Check that the app store compliance patch can be applied (if configured). +# This is checked as a dry-run against the original library sources; +# the patch will be actually applied during the install phase. +.PHONY: check-app-store-compliance +check-app-store-compliance: + @if [ "$(APP_STORE_COMPLIANCE_PATCH)" != "" ]; then \ + patch --dry-run --quiet --force --strip 1 --directory "$(abs_srcdir)" --input "$(abs_srcdir)/$(APP_STORE_COMPLIANCE_PATCH)"; \ + echo "App store compliance patch can be applied."; \ + fi + # Profile generation build must start from a clean tree. profile-clean-stamp: $(MAKE) clean @@ -1626,7 +1639,16 @@ libinstall: build_all $(srcdir)/Modules/xxmodule.c $(INSTALL_DATA) $(srcdir)/Modules/xxmodule.c \ $(DESTDIR)$(LIBDEST)/distutils/tests ; \ fi - -PYTHONPATH=$(DESTDIR)$(LIBDEST) $(RUNSHARED) \ + @ # If app store compliance has been configured, apply the patch to the + @ # installed library code. The patch has been previously validated against + @ # the original source tree, so we can ignore any errors that are raised + @ # due to files that are missing because of --disable-test-modules etc. + @if [ "$(APP_STORE_COMPLIANCE_PATCH)" != "" ]; then \ + echo "Applying app store compliance patch"; \ + patch --force --reject-file "$(abs_builddir)/app-store-compliance.rej" --strip 2 --directory "$(DESTDIR)$(LIBDEST)" --input "$(abs_srcdir)/$(APP_STORE_COMPLIANCE_PATCH)" || true ; \ + fi + @ # Build PYC files for the 3 optimization levels (0, 1, 2) + -PYTHONPATH=$(DESTDIR)$(LIBDEST) $(RUNSHARED) \ $(PYTHON_FOR_BUILD) -Wi $(DESTDIR)$(LIBDEST)/compileall.py \ -j0 -d $(LIBDEST) -f \ -x 'bad_coding|badsyntax|site-packages|lib2to3/tests/data' \ diff --git a/Misc/NEWS.d/next/Build/2024-07-18-07-53-07.gh-issue-120522.dg3o5A.rst b/Misc/NEWS.d/next/Build/2024-07-18-07-53-07.gh-issue-120522.dg3o5A.rst new file mode 100644 index 00000000000000..e90c625a886b65 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2024-07-18-07-53-07.gh-issue-120522.dg3o5A.rst @@ -0,0 +1,2 @@ +Added a :option:`--with-app-store-compliance` option to patch out known +issues with macOS/iOS App Store review processes. diff --git a/configure b/configure index 6f76ee435ca882..677502d4673841 100755 --- a/configure +++ b/configure @@ -737,6 +737,7 @@ IPHONEOS_DEPLOYMENT_TARGET EXPORT_MACOSX_DEPLOYMENT_TARGET CONFIGURE_MACOSX_DEPLOYMENT_TARGET _PYTHON_HOST_PLATFORM +APP_STORE_COMPLIANCE_PATCH INSTALLTARGETS FRAMEWORKINSTALLAPPSPREFIX FRAMEWORKUNIXTOOLSPREFIX @@ -820,6 +821,7 @@ enable_universalsdk with_universal_archs with_framework_name enable_framework +with_app_store_compliance with_cxx_main with_suffix enable_shared @@ -1524,6 +1526,10 @@ Optional Packages: specify the name for the python framework on macOS only valid when --enable-framework is set. see Mac/README.rst (default is 'Python') + --with-app-store-compliance=[PATCH-FILE] + Enable any patches required for compiliance with app + stores. Optional PATCH-FILE specifies the custom + patch to apply. --with-cxx-main[=COMPILER] compile main() and link Python executable with C++ compiler specified in COMPILER (default is $CXX) @@ -3457,6 +3463,52 @@ cat >>confdefs.h <<_ACEOF _ACEOF +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-app-store-compliance" >&5 +$as_echo_n "checking for --with-app-store-compliance... " >&6; } + +# Check whether --with-app_store_compliance was given. +if test "${with_app_store_compliance+set}" = set; then : + withval=$with_app_store_compliance; + case "$withval" in + yes) + case $ac_sys_system in + Darwin|iOS) + # iOS is able to share the macOS patch + APP_STORE_COMPLIANCE_PATCH="Mac/Resources/app-store-compliance.patch" + ;; + *) as_fn_error $? "no default app store compliance patch available for $ac_sys_system" "$LINENO" 5 ;; + esac + { $as_echo "$as_me:${as_lineno-$LINENO}: result: applying default app store compliance patch" >&5 +$as_echo "applying default app store compliance patch" >&6; } + ;; + *) + APP_STORE_COMPLIANCE_PATCH="${withval}" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: applying custom app store compliance patch" >&5 +$as_echo "applying custom app store compliance patch" >&6; } + ;; + esac + +else + + case $ac_sys_system in + iOS) + # Always apply the compliance patch on iOS; we can use the macOS patch + APP_STORE_COMPLIANCE_PATCH="Mac/Resources/app-store-compliance.patch" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: applying default app store compliance patch" >&5 +$as_echo "applying default app store compliance patch" >&6; } + ;; + *) + # No default app compliance patching on any other platform + APP_STORE_COMPLIANCE_PATCH= + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not patching for app store compliance" >&5 +$as_echo "not patching for app store compliance" >&6; } + ;; + esac + +fi + + + # Set name for machine-dependent library files diff --git a/configure.ac b/configure.ac index c4af5aa5bc54a4..f303daa52ab1c7 100644 --- a/configure.ac +++ b/configure.ac @@ -541,6 +541,47 @@ AC_SUBST([INSTALLTARGETS]) AC_DEFINE_UNQUOTED(_PYTHONFRAMEWORK, "${PYTHONFRAMEWORK}", [framework name]) +dnl quadrigraphs "@<:@" and "@:>@" produce "[" and "]" in the output +AC_MSG_CHECKING([for --with-app-store-compliance]) +AC_ARG_WITH( + [app_store_compliance], + [AS_HELP_STRING( + [--with-app-store-compliance=@<:@PATCH-FILE@:>@], + [Enable any patches required for compiliance with app stores. + Optional PATCH-FILE specifies the custom patch to apply.] + )],[ + case "$withval" in + yes) + case $ac_sys_system in + Darwin|iOS) + # iOS is able to share the macOS patch + APP_STORE_COMPLIANCE_PATCH="Mac/Resources/app-store-compliance.patch" + ;; + *) AC_MSG_ERROR([no default app store compliance patch available for $ac_sys_system]) ;; + esac + AC_MSG_RESULT([applying default app store compliance patch]) + ;; + *) + APP_STORE_COMPLIANCE_PATCH="${withval}" + AC_MSG_RESULT([applying custom app store compliance patch]) + ;; + esac + ],[ + case $ac_sys_system in + iOS) + # Always apply the compliance patch on iOS; we can use the macOS patch + APP_STORE_COMPLIANCE_PATCH="Mac/Resources/app-store-compliance.patch" + AC_MSG_RESULT([applying default app store compliance patch]) + ;; + *) + # No default app compliance patching on any other platform + APP_STORE_COMPLIANCE_PATCH= + AC_MSG_RESULT([not patching for app store compliance]) + ;; + esac +]) +AC_SUBST([APP_STORE_COMPLIANCE_PATCH]) + AC_SUBST([_PYTHON_HOST_PLATFORM]) # Set name for machine-dependent library files