From da93458b50eeb503485d1d5530f8e976499cad3d Mon Sep 17 00:00:00 2001 From: John Zhou Date: Tue, 8 Jul 2025 14:31:08 -0500 Subject: [PATCH] Add a basic set of docs. --- .gitignore | 2 + docs/Makefile | 20 ++ docs/about/index.rst | 11 ++ docs/about/versions.rst | 55 ++++++ docs/about/workings.rst | 18 ++ docs/conf.py | 372 +++++++++++++++++++++++++++++++++++++ docs/extra/.gitkeep | 0 docs/how-to/contribute.rst | 72 +++++++ docs/how-to/index.rst | 11 ++ docs/how-to/packages.rst | 36 ++++ docs/images/PAS.png | Bin 0 -> 8704 bytes docs/index.rst | 31 ++++ docs/make.bat | 35 ++++ docs/usage/embedding.rst | 147 +++++++++++++++ docs/usage/index.rst | 11 ++ docs/usage/obtain.rst | 48 +++++ 16 files changed, 869 insertions(+) create mode 100644 docs/Makefile create mode 100644 docs/about/index.rst create mode 100644 docs/about/versions.rst create mode 100644 docs/about/workings.rst create mode 100644 docs/conf.py create mode 100644 docs/extra/.gitkeep create mode 100644 docs/how-to/contribute.rst create mode 100644 docs/how-to/index.rst create mode 100644 docs/how-to/packages.rst create mode 100644 docs/images/PAS.png create mode 100644 docs/index.rst create mode 100644 docs/make.bat create mode 100644 docs/usage/embedding.rst create mode 100644 docs/usage/index.rst create mode 100644 docs/usage/obtain.rst diff --git a/.gitignore b/.gitignore index f8053935..385d9a61 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,5 @@ tests/testbed/iOS *.log *.gz *.DS_Store + +_build diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 00000000..d4bb2cbb --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/about/index.rst b/docs/about/index.rst new file mode 100644 index 00000000..c33abd6f --- /dev/null +++ b/docs/about/index.rst @@ -0,0 +1,11 @@ +.. _about: + +========================== +About Python Apple Support +========================== + +.. toctree:: + :maxdepth: 1 + + versions + workings diff --git a/docs/about/versions.rst b/docs/about/versions.rst new file mode 100644 index 00000000..df57d08e --- /dev/null +++ b/docs/about/versions.rst @@ -0,0 +1,55 @@ +================== +Supported Versions +================== + +Python Versions +--------------- + +Python Apple Support currently supports Python versions 3.9 to 3.14, inclusive. + +Operating Systems +----------------- + +The binaries support x86_64 and arm64 for macOS; arm64 for iOS and appleTV devices; arm64_32 for watchOS devices; and arm64 for visionOS devices. It also supports device simulators on both x86_64 and M1 hardware, except for visionOS, for which x86_64 simulators are officially unsupported. This should enable the code to run on: + +- macOS 11 (Big Sur) or later, on: + + - MacBook (including MacBooks using Apple Silicon) + - iMac (including iMacs using Apple Silicon) + - Mac Mini (including Apple Silicon Mac minis) + - Mac Studio (all models) + - Mac Pro (all models) + +- iOS 13.0 or later, on: + + - iPhone (6s or later) + - iPad (5th gen or later) + - iPad Air (all models) + - iPad Mini (2 or later) + - iPad Pro (all models) + - iPod Touch (7th gen or later) + +- tvOS 12.0 or later, on: + + - Apple TV (4th gen or later) + +- watchOS 4.0 or later, on: + + - Apple Watch (4th gen or later) + +- visionOS 2.0 or later, on: + + - Apple Vision Pro + +Historical support +------------------ + +The following Python versions were supported in the past, but are no longer +maintained: + +* Python 2.7 (EOL January 2020) +* Python 3.4 (EOL March 2019) +* Python 3.5 (EOL February 2021) +* Python 3.6 (EOL December 2021) +* Python 3.7 (EOL September 2022) +* Python 3.8 (EOL October 2024) diff --git a/docs/about/workings.rst b/docs/about/workings.rst new file mode 100644 index 00000000..d4781cea --- /dev/null +++ b/docs/about/workings.rst @@ -0,0 +1,18 @@ +====================== +How This Project Works +====================== + +Python Apple Support works by downloading, patching, and building a fat binary +of Python and selected pre-requisites, and packaging them as frameworks that can be +incorporated into an Xcode project. The binary modules in the Python standard +library are distributed as binaries that can be dynamically loaded at runtime. + +The macOS package is a re-bundling of the official macOS binary, modified so that +it is relocatable, with the IDLE, Tkinter and turtle packages removed, and the +App Store compliance patch applied. + +The iOS, tvOS, watchOS, and visionOS packages compiled by this project use the +official `PEP 730 `__ code that is part of +Python 3.13 to provide iOS support; the relevant patches have been backported +to 3.9-3.12. Additional patches have been applied to add tvOS, watchOS, and +visionOS support. \ No newline at end of file diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 00000000..be15680b --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,372 @@ +import os + +import beeware_theme + +# BeeWare theme override for Furo Sphinx theme to add BeeWare features. +templates_path = [] +html_static_path = [] +html_css_files = [] +html_context = {} +html_theme_options = {} + +beeware_theme.init( + project_name="Python-Apple-Support", + templates=templates_path, + context=html_context, + static=html_static_path, + css=html_css_files, + theme_options=html_theme_options, +) + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# sys.path.insert(0, os.path.abspath(".")) + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = [ + "sphinx.ext.autodoc", + "sphinx.ext.todo", + "sphinx_tabs.tabs", + "crate.sphinx.csv", + "sphinx_copybutton", + "sphinx_toolbox.more_autodoc.autonamedtuple", + "sphinx_toolbox.more_autodoc.autoprotocol", + "sphinx.ext.intersphinx", + "sphinxcontrib.spelling", +] + +# The suffix of source filenames. +source_suffix = ".rst" + +# The encoding of source files. +# source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = "index" + +# General information about the project. +project = "Python Apple Support" +copyright = "Russell Keith-Magee" + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The full version, including alpha/beta/rc tags +release = "1.0.0" +# The short X.Y version +version = "1.0" + +autoclass_content = "both" +autodoc_preserve_defaults = True +autodoc_default_options = { + # For show-inheritance, see autodoc-process-signature below. + "members": True, + "undoc-members": True, +} +autodoc_typehints = "description" + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +# today = '' +# Else, today_fmt is used as the format for a strftime call. +# today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ["_build"] + +# The reST default role (used for this markup: `text`) to use for all documents. +# default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +# add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +# add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +# show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = "sphinx" + +# A list of ignored prefixes for module index sorting. +# modindex_common_prefix = [] + +# API status indicators. +rst_prolog = """ +.. role:: stable +.. role:: beta +.. role:: no +.. |y| replace:: :stable:`●` +.. |b| replace:: :beta:`○` +.. |beta| replace:: :beta:`β` +.. |no| replace:: :no:`✖︎` +""" + +intersphinx_mapping = { + "python": ("https://docs.python.org/3", None), + "PIL": ("https://pillow.readthedocs.io/en/stable/", None), +} + +# Hide the class and module name on the right sidebar to prevent wrapping +toc_object_entries_show_parents = "hide" + +# -- Local extensions ---------------------------------------------------------- + + +def setup(app): + app.connect("autodoc-process-signature", autodoc_process_signature) + return { + "parallel_read_safe": True, + "parallel_write_safe": True, + } + + +# Adding show-inheritance to autodoc_default_options adds a Bases line to ALL classes, +# even those that only inherit from `object`, or whose bases have all been filtered out +# by autodoc-process-bases. Instead, we enable the option here. +def autodoc_process_signature( + app, what, name, obj, options, signature, return_annotation +): + if what == "class": + # Travertino classes are not part of the public API. + bases = [ + base + for base in obj.__bases__ + if base is not object and not base.__module__.startswith("travertino.") + ] + if bases: + options.show_inheritance = True + + +# -- Options for link checking ------------------------------------------------- + +linkcheck_ignore = [ + # GitHub generates anchors in javascript + r"https://github.com/.*#", + # References to Github issues/pulls should all be safe. + r"^https://github.com/beeware/Python-Apple-Support/issues/\d+$", + r"^https://github.com/beeware/Python-Apple-Support/pull/\d+$", +] + +# -- Options for copy button --------------------------------------------------- + +# virtual env prefix: (venv), (beeware-venv) +venv = r"\((?:beeware-)?venv\)" +# macOS and Linux shell prompt: $ +shell = r"\$" +# win CMD prompt: C:\>, C:\...> +cmd = r"C:\\>|C:\\\.\.\.>" +# PowerShell prompt: PS C:\>, PS C:\...> +ps = r"PS C:\\>|PS C:\\\.\.\.>" +# zero or one whitespace char +sp = r"\s?" + +# optional venv prefix +venv_prefix = rf"(?:{venv})?" +# one of the platforms' shell prompts +shell_prompt = rf"(?:{shell}|{cmd}|{ps})" + +copybutton_prompt_text = "|".join( + [ + # Python REPL + # r">>>\s?", r"\.\.\.\s?", + # IPython and Jupyter + # r"In \[\d*\]:\s?", r" {5,8}:\s?", r" {2,5}\.\.\.:\s?", + # Shell prompt + rf"{venv_prefix}{sp}{shell_prompt}{sp}", + ] +) +copybutton_prompt_is_regexp = True +copybutton_remove_prompts = True +copybutton_only_copy_prompt_lines = True +copybutton_copy_empty_lines = False + +# -- Options for HTML output --------------------------------------------------- + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# html_theme_options = { +# "project_baseurl": "https://github.com/beeware/Python-Apple-Support", +# } + +# Add any paths that contain custom themes here, relative to this directory. +# html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +html_title = f"Python Apple Support" + +# A shorter title for the navigation bar. Default is the same as html_title. +# html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +html_logo = "images/PAS.png" + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +# html_favicon = None + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +# html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +# html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +# html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +# html_additional_pages = {} + +# If false, no module index is generated. +# html_domain_indices = True + +# If false, no index is generated. +# html_use_index = True + +# If true, the index is split into individual pages for each letter. +# html_split_index = False + +# If true, links to the reST sources are added to the pages. +# html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +# html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +# html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +# html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +# html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = "pasdoc" + +html_theme = "furo" + +html_extra_path = ["extra"] + +# -- Options for LaTeX output -------------------------------------------------- + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # 'papersize': 'letterpaper', + # The font size ('10pt', '11pt' or '12pt'). + # 'pointsize': '10pt', + # Additional stuff for the LaTeX preamble. + # 'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ("index", "PythonAppleSupport.tex", "Python Apple Support Documentation", "Russell Keith-Magee", "manual"), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +# latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +# latex_use_parts = False + +# If true, show page references after internal links. +# latex_show_pagerefs = False + +# If true, show URL addresses after external links. +# latex_show_urls = False + +# Documents to append as an appendix to all manuals. +# latex_appendices = [] + +# If false, no module index is generated. +# latex_domain_indices = True + + +# -- Options for manual page output -------------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [("index", "python-apple-support", "Python Apple Support Documentation", ["Russell Keith-Magee"], 1)] + +# If true, show URL addresses after external links. +# man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------------ + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ( + "index", + "python_apple_support", + "Python Apple Support Documentation", + "Russell Keith-Magee", + "Python Apple Support", + "A Python native, OS native GUI toolkit.", + "Miscellaneous", + ), +] + +# Documents to append as an appendix to all manuals. +# texinfo_appendices = [] + +# If false, no module index is generated. +# texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +# texinfo_show_urls = 'footnote' + +# -- Options for spelling ------------------------------------------- + +# Spelling check needs an additional module that is not installed by default. +# Add it only if spelling check is requested so docs can be generated without it. + +# Spelling language. +spelling_lang = "en_US" + +# Location of word list. +spelling_word_list_filename = "spelling_wordlist" + +# -- Options for Todos ------------------------------------------- + +# If this is True, todo and todolist produce output, else they produce nothing. +# The default is False. +todo_include_todos = True + +# If this is True, todo emits a warning for each TODO entries. The default is False. +# todo_emit_warnings = False + +# If this is True, todolist produce output without file path and line, +# The default is False. +# todo_link_only = False diff --git a/docs/extra/.gitkeep b/docs/extra/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/docs/how-to/contribute.rst b/docs/how-to/contribute.rst new file mode 100644 index 00000000..b1628411 --- /dev/null +++ b/docs/how-to/contribute.rst @@ -0,0 +1,72 @@ +==================================== +Contributing to Python Apple Support +==================================== + +Setting Up Your Environment +--------------------------- + +Make sure you have an up-to-date Xcode and iOS/tvOS/watchOS/visionOS simulators +(depending on the platforms you plan to run the testbed on) installed. If you +plan to change Python.patch, you will also need ``patchutils``, installable through +Homebrew. You will also need the Xcode command line tools. + +Is This the Right Place to Contribute? +-------------------------------------- + +Any iOS or macOS-specific changes to the patches should be submitted to CPython itself, +since they're both officially supported platforms and the code distributed by this +project is directly compiled from the upstream repository. + +If you're suggesting a change to the build process of this project in the Makefile or a +fix for the patch for other platforms, then go ahead and contribute to this repository. + +Submit all changes to the ``main`` branch and/or the latest ``X.Y-patched`` branch in the +Fork of CPython; forward- and back-porting will be managed by the maintainers. + +Changes to ``Python.patch`` +--------------------------- + +Changes to support other platforms or otherwise make changes to the patch file +can be included in a PR for this repo, but they must +also be submitted as a pull request against the ``MAJOR.MINOR-patched`` +branch on `the ``freakboy3742`` fork of the CPython +repo `__. This is required to ensure that +any contributed changes can be easily reproduced in future patches as more +changes are made. + +Note that the ``MAJOR.MINOR-patched`` branch of that fork is maintained in the format +of a *patch tree*, which is a branch that consists of an entirely linear sequence of +commits applied on top of another branch (in the case of the fork, ``MAJOR.MINOR``), +each of which adds a significant new feature. Therefore, a bug fix for an existing commit +in the patch tree *will* be merged when appropriate, but its changes will get combined +with that existing commit that adds the feature. A feature addition PR will be squashed +into a single, new commit, and then put on top of the patch tree. + +This also means that if another contributor gets a pull request merged into +``MAJOR.MINOR-patched``, you must *rebase* your changes on top of the updated +``MAJOR.MINOR-patched`` branch, as opposed to *merging* ``MAJOR.MINOR-patched`` into your +branch, since the "history" of a patch tree is likely to change in a way that is +incompatible with merge commits. + +To update the patch to test your changes in CPython in the context of Python-Apple-Support, +first merge your changes into your local ``X.Y-patched`` branch, +then run ``export PYTHON_REPO_DIR=/path/to/cpython/checkout`` and ``make update-patch`` +in Python-Apple-Support. You can undo the merge commit after the patch updates, or you can +keep it there and then ``git pull --force`` on ``X.Y-patched`` branch the next time you +want to contribute a change. + +Executing the Tests +------------------- + +In your CPython checkout, run ``make testios`` / ``make testvisionos`` depending on the platform +on which you want the tests to run to execute the testbed. Make sure you have cleaned, built, +and installed your code before you try to do this. + +The above command will clone the testbed to a temporary directory, adding the XCFrameworks +in the process, and execute the tests. To execute only some tests without without running +the full test suite, you can go to the iOS directory of the CPython checkout, and run +``python -m testbed clone --framework /path/to/installed/Python.framework /path/to/temp/directory/testbed-name``, +and then ``cd /path/to/temp/directory`` and then ``python -m testbed-name run -- ``, +which invokes the equivalent of ``python -m ``. ```` has a default of +``test -uall --single-process --rerun -W``, and you can run a subset of tests by appending the +names to that sequence. diff --git a/docs/how-to/index.rst b/docs/how-to/index.rst new file mode 100644 index 00000000..b1c8df26 --- /dev/null +++ b/docs/how-to/index.rst @@ -0,0 +1,11 @@ +.. _howto: + +============= +How-To Guides +============= + +.. toctree:: + :maxdepth: 1 + + contribute + packages \ No newline at end of file diff --git a/docs/how-to/packages.rst b/docs/how-to/packages.rst new file mode 100644 index 00000000..7ea71178 --- /dev/null +++ b/docs/how-to/packages.rst @@ -0,0 +1,36 @@ +========================== +Installing Python Packages +========================== + +Each slice of an iOS/tvOS/watchOS/visionOS XCframework contains a +``platform-config`` folder with a subfolder for each supported architecture in +that slice. These subfolders can be used to make a macOS Python environment +behave as if it were on an iOS/tvOS/watchOS/visionOS device. This works in one +of two ways: + +1. **A sitecustomize.py script**. If the ``platform-config`` subfolder is on + your ``PYTHONPATH`` when a Python interpreter is started, a site + customization will be applied that patches methods in ``sys``, ``sysconfig`` + and ``platform`` that are used to identify the system. + +2. **A make_cross_venv.py script**. If you call ``make_cross_venv.py``, + providing the location of a virtual environment, the script will add some + files to the ``site-packages`` folder of that environment that will + automatically apply the same set of patches as the ``sitecustomize.py`` + script whenever the environment is activated, without any need to modify + ``PYTHONPATH``. If you use ``build`` to create an isolated PEP 517 + environment to build a wheel, these patches will also be applied to the + isolated build environment that is created. + +Using one of these two methods, you should be able to use the ``--target`` +option of ``pip install`` to install your package to the appropriate location +in your Xcode project for third-party code. + +Building binary wheels +---------------------- + +This project packages the Python standard library, but does not address building +binary wheels. Binary wheels for macOS can be obtained from PyPI. `Mobile Forge +`__ is a project that provides the +tooling to build build binary wheels for iOS (and potentially for tvOS, watchOS, +and visionOS, although that hasn't been tested). \ No newline at end of file diff --git a/docs/images/PAS.png b/docs/images/PAS.png new file mode 100644 index 0000000000000000000000000000000000000000..aaa393ba5a9bc06d52ece312f000405d55396935 GIT binary patch literal 8704 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

%LJsZ*LT7TZyKT5UNcp~Bny;qfiK<; zB6tY~U%v5Un+}b96LTRpd$mwKlLklcskYz0tZ`3<%6MnY%ljwQxa&{+HVPsilRWgO zy1A2?1okQK3#%jHn0}*DPD|Use3oZ+O(HU!5&Z z-gZfL^q@W-ZF7WKk@5z)H@`)+5=N0J=4G;SJm+_Ljj9c;Y;ifaSfo9M6~;J4Quv!{ z+;-04Tsej){1C31v^y+`+;d5#sc_Sc{KF!tny@{ueGUnl7f`7M6iUe?3YBO3O<`tQp>FlTOCIM|8V@sK$>Wcz?-JlV?R_t-+1 z{#)tNx#$;znH=533HxlcEpVRaJ|n$ z5?%g4O04wJBbu{!A^w?xs1=vj=l!_^7jx*T+eeR@q38XHhc`0i>o4sTcy8%4Net%F zds(N?;aZ%ch$K>Ig3WdQ5v;RL&^e3KmfvMlONkJ6kz4axrk~X686&ClTt~Ma$nd&@ z$2w1*1-s;Rmt8c`>{Ewh6gi^q%rldWs@!AtY8YMQvaN_;*a>G40dYeHA@Qr#R=e;? zX3pR}nZfOk^ALgMNm;SQ$}(k}m^qWH=(OgNpa4v`|7=^=(>8OLFn23^#z<$~(>j_P zZwV(sM>_&vT^uHJtiEPmcswBJgUAL|A_FQ759;&koz#1FsH8rFK2LuaMNc-dEyc!6 zFA1FW!Fc!%*12O!dG@LLF9ew{?=Ig2HPA-`TLAqEPt;4kEWhAtbcQgzL9v^PSdenR zKSVx(F(l!~&C};!c9VI)5s`aRpYR%?L5Q5=fcc>z{#f_D)%Qoz;s>1 zRl=*zD9RrRpiW&ph<2TOxE%)LTkQ)6oq@jMQb&FPOAFhHHfU^bo&%d7)qC#B0f&hmJ z9@DY}8v1;Y#=srPuKiIOw4~~>3?8bw1-nDa3J&I2UY`{YT&Zjoa&EKadLdUAPP!_g z|D$$c`?+hEFVt~&dvP!NBH*;QN;r~?6j2g7BlR$dZGS{-zB5D}zeQjXVLI6<^l@{w zBj^%$|H{?PPe;*k0m5*FQ?QvC&On&LqI$ji85>j>p_OBa<%^pVJCe}(wp+&18B#Ph zi8o-Bq?~vuR(BD%FPGVl-OqMv?CSHSIV3Y;ppUF1<^lDG5c_`F7iXvnm>Csh?8$_1 zcC_I1w!}{2S&%gI6?MiXFUw^BN0M?rN9UJ?2@E3BK%pzq!auzp+WN58PG`otp{-!N zt%K0M?jvJR*=%Qni8ic|!c(S#S7vnGGrRPFESr{y7&%;caSK5rdBM$abPKk5H-rr7 zg{%_{+D2L&&ED&IP_l|UkzJDtIAMLw=1;NLH1eLyP#Z0!!%sT+YXKEW#i7>z1(^$! z+oR&|S;)9d>qNg_BQ~y+?en4NiL%D>Q$aw@DOjOiDjr~hyf-xSCm3-yX^l8}?Xx>o z{5spx82#HnHNL+o8Fz31Qi))%-_CSRv}&5}+^mcnkD((X-FlUAN$->4q*_*PZ_cEs z*7kI}PE16bru?l0Zl>YkNh;vpQ6(-t{oKF24{MxBN`qZr^>&D8zGSlSF}*_@0ZW?C z!PoqkE~`7wAnl1%Zv-YlzM z)_9xKYYZ-QSYL|EL^b>#-nkcO5s4{b5V2rH9cs zxEx(RyQBSi@wlf8t3IqLBRpitU6|w8=sw@yNvJ9?$tYt}OorM>YWTc_rOTP1p z0~MT9A{q$kJHNyH8F7{m_=rG!^Dg9$4T;hLP=Qq` zw0<~sb(CkX3u{}~ASmNJP4-DWMNUZ);}1ejN{cDS5@+P()7gUNr}N#nCkva36AJ^4 z2gaAmNA3kS^TU^NcvOMm&?olsd`uzDc6v5}HKmwGg(E zaM`)Xmu@uh@S)eA6C`!sHJpoumc$7m^MXCrm|^sR zOUT-9)9Oo!zN__ z!se1WKE6X&x+AV%9Yi6auwSy~T+S@i*1K+Gy${*&U@*Xo_PZMs@d^H+d1D+NaYV#5 zIh<7$unvmu7$(7#pH;OwYdJDsP;6bS>9t62l<{Jtmw{o;J&DN+hB(NCxz}eU*DnLn zzH?hQqyKPjMMqpV`a)SW1{TE+WnB+OWaPjGQNF;dn{7ku{CBN?qq z@*Jpe3)fc407D}(ouCKJmq(hzMk6Ov^WTEKdg-z9q^N~0*#XmLJqFkFUt7Y!V79iEf6LQh{s?Di?Q0 znPvrpu8)3{z3;W4*fNA1pCsgM{IKkL+s^(9o?y$pfxLw<;*1 z{sTh214kP2^@3%Ms!n`GZ1}LS4Qta$`l5bped`HX4)wg58$RCI~!w;l#6dq_w;)B;E zY`j}h1xJ6Z$u<;;tdNrlujhUuJGLQms(^uxr213^`p98{hipURZ7`wcq-g&SbF({; zIgO^%FL*l}Jou}jux|TM{x%WoLp(u(QTCFQj&5Y*tTGoy|1W>SVB2TQ?$VCax*MLR z6kFRaoOjOoi;-cmWJrKpT>$$AOMp+S{69=!B*RJmB&S;jHI_gZ87gVhZ1?tiMfhN> z?ZLZ(`7c;XSEh>KhLSwj{#!9ONc!kb0(0d9j$CoO)<>B6fk%?F;RbIyI@Eq;OQX&( zZ3D#*(n}{cwemi@=Fowu9K(G zA1i|BJ{W)wL_vZy3x_mMM~S(?Bp+$4e0`1OPnO^PS^oL%^V70VI-?Hvz4n*24wv8Q zenz9wKL*+oV@E+`=Hhe&q6!L?xqhoGwbj*wL%S$JLBZ0Oxqj;LiHUrd@~7YM`7HBy z{vdwF*gqR3c~5(Ld*#{My7u?K_@8c+JgG5$cz%Yp#!pPstwRFWbDW#k(bkj@9%Jh3 z%dx$sF8V74n6WCrljMv9y>M`NQ863G&+8JMAy<>C>m8wzO)z<4nb+k;u6+ zSz`l}ovX3wlJdve4_iK%1mU$b&P=$gFj1igi}jpOkd~M4#{=5J=?_jf$zk|C3Nj-j zW1%~l7Y5x)=GDLhn*TQNr}y^t^#Kpx^dRL0tatB}j<)>VLTwk}JPn4CB(Js*Y zpXjAy4&{}VM;8rcWo4rdwf~@hn0k0hRHt2RfL`o~#rM$>%k;@mKnvcwo%B1P>D}K1 zD7ofJ70k~s^KpsJ;YCAVaWIesw4$_FptX(R4go>V!o=JUyQdcH5UvCwrlG!s5Z{Yo{n_to-%x%5D%`egAOt zE@M8lH?Q&7kgjP}GQ{ug)t>XK7O&-*5fQ}N#n*}rV$6gm z*k>MBJbh+jvN-zb@%e5PbeR;21BtX^uVrO@+L5UuyaMAy6djsHyjk%ncui0}0UUIW zD$;$?tlCdO<+{?7s+4^l=MoH6`*NiW@g?)kSvEI$)?{kogURH=5>rY=URq1vxFSry z>F+iZ;7PUT9HC%SV4BJl%=+_c(w1EK{_&h#I5T`g^IEl}Fi@3G|L`n%r6VUFHRJfGC2DH9wU4&xtfc`2R_$IYUzWC8RT6Qa7q+gP+G`ZZ#a z{_F0!a79Qw{md2_aEQADt}npXTT1Wqn5UfKEm_XI-SOJF`. + + +.. toctree:: + :maxdepth: 2 + :hidden: + :titlesonly: + + usage/index + about/index + how-to/index + + +:ref:`Usage ` +-------------------- + +Find out how to use the support packages. + +:ref:`About Python Apple Support ` +----------------------------------------- + +Miscellaneous information about Python Apple Support. + + +:ref:`How-To Guides ` +----------------------------------------- + +How-to guides, including how to contribute. diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 00000000..32bb2452 --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=. +set BUILDDIR=_build + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.https://www.sphinx-doc.org/ + exit /b 1 +) + +if "%1" == "" goto help + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/docs/usage/embedding.rst b/docs/usage/embedding.rst new file mode 100644 index 00000000..61a39c77 --- /dev/null +++ b/docs/usage/embedding.rst @@ -0,0 +1,147 @@ +.. _embedding: + +============================== +Embedding a Python Interpreter +============================== + +The easy way +------------ + +The easist way to use these packages is by creating a project with +`Briefcase `__. Briefcase will +download pre-compiled versions of these support packages, and add them +to an Xcode project (or pre-build stub application, in the case of +macOS). + +The manual way +-------------- + +.. note:: + Briefcase usage is the officially supported approach for using this + support package. If you are experiencing diffculties, one approach + for debugging is to generate a “Hello World” project with Briefcase, and + compare the project that Briefcase has generated with your own project. + +The Python support package *can* be manually added to any Xcode project; +however, you’ll need to perform some steps manually (essentially +reproducing what Briefcase is doing). The steps required are documented +in the CPython usage guides: + +- `macOS `__ +- `iOS `__ + +For tvOS, watchOS, and visionOS, you should be able to broadly follow +the instructions in the iOS guide, changing some platform names in the +first script. The testbed projects generated on iOS and visionOS may be +used as rough references as well. + +Using Objective C +~~~~~~~~~~~~~~~~~ + +Once you’ve added the Python XCframework to your project, you’ll need to +initialize the Python runtime in your Objective C code (This is step 10 +of the iOS guide linked above). This initialization should generally be +done as early as possible in the application’s lifecycle, but definitely +needs to be done before you invoke Python code. + +As a *bare minimum*, you can do the following: + +1. Import the Python C API headers: + + .. code:: objc + + #include + +2. Initialize the Python interpreter: + + .. code:: objc + + NSString *resourcePath = [[NSBundle mainBundle] resourcePath]; + NSString *pythonHome = [NSString stringWithFormat:@"%@/python", resourcePath, nil]; + NSString *appPath = [NSString stringWithFormat:@"%@/app", resourcePath, nil]; + + setenv("PYTHONHOME", [pythonHome UTF8String], 1); + setenv("PYTHONPATH", [appPath UTF8String], 1); + + Py_Initialize(); + + // we now have a Python interpreter ready to be used + +Again - this is the *bare minimum* initialization. In practice, you will +likely need to configure other aspects of the Python interpreter using +the ``PyPreConfig`` and ``PyConfig`` mechanisms. Consult the `Python +documentation on interpreter +configuration `__ for +more details on the configuration options that are available. You may +find the `bootstrap mainline code used by +Briefcase `__ +a helpful point of comparison. + +Using Swift +~~~~~~~~~~~ + +If you want to use Swift instead of Objective C, the bare minimum +initialization code will look something like this: + +1. Import the Python framework: + + .. code:: swift + + import Python + +2. Initialize the Python interpreter: + + .. code:: swift + + guard let pythonHome = Bundle.main.path(forResource: "python", ofType: nil) else { return } + let appPath = Bundle.main.path(forResource: "app", ofType: nil) + + setenv("PYTHONHOME", pythonHome, 1) + setenv("PYTHONPATH", appPath, 1) + Py_Initialize() + // we now have a Python interpreter ready to be used + + Again, references to a specific Python version should reflect the + version of Python you are using; and you will likely need to use + ``PyPreConfig`` and ``PreConfig`` APIs. + +Accessing the Python runtime +---------------------------- + +There are 2 ways to access the Python runtime in your project code. + +Embedded C API +~~~~~~~~~~~~~~ + +You can use the `Python Embedded C +API `__ to invoke +Python code and interact with Python objects. This is a raw C API that +is accesible to both Objective C and Swift. + +PythonKit +~~~~~~~~~ + +If you’re using Swift, an alternate approach is to use +`PythonKit `__. PythonKit is a +package that provides a Swift API to running Python code. + +To use PythonKit in your project, add the Python Apple Support package +to your project and instantiate a Python interpreter as described above; +then add PythonKit to your project using the Swift Package manager (see +the `PythonKit documentation `__ +for details). + +Once you’ve done this, you can import PythonKit: + +.. code:: swift + + import PythonKit + +and use the PythonKit Swift API to interact with Python code: + +.. code:: swift + + let sys = Python.import("sys") + print("Python Version: \(sys.version_info.major).\(sys.version_info.minor)") + print("Python Encoding: \(sys.getdefaultencoding().upper())") + print("Python Path: \(sys.path)") \ No newline at end of file diff --git a/docs/usage/index.rst b/docs/usage/index.rst new file mode 100644 index 00000000..fba16b70 --- /dev/null +++ b/docs/usage/index.rst @@ -0,0 +1,11 @@ +.. _usage: + +===== +Usage +===== + +.. toctree:: + :maxdepth: 1 + + obtain + embedding diff --git a/docs/usage/obtain.rst b/docs/usage/obtain.rst new file mode 100644 index 00000000..e826b5aa --- /dev/null +++ b/docs/usage/obtain.rst @@ -0,0 +1,48 @@ +========================== +Obtaining Support Packages +========================== + +Pre-built versions of the frameworks can be downloaded from the `Github releases page +`__ and added to your project. + +Alternatively, to build the frameworks on your own, download/clone this +repository, and then in the root directory, and run: + +* ``make`` (or ``make all``) to build everything. +* ``make macOS`` to build everything for macOS. +* ``make iOS`` to build everything for iOS. +* ``make tvOS`` to build everything for tvOS. +* ``make watchOS`` to build everything for watchOS. +* ``make visionOS`` to build everything for visionOS. + +This should: + +1. Download the original source packages +2. Patch them as required for compatibility with the selected OS +3. Build the packages as Xcode-compatible XCFrameworks. + +The resulting support packages will be packaged as ``.tar.gz`` files +in the ``dist`` folder. + +Each support package contains: + +* ``VERSIONS``, a text file describing the specific versions of code used to build the + support package; +* ``Python.xcframework``, a multi-architecture build of the Python runtime library. + +On iOS/tvOS/watchOS/visionOS, the ``Python.xcframework`` contains a +slice for each supported ABI (device and simulator). The folder containing the +slice can also be used as a ``PYTHONHOME``, as it contains a ``bin``, ``include`` +and ``lib`` directory. + +The ``bin`` folder does not contain Python executables (as they can't be +invoked). However, it *does* contain shell aliases for the compilers that are +needed to build packages. This is required because Xcode uses the ``xcrun`` +alias to dynamically generate the name of binaries, but a lot of C tooling +expects that ``CC`` will not contain spaces. + +iOS and visionOS distributions also contain a copy of the iOS or visionOS +``testbed`` project - an Xcode project that can be used to run test suites of +Python code. See the `CPython documentation on testing packages +`__ for +details on how to use this testbed.