diff --git a/.gitignore b/.gitignore index f805393..385d9a6 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 0000000..d4bb2cb --- /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 0000000..c33abd6 --- /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 0000000..df57d08 --- /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 0000000..d4781ce --- /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 0000000..be15680 --- /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 0000000..e69de29 diff --git a/docs/how-to/contribute.rst b/docs/how-to/contribute.rst new file mode 100644 index 0000000..b162841 --- /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 0000000..b1c8df2 --- /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 0000000..7ea7117 --- /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 0000000..aaa393b Binary files /dev/null and b/docs/images/PAS.png differ diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..ff090d3 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,31 @@ +Python Apple Support +==================== + +Python Apple Support is a meta-package for building a version of Python that can be embedded into a macOS, iOS, tvOS, watchOS, or visionOS project. For supported versions and devices, refer to :doc:`Supported Versions `. + + +.. 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 0000000..32bb245 --- /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 0000000..61a39c7 --- /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 0000000..fba16b7 --- /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 0000000..e826b5a --- /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.