diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4a39ee3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +# Generated sphinx docs +docs/_build/ +# Generated API docs +/docs/source/api/ +!/docs/source/api/index.md diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 0000000..cbb61ae --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,23 @@ + +version: 2 + +formats: + - pdf + - htmlzip + +sphinx: + configuration: docs/source/conf.py + +build: + os: "ubuntu-22.04" + tools: + python: "3.11" + nodejs: "19" + jobs: + pre_build: + - npm install -g @bazel/bazelisk + - bazel run //docs:run_sphinx_build + +python: + install: + - requirements: docs/requirements.txt diff --git a/MODULE.bazel b/MODULE.bazel index 3d5f132..046e33e 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -4,9 +4,12 @@ module( compatibility_level = 1, ) +bazel_dep(name = "platforms", version = "0.0.6") bazel_dep(name = "bazel_skylib", version = "1.3.0") bazel_dep(name = "rules_license", version = "0.0.4") +# ===== The rest of these are development dependencies ===== + # TODO(https://github.com/bazelbuild/stardoc/issues/117): stardoc doesn't yet # work with bzlmod enabled. This defines the repo so load() works. bazel_dep( @@ -15,3 +18,30 @@ bazel_dep( dev_dependency = True, repo_name = "io_bazel_stardoc", ) +bazel_dep(name = "rules_python", version = "0.20.0", dev_dependency = True) + +python = use_extension( + "@rules_python//python:extensions.bzl", + "python", + dev_dependency = True, +) +python.toolchain( + name = "python3_11", + python_version = "3.11", +) +use_repo(python, "python3_11_toolchains") + +register_toolchains( + "@python3_11_toolchains//:all", +) + +pip = use_extension( + "@rules_python//python:extensions.bzl", + "pip", + dev_dependency = True, +) +pip.parse( + name = "docs-pypi", + requirements_lock = "//docs:requirements.txt", +) +use_repo(pip, "docs-pypi") diff --git a/WORKSPACE.bazel b/WORKSPACE.bazel index 24a914a..4f36512 100644 --- a/WORKSPACE.bazel +++ b/WORKSPACE.bazel @@ -34,3 +34,32 @@ http_archive( load("@io_bazel_stardoc//:setup.bzl", "stardoc_repositories") stardoc_repositories() + +http_archive( + name = "rules_python", + sha256 = "a644da969b6824cc87f8fe7b18101a8a6c57da5db39caa6566ec6109f37d2141", + strip_prefix = "rules_python-0.20.0", + url = "https://github.com/bazelbuild/rules_python/releases/download/0.20.0/rules_python-0.20.0.tar.gz", +) + +load("@rules_python//python:repositories.bzl", "python_register_toolchains") + +python_register_toolchains( + name = "python3_11", + # Available versions are listed in @rules_python//python:versions.bzl. + # We recommend using the same version your team is already standardized on. + python_version = "3.11", +) + +load("@python3_11//:defs.bzl", "interpreter") +load("@rules_python//python:pip.bzl", "pip_parse") + +pip_parse( + name = "docs-pypi", + python_interpreter_target = interpreter, + requirements_lock = "//docs:requirements.txt", +) + +load("@docs-pypi//:requirements.bzl", "install_deps") + +install_deps() diff --git a/docgen/BUILD b/docgen/BUILD index 7df0f37..3acaa53 100644 --- a/docgen/BUILD +++ b/docgen/BUILD @@ -1,38 +1,48 @@ -# Generated documentation for the docs/ directory - -load("@io_bazel_stardoc//stardoc:stardoc.bzl", "stardoc") -load("@bazel_skylib//rules:build_test.bzl", "build_test") +# Copyright 2023 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. -stardoc( - name = "truth", - out = "truth.md", - input = "//lib:truth.bzl", - tags = ["skip-bzlmod"], - deps = ["//lib:truth_bzl"], -) +# Generated documentation for the docs/ directory -stardoc( - name = "analysis_test", - out = "analysis_test.md", - input = "//lib:analysis_test.bzl", - tags = ["skip-bzlmod"], - deps = ["//lib:analysis_test_bzl"], -) +load(":docgen.bzl", "sphinx_stardocs") -stardoc( - name = "util", - out = "util.md", - input = "//lib:util.bzl", - tags = ["skip-bzlmod"], - deps = ["//lib:util_bzl"], +package( + default_applicable_licenses = ["//:package_license"], + default_visibility = ["//:__subpackages__"], ) -build_test( - name = "docs_build_test", - tags = ["skip-bzlmod"], - targets = [ - ":truth", - ":util", - ":analysis_test", +sphinx_stardocs( + name = "docs", + bzl_libraries = [ + "//lib:analysis_test_bzl", + "//lib:truth_bzl", + "//lib:util_bzl", + "//lib/private:action_subject_bzl", + "//lib/private:bool_subject_bzl", + "//lib/private:collection_subject_bzl", + "//lib/private:depset_file_subject_bzl", + "//lib/private:dict_subject_bzl", + "//lib/private:execution_info_subject_bzl", + "//lib/private:expect_bzl", + "//lib/private:expect_meta_bzl", + "//lib/private:file_subject_bzl", + "//lib/private:instrumented_files_info_subject_bzl", + "//lib/private:int_subject_bzl", + "//lib/private:label_subject_bzl", + "//lib/private:ordered_bzl", + "//lib/private:run_environment_info_subject_bzl", + "//lib/private:runfiles_subject_bzl", + "//lib/private:str_subject_bzl", + "//lib/private:target_subject_bzl", ], ) diff --git a/docgen/docgen.bzl b/docgen/docgen.bzl new file mode 100644 index 0000000..f89328a --- /dev/null +++ b/docgen/docgen.bzl @@ -0,0 +1,70 @@ +# Copyright 2023 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Rules to help generate rules_testing docs.""" + +load("@io_bazel_stardoc//stardoc:stardoc.bzl", "stardoc") +load("@bazel_skylib//rules:build_test.bzl", "build_test") + +def sphinx_stardocs(name, bzl_libraries, **kwargs): + """Generate Sphinx-friendly markdown docs using Stardoc for bzl libraries. + + Args: + name: str, the name of the resulting file group with the generated docs. + bzl_libraries: list of targets, the libraries to generate docs for. + The must be in "//foo:{name}_bzl" format; the `{name}` portion + will become the output file name. + **kwargs: Additional kwargs to pass onto generated targets (e.g. + tags) + """ + + # Stardoc doesn't yet work with bzlmod; we can detect this by + # looking for "@@" vs "@" in labels. + if "@@" in str(Label("//:X")): + kwargs["target_compatible_with"] = ["@platforms//:incompatible"] + + docs = [] + for label in bzl_libraries: + lib_name = Label(label).name.replace("_bzl", "") + + doc_rule_name = "_{}_{}".format(name, lib_name) + sphinx_stardoc( + name = "_{}_{}".format(name, lib_name), + out = lib_name + ".md", + input = label.replace("_bzl", ".bzl"), + deps = [label], + **kwargs + ) + docs.append(doc_rule_name) + + native.filegroup( + name = name, + srcs = docs, + **kwargs + ) + build_test( + name = name + "_build_test", + targets = docs, + **kwargs + ) + +def sphinx_stardoc(**kwargs): + stardoc( + # copybara-marker: stardoc format + func_template = "func_template.vm", + header_template = "header_template.vm", + rule_template = "rule_template.vm", + provider_template = "provider_template.vm", + **kwargs + ) diff --git a/docgen/func_template.vm b/docgen/func_template.vm new file mode 100644 index 0000000..ee6a2bf --- /dev/null +++ b/docgen/func_template.vm @@ -0,0 +1,56 @@ +#set( $nl = " +" ) +#set( $fn = $funcInfo.functionName) +#set( $fnl = $fn.replaceAll("[.]", "_").toLowerCase()) +{.starlark-object} +#[[##]]# $fn + +#set( $hasParams = false) +{.starlark-signature} +${funcInfo.functionName}(## Comment to consume newline +#foreach ($param in $funcInfo.getParameterList()) +#if($param.name != "self") +#set( $hasParams = true) +[${param.name}](#${fnl}_${param.name})## Comment to consume newline +#if(!$param.getDefaultValue().isEmpty()) +=$param.getDefaultValue()#end#if($foreach.hasNext), +#end +#end +#end +) + +${funcInfo.docString} + +#if ($hasParams) +{#${fnl}_parameters} +**PARAMETERS** [¶](#${fnl}_parameters){.headerlink} + +#foreach ($param in $funcInfo.getParameterList()) +#if($param.name != "self") +#set($link = $fnl + "_" + $param.name) +#if($foreach.first) +{.params-box} +#end +## The .span wrapper is necessary so the trailing colon doesn't wrap +:[${param.name}[¶](#$link){.headerlink}]{.span}: []{#$link} +#if(!$param.getDefaultValue().isEmpty())(_default `${param.getDefaultValue()}`_) #end +#if(!$param.docString.isEmpty()) + $param.docString.replaceAll("$nl", "$nl ") +#else + _undocumented_ +#end +#end +#end +#end +#if (!$funcInfo.getReturn().docString.isEmpty()) + +{#${fnl}_returns} +RETURNS [¶](#${fnl}_returns){.headerlink} +: ${funcInfo.getReturn().docString.replaceAll("$nl", "$nl ")} +#end +#if (!$funcInfo.getDeprecated().docString.isEmpty()) + +**DEPRECATED** + +${funcInfo.getDeprecated().docString} +#end diff --git a/docgen/header_template.vm b/docgen/header_template.vm new file mode 100644 index 0000000..fee7e2c --- /dev/null +++ b/docgen/header_template.vm @@ -0,0 +1 @@ +$moduleDocstring diff --git a/docgen/provider_template.vm b/docgen/provider_template.vm new file mode 100644 index 0000000..55e6871 --- /dev/null +++ b/docgen/provider_template.vm @@ -0,0 +1,29 @@ +#set( $nl = " +" ) +#set( $pn = $providerInfo.providerName) +#set( $pnl = $pn.replaceAll("[.]", "_").toLowerCase()) +{.starlark-object} +#[[##]]# ${providerName} + +#set( $hasFields = false) +{.starlark-signature} +${providerInfo.providerName}(## Comment to consume newline +#foreach ($field in $providerInfo.getFieldInfoList()) +#set( $hasFields = true) +[${field.name}](#${pnl}_${field.name})## Comment to consume newline +#if($foreach.hasNext), +#end +#end +) + +$providerInfo.docString + +#if ($hasFields) +**FIELDS** [¶](#${pnl}_fields){.headerlink} + +#foreach ($field in $providerInfo.getFieldInfoList()) +#set($link = $pnl + "_" + $field.name) +:[${field.name}[¶](#$link){.headerlink}]{.span}: []{#$link} + $field.docString.replaceAll("$nl", "$nl ") +#end +#end diff --git a/docgen/rule_template.vm b/docgen/rule_template.vm new file mode 100644 index 0000000..d91bad2 --- /dev/null +++ b/docgen/rule_template.vm @@ -0,0 +1,48 @@ +#set( $nl = " +" ) +#set( $rn = $ruleInfo.ruleName) +#set( $rnl = $rn.replaceAll("[.]", "_").toLowerCase()) +{.starlark-object} +#[[##]]# $ruleName + +#set( $hasAttrs = false) +{.starlark-signature} +${ruleInfo.ruleName}(## Comment to consume newline +#foreach ($attr in $ruleInfo.getAttributeList()) +#set( $hasAttrs = true) +[${attr.name}](#${rnl}_${attr.name})## Comment to consume newline +#if(!$attr.getDefaultValue().isEmpty()) +=$attr.getDefaultValue()#end#if($foreach.hasNext), +#end +#end +) + +$ruleInfo.docString + +#if ($hasAttrs) +{#${rnl}_attributes} +**ATTRIBUTES** [¶](#${rnl}_attributes){.headerlink} + +#foreach ($attr in $ruleInfo.getAttributeList()) +#set($link = $rnl + "_" + $attr.name) +#if($attr.mandatory) +#set($opt = "required") +#else +#set($opt = "optional") +#end +#if($attr.type == "NAME") +#set($type = "[Name][target-name]") +#elseif($attr.type == "LABEL_LIST") +#set($type = "list of [label][attr-label]s") +#end +#if(!$attr.getDefaultValue().isEmpty()) +#set($default = ", default `" + $attr.getDefaultValue() + "`") +#else +#set($default = "") +#end +:[${attr.name}[¶](#$link){.headerlink}]{.span}: []{#$link} + _($opt $type$default)_ + $attr.docString.replaceAll("$nl", "$nl ") + +#end +#end diff --git a/docs/BUILD b/docs/BUILD new file mode 100644 index 0000000..59d0295 --- /dev/null +++ b/docs/BUILD @@ -0,0 +1,74 @@ +# Copyright 2023 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load("@docs-pypi//:requirements.bzl", "requirement") +load("@rules_python//python:pip.bzl", "compile_pip_requirements") +load("@rules_python//python:py_binary.bzl", "py_binary") + +package( + default_applicable_licenses = ["//:package_license"], +) + +sh_binary( + name = "run_sphinx_build", + srcs = ["run_sphinx_build.sh"], + args = [ + "$(rootpath :sphinx_build)", + "$(rootpath :crossrefs.md)", + "$(rootpaths //docgen:docs)", + ], + data = [ + "crossrefs.md", + ":sphinx_build", + ":sphinx_sources", + "//docgen:docs", + ], +) + +py_binary( + name = "sphinx_build", + srcs = ["sphinx_build.py"], + deps = [ + requirement("sphinx"), + requirement("sphinx_rtd_theme"), + requirement("myst_parser"), + ], +) + +# Run bazel run //docs:requirements.update +compile_pip_requirements( + name = "requirements", + requirements_in = "requirements.in", + requirements_txt = "requirements.txt", + # The requirements output differs on Windows, so just restrict it to Linux. + # The build process is only run on, and only works for, Linux anyways. + target_compatible_with = ["@platforms//os:linux"], +) + +filegroup( + name = "sphinx_sources", + srcs = [ + # This isn't generated like the other files under the api directory, + # but it can't go in the glob because the exclude param will ignore it. + "source/api/index.md", + ] + glob( + [ + "**", + ], + exclude = [ + "source/api/**", # These are all generated files + "_build/**", + ], + ), +) diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..893a1b0 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,63 @@ +# rules_testing docs generation + +The docs for rules_testing are generated using a combination of Sphinx, Bazel, +and Readthedocs.org. The Markdown files in source control are unlikely to render +properly without the Sphinx processing step because they rely on Sphinx and +MyST-specific Markdown functionalit. + +The actual sources that Sphinx consumes are in the docs/source directory. + +Manually building the docs isn't necessary -- readthedocs.org will +automatically build and deploy them when commits are pushed to the repo. + +## Generating docs for development + +To generate docs for development/preview purposes, install +[ibazel](https://github.com/bazelbuild/bazel-watcher)[^ibazel] and run: + +``` +ibazel run //docs:run_sphinx_build +``` + +This will build the docs and start a local webserver at http://localhost:8000 +where you can view the output. As you edit files, ibazel will detect the file +changes and re-run the build process, and you can simply refresh your browser to +see the changes. + +## MyST Markdown flavor + +Sphinx is configured to parse Markdown files using MyST, which is a more +advanced flavor of Markdown that supports most features of restructured text and +integrates with Sphinx functionality such as automatic cross references, +creating indexes, and using concise markup to generate rich documentation. + +MyST features and behaviors are controlled by the Sphinx configuration file, +`docs/source/conf.py`. For more info, see https://myst-parser.readthedocs.io. + +## Sphinx configuration + +The Sphinx-specific configuration files and input doc files live in +docs/source -- anything under this directory will be treated by Sphinx as +something it should create documentation for. + +The Sphinx configuration is `docs/source/conf.py`. See +https://www.sphinx-doc.org/ for details about the configuration file. + +## Readthedocs configuration + +There's two basic parts to the readthedocs configuration: + +* `.readthedocs.yaml`: This configuration file controls most settings, such as + the OS version used to build, Python version, dependencies, what Bazel + commands to run, etc. +* https://readthedocs.org/projects/rules-testing: This is the project + administration page. While most settings come from the config file, this + controls additional settings such as permissions, what versions are + published, when to publish changes, etc. + +For more readthedocs configuration details, see docs.readthedocs.io. + +Of particular note, `//docs:requirements.txt` is used by readthedocs for +specifying Python dependencies (including Sphinx version). + +[^ibazel]: Quick install: `npm install -g @bazel/ibazel` diff --git a/docs/api.md b/docs/api.md deleted file mode 100644 index 6a6123f..0000000 --- a/docs/api.md +++ /dev/null @@ -1,4 +0,0 @@ -# API References - -* [analysis_test](api/analysis_test.md) -* [truth](api/truth.md) diff --git a/docs/crossrefs.md b/docs/crossrefs.md new file mode 100644 index 0000000..59d6be1 --- /dev/null +++ b/docs/crossrefs.md @@ -0,0 +1,26 @@ +[`Action`]: https://bazel.build/rules/lib/Action +[`ActionSubject`]: /api/action_subject +[`bool`]: https://bazel.build/rules/lib/bool +[`BoolSubject`]: /api/bool_subject +[`CollectionSubject`]: /api/collection_subject +[`depset`]: https://bazel.build/rules/lib/depset +[`DepsetFileSubject`]: /api/depset_file_subject +[`dict`]: https://bazel.build/rules/lib/dict +[`DictSubject`]: /api/dict_subject +[`Expect`]: /api/expect +[`ExpectMeta`]: /api/expect_meta +[`File`]: https://bazel.build/rules/lib/File +[`FileSubject`]: /api/file_subject +[`format_str`]: /api/expect_meta.html#expectmeta-format-str +[`IntSubject`]: /api/int_subject +[`Label`]: https://bazel.build/rules/lib/Label +[`LabelSubject`]: /api/label_subject +[`list`]: https://bazel.build/rules/lib/list +[`Ordered`]: /api/ordered +[`RunfilesSubject`]: /api/runfiles_subject +[`str`]: https://bazel.build/rules/lib/string +[`StrSubject`]: /api/str_subject +[`Target`]: https://bazel.build/rules/lib/Target +[`TargetSubject`]: /api/target_subject +[target-name]: https://bazel.build/concepts/labels#target-names +[attr-label]: https://bazel.build/concepts/labels diff --git a/docs/requirements.in b/docs/requirements.in new file mode 100644 index 0000000..aa179a4 --- /dev/null +++ b/docs/requirements.in @@ -0,0 +1,5 @@ +# NOTE: This is only used as input to create the resolved requirements.txt file, +# which is what builds, both Bazel and Readthedocs, both use. +sphinx +myst-parser +sphinx_rtd_theme diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 0000000..db2141e --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,288 @@ +# +# This file is autogenerated by pip-compile with Python 3.11 +# by the following command: +# +# bazel run //docs:requirements.update +# +alabaster==0.7.13 \ + --hash=sha256:1ee19aca801bbabb5ba3f5f258e4422dfa86f82f3e9cefb0859b283cdd7f62a3 \ + --hash=sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2 + # via sphinx +babel==2.12.1 \ + --hash=sha256:b4246fb7677d3b98f501a39d43396d3cafdc8eadb045f4a31be01863f655c610 \ + --hash=sha256:cc2d99999cd01d44420ae725a21c9e3711b3aadc7976d6147f622d8581963455 + # via sphinx +certifi==2022.12.7 \ + --hash=sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3 \ + --hash=sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18 + # via requests +charset-normalizer==3.1.0 \ + --hash=sha256:04afa6387e2b282cf78ff3dbce20f0cc071c12dc8f685bd40960cc68644cfea6 \ + --hash=sha256:04eefcee095f58eaabe6dc3cc2262f3bcd776d2c67005880894f447b3f2cb9c1 \ + --hash=sha256:0be65ccf618c1e7ac9b849c315cc2e8a8751d9cfdaa43027d4f6624bd587ab7e \ + --hash=sha256:0c95f12b74681e9ae127728f7e5409cbbef9cd914d5896ef238cc779b8152373 \ + --hash=sha256:0ca564606d2caafb0abe6d1b5311c2649e8071eb241b2d64e75a0d0065107e62 \ + --hash=sha256:10c93628d7497c81686e8e5e557aafa78f230cd9e77dd0c40032ef90c18f2230 \ + --hash=sha256:11d117e6c63e8f495412d37e7dc2e2fff09c34b2d09dbe2bee3c6229577818be \ + --hash=sha256:11d3bcb7be35e7b1bba2c23beedac81ee893ac9871d0ba79effc7fc01167db6c \ + --hash=sha256:12a2b561af122e3d94cdb97fe6fb2bb2b82cef0cdca131646fdb940a1eda04f0 \ + --hash=sha256:12d1a39aa6b8c6f6248bb54550efcc1c38ce0d8096a146638fd4738e42284448 \ + --hash=sha256:1435ae15108b1cb6fffbcea2af3d468683b7afed0169ad718451f8db5d1aff6f \ + --hash=sha256:1c60b9c202d00052183c9be85e5eaf18a4ada0a47d188a83c8f5c5b23252f649 \ + --hash=sha256:1e8fcdd8f672a1c4fc8d0bd3a2b576b152d2a349782d1eb0f6b8e52e9954731d \ + --hash=sha256:20064ead0717cf9a73a6d1e779b23d149b53daf971169289ed2ed43a71e8d3b0 \ + --hash=sha256:21fa558996782fc226b529fdd2ed7866c2c6ec91cee82735c98a197fae39f706 \ + --hash=sha256:22908891a380d50738e1f978667536f6c6b526a2064156203d418f4856d6e86a \ + --hash=sha256:3160a0fd9754aab7d47f95a6b63ab355388d890163eb03b2d2b87ab0a30cfa59 \ + --hash=sha256:322102cdf1ab682ecc7d9b1c5eed4ec59657a65e1c146a0da342b78f4112db23 \ + --hash=sha256:34e0a2f9c370eb95597aae63bf85eb5e96826d81e3dcf88b8886012906f509b5 \ + --hash=sha256:3573d376454d956553c356df45bb824262c397c6e26ce43e8203c4c540ee0acb \ + --hash=sha256:3747443b6a904001473370d7810aa19c3a180ccd52a7157aacc264a5ac79265e \ + --hash=sha256:38e812a197bf8e71a59fe55b757a84c1f946d0ac114acafaafaf21667a7e169e \ + --hash=sha256:3a06f32c9634a8705f4ca9946d667609f52cf130d5548881401f1eb2c39b1e2c \ + --hash=sha256:3a5fc78f9e3f501a1614a98f7c54d3969f3ad9bba8ba3d9b438c3bc5d047dd28 \ + --hash=sha256:3d9098b479e78c85080c98e1e35ff40b4a31d8953102bb0fd7d1b6f8a2111a3d \ + --hash=sha256:3dc5b6a8ecfdc5748a7e429782598e4f17ef378e3e272eeb1340ea57c9109f41 \ + --hash=sha256:4155b51ae05ed47199dc5b2a4e62abccb274cee6b01da5b895099b61b1982974 \ + --hash=sha256:49919f8400b5e49e961f320c735388ee686a62327e773fa5b3ce6721f7e785ce \ + --hash=sha256:53d0a3fa5f8af98a1e261de6a3943ca631c526635eb5817a87a59d9a57ebf48f \ + --hash=sha256:5f008525e02908b20e04707a4f704cd286d94718f48bb33edddc7d7b584dddc1 \ + --hash=sha256:628c985afb2c7d27a4800bfb609e03985aaecb42f955049957814e0491d4006d \ + --hash=sha256:65ed923f84a6844de5fd29726b888e58c62820e0769b76565480e1fdc3d062f8 \ + --hash=sha256:6734e606355834f13445b6adc38b53c0fd45f1a56a9ba06c2058f86893ae8017 \ + --hash=sha256:6baf0baf0d5d265fa7944feb9f7451cc316bfe30e8df1a61b1bb08577c554f31 \ + --hash=sha256:6f4f4668e1831850ebcc2fd0b1cd11721947b6dc7c00bf1c6bd3c929ae14f2c7 \ + --hash=sha256:6f5c2e7bc8a4bf7c426599765b1bd33217ec84023033672c1e9a8b35eaeaaaf8 \ + --hash=sha256:6f6c7a8a57e9405cad7485f4c9d3172ae486cfef1344b5ddd8e5239582d7355e \ + --hash=sha256:7381c66e0561c5757ffe616af869b916c8b4e42b367ab29fedc98481d1e74e14 \ + --hash=sha256:73dc03a6a7e30b7edc5b01b601e53e7fc924b04e1835e8e407c12c037e81adbd \ + --hash=sha256:74db0052d985cf37fa111828d0dd230776ac99c740e1a758ad99094be4f1803d \ + --hash=sha256:75f2568b4189dda1c567339b48cba4ac7384accb9c2a7ed655cd86b04055c795 \ + --hash=sha256:78cacd03e79d009d95635e7d6ff12c21eb89b894c354bd2b2ed0b4763373693b \ + --hash=sha256:80d1543d58bd3d6c271b66abf454d437a438dff01c3e62fdbcd68f2a11310d4b \ + --hash=sha256:830d2948a5ec37c386d3170c483063798d7879037492540f10a475e3fd6f244b \ + --hash=sha256:891cf9b48776b5c61c700b55a598621fdb7b1e301a550365571e9624f270c203 \ + --hash=sha256:8f25e17ab3039b05f762b0a55ae0b3632b2e073d9c8fc88e89aca31a6198e88f \ + --hash=sha256:9a3267620866c9d17b959a84dd0bd2d45719b817245e49371ead79ed4f710d19 \ + --hash=sha256:a04f86f41a8916fe45ac5024ec477f41f886b3c435da2d4e3d2709b22ab02af1 \ + --hash=sha256:aaf53a6cebad0eae578f062c7d462155eada9c172bd8c4d250b8c1d8eb7f916a \ + --hash=sha256:abc1185d79f47c0a7aaf7e2412a0eb2c03b724581139193d2d82b3ad8cbb00ac \ + --hash=sha256:ac0aa6cd53ab9a31d397f8303f92c42f534693528fafbdb997c82bae6e477ad9 \ + --hash=sha256:ac3775e3311661d4adace3697a52ac0bab17edd166087d493b52d4f4f553f9f0 \ + --hash=sha256:b06f0d3bf045158d2fb8837c5785fe9ff9b8c93358be64461a1089f5da983137 \ + --hash=sha256:b116502087ce8a6b7a5f1814568ccbd0e9f6cfd99948aa59b0e241dc57cf739f \ + --hash=sha256:b82fab78e0b1329e183a65260581de4375f619167478dddab510c6c6fb04d9b6 \ + --hash=sha256:bd7163182133c0c7701b25e604cf1611c0d87712e56e88e7ee5d72deab3e76b5 \ + --hash=sha256:c36bcbc0d5174a80d6cccf43a0ecaca44e81d25be4b7f90f0ed7bcfbb5a00909 \ + --hash=sha256:c3af8e0f07399d3176b179f2e2634c3ce9c1301379a6b8c9c9aeecd481da494f \ + --hash=sha256:c84132a54c750fda57729d1e2599bb598f5fa0344085dbde5003ba429a4798c0 \ + --hash=sha256:cb7b2ab0188829593b9de646545175547a70d9a6e2b63bf2cd87a0a391599324 \ + --hash=sha256:cca4def576f47a09a943666b8f829606bcb17e2bc2d5911a46c8f8da45f56755 \ + --hash=sha256:cf6511efa4801b9b38dc5546d7547d5b5c6ef4b081c60b23e4d941d0eba9cbeb \ + --hash=sha256:d16fd5252f883eb074ca55cb622bc0bee49b979ae4e8639fff6ca3ff44f9f854 \ + --hash=sha256:d2686f91611f9e17f4548dbf050e75b079bbc2a82be565832bc8ea9047b61c8c \ + --hash=sha256:d7fc3fca01da18fbabe4625d64bb612b533533ed10045a2ac3dd194bfa656b60 \ + --hash=sha256:dd5653e67b149503c68c4018bf07e42eeed6b4e956b24c00ccdf93ac79cdff84 \ + --hash=sha256:de5695a6f1d8340b12a5d6d4484290ee74d61e467c39ff03b39e30df62cf83a0 \ + --hash=sha256:e0ac8959c929593fee38da1c2b64ee9778733cdf03c482c9ff1d508b6b593b2b \ + --hash=sha256:e1b25e3ad6c909f398df8921780d6a3d120d8c09466720226fc621605b6f92b1 \ + --hash=sha256:e633940f28c1e913615fd624fcdd72fdba807bf53ea6925d6a588e84e1151531 \ + --hash=sha256:e89df2958e5159b811af9ff0f92614dabf4ff617c03a4c1c6ff53bf1c399e0e1 \ + --hash=sha256:ea9f9c6034ea2d93d9147818f17c2a0860d41b71c38b9ce4d55f21b6f9165a11 \ + --hash=sha256:f645caaf0008bacf349875a974220f1f1da349c5dbe7c4ec93048cdc785a3326 \ + --hash=sha256:f8303414c7b03f794347ad062c0516cee0e15f7a612abd0ce1e25caf6ceb47df \ + --hash=sha256:fca62a8301b605b954ad2e9c3666f9d97f63872aa4efcae5492baca2056b74ab + # via requests +docutils==0.18.1 \ + --hash=sha256:23010f129180089fbcd3bc08cfefccb3b890b0050e1ca00c867036e9d161b98c \ + --hash=sha256:679987caf361a7539d76e584cbeddc311e3aee937877c87346f31debc63e9d06 + # via + # myst-parser + # sphinx + # sphinx-rtd-theme +idna==3.4 \ + --hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 \ + --hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2 + # via requests +imagesize==1.4.1 \ + --hash=sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b \ + --hash=sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a + # via sphinx +jinja2==3.1.2 \ + --hash=sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852 \ + --hash=sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61 + # via + # myst-parser + # sphinx +markdown-it-py==2.2.0 \ + --hash=sha256:5a35f8d1870171d9acc47b99612dc146129b631baf04970128b568f190d0cc30 \ + --hash=sha256:7c9a5e412688bc771c67432cbfebcdd686c93ce6484913dccf06cb5a0bea35a1 + # via + # mdit-py-plugins + # myst-parser +markupsafe==2.1.2 \ + --hash=sha256:0576fe974b40a400449768941d5d0858cc624e3249dfd1e0c33674e5c7ca7aed \ + --hash=sha256:085fd3201e7b12809f9e6e9bc1e5c96a368c8523fad5afb02afe3c051ae4afcc \ + --hash=sha256:090376d812fb6ac5f171e5938e82e7f2d7adc2b629101cec0db8b267815c85e2 \ + --hash=sha256:0b462104ba25f1ac006fdab8b6a01ebbfbce9ed37fd37fd4acd70c67c973e460 \ + --hash=sha256:137678c63c977754abe9086a3ec011e8fd985ab90631145dfb9294ad09c102a7 \ + --hash=sha256:1bea30e9bf331f3fef67e0a3877b2288593c98a21ccb2cf29b74c581a4eb3af0 \ + --hash=sha256:22152d00bf4a9c7c83960521fc558f55a1adbc0631fbb00a9471e097b19d72e1 \ + --hash=sha256:22731d79ed2eb25059ae3df1dfc9cb1546691cc41f4e3130fe6bfbc3ecbbecfa \ + --hash=sha256:2298c859cfc5463f1b64bd55cb3e602528db6fa0f3cfd568d3605c50678f8f03 \ + --hash=sha256:28057e985dace2f478e042eaa15606c7efccb700797660629da387eb289b9323 \ + --hash=sha256:2e7821bffe00aa6bd07a23913b7f4e01328c3d5cc0b40b36c0bd81d362faeb65 \ + --hash=sha256:2ec4f2d48ae59bbb9d1f9d7efb9236ab81429a764dedca114f5fdabbc3788013 \ + --hash=sha256:340bea174e9761308703ae988e982005aedf427de816d1afe98147668cc03036 \ + --hash=sha256:40627dcf047dadb22cd25ea7ecfe9cbf3bbbad0482ee5920b582f3809c97654f \ + --hash=sha256:40dfd3fefbef579ee058f139733ac336312663c6706d1163b82b3003fb1925c4 \ + --hash=sha256:4cf06cdc1dda95223e9d2d3c58d3b178aa5dacb35ee7e3bbac10e4e1faacb419 \ + --hash=sha256:50c42830a633fa0cf9e7d27664637532791bfc31c731a87b202d2d8ac40c3ea2 \ + --hash=sha256:55f44b440d491028addb3b88f72207d71eeebfb7b5dbf0643f7c023ae1fba619 \ + --hash=sha256:608e7073dfa9e38a85d38474c082d4281f4ce276ac0010224eaba11e929dd53a \ + --hash=sha256:63ba06c9941e46fa389d389644e2d8225e0e3e5ebcc4ff1ea8506dce646f8c8a \ + --hash=sha256:65608c35bfb8a76763f37036547f7adfd09270fbdbf96608be2bead319728fcd \ + --hash=sha256:665a36ae6f8f20a4676b53224e33d456a6f5a72657d9c83c2aa00765072f31f7 \ + --hash=sha256:6d6607f98fcf17e534162f0709aaad3ab7a96032723d8ac8750ffe17ae5a0666 \ + --hash=sha256:7313ce6a199651c4ed9d7e4cfb4aa56fe923b1adf9af3b420ee14e6d9a73df65 \ + --hash=sha256:7668b52e102d0ed87cb082380a7e2e1e78737ddecdde129acadb0eccc5423859 \ + --hash=sha256:7df70907e00c970c60b9ef2938d894a9381f38e6b9db73c5be35e59d92e06625 \ + --hash=sha256:7e007132af78ea9df29495dbf7b5824cb71648d7133cf7848a2a5dd00d36f9ff \ + --hash=sha256:835fb5e38fd89328e9c81067fd642b3593c33e1e17e2fdbf77f5676abb14a156 \ + --hash=sha256:8bca7e26c1dd751236cfb0c6c72d4ad61d986e9a41bbf76cb445f69488b2a2bd \ + --hash=sha256:8db032bf0ce9022a8e41a22598eefc802314e81b879ae093f36ce9ddf39ab1ba \ + --hash=sha256:99625a92da8229df6d44335e6fcc558a5037dd0a760e11d84be2260e6f37002f \ + --hash=sha256:9cad97ab29dfc3f0249b483412c85c8ef4766d96cdf9dcf5a1e3caa3f3661cf1 \ + --hash=sha256:a4abaec6ca3ad8660690236d11bfe28dfd707778e2442b45addd2f086d6ef094 \ + --hash=sha256:a6e40afa7f45939ca356f348c8e23048e02cb109ced1eb8420961b2f40fb373a \ + --hash=sha256:a6f2fcca746e8d5910e18782f976489939d54a91f9411c32051b4aab2bd7c513 \ + --hash=sha256:a806db027852538d2ad7555b203300173dd1b77ba116de92da9afbc3a3be3eed \ + --hash=sha256:abcabc8c2b26036d62d4c746381a6f7cf60aafcc653198ad678306986b09450d \ + --hash=sha256:b8526c6d437855442cdd3d87eede9c425c4445ea011ca38d937db299382e6fa3 \ + --hash=sha256:bb06feb762bade6bf3c8b844462274db0c76acc95c52abe8dbed28ae3d44a147 \ + --hash=sha256:c0a33bc9f02c2b17c3ea382f91b4db0e6cde90b63b296422a939886a7a80de1c \ + --hash=sha256:c4a549890a45f57f1ebf99c067a4ad0cb423a05544accaf2b065246827ed9603 \ + --hash=sha256:ca244fa73f50a800cf8c3ebf7fd93149ec37f5cb9596aa8873ae2c1d23498601 \ + --hash=sha256:cf877ab4ed6e302ec1d04952ca358b381a882fbd9d1b07cccbfd61783561f98a \ + --hash=sha256:d9d971ec1e79906046aa3ca266de79eac42f1dbf3612a05dc9368125952bd1a1 \ + --hash=sha256:da25303d91526aac3672ee6d49a2f3db2d9502a4a60b55519feb1a4c7714e07d \ + --hash=sha256:e55e40ff0cc8cc5c07996915ad367fa47da6b3fc091fdadca7f5403239c5fec3 \ + --hash=sha256:f03a532d7dee1bed20bc4884194a16160a2de9ffc6354b3878ec9682bb623c54 \ + --hash=sha256:f1cd098434e83e656abf198f103a8207a8187c0fc110306691a2e94a78d0abb2 \ + --hash=sha256:f2bfb563d0211ce16b63c7cb9395d2c682a23187f54c3d79bfec33e6705473c6 \ + --hash=sha256:f8ffb705ffcf5ddd0e80b65ddf7bed7ee4f5a441ea7d3419e861a12eaf41af58 + # via jinja2 +mdit-py-plugins==0.3.5 \ + --hash=sha256:ca9a0714ea59a24b2b044a1831f48d817dd0c817e84339f20e7889f392d77c4e \ + --hash=sha256:eee0adc7195e5827e17e02d2a258a2ba159944a0748f59c5099a4a27f78fcf6a + # via myst-parser +mdurl==0.1.2 \ + --hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 \ + --hash=sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba + # via markdown-it-py +myst-parser==1.0.0 \ + --hash=sha256:502845659313099542bd38a2ae62f01360e7dd4b1310f025dd014dfc0439cdae \ + --hash=sha256:69fb40a586c6fa68995e6521ac0a525793935db7e724ca9bac1d33be51be9a4c + # via -r docs/requirements.in +packaging==23.0 \ + --hash=sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2 \ + --hash=sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97 + # via sphinx +pygments==2.15.0 \ + --hash=sha256:77a3299119af881904cd5ecd1ac6a66214b6e9bed1f2db16993b54adede64094 \ + --hash=sha256:f7e36cffc4c517fbc252861b9a6e4644ca0e5abadf9a113c72d1358ad09b9500 + # via sphinx +pyyaml==6.0 \ + --hash=sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf \ + --hash=sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293 \ + --hash=sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b \ + --hash=sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57 \ + --hash=sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b \ + --hash=sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4 \ + --hash=sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07 \ + --hash=sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba \ + --hash=sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9 \ + --hash=sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287 \ + --hash=sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513 \ + --hash=sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0 \ + --hash=sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782 \ + --hash=sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0 \ + --hash=sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92 \ + --hash=sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f \ + --hash=sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2 \ + --hash=sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc \ + --hash=sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1 \ + --hash=sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c \ + --hash=sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86 \ + --hash=sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4 \ + --hash=sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c \ + --hash=sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34 \ + --hash=sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b \ + --hash=sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d \ + --hash=sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c \ + --hash=sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb \ + --hash=sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7 \ + --hash=sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737 \ + --hash=sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3 \ + --hash=sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d \ + --hash=sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358 \ + --hash=sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53 \ + --hash=sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78 \ + --hash=sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803 \ + --hash=sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a \ + --hash=sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f \ + --hash=sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174 \ + --hash=sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5 + # via myst-parser +requests==2.28.2 \ + --hash=sha256:64299f4909223da747622c030b781c0d7811e359c37124b4bd368fb8c6518baa \ + --hash=sha256:98b1b2782e3c6c4904938b84c0eb932721069dfdb9134313beff7c83c2df24bf + # via sphinx +snowballstemmer==2.2.0 \ + --hash=sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1 \ + --hash=sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a + # via sphinx +sphinx==6.1.3 \ + --hash=sha256:0dac3b698538ffef41716cf97ba26c1c7788dba73ce6f150c1ff5b4720786dd2 \ + --hash=sha256:807d1cb3d6be87eb78a381c3e70ebd8d346b9a25f3753e9947e866b2786865fc + # via + # -r docs/requirements.in + # myst-parser + # sphinx-rtd-theme + # sphinxcontrib-jquery +sphinx-rtd-theme==1.2.0 \ + --hash=sha256:a0d8bd1a2ed52e0b338cbe19c4b2eef3c5e7a048769753dac6a9f059c7b641b8 \ + --hash=sha256:f823f7e71890abe0ac6aaa6013361ea2696fc8d3e1fa798f463e82bdb77eeff2 + # via -r docs/requirements.in +sphinxcontrib-applehelp==1.0.4 \ + --hash=sha256:29d341f67fb0f6f586b23ad80e072c8e6ad0b48417db2bde114a4c9746feb228 \ + --hash=sha256:828f867945bbe39817c210a1abfd1bc4895c8b73fcaade56d45357a348a07d7e + # via sphinx +sphinxcontrib-devhelp==1.0.2 \ + --hash=sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e \ + --hash=sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4 + # via sphinx +sphinxcontrib-htmlhelp==2.0.1 \ + --hash=sha256:0cbdd302815330058422b98a113195c9249825d681e18f11e8b1f78a2f11efff \ + --hash=sha256:c38cb46dccf316c79de6e5515e1770414b797162b23cd3d06e67020e1d2a6903 + # via sphinx +sphinxcontrib-jquery==4.1 \ + --hash=sha256:1620739f04e36a2c779f1a131a2dfd49b2fd07351bf1968ced074365933abc7a \ + --hash=sha256:f936030d7d0147dd026a4f2b5a57343d233f1fc7b363f68b3d4f1cb0993878ae + # via sphinx-rtd-theme +sphinxcontrib-jsmath==1.0.1 \ + --hash=sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178 \ + --hash=sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8 + # via sphinx +sphinxcontrib-qthelp==1.0.3 \ + --hash=sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72 \ + --hash=sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6 + # via sphinx +sphinxcontrib-serializinghtml==1.1.5 \ + --hash=sha256:352a9a00ae864471d3a7ead8d7d79f5fc0b57e8b3f95e9867eb9eb28999b92fd \ + --hash=sha256:aa5f6de5dfdf809ef505c4895e51ef5c9eac17d0f287933eb49ec495280b6952 + # via sphinx +urllib3==1.26.15 \ + --hash=sha256:8a388717b9476f934a21484e8c8e61875ab60644d29b9b39e11e4b9dc1c6b305 \ + --hash=sha256:aa751d169e23c7479ce47a0cb0da579e3ede798f994f5816a74e4f4500dcea42 + # via requests diff --git a/docs/run_sphinx_build.sh b/docs/run_sphinx_build.sh new file mode 100755 index 0000000..dea8984 --- /dev/null +++ b/docs/run_sphinx_build.sh @@ -0,0 +1,48 @@ +#!/bin/bash +# +# NOTE: This is meant to be run using `bazel run`. Directly running it +# won't work. +# +# Build docs for Sphinx. This is usually run by the readthedocs build process. +# +# It can also be run locally during development using Bazel, in which case, +# it will run Sphinx and start a local webserver to server HTML. +# +# To make the local devx nicer, run it using ibazel, and it will automatically +# update docs: +# ibazel run //docs:run_sphinx_build + +set -e + +if [[ -z "$BUILD_WORKSPACE_DIRECTORY" ]]; then + echo "ERROR: Must be run using bazel run" + exit 1 +fi + +sphinx=$(pwd)/$1 +shift + +crossrefs=$1 +shift + +dest_dir="$BUILD_WORKSPACE_DIRECTORY/docs/source/api" +mkdir -p "$dest_dir" +for path in "$@"; do + dest="$dest_dir/$(basename $path)" + if [[ -e $dest ]]; then + chmod +w $dest + fi + cat $path $crossrefs > $dest +done + +if [[ -z "$READTHEDOCS" ]]; then + sourcedir="$BUILD_WORKSPACE_DIRECTORY/docs/source" + outdir="$BUILD_WORKSPACE_DIRECTORY/docs/_build" + # This avoids stale files or since-deleted files from being processed. + rm -fr "$outdir" + "$sphinx" -T -b html "$sourcedir" "$outdir" + + echo "HTML built, to view, run:" + echo "python3 -m http.server --directory $outdir" + python3 -m http.server --directory "$outdir" +fi diff --git a/docs/source/_static/css/custom.css b/docs/source/_static/css/custom.css new file mode 100644 index 0000000..c97d2f5 --- /dev/null +++ b/docs/source/_static/css/custom.css @@ -0,0 +1,34 @@ +.wy-nav-content { + max-width: 70%; +} + +.starlark-object { + border: thin solid grey; + margin-bottom: 1em; +} + +.starlark-object h2 { + background-color: #e7f2fa; + border-bottom: thin solid grey; + padding-left: 0.5ex; +} + +.starlark-object>p, .starlark-object>dl { + /* Prevent the words from touching the border line */ + padding-left: 0.5ex; +} + +.starlark-signature { + font-family: monospace; +} + +/* Fixup the headerlinks in param names */ +.starlark-object dt a { + /* Offset the link icon to be outside the colon */ + position: relative; + right: -1ex; + /* Remove the empty space between the param name and colon */ + width: 0; + /* Override the .headerlink margin */ + margin-left: 0 !important; +} diff --git a/docs/analysis_tests.md b/docs/source/analysis_tests.md similarity index 100% rename from docs/analysis_tests.md rename to docs/source/analysis_tests.md diff --git a/docs/source/api/index.md b/docs/source/api/index.md new file mode 100644 index 0000000..b180478 --- /dev/null +++ b/docs/source/api/index.md @@ -0,0 +1,7 @@ +# API Reference + +```{toctree} +:glob: + +** +``` diff --git a/docs/source/conf.py b/docs/source/conf.py new file mode 100644 index 0000000..993d6f7 --- /dev/null +++ b/docs/source/conf.py @@ -0,0 +1,73 @@ +# Configuration file for the Sphinx documentation builder. + +# -- Project information +project = 'rules_testing' +copyright = '2023, The Bazel Authors' +author = 'Bazel' + +# Readthedocs fills these in +release = '0.0.0' +version = release + +# -- General configuration + +# Any extensions here not built into Sphinx must also be added to +# the dependencies of Bazel and Readthedocs. +# * //docs:requirements.in +# * Regenerate //docs:requirements.txt (used by readthedocs) +# * Add the dependencies to //docs:sphinx_build +extensions = [ + 'sphinx.ext.duration', + 'sphinx.ext.doctest', + 'sphinx.ext.autodoc', + 'sphinx.ext.autosummary', + 'sphinx.ext.intersphinx', + 'sphinx.ext.autosectionlabel', + 'myst_parser', + 'sphinx_rtd_theme', # Necessary to get jquery to make flyout work +] + +intersphinx_mapping = { +} + +intersphinx_disabled_domains = ['std'] + +# Prevent local refs from inadvertently linking elsewhere, per +# https://docs.readthedocs.io/en/stable/guides/intersphinx.html#using-intersphinx +intersphinx_disabled_reftypes = ["*"] + +templates_path = ['_templates'] + +# -- Options for HTML output + +html_theme = 'sphinx_rtd_theme' + +# See https://sphinx-rtd-theme.readthedocs.io/en/stable/configuring.html +# for options +html_theme_options = {} + +# Keep this in sync with the stardoc templates +html_permalinks_icon = '¶' + +# See https://myst-parser.readthedocs.io/en/latest/syntax/optional.html +# for additional extensions. +myst_enable_extensions = [ + "fieldlist", + "attrs_block", + "attrs_inline", + "colon_fence", + "deflist", +] + +# These folders are copied to the documentation's HTML output +html_static_path = ['_static'] + +# These paths are either relative to html_static_path +# or fully qualified paths (eg. https://...) +html_css_files = [ + 'css/custom.css', +] + +# -- Options for EPUB output +epub_show_urls = 'footnote' + diff --git a/docs/guides.md b/docs/source/guides.md similarity index 100% rename from docs/guides.md rename to docs/source/guides.md diff --git a/docs/index.md b/docs/source/index.md similarity index 82% rename from docs/index.md rename to docs/source/index.md index 38e7f8f..38cf0c2 100644 --- a/docs/index.md +++ b/docs/source/index.md @@ -3,6 +3,8 @@ rules_testing is a collection of utilities, libraries, and frameworks to make testing Starlark and Bazel rules easy and pleasant. +version |version| + ## Installation To use rules_testing, you need to modify `WORKSPACE` or `MODULE.bazel` @@ -28,10 +30,20 @@ config to copy and paste. Analysis testing means testing something during the analysis phase of Bazel execution -- this is when rule logic is run. -See [Analysis testing](analysis_testing.md) for how to write analysis tests. +See [Analysis tests](/analysis_tests.md) for how to write analysis tests. ## Fluent asserts Included in rules_testing is a fluent, truth-style asserts library. -See [Truth docs](truth.md) for how to use it. +See [Truth docs](/truth.md) for how to use it. + + +```{toctree} +:glob: +:hidden: + +self +* +api/index +``` diff --git a/docs/truth.md b/docs/source/truth.md similarity index 100% rename from docs/truth.md rename to docs/source/truth.md diff --git a/docs/sphinx_build.py b/docs/sphinx_build.py new file mode 100644 index 0000000..a06f380 --- /dev/null +++ b/docs/sphinx_build.py @@ -0,0 +1,4 @@ +import sys +from sphinx.cmd.build import main +if __name__ == "__main__": + sys.exit(main()) diff --git a/lib/analysis_test.bzl b/lib/analysis_test.bzl index 712f092..a0605e0 100644 --- a/lib/analysis_test.bzl +++ b/lib/analysis_test.bzl @@ -12,7 +12,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""Analysis testing support.""" +"""# Analysis test + +Support for testing analysis phase logic, such as rules. +""" load("//lib:truth.bzl", "truth") load("//lib:util.bzl", "recursive_testing_aspect", "testing_aspect") diff --git a/lib/private/BUILD b/lib/private/BUILD index 11afd9a..6372128 100644 --- a/lib/private/BUILD +++ b/lib/private/BUILD @@ -21,6 +21,11 @@ package( default_visibility = ["//:__subpackages__"], ) +# Necessary for documentation generation +exports_files( + glob(["*.bzl"]), +) + bzl_library( name = "matching_bzl", srcs = ["matching.bzl"], diff --git a/lib/private/action_subject.bzl b/lib/private/action_subject.bzl index 4a138f9..7de79fc 100644 --- a/lib/private/action_subject.bzl +++ b/lib/private/action_subject.bzl @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""ActionSubject implementation.""" +"""# ActionSubject""" load(":collection_subject.bzl", "CollectionSubject") load(":depset_file_subject.bzl", "DepsetFileSubject") @@ -96,6 +96,9 @@ def _action_subject_argv(self): """Returns a CollectionSubject for the action's argv. Method: ActionSubject.argv + + Returns: + [`CollectionSubject`] object. """ meta = self.meta.derive("argv()") return CollectionSubject.new( @@ -117,7 +120,8 @@ def _action_subject_contains_at_least_args(self, args): self: implicitly added. args: ([`list`] of [`str`]) all the args must be in the argv exactly as provided. Multiplicity is respected. - Returns + + Returns: [`Ordered`] (see `_ordered_incorrectly_new`). """ return CollectionSubject.new( @@ -181,7 +185,8 @@ def _action_subject_has_flags_specified(self, flags): Multiplicity is respected. A flag is considered present if any of these forms are detected: `--flag=value`, `--flag value`, or a lone `--flag`. - Returns + + Returns: [`Ordered`] (see `_ordered_incorrectly_new`). """ return CollectionSubject.new( @@ -313,7 +318,8 @@ def _action_subject_contains_at_least_inputs(self, inputs): self: implicitly added. inputs: (collection of [`File`]) All must be present. Multiplicity is respected. - Returns + + Returns: [`Ordered`] (see `_ordered_incorrectly_new`). """ return DepsetFileSubject.new( @@ -355,4 +361,17 @@ def _action_subject_env(self): # buildifier: disable=name-conventions ActionSubject = struct( new = _action_subject_new, + parse_flags = _action_subject_parse_flags, + argv = _action_subject_argv, + contains_at_least_args = _action_subject_contains_at_least_args, + not_contains_arg = _action_subject_not_contains_arg, + substitutions = _action_subject_substitutions, + has_flags_specified = _action_subject_has_flags_specified, + mnemonic = _action_subject_mnemonic, + inputs = _action_subject_inputs, + contains_flag_values = _action_subject_contains_flag_values, + contains_none_of_flag_values = _action_subject_contains_none_of_flag_values, + contains_at_least_inputs = _action_subject_contains_at_least_inputs, + content = _action_subject_content, + env = _action_subject_env, ) diff --git a/lib/private/bool_subject.bzl b/lib/private/bool_subject.bzl index 3252d39..d07f3c3 100644 --- a/lib/private/bool_subject.bzl +++ b/lib/private/bool_subject.bzl @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""BoolSubject implementation.""" +"""# BoolSubject""" load(":check_util.bzl", "check_not_equals", "common_subject_is_in") @@ -73,4 +73,6 @@ def _bool_subject_not_equals(self, unexpected): # buildifier: disable=name-conventions BoolSubject = struct( new = _bool_subject_new, + equals = _bool_subject_equals, + not_equals = _bool_subject_not_equals, ) diff --git a/lib/private/collection_subject.bzl b/lib/private/collection_subject.bzl index 514ad3d..38347b8 100644 --- a/lib/private/collection_subject.bzl +++ b/lib/private/collection_subject.bzl @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""CollectionSubject implementation.""" +"""# CollectionSubject""" load( ":check_util.bzl", @@ -129,7 +129,8 @@ def _collection_subject_contains_exactly(self, expected): Args: self: implicitly added. expected: ([`list`]) values that must exist. - Returns + + Returns: [`Ordered`] (see `_ordered_incorrectly_new`). """ expected = to_list(expected) @@ -184,7 +185,8 @@ def _collection_subject_contains_exactly_predicates(self, expected): Args: self: implicitly added. expected: ([`list`] of [`Matcher`]) that must match. - Returns + + Returns: [`Ordered`] (see `_ordered_incorrectly_new`). """ expected = to_list(expected) @@ -327,4 +329,13 @@ def _collection_subject_not_contains_predicate(self, matcher): # buildifier: disable=name-conventions CollectionSubject = struct( new = _collection_subject_new, + has_size = _collection_subject_has_size, + contains = _collection_subject_contains, + contains_exactly = _collection_subject_contains_exactly, + contains_exactly_predicates = _collection_subject_contains_exactly_predicates, + contains_none_of = _collection_subject_contains_none_of, + contains_predicate = _collection_subject_contains_predicate, + contains_at_least = _collection_subject_contains_at_least, + contains_at_least_predicates = _collection_subject_contains_at_least_predicates, + not_contains_predicate = _collection_subject_not_contains_predicate, ) diff --git a/lib/private/depset_file_subject.bzl b/lib/private/depset_file_subject.bzl index fce1611..554e3a5 100644 --- a/lib/private/depset_file_subject.bzl +++ b/lib/private/depset_file_subject.bzl @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""DepsetFileSubject implementation.""" +"""# DepsetFileSubject""" load("//lib:util.bzl", "is_file") load( @@ -113,6 +113,7 @@ def _depset_file_subject_contains_at_least(self, expected): `ExpectMeta.format_str` and its current contextual keywords. Note that, when using `File` objects, two files' configurations must be the same for them to be considered equal. + Returns: [`Ordered`] (see `_ordered_incorrectly_new`). """ @@ -280,4 +281,12 @@ def _depset_file_subject_not_contains_predicate(self, matcher): # buildifier: disable=name-conventions DepsetFileSubject = struct( new = _depset_file_subject_new, + contains = _depset_file_subject_contains, + contains_at_least = _depset_file_subject_contains_at_least, + contains_any_in = _depset_file_subject_contains_any_in, + contains_at_least_predicates = _depset_file_subject_contains_at_least_predicates, + contains_predicate = _depset_file_subject_contains_predicate, + contains_exactly = _depset_file_subject_contains_exactly, + not_contains = _depset_file_subject_not_contains, + not_contains_predicate = _depset_file_subject_not_contains_predicate, ) diff --git a/lib/private/dict_subject.bzl b/lib/private/dict_subject.bzl index ec01715..48d9463 100644 --- a/lib/private/dict_subject.bzl +++ b/lib/private/dict_subject.bzl @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""DictSubject implementation.""" +"""# DictSubject""" load(":collection_subject.bzl", "CollectionSubject") load(":compare_util.bzl", "compare_dicts") @@ -159,6 +159,7 @@ def _dict_subject_keys(self): Args: self: implicitly added + Returns: [`CollectionSubject`] of the keys. """ @@ -173,4 +174,8 @@ def _dict_subject_keys(self): # buildifier: disable=name-conventions DictSubject = struct( new = _dict_subject_new, + contains_at_least = _dict_subject_contains_at_least, + contains_exactly = _dict_subject_contains_exactly, + contains_none_of = _dict_subject_contains_none_of, + keys = _dict_subject_keys, ) diff --git a/lib/private/execution_info_subject.bzl b/lib/private/execution_info_subject.bzl index 069dba4..35524f6 100644 --- a/lib/private/execution_info_subject.bzl +++ b/lib/private/execution_info_subject.bzl @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""ExecutionInfoSubject implementation.""" +"""# ExecutionInfoSubject""" load(":dict_subject.bzl", "DictSubject") load(":str_subject.bzl", "StrSubject") @@ -79,4 +79,6 @@ def _execution_info_subject_exec_group(self): # buildifier: disable=name-conventions ExecutionInfoSubject = struct( new = _execution_info_subject_new, + requirements = _execution_info_subject_requirements, + exec_group = _execution_info_subject_exec_group, ) diff --git a/lib/private/expect.bzl b/lib/private/expect.bzl index 40e28e0..e568a54 100644 --- a/lib/private/expect.bzl +++ b/lib/private/expect.bzl @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""Expect object implementation.""" +"""# Expect""" load(":action_subject.bzl", "ActionSubject") load(":bool_subject.bzl", "BoolSubject") @@ -257,4 +257,15 @@ def _expect_where(self, **details): # buildifier: disable=name-conventions Expect = struct( new_from_env = _expect_new_from_env, + new = _expect_new, + that_action = _expect_that_action, + that_bool = _expect_that_bool, + that_collection = _expect_that_collection, + that_depset_of_files = _expect_that_depset_of_files, + that_dict = _expect_that_dict, + that_file = _expect_that_file, + that_int = _expect_that_int, + that_str = _expect_that_str, + that_target = _expect_that_target, + where = _expect_where, ) diff --git a/lib/private/expect_meta.bzl b/lib/private/expect_meta.bzl index e970cad..8ce9f1e 100644 --- a/lib/private/expect_meta.bzl +++ b/lib/private/expect_meta.bzl @@ -11,7 +11,10 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -"""ExpectMeta object implementation.""" +"""# ExpectMeta + +ExpectMeta object implementation. +""" load("@bazel_skylib//lib:unittest.bzl", ut_asserts = "asserts") @@ -173,6 +176,7 @@ def _expect_meta_get_provider(self, target, provider): self: implicitly added. target: ([`Target`]) the target to get the provider from. provider: The provider type to get. + Returns: The found provider, or fails if not present. """ @@ -191,6 +195,7 @@ def _expect_meta_has_provider(self, target, provider): self: implicitly added. target: ([`Target`]) the target to check for the provider. provider: the provider type to check for. + Returns: True if the target has the provider, False if not. """ @@ -264,4 +269,10 @@ def _expect_meta_call_fail(self, msg): # buildifier: disable=name-conventions ExpectMeta = struct( new = _expect_meta_new, + derive = _expect_meta_derive, + format_str = _expect_meta_format_str, + get_provider = _expect_meta_get_provider, + has_provider = _expect_meta_has_provider, + add_failure = _expect_meta_add_failure, + call_fail = _expect_meta_call_fail, ) diff --git a/lib/private/file_subject.bzl b/lib/private/file_subject.bzl index 80d876c..e8fc825 100644 --- a/lib/private/file_subject.bzl +++ b/lib/private/file_subject.bzl @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""FileSubject implementation.""" +"""# FileSubject""" load(":str_subject.bzl", "StrSubject") @@ -24,6 +24,7 @@ def _file_subject_new(file, meta): Args: file: ([`File`]) the file to assert against. meta: ([`ExpectMeta`]) + Returns: [`FileSubject`] object. """ @@ -97,4 +98,7 @@ def _file_subject_short_path_equals(self, path): # buildifier: disable=name-conventions FileSubject = struct( new = _file_subject_new, + equals = _file_subject_equals, + path = _file_subject_path, + short_path_equals = _file_subject_short_path_equals, ) diff --git a/lib/private/instrumented_files_info_subject.bzl b/lib/private/instrumented_files_info_subject.bzl index a228d87..4ba0b3b 100644 --- a/lib/private/instrumented_files_info_subject.bzl +++ b/lib/private/instrumented_files_info_subject.bzl @@ -11,7 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -"""InstrumentedFilesInfoSubject implementation.""" +"""# InstrumentedFilesInfoSubject""" load(":depset_file_subject.bzl", "DepsetFileSubject") @@ -68,4 +68,6 @@ def _instrumented_files_info_subject_metadata_files(self): # buildifier: disable=name-conventions InstrumentedFilesInfoSubject = struct( new = _instrumented_files_info_subject_new, + instrumented_files = _instrumented_files_info_subject_instrumented_files, + metadata_files = _instrumented_files_info_subject_metadata_files, ) diff --git a/lib/private/int_subject.bzl b/lib/private/int_subject.bzl index 237558b..cb8dda3 100644 --- a/lib/private/int_subject.bzl +++ b/lib/private/int_subject.bzl @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""IntSubject implementation.""" +"""# IntSubject""" load("@bazel_skylib//lib:types.bzl", "types") load(":check_util.bzl", "check_not_equals", "common_subject_is_in") @@ -96,4 +96,7 @@ def _int_subject_not_equals(self, unexpected): # buildifier: disable=name-conventions IntSubject = struct( new = _int_subject_new, + equals = _int_subject_equals, + is_greater_than = _int_subject_is_greater_than, + not_equals = _int_subject_not_equals, ) diff --git a/lib/private/label_subject.bzl b/lib/private/label_subject.bzl index 728c39c..f801ef7 100644 --- a/lib/private/label_subject.bzl +++ b/lib/private/label_subject.bzl @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""LabelSubject implementation.""" +"""# LabelSubject""" load("@bazel_skylib//lib:types.bzl", "types") load(":check_util.bzl", "common_subject_is_in") @@ -78,4 +78,6 @@ def _label_subject_is_in(self, any_of): # buildifier: disable=name-conventions LabelSubject = struct( new = _label_subject_new, + equals = _label_subject_equals, + is_in = _label_subject_is_in, ) diff --git a/lib/private/ordered.bzl b/lib/private/ordered.bzl index ca0271a..c9a0ed9 100644 --- a/lib/private/ordered.bzl +++ b/lib/private/ordered.bzl @@ -12,10 +12,14 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""Ordered objects implementions.""" +"""# Ordered""" + +# This is just a stub so doc generation is nicer. +def _ordered_in_order(): + """Checks that the values were in order.""" IN_ORDER = struct( - in_order = lambda: None, + in_order = _ordered_in_order, ) def _ordered_incorrectly_new(format_problem, format_actual, meta): @@ -56,4 +60,5 @@ def _ordered_incorrectly_in_order(self): # buildifier: disable=name-conventions OrderedIncorrectly = struct( new = _ordered_incorrectly_new, + in_order = _ordered_incorrectly_in_order, ) diff --git a/lib/private/run_environment_info_subject.bzl b/lib/private/run_environment_info_subject.bzl index 72a7d9a..43d9e67 100644 --- a/lib/private/run_environment_info_subject.bzl +++ b/lib/private/run_environment_info_subject.bzl @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""RunEnvironmentInfoSubject implementation.""" +"""# RunEnvironmentInfoSubject""" load(":collection_subject.bzl", "CollectionSubject") load(":dict_subject.bzl", "DictSubject") @@ -75,4 +75,6 @@ def _run_environment_info_subject_inherited_environment(self): # buildifier: disable=name-conventions RunEnvironmentInfoSubject = struct( new = _run_environment_info_subject_new, + environment = _run_environment_info_subject_environment, + inherited_environment = _run_environment_info_subject_inherited_environment, ) diff --git a/lib/private/runfiles_subject.bzl b/lib/private/runfiles_subject.bzl index 76aab9c..f517795 100644 --- a/lib/private/runfiles_subject.bzl +++ b/lib/private/runfiles_subject.bzl @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""RunfilesSubject implementation.""" +"""# RunfilesSubject""" load( "//lib:util.bzl", @@ -255,4 +255,12 @@ def _runfiles_subject_check_workspace_prefix(self, path): # buildifier: disable=name-conventions RunfilesSubject = struct( new = _runfiles_subject_new, + contains = _runfiles_subject_contains, + contains_at_least = _runfiles_subject_contains_at_least, + contains_predicate = _runfiles_subject_contains_predicate, + contains_exactly = _runfiles_subject_contains_exactly, + contains_none_of = _runfiles_subject_contains_none_of, + not_contains = _runfiles_subject_not_contains, + not_contains_predicate = _runfiles_subject_not_contains_predicate, + check_workspace_prefix = _runfiles_subject_check_workspace_prefix, ) diff --git a/lib/private/str_subject.bzl b/lib/private/str_subject.bzl index b8c41fb..c4655b1 100644 --- a/lib/private/str_subject.bzl +++ b/lib/private/str_subject.bzl @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""StrSubject implementation.""" +"""# StrSubject""" load( ":check_util.bzl", @@ -109,4 +109,8 @@ def _str_subject_split(self, sep): # buildifier: disable=name-conventions StrSubject = struct( new = _str_subject_new, + contains = _str_subject_contains, + equals = _str_subject_equals, + not_equals = _str_subject_not_equals, + split = _str_subject_split, ) diff --git a/lib/private/target_subject.bzl b/lib/private/target_subject.bzl index 1ffe7f5..47d8b94 100644 --- a/lib/private/target_subject.bzl +++ b/lib/private/target_subject.bzl @@ -12,7 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""TargetSubject implementation.""" +"""# TargetSubject + +`TargetSubject` wraps a [`Target`] object and provides method for asserting +its state. +""" load( "//lib:util.bzl", @@ -398,4 +402,18 @@ def _provider_name(provider): # buildifier: disable=name-conventions TargetSubject = struct( new = _target_subject_new, + runfiles = _target_subject_runfiles, + tags = _target_subject_tags, + get_attr = _target_subject_get_attr, + data_runfiles = _target_subject_data_runfiles, + default_outputs = _target_subject_default_outputs, + executable = _target_subject_executable, + failures = _target_subject_failures, + has_provider = _target_subject_has_provider, + label = _target_subject_label, + output_group = _target_subject_output_group, + provider = _target_subject_provider, + action_generating = _target_subject_action_generating, + action_named = _target_subject_action_named, + attr = _target_subject_attr, ) diff --git a/lib/private/truth_common.bzl b/lib/private/truth_common.bzl index 8d1cbe8..c7e6b60 100644 --- a/lib/private/truth_common.bzl +++ b/lib/private/truth_common.bzl @@ -31,6 +31,7 @@ def enumerate_list_as_lines(values, prefix = "", format_value = None): If not specified, then an appropriate converter will be inferred based on the values. If specified, then the callable must accept 1 positional arg and return a string. + Returns: [`str`]; the values formatted as a human-friendly list. """ diff --git a/lib/truth.bzl b/lib/truth.bzl index 56cb5cc..95f1fdd 100644 --- a/lib/truth.bzl +++ b/lib/truth.bzl @@ -12,7 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""Truth-style asserts for Bazel's Starlark. +"""# Truth + +Truth-style asserts for Bazel's Starlark. These asserts follow the Truth-style way of performing assertions. This basically means the actual value is wrapped in a type-specific object that diff --git a/lib/util.bzl b/lib/util.bzl index 10ad201..fba4e14 100644 --- a/lib/util.bzl +++ b/lib/util.bzl @@ -12,7 +12,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""Various utilities to aid with testing.""" +"""# Util + +Various utilities to aid with testing. +""" load("@bazel_skylib//lib:paths.bzl", "paths") load("@bazel_skylib//lib:types.bzl", "types")