1# Bazel plugin for Sphinx 2 3The `sphinx_bzl` Python package is a Sphinx plugin that defines a custom domain 4("bzl") in the Sphinx system. This provides first-class integration with Sphinx 5and allows code comments to provide rich information and allows manually writing 6docs for objects that aren't directly representable in bzl source code. For 7example, the fields of a provider can use `:type:` to indicate the type of a 8field, or manually written docs can use the `{bzl:target}` directive to document 9a well known target. 10 11## Configuring Sphinx 12 13To enable the plugin in Sphinx, depend on 14`@rules_python//sphinxdocs/src/sphinx_bzl` and enable it in `conf.py`: 15 16``` 17extensions = [ 18 "sphinx_bzl.bzl", 19] 20``` 21 22## Brief introduction to Sphinx terminology 23 24To aid understanding how to write docs, lets define a few common terms: 25 26* **Role**: A role is the "bzl:obj" part when writing ``{bzl:obj}`ref` ``. 27 Roles mark inline text as needing special processing. There's generally 28 two types of processing: creating cross references, or role-specific custom 29 rendering. For example `{bzl:obj}` will create a cross references, while 30 `{bzl:default-value}` indicates the default value of an argument. 31* **Directive**: A directive is indicated with `:::` and allows defining an 32 entire object and its parts. For example, to describe a function and its 33 arguments, the `:::{bzl:function}` directive is used. 34* **Directive Option**: A directive option is the "type" part when writing 35 `:type:` within a directive. Directive options are how directives are told 36 the meaning of certain values, such as the type of a provider field. Depending 37 on the object being documented, a directive option may be used instead of 38 special role to indicate semantic values. 39 40Most often, you'll be using roles to refer other objects or indicate special 41values in doc strings. For directives, you're likely to only use them when 42manually writing docs to document flags, targets, or other objects that 43`sphinx_stardoc` generates for you. 44 45## MyST vs RST 46 47By default, Sphinx uses ReStructured Text (RST) syntax for its documents. 48Unfortunately, RST syntax is very different than the popular Markdown syntax. To 49bridge the gap, MyST translates Markdown-style syntax into the RST equivalents. 50This allows easily using Markdown in bzl files. 51 52While MyST isn't required for the core `sphinx_bzl` plugin to work, this 53document uses MyST syntax because `sphinx_stardoc` bzl doc gen rule requires 54MyST. 55 56The main difference in syntax is: 57* MyST directives use `:::{name}` with closing `:::` instead of `.. name::` with 58 indented content. 59* MyST roles use `{role:name}` instead of `:role:name:` 60 61## Type expressions 62 63Several roles or fields accept type expressions. Type expressions use 64Python-style annotation syntax to describe data types. For example `None | list[str]` 65describes a type of "None or a list of strings". Each component of the 66expression is parsed and cross reference to its associated type definition. 67 68## Cross references 69 70In brief, to reference bzl objects, use the `bzl:obj` role and use the 71Bazel label string you would use to refer to the object in Bazel (using `%` to 72denote names within a file). For example, to unambiguously refer to `py_binary`: 73 74``` 75{bzl:obj}`@rules_python//python:py_binary.bzl%py_binary` 76``` 77 78The above is pretty long, so shorter names are also supported, and `sphinx_bzl` 79will try to find something that matches. Additionally, in `.bzl` code, the 80`bzl:` prefix is set as the default. The above can then be shortened to: 81 82``` 83{obj}`py_binary` 84``` 85 86The text that is displayed can be customized by putting the reference string in 87chevrons (`<>`): 88 89``` 90{obj}`the binary rule <py_binary>` 91``` 92 93Specific types of objects (rules, functions, providers, etc) can be 94specified to help disambiguate short names: 95 96``` 97{function}`py_binary` # Refers to the wrapping macro 98{rule}`py_binary` # Refers to the underlying rule 99``` 100 101Finally, objects built into Bazel can be explicitly referenced by forcing 102a lookup outside the local project using `{external}`. For example, the symbol 103`toolchain` is a builtin Bazel function, but it could also be the name of a tag 104class in the local project. To force looking up the builtin Bazel `toolchain` rule, 105`{external:bzl:rule}` can be used, e.g.: 106 107``` 108{external:bzl:obj}`toolchain` 109``` 110 111Those are the basics of cross referencing. Sphinx has several additional 112syntaxes for finding and referencing objects; see 113[the MyST docs for supported 114syntaxes](https://myst-parser.readthedocs.io/en/latest/syntax/cross-referencing.html#reference-roles) 115 116### Cross reference roles 117 118A cross reference role is the `obj` portion of `{bzl:obj}`. It affects what is 119searched and matched. 120 121:::{note} 122The documentation renders using RST notation (`:foo:role:`), not 123MyST notation (`{foo:role}`. 124::: 125 126:::{rst:role} bzl:arg 127Refer to a function argument. 128::: 129 130:::{rst:role} bzl:attr 131Refer to a rule attribute. 132::: 133 134:::{rst:role} bzl:flag 135Refer to a flag. 136::: 137 138:::{rst:role} bzl:obj 139Refer to any type of Bazel object 140::: 141 142:::{rst:role} bzl:rule 143Refer to a rule. 144::: 145 146:::{rst:role} bzl:target 147Refer to a target. 148::: 149 150:::{rst:role} bzl:type 151Refer to a type or type expression; can also be used in argument documentation. 152 153``` 154def func(arg): 155 """Do stuff 156 157 Args: 158 arg: {type}`int | str` the arg 159 """ 160 print(arg + 1) 161``` 162::: 163 164## Special roles 165 166There are several special roles that can be used to annotate parts of objects, 167such as the type of arguments or their default values. 168 169:::{note} 170The documentation renders using RST notation (`:foo:role:`), not 171MyST notation (`{foo:role}`. 172::: 173 174:::{rst:role} bzl:default-value 175 176Indicate the default value for a function argument or rule attribute. Use it in 177the Args doc of a function or the doc text of an attribute. 178 179``` 180def func(arg=1): 181 """Do stuff 182 183 Args: 184 foo: {default-value}`1` the arg 185 186my_rule = rule(attrs = { 187 "foo": attr.string(doc="{default-value}`bar`) 188}) 189 190``` 191::: 192 193:::{rst:role} bzl:return-type 194 195Indicates the return type for a function. Use it in the Returns doc of a 196function. 197 198``` 199def func(): 200 """Do stuff 201 202 Returns: 203 {return-type}`int` 204 """ 205 return 1 206``` 207::: 208 209## Directives 210 211Most directives are automatically generated by `sphinx_stardoc`. Here, we only 212document ones that must be manually written. 213 214To write a directive, a line starts with 3 to 6 colons (`:`), followed by the 215directive name in braces (`{}`), and eventually ended by the same number of 216colons on their own line. For example: 217 218``` 219:::{bzl:target} //my:target 220 221Doc about target 222::: 223``` 224 225:::{note} 226The documentation renders using RST notation (`.. directive::`), not 227MyST notation. 228::: 229 230:::{rst:directive} .. bzl:currentfile:: file 231 232This directive indicates the Bazel file that objects defined in the current 233documentation file are in. This is required for any page that defines Bazel 234objects. The format of `file` is Bazel label syntax, e.g. `//foo:bar.bzl` for bzl 235files, and `//foo:BUILD.bazel` for things in BUILD files. 236 237::: 238 239 240:::{rst:directive} .. bzl:target:: target 241 242Documents a target. It takes no directive options. The format of `target` 243can either be a fully qualified label (`//foo:bar`), or the base target name 244relative to `{bzl:currentfile}`. 245 246``` 247:::{bzl:target} //foo:target 248 249My docs 250::: 251``` 252 253:::{rst:directive} .. bzl:flag:: target 254 255Documents a flag. It has the same format as `{bzl:target}` 256::: 257 258