Python grapples with Apple App Store rejections
An upgrade from Python 3.11 to 3.12 has led to the rejection of some Python apps by Apple's app stores. That led to Eric Froemling submitting a bug report against CPython. That, in turn, led to an interesting discussion among Python developers about how far the project was willing to go to accommodate app store review processes. Developers reached a quick consensus, and a solution that may arrive as soon as Python 3.13.
The problem at hand is that Apple's macOS App Store is automatically rejecting apps that contain the string "itms-services". That is the URL scheme for apps that want to ask Apple's iTunes Store to install another app. Software distributed via Apple's macOS store is sandboxed, and sandboxed apps are prohibited from using URLs with the itms-services scheme. That string is in the urllib parser in Python's standard library, though an application may never actually use the itms-services handler.
Of course, Apple did not do anything so straightforward as to explain this to Froemling. Once he filed an appeal with Apple about the rejection, Apple finally told him that parse.py and parse.pyc were the offending files. After that, he said, it was not hard to track down the problem:
Now in retrospect I'm frustrated I didn't think to run a full text search for itms-services over Python itself earlier or stumble across one of the other cases of folks hitting this.
Russell Keith-Magee started the discussion in the Python Core
Development discussion forum on June 17. He wanted to know whether "acceptable to app
stores
" should be a design goal for CPython, or if that compliance
should be a problem left to the tools that generate application
bundles for app stores.
Paranoid and inscrutable
Keith-Magee noted in his initial question that Apple's review processes were the
most "paranoid and inscrutable
" of app-store-review processes,
but that other app stores also had "validation and acceptance processes
that are entirely opaque
". One solution might be to obfuscate the
offending string to pass review, but that might "lead to an obfuscation arms race
" and
there were no guarantees this would be the last time the project had
to resolve app-validation problems. The other option, he said, was to
consider this to be a distribution problem and leave it to tools like
Briefcase,
py2app, and buildozer to
solve. Traditionally, they have had to patch CPython anyway, he said,
because it did not support Android or iOS "out of the box". But that
will change with Python 3.13 when no patching should be required for
those platforms.
Alex Gaynor suggested that the project try
an approach that Keith-Magee had not put forward inspired by
Gaynor's experience with the cryptography library.
The project often receives complaints that the library refuses
to parse a certificate that is technically invalid, but was in wide
use. He said that the policy was to accept pull
requests that work around those issues "provided they are small,
localized, and generally aren't too awful
".
But, he added, these patches should only be accepted on the condition
that someone complains to the third party (in this case Apple), and extracts
some kind of commitment that they would do something about it. He
suggested that the workaround be time-limited, to give users a decent
experience "while also not letting large firms simply externalize
their bizarre issues onto OSS projects
".
Brandt Bucher wondered
whether obfuscation was even allowed, or if it would be seen as
circumventing the review process. That was a question no one seemed to
have an answer to; and Keith-Magee responded with an 8-Ball emoji and
the phrase "ask again later
." He added that Gaynor's approach
sounded appealing, but it would be like screaming into the
void. Apple, he said, barely has an appeals process and there is no
channel available to the Python project "to raise a complaint that
we could reasonably believe would result in a change of
policy
".
Another approach, suggested
by Alyssa Coghlan, would be to use a JSON configuration file that
urllib would read to set up its module level attributes
"rather than hardcoding its knowledge of all the relevant schemes
".
That could allow app generators to drop "itms-services"
from the configuration file rather than patching urllib.py
directly. Keith-Magee said that could work, but "it strikes me as a
bit of overkill for an edge case
" that could be handled by
obfuscation or distribution-level patching.
On June 20, Keith-Magee wrote that he had thought of another approach: adding a build-time option called "--with-app-store-patch" that removes code that is known to be problematic. He said it would be enabled by default for the iOS platform, and disabled elsewhere. It could be used when building an application for macOS, if the developer intended to distribute that application via the macOS App Store. He suggested that the option could also accept a path to a file with a patch, to allow distributors to provide an updated patch if an app store changes its rules after the maintenance window for a Python release has closed.
Let's paint the bikeshed
Coghlan asked
if it was now time to "paint a config option bikeshed
". She
said that the proposed option name was both too broad and too
narrow. The "app-store" component of the name was too broad, because
it could encompass any app store, not only Apple app stores. The
"patch" component was too narrow, because patch specifies the
method of complying with policies rather than intent. There may be
other methods required to comply with app-store-compliance
checks. Keith-Magee liked the suggestion about dropping "patch" from
the option name, and suggested painting the bikeshed a nice shade of
"--with-app-store-compliance" that would interact with
platform identification to sort out what is required.
On June 25, Keith-Magee thanked participants in the discussion for their input, and pointed to a pull request that would implement the --with-app-store-compliance configuration option. In the request, he noted that it would be possible to use the option with platforms other than iOS or macOS, but there were no use cases for that at present. If all goes well, it should be available in Python 3.13.
It is frustrating that free-software projects like Python have to waste time finding ways around opaque review processes just so developers can write software for non-free platforms. However, the approach taken by Keith-Magee and other CPython developers seems to be the least-bad option that offers the best experience for Python application developers. It will almost certainly not be the last time that a project runs into this problem.
