Skip to content

Commit

Permalink
Generate reST/ref docs from python or stub files
Browse files Browse the repository at this point in the history
  • Loading branch information
zoldalma999 committed Oct 21, 2024
1 parent 8b09b1f commit bbedc0a
Show file tree
Hide file tree
Showing 7 changed files with 135 additions and 7 deletions.
2 changes: 2 additions & 0 deletions buildconfig/stubs/gen_stubs.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ def get_all(mod: Any):
f.write(misc_stubs)

for mod, items in pygame_all_imports.items():
if mod == "pygame":
mod = "."
if len(items) <= 4:
# try to write imports in a single line if it can fit the line limit
import_items = (f"{string} as {string}" for string in items)
Expand Down
2 changes: 1 addition & 1 deletion buildconfig/stubs/pygame/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# A script to auto-generate locals.pyi, constants.pyi and __init__.pyi typestubs
# IMPORTANT NOTE: Do not edit this file by hand!

from pygame import (
from . import (
display as display,
draw as draw,
event as event,
Expand Down
19 changes: 15 additions & 4 deletions docs/reST/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
# All configuration values have a default; values that are commented out
# serve to show the default.

import sys, os
import sys, os, pathlib

# 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
Expand All @@ -23,11 +23,22 @@

# 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.doctest',
'sphinx.ext.coverage', 'ext.headers', 'ext.boilerplate',
'ext.customversion', 'ext.edit_on_github']
extensions = ['autoapi.extension', 'ext.headers', 'ext.boilerplate',
'ext.customversion', 'ext.edit_on_github', 'ext.documenters']


autoapi_dirs = [
pathlib.Path(os.path.abspath(".")).parent.parent / 'buildconfig' / 'stubs' / 'pygame' / '',
pathlib.Path(os.path.abspath(".")).parent.parent / 'src_py' / '',
]

autoapi_options = ['members', 'undoc-members']
autoapi_ignore = ["*controller.py", "*_sdl2/window.py", "*freetype.py", "*ftfont.py", "*__pyinstaller*", "*__init__.py", "*__briefcase*"]
autoapi_generate_api_docs = False
autodoc_typehints = 'none'
suppress_warnings = ['autoapi.python_import_resolution']
autodoc_member_order = 'bysource'

# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']

Expand Down
112 changes: 112 additions & 0 deletions docs/reST/ext/documenters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import autoapi
import autoapi.documenters
from autoapi._objects import PythonClass


def build_signatures(object):
name = object.short_name

if isinstance(object, PythonClass):
if object.constructor is not None:
object = object.constructor
object.obj["return_annotation"] = name
object.obj["overloads"] = [
(arg, name) for arg, _ in object.obj["overloads"]
]

else:
for child in object.children:
if child.short_name == "__new__":
object = child
break

if object is None:
return

sigs = [(object.obj["args"], object.obj["return_annotation"])]
sigs.extend(object.obj["overloads"])

for args, ret in sigs:
arg_string = ""
for modifier, arg_name, _, default in args:
modifier = modifier or ""
arg_name = arg_name or ""
default = default or ""

if default:
default = "=" + default
arg_string += f", {modifier}{arg_name}{default}"

if arg_string:
arg_string = arg_string[2:]

if ret.count("[") > 2 or ret.count(",") > 3:
ret = "..."

yield f"| :sg:`{name}({arg_string}) -> {ret}`"


class AutopgDocumenter(autoapi.documenters.AutoapiDocumenter):
def format_signature(self, **kwargs):
return ""

def get_doc(self, encoding=None, ignore=1):
if self.object.docstring:
return super().get_doc(encoding, ignore)

# If we don't already have docs, check if a python implementation exists of this
# module and return its docstring if it does
python_object = self.env.autoapi_all_objects.get(
self.object.id.replace("pygame", "src_py"), None
)
if python_object is not None:
return [python_object.docstring.splitlines()]

return [""]

def process_doc(self, docstrings: list[str]):
for docstring in docstrings:
if not docstring:
continue

yield f"| :sl:`{docstring[0]}`"

if "args" in self.object.obj or hasattr(self.object, "constructor"):
yield from build_signatures(self.object)
else:
annotation = self.object.obj.get("annotation", None)
if annotation is not None:
if annotation.count("[") > 2 or annotation.count(",") > 3:
annotation = "..."
yield f"| :sg:`{self.object.short_name} -> {annotation}`"

yield from docstring[1:]

yield ""


def setup(app):
names = [
"function",
"property",
"decorator",
"class",
"method",
"data",
"attribute",
"module",
"exception",
]

for name in names:
capitalized = name.capitalize()
app.add_autodocumenter(
type(
f"Autopg{capitalized}Documenter",
(
AutopgDocumenter,
getattr(autoapi.documenters, f"Autoapi{capitalized}Documenter"),
),
{"objtype": f"pg{name}"},
)
)
2 changes: 1 addition & 1 deletion docs/reST/ext/indexer.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ def collect_document_info(app, doctree):


class CollectInfo(Visitor):

"""Records the information for a document"""

desctypes = {
Expand All @@ -74,6 +73,7 @@ class CollectInfo(Visitor):
"exception",
"class",
"attribute",
"property",
"method",
"staticmethod",
"classmethod",
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ requires = [
"ninja<=1.11.1.1",
"cython<=3.0.11",
"sphinx<=7.2.6",
"autoapi<=3.3.2",
]
build-backend = 'mesonpy'

Expand Down
4 changes: 3 additions & 1 deletion src_py/camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ def _pre_init_placeholder_varargs(*_, **__):


class _PreInitPlaceholderCamera(AbstractCamera):
__init__ = _pre_init_placeholder_varargs
def __init__(self, *args, **kwargs):
_pre_init_placeholder()

start = _pre_init_placeholder_varargs
stop = _pre_init_placeholder_varargs
get_controls = _pre_init_placeholder_varargs
Expand Down

0 comments on commit bbedc0a

Please sign in to comment.