Python grapples with Apple App Store rejections [LWN subscriber-only content]
Welcome to LWN.net The following subscription-only content has been made available to you by an LWN subscriber. Thousands of subscribers depend on LWN for the best news from the Linux and free software communities. If you enjoy this article, please consider subscribing to LWN. Thank you for visiting LWN.net!
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 a 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.