diff --git a/arcade/draw/point.py b/arcade/draw/point.py index c4e1827b5..4faf5e9d1 100644 --- a/arcade/draw/point.py +++ b/arcade/draw/point.py @@ -16,7 +16,7 @@ def draw_point(x: float, y: float, color: RGBOrA255, size: float = 1.0) -> None: To draw more rounded shapes, please see: * :py:func:`arcade.draw_circle_filled` - * :py:func:`pyglet.shapes.Circle` + * :py:class:`pyglet.shapes.Circle` Args: x: @@ -41,7 +41,7 @@ def draw_points(point_list: Point2List, color: RGBOrA255, size: float = 1.0) -> To draw more rounded shapes, please see: * :py:func:`arcade.draw_circle_filled` - * :py:func:`pyglet.shapes.Circle` + * :py:class:`pyglet.shapes.Circle` Args: point_list: diff --git a/arcade/gui/widgets/text.py b/arcade/gui/widgets/text.py index 8d4b411c1..7326936a5 100644 --- a/arcade/gui/widgets/text.py +++ b/arcade/gui/widgets/text.py @@ -60,10 +60,10 @@ class UILabel(UIWidget): y: y position (default anchor is bottom-left). width: Width of the label. Defaults to text width if not specified. See - :py:meth:`~pyglet.text.layout.TextLayout.content_width`. + :py:attr:`~pyglet.text.layout.TextLayout.content_width`. height: Height of the label. Defaults to text height if not specified. See - :py:meth:`~pyglet.text.layout.TextLayout.content_height`. + :py:attr:`~pyglet.text.layout.TextLayout.content_height`. font_name: A list of fonts to use. Arcade will start at the beginning of the tuple and keep trying to load fonts until success. diff --git a/arcade/pymunk_physics_engine.py b/arcade/pymunk_physics_engine.py index 0647c906a..ab68c49d2 100644 --- a/arcade/pymunk_physics_engine.py +++ b/arcade/pymunk_physics_engine.py @@ -202,7 +202,7 @@ def add_sprite( pass :py:attr:`MOMENT_INF` or ``float('inf')`` to "lock" its angle). - See :py:attr:`pymunk.Shape.moment_of_inertia` to learn more. + See :py:attr:`pymunk.Shape.moment` to learn more. body_type: :py:attr:`DYNAMIC` (default), :py:attr:`KINEMATIC`, or @@ -402,7 +402,7 @@ def add_sprite_list( pass :py:attr:`MOMENT_INF` or ``float('inf')`` to "lock" its angle). - See :py:attr:`pymunk.Shape.moment_of_inertia` to learn more. + See :py:attr:`pymunk.Shape.moment` to learn more. body_type: :py:attr:`DYNAMIC` (default), :py:attr:`KINEMATIC`, or diff --git a/arcade/sound.py b/arcade/sound.py index 11a23e98d..6987059bf 100644 --- a/arcade/sound.py +++ b/arcade/sound.py @@ -158,7 +158,7 @@ def _on_player_eos(): return player def stop(self, player: media.AudioPlayer) -> None: - """Stop and :py:meth:`~pyglet.media.player.Player.delete` ``player``. + """Stop and :py:meth:`~pyglet.media.player.AudioPlayer.delete` ``player``. All references to it in the internal table for :py:class:`pyglet.media.Source` will be deleted. @@ -300,7 +300,7 @@ def play_sound( * - Yes - N/A - - A pyglet :py:class:`~pyglet.media.player.Player` + - A pyglet :py:class:`~pyglet.media.player.AudioPlayer` To learn more about the ``streaming`` keyword and restrictions, please see: diff --git a/arcade/text.py b/arcade/text.py index 47a595f44..8a21bdcde 100644 --- a/arcade/text.py +++ b/arcade/text.py @@ -736,7 +736,7 @@ def rect(self) -> Rect: .. tip:: Don't worry about `width` being `None`. Although a label can be created with a `width=None`: - * The underlying :py:mod:`pyglet` label will have bounding dimensions + * The underlying pyglet label will have bounding dimensions * This rect is for on-screen click and layout purposes, not maximum possible width """ return LRBT(self.left, self.right, self.bottom, self.top) diff --git a/arcade/texture_atlas/atlas_default.py b/arcade/texture_atlas/atlas_default.py index 017eac39a..238718c29 100644 --- a/arcade/texture_atlas/atlas_default.py +++ b/arcade/texture_atlas/atlas_default.py @@ -279,7 +279,7 @@ def add(self, texture: Texture) -> tuple[int, AtlasRegion]: Returns: texture_id, AtlasRegion tuple Raises: - AllocatorException: If there are no room for the texture + pyglet.graphics.atlas.AllocatorException: If there are no room for the texture """ return self._add(texture) diff --git a/arcade/texture_atlas/base.py b/arcade/texture_atlas/base.py index 1ec5142b5..7d4063190 100644 --- a/arcade/texture_atlas/base.py +++ b/arcade/texture_atlas/base.py @@ -132,7 +132,7 @@ def add(self, texture: Texture) -> tuple[int, AtlasRegion]: Returns: texture_id, AtlasRegion tuple Raises: - AllocatorException: If there are no room for the texture + pyglet.graphics.atlas.AllocatorException: If there are no room for the texture """ ... diff --git a/arcade/types/vector_like.py b/arcade/types/vector_like.py index 379576917..fef103cdf 100644 --- a/arcade/types/vector_like.py +++ b/arcade/types/vector_like.py @@ -27,11 +27,11 @@ #: * An ordinary :py:class:`tuple` of 2 or 3 values, either: #: #: * :py:class:`int` -# * :py:class:`float` +#: * :py:class:`float` #: -#: This works the same way as :py:attr:`arcade.types.RGBOrA255` to +#: This works the same way as :py:data:`~arcade.types.color.RGBOrA255` to #: annotate RGB tuples, RGBA tuples, and :py:class:`tuple` or a -#: :py:class:`Color` instances. +#: :py:class:`~arcade.types.Color` instances. Point = Point2 | Point3 PointList = Sequence[Point] diff --git a/arcade/utils.py b/arcade/utils.py index 832020907..86e90cf08 100644 --- a/arcade/utils.py +++ b/arcade/utils.py @@ -35,7 +35,7 @@ class Chain(Generic[_T]): - """A reusable OOP version of :py:class:`itertools.chain`. + """A reusable OOP version of :py:func:`itertools.chain`. In some cases (physics engines), we need to iterate over multiple sequences of objects repeatedly. This class provides a way to do so @@ -166,7 +166,7 @@ def grow_sequence( * an abbreviation for repetitive if-blocks in config and settings menus The default ``append_if`` value is the :py:func:`.is_str_or_noniterable` - function in this module. You can pass any :py:func:`~typing.Callable` + function in this module. You can pass any :py:data:`~typing.Callable` which returns: * ``True`` if we should :py:meth:`append ` diff --git a/doc/_includes/resources_Video.rst b/doc/_includes/resources_Video.rst index 9ae0cc0c3..66029bf6a 100644 --- a/doc/_includes/resources_Video.rst +++ b/doc/_includes/resources_Video.rst @@ -1,4 +1,4 @@ -Arcade offers experimental support for video playback through :py:mod:`pyglet` and other libraries. +Arcade offers experimental support for video playback through pyglet and other libraries. .. warning:: These features are works-in-progress! @@ -13,7 +13,7 @@ examples below may require installing both :ref:`guide-supportedmedia-ffmpeg` an * The `cv2-based video examples `_ * The `cv2-based shadertoy example `_ -The links above use the unstable development branch of Arcade to gain access to the latest :py:mod:`pyglet` +The links above use the unstable development branch of Arcade to gain access to the latest pyglet and Arcade features. If you have questions or want to help develop these examples further, we'd love to hear from you. The Arcade `Discord server `_ and `GitHub repository `_ always welcome new community members. diff --git a/doc/api_docs/gl/index.rst b/doc/api_docs/gl/index.rst index 266841acb..122f79337 100644 --- a/doc/api_docs/gl/index.rst +++ b/doc/api_docs/gl/index.rst @@ -22,7 +22,7 @@ This module **does not** aim to be a perfect copy of any other graphics API. This module assumes you are familiar with low-level graphics programming! -Instead, it takes inspiration from ModernGL_ to build on :py:mod:`pyglet.gl` +Instead, it takes inspiration from ModernGL_ to build on ``pyglet.gl`` with more :py:mod:`ctypes` bindings. @@ -149,10 +149,10 @@ To maximize hardware support, it requires at least one of the following: * GLES with certain extensions It avoids binary dependencies by using Python's built-in :py:mod:`ctypes` -module via both :py:mod:`pyglet` and Arcade's added OpenGL bindings. +module via both pyglet and Arcade's added OpenGL bindings. This ensures Arcade can run on most desktop and laptop hardware from the past -decade, just like :py:mod:`pyglet`. This portability trades away a bit of speed +decade, just like pyglet. This portability trades away a bit of speed and context-handling flexibility compared to ModernGL_. Future Backends diff --git a/doc/conf.py b/doc/conf.py index 196d1495c..5d38e8afd 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -159,6 +159,9 @@ def run_util(filename, run_name="__main__", init_globals=None): autodoc_inherit_docstrings = False +# Show default values as written in the source, such as ``cls=UIWidget``. +# Their repr (````) breaks Sphinx's signature parsing. +autodoc_preserve_defaults = True autodoc_default_options = { "members": True, # 'member-order': 'groupwise', @@ -247,7 +250,40 @@ def run_util(filename, run_name="__main__", init_globals=None): # Warn about all references where the target cannot be found. # This is important to always enable to catch broken doc or api links -# nitpicky = True +nitpicky = True +nitpick_ignore_regex = [ + # Type variables, such as SpriteType, W and T in generic signatures. + # They aren't documented, so there's nothing to link to. + (r"py:(class|obj)", r"(.*\.)?([A-Z]|[A-Z]\w*_co|_?\w+_contra|SpriteType|TShape|SupportsRichComparisonT|StyleRef)"), + # Private names (with a leading underscore) that appear in signatures + (r"py:(class|obj|meth)", r"(.*\.)?_\w+"), +] +nitpick_ignore = [ + # Not in pyglet's docs + ("py:class", "pyglet.media.codecs.MediaDecoder"), +] + +# Short names that type annotations use, because the module imports them +# only for type checking. on_missing_reference below links them. +SHORT_NAMES = { + "Controller": "pyglet.input.Controller", + "Vec2": "pyglet.math.Vec2", + "Vec3": "pyglet.math.Vec3", + "Mat4": "pyglet.math.Mat4", + "AbstractDocument": "pyglet.text.document.AbstractDocument", + # arcade.tilemap imports pytiled_parser's Color under this name + "Color": "pytiled_parser.common_types.Color", + "Image.Image": "PIL.Image.Image", + "Path": "pathlib.Path", + "Point": "arcade.types.vector_like.Point", + "Point2": "arcade.types.vector_like.Point2", + "Point3": "arcade.types.vector_like.Point3", + "Point2List": "arcade.types.vector_like.Point2List", + "RGBA255": "arcade.types.color.RGBA255", + "sh.SpatialHash": "arcade.SpatialHash", + "sh.ReadOnlySpatialHash": "arcade.sprite_list.spatial_hash.ReadOnlySpatialHash", + "pytiled_parser.TiledMap": "pytiled_parser.tiled_map.TiledMap", +} # -- Options for HTML output ---------------------------------------------- @@ -308,18 +344,20 @@ def run_util(filename, run_name="__main__", init_globals=None): # Configuration for intersphinx enabling linking other projects intersphinx_mapping = { "python": ("https://docs.python.org/3", None), - # As of January 25th, pyglet's 2.1.X branch is on this URL and their - # development build on readthedocs is for their in-progress 3.0.0 alpha. - "pyglet": ("https://pyglet.readthedocs.io/en/latest/", None), + # Arcade uses pyglet 3, which is on pyglet's development docs. Their + # "latest" docs are for pyglet 2.1. + "pyglet": ("https://pyglet.readthedocs.io/en/development/", None), "PIL": ("https://pillow.readthedocs.io/en/stable", None), "pymunk": ("https://www.pymunk.org/en/latest/", None), + "pytiled_parser": ("https://pytiled-parser.readthedocs.io/en/latest/", None), + "typing_extensions": ("https://typing-extensions.readthedocs.io/en/latest/", None), } # These will be joined as one block and prepended to every source file. # Substitutions for |version| and |release| are predefined by Sphinx. PROLOG_PARTS = [ # ".. include:: /links.rst", - ".. |pyglet Player| replace:: pyglet :py:class:`~pyglet.media.player.Player`", + ".. |pyglet Player| replace:: pyglet :py:class:`~pyglet.media.player.AudioPlayer`", ".. _Arcade's License File on GitHub: {FMT_URL_REF_BASE}/license.rst", ( # Allows explaining how to copy anywhere in the doc. ".. |Example Copy Button| raw:: html\n\n" @@ -472,6 +510,19 @@ def _get_dir(app, path): generate_color_table(_get_dir(_app, "uicolor.py"), source) +def on_missing_reference(app, env, node, contnode): + """Link a short name from SHORT_NAMES to its full name.""" + full_name = SHORT_NAMES.get(node.get("reftarget")) + if node.get("refdomain") != "py" or full_name is None: + return None + node["reftarget"] = full_name + # Arcade's own names resolve here. Other libraries' are resolved by + # intersphinx, which handles this event after us. + return env.get_domain("py").resolve_xref( + env, node["refdoc"], app.builder, node["reftype"], full_name, node, contnode + ) + + def on_autodoc_process_bases(app, name, obj, options, bases): """We don't care about the `object` base class, so remove it from the list of bases.""" bases[:] = [base for base in bases if base is not object] @@ -532,6 +583,8 @@ def setup(app): app.connect("autodoc-process-docstring", inspect_docstring_for_member) app.connect("autodoc-process-signature", strip_init_return_typehint, -1000) app.connect("autodoc-process-bases", on_autodoc_process_bases) + # Run before intersphinx, so it can resolve the full names of pyglet objects + app.connect("missing-reference", on_missing_reference, priority=400) # app.add_transform(Transform) app.add_role("resource", ResourceRole()) # Don't do anything that can fail on this event or it'll kill your build hard diff --git a/doc/example_code/drawing_text_objects_batch.rst b/doc/example_code/drawing_text_objects_batch.rst index d3cad70b0..f5c929c5e 100644 --- a/doc/example_code/drawing_text_objects_batch.rst +++ b/doc/example_code/drawing_text_objects_batch.rst @@ -10,7 +10,7 @@ The Fastest Text Drawing: pyglet Batches This example demonstrates the most efficient way to render :py:class:`arcade.Text` objects: adding them to pyglet's -:py:class:`~pyglet.graphics.Batch`. Otherwise, it is the +:py:class:`~pyglet.graphics.draw.Batch`. Otherwise, it is the same as the :ref:`drawing_text_objects` example. For a much simpler and slower approach, see :ref:`drawing_text`. diff --git a/doc/get_started/install.rst b/doc/get_started/install.rst index 876c673e7..981314db0 100644 --- a/doc/get_started/install.rst +++ b/doc/get_started/install.rst @@ -68,7 +68,7 @@ can always :ref:`ask for help. `. Raspberry Pi and Other ARM SBCs ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The Arcade and :py:mod:`pyglet` teams have verified the Raspberry Pi 4 and 5 +The Arcade and pyglet teams have verified the Raspberry Pi 4 and 5 as working. The Raspberry Pi 400 will also likely work, but other Pi models will not. To learn more, please see: diff --git a/doc/programming_guide/performance_tips.rst b/doc/programming_guide/performance_tips.rst index f4ede19d8..029c4d949 100644 --- a/doc/programming_guide/performance_tips.rst +++ b/doc/programming_guide/performance_tips.rst @@ -346,8 +346,8 @@ Advanced users may want to try pyglet's :py:class:`pyglet.sprite.Sprite`. Instead of Arcade's :py:class:`~arcade.SpriteList`, pyglet sprites use a mix of the following classes: -* :py:class:`pyglet.graphics.Batch` -* :py:class:`pyglet.graphics.Group` +* :py:class:`pyglet.graphics.draw.Batch` +* :py:class:`pyglet.graphics.draw.Group` Both pyglet's sprites, groups, and batches are much closer to OpenGL's low-level components and will require investing time to learn their features. @@ -368,7 +368,7 @@ To improve performance: text again, but changing the text, font, size, or style does. #. To change several layout properties at once, do it in a ``with text:`` block, so the text is laid out once. -#. Add many ``Text`` objects to a pyglet :py:class:`~pyglet.graphics.Batch` +#. Add many ``Text`` objects to a pyglet :py:class:`~pyglet.graphics.draw.Batch` and draw them with one call. #. If you prefer ``draw_text`` style code, use :py:class:`arcade.TextPool`. #. For text that doesn't change but moves, rotates, or scales, use diff --git a/doc/programming_guide/sound.rst b/doc/programming_guide/sound.rst index 5d1edb851..32bd442ee 100644 --- a/doc/programming_guide/sound.rst +++ b/doc/programming_guide/sound.rst @@ -224,7 +224,7 @@ Stopping a Specific Playback There are two easy ways of stopping a playback of a :py:class:`Sound`. The first is to choose which function we'll pass its -:py:class:`~pyglet.media.player.Player` object to: +:py:class:`~pyglet.media.player.AudioPlayer` object to: * :py:func:`arcade.stop_sound`: @@ -342,7 +342,7 @@ may want to access its functionality directly. .. rubric:: Pausing There is no stop method. Instead, call -:py:meth:`Player.pause() `: +:py:meth:`AudioPlayer.pause() `: .. code-block:: python @@ -355,7 +355,7 @@ There is no stop method. Instead, call After you've paused a player, you can stop playback permanently as follows: -#. Call the player's :py:meth:`~pyglet.media.player.Player.delete` method: +#. Call the player's :py:meth:`~pyglet.media.player.AudioPlayer.delete` method: .. code-block:: python @@ -429,7 +429,7 @@ following advanced arguments: Change Ongoing Playbacks via Player Objects """"""""""""""""""""""""""""""""""""""""""" -:py:meth:`Player.pause() ` is one of +:py:meth:`AudioPlayer.pause() ` is one of many method and property members which change aspects of an ongoing playback. It's impossible to cover them all here, especially given the complexity of :ref:`positional audio `. @@ -442,22 +442,22 @@ arguments to Arcade functions. .. list-table:: :header-rows: 1 - * - :py:class:`~pyglet.media.player.Player` Member + * - :py:class:`~pyglet.media.player.AudioPlayer` Member - Type - Default - Purpose - * - :py:meth:`~pyglet.media.player.Player.pause` + * - :py:meth:`~pyglet.media.player.AudioPlayer.pause` - method - N/A - Pause playback resumably. - * - :py:meth:`~pyglet.media.player.Player.play` + * - :py:meth:`~pyglet.media.player.AudioPlayer.play` - method - N/A - Resume paused playback. - * - :py:meth:`~pyglet.media.player.Player.seek` + * - :py:meth:`~pyglet.media.player.AudioPlayer.seek` - method - N/A - .. warning:: :ref:`Using this option with streaming can cause freezes! @@ -466,18 +466,18 @@ arguments to Arcade functions. Skip to the passed :py:class:`float` timestamp measured as seconds from the audio's start. - * - :py:attr:`~pyglet.media.player.Player.volume` + * - :py:attr:`~pyglet.media.player.AudioPlayer.volume` - :py:class:`float` property - ``1.0`` - A scaling factor for playing the audio between ``0.0`` (silent) and ``1.0`` (full volume). - * - :py:attr:`~pyglet.media.player.Player.loop` + * - :py:attr:`~pyglet.media.player.AudioPlayer.loop` - :py:class:`bool` property - ``False`` - Whether to restart playback automatically after finishing. [#streamingnoloop2]_ - * - :py:attr:`~pyglet.media.player.Player.pitch` [#inconsistencyspeed]_ + * - :py:attr:`~pyglet.media.player.AudioPlayer.pitch` [#inconsistencyspeed]_ - :py:class:`float` property - ``1.0`` - How fast to play the sound data; also affects pitch. @@ -496,7 +496,7 @@ Configure New Playbacks via Keyword Arguments Arcade's helper functions for playing sound also accept keyword arguments for configuring playback. As mentioned above, the names of these keywords are similar or identical to those of properties on -:py:class:`~pyglet.media.player.Player`. See the following to learn +:py:class:`~pyglet.media.player.AudioPlayer`. See the following to learn more: * :py:func:`arcade.play_sound` @@ -729,7 +729,7 @@ volumes across the channels for physical speakers based on in-game distances. Although pyglet exposes its support for this through its -:py:class:`~pyglet.media.player.Player`, Arcade does not currently offer +:py:class:`~pyglet.media.player.AudioPlayer`, Arcade does not currently offer integrations. You will have to do the setup work yourself. .. _pyglet_positional_guide: https://pyglet.readthedocs.io/en/latest/programming_guide/media.html#positional-audio @@ -744,7 +744,7 @@ of links should serve as a primer for trying positional audio: #. `Controlling playback `_ #. `Positional audio `_ -#. :py:class:`pyglet.media.player.Player`'s full documentation +#. :py:class:`pyglet.media.player.AudioPlayer`'s full documentation External Libraries ^^^^^^^^^^^^^^^^^^ diff --git a/doc/programming_guide/text.rst b/doc/programming_guide/text.rst index b9ef757ac..6cf46a725 100644 --- a/doc/programming_guide/text.rst +++ b/doc/programming_guide/text.rst @@ -107,7 +107,7 @@ Batches ~~~~~~~ Drawing many ``Text`` objects one at a time adds up. If you add them to a -pyglet :py:class:`~pyglet.graphics.Batch`, one call draws all of them: +pyglet :py:class:`~pyglet.graphics.draw.Batch`, one call draws all of them: .. code-block:: python diff --git a/util/update_quick_index.py b/util/update_quick_index.py index 0f858f150..a90a3a4a7 100644 --- a/util/update_quick_index.py +++ b/util/update_quick_index.py @@ -80,7 +80,16 @@ def error(message: str) -> None: "arcade.types.box", ], # Type aliases, which the parser below can't find - "data": ["arcade.types.numbers.AsFloat"], + "data": [ + "arcade.types.numbers.AsFloat", + "arcade.types.vector_like.Point", + "arcade.types.vector_like.Point2", + "arcade.types.vector_like.Point3", + "arcade.types.vector_like.Point2List", + "arcade.types.color.RGBA255", + "arcade.types.color.RGBOrA255", + "arcade.types.OneOrIterableOf", + ], }, "resources.rst": { "title": "Resources",