From bfa18f92e4a040f5731a1c32c4db19e24b05fb17 Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Fri, 11 Oct 2024 11:18:44 -0700 Subject: [PATCH] wip: use sphinxdocs for docgen --- .bazelci/presubmit.yml | 1 - .gitignore | 5 - .readthedocs.yaml | 23 +- MODULE.bazel | 7 +- MODULE.bazel.lock | 161 ++++++ WORKSPACE.bazel | 20 +- docgen/BUILD | 51 -- docgen/docgen.bzl | 65 --- docgen/func_template.vm | 56 -- docgen/header_template.vm | 1 - docgen/provider_template.vm | 29 - docgen/rule_template.vm | 48 -- docs/BUILD | 101 ++-- docs/{source => }/_static/css/custom.css | 0 docs/{source => }/analysis_tests.md | 0 docs/{source => }/api/index.md | 0 docs/{source => }/best_practices.md | 0 docs/{source => }/conf.py | 4 +- docs/crossrefs.md | 28 - docs/{source => }/guides.md | 0 docs/{source => }/index.md | 0 docs/readthedocs_build.sh | 20 + docs/requirements.in | 2 + docs/requirements.txt | 527 ++++++++++-------- docs/run_sphinx_build.sh | 48 -- docs/sphinx_build.py | 4 - docs/{source => }/test_suite.md | 0 docs/{source => }/truth.md | 0 docs/{source => }/unit_tests.md | 0 lib/analysis_test.bzl | 7 +- lib/private/action_subject.bzl | 57 +- lib/private/analysis_test.bzl | 2 +- lib/private/bool_subject.bzl | 27 +- lib/private/collection_subject.bzl | 71 ++- lib/private/default_info_subject.bzl | 29 +- lib/private/depset_file_subject.bzl | 57 +- lib/private/dict_subject.bzl | 35 +- lib/private/execution_info_subject.bzl | 24 +- lib/private/expect.bzl | 90 +-- lib/private/expect_meta.bzl | 141 +++-- lib/private/file_subject.bzl | 28 +- .../instrumented_files_info_subject.bzl | 29 +- lib/private/int_subject.bzl | 26 +- lib/private/label_subject.bzl | 24 +- lib/private/matching.bzl | 84 +-- lib/private/ordered.bzl | 19 +- lib/private/run_environment_info_subject.bzl | 23 +- lib/private/runfiles_subject.bzl | 49 +- lib/private/str_subject.bzl | 33 +- lib/private/struct_subject.bzl | 36 +- lib/private/target_subject.bzl | 55 +- lib/truth.bzl | 12 +- lib/util.bzl | 5 +- 53 files changed, 1192 insertions(+), 972 deletions(-) create mode 100644 MODULE.bazel.lock delete mode 100644 docgen/BUILD delete mode 100644 docgen/docgen.bzl delete mode 100644 docgen/func_template.vm delete mode 100644 docgen/header_template.vm delete mode 100644 docgen/provider_template.vm delete mode 100644 docgen/rule_template.vm rename docs/{source => }/_static/css/custom.css (100%) rename docs/{source => }/analysis_tests.md (100%) rename docs/{source => }/api/index.md (100%) rename docs/{source => }/best_practices.md (100%) rename docs/{source => }/conf.py (93%) delete mode 100644 docs/crossrefs.md rename docs/{source => }/guides.md (100%) rename docs/{source => }/index.md (100%) create mode 100755 docs/readthedocs_build.sh delete mode 100755 docs/run_sphinx_build.sh delete mode 100644 docs/sphinx_build.py rename docs/{source => }/test_suite.md (100%) rename docs/{source => }/truth.md (100%) rename docs/{source => }/unit_tests.md (100%) diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml index 1512cd1..df8c79a 100644 --- a/.bazelci/presubmit.yml +++ b/.bazelci/presubmit.yml @@ -38,7 +38,6 @@ tasks: test_flags: - "--enable_bzlmod" test_targets: - - "//docgen/..." - "//docs/..." e2e_bzlmod: diff --git a/.gitignore b/.gitignore index 4a39ee3..e69de29 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +0,0 @@ -# Generated sphinx docs -docs/_build/ -# Generated API docs -/docs/source/api/ -!/docs/source/api/index.md diff --git a/.readthedocs.yaml b/.readthedocs.yaml index cbb61ae..f6470d0 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -1,23 +1,14 @@ 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 + commands: + - env + - npm install -g @bazel/bazelisk + - bazel version + # Put the actual action behind a shell script because it's + # easier to modify than the yaml config. + - docs/readthedocs_build.sh diff --git a/MODULE.bazel b/MODULE.bazel index d5d2672..52c0453 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -4,6 +4,7 @@ module( compatibility_level = 1, ) +bazel_dep(name = "rules_python", version = "0.37.0") 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") @@ -18,7 +19,6 @@ bazel_dep( dev_dependency = True, repo_name = "io_bazel_stardoc", ) -bazel_dep(name = "rules_python", version = "0.27.0", dev_dependency = True) python = use_extension( "@rules_python//python/extensions:python.bzl", @@ -40,3 +40,8 @@ pip.parse( requirements_lock = "//docs:requirements.txt", ) use_repo(pip, "docs-pypi") + +##local_path_override( +## module_name = "rules_python", +## path = "../rules_python", +##) diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock new file mode 100644 index 0000000..4d25060 --- /dev/null +++ b/MODULE.bazel.lock @@ -0,0 +1,161 @@ +{ + "lockFileVersion": 11, + "registryFileHashes": { + "https://bcr.bazel.build/bazel_registry.json": "8a28e4aff06ee60aed2a8c281907fb8bcbf3b753c91fb5a5c57da3215d5b3497", + "https://bcr.bazel.build/modules/abseil-cpp/20210324.2/MODULE.bazel": "7cd0312e064fde87c8d1cd79ba06c876bd23630c83466e9500321be55c96ace2", + "https://bcr.bazel.build/modules/abseil-cpp/20211102.0/MODULE.bazel": "70390338f7a5106231d20620712f7cccb659cd0e9d073d1991c038eb9fc57589", + "https://bcr.bazel.build/modules/abseil-cpp/20230125.1/MODULE.bazel": "89047429cb0207707b2dface14ba7f8df85273d484c2572755be4bab7ce9c3a0", + "https://bcr.bazel.build/modules/abseil-cpp/20230802.0.bcr.1/MODULE.bazel": "1c8cec495288dccd14fdae6e3f95f772c1c91857047a098fad772034264cc8cb", + "https://bcr.bazel.build/modules/abseil-cpp/20230802.0.bcr.1/source.json": "14892cc698e02ffedf4967546e6bedb7245015906888d3465fcf27c90a26da10", + "https://bcr.bazel.build/modules/apple_support/1.5.0/MODULE.bazel": "50341a62efbc483e8a2a6aec30994a58749bd7b885e18dd96aa8c33031e558ef", + "https://bcr.bazel.build/modules/apple_support/1.5.0/source.json": "eb98a7627c0bc486b57f598ad8da50f6625d974c8f723e9ea71bd39f709c9862", + "https://bcr.bazel.build/modules/bazel_features/1.11.0/MODULE.bazel": "f9382337dd5a474c3b7d334c2f83e50b6eaedc284253334cf823044a26de03e8", + "https://bcr.bazel.build/modules/bazel_features/1.11.0/source.json": "c9320aa53cd1c441d24bd6b716da087ad7e4ff0d9742a9884587596edfe53015", + "https://bcr.bazel.build/modules/bazel_features/1.9.1/MODULE.bazel": "8f679097876a9b609ad1f60249c49d68bfab783dd9be012faf9d82547b14815a", + "https://bcr.bazel.build/modules/bazel_skylib/1.0.3/MODULE.bazel": "bcb0fd896384802d1ad283b4e4eb4d718eebd8cb820b0a2c3a347fb971afd9d8", + "https://bcr.bazel.build/modules/bazel_skylib/1.2.0/MODULE.bazel": "44fe84260e454ed94ad326352a698422dbe372b21a1ac9f3eab76eb531223686", + "https://bcr.bazel.build/modules/bazel_skylib/1.2.1/MODULE.bazel": "f35baf9da0efe45fa3da1696ae906eea3d615ad41e2e3def4aeb4e8bc0ef9a7a", + "https://bcr.bazel.build/modules/bazel_skylib/1.3.0/MODULE.bazel": "20228b92868bf5cfc41bda7afc8a8ba2a543201851de39d990ec957b513579c5", + "https://bcr.bazel.build/modules/bazel_skylib/1.4.1/MODULE.bazel": "a0dcb779424be33100dcae821e9e27e4f2901d9dfd5333efe5ac6a8d7ab75e1d", + "https://bcr.bazel.build/modules/bazel_skylib/1.4.2/MODULE.bazel": "3bd40978e7a1fac911d5989e6b09d8f64921865a45822d8b09e815eaa726a651", + "https://bcr.bazel.build/modules/bazel_skylib/1.5.0/MODULE.bazel": "32880f5e2945ce6a03d1fbd588e9198c0a959bb42297b2cfaf1685b7bc32e138", + "https://bcr.bazel.build/modules/bazel_skylib/1.6.1/MODULE.bazel": "8fdee2dbaace6c252131c00e1de4b165dc65af02ea278476187765e1a617b917", + "https://bcr.bazel.build/modules/bazel_skylib/1.6.1/source.json": "082ed5f9837901fada8c68c2f3ddc958bb22b6d654f71dd73f3df30d45d4b749", + "https://bcr.bazel.build/modules/buildozer/7.1.2/MODULE.bazel": "2e8dd40ede9c454042645fd8d8d0cd1527966aa5c919de86661e62953cd73d84", + "https://bcr.bazel.build/modules/buildozer/7.1.2/source.json": "c9028a501d2db85793a6996205c8de120944f50a0d570438fcae0457a5f9d1f8", + "https://bcr.bazel.build/modules/googletest/1.11.0/MODULE.bazel": "3a83f095183f66345ca86aa13c58b59f9f94a2f81999c093d4eeaa2d262d12f4", + "https://bcr.bazel.build/modules/googletest/1.14.0/MODULE.bazel": "cfbcbf3e6eac06ef9d85900f64424708cc08687d1b527f0ef65aa7517af8118f", + "https://bcr.bazel.build/modules/googletest/1.14.0/source.json": "2478949479000fdd7de9a3d0107ba2c85bb5f961c3ecb1aa448f52549ce310b5", + "https://bcr.bazel.build/modules/platforms/0.0.4/MODULE.bazel": "9b328e31ee156f53f3c416a64f8491f7eb731742655a47c9eec4703a71644aee", + "https://bcr.bazel.build/modules/platforms/0.0.5/MODULE.bazel": "5733b54ea419d5eaf7997054bb55f6a1d0b5ff8aedf0176fef9eea44f3acda37", + "https://bcr.bazel.build/modules/platforms/0.0.6/MODULE.bazel": "ad6eeef431dc52aefd2d77ed20a4b353f8ebf0f4ecdd26a807d2da5aa8cd0615", + "https://bcr.bazel.build/modules/platforms/0.0.7/MODULE.bazel": "72fd4a0ede9ee5c021f6a8dd92b503e089f46c227ba2813ff183b71616034814", + "https://bcr.bazel.build/modules/platforms/0.0.8/MODULE.bazel": "9f142c03e348f6d263719f5074b21ef3adf0b139ee4c5133e2aa35664da9eb2d", + "https://bcr.bazel.build/modules/platforms/0.0.9/MODULE.bazel": "4a87a60c927b56ddd67db50c89acaa62f4ce2a1d2149ccb63ffd871d5ce29ebc", + "https://bcr.bazel.build/modules/platforms/0.0.9/source.json": "cd74d854bf16a9e002fb2ca7b1a421f4403cda29f824a765acd3a8c56f8d43e6", + "https://bcr.bazel.build/modules/protobuf/21.7/MODULE.bazel": "a5a29bb89544f9b97edce05642fac225a808b5b7be74038ea3640fae2f8e66a7", + "https://bcr.bazel.build/modules/protobuf/23.1/MODULE.bazel": "88b393b3eb4101d18129e5db51847cd40a5517a53e81216144a8c32dfeeca52a", + "https://bcr.bazel.build/modules/protobuf/24.4/MODULE.bazel": "7bc7ce5f2abf36b3b7b7c8218d3acdebb9426aeb35c2257c96445756f970eb12", + "https://bcr.bazel.build/modules/protobuf/24.4/source.json": "ace4b8c65d4cfe64efe544f09fc5e5df77faf3a67fbb29c5341e0d755d9b15d6", + "https://bcr.bazel.build/modules/protobuf/3.19.0/MODULE.bazel": "6b5fbb433f760a99a22b18b6850ed5784ef0e9928a72668b66e4d7ccd47db9b0", + "https://bcr.bazel.build/modules/protobuf/3.19.6/MODULE.bazel": "9233edc5e1f2ee276a60de3eaa47ac4132302ef9643238f23128fea53ea12858", + "https://bcr.bazel.build/modules/rules_cc/0.0.1/MODULE.bazel": "cb2aa0747f84c6c3a78dad4e2049c154f08ab9d166b1273835a8174940365647", + "https://bcr.bazel.build/modules/rules_cc/0.0.2/MODULE.bazel": "6915987c90970493ab97393024c156ea8fb9f3bea953b2f3ec05c34f19b5695c", + "https://bcr.bazel.build/modules/rules_cc/0.0.6/MODULE.bazel": "abf360251023dfe3efcef65ab9d56beefa8394d4176dd29529750e1c57eaa33f", + "https://bcr.bazel.build/modules/rules_cc/0.0.8/MODULE.bazel": "964c85c82cfeb6f3855e6a07054fdb159aced38e99a5eecf7bce9d53990afa3e", + "https://bcr.bazel.build/modules/rules_cc/0.0.9/MODULE.bazel": "836e76439f354b89afe6a911a7adf59a6b2518fafb174483ad78a2a2fde7b1c5", + "https://bcr.bazel.build/modules/rules_cc/0.0.9/source.json": "1f1ba6fea244b616de4a554a0f4983c91a9301640c8fe0dd1d410254115c8430", + "https://bcr.bazel.build/modules/rules_java/4.0.0/MODULE.bazel": "5a78a7ae82cd1a33cef56dc578c7d2a46ed0dca12643ee45edbb8417899e6f74", + "https://bcr.bazel.build/modules/rules_java/6.3.0/MODULE.bazel": "a97c7678c19f236a956ad260d59c86e10a463badb7eb2eda787490f4c969b963", + "https://bcr.bazel.build/modules/rules_java/7.1.0/MODULE.bazel": "30d9135a2b6561c761bd67bd4990da591e6bdc128790ce3e7afd6a3558b2fb64", + "https://bcr.bazel.build/modules/rules_java/7.6.5/MODULE.bazel": "481164be5e02e4cab6e77a36927683263be56b7e36fef918b458d7a8a1ebadb1", + "https://bcr.bazel.build/modules/rules_java/7.6.5/source.json": "a805b889531d1690e3c72a7a7e47a870d00323186a9904b36af83aa3d053ee8d", + "https://bcr.bazel.build/modules/rules_jvm_external/4.4.2/MODULE.bazel": "a56b85e418c83eb1839819f0b515c431010160383306d13ec21959ac412d2fe7", + "https://bcr.bazel.build/modules/rules_jvm_external/5.1/MODULE.bazel": "33f6f999e03183f7d088c9be518a63467dfd0be94a11d0055fe2d210f89aa909", + "https://bcr.bazel.build/modules/rules_jvm_external/5.2/MODULE.bazel": "d9351ba35217ad0de03816ef3ed63f89d411349353077348a45348b096615036", + "https://bcr.bazel.build/modules/rules_jvm_external/5.2/source.json": "10572111995bc349ce31c78f74b3c147f6b3233975c7fa5eff9211f6db0d34d9", + "https://bcr.bazel.build/modules/rules_license/0.0.3/MODULE.bazel": "627e9ab0247f7d1e05736b59dbb1b6871373de5ad31c3011880b4133cafd4bd0", + "https://bcr.bazel.build/modules/rules_license/0.0.4/MODULE.bazel": "6a88dd22800cf1f9f79ba32cacad0d3a423ed28efa2c2ed5582eaa78dd3ac1e5", + "https://bcr.bazel.build/modules/rules_license/0.0.7/MODULE.bazel": "088fbeb0b6a419005b89cf93fe62d9517c0a2b8bb56af3244af65ecfe37e7d5d", + "https://bcr.bazel.build/modules/rules_license/0.0.7/source.json": "355cc5737a0f294e560d52b1b7a6492d4fff2caf0bef1a315df5a298fca2d34a", + "https://bcr.bazel.build/modules/rules_pkg/0.7.0/MODULE.bazel": "df99f03fc7934a4737122518bb87e667e62d780b610910f0447665a7e2be62dc", + "https://bcr.bazel.build/modules/rules_pkg/0.7.0/source.json": "c2557066e0c0342223ba592510ad3d812d4963b9024831f7f66fd0584dd8c66c", + "https://bcr.bazel.build/modules/rules_proto/4.0.0/MODULE.bazel": "a7a7b6ce9bee418c1a760b3d84f83a299ad6952f9903c67f19e4edd964894e06", + "https://bcr.bazel.build/modules/rules_proto/5.3.0-21.7/MODULE.bazel": "e8dff86b0971688790ae75528fe1813f71809b5afd57facb44dad9e8eca631b7", + "https://bcr.bazel.build/modules/rules_proto/6.0.0-rc1/MODULE.bazel": "1e5b502e2e1a9e825eef74476a5a1ee524a92297085015a052510b09a1a09483", + "https://bcr.bazel.build/modules/rules_proto/6.0.0-rc1/source.json": "8d8448e71706df7450ced227ca6b3812407ff5e2ccad74a43a9fbe79c84e34e0", + "https://bcr.bazel.build/modules/rules_python/0.10.2/MODULE.bazel": "cc82bc96f2997baa545ab3ce73f196d040ffb8756fd2d66125a530031cd90e5f", + "https://bcr.bazel.build/modules/rules_python/0.22.1/MODULE.bazel": "26114f0c0b5e93018c0c066d6673f1a2c3737c7e90af95eff30cfee38d0bbac7", + "https://bcr.bazel.build/modules/rules_python/0.37.0/MODULE.bazel": "bd90c62e4c789ea94ed61ab21a5a538dd4145548d1de994192049652d433816e", + "https://bcr.bazel.build/modules/rules_python/0.37.0/source.json": "c17b8ca7a2348fd8fa96ad5b414223dd1ce5d6e8265c3134a88d337b0554d53c", + "https://bcr.bazel.build/modules/rules_python/0.4.0/MODULE.bazel": "9208ee05fd48bf09ac60ed269791cf17fb343db56c8226a720fbb1cdf467166c", + "https://bcr.bazel.build/modules/stardoc/0.5.1/MODULE.bazel": "1a05d92974d0c122f5ccf09291442580317cdd859f07a8655f1db9a60374f9f8", + "https://bcr.bazel.build/modules/stardoc/0.5.3/MODULE.bazel": "c7f6948dae6999bf0db32c1858ae345f112cacf98f174c7a8bb707e41b974f1c", + "https://bcr.bazel.build/modules/stardoc/0.6.2/MODULE.bazel": "7060193196395f5dd668eda046ccbeacebfd98efc77fed418dbe2b82ffaa39fd", + "https://bcr.bazel.build/modules/stardoc/0.6.2/source.json": "d2ff8063b63b4a85e65fe595c4290f99717434fa9f95b4748a79a7d04dfed349", + "https://bcr.bazel.build/modules/upb/0.0.0-20220923-a547704/MODULE.bazel": "7298990c00040a0e2f121f6c32544bab27d4452f80d9ce51349b1a28f3005c43", + "https://bcr.bazel.build/modules/upb/0.0.0-20230516-61a97ef/MODULE.bazel": "c0df5e35ad55e264160417fd0875932ee3c9dda63d9fccace35ac62f45e1b6f9", + "https://bcr.bazel.build/modules/upb/0.0.0-20230516-61a97ef/source.json": "b2150404947339e8b947c6b16baa39fa75657f4ddec5e37272c7b11c7ab533bc", + "https://bcr.bazel.build/modules/zlib/1.2.11/MODULE.bazel": "07b389abc85fdbca459b69e2ec656ae5622873af3f845e1c9d80fe179f3effa0", + "https://bcr.bazel.build/modules/zlib/1.2.12/MODULE.bazel": "3b1a8834ada2a883674be8cbd36ede1b6ec481477ada359cd2d3ddc562340b27", + "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.3/MODULE.bazel": "af322bc08976524477c79d1e45e241b6efbeb918c497e8840b8ab116802dda79", + "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.3/source.json": "2be409ac3c7601245958cd4fcdff4288be79ed23bd690b4b951f500d54ee6e7d" + }, + "selectedYankedVersions": {}, + "moduleExtensions": { + "@@apple_support~//crosstool:setup.bzl%apple_cc_configure_extension": { + "general": { + "bzlTransitiveDigest": "PjIds3feoYE8SGbbIq2SFTZy3zmxeO2tQevJZNDo7iY=", + "usagesDigest": "aLmqbvowmHkkBPve05yyDNGN7oh7QE9kBADr3QIZTZs=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "local_config_apple_cc": { + "bzlFile": "@@apple_support~//crosstool:setup.bzl", + "ruleClassName": "_apple_cc_autoconf", + "attributes": {} + }, + "local_config_apple_cc_toolchains": { + "bzlFile": "@@apple_support~//crosstool:setup.bzl", + "ruleClassName": "_apple_cc_autoconf_toolchains", + "attributes": {} + } + }, + "recordedRepoMappingEntries": [ + [ + "apple_support~", + "bazel_tools", + "bazel_tools" + ] + ] + } + }, + "@@platforms//host:extension.bzl%host_platform": { + "general": { + "bzlTransitiveDigest": "xelQcPZH8+tmuOHVjL9vDxMnnQNMlwj0SlvgoqBkm4U=", + "usagesDigest": "meSzxn3DUCcYEhq4HQwExWkWtU4EjriRBQLsZN+Q0SU=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "host_platform": { + "bzlFile": "@@platforms//host:extension.bzl", + "ruleClassName": "host_platform_repo", + "attributes": {} + } + }, + "recordedRepoMappingEntries": [] + } + }, + "@@protobuf~//:non_module_deps.bzl%non_module_deps": { + "general": { + "bzlTransitiveDigest": "jsbfONl9OksDWiAs7KDFK5chH/tYI3DngdM30NKdk5Y=", + "usagesDigest": "eVrT3hFCIZNRuTKpfWDzSIwTi2p6U6PWbt+tNWl/Tqk=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "utf8_range": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "urls": [ + "https://github.com/protocolbuffers/utf8_range/archive/de0b4a8ff9b5d4c98108bdfe723291a33c52c54f.zip" + ], + "strip_prefix": "utf8_range-de0b4a8ff9b5d4c98108bdfe723291a33c52c54f", + "sha256": "5da960e5e5d92394c809629a03af3c7709d2d3d0ca731dacb3a9fb4bf28f7702" + } + } + }, + "recordedRepoMappingEntries": [ + [ + "protobuf~", + "bazel_tools", + "bazel_tools" + ] + ] + } + } + } +} diff --git a/WORKSPACE.bazel b/WORKSPACE.bazel index 8305108..4d25f96 100644 --- a/WORKSPACE.bazel +++ b/WORKSPACE.bazel @@ -31,6 +31,17 @@ http_archive( ], ) +http_archive( + name = "rules_python", + sha256 = "0cc05ddb27614baecace068986931e2a6e9f69114e6115fc5dc58250faf56e0f", + strip_prefix = "rules_python-0.37.0", + url = "https://github.com/bazelbuild/rules_python/releases/download/0.37.0/rules_python-0.37.0.tar.gz", +) + +load("@rules_python//python:repositories.bzl", "py_repositories", "python_register_toolchains") + +py_repositories() + load("@io_bazel_stardoc//:setup.bzl", "stardoc_repositories") stardoc_repositories() @@ -52,15 +63,6 @@ http_archive( ], ) -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. diff --git a/docgen/BUILD b/docgen/BUILD deleted file mode 100644 index dbb8391..0000000 --- a/docgen/BUILD +++ /dev/null @@ -1,51 +0,0 @@ -# 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. - -# Generated documentation for the docs/ directory - -load(":docgen.bzl", "sphinx_stardocs") - -package( - default_applicable_licenses = ["//:package_license"], - default_visibility = ["//:__subpackages__"], -) - -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:struct_subject_bzl", - "//lib/private:target_subject_bzl", - "//lib/private:default_info_subject_bzl", - ], - tags = ["docs"], -) diff --git a/docgen/docgen.bzl b/docgen/docgen.bzl deleted file mode 100644 index 5e829d3..0000000 --- a/docgen/docgen.bzl +++ /dev/null @@ -1,65 +0,0 @@ -# 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("@bazel_skylib//rules:build_test.bzl", "build_test") -load("@io_bazel_stardoc//stardoc:stardoc.bzl", "stardoc") - -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) - """ - - 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 deleted file mode 100644 index ee6a2bf..0000000 --- a/docgen/func_template.vm +++ /dev/null @@ -1,56 +0,0 @@ -#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 deleted file mode 100644 index fee7e2c..0000000 --- a/docgen/header_template.vm +++ /dev/null @@ -1 +0,0 @@ -$moduleDocstring diff --git a/docgen/provider_template.vm b/docgen/provider_template.vm deleted file mode 100644 index 55e6871..0000000 --- a/docgen/provider_template.vm +++ /dev/null @@ -1,29 +0,0 @@ -#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 deleted file mode 100644 index d91bad2..0000000 --- a/docgen/rule_template.vm +++ /dev/null @@ -1,48 +0,0 @@ -#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 index 59d0295..ceb4561 100644 --- a/docs/BUILD +++ b/docs/BUILD @@ -12,63 +12,90 @@ # 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") +load("@rules_python//sphinxdocs:readthedocs.bzl", "readthedocs_install") +load("@rules_python//sphinxdocs:sphinx.bzl", "sphinx_build_binary", "sphinx_docs") +load("@rules_python//sphinxdocs:sphinx_stardoc.bzl", "sphinx_stardocs") 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)", +sphinx_docs( + name = "docs", + srcs = glob( + include = [ + "*.md", + "**/*.md", + ], + exclude = ["README.md"], + ), + config = "conf.py", + formats = ["html"], + renamed_srcs = { + "@rules_python//sphinxdocs/inventories:bazel_inventory": "bazel_inventory.inv", + }, + sphinx = ":sphinx-build", + strip_prefix = package_name() + "/", + deps = [ + ":bzl_docs", ], - data = [ - "crossrefs.md", - ":sphinx_build", - ":sphinx_sources", - "//docgen:docs", +) + +sphinx_stardocs( + name = "bzl_docs", + srcs = [ + "//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:default_info_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:struct_subject_bzl", + "//lib/private:target_subject_bzl", ], + prefix = "api/", ) -py_binary( - name = "sphinx_build", - srcs = ["sphinx_build.py"], +sphinx_build_binary( + name = "sphinx-build", deps = [ - requirement("sphinx"), - requirement("sphinx_rtd_theme"), - requirement("myst_parser"), + "@docs-pypi//myst_parser", + "@docs-pypi//readthedocs_sphinx_ext", + "@docs-pypi//sphinx", + "@docs-pypi//sphinx_rtd_theme", + "@docs-pypi//typing_extensions", + "@rules_python//sphinxdocs/src/sphinx_bzl", ], ) +readthedocs_install( + name = "readthedocs_install", + docs = [":docs"], + target_compatible_with = ["@platforms//os:linux"], +) + # Run bazel run //docs:requirements.update compile_pip_requirements( name = "requirements", + extra_args = ["--upgrade"], 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/source/_static/css/custom.css b/docs/_static/css/custom.css similarity index 100% rename from docs/source/_static/css/custom.css rename to docs/_static/css/custom.css diff --git a/docs/source/analysis_tests.md b/docs/analysis_tests.md similarity index 100% rename from docs/source/analysis_tests.md rename to docs/analysis_tests.md diff --git a/docs/source/api/index.md b/docs/api/index.md similarity index 100% rename from docs/source/api/index.md rename to docs/api/index.md diff --git a/docs/source/best_practices.md b/docs/best_practices.md similarity index 100% rename from docs/source/best_practices.md rename to docs/best_practices.md diff --git a/docs/source/conf.py b/docs/conf.py similarity index 93% rename from docs/source/conf.py rename to docs/conf.py index 993d6f7..51aa772 100644 --- a/docs/source/conf.py +++ b/docs/conf.py @@ -25,16 +25,18 @@ 'sphinx.ext.autosectionlabel', 'myst_parser', 'sphinx_rtd_theme', # Necessary to get jquery to make flyout work + 'sphinx_bzl.bzl', ] intersphinx_mapping = { + "bazel": ("https://bazel.build/", "bazel_inventory.inv"), } 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 = ["*"] +##intersphinx_disabled_reftypes = ["*"] templates_path = ['_templates'] diff --git a/docs/crossrefs.md b/docs/crossrefs.md deleted file mode 100644 index 8c2106f..0000000 --- a/docs/crossrefs.md +++ /dev/null @@ -1,28 +0,0 @@ -[`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 -[`struct`]: https://bazel.build/rules/lib/builtins/struct -[`StrSubject`]: /api/str_subject -[`StructSubject`]: /api/struct_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/source/guides.md b/docs/guides.md similarity index 100% rename from docs/source/guides.md rename to docs/guides.md diff --git a/docs/source/index.md b/docs/index.md similarity index 100% rename from docs/source/index.md rename to docs/index.md diff --git a/docs/readthedocs_build.sh b/docs/readthedocs_build.sh new file mode 100755 index 0000000..5fe3a9f --- /dev/null +++ b/docs/readthedocs_build.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +set -eou pipefail + +declare -a extra_env +while IFS='=' read -r -d '' name value; do + if [[ "$name" == READTHEDOCS* ]]; then + extra_env+=("--@rules_python//sphinxdocs:extra_env=$name=$value") + fi +done < <(env -0) + +# In order to get the build number, we extract it from the host name +extra_env+=("--@rules_python//sphinxdocs:extra_env=HOSTNAME=$HOSTNAME") + +set -x +bazel run \ + --stamp \ + "--@rules_python//sphinxdocs:extra_defines=version=$READTHEDOCS_VERSION" \ + "${extra_env[@]}" \ + //docs:readthedocs_install diff --git a/docs/requirements.in b/docs/requirements.in index aa179a4..3e6ff1d 100644 --- a/docs/requirements.in +++ b/docs/requirements.in @@ -3,3 +3,5 @@ sphinx myst-parser sphinx_rtd_theme +typing-extensions +readthedocs-sphinx-ext diff --git a/docs/requirements.txt b/docs/requirements.txt index db2141e..166b528 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -4,267 +4,330 @@ # # bazel run //docs:requirements.update # -alabaster==0.7.13 \ - --hash=sha256:1ee19aca801bbabb5ba3f5f258e4422dfa86f82f3e9cefb0859b283cdd7f62a3 \ - --hash=sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2 +alabaster==1.0.0 \ + --hash=sha256:c00dca57bca26fa62a6d7d0a9fcce65f3e026e9bfe33e9c538fd3fbb2144fd9e \ + --hash=sha256:fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b # via sphinx -babel==2.12.1 \ - --hash=sha256:b4246fb7677d3b98f501a39d43396d3cafdc8eadb045f4a31be01863f655c610 \ - --hash=sha256:cc2d99999cd01d44420ae725a21c9e3711b3aadc7976d6147f622d8581963455 +babel==2.16.0 \ + --hash=sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b \ + --hash=sha256:d1f3554ca26605fe173f3de0c65f750f5a42f924499bf134de6423582298e316 # via sphinx -certifi==2022.12.7 \ - --hash=sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3 \ - --hash=sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18 +certifi==2024.8.30 \ + --hash=sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8 \ + --hash=sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9 # 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 +charset-normalizer==3.4.0 \ + --hash=sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621 \ + --hash=sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6 \ + --hash=sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8 \ + --hash=sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912 \ + --hash=sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c \ + --hash=sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b \ + --hash=sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d \ + --hash=sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d \ + --hash=sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95 \ + --hash=sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e \ + --hash=sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565 \ + --hash=sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64 \ + --hash=sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab \ + --hash=sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be \ + --hash=sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e \ + --hash=sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907 \ + --hash=sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0 \ + --hash=sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2 \ + --hash=sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62 \ + --hash=sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62 \ + --hash=sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23 \ + --hash=sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc \ + --hash=sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284 \ + --hash=sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca \ + --hash=sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455 \ + --hash=sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858 \ + --hash=sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b \ + --hash=sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594 \ + --hash=sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc \ + --hash=sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db \ + --hash=sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b \ + --hash=sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea \ + --hash=sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6 \ + --hash=sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920 \ + --hash=sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749 \ + --hash=sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7 \ + --hash=sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd \ + --hash=sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99 \ + --hash=sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242 \ + --hash=sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee \ + --hash=sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129 \ + --hash=sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2 \ + --hash=sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51 \ + --hash=sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee \ + --hash=sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8 \ + --hash=sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b \ + --hash=sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613 \ + --hash=sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742 \ + --hash=sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe \ + --hash=sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3 \ + --hash=sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5 \ + --hash=sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631 \ + --hash=sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7 \ + --hash=sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15 \ + --hash=sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c \ + --hash=sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea \ + --hash=sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417 \ + --hash=sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250 \ + --hash=sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88 \ + --hash=sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca \ + --hash=sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa \ + --hash=sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99 \ + --hash=sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149 \ + --hash=sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41 \ + --hash=sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574 \ + --hash=sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0 \ + --hash=sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f \ + --hash=sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d \ + --hash=sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654 \ + --hash=sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3 \ + --hash=sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19 \ + --hash=sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90 \ + --hash=sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578 \ + --hash=sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9 \ + --hash=sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1 \ + --hash=sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51 \ + --hash=sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719 \ + --hash=sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236 \ + --hash=sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a \ + --hash=sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c \ + --hash=sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade \ + --hash=sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944 \ + --hash=sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc \ + --hash=sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6 \ + --hash=sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6 \ + --hash=sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27 \ + --hash=sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6 \ + --hash=sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2 \ + --hash=sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12 \ + --hash=sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf \ + --hash=sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114 \ + --hash=sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7 \ + --hash=sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf \ + --hash=sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d \ + --hash=sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b \ + --hash=sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed \ + --hash=sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03 \ + --hash=sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4 \ + --hash=sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67 \ + --hash=sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365 \ + --hash=sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a \ + --hash=sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748 \ + --hash=sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b \ + --hash=sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079 \ + --hash=sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482 # via requests -docutils==0.18.1 \ - --hash=sha256:23010f129180089fbcd3bc08cfefccb3b890b0050e1ca00c867036e9d161b98c \ - --hash=sha256:679987caf361a7539d76e584cbeddc311e3aee937877c87346f31debc63e9d06 +docutils==0.21.2 \ + --hash=sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f \ + --hash=sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2 # via # myst-parser # sphinx # sphinx-rtd-theme -idna==3.4 \ - --hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 \ - --hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2 +idna==3.10 \ + --hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \ + --hash=sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3 # via requests imagesize==1.4.1 \ --hash=sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b \ --hash=sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a # via sphinx -jinja2==3.1.2 \ - --hash=sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852 \ - --hash=sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61 +jinja2==3.1.4 \ + --hash=sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369 \ + --hash=sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d # via # myst-parser + # readthedocs-sphinx-ext # sphinx -markdown-it-py==2.2.0 \ - --hash=sha256:5a35f8d1870171d9acc47b99612dc146129b631baf04970128b568f190d0cc30 \ - --hash=sha256:7c9a5e412688bc771c67432cbfebcdd686c93ce6484913dccf06cb5a0bea35a1 +markdown-it-py==3.0.0 \ + --hash=sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1 \ + --hash=sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb # 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 +markupsafe==3.0.2 \ + --hash=sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4 \ + --hash=sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30 \ + --hash=sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0 \ + --hash=sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9 \ + --hash=sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396 \ + --hash=sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13 \ + --hash=sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028 \ + --hash=sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca \ + --hash=sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557 \ + --hash=sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832 \ + --hash=sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0 \ + --hash=sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b \ + --hash=sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579 \ + --hash=sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a \ + --hash=sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c \ + --hash=sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff \ + --hash=sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c \ + --hash=sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22 \ + --hash=sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094 \ + --hash=sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb \ + --hash=sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e \ + --hash=sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5 \ + --hash=sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a \ + --hash=sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d \ + --hash=sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a \ + --hash=sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b \ + --hash=sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8 \ + --hash=sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225 \ + --hash=sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c \ + --hash=sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144 \ + --hash=sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f \ + --hash=sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87 \ + --hash=sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d \ + --hash=sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93 \ + --hash=sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf \ + --hash=sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158 \ + --hash=sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84 \ + --hash=sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb \ + --hash=sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48 \ + --hash=sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171 \ + --hash=sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c \ + --hash=sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6 \ + --hash=sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd \ + --hash=sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d \ + --hash=sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1 \ + --hash=sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d \ + --hash=sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca \ + --hash=sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a \ + --hash=sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29 \ + --hash=sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe \ + --hash=sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798 \ + --hash=sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c \ + --hash=sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8 \ + --hash=sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f \ + --hash=sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f \ + --hash=sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a \ + --hash=sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178 \ + --hash=sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0 \ + --hash=sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79 \ + --hash=sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430 \ + --hash=sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50 # via jinja2 -mdit-py-plugins==0.3.5 \ - --hash=sha256:ca9a0714ea59a24b2b044a1831f48d817dd0c817e84339f20e7889f392d77c4e \ - --hash=sha256:eee0adc7195e5827e17e02d2a258a2ba159944a0748f59c5099a4a27f78fcf6a +mdit-py-plugins==0.4.2 \ + --hash=sha256:0c673c3f889399a33b95e88d2f0d111b4447bdfea7f237dab2d488f459835636 \ + --hash=sha256:5f2cd1fdb606ddf152d37ec30e46101a60512bc0e5fa1a7002c36647b09e26b5 # 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 +myst-parser==4.0.0 \ + --hash=sha256:851c9dfb44e36e56d15d05e72f02b80da21a9e0d07cba96baf5e2d476bb91531 \ + --hash=sha256:b9317997552424448c6096c2558872fdb6f81d3ecb3a40ce84a7518798f3f28d # 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 +packaging==24.1 \ + --hash=sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002 \ + --hash=sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124 + # via + # readthedocs-sphinx-ext + # sphinx +pygments==2.18.0 \ + --hash=sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199 \ + --hash=sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a # 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 +pyyaml==6.0.2 \ + --hash=sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff \ + --hash=sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48 \ + --hash=sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086 \ + --hash=sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e \ + --hash=sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133 \ + --hash=sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5 \ + --hash=sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484 \ + --hash=sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee \ + --hash=sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5 \ + --hash=sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68 \ + --hash=sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a \ + --hash=sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf \ + --hash=sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99 \ + --hash=sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8 \ + --hash=sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85 \ + --hash=sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19 \ + --hash=sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc \ + --hash=sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a \ + --hash=sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1 \ + --hash=sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317 \ + --hash=sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c \ + --hash=sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631 \ + --hash=sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d \ + --hash=sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652 \ + --hash=sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5 \ + --hash=sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e \ + --hash=sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b \ + --hash=sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8 \ + --hash=sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476 \ + --hash=sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706 \ + --hash=sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563 \ + --hash=sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237 \ + --hash=sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b \ + --hash=sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083 \ + --hash=sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180 \ + --hash=sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425 \ + --hash=sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e \ + --hash=sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f \ + --hash=sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725 \ + --hash=sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183 \ + --hash=sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab \ + --hash=sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774 \ + --hash=sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725 \ + --hash=sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e \ + --hash=sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5 \ + --hash=sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d \ + --hash=sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290 \ + --hash=sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44 \ + --hash=sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed \ + --hash=sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4 \ + --hash=sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba \ + --hash=sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12 \ + --hash=sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4 # via myst-parser -requests==2.28.2 \ - --hash=sha256:64299f4909223da747622c030b781c0d7811e359c37124b4bd368fb8c6518baa \ - --hash=sha256:98b1b2782e3c6c4904938b84c0eb932721069dfdb9134313beff7c83c2df24bf - # via sphinx +readthedocs-sphinx-ext==2.2.5 \ + --hash=sha256:ee5fd5b99db9f0c180b2396cbce528aa36671951b9526bb0272dbfce5517bd27 \ + --hash=sha256:f8c56184ea011c972dd45a90122568587cc85b0127bc9cf064d17c68bc809daa + # via -r docs/requirements.in +requests==2.32.3 \ + --hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \ + --hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6 + # via + # readthedocs-sphinx-ext + # sphinx snowballstemmer==2.2.0 \ --hash=sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1 \ --hash=sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a # via sphinx -sphinx==6.1.3 \ - --hash=sha256:0dac3b698538ffef41716cf97ba26c1c7788dba73ce6f150c1ff5b4720786dd2 \ - --hash=sha256:807d1cb3d6be87eb78a381c3e70ebd8d346b9a25f3753e9947e866b2786865fc +sphinx==8.1.3 \ + --hash=sha256:09719015511837b76bf6e03e42eb7595ac8c2e41eeb9c29c5b755c6b677992a2 \ + --hash=sha256:43c1911eecb0d3e161ad78611bc905d1ad0e523e4ddc202a58a821773dc4c927 # via # -r docs/requirements.in # myst-parser # sphinx-rtd-theme # sphinxcontrib-jquery -sphinx-rtd-theme==1.2.0 \ - --hash=sha256:a0d8bd1a2ed52e0b338cbe19c4b2eef3c5e7a048769753dac6a9f059c7b641b8 \ - --hash=sha256:f823f7e71890abe0ac6aaa6013361ea2696fc8d3e1fa798f463e82bdb77eeff2 +sphinx-rtd-theme==3.0.1 \ + --hash=sha256:921c0ece75e90633ee876bd7b148cfaad136b481907ad154ac3669b6fc957916 \ + --hash=sha256:a4c5745d1b06dfcb80b7704fe532eb765b44065a8fad9851e4258c8804140703 # via -r docs/requirements.in -sphinxcontrib-applehelp==1.0.4 \ - --hash=sha256:29d341f67fb0f6f586b23ad80e072c8e6ad0b48417db2bde114a4c9746feb228 \ - --hash=sha256:828f867945bbe39817c210a1abfd1bc4895c8b73fcaade56d45357a348a07d7e +sphinxcontrib-applehelp==2.0.0 \ + --hash=sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1 \ + --hash=sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5 # via sphinx -sphinxcontrib-devhelp==1.0.2 \ - --hash=sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e \ - --hash=sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4 +sphinxcontrib-devhelp==2.0.0 \ + --hash=sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad \ + --hash=sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2 # via sphinx -sphinxcontrib-htmlhelp==2.0.1 \ - --hash=sha256:0cbdd302815330058422b98a113195c9249825d681e18f11e8b1f78a2f11efff \ - --hash=sha256:c38cb46dccf316c79de6e5515e1770414b797162b23cd3d06e67020e1d2a6903 +sphinxcontrib-htmlhelp==2.1.0 \ + --hash=sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8 \ + --hash=sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9 # via sphinx sphinxcontrib-jquery==4.1 \ --hash=sha256:1620739f04e36a2c779f1a131a2dfd49b2fd07351bf1968ced074365933abc7a \ @@ -274,15 +337,19 @@ sphinxcontrib-jsmath==1.0.1 \ --hash=sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178 \ --hash=sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8 # via sphinx -sphinxcontrib-qthelp==1.0.3 \ - --hash=sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72 \ - --hash=sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6 +sphinxcontrib-qthelp==2.0.0 \ + --hash=sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab \ + --hash=sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb # via sphinx -sphinxcontrib-serializinghtml==1.1.5 \ - --hash=sha256:352a9a00ae864471d3a7ead8d7d79f5fc0b57e8b3f95e9867eb9eb28999b92fd \ - --hash=sha256:aa5f6de5dfdf809ef505c4895e51ef5c9eac17d0f287933eb49ec495280b6952 +sphinxcontrib-serializinghtml==2.0.0 \ + --hash=sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331 \ + --hash=sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d # via sphinx -urllib3==1.26.15 \ - --hash=sha256:8a388717b9476f934a21484e8c8e61875ab60644d29b9b39e11e4b9dc1c6b305 \ - --hash=sha256:aa751d169e23c7479ce47a0cb0da579e3ede798f994f5816a74e4f4500dcea42 +typing-extensions==4.12.2 \ + --hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \ + --hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8 + # via -r docs/requirements.in +urllib3==2.2.3 \ + --hash=sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac \ + --hash=sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9 # via requests diff --git a/docs/run_sphinx_build.sh b/docs/run_sphinx_build.sh deleted file mode 100755 index dea8984..0000000 --- a/docs/run_sphinx_build.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/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/sphinx_build.py b/docs/sphinx_build.py deleted file mode 100644 index a06f380..0000000 --- a/docs/sphinx_build.py +++ /dev/null @@ -1,4 +0,0 @@ -import sys -from sphinx.cmd.build import main -if __name__ == "__main__": - sys.exit(main()) diff --git a/docs/source/test_suite.md b/docs/test_suite.md similarity index 100% rename from docs/source/test_suite.md rename to docs/test_suite.md diff --git a/docs/source/truth.md b/docs/truth.md similarity index 100% rename from docs/source/truth.md rename to docs/truth.md diff --git a/docs/source/unit_tests.md b/docs/unit_tests.md similarity index 100% rename from docs/source/unit_tests.md rename to docs/unit_tests.md diff --git a/lib/analysis_test.bzl b/lib/analysis_test.bzl index d8ad2b1..b21191e 100644 --- a/lib/analysis_test.bzl +++ b/lib/analysis_test.bzl @@ -12,10 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""# Analysis test - -Support for testing analysis phase logic, such as rules. -""" +"""Support for testing analysis phase logic, such as rules.""" load("//lib:test_suite.bzl", _test_suite = "test_suite") load("//lib/private:analysis_test.bzl", _analysis_test = "analysis_test") @@ -23,7 +20,7 @@ load("//lib/private:analysis_test.bzl", _analysis_test = "analysis_test") analysis_test = _analysis_test def test_suite(**kwargs): - """This is an alias to lib/test_suite.bzl#test_suite. + """This is an alias to {obj}`//lib:test_suite.bzl%test_suite` Args: **kwargs: Args passed through to test_suite diff --git a/lib/private/action_subject.bzl b/lib/private/action_subject.bzl index 7de79fc..7ffc28e 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""" +"" load(":collection_subject.bzl", "CollectionSubject") load(":depset_file_subject.bzl", "DepsetFileSubject") @@ -36,11 +36,11 @@ def _action_subject_new(action, meta): expect(env).that_action(action).not_contains_arg("foo") Args: - action: ([`Action`]) value to check against. - meta: ([`ExpectMeta`]) of call chain information. + action: {type}`Action` value to check against. + meta: {type}`ExpectMeta` of call chain information. Returns: - [`ActionSubject`] object. + {type}`ActionSubject` object. """ # buildifier: disable=uninitialized @@ -98,7 +98,7 @@ def _action_subject_argv(self): Method: ActionSubject.argv Returns: - [`CollectionSubject`] object. + {type}`CollectionSubject` object. """ meta = self.meta.derive("argv()") return CollectionSubject.new( @@ -118,11 +118,11 @@ def _action_subject_contains_at_least_args(self, args): Args: self: implicitly added. - args: ([`list`] of [`str`]) all the args must be in the argv exactly + args: {type}`list[str]` all the args must be in the argv exactly as provided. Multiplicity is respected. Returns: - [`Ordered`] (see `_ordered_incorrectly_new`). + {type}`Ordered` (see `_ordered_incorrectly_new`). """ return CollectionSubject.new( self.action.argv, @@ -140,7 +140,7 @@ def _action_subject_not_contains_arg(self, arg): Args: self: implicitly added. - arg: ([`str`]) the arg that cannot be present in the argv. + arg: {type}`str` the arg that cannot be present in the argv. """ if arg in self.action.argv: problem, actual = format_failure_unexpected_value( @@ -160,7 +160,7 @@ def _action_subject_substitutions(self): self: implicitly added Returns: - `DictSubject` struct. + {type}`DictSubject` struct. """ return DictSubject.new( actual = self.action.substitutions, @@ -181,13 +181,13 @@ def _action_subject_has_flags_specified(self, flags): Args: self: implicitly added. - flags: ([`list`] of [`str`]) The flags to check for. Include the leading "--". + flags: {type}`list[str]` The flags to check for. Include the leading "--". Multiplicity is respected. A flag is considered present if any of these forms are detected: `--flag=value`, `--flag value`, or a lone `--flag`. Returns: - [`Ordered`] (see `_ordered_incorrectly_new`). + {type}`Ordered` (see `_ordered_incorrectly_new`). """ return CollectionSubject.new( # Starlark dict keys maintain insertion order, so it's OK to @@ -205,7 +205,7 @@ def _action_subject_mnemonic(self): Method: ActionSubject.mnemonic Returns: - [`StrSubject`] object. + {type}`StrSubject` object. """ return StrSubject.new( self.action.mnemonic, @@ -218,7 +218,7 @@ def _action_subject_inputs(self): Method: ActionSubject.inputs Returns: - `DepsetFileSubject` of the action's inputs. + {type}`DepsetFileSubject` of the action's inputs. """ meta = self.meta.derive("inputs()") return DepsetFileSubject.new(self.action.inputs, meta) @@ -247,9 +247,10 @@ def _action_subject_contains_flag_values(self, flag_values): Args: self: implicitly added. - flag_values: ([`list`] of ([`str`] name, [`str`]) tuples) Include the - leading "--" in the flag name. Order and duplicates aren't checked. - Flags without a value found use `None` as their value. + flag_values: {type}`list[tuple[str, str]]`, where the first tuple + element is the flag name, and the second is the flag value. Include + the leading "--" in the flag name. Order and duplicates aren't + checked. Flags without a value found use `None` as their value. """ missing = [] for flag, value in sorted(flag_values): @@ -285,7 +286,8 @@ def _action_subject_contains_none_of_flag_values(self, flag_values): Args: self: implicitly added. - flag_values: ([`list`] of ([`str`] name, [`str`] value) tuples) Include + flag_values: {type}`list[tuple[str, str]]`, where the first tuple + element is the flag name, and the second is the flag value. Include the leading "--" in the flag name. Order and duplicates aren't checked. """ @@ -316,11 +318,11 @@ def _action_subject_contains_at_least_inputs(self, inputs): Args: self: implicitly added. - inputs: (collection of [`File`]) All must be present. Multiplicity + inputs: {type}`collection[File]` All must be present. Multiplicity is respected. Returns: - [`Ordered`] (see `_ordered_incorrectly_new`). + {type}`Ordered` (see `_ordered_incorrectly_new`). """ return DepsetFileSubject.new( self.action.inputs, @@ -335,7 +337,7 @@ def _action_subject_content(self): Method: ActionSubject.content Returns: - [`StrSubject`] object. + {type}`StrSubject` object. """ return StrSubject.new( self.action.content, @@ -357,9 +359,24 @@ def _action_subject_env(self): key_plural_name = "envvars", ) +def _action_subject_typedef(): + """A wrapper around {obj}`Action` objects for testing. + + These can be created using {obj}`subjects.action`, but more typically + are created through {obj}`Expect.that_action()` or + {obj}`TargetSubject.action_generating`. + + :::{field} actual + :type: Action + + The underlying action that is asserted against. + ::: + """ + # We use this name so it shows up nice in docs. # buildifier: disable=name-conventions ActionSubject = struct( + TYPEDEF = _action_subject_typedef, new = _action_subject_new, parse_flags = _action_subject_parse_flags, argv = _action_subject_argv, diff --git a/lib/private/analysis_test.bzl b/lib/private/analysis_test.bzl index 27cc7c8..787fb51 100644 --- a/lib/private/analysis_test.bzl +++ b/lib/private/analysis_test.bzl @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""# Analysis test +"""Analysis test Support for testing analysis phase logic, such as rules. """ diff --git a/lib/private/bool_subject.bzl b/lib/private/bool_subject.bzl index d07f3c3..d8f2809 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""" +"""BoolSubject""" load(":check_util.bzl", "check_not_equals", "common_subject_is_in") @@ -22,15 +22,16 @@ def _bool_subject_new(value, meta): Method: BoolSubject.new Args: - value: ([`bool`]) the value to assert against. - meta: ([`ExpectMeta`]) the metadata about the call chain. + value: {type}`bool` the value to assert against. + meta: {type}`ExpectMeta` the metadata about the call chain. Returns: - A [`BoolSubject`]. + {type}`BoolSubject` """ self = struct(actual = value, meta = meta) public = struct( # keep sorted start + actual = value, equals = lambda *a, **k: _bool_subject_equals(self, *a, **k), is_in = lambda *a, **k: common_subject_is_in(self, *a, **k), not_equals = lambda *a, **k: _bool_subject_not_equals(self, *a, **k), @@ -45,7 +46,7 @@ def _bool_subject_equals(self, expected): Args: self: implicitly added. - expected: ([`bool`]) the expected value. + expected: {type}`bool` the expected value. """ if self.actual == expected: return @@ -61,7 +62,7 @@ def _bool_subject_not_equals(self, unexpected): Args: self: implicitly added. - unexpected: ([`bool`]) the value actual cannot equal. + unexpected: {type}`bool` the value actual cannot equal. """ return check_not_equals( actual = self.actual, @@ -69,9 +70,23 @@ def _bool_subject_not_equals(self, unexpected): meta = self.meta, ) +def _bool_typedef(): + """A wrapper around {obj}`bool` objects for testing. + + These can be created using {obj}`subjects.bool` or + {obj}`Expect.that_bool()`. + + :::{field} actual + :type: bool | None + + The underlying value that is asserted against. + ::: + """ + # We use this name so it shows up nice in docs. # buildifier: disable=name-conventions BoolSubject = struct( + TYPEDEF = _bool_typedef, 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 6d72efe..6580d17 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""" +"""CollectionSubject""" load( ":check_util.bzl", @@ -54,18 +54,15 @@ def _collection_subject_new( Method: CollectionSubject.new - Public Attributes: - * `actual`: The wrapped collection. - Args: - values: ([`collection`]) the values to assert against. - meta: ([`ExpectMeta`]) the metadata about the call chain. - container_name: ([`str`]) conceptual name of the container. - sortable: ([`bool`]) True if output should be sorted for display, False if not. - element_plural_name: ([`str`]) the plural word for the values in the container. + values: {type}`collection` the values to assert against. + meta: {type}`ExpectMeta` the metadata about the call chain. + container_name: {type}`str` conceptual name of the container. + sortable: {type}`bool` True if output should be sorted for display, False if not. + element_plural_name: {type}`str` the plural word for the values in the container. Returns: - [`CollectionSubject`]. + {type}`CollectionSubject` """ # buildifier: disable=uninitialized @@ -104,7 +101,7 @@ def _collection_subject_has_size(self, expected): Args: self: implicitly added. - expected: ([`int`]) the expected size of the collection. + expected: {type}`int` the expected size of the collection. """ return IntSubject.new( len(self.actual), @@ -118,7 +115,7 @@ def _collection_subject_contains(self, expected): Args: self: implicitly added. - expected: ([`str`]) the value that must be present. + expected: {type}`str` the value that must be present. """ matcher = matching.equals_wrapper(expected) return self.contains_predicate(matcher) @@ -139,10 +136,10 @@ def _collection_subject_contains_exactly(self, expected): Args: self: implicitly added. - expected: ([`list`]) values that must exist. + expected: {type}`list` values that must exist. Returns: - [`Ordered`] (see `_ordered_incorrectly_new`). + {type}`Ordered` (see `_ordered_incorrectly_new`). """ expected = to_list(expected) return check_contains_exactly( @@ -195,10 +192,10 @@ def _collection_subject_contains_exactly_predicates(self, expected): Args: self: implicitly added. - expected: ([`list`] of [`Matcher`]) that must match. + expected: {type}`list[Matcher]` that must match. Returns: - [`Ordered`] (see `_ordered_incorrectly_new`). + {type}`Ordered` (see `_ordered_incorrectly_new`). """ expected = to_list(expected) return check_contains_exactly_predicates( @@ -232,7 +229,7 @@ def _collection_subject_contains_none_of(self, values): Args: self: implicitly added - values: ([`collection`]) values of which none of are allowed to exist. + values: {type}`collection` values of which none of are allowed to exist. """ check_contains_none_of( collection = self.actual, @@ -248,7 +245,7 @@ def _collection_subject_contains_predicate(self, matcher): Args: self: implicitly added. - matcher: ([`Matcher`]) (see `matchers` struct). + matcher: {type}`Matcher` (see `matchers` struct). """ check_contains_predicate( self.actual, @@ -274,10 +271,10 @@ def _collection_subject_contains_at_least(self, expect_contains): Args: self: implicitly added. - expect_contains: ([`list`]) values that must be in the collection. + expect_contains: {type}`list` values that must be in the collection. Returns: - [`Ordered`] (see `_ordered_incorrectly_new`). + {type}`Ordered` (see `_ordered_incorrectly_new`). """ matchers = [ matching.equals_wrapper(expected) @@ -297,10 +294,10 @@ def _collection_subject_contains_at_least_predicates(self, matchers): Args: self: implicitly added. - matchers: ([`list`] of [`Matcher`]) (see `matchers` struct). + matchers: {type}`list[Matcher]` (see `matchers` struct). Returns: - [`Ordered`] (see `_ordered_incorrectly_new`). + {type}`Ordered` (see `_ordered_incorrectly_new`). """ ordered = check_contains_at_least_predicates( self.actual, @@ -335,7 +332,7 @@ def _collection_subject_not_contains_predicate(self, matcher): Args: self: implicitly added. - matcher: [`Matcher`] object (see `matchers` struct). + matcher: {type}`Matcher` object (see `matchers` struct). """ check_not_contains_predicate( self.actual, @@ -349,8 +346,8 @@ def _collection_subject_offset(self, offset, factory): Args: self: implicitly added. - offset: ([`int`]) the offset to fetch - factory: ([`callable`]). The factory function to use to create + offset: {type}`int` the offset to fetch + factory: {type}`callable`. The factory function to use to create the subject for the offset's value. It must have the following signature: `def factory(value, *, meta)`. @@ -381,20 +378,20 @@ def _collection_subject_transform( Args: self: implicitly added. - desc: (optional [`str`]) a human-friendly description of the transform + desc: {type}`str|None` a human-friendly description of the transform for use in error messages. Required when a description can't be inferred from the other args. The description can be inferred if the filter arg is a named function (non-lambda) or Matcher object. - map_each: (optional [`callable`]) function to transform an element in + map_each: {type}`callable|None` function to transform an element in the collection. It takes one positional arg, the loop's current iteration value, and its return value will be the element's new value. If not specified, the values from the loop iteration are returned unchanged. - loop: (optional [`callable`]) function to produce values from the + loop: {type}`callable | None` function to produce values from the original collection and whose values are iterated over. It takes one positional arg, which is the original collection. If not specified, the original collection values are iterated over. - filter: (optional [`callable`]) function that decides what values are + filter: {type}`callable|None` function that decides what values are passed onto `map_each` for inclusion in the final result. It takes one positional arg, the value to match (which is the current iteration value before `map_each` is applied), and returns a bool @@ -402,7 +399,7 @@ def _collection_subject_transform( should be skipped). Returns: - [`CollectionSubject`] of the transformed values. + {type}`CollectionSubject` of the transformed values. """ if not desc: if map_each or loop: @@ -444,9 +441,23 @@ def _collection_subject_transform( element_plural_name = self.element_plural_name, ) +def _collection_subject_typedef(): + """A wrapper around collection objects for testing. + + These can be created using {obj}`subjects.collection` or + {obj}`Expect.that_collection()`. + + :::{field} actual + :type: collection | None + + The underlying value that is asserted against. + ::: + """ + # We use this name so it shows up nice in docs. # buildifier: disable=name-conventions CollectionSubject = struct( + TYPEDEF = _collection_subject_typedef, # keep sorted start contains = _collection_subject_contains, contains_at_least = _collection_subject_contains_at_least, diff --git a/lib/private/default_info_subject.bzl b/lib/private/default_info_subject.bzl index 05483e2..c70096e 100644 --- a/lib/private/default_info_subject.bzl +++ b/lib/private/default_info_subject.bzl @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""# DefaultInfoSubject""" +"""DefaultInfoSubject""" load(":depset_file_subject.bzl", "DepsetFileSubject") load(":file_subject.bzl", "FileSubject") @@ -22,11 +22,11 @@ def _default_info_subject_new(info, *, meta): """Creates a `DefaultInfoSubject` Args: - info: ([`DefaultInfo`]) the DefaultInfo object to wrap. - meta: ([`ExpectMeta`]) call chain information. + info: {type}`DefaultInfo` the DefaultInfo object to wrap. + meta: {type}`ExpectMeta` call chain information. Returns: - [`DefaultInfoSubject`] object. + {type}`DefaultInfoSubject` object. """ self = struct(actual = info, meta = meta) public = struct( @@ -48,7 +48,7 @@ def _default_info_subject_runfiles(self): self: implicitly added. Returns: - [`RunfilesSubject`] object + {type}`RunfilesSubject` object """ return RunfilesSubject.new( self.actual.default_runfiles, @@ -63,7 +63,7 @@ def _default_info_subject_data_runfiles(self): self: implicitly added. Returns: - [`RunfilesSubject`] object + {type}`RunfilesSubject` object """ return RunfilesSubject.new( self.actual.data_runfiles, @@ -78,7 +78,7 @@ def _default_info_subject_default_outputs(self): self: implicitly added. Returns: - [`DepsetFileSubject`] object. + {type}`DepsetFileSubject` object. """ return DepsetFileSubject.new( self.actual.files, @@ -92,7 +92,7 @@ def _default_info_subject_executable(self): self: implicitly added. Returns: - [`FileSubject`] object. + {type}`FileSubject` object. """ return FileSubject.new( self.actual.files_to_run.executable, @@ -106,16 +106,27 @@ def _default_info_subject_runfiles_manifest(self): self: implicitly added. Returns: - [`FileSubject`] object. + {type}`FileSubject` object. """ return FileSubject.new( self.actual.files_to_run.runfiles_manifest, meta = self.meta.derive("runfiles_manifest()"), ) +def _default_info_subject_typedef(): + """Subject for {obj}`DefaultInfo` + + :::{field} actual + :type: DefaultInfo + + The underlying object asserted against. + ::: + """ + # We use this name so it shows up nice in docs. # buildifier: disable=name-conventions DefaultInfoSubject = struct( + TYPEDEF = _default_info_subject_typedef, # keep sorted start new = _default_info_subject_new, runfiles = _default_info_subject_runfiles, diff --git a/lib/private/depset_file_subject.bzl b/lib/private/depset_file_subject.bzl index 554e3a5..fd79656 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""" +"""DepsetFileSubject""" load("//lib:util.bzl", "is_file") load( @@ -42,18 +42,19 @@ def _depset_file_subject_new(files, meta, container_name = "depset", element_plu Method: DepsetFileSubject.new Args: - files: ([`depset`] of [`File`]) the values to assert on. - meta: ([`ExpectMeta`]) of call chain information. - container_name: ([`str`]) conceptual name of the container. - element_plural_name: ([`str`]) the plural word for the values in the container. + files: {type}`depset[File]` the values to assert on. + meta: {type}`ExpectMeta` of call chain information. + container_name: {type}`str` conceptual name of the container. + element_plural_name: {type}`str` the plural word for the values in the container. Returns: - [`DepsetFileSubject`] object. + {type}`DepsetFileSubject` object. """ # buildifier: disable=uninitialized public = struct( # keep sorted start + actual = files, contains = lambda *a, **k: _depset_file_subject_contains(self, *a, **k), contains_any_in = lambda *a, **k: _depset_file_subject_contains_any_in(self, *a, **k), contains_at_least = lambda *a, **k: _depset_file_subject_contains_at_least(self, *a, **k), @@ -81,9 +82,9 @@ def _depset_file_subject_contains(self, expected): Args: self: implicitly added - expected: ([`str`] | [`File`]) If a string path is provided, it is + expected: {type}`str | File` If a string path is provided, it is compared to the short path of the files and are formatted using - [`ExpectMeta.format_str`] and its current contextual keywords. Note + {obj}`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. """ @@ -107,15 +108,15 @@ def _depset_file_subject_contains_at_least(self, expected): Args: self: implicitly added - expected: ([`collection`] of [`str`] | collection of [`File`]) multiplicity + expected: {type}`collection[str] | collection[File]` multiplicity is respected. If string paths are provided, they are compared to the short path of the files and are formatted using - `ExpectMeta.format_str` and its current contextual keywords. Note + {obj}`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`). + {type}`Ordered` (see `_ordered_incorrectly_new`). """ expected = to_list(expected) if len(expected) < 1 or is_file(expected[0]): @@ -138,11 +139,11 @@ def _depset_file_subject_contains_any_in(self, expected): Args: self: implicitly added. - expected: ([`collection`] of [`str`] paths | [`collection`] of [`File`]) - at least one of the values must exist. Note that, when using `File` - objects, two files' configurations must be the same for them to be - considered equal. When string paths are provided, they are compared - to `File.short_path`. + expected: {type}`collection[str] | collection[File]` at least one of the + values must exist. Note that, when using `File` objects, two files' + configurations must be the same for them to be considered equal. + When string paths are provided, they are compared to + `File.short_path`. """ expected = to_list(expected) if len(expected) < 1 or is_file(expected[0]): @@ -175,11 +176,10 @@ def _depset_file_subject_contains_at_least_predicates(self, matchers): Args: self: implicitly added. - matchers: ([`list`] of [`Matcher`]) (see `matchers` struct) that - accept [`File`] objects. + matchers: {type}`list[Matcher]` that accept `File` objects. Returns: - [`Ordered`] (see `_ordered_incorrectly_new`). + {type}`Ordered` (see `_ordered_incorrectly_new`). """ ordered = check_contains_at_least_predicates( self.files, @@ -205,7 +205,7 @@ def _depset_file_subject_contains_predicate(self, matcher): Args: self: implicitly added. - matcher: [`Matcher`] (see `matching` struct) that accepts `File` objects. + matcher: {type}`Matcher` (see `matching` struct) that accepts `File` objects. """ check_contains_predicate( self.files, @@ -225,7 +225,7 @@ def _depset_file_subject_contains_exactly(self, paths): Args: self: implicitly added. - paths: ([`collection`] of [`str`]) the paths that must exist. These are + paths: {type}`collection[str]` the paths that must exist. These are compared to the `short_path` values of the files in the depset. All the paths, and no more, must exist. """ @@ -260,7 +260,7 @@ def _depset_file_subject_not_contains(self, short_path): Args: self: implicitly added. - short_path: ([`str`]) the short path that should not be present. + short_path: {type}`str` the short path that should not be present. """ short_path = self.meta.format_str(short_path) matcher = matching.custom(short_path, lambda f: f.short_path == short_path) @@ -273,13 +273,24 @@ def _depset_file_subject_not_contains_predicate(self, matcher): Args: self: implicitly added. - matcher: ([`Matcher`]) that must match. It operates on [`File`] objects. + matcher: {type}`Matcher` that must match. It operates on {obj}`File` objects. """ check_not_contains_predicate(self.files, matcher, meta = self.meta) +def _depset_file_subject_typedef(): + """Subject for {obj}`depset` of {obj}`File`. + + :::{field} actual + :type: depset[File] + + The underlying object asserted against. + ::: + """ + # We use this name so it shows up nice in docs. # buildifier: disable=name-conventions DepsetFileSubject = struct( + TYPEDEF = _depset_file_subject_typedef, new = _depset_file_subject_new, contains = _depset_file_subject_contains, contains_at_least = _depset_file_subject_contains_at_least, diff --git a/lib/private/dict_subject.bzl b/lib/private/dict_subject.bzl index f155a17..ba8bf60 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""" +"""DictSubject""" load(":collection_subject.bzl", "CollectionSubject") load(":compare_util.bzl", "compare_dicts") @@ -28,13 +28,13 @@ def _dict_subject_new(actual, meta, container_name = "dict", key_plural_name = " Method: DictSubject.new Args: - actual: ([`dict`]) the dict to assert against. - meta: ([`ExpectMeta`]) of call chain information. - container_name: ([`str`]) conceptual name of the dict. - key_plural_name: ([`str`]) the plural word for the keys of the dict. + actual: {type}`dict` the dict to assert against. + meta: {type}`ExpectMeta` of call chain information. + container_name: {type}`str` conceptual name of the dict. + key_plural_name: {type}`str` the plural word for the keys of the dict. Returns: - New `DictSubject` struct. + {type}`DictSubject` struct. """ # buildifier: disable=uninitialized @@ -62,7 +62,7 @@ def _dict_subject_contains_at_least(self, at_least): Args: self: implicitly added. - at_least: ([`dict`]) the subset of keys/values that must exist. Extra + at_least: {type}`dict` the subset of keys/values that must exist. Extra keys are allowed. Order is not checked. """ result = compare_dicts( @@ -91,7 +91,7 @@ def _dict_subject_contains_exactly(self, expected): Args: self: implicitly added - expected: ([`dict`]) the values that must exist. Missing values or + expected: {type}`dict` the values that must exist. Missing values or extra values are not allowed. Order is not checked. """ result = compare_dicts( @@ -122,7 +122,7 @@ def _dict_subject_contains_none_of(self, none_of): Args: self: implicitly added - none_of: ([`dict`]) the keys/values that must not exist. Order is not + none_of: {type}`dict` the keys/values that must not exist. Order is not checked. """ result = compare_dicts( @@ -160,8 +160,8 @@ def _dict_subject_get(self, key, *, factory): Args: self: implicitly added. - key: ([`object`]) the key to fetch. - factory: ([`callable`]) subject factory function, with the signature + key: {type}`object` the key to fetch. + factory: {type}`callable` subject factory function, with the signature of `def factory(value, *, meta)`, and returns the wrapped value. Returns: @@ -183,7 +183,7 @@ def _dict_subject_keys(self): self: implicitly added Returns: - [`CollectionSubject`] of the keys. + {type}`CollectionSubject` of the keys. """ return CollectionSubject.new( self.actual.keys(), @@ -192,9 +192,20 @@ def _dict_subject_keys(self): element_plural_name = "keys", ) +def _dict_subject_typedef(): + """Subject for `dict` assertions. + + :::{field} actual + :type: dict + + Underlying object asserted against + ::: + """ + # We use this name so it shows up nice in docs. # buildifier: disable=name-conventions DictSubject = struct( + TYPEDEF = _dict_subject_typedef, new = _dict_subject_new, contains_at_least = _dict_subject_contains_at_least, contains_exactly = _dict_subject_contains_exactly, diff --git a/lib/private/execution_info_subject.bzl b/lib/private/execution_info_subject.bzl index 35524f6..2ef70e1 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""" +"""ExecutionInfoSubject""" load(":dict_subject.bzl", "DictSubject") load(":str_subject.bzl", "StrSubject") @@ -23,16 +23,17 @@ def _execution_info_subject_new(info, *, meta): Method: ExecutionInfoSubject.new Args: - info: ([`testing.ExecutionInfo`]) provider instance. - meta: ([`ExpectMeta`]) of call chain information. + info: {type}`testing.ExecutionInfo` provider instance. + meta: {type}`ExpectMeta` of call chain information. Returns: - `ExecutionInfoSubject` struct. + {type}`ExecutionInfoSubject` struct. """ # buildifier: disable=uninitialized public = struct( # keep sorted start + actual = info, requirements = lambda *a, **k: _execution_info_subject_requirements(self, *a, **k), exec_group = lambda *a, **k: _execution_info_subject_exec_group(self, *a, **k), # keep sorted end @@ -52,7 +53,7 @@ def _execution_info_subject_requirements(self): self: implicitly added Returns: - `DictSubject` of the requirements. + {type}`DictSubject` of the requirements. """ return DictSubject.new( self.actual.requirements, @@ -68,16 +69,27 @@ def _execution_info_subject_exec_group(self): self: implicitly added Returns: - A [`StrSubject`] for the exec group. + {type}`StrSubject` for the exec group. """ return StrSubject.new( self.actual.exec_group, meta = self.meta.derive("exec_group()"), ) +def _execution_info_subject_typedef(): + """Subject for {obj}`testing.ExecutionInfo` + + :::{field} actual + :type: testing.ExecutionInfo + + The underlying object asserted against. + ::: + """ + # We use this name so it shows up nice in docs. # buildifier: disable=name-conventions ExecutionInfoSubject = struct( + TYPEDEF = _execution_info_subject_typedef, 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 c01c01c..7ccd3bd 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""" +"""Expect""" load(":action_subject.bzl", "ActionSubject") load(":bool_subject.bzl", "BoolSubject") @@ -37,18 +37,19 @@ def _expect_new_from_env(env): customize behavior. Usually this is helpful for testing. See `_fake_env()` in truth_tests.bzl for examples. * `fail`: callable that takes a failure message. If present, it - will be called instead of the regular `Expect.add_failure` logic. + will be called instead of the regular {obj}`Expect.add_failure()` logic. * `get_provider`: callable that takes 2 positional args (target and provider) and returns the found provider or fails. - * `has_provider`: callable that takes 2 positional args (a [`Target`] and - a [`provider`]) and returns [`bool`] (`True` if present, `False` otherwise) or fails. + * `has_provider`: callable that takes 2 positional args (a {obj}`Target` and + a {obj}`provider`) and returns {obj}`bool` (`True` if present, `False` + otherwise) or fails. Args: - env: unittest env struct, or some approximation. There are several + env: {type}`Env` unittest env struct, or some approximation. There are several attributes that override regular behavior; see above doc. Returns: - [`Expect`] object + {type}`Expect` object """ return _expect_new(env, None) @@ -58,11 +59,11 @@ def _expect_new(env, meta): Internal; only other `Expect` methods should be calling this. Args: - env: unittest env struct or some approximation. - meta: ([`ExpectMeta`]) metadata about call chain and state. + env: {type}`Env` unittest env struct or some approximation. + meta: {type}`ExpectMeta` metadata about call chain and state. Returns: - [`Expect`] object + {type}`Expect` object """ meta = meta or ExpectMeta.new(env) @@ -94,10 +95,10 @@ def _expect_that_action(self, action): Args: self: implicitly added. - action: ([`Action`]) the action to check. + action: {type}`Action` the action to check. Returns: - [`ActionSubject`] object. + {type}`ActionSubject` object. """ return ActionSubject.new( action, @@ -112,11 +113,11 @@ def _expect_that_bool(self, value, expr = "boolean"): Args: self: implicitly added. - value: ([`bool`]) the bool to check. - expr: ([`str`]) the starting "value of" expression to report in errors. + value: {type}`bool` the bool to check. + expr: {type}`str` the starting "value of" expression to report in errors. Returns: - [`BoolSubject`] object. + {type}`BoolSubject` object. """ return BoolSubject.new( value, @@ -129,11 +130,11 @@ def _expect_that_collection(self, collection, expr = "collection", **kwargs): Args: self: implicitly added. collection: The collection (list or depset) to assert. - expr: ([`str`]) the starting "value of" expression to report in errors. + expr: {type}`str` the starting "value of" expression to report in errors. **kwargs: Additional kwargs to pass onto CollectionSubject.new Returns: - [`CollectionSubject`] object. + {type}`CollectionSubject` object. """ return CollectionSubject.new(collection, self.meta.derive(expr), **kwargs) @@ -144,10 +145,10 @@ def _expect_that_depset_of_files(self, depset_files): Args: self: implicitly added. - depset_files: ([`depset`] of [`File`]) the values to assert on. + depset_files: {type}`depset[File]` the values to assert on. Returns: - [`DepsetFileSubject`] object. + {type}`DepsetFileSubject` object. """ return DepsetFileSubject.new(depset_files, self.meta.derive("depset_files")) @@ -158,11 +159,11 @@ def _expect_that_dict(self, mapping, meta = None): Args: self: implicitly added - mapping: ([`dict`]) the values to assert on - meta: ([`ExpectMeta`]) optional custom call chain information to use instead + mapping: {type}`dict` the values to assert on + meta: {type}`ExpectMeta` optional custom call chain information to use instead Returns: - [`DictSubject`] object. + {type}`DictSubject` object. """ meta = meta or self.meta.derive("dict") return DictSubject.new(mapping, meta = meta) @@ -174,11 +175,11 @@ def _expect_that_file(self, file, meta = None): Args: self: implicitly added. - file: ([`File`]) the value to assert. - meta: ([`ExpectMeta`]) optional custom call chain information to use instead + file: {type}`File` the value to assert. + meta: {type}`ExpectMeta` optional custom call chain information to use instead Returns: - [`FileSubject`] object. + {type}`FileSubject` object. """ meta = meta or self.meta.derive("file") return FileSubject.new(file, meta = meta) @@ -190,11 +191,11 @@ def _expect_that_int(self, value, expr = "integer"): Args: self: implicitly added. - value: ([`int`]) the value to check against. - expr: ([`str`]) the starting "value of" expression to report in errors. + value: {type}`int` the value to check against. + expr: {type}`str` the starting "value of" expression to report in errors. Returns: - [`IntSubject`] object. + {type}`IntSubject` object. """ return IntSubject.new(value, self.meta.derive(expr)) @@ -203,10 +204,10 @@ def _expect_that_str(self, value): Args: self: implicitly added. - value: ([`str`]) the value to check against. + value: {type}`str` the value to check against. Returns: - [`StrSubject`] object. + {type}`StrSubject` object. """ return StrSubject.new(value, self.meta.derive("string")) @@ -215,17 +216,17 @@ def _expect_that_struct(self, value, *, attrs, expr = "struct"): Args: self: implicitly added. - value: ([`struct`]) the value to check against. - expr: ([`str`]) The starting "value of" expression to report in errors. - attrs: ([`dict`] of [`str`] to [`callable`]) the functions to convert + value: {type}`struct` the value to check against. + expr: {type}`str` The starting "value of" expression to report in errors. + attrs: {type}`dict[str, callable]` the functions to convert attributes to subjects. The keys are attribute names that must exist on `actual`. The values are functions with the signature `def factory(value, *, meta)`, where `value` is the actual attribute - value of the struct, and `meta` is an [`ExpectMeta`] object. + value of the struct, and `meta` is an {type}`ExpectMeta` object. Returns: - [`StructSubject`] object. + {type}`StructSubject` object. """ return StructSubject.new(value, meta = self.meta.derive(expr), attrs = attrs) @@ -238,10 +239,10 @@ def _expect_that_target(self, target): Args: self: implicitly added. - target: ([`Target`]) subject target to check against. + target: {obj}`Target` subject target to check against. Returns: - [`TargetSubject`] object. + {type}`TargetSubject` object. """ return TargetSubject.new(target, self.meta.derive( expr = "target({})".format(target.label), @@ -257,10 +258,10 @@ def _expect_that_value(self, value, *, factory, expr = "value"): Args: self: implicitly added. - value: ([`struct`]) the value to check against. + value: {type}`struct` the value to check against. factory: A subject factory (a function that takes value and meta). Eg. subjects.collection - expr: ([`str`]) The starting "value of" expression to report in errors. + expr: {type}`str` The starting "value of" expression to report in errors. Returns: A subject corresponding to the type returned by the factory. @@ -279,21 +280,30 @@ def _expect_where(self, **details): Args: self: implicitly added. - **details: ([`dict`] of [`str`] to value) Each named arg is added to + **details: {type}`dict[str, value]` Each named arg is added to the metadata details with the provided string, which is printed as part of displaying any failures. Returns: - [`Expect`] object with separate metadata derived from the original self. + {type}`Expect` object with separate metadata derived from the original self. """ meta = self.meta.derive( details = ["{}: {}".format(k, v) for k, v in details.items()], ) return _expect_new(env = self.env, meta = meta) +def _expect_typedef(): + """Entry point for truth-style assertions with context. + + This is typically created through `env.expect` as part of the + analysis test framework. It holds context related to the test + state for later use in asserts and error reporting. + """ + # We use this name so it shows up nice in docs. # buildifier: disable=name-conventions Expect = struct( + TYPEDEF = _expect_typedef, # keep sorted start new = _expect_new, new_from_env = _expect_new_from_env, diff --git a/lib/private/expect_meta.bzl b/lib/private/expect_meta.bzl index 79672cc..4b246de 100644 --- a/lib/private/expect_meta.bzl +++ b/lib/private/expect_meta.bzl @@ -11,61 +11,29 @@ # 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 - -ExpectMeta object implementation. -""" +"""ExpectMeta object implementation.""" load("//lib:unittest.bzl", ut_asserts = "asserts") def _expect_meta_new(env, exprs = [], details = [], format_str_kwargs = None): - """Creates a new "ExpectMeta" struct". - - Method: ExpectMeta.new - - ExpectMeta objects are internal helpers for the Expect object and Subject - objects. They are used for Subjects to store and communicate state through a - series of call chains and asserts. - - This constructor should only be directly called by `Expect` objects. When a - parent Subject is creating a child-Subject, then [`derive()`] should be - used. - - ### Env objects + """Creates a new `ExpectMeta` struct". - The `env` object basically provides a way to interact with things outside - of the truth assertions framework. This allows easier testing of the - framework itself and decouples it from a particular test framework (which - makes it usable by by rules_testing's analysis_test and skylib's - analysistest) - - The `env` object requires the following attribute: - * ctx: The test's ctx. - - The `env` object allows the following attributes to customize behavior: - * fail: A callable that accepts a single string, which is the failure - message. Its return value is ignored. This is called when an assertion - fails. It's generally expected that it records a failure instead of - immediately failing. - * has_provider: (callable) it accepts two positional args, target and - provider and returns [`bool`]. This is used to implement `Provider in - target` operations. - * get_provider: (callable) it accepts two positional args, target and - provider and returns the provider value. This is used to implement - `target[Provider]`. + This constructor should only be directly called by {obj}`Expect` objects. + When a parent Subject is creating a child-Subject, then {obj}`derive()` + should be used. Args: - env: unittest env struct or some approximation. - exprs: ([`list`] of [`str`]) the expression strings of the call chain for + env: {type}`Env` unittest env struct or some approximation. + exprs: {type}`list[str]` the expression strings of the call chain for the subject. - details: ([`list`] of [`str`]) additional details to print on error. These + details: {type}`list[str]` additional details to print on error. These are usually informative details of the objects under test. format_str_kwargs: optional dict of format() kwargs. These kwargs are propagated through `derive()` calls and used when `ExpectMeta.format_str()` is called. Returns: - [`ExpectMeta`] object. + {type}`ExpectMeta` object. """ if format_str_kwargs == None: format_str_kwargs = {} @@ -111,21 +79,21 @@ def _expect_meta_derive(self, expr = None, details = None, format_str_kwargs = { Args: self: implicitly added. - expr: ([`str`]) human-friendly description of the call chain expression. + expr: {type}`str` human-friendly description of the call chain expression. e.g., if `foo_subject.bar_named("baz")` returns a child-subject, then "bar_named("bar")" would be the expression. - details: (optional [`list`] of [`str`]) human-friendly descriptions of additional + details: {type}`list[str] | None` human-friendly descriptions of additional detail to include in errors. This is usually additional information the child Subject wouldn't include itself. e.g. if `foo.first_action_argv().contains(1)`, returned a ListSubject, then including "first action: Action FooCompile" helps add context to the error message. If there is no additional detail to include, pass None. - format_str_kwargs: ([`dict`] of format()-kwargs) additional kwargs to - make available to [`format_str`] calls. + format_str_kwargs: {type}`dict[str, object]` additional kwargs to + make available to {obj}`format_str` calls. Returns: - [`ExpectMeta`] object. + {type}`ExpectMeta` object. """ if not details: details = [] @@ -160,10 +128,10 @@ def _expect_meta_format_str(self, template): Args: self: implicitly added. - template: ([`str`]) the format template string to use. + template: {type}`str` the format template string to use. Returns: - [`str`]; the template with parameters replaced. + {type}`str` the template with parameters replaced. """ return template.format(**self._format_str_kwargs) @@ -175,7 +143,7 @@ def _expect_meta_get_provider(self, target, provider): Args: self: implicitly added. - target: ([`Target`]) the target to get the provider from. + target: {type}`Target` the target to get the provider from. provider: The provider type to get. Returns: @@ -194,7 +162,7 @@ def _expect_meta_has_provider(self, target, provider): Args: self: implicitly added. - target: ([`Target`]) the target to check for the provider. + target: {type}`Target` the target to check for the provider. provider: the provider type to check for. Returns: @@ -215,14 +183,14 @@ def _expect_meta_add_failure(self, problem, actual): Args: self: implicitly added. - problem: ([`str`]) a string describing the expected value or problem + problem: {type}`str` a string describing the expected value or problem detected, and the expected values that weren't satisfied. A colon should be used to separate the description from the values. The description should be brief and include the word "expected", e.g. "expected: foo", or "expected values missing: ", the key point being the reader can easily take the values shown and look for it in the actual values displayed below it. - actual: ([`str`]) a string describing the values observed. A colon should + actual: {type}`str` a string describing the values observed. A colon should be used to separate the description from the observed values. The description should be brief and include the word "actual", e.g., "actual: bar". The values should include the actual, observed, @@ -257,7 +225,7 @@ def _expect_meta_current_expr(self): self: implicitly added. Returns: - [`str`] A string representing the current expression, e.g. + {type}`str` A string representing the current expression, e.g. "foo.bar(something).baz()" """ return ".".join(self._exprs) @@ -267,7 +235,7 @@ def _expect_meta_call_fail(self, msg): Args: self: implicitly added. - msg: ([`str`]) the failure message. + msg: {type}`str` the failure message. """ fail_func = getattr(self.env, "fail", None) if fail_func != None: @@ -278,9 +246,31 @@ def _expect_meta_call_fail(self, msg): # the first line of our message hard to see. ut_asserts.true(self.env, False, "\n" + msg) +def _expect_meta_typedef(): + """Internal helper for `Expect` objects. + + ExpectMeta objects are internal helpers for the {obj}`Expect` object and + Subject objects. They are used for Subjects to store and communicate state + through a series of call chains and asserts. + + + :::{field} ctx + :type: ctx + + The test's ctx + ::: + + :::{field} env + :type: Env + + The underlying env + ::: + """ + # We use this name so it shows up nice in docs. # buildifier: disable=name-conventions ExpectMeta = struct( + TYPEDEF = _expect_meta_typedef, new = _expect_meta_new, derive = _expect_meta_derive, format_str = _expect_meta_format_str, @@ -289,3 +279,46 @@ ExpectMeta = struct( add_failure = _expect_meta_add_failure, call_fail = _expect_meta_call_fail, ) + +def _env_typedef(): + """Interface for interacting outside the truth framework. + + The `env` object basically provides a way to interact with things outside + of the truth assertions framework. This allows easier testing of the + framework itself and decouples it from a particular test framework (which + makes it usable by by rules_testing's analysis_test and skylib's + analysistest) + + :::{field} ctx + :type: ctx + + The test's ctx + ::: + + :::{field} fail + :type: callable | unset + + A optional callable that accepts a single string, which is the failure + message. Its return value is ignored. This is called when an assertion + fails. It's generally expected that it records a failure instead of + immediately failing. + ::: + + :::{field} has_provider + :type: callable | unset + + A callable that accepts two positional args, target and provider, and returns + `bool`. This is used to implement `Provider in target` operations. + ::: + + :::{field} get_provider + :type: callable + + A callable that accepts two positional args, target and provider, and + returns the provider value. This is used to implement `target[Provider]`. + """ + +# buildifier: disable=name-conventions +Env = struct( + TYPEDEF = _env_typedef, +) diff --git a/lib/private/file_subject.bzl b/lib/private/file_subject.bzl index e8fc825..7c08eb4 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""" +"""FileSubject""" load(":str_subject.bzl", "StrSubject") @@ -22,16 +22,17 @@ def _file_subject_new(file, meta): Method: FileSubject.new Args: - file: ([`File`]) the file to assert against. - meta: ([`ExpectMeta`]) + file: {type}`File` the file to assert against. + meta: {type}`ExpectMeta` Returns: - [`FileSubject`] object. + {type}`FileSubject` object. """ # buildifier: disable=uninitialized public = struct( # keep sorted start + actual = file, equals = lambda *a, **k: _file_subject_equals(self, *a, **k), path = lambda *a, **k: _file_subject_path(self, *a, **k), short_path_equals = lambda *a, **k: _file_subject_short_path_equals(self, *a, **k), @@ -43,7 +44,7 @@ def _file_subject_new(file, meta): def _file_subject_equals(self, expected): """Asserts that `expected` references the same file as `self`. - This uses Bazel's notion of [`File`] equality, which usually includes + This uses Bazel's notion of {obj}`File` equality, which usually includes the configuration, owning action, internal hash, etc of a `File`. The particulars of comparison depend on the actual Java type implementing the `File` object (some ignore owner, for example). @@ -52,7 +53,7 @@ def _file_subject_equals(self, expected): NOTE: Same files generated by different owners are likely considered not equal to each other. The alternative for this is to assert the - `File.path` paths are equal using [`FileSubject.path()`] + `File.path` paths are equal using {obj}`FileSubject.path()` Method: FileSubject.equals """ @@ -70,7 +71,7 @@ def _file_subject_path(self): Method: FileSubject.path Returns: - [`StrSubject`] object. + {type}`StrSubject` object. """ return StrSubject.new( self.file.path, @@ -84,7 +85,7 @@ def _file_subject_short_path_equals(self, path): Args: self: implicitly added. - path: ([`str`]) the value the file's `short_path` must be equal to. + path: {type}`str` the value the underlying {obj}`File.short_path` must be equal to. """ path = self.meta.format_str(path) if path == self.file.short_path: @@ -94,9 +95,20 @@ def _file_subject_short_path_equals(self, path): "actual: {}".format(self.file.short_path), ) +def _file_subject_typedef(): + """Subject for asserting on {obj}`File` objects. + + :::{field} actual + :type: File + + The underlying file asserted against. + ::: + """ + # We use this name so it shows up nice in docs. # buildifier: disable=name-conventions FileSubject = struct( + TYPEDEF = _file_subject_typedef, new = _file_subject_new, equals = _file_subject_equals, path = _file_subject_path, diff --git a/lib/private/instrumented_files_info_subject.bzl b/lib/private/instrumented_files_info_subject.bzl index 4ba0b3b..65b0cdc 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""" +"""InstrumentedFilesInfoSubject""" load(":depset_file_subject.bzl", "DepsetFileSubject") @@ -21,11 +21,11 @@ def _instrumented_files_info_subject_new(info, *, meta): Method: InstrumentedFilesInfoSubject.new Args: - info: ([`InstrumentedFilesInfo`]) provider instance. - meta: ([`ExpectMeta`]) the meta data about the call chain. + info: {type}`InstrumentedFilesInfo` provider instance. + meta: {type}`ExpectMeta` the meta data about the call chain. Returns: - An `InstrumentedFilesInfoSubject` struct. + {type}`InstrumentedFilesInfoSubject` struct. """ self = struct( actual = info, @@ -39,12 +39,15 @@ def _instrumented_files_info_subject_new(info, *, meta): return public def _instrumented_files_info_subject_instrumented_files(self): - """Returns a `DesetFileSubject` of the instrumented files. + """Returns a `DepsetFileSubject` of the instrumented files. Method: InstrumentedFilesInfoSubject.instrumented_files Args: self: implicitly added + + Returns: + {type}`DepsetFileSubject` """ return DepsetFileSubject.new( self.actual.instrumented_files, @@ -52,21 +55,35 @@ def _instrumented_files_info_subject_instrumented_files(self): ) def _instrumented_files_info_subject_metadata_files(self): - """Returns a `DesetFileSubject` of the metadata files. + """Returns a `DepsetFileSubject` of the metadata files. Method: InstrumentedFilesInfoSubject.metadata_files Args: self: implicitly added + + Returns: + {type}`DepsetFileSubject` """ return DepsetFileSubject.new( self.actual.metadata_files, meta = self.meta.derive("metadata_files()"), ) +def _instrumented_files_info_subject_typedef(): + """Wrapper for asserting {type}`InstrumentedFilesInfo` objects. + + :::{field} actual + :type: InstrumentedFilesInfo + + The underlying object assert against + ::: + """ + # We use this name so it shows up nice in docs. # buildifier: disable=name-conventions InstrumentedFilesInfoSubject = struct( + TYPEDEF = _instrumented_files_info_subject_typedef, 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 cb8dda3..9bd0ca7 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""" +"""IntSubject""" load("@bazel_skylib//lib:types.bzl", "types") load(":check_util.bzl", "check_not_equals", "common_subject_is_in") @@ -24,11 +24,11 @@ def _int_subject_new(value, meta): Method: IntSubject.new Args: - value: (optional [`int`]) the value to perform asserts against may be None. - meta: ([`ExpectMeta`]) the meta data about the call chain. + value: {type}`int | None` the value to perform asserts against may be None. + meta: {type}`ExpectMeta` the meta data about the call chain. Returns: - [`IntSubject`]. + {type}`IntSubject` """ if not types.is_int(value) and value != None: fail("int required, got: {}".format(repr_with_type(value))) @@ -36,6 +36,7 @@ def _int_subject_new(value, meta): # buildifier: disable=uninitialized public = struct( # keep sorted start + actual = value, equals = lambda *a, **k: _int_subject_equals(self, *a, **k), is_greater_than = lambda *a, **k: _int_subject_is_greater_than(self, *a, **k), is_in = lambda *a, **k: common_subject_is_in(self, *a, **k), @@ -52,7 +53,7 @@ def _int_subject_equals(self, other): Args: self: implicitly added. - other: ([`int`]) value the subject must be equal to. + other: {type}`int` value the subject must be equal to. """ if self.actual == other: return @@ -68,7 +69,7 @@ def _int_subject_is_greater_than(self, other): Args: self: implicitly added. - other: ([`int`]) value the subject must be greater than. + other: {type}`int` value the subject must be greater than. """ if self.actual != None and other != None and self.actual > other: return @@ -84,7 +85,7 @@ def _int_subject_not_equals(self, unexpected): Args: self: implicitly added - unexpected: ([`int`]) the value actual cannot equal. + unexpected: {type}`int` the value actual cannot equal. """ return check_not_equals( actual = self.actual, @@ -92,9 +93,20 @@ def _int_subject_not_equals(self, unexpected): meta = self.meta, ) +def _int_subject_typedef(): + """Wrapper for asserting int values. + + :::{field} actual + :type: int | None + + The underlying value to assert against. + ::: + """ + # We use this name so it shows up nice in docs. # buildifier: disable=name-conventions IntSubject = struct( + TYPEDEF = _int_subject_typedef, new = _int_subject_new, equals = _int_subject_equals, is_greater_than = _int_subject_is_greater_than, diff --git a/lib/private/label_subject.bzl b/lib/private/label_subject.bzl index f801ef7..ab1b539 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""" +"""LabelSubject""" load("@bazel_skylib//lib:types.bzl", "types") load(":check_util.bzl", "common_subject_is_in") @@ -24,16 +24,17 @@ def _label_subject_new(label, meta): Method: LabelSubject.new Args: - label: ([`Label`]) the label to check against. - meta: ([`ExpectMeta`]) the metadata about the call chain. + label: {type}`Label` the label to check against. + meta: {type}`ExpectMeta` the metadata about the call chain. Returns: - [`LabelSubject`]. + {type}`LabelSubject`. """ # buildifier: disable=uninitialized public = struct( # keep sorted start + actual = label, equals = lambda *a, **k: _label_subject_equals(self, *a, **k), is_in = lambda *a, **k: _label_subject_is_in(self, *a, **k), # keep sorted end @@ -48,7 +49,7 @@ def _label_subject_equals(self, other): Args: self: implicitly added. - other: ([`Label`] | [`str`]) the expected value. If a `str` is passed, it + other: {type}`Label` | str` the expected value. If a `str` is passed, it will be converted to a `Label` using the `Label` function. """ if types.is_string(other): @@ -65,7 +66,7 @@ def _label_subject_is_in(self, any_of): Args: self: implicitly added. - any_of: ([`collection`] of ([`Label`] | [`str`])) If strings are + any_of: {type}`collection[Label | str]` If strings are provided, they must be parsable by `Label`. """ any_of = [ @@ -74,9 +75,20 @@ def _label_subject_is_in(self, any_of): ] common_subject_is_in(self, any_of) +def _label_subject_typedef(): + """Wrapper for asserts on Label objects + + :::{field} actual + :type: Label + + The underlying value to assert against. + ::: + """ + # We use this name so it shows up nice in docs. # buildifier: disable=name-conventions LabelSubject = struct( + TYPEDEF = _label_subject_typedef, new = _label_subject_new, equals = _label_subject_equals, is_in = _label_subject_is_in, diff --git a/lib/private/matching.bzl b/lib/private/matching.bzl index b8668ba..ee9059b 100644 --- a/lib/private/matching.bzl +++ b/lib/private/matching.bzl @@ -18,11 +18,11 @@ def _match_all(*matchers): """Match that all of multiple matchers match. Args: - *matchers: `list` of [`Matcher`]. If all match, then it is + *matchers: {type}`list[Matcher]` If all match, then it is considered a match. Returns: - [`Matcher`] (see `_match_custom`) + {type}`Matcher` (see `_match_custom`) """ desc = " and ".join([str(m.desc) for m in matchers]) @@ -37,21 +37,13 @@ def _match_all(*matchers): def _match_custom(desc, func): """Wrap an arbitrary function up as a Matcher. - Method: Matcher.new - - `Matcher` struct attributes: - - * `desc`: ([`str`]) a human-friendly description - * `match`: (callable) accepts 1 positional arg (the value to match) and - returns [`bool`] (`True` if it matched, `False` if not). - Args: - desc: ([`str`]) a human-friendly string describing what is matched. - func: (callable) accepts 1 positional arg (the value to match) and - returns [`bool`] (`True` if it matched, `False` if not). + desc: {type}`str` a human-friendly string describing what is matched. + func: {type}`callable` accepts 1 positional arg (the value to match) and + returns `bool` (`True` if it matched, `False` if not). Returns: - [`Matcher`] (see above). + {type}`Matcher` """ return struct(desc = desc, match = func) @@ -65,7 +57,7 @@ def _match_equals_wrapper(value): value: object, the value that must be equal to. Returns: - [`Matcher`] (see `_match_custom()`), whose description is `value`. + {type}`Matcher` (see `_match_custom()`), whose description is `value`. """ return _match_custom(value, lambda other: other == value) @@ -73,10 +65,10 @@ def _match_file_basename_contains(substr): """Match that a a `File.basename` string contains a substring. Args: - substr: ([`str`]) the substring to match. + substr: {type}`str` the substring to match. Returns: - [`Matcher`] (see `_match_custom()`). + {type}`Matcher` (see `_match_custom()`). """ return struct( desc = "".format(substr), @@ -87,11 +79,11 @@ def _match_file_path_matches(pattern): """Match that a `File.path` string matches a glob-style pattern. Args: - pattern: ([`str`]) the pattern to match. "*" can be used to denote + pattern: {type}`str` the pattern to match. "*" can be used to denote "match anything". Returns: - [`Matcher`] (see `_match_custom`). + {type}`Matcher` (see `_match_custom`). """ parts = pattern.split("*") return struct( @@ -103,10 +95,10 @@ def _match_file_basename_equals(value): """Match that a `File.basename` string equals `value`. Args: - value: ([`str`]) the basename to match. + value: {type}`str` the basename to match. Returns: - [`Matcher`] instance + {type}`Matcher` instance """ return struct( desc = "".format(value), @@ -120,10 +112,10 @@ def _match_file_extension_in(values): have multiple parts, e.g. `*.tar.gz` or `*.so.*`. Args: - values: ([`list`] of [`str`]) the extensions to match. + values: {type}`list[str]` the extensions to match. Returns: - [`Matcher`] instance + {type}`Matcher` instance """ return struct( desc = "".format(repr(values)), @@ -142,7 +134,7 @@ def _match_is_in(values): values: The collection that the value must be within. Returns: - [`Matcher`] (see `_match_custom()`). + {type}`Matcher` (see `_match_custom()`). """ return struct( desc = "".format(repr(values)), @@ -156,10 +148,10 @@ def _match_never(desc): while providing a custom description. Args: - desc: ([`str`]) human-friendly string. + desc: {type}`str` human-friendly string. Returns: - [`Matcher`] (see `_match_custom`). + {type}`Matcher` (see `_match_custom`). """ return struct( desc = desc, @@ -173,11 +165,11 @@ def _match_any(*matchers): values. Args: - *matchers: `list` of [`Matcher`]. If any match, then it is + *matchers: {type}`list[Matcher]` If any match, then it is considered a match. Returns: - [`Matcher`] (see `_match_custom`) + {type}`Matcher` (see `_match_custom`) """ desc = " or ".join([str(m.desc) for m in matchers]) @@ -199,7 +191,7 @@ def _match_contains(contained): contained: the value that to-be-matched value must contain. Returns: - [`Matcher`] (see `_match_custom`). + {type}`Matcher` (see `_match_custom`). """ return struct( desc = "".format(contained), @@ -210,10 +202,10 @@ def _match_str_endswith(suffix): """Match that a string contains another string. Args: - suffix: ([`str`]) the suffix that must be present + suffix: {type}`str` the suffix that must be present Returns: - [`Matcher`] (see `_match_custom`). + {type}`Matcher` (see `_match_custom`). """ return struct( desc = "".format(suffix), @@ -224,12 +216,12 @@ def _match_str_matches(pattern): """Match that a string matches a glob-style pattern. Args: - pattern: ([`str`]) the pattern to match. `*` can be used to denote + pattern: {type}`str` the pattern to match. `*` can be used to denote "match anything". There is an implicit `*` at the start and end of the pattern. Returns: - [`Matcher`] object. + {type}`Matcher` object. """ parts = pattern.split("*") return struct( @@ -241,10 +233,10 @@ def _match_str_startswith(prefix): """Match that a string contains another string. Args: - prefix: ([`str`]) the prefix that must be present + prefix: {type}`str` the prefix that must be present Returns: - [`Matcher`] (see `_match_custom`). + {type}`Matcher` (see `_match_custom`). """ return struct( desc = "".format(prefix), @@ -262,6 +254,28 @@ def _match_parts_in_order(string, parts): def _is_matcher(obj): return hasattr(obj, "desc") and hasattr(obj, "match") +def _matcher_typedef(): + """A struct to represent matching with information metadata. + + To create a custom Matcher, use {obj}`matching.custom()`. + + :::{field} desc + :type: str + A human friendly description of what matches. + ::: + :::{field} match + :type: callable + + callable that accepts 1 positional arg (the value to match) and + returns `bool` (`True` if it matched, `False` if not). + ::: + """ + +# buildifier: disable=name-conventions +Matcher = struct( + TYPEDEF = _matcher_typedef, +) + # For the definition of a `Matcher` object, see `_match_custom`. matching = struct( # keep sorted start diff --git a/lib/private/ordered.bzl b/lib/private/ordered.bzl index dec2662..0e40a68 100644 --- a/lib/private/ordered.bzl +++ b/lib/private/ordered.bzl @@ -12,13 +12,17 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""# Ordered""" +"""Ordered""" # This is just a stub so doc generation is nicer. def _ordered_in_order(): """Checks that the values were in order.""" +def _in_order_typedef(): + """Singleton Ordered implementation for when order was respected.""" + IN_ORDER = struct( + TYPEDEF = _in_order_typedef, in_order = _ordered_in_order, ) @@ -56,9 +60,22 @@ def _ordered_incorrectly_in_order(self): """ self.meta.add_failure(self.format_problem(), self.format_actual()) +def _ordered_incorrectly_typedef(): + """Ordered implementation for when order was not respected.""" + # We use this name so it shows up nice in docs. # buildifier: disable=name-conventions OrderedIncorrectly = struct( + TYPEDEF = _ordered_incorrectly_typedef, new = _ordered_incorrectly_new, in_order = _ordered_incorrectly_in_order, ) + +def _ordered_typedef(): + """Interface for asserting values were matched in order.""" + +# buildifier: disable=name-conventions +Ordered = struct( + TYPEDEF = _ordered_typedef, + in_order = _ordered_in_order, +) diff --git a/lib/private/run_environment_info_subject.bzl b/lib/private/run_environment_info_subject.bzl index 43d9e67..6e2af3f 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""" +"""RunEnvironmentInfoSubject""" load(":collection_subject.bzl", "CollectionSubject") load(":dict_subject.bzl", "DictSubject") @@ -23,8 +23,8 @@ def _run_environment_info_subject_new(info, *, meta): Method: RunEnvironmentInfoSubject.new Args: - info: ([`RunEnvironmentInfo`]) provider instance. - meta: ([`ExpectMeta`]) of call chain information. + info: {type}`RunEnvironmentInfo` provider instance. + meta: {type}`ExpectMeta` of call chain information. """ # buildifier: disable=uninitialized @@ -47,7 +47,7 @@ def _run_environment_info_subject_environment(self): self: implicitly added Returns: - [`DictSubject`] of the str->str environment map. + {type}`DictSubject[str, str]` of the str->str environment map. """ return DictSubject.new( self.actual.environment, @@ -63,17 +63,28 @@ def _run_environment_info_subject_inherited_environment(self): self: implicitly added Returns: - [`CollectionSubject`] of [`str`]; from the - [`RunEnvironmentInfo.inherited_environment`] list. + {type}`CollectionSubject[str]` from + {obj}`RunEnvironmentInfo.inherited_environment` list. """ return CollectionSubject.new( self.actual.inherited_environment, meta = self.meta.derive("inherited_environment()"), ) +def _run_environment_info_subject_typedef(): + """Subject for {obj}`RunEnvironmentInfo` object + + :::{field} actual + :type: RunEnvironmentInfo + + The underlying value to assert against. + ::: + """ + # We use this name so it shows up nice in docs. # buildifier: disable=name-conventions RunEnvironmentInfoSubject = struct( + TYPEDEF = _run_environment_info_subject_typedef, 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 046e419..bdf6363 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""" +"""RunfilesSubject""" load( "//lib:util.bzl", @@ -43,13 +43,13 @@ def _runfiles_subject_new(runfiles, meta, kind = None): Method: RunfilesSubject.new Args: - runfiles: ([`runfiles`]) the runfiles to check against. - meta: ([`ExpectMeta`]) the metadata about the call chain. - kind: (optional [`str`]) what type of runfiles they are, usually "data" + runfiles: {type}`runfiles` the runfiles to check against. + meta: {type}`ExpectMeta` the metadata about the call chain. + kind: {type}`str | None` what type of runfiles they are, usually "data" or "default". If not known or not applicable, use None. Returns: - [`RunfilesSubject`] object. + {type}`RunfilesSubject` object. """ self = struct( runfiles = runfiles, @@ -81,7 +81,7 @@ def _runfiles_subject_contains(self, expected): Args: self: implicitly added. - expected: ([`str`]) the path to check is present. This will be formatted + expected: {type}`str` the path to check is present. This will be formatted using `ExpectMeta.format_str` and its current contextual keywords. Note that paths are runfiles-root relative (i.e. you likely need to include the workspace name.) @@ -100,9 +100,9 @@ def _runfiles_subject_contains_at_least(self, paths): Args: self: implicitly added. - paths: ((collection of [`str`]) | [`runfiles`]) the paths that must + paths: {type}`collection[str] | runfiles` the paths that must exist. If a collection of strings is provided, they will be - formatted using [`ExpectMeta.format_str`], so its template keywords + formatted using {type}`ExpectMeta.format_str`, so its template keywords can be directly passed. If a `runfiles` object is passed, it is converted to a set of path strings. """ @@ -147,8 +147,8 @@ def _runfiles_subject_contains_predicate(self, matcher): Args: self: implicitly added. - matcher: callable that takes 1 positional arg ([`str`] path) and returns - boolean. + matcher: {type}`callable` callable that takes 1 positional arg + ({type}`str` path) and returns boolean. """ check_contains_predicate( self.actual_paths, @@ -168,10 +168,10 @@ def _runfiles_subject_contains_exactly(self, paths): Args: self: implicitly added. - paths: ([`collection`] of [`str`]) the paths to check. These will be - formatted using `meta.format_str`, so its template keywords can - be directly passed. All the paths must exist in the runfiles exactly - as provided, and no extra paths may exist. + paths: {type}`collection[str]` the paths to check. These will be + formatted using {obj}`ExpectMeta.format_str()`, so its template + keywords can be directly passed. All the paths must exist in the + runfiles exactly as provided, and no extra paths may exist. """ paths = [self.meta.format_str(p) for p in to_list(paths)] runfiles_name = "{}runfiles".format(self.kind + " " if self.kind else "") @@ -224,11 +224,11 @@ def _runfiles_subject_contains_none_of(self, paths, require_workspace_prefix = T Args: self: implicitly added. - paths: ([`collection`] of [`str`]) the paths that should not exist. They should + paths: {type}`collection[str]` the paths that should not exist. They should be runfiles root-relative paths (not workspace relative). The value is formatted using `ExpectMeta.format_str` and the current contextual keywords. - require_workspace_prefix: ([`bool`]) True to check that the path includes the + require_workspace_prefix: {type}`bool` True to check that the path includes the workspace prefix. This is to guard against accidentallly passing a workspace relative path, which will (almost) never exist, and cause the test to always pass. Specify False if the file being checked for @@ -254,11 +254,11 @@ def _runfiles_subject_not_contains(self, path, require_workspace_prefix = True): Args: self: implicitly added. - path: ([`str`]) the path that should not exist. It should be a runfiles + path: {type}`str` the path that should not exist. It should be a runfiles root-relative path (not workspace relative). The value is formatted using `format_str`, so its template keywords can be directly passed. - require_workspace_prefix: ([`bool`]) True to check that the path includes the + require_workspace_prefix: {type}`bool` True to check that the path includes the workspace prefix. This is to guard against accidentallly passing a workspace relative path, which will (almost) never exist, and cause the test to always pass. Specify False if the file being checked for @@ -284,7 +284,7 @@ def _runfiles_subject_not_contains_predicate(self, matcher): Args: self: implicitly added. - matcher: [`Matcher`] that accepts a string (runfiles root-relative path). + matcher: {type}`Matcher` that accepts a string (runfiles root-relative path). """ check_not_contains_predicate(self.actual_paths, matcher, meta = self.meta) @@ -311,9 +311,20 @@ def _runfiles_subject_check_workspace_prefix(self, path): "require_workspace_prefix=False if the path is truly " + "runfiles-root relative, not workspace relative.\npath=" + path) +def _runfiles_subject_typedef(): + """Subject for asserting runfiles objects + + :::{field} actual + :type: runfiles + + Underlying object to assert against. + ::: + """ + # We use this name so it shows up nice in docs. # buildifier: disable=name-conventions RunfilesSubject = struct( + TYPEDEF = _runfiles_subject_typedef, new = _runfiles_subject_new, contains = _runfiles_subject_contains, contains_at_least = _runfiles_subject_contains_at_least, diff --git a/lib/private/str_subject.bzl b/lib/private/str_subject.bzl index c4655b1..64abd93 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""" +"""StrSubject""" load( ":check_util.bzl", @@ -27,15 +27,16 @@ def _str_subject_new(actual, meta): Method: StrSubject.new Args: - actual: ([`str`]) the string to check against. - meta: ([`ExpectMeta`]) of call chain information. + actual: {type}`str` the string to check against. + meta: {type}`ExpectMeta` of call chain information. Returns: - [`StrSubject`] object. + {type}`StrSubject` object. """ self = struct(actual = actual, meta = meta) public = struct( # keep sorted start + actual = actual, contains = lambda *a, **k: _str_subject_contains(self, *a, **k), equals = lambda *a, **k: _str_subject_equals(self, *a, **k), is_in = lambda *a, **k: common_subject_is_in(self, *a, **k), @@ -52,7 +53,7 @@ def _str_subject_contains(self, substr): Args: self: implicitly added. - substr: ([`str`]) the substring to check for. + substr: {type}`str` the substring to check for. """ if substr in self.actual: return @@ -68,7 +69,7 @@ def _str_subject_equals(self, other): Args: self: implicitly added. - other: ([`str`]) the expected value it should equal. + other: {type}`str` the expected value it should equal. """ if self.actual == other: return @@ -84,7 +85,7 @@ def _str_subject_not_equals(self, unexpected): Args: self: implicitly added. - unexpected: ([`str`]) the value actual cannot equal. + unexpected: {type}`str` the value actual cannot equal. """ return check_not_equals( actual = self.actual, @@ -96,6 +97,13 @@ def _str_subject_split(self, sep): """Return a `CollectionSubject` for the actual string split by `sep`. Method: StrSubject.split + + Args: + self: implicitly added. + sep: {type}`str` string to split by + + Returns: + {type}`CollectionSubject[str]` """ return CollectionSubject.new( self.actual.split(sep), @@ -105,9 +113,20 @@ def _str_subject_split(self, sep): element_plural_name = "parts", ) +def _str_subject_typedef(): + """Subject for asserting strings. + + :::{field} actual + :type: str + + Underlying object to assert against. + ::: + """ + # We use this name so it shows up nice in docs. # buildifier: disable=name-conventions StrSubject = struct( + TYPEDEF = _str_subject_typedef, new = _str_subject_new, contains = _str_subject_contains, equals = _str_subject_equals, diff --git a/lib/private/struct_subject.bzl b/lib/private/struct_subject.bzl index 7822341..d049bbe 100644 --- a/lib/private/struct_subject.bzl +++ b/lib/private/struct_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. -"""# StructSubject +"""StructSubject A subject for arbitrary structs. This is most useful when wrapping an ad-hoc struct (e.g. a struct specific to a particular function). Such ad-hoc structs @@ -63,22 +63,19 @@ def _foo_test(env): """ def _struct_subject_new(actual, *, meta, attrs): - """Creates a `StructSubject`, which is a thin wrapper around a [`struct`]. + """Creates a `StructSubject`, which is a thin wrapper around a {type}`struct`. Args: - actual: ([`struct`]) the struct to wrap. - meta: ([`ExpectMeta`]) object of call context information. - attrs: ([`dict`] of [`str`] to [`callable`]) the functions to convert + actual: {type}`struct` the struct to wrap. + meta: {type}`ExpectMeta` object of call context information. + attrs: {type}`dict[str, callable]` the functions to convert attributes to subjects. The keys are attribute names that must exist on `actual`. The values are functions with the signature `def factory(value, *, meta)`, where `value` is the actual attribute - value of the struct, and `meta` is an [`ExpectMeta`] object. + value of the struct, and `meta` is an {type}`ExpectMeta` object. Returns: - [`StructSubject`] object, which is a struct with the following shape: - * `actual` attribute, the underlying struct that was wrapped. - * A callable attribute for each `attrs` entry; it takes no args - and returns what the corresponding factory from `attrs` returns. + {type}`StructSubject` object """ attr_accessors = {} for name, factory in attrs.items(): @@ -100,9 +97,28 @@ def _make_attr_accessor(actual, name, factory, meta): return attr_accessor +def _struct_subject_typedef(): + """Subject for wrapping arbitrary structs. + + :::{field} actual + :type: struct + + The underlying struct being asserted against. + ::: + + :::{field} + :type: callable + + A callable attribute exists for each attribute of `actual`. Each callable + takes no args and returns what the corresponding factory from `attrs` + returns. + ::: + """ + # buildifier: disable=name-conventions StructSubject = struct( # keep sorted start + TYPEDEF = _struct_subject_typedef, new = _struct_subject_new, # keep sorted end ) diff --git a/lib/private/target_subject.bzl b/lib/private/target_subject.bzl index a8d7312..e8d8d0b 100644 --- a/lib/private/target_subject.bzl +++ b/lib/private/target_subject.bzl @@ -12,9 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""# TargetSubject +"""TargetSubject -`TargetSubject` wraps a [`Target`] object and provides method for asserting +`TargetSubject` wraps a {type}`Target` object and provides method for asserting its state. """ @@ -40,14 +40,14 @@ def _target_subject_new(target, meta): Method: TargetSubject.new **Public attributes**: - * `actual`: The wrapped [`Target`] object. + * `actual`: The wrapped {type}`Target` object. Args: - target: ([`Target`]) the target to check against. - meta: ([`ExpectMeta`]) metadata about the call chain. + target: {type}`Target` the target to check against. + meta: {type}`ExpectMeta` metadata about the call chain. Returns: - [`TargetSubject`] object + {type}`TargetSubject` object """ self = struct(target = target, meta = meta) public = struct( @@ -80,7 +80,7 @@ def _target_subject_runfiles(self): self: implicitly added. Returns: - [`RunfilesSubject`] object. + {type}`RunfilesSubject` object. """ meta = self.meta.derive("runfiles()") return RunfilesSubject.new(self.target[DefaultInfo].default_runfiles, meta, "default") @@ -94,7 +94,7 @@ def _target_subject_tags(self): self: implicitly added Returns: - [`CollectionSubject`] asserting the target's tags. + {type}`CollectionSubject` asserting the target's tags. """ return CollectionSubject.new( _target_subject_get_attr(self, "tags"), @@ -121,7 +121,7 @@ def _target_subject_data_runfiles(self): self: implicitly added. Returns: - [`RunfilesSubject`] object + {type}`RunfilesSubject` object """ meta = self.meta.derive("data_runfiles()") return RunfilesSubject.new(self.target[DefaultInfo].data_runfiles, meta, "data") @@ -135,7 +135,7 @@ def _target_subject_default_outputs(self): self: implicitly added. Returns: - [`DepsetFileSubject`] object. + {type}`DepsetFileSubject` object. """ meta = self.meta.derive("default_outputs()") return DepsetFileSubject.new(self.target[DefaultInfo].files, meta) @@ -149,7 +149,7 @@ def _target_subject_executable(self): self: implicitly added. Returns: - [`FileSubject`] object. + {type}`FileSubject` object. """ meta = self.meta.derive("executable()") return FileSubject.new(self.target[DefaultInfo].files_to_run.executable, meta) @@ -163,7 +163,7 @@ def _target_subject_failures(self): self: implicitly added Returns: - [`CollectionSubject`] of [`str`]. + {type}`CollectionSubject[str]` """ meta = self.meta.derive("failures()") if AnalysisFailureInfo in self.target: @@ -208,7 +208,7 @@ def _target_subject_output_group(self, name): Args: self: implicitly added. - name: ([`str`]) an output group name. If it isn't present, an error is raised. + name: {type}`str` an output group name. If it isn't present, an error is raised. Returns: DepsetFileSubject of the named output group. @@ -269,12 +269,12 @@ def _target_subject_action_generating(self, short_path): Args: self: implicitly added. - short_path: ([`str`]) the output's short_path to match. The value is - formatted using [`format_str`], so its template keywords can be + short_path: {type}`str` the output's short_path to match. The value is + formatted using {obj}`format_str`, so its template keywords can be directly passed. Returns: - [`ActionSubject`] for the matching action. If no action is found, or + {type}`ActionSubject` for the matching action. If no action is found, or more than one action matches, then an error is raised. """ @@ -309,15 +309,15 @@ def _target_subject_action_named(self, mnemonic): Method: TargetSubject.action_named - NOTE: in order to use this method, the target must have the [`TestingAspectInfo`] - provider (added by the [`testing_aspect`] aspect.) + NOTE: in order to use this method, the target must have the {obj}`TestingAspectInfo` + provider (added by the {obj}`testing_aspect`] aspect.) Args: self: implicitly added. - mnemonic: ([`str`]) the mnemonic to match + mnemonic: {type}`str` the mnemonic to match Returns: - [`ActionSubject`]. If no action matches, or more than one action matches, an error + {type}`ActionSubject`. If no action matches, or more than one action matches, an error is raised. """ if TestingAspectInfo not in self.target: @@ -364,9 +364,9 @@ def _target_subject_attr(self, name, *, factory = None): Args: self: implicitly added - name: ([`str`]) the attribute to get. If it's an unsupported attribute, and + name: {type}`str` the attribute to get. If it's an unsupported attribute, and no explicit factory was provided, an error will be raised. - factory: (callable) function to create the returned subject based on + factory: {type}`callable` function to create the returned subject based on the attribute value. If specified, it takes precedence over the attributes that are inherently understood. It must have the following signature: `def factory(value, *, meta)`, where `value` is @@ -422,9 +422,20 @@ PROVIDER_SUBJECT_FACTORIES = [ ), ] +def _target_subject_typedef(): + """Subject for `Target` objects. + + :::{field} actual + :type: Target + + Underlying object asserted against. + ::: + """ + # We use this name so it shows up nice in docs. # buildifier: disable=name-conventions TargetSubject = struct( + TYPEDEF = _target_subject_typedef, new = _target_subject_new, runfiles = _target_subject_runfiles, tags = _target_subject_tags, diff --git a/lib/truth.bzl b/lib/truth.bzl index 920567d..e388cdf 100644 --- a/lib/truth.bzl +++ b/lib/truth.bzl @@ -12,9 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""# Truth - -Truth-style asserts for Bazel's Starlark. +"""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 @@ -26,10 +24,13 @@ provides type-specific assertion methods. This style provides several benefits: For more detailed documentation, see the docs on GitHub. -## Basic usage +::::{topic} Basic usage -NOTE: This example assumes usage of [`rules_testing`]'s [`analysis_test`] +:::{note} +This example assumes usage of [`rules_testing`]'s [`analysis_test`] framework, but that framework is not required. +::: +:::: ``` def foo_test(env, target): @@ -40,6 +41,7 @@ def foo_test(env, target): subject = env.expect.that_action(...) subject.contains_at_least_args(...) ``` +:::: """ load("//lib/private:bool_subject.bzl", "BoolSubject") diff --git a/lib/util.bzl b/lib/util.bzl index e328b71..3e92079 100644 --- a/lib/util.bzl +++ b/lib/util.bzl @@ -12,10 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""# Util - -Various utilities to aid with testing. -""" +"""Various utilities to aid with testing.""" load("@bazel_skylib//lib:paths.bzl", "paths") load("@bazel_skylib//lib:types.bzl", "types")