From 2a06b453970dd513837d2d6f5480f67b181b928d Mon Sep 17 00:00:00 2001 From: Dan Lee Date: Mon, 22 Mar 2021 14:35:56 -0400 Subject: [PATCH 001/279] Initial push --- .../gcp-sphinx-docfx-yaml/CONTRIBUTING.md | 34 + packages/gcp-sphinx-docfx-yaml/LICENSE | 202 +++ packages/gcp-sphinx-docfx-yaml/MANIFEST.in | 1 + packages/gcp-sphinx-docfx-yaml/README.rst | 92 ++ packages/gcp-sphinx-docfx-yaml/appveyor.yml | 41 + packages/gcp-sphinx-docfx-yaml/debug.py | 41 + .../docfx_yaml/__init__.py | 14 + .../docfx_yaml/directives.py | 46 + .../docfx_yaml/extension.py | 865 +++++++++++++ .../docfx_yaml/extract_nodes.py | 175 +++ .../docfx_yaml/monkeypatch.py | 459 +++++++ .../gcp-sphinx-docfx-yaml/docfx_yaml/nodes.py | 34 + .../docfx_yaml/settings.py | 23 + .../gcp-sphinx-docfx-yaml/docfx_yaml/utils.py | 56 + .../docfx_yaml/writer.py | 1129 +++++++++++++++++ .../docs/How_to_Document_Python_API.md | 354 ++++++ packages/gcp-sphinx-docfx-yaml/docs/Makefile | 195 +++ .../gcp-sphinx-docfx-yaml/docs/Workflow.vsdx | Bin 0 -> 88545 bytes packages/gcp-sphinx-docfx-yaml/docs/api.rst | 14 + packages/gcp-sphinx-docfx-yaml/docs/conf.py | 312 +++++ .../gcp-sphinx-docfx-yaml/docs/design.rst | 103 ++ .../gcp-sphinx-docfx-yaml/docs/docfx.json | 22 + packages/gcp-sphinx-docfx-yaml/docs/index.rst | 1 + .../gcp-sphinx-docfx-yaml/docs/layout.rst | 19 + .../gcp-sphinx-docfx-yaml/old_appveyor.yml | 57 + packages/gcp-sphinx-docfx-yaml/prospector.yml | 40 + .../gcp-sphinx-docfx-yaml/readthedocs.yml | 22 + .../gcp-sphinx-docfx-yaml/requirements.txt | 2 + packages/gcp-sphinx-docfx-yaml/setup.cfg | 2 + packages/gcp-sphinx-docfx-yaml/setup.py | 40 + .../gcp-sphinx-docfx-yaml/tests/__init__.py | 14 + .../tests/example/conflict/__init__.py | 22 + .../tests/example/conflict/foo.py | 184 +++ .../tests/example/doc/conf.py | 40 + .../tests/example/doc/format.google.rst | 22 + .../tests/example/doc/format.numpy.rst | 22 + .../tests/example/doc/format.rst | 19 + .../tests/example/doc/format.rst.rst | 38 + .../tests/example/doc/index.rst | 0 .../example/doc/nspkg.native.native_foo.rst | 10 + .../nspkg.pkg_resources.pkg_resources_foo.rst | 10 + .../tests/example/doc/nspkg.pkg_resources.rst | 17 + .../example/doc/nspkg.pkgutil.pkgutil_foo.rst | 10 + .../tests/example/doc/nspkg.pkgutil.rst | 17 + .../tests/example/doc/nspkg.rst | 18 + .../tests/example/format/__init__.py | 18 + .../tests/example/format/google/__init__.py | 16 + .../tests/example/format/google/foo.py | 181 +++ .../tests/example/format/numpy/__init__.py | 16 + .../tests/example/format/numpy/foo.py | 204 +++ .../tests/example/format/rst/__init__.py | 23 + .../tests/example/format/rst/directives.py | 85 ++ .../tests/example/format/rst/enum.py | 24 + .../tests/example/format/rst/foo.py | 203 +++ .../tests/example/nspkg/__init__.py | 18 + .../tests/example/nspkg/native/__init__.pyi | 2 + .../nspkg/native/native_foo/__init__.py | 19 + .../example/nspkg/pkg_resources/__init__.py | 19 + .../pkg_resources_foo/__init__.py | 19 + .../tests/example/nspkg/pkgutil/__init__.py | 19 + .../nspkg/pkgutil/pkgutil_foo/__init__.py | 19 + .../tests/example/setup.cfg | 2 + .../tests/example/setup.py | 27 + .../gcp-sphinx-docfx-yaml/tests/test_yaml.py | 534 ++++++++ packages/gcp-sphinx-docfx-yaml/tox.ini | 30 + 65 files changed, 6316 insertions(+) create mode 100644 packages/gcp-sphinx-docfx-yaml/CONTRIBUTING.md create mode 100644 packages/gcp-sphinx-docfx-yaml/LICENSE create mode 100644 packages/gcp-sphinx-docfx-yaml/MANIFEST.in create mode 100644 packages/gcp-sphinx-docfx-yaml/README.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/appveyor.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/debug.py create mode 100644 packages/gcp-sphinx-docfx-yaml/docfx_yaml/__init__.py create mode 100644 packages/gcp-sphinx-docfx-yaml/docfx_yaml/directives.py create mode 100644 packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py create mode 100644 packages/gcp-sphinx-docfx-yaml/docfx_yaml/extract_nodes.py create mode 100644 packages/gcp-sphinx-docfx-yaml/docfx_yaml/monkeypatch.py create mode 100644 packages/gcp-sphinx-docfx-yaml/docfx_yaml/nodes.py create mode 100644 packages/gcp-sphinx-docfx-yaml/docfx_yaml/settings.py create mode 100644 packages/gcp-sphinx-docfx-yaml/docfx_yaml/utils.py create mode 100644 packages/gcp-sphinx-docfx-yaml/docfx_yaml/writer.py create mode 100644 packages/gcp-sphinx-docfx-yaml/docs/How_to_Document_Python_API.md create mode 100644 packages/gcp-sphinx-docfx-yaml/docs/Makefile create mode 100644 packages/gcp-sphinx-docfx-yaml/docs/Workflow.vsdx create mode 100644 packages/gcp-sphinx-docfx-yaml/docs/api.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/docs/conf.py create mode 100644 packages/gcp-sphinx-docfx-yaml/docs/design.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/docs/docfx.json create mode 100644 packages/gcp-sphinx-docfx-yaml/docs/index.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/docs/layout.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/old_appveyor.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/prospector.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/readthedocs.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/requirements.txt create mode 100644 packages/gcp-sphinx-docfx-yaml/setup.cfg create mode 100644 packages/gcp-sphinx-docfx-yaml/setup.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/__init__.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/conflict/__init__.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/conflict/foo.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/doc/conf.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/doc/format.google.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/doc/format.numpy.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/doc/format.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/doc/format.rst.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/doc/index.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.native.native_foo.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.pkg_resources.pkg_resources_foo.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.pkg_resources.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.pkgutil.pkgutil_foo.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.pkgutil.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/format/__init__.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/format/google/__init__.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/format/google/foo.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/format/numpy/__init__.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/format/numpy/foo.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/format/rst/__init__.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/format/rst/directives.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/format/rst/enum.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/format/rst/foo.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/__init__.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/native/__init__.pyi create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/native/native_foo/__init__.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/pkg_resources/__init__.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/pkg_resources/pkg_resources_foo/__init__.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/pkgutil/__init__.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/pkgutil/pkgutil_foo/__init__.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/setup.cfg create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/setup.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/test_yaml.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tox.ini diff --git a/packages/gcp-sphinx-docfx-yaml/CONTRIBUTING.md b/packages/gcp-sphinx-docfx-yaml/CONTRIBUTING.md new file mode 100644 index 000000000000..1237ad35d3f8 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/CONTRIBUTING.md @@ -0,0 +1,34 @@ +**Please note that this is the forked version of the original repository, which +is found on https://github.com/docascode/sphinx-docfx-yaml. Unless the issue +applies only to this repository, please also file an issue and/or contribute +to the original repository as well.** + +# How to Contribute + +We'd love to accept your patches and contributions to this project. +There are just a few small guidelines you need to follow. + +## Contributor License Agreement + +Contributions to this project must be accompanied by a Contributor License +Agreement (CLA). You (or your employer) retain the copyright to your +contribution; this simply gives us permission to use and redistribute your +contributions as part of the project. Head over to + to see your current agreements on file or +to sign a new one. + +You generally only need to submit a CLA once, so if you've already submitted one +(even if it was for a different project), you probably don't need to do it +again. + +## Code Reviews + +All submissions, including submissions by project members, require review. We +use GitHub pull requests for this purpose. Consult +[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more +information on using pull requests. + +## Community Guidelines + +This project follows +[Google's Open Source Community Guidelines](https://opensource.google/conduct/). diff --git a/packages/gcp-sphinx-docfx-yaml/LICENSE b/packages/gcp-sphinx-docfx-yaml/LICENSE new file mode 100644 index 000000000000..d64569567334 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/packages/gcp-sphinx-docfx-yaml/MANIFEST.in b/packages/gcp-sphinx-docfx-yaml/MANIFEST.in new file mode 100644 index 000000000000..bb37a2723dae --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/MANIFEST.in @@ -0,0 +1 @@ +include *.rst diff --git a/packages/gcp-sphinx-docfx-yaml/README.rst b/packages/gcp-sphinx-docfx-yaml/README.rst new file mode 100644 index 000000000000..61aee5f456ba --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/README.rst @@ -0,0 +1,92 @@ +This is not an officially supported Google product. + +This is a forked version of the original from https://github.com/docascode/sphinx-docfx-yaml. + +Feel free to use this forked repository for personal or experimental use, use the original otherwise. + +Sphinx DocFX YAML +================= + +.. image:: https://travis-ci.org/docascode/sphinx-docfx-yaml.svg?branch=master + :target: https://travis-ci.org/docascode/sphinx-docfx-yaml + +Sphinx DocFX YAML is an exporter for the Sphinx Autodoc module into `DocFX YAML `_. + +You can read the full documentation online at http://sphinx-docfx-yaml.readthedocs.io + +Contents +-------- + +.. toctree:: + :glob: + :maxdepth: 2 + + design + layout + api + +Basic Workflow +-------------- + +* Write RST that includes Python `autodoc `_ +* Render internal doctree into YAML +* Output YAML into output directory + +Install +------- + +First you need to install docfx-yaml: + +.. code:: bash + + pip install sphinx-docfx-yaml + +Then add it to your Sphinx project's ``conf.py``: + +.. code:: python + + # Order matters here. + # The extension must be defined *after* autodoc, + # because it uses a signal that autodoc defines + extensions = ['sphinx.ext.autodoc', 'docfx_yaml.extension'] + +Make sure you are using autodoc in your code somewhere:: + + .. automodule:: foo.bar + +Then build your documentation:: + + make html + +Inside your build directory (``_build/html`` usually), +the ``docfx_yaml`` will contain the YAML files that are output. + +.. Modes + ----- + + There are two output modes that specify the structure of the YAML files. + The first is ``module`` which means that the YAML files will be output in files corresponding to the name of their module. + The second modes is ``rst`` which outputs them in the same structure as the RST files they were defined in. + +Design +------ + +Read more about the design in our :doc:`design`. + +Layout +------ + +This project has a few different pieces at this point. +It's primary goal was to integrate the Azure Python SDK into the docfx tooling. +You can read more about the pieces currently set up in the :doc:`layout`. + + +Napoleon Support +---------------- + +We support ``sphinx.ext.napoleon`` for parsing docstrings in other formats. +Currently all markup that maps to existing Sphinx `info field lists `_ will work, +along with ``Examples``. +In order to pull examples out, +you need the ``napoleon_use_admonition_for_examples`` set to ``True``. + diff --git a/packages/gcp-sphinx-docfx-yaml/appveyor.yml b/packages/gcp-sphinx-docfx-yaml/appveyor.yml new file mode 100644 index 000000000000..93653f855b20 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/appveyor.yml @@ -0,0 +1,41 @@ +# Copyright 2021 Google LLC +# +# 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. + +environment: + matrix: + - PYTHON: "C:/Python27" + +clone_folder: c:\projects\sphinx-docfx-yaml + +install: + # Nuget + - nuget install uref -Source https://www.myget.org/F/docfx/api/v3/index.json -ExcludeVersion -OutputDirectory c:\projects + - nuget install docfx.console -Source https://www.myget.org/F/docfx/api/v3/index.json -ExcludeVersion -OutputDirectory c:\projects + # Python + - ps: (new-object net.webclient).DownloadFile('https://bootstrap.pypa.io/get-pip.py', 'C:/get-pip.py') + - "%PYTHON%/python.exe C:/get-pip.py" + - "%PYTHON%/Scripts/pip.exe --version" + - "%PYTHON%/Scripts/pip.exe -q -q -q install tox sphinx msrest msrestazure sphinx_rtd_theme ." + +build_script: + - cd c:\projects\sphinx-docfx-yaml\docs + - "git clone https://github.com/ericholscher/azure-sdk-for-python/" + - cd azure-sdk-for-python + - python setup.py -q install + - cd doc + - "%PYTHON%/Scripts/sphinx-build.exe -b html -d _build/doctrees . _build/html" + - c:\projects\docfx.console\tools\docfx.exe build -t c:\projects\uref\content + +artifacts: + - path: 'docs/azure-sdk-for-python/doc/' diff --git a/packages/gcp-sphinx-docfx-yaml/debug.py b/packages/gcp-sphinx-docfx-yaml/debug.py new file mode 100644 index 000000000000..48efa2b282de --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/debug.py @@ -0,0 +1,41 @@ +# Copyright 2021 Google LLC +# +# 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. + +import os +import shutil +import unittest +from contextlib import contextmanager +from sphinx.application import Sphinx + +@contextmanager +def sphinx_build(test_dir): + os.chdir('tests/{0}'.format(test_dir)) + + try: + app = Sphinx( + srcdir='doc', + confdir='doc', + outdir='_build/yaml', + doctreedir='_build/.doctrees', + buildername='html', + ) + app.build(force_all=True) + yield + finally: + # shutil.rmtree('_build') + os.chdir('../..') + +if __name__ == '__main__': + with sphinx_build('example'): + print('Debug finished.') diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/__init__.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/__init__.py new file mode 100644 index 000000000000..690df65fb6bc --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/__init__.py @@ -0,0 +1,14 @@ +# Copyright 2021 Google LLC +# +# 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. + diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/directives.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/directives.py new file mode 100644 index 000000000000..3b10c4b761a8 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/directives.py @@ -0,0 +1,46 @@ +# Copyright 2021 Google LLC +# +# 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. + +# coding: utf-8 + +""" +This module is used to add extra supported directives to sphinx. +""" + +from docutils.parsers.rst.directives.admonitions import BaseAdmonition +from docutils.parsers.rst import Directive +from docutils import nodes + +from .nodes import remarks + + +class RemarksDirective(BaseAdmonition): + """ + Class to enable remarks directive. + """ + node_class = remarks + +class TodoDirective(Directive): + """ + Class to ignore todo directive. + """ + + # Enable content in the directive + has_content = True + + # Directive class must override run function. + def run(self): + return_nodes = [] + + return return_nodes diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py new file mode 100644 index 000000000000..04c108130354 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -0,0 +1,865 @@ +# Copyright 2021 Google LLC +# +# 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. + +# -*- coding: utf-8 -*- +""" +Sphinx DocFX YAML Top-level Extension. + +This extension allows you to automagically generate DocFX YAML from your Python AutoAPI docs. +""" +import os +import inspect +import re +from functools import partial +from itertools import zip_longest + +try: + from subprocess import getoutput +except ImportError: + from commands import getoutput + +from yaml import safe_dump as dump + +from sphinx.util.console import darkgreen, bold +from sphinx.util import ensuredir +from sphinx.errors import ExtensionError +from sphinx.util.nodes import make_refnode + +from .utils import transform_node, transform_string +from .settings import API_ROOT +from .monkeypatch import patch_docfields +from .directives import RemarksDirective, TodoDirective +from .nodes import remarks + + +class Bcolors: + HEADER = '\033[95m' + OKBLUE = '\033[94m' + OKGREEN = '\033[92m' + WARNING = '\033[93m' + FAIL = '\033[91m' + ENDC = '\033[0m' + BOLD = '\033[1m' + UNDERLINE = '\033[4m' + + +try: + from conf import * +except ImportError: + print(Bcolors.FAIL + 'can not import conf.py! ' + 'you should have a conf.py in working project folder' + Bcolors.ENDC) + +METHOD = 'method' +FUNCTION = 'function' +MODULE = 'module' +CLASS = 'class' +EXCEPTION = 'exception' +ATTRIBUTE = 'attribute' +REFMETHOD = 'meth' +REFFUNCTION = 'func' +INITPY = '__init__.py' +REF_PATTERN = ':(py:)?(func|class|meth|mod|ref):`~?[a-zA-Z_\.<> ]*?`' + + +def build_init(app): + """ + Set up environment data + """ + if not app.config.docfx_yaml_output: + raise ExtensionError('You must configure an docfx_yaml_output setting') + + # This stores YAML object for modules + app.env.docfx_yaml_modules = {} + # This stores YAML object for classes + app.env.docfx_yaml_classes = {} + # This stores YAML object for functions + app.env.docfx_yaml_functions = {} + # This store the data extracted from the info fields + app.env.docfx_info_field_data = {} + # This stores signature for functions and methods + app.env.docfx_signature_funcs_methods = {} + # This store the uid-type mapping info + app.env.docfx_info_uid_types = {} + + remote = getoutput('git remote -v') + + try: + app.env.docfx_remote = remote.split('\t')[1].split(' ')[0] + except Exception: + app.env.docfx_remote = None + try: + app.env.docfx_branch = getoutput('git rev-parse --abbrev-ref HEAD').strip() + except Exception: + app.env.docfx_branch = None + + try: + app.env.docfx_root = getoutput('git rev-parse --show-toplevel').strip() + except Exception: + app.env.docfx_root = None + + patch_docfields(app) + + app.docfx_transform_node = partial(transform_node, app) + app.docfx_transform_string = partial(transform_string, app) + + +def _get_cls_module(_type, name): + """ + Get the class and module name for an object + + .. _sending: + + Foo + + """ + cls = None + if _type in [FUNCTION, EXCEPTION]: + module = '.'.join(name.split('.')[:-1]) + elif _type in [METHOD, ATTRIBUTE]: + cls = '.'.join(name.split('.')[:-1]) + module = '.'.join(name.split('.')[:-2]) + elif _type in [CLASS]: + cls = name + module = '.'.join(name.split('.')[:-1]) + elif _type in [MODULE]: + module = name + else: + return (None, None) + return (cls, module) + + +def _create_reference(datam, parent, is_external=False): + return { + 'uid': datam['uid'], + 'parent': parent, + 'isExternal': is_external, + 'name': datam['name'], + 'fullName': datam['fullName'], + } + + +def _refact_example_in_module_summary(lines): + new_lines = [] + block_lines = [] + example_block_flag = False + for line in lines: + if line.startswith('.. admonition:: Example'): + example_block_flag = True + line = '### Example\n\n' + new_lines.append(line) + elif example_block_flag and len(line) != 0 and not line.startswith(' '): + example_block_flag = False + new_lines.append(''.join(block_lines)) + new_lines.append(line) + block_lines[:] = [] + elif example_block_flag: + if line == ' ': # origianl line is blank line ('\n'). + line = '\n' # after outer ['\n'.join] operation, + # this '\n' will be appended to previous line then. BINGO! + elif line.startswith(' '): + # will be indented by 4 spaces according to yml block syntax. + # https://learnxinyminutes.com/docs/yaml/ + line = ' ' + line + '\n' + block_lines.append(line) + + else: + new_lines.append(line) + return new_lines + + +def _resolve_reference_in_module_summary(lines): + new_lines = [] + for line in lines: + matched_objs = list(re.finditer(REF_PATTERN, line)) + new_line = line + for matched_obj in matched_objs: + start = matched_obj.start() + end = matched_obj.end() + matched_str = line[start:end] + if '<' in matched_str and '>' in matched_str: + # match string like ':func:`***<***>`' + index = matched_str.index('<') + ref_name = matched_str[index+1:-2] + else: + # match string like ':func:`~***`' or ':func:`***`' + index = matched_str.index('~') if '~' in matched_str else matched_str.index('`') + ref_name = matched_str[index+1:-1] + new_line = new_line.replace(matched_str, ''.format(ref_name)) + new_lines.append(new_line) + return new_lines + + +def enumerate_extract_signature(doc, max_args=20): + el = "((?P[*a-zA-Z_]+) *(?P: *[a-zA-Z_.]+)? *(?P= *[^ ]+?)?)" + els = [el % (i, i, i) for i in range(0, max_args)] + par = els[0] + "?" + "".join(["( *, *" + e + ")?" for e in els[1:]]) + exp = "(?P[a-zA-Z_]+) *[(] *(?P{0}) *[)]".format(par) + reg = re.compile(exp) + for func in reg.finditer(doc.replace("\n", " ")): + yield func + + +def enumerate_cleaned_signature(doc, max_args=20): + for sig in enumerate_extract_signature(doc, max_args=max_args): + dic = sig.groupdict() + name = sig["name"] + args = [] + for i in range(0, max_args): + p = dic.get('p%d' % i, None) + if p is None: + break + d = dic.get('d%d' % i, None) + if d is None: + args.append(p) + else: + args.append("%s%s" % (p, d)) + yield "{0}({1})".format(name, ", ".join(args)) + + +def _extract_signature(obj_sig): + try: + signature = inspect.signature(obj_sig) + parameters = signature.parameters + except TypeError as e: + mes = "[docfx] unable to get signature of '{0}' - {1}.".format( + object_name, str(e).replace("\n", "\\n")) + signature = None + parameters = None + except ValueError as e: + # Backup plan, no __text_signature__, this happen + # when a function was created with pybind11. + doc = obj_sig.__doc__ + sigs = set(enumerate_cleaned_signature(doc)) + if len(sigs) == 0: + mes = "[docfx] unable to get signature of '{0}' - {1}.".format( + object_name, str(e).replace("\n", "\\n")) + signature = None + parameters = None + elif len(sigs) > 1: + mes = "[docfx] too many signatures for '{0}' - {1} - {2}.".format( + object_name, str(e).replace("\n", "\\n"), " *** ".join(sigs)) + signature = None + parameters = None + else: + try: + signature = inspect._signature_fromstr( + inspect.Signature, obj_sig, list(sigs)[0]) + parameters = signature.parameters + except TypeError as e: + mes = "[docfx] unable to get signature of '{0}' - {1}.".format( + object_name, str(e).replace("\n", "\\n")) + signature = None + parameters = None + return signature, parameters + + +def _create_datam(app, cls, module, name, _type, obj, lines=None): + """ + Build the data structure for an autodoc class + """ + + def _update_friendly_package_name(path): + package_name_index = path.find(os.sep) + package_name = path[:package_name_index] + if len(package_name) > 0: + try: + for name in namespace_package_dict: + if re.match(name, package_name) is not None: + package_name = namespace_package_dict[name] + path = os.path.join(package_name, path[package_name_index + 1:]) + return path + + except NameError: + pass + + return path + + + if lines is None: + lines = [] + short_name = name.split('.')[-1] + args = [] + try: + if _type in [METHOD, FUNCTION]: + argspec = inspect.getfullargspec(obj) # noqa + for arg in argspec.args: + args.append({'id': arg}) + if argspec.defaults: + for count, default in enumerate(argspec.defaults): + cut_count = len(argspec.defaults) + # Only add defaultValue when str(default) doesn't contain object address string(object at 0x) + # inspect.getargspec method will return wrong defaults which contain object address for some default values, like sys.stdout + # Match the defaults with the count + if 'object at 0x' not in str(default): + args[len(args) - cut_count + count]['defaultValue'] = str(default) + except Exception as e: + print("Can't get argspec for {}: {}. Exception: {}".format(type(obj), name, e)) + + if name in app.env.docfx_signature_funcs_methods: + sig = app.env.docfx_signature_funcs_methods[name] + else: + sig = None + + try: + full_path = inspect.getsourcefile(obj) + if full_path is None: # Meet a .pyd file + raise TypeError() + # Sub git repo path + path = full_path.replace(app.env.docfx_root, '') + # Support global file imports, if it's installed already + import_path = os.path.dirname(inspect.getfile(os)) + path = path.replace(os.path.join(import_path, 'site-packages'), '') + path = path.replace(import_path, '') + + # Make relative + path = path.replace(os.sep, '', 1) + start_line = inspect.getsourcelines(obj)[1] + + path = _update_friendly_package_name(path) + + # Get folder name from conf.py + path = os.path.join(app.config.folder, path) + + # append relative path defined in conf.py (in case of "binding python" project) + try: + source_prefix # does source_prefix exist in the current namespace + path = source_prefix + path + except NameError: + pass + + except (TypeError, OSError): + print("Can't inspect type {}: {}".format(type(obj), name)) + path = None + start_line = None + + datam = { + 'module': module, + 'uid': name, + 'type': _type, + 'name': short_name, + 'fullName': name, + 'source': { + 'remote': { + 'path': path, + 'branch': app.env.docfx_branch, + 'repo': app.env.docfx_remote, + }, + 'id': short_name, + 'path': path, + 'startLine': start_line, + }, + 'langs': ['python'], + } + + # Only add summary to parts of the code that we don't get it from the monkeypatch + if _type == MODULE: + lines = _resolve_reference_in_module_summary(lines) + summary = app.docfx_transform_string('\n'.join(_refact_example_in_module_summary(lines))) + if summary: + datam['summary'] = summary.strip(" \n\r\r") + + if args or sig: + datam['syntax'] = {} + if args: + datam['syntax']['parameters'] = args + if sig: + datam['syntax']['content'] = sig + if cls: + datam[CLASS] = cls + if _type in [CLASS, MODULE]: + datam['children'] = [] + datam['references'] = [] + + if _type in [FUNCTION, METHOD]: + datam['name'] = app.env.docfx_signature_funcs_methods.get(name, datam['name']) + + return datam + + +def _fullname(obj): + """ + Get the fullname from a Python object + """ + return obj.__module__ + "." + obj.__name__ + + +def process_docstring(app, _type, name, obj, options, lines): + """ + This function takes the docstring and indexes it into memory. + """ + # Use exception as class + + if _type == EXCEPTION: + _type = CLASS + + cls, module = _get_cls_module(_type, name) + if not module: + print('Unknown Type: %s' % _type) + return None + + datam = _create_datam(app, cls, module, name, _type, obj, lines) + + if _type == MODULE: + if module not in app.env.docfx_yaml_modules: + app.env.docfx_yaml_modules[module] = [datam] + else: + app.env.docfx_yaml_modules[module].append(datam) + + if _type == CLASS: + if cls not in app.env.docfx_yaml_classes: + app.env.docfx_yaml_classes[cls] = [datam] + else: + app.env.docfx_yaml_classes[cls].append(datam) + + if _type == FUNCTION and app.config.autodoc_functions: + if datam['uid'] is None: + raise ValueError("Issue with {0} (name={1})".format(datam, name)) + if cls is None: + cls = name + if cls is None: + raise ValueError("cls is None for name='{1}' {0}".format(datam, name)) + if cls not in app.env.docfx_yaml_functions: + app.env.docfx_yaml_functions[cls] = [datam] + else: + app.env.docfx_yaml_functions[cls].append(datam) + + insert_inheritance(app, _type, obj, datam) + insert_children_on_module(app, _type, datam) + insert_children_on_class(app, _type, datam) + insert_children_on_function(app, _type, datam) + + app.env.docfx_info_uid_types[datam['uid']] = _type + + +def process_signature(app, _type, name, obj, options, signature, return_annotation): + if signature: + short_name = name.split('.')[-1] + signature = short_name + signature + app.env.docfx_signature_funcs_methods[name] = signature + + +def insert_inheritance(app, _type, obj, datam): + + def collect_inheritance(base, to_add): + for new_base in base.__bases__: + new_add = {'type': _fullname(new_base)} + collect_inheritance(new_base, new_add) + if 'inheritance' not in to_add: + to_add['inheritance'] = [] + to_add['inheritance'].append(new_add) + + if hasattr(obj, '__bases__'): + if 'inheritance' not in datam: + datam['inheritance'] = [] + for base in obj.__bases__: + to_add = {'type': _fullname(base)} + collect_inheritance(base, to_add) + datam['inheritance'].append(to_add) + + +def insert_children_on_module(app, _type, datam): + """ + Insert children of a specific module + """ + + if MODULE not in datam or datam[MODULE] not in app.env.docfx_yaml_modules: + return + insert_module = app.env.docfx_yaml_modules[datam[MODULE]] + # Find the module which the datam belongs to + for obj in insert_module: + # Add standardlone function to global class + if _type in [FUNCTION] and \ + obj['type'] == MODULE and \ + obj[MODULE] == datam[MODULE]: + obj['children'].append(datam['uid']) + + # If it is a function, add this to its module. No need for class and module since this is + # done before calling this function. + insert_module.append(datam) + + obj['references'].append(_create_reference(datam, parent=obj['uid'])) + break + # Add classes & exceptions to module + if _type in [CLASS, EXCEPTION] and \ + obj['type'] == MODULE and \ + obj[MODULE] == datam[MODULE]: + obj['children'].append(datam['uid']) + obj['references'].append(_create_reference(datam, parent=obj['uid'])) + break + + if _type in [MODULE]: # Make sure datam is a module. + # Add this module(datam) to parent module node + if datam[MODULE].count('.') >= 1: + parent_module_name = '.'.join(datam[MODULE].split('.')[:-1]) + + if parent_module_name not in app.env.docfx_yaml_modules: + return + + insert_module = app.env.docfx_yaml_modules[parent_module_name] + + for obj in insert_module: + if obj['type'] == MODULE and obj[MODULE] == parent_module_name: + obj['children'].append(datam['uid']) + obj['references'].append(_create_reference(datam, parent=obj['uid'])) + break + + # Add datam's children modules to it. Based on Python's passing by reference. + # If passing by reference would be changed in python's future release. + # Time complex: O(N^2) + for module, module_contents in app.env.docfx_yaml_modules.items(): + if module != datam['uid'] and \ + module[:module.rfind('.')] == datam['uid']: # Current module is submodule/subpackage of datam + for obj in module_contents: # Traverse module's contents to find the module itself. + if obj['type'] == MODULE and obj['uid'] == module: + datam['children'].append(module) + datam['references'].append(_create_reference(obj, parent=module)) + break + + +def insert_children_on_class(app, _type, datam): + """ + Insert children of a specific class + """ + if CLASS not in datam: + return + + insert_class = app.env.docfx_yaml_classes[datam[CLASS]] + # Find the class which the datam belongs to + for obj in insert_class: + if obj['type'] != CLASS: + continue + # Add methods & attributes to class + if _type in [METHOD, ATTRIBUTE] and \ + obj[CLASS] == datam[CLASS]: + obj['children'].append(datam['uid']) + obj['references'].append(_create_reference(datam, parent=obj['uid'])) + insert_class.append(datam) + + +def insert_children_on_function(app, _type, datam): + """ + Insert children of a specific class + """ + if FUNCTION not in datam: + return + + insert_functions = app.env.docfx_yaml_functions[datam[FUNCTION]] + insert_functions.append(datam) + + +def build_finished(app, exception): + """ + Output YAML on the file system. + """ + def find_node_in_toc_tree(toc_yaml, to_add_node): + for module in toc_yaml: + if module['name'] == to_add_node: + return module + + if 'items' in module: + items = module['items'] + found_module = find_node_in_toc_tree(items, to_add_node) + if found_module != None: + return found_module + + return None + + def convert_module_to_package_if_needed(obj): + if 'source' in obj and 'path' in obj['source'] and obj['source']['path']: + if obj['source']['path'].endswith(INITPY): + obj['type'] = 'package' + return + + for child_uid in obj['children']: + if child_uid in app.env.docfx_info_uid_types: + child_uid_type = app.env.docfx_info_uid_types[child_uid] + + if child_uid_type == MODULE: + obj['type'] = 'package' + return + + + normalized_outdir = os.path.normpath(os.path.join( + app.builder.outdir, # Output Directory for Builder + API_ROOT, + )) + ensuredir(normalized_outdir) + + toc_yaml = [] + # Used to record filenames dumped to avoid confliction + # caused by Windows case insensitive file system + file_name_set = set() + + # Order matters here, we need modules before lower level classes, + # so that we can make sure to inject the TOC properly + for data_set in (app.env.docfx_yaml_modules, + app.env.docfx_yaml_classes, + app.env.docfx_yaml_functions): # noqa + + for uid, yaml_data in iter(sorted(data_set.items())): + if not uid: + # Skip objects without a module + continue + + references = [] + + # Merge module data with class data + for obj in yaml_data: + arg_params = obj.get('syntax', {}).get('parameters', []) + if(len(arg_params) > 0 and 'id' in arg_params[0] and arg_params[0]['id'] == 'self'): + # Support having `self` as an arg param, but not documented + arg_params = arg_params[1:] + obj['syntax']['parameters'] = arg_params + if obj['uid'] in app.env.docfx_info_field_data and \ + obj['type'] == app.env.docfx_info_field_data[obj['uid']]['type']: + # Avoid entities with same uid and diff type. + del(app.env.docfx_info_field_data[obj['uid']]['type']) # Delete `type` temporarily + if 'syntax' not in obj: + obj['syntax'] = {} + merged_params = [] + if 'parameters' in app.env.docfx_info_field_data[obj['uid']]: + doc_params = app.env.docfx_info_field_data[obj['uid']].get('parameters', []) + if arg_params and doc_params: + if len(arg_params) - len(doc_params) > 0: + app.warn( + "Documented params don't match size of params:" + " {}".format(obj['uid'])) + # Zip 2 param lists until the long one is exhausted + for args, docs in zip_longest(arg_params, doc_params, fillvalue={}): + if len(args) == 0: + merged_params.append(docs) + else: + args.update(docs) + merged_params.append(args) + obj['syntax'].update(app.env.docfx_info_field_data[obj['uid']]) + if merged_params: + obj['syntax']['parameters'] = merged_params + + if 'parameters' in obj['syntax'] and obj['type'] == 'method': + for args in obj['syntax']['parameters']: + if 'isRequired' not in args and 'defaultValue' not in args: + args['isRequired'] = True + + # Raise up summary + if 'summary' in obj['syntax'] and obj['syntax']['summary']: + obj['summary'] = obj['syntax'].pop('summary').strip(" \n\r\r") + + # Raise up remarks + if 'remarks' in obj['syntax'] and obj['syntax']['remarks']: + obj['remarks'] = obj['syntax'].pop('remarks') + + # Raise up seealso + if 'seealso' in obj['syntax'] and obj['syntax']['seealso']: + obj['seealsoContent'] = obj['syntax'].pop('seealso') + + # Raise up example + if 'example' in obj['syntax'] and obj['syntax']['example']: + obj.setdefault('example', []).append(obj['syntax'].pop('example')) + + # Raise up exceptions + if 'exceptions' in obj['syntax'] and obj['syntax']['exceptions']: + obj['exceptions'] = obj['syntax'].pop('exceptions') + + # Raise up references + if 'references' in obj['syntax'] and obj['syntax']['references']: + obj.setdefault('references', []).extend(obj['syntax'].pop('references')) + + # add content of temp list 'added_attribute' to children and yaml_data + if 'added_attribute' in obj['syntax'] and obj['syntax']['added_attribute']: + added_attribute = obj['syntax'].pop('added_attribute') + for attrData in added_attribute: + existed_Data = next((n for n in yaml_data if n['uid'] == attrData['uid']), None) + if existed_Data: + # Update data for already existed one which has attribute comment in source file + existed_Data.update(attrData) + else: + obj.get('children', []).append(attrData['uid']) + yaml_data.append(attrData) + if 'class' in attrData: + # Get parent for attrData of Non enum class + parent = attrData['class'] + else: + # Get parent for attrData of enum class + parent = attrData['parent'] + obj['references'].append(_create_reference(attrData, parent)) + app.env.docfx_info_field_data[obj['uid']]['type'] = obj['type'] # Revert `type` for other objects to use + + if 'references' in obj: + # Ensure that references have no duplicate ref + ref_uids = [r['uid'] for r in references] + for ref_obj in obj['references']: + if ref_obj['uid'] not in ref_uids: + references.append(ref_obj) + obj.pop('references') + + if obj['type'] == 'module': + convert_module_to_package_if_needed(obj) + + if obj['type'] == 'method': + obj['namewithoutparameters'] = obj['source']['id'] + + # To distinguish distribution package and import package + if obj.get('type', '') == 'package' and obj.get('kind', '') != 'distribution': + obj['kind'] = 'import' + + try: + if remove_inheritance_for_notfound_class: + if 'inheritance' in obj: + python_sdk_name = obj['uid'].split('.')[0] + obj['inheritance'] = [n for n in obj['inheritance'] if not n['type'].startswith(python_sdk_name) or + n['type'] in app.env.docfx_info_uid_types] + if not obj['inheritance']: + obj.pop('inheritance') + + except NameError: + pass + + if 'source' in obj and (not obj['source']['remote']['repo'] or \ + obj['source']['remote']['repo'] == 'https://apidrop.visualstudio.com/Content%20CI/_git/ReferenceAutomation'): + del(obj['source']) + + # Output file + if uid.lower() in file_name_set: + filename = uid + "(%s)" % app.env.docfx_info_uid_types[uid] + else: + filename = uid + + out_file = os.path.join(normalized_outdir, '%s.yml' % filename) + ensuredir(os.path.dirname(out_file)) + if app.verbosity >= 1: + app.info(bold('[docfx_yaml] ') + darkgreen('Outputting %s' % filename)) + + with open(out_file, 'w') as out_file_obj: + out_file_obj.write('### YamlMime:UniversalReference\n') + try: + dump( + { + 'items': yaml_data, + 'references': references, + 'api_name': [], # Hack around docfx YAML + }, + out_file_obj, + default_flow_style=False + ) + except Exception as e: + raise ValueError("Unable to dump object\n{0}".format(yaml_data)) from e + + file_name_set.add(filename) + + # Build nested TOC + if uid.count('.') >= 1: + parent_level = '.'.join(uid.split('.')[:-1]) + found_node = find_node_in_toc_tree(toc_yaml, parent_level) + + if found_node: + found_node.pop('uid', 'No uid found') + found_node.setdefault('items', [{'name': 'Overview', 'uid': parent_level}]).append({'name': uid, 'uid': uid}) + else: + toc_yaml.append({'name': uid, 'uid': uid}) + + else: + toc_yaml.append({'name': uid, 'uid': uid}) + + if len(toc_yaml) == 0: + raise RuntimeError("No documentation for this module.") + + toc_file = os.path.join(normalized_outdir, 'toc.yml') + with open(toc_file, 'w') as writable: + writable.write( + dump( + [{ + 'name': app.config.project, + 'items': [{'name': 'Overview', 'uid': 'project-' + app.config.project}] + toc_yaml + }], + default_flow_style=False, + ) + ) + + index_file = os.path.join(normalized_outdir, 'index.yml') + index_children = [] + index_references = [] + for item in toc_yaml: + index_children.append(item.get('name', '')) + index_references.append({ + 'uid': item.get('name', ''), + 'name': item.get('name', ''), + 'fullname': item.get('name', ''), + 'isExternal': False + }) + with open(index_file, 'w') as index_file_obj: + index_file_obj.write('### YamlMime:UniversalReference\n') + dump( + { + 'items': [{ + 'uid': 'project-' + app.config.project, + 'name': app.config.project, + 'fullName': app.config.project, + 'langs': ['python'], + 'type': 'package', + 'kind': 'distribution', + 'summary': '', + 'children': index_children + }], + 'references': index_references + }, + index_file_obj, + default_flow_style=False + ) + + +def missing_reference(app, env, node, contnode): + reftarget = '' + refdoc = '' + reftype = '' + module = '' + if 'refdomain' in node.attributes and node.attributes['refdomain'] == 'py': + reftarget = node['reftarget'] + reftype = node['reftype'] + if 'refdoc' in node: + refdoc = node['refdoc'] + if 'py:module' in node: + module = node['py:module'] + + #Refactor reftarget to fullname if it is a short name + if reftype in [CLASS, REFFUNCTION, REFMETHOD] and module and '.' not in reftarget: + if reftype in [CLASS, REFFUNCTION]: + fields = (module, reftarget) + else: + fields = (module, node['py:class'], reftarget) + reftarget = '.'.join(field for field in fields if field is not None) + + return make_refnode(app.builder, refdoc, reftarget, '', contnode) + + +def setup(app): + """ + Plugin init for our Sphinx extension. + + Args: + app (Application): The Sphinx application instance + + """ + + app.add_node(remarks, html = (remarks.visit_remarks, remarks.depart_remarks)) + app.add_directive('remarks', RemarksDirective) + app.add_directive('todo', TodoDirective) + + app.connect('builder-inited', build_init) + app.connect('autodoc-process-docstring', process_docstring) + app.connect('autodoc-process-signature', process_signature) + app.connect('build-finished', build_finished) + app.connect('missing-reference', missing_reference) + app.add_config_value('docfx_yaml_output', API_ROOT, 'html') + app.add_config_value('folder', '', 'html') + app.add_config_value('autodoc_functions', False, 'env') diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extract_nodes.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extract_nodes.py new file mode 100644 index 000000000000..cf48bb296a72 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extract_nodes.py @@ -0,0 +1,175 @@ +# Copyright 2021 Google LLC +# +# 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. + +""" +**DEPRECATED** + +This was an approach that pulls domain data from doctree. + +This approach will work for non-autodoc domains. +However, +the approach used in this extension is easiest for autodoc. + +In order to build the approach going forward, +a bit more work needs to be done to pull docstrings in raw format. +""" + +from docutils import nodes +from sphinx.util.console import bold, red +from sphinx.util.docfields import _is_single_paragraph +from sphinx import addnodes + +from .utils import _get_desc_data + +TITLE_MAP = { + 'Returns': 'return', + 'Return type': 'return_type', + 'Raises': 'raises', + 'Parameters': 'params', +} + + +def doctree_resolved(app, doctree, docname): + """ + Render out the YAML from the Sphinx domain objects + """ + yaml_data, yaml_modules = extract_yaml(app, doctree, ignore_patterns=None) + extract_info_lists(app, doctree) + # if yaml_data: + # app.env.docfx_yaml_data[docname] = yaml_data + # if yaml_modules: + # for module in yaml_modules: + # app.env.docfx_yaml_modules[module] = yaml_modules[module] + + +def _get_full_data(node): + data = {} + parent_desc = node.parent.parent + name, uid = _get_desc_data(parent_desc) + if not name: + return + + for field in node: + fieldname, fieldbody = field + try: + # split into field type and argument + fieldtype, _ = fieldname.astext().split(None, 1) + except ValueError: + # maybe an argument-less field type? + fieldtype = fieldname.astext() + + # collect the content, trying not to keep unnecessary paragraphs + if _is_single_paragraph(fieldbody): + content = fieldbody.children[0].children + else: + content = fieldbody.children + + data.setdefault(uid, {}) + + if fieldtype == 'Returns': + for child in content: + ret_data = child.astext() + data[uid].setdefault(fieldtype, []).append(ret_data) + + if fieldtype == 'Raises': + for child in content: + ret_data = child.astext() + data[uid].setdefault(fieldtype, []).append(ret_data) + return data + + +def extract_info_lists(app, doctree): + data = [] + + for node in doctree.traverse(nodes.field_list): + data.append(_get_full_data(node)) + + print(data) + + +def extract_yaml(app, doctree, ignore_patterns): + """ + Iterate over all Python domain objects and output YAML + """ + items = [] + modules = {} + + for desc_node in doctree.traverse(addnodes.desc): + if desc_node.attributes['domain'] != 'py': + app.info(bold('[docfx_yaml] ') + red( + 'Skipping Domain Object (%s)' % desc_node.attributes['domain'] + )) + continue + + module = desc_node[0].attributes['module'] + + if not module: + app.info(bold('[docfx_yaml] ') + red( + 'Skipping object with no module' + )) + continue + + if module not in modules: + modules[module] = [{ + 'module': str(module), + 'uid': str(module), + 'type': 'Namespace', + 'type': 'module', + 'name': str(module), + 'children': [] + }] + + _type = desc_node.attributes['objtype'] + full_name = desc_node[0].attributes['fullname'] + try: + uid = desc_node[0].attributes['ids'][0] + except Exception: + uid = '{module}.{full_name}'.format(module=module, full_name=full_name) + print('Non-standard id: %s' % uid) + name = desc_node[0].attributes['names'][0] + source = desc_node[0].source + try: + summary = desc_node[1][0].astext() + except (KeyError, IndexError): + summary = '' + + try: + args = [arg.strip() for arg in desc_node[0][3].astext().split(',')] + except Exception: + args = [] + + if args: + full_name += "({args})".format(args=', '.join(args)) + + datam = { + 'module': str(module), + 'uid': uid, + 'type': _type, + 'name': name, + 'fullName': full_name, + 'summary': summary, + 'rst_source': source, + } + + if _type == 'method': + datam['class'] = '.'.join(name.split('.')[:-1]) + if _type == 'class': + datam['children'] = [] + + # insert_children(_type, datam, modules) + items.append(datam) + + modules[module].append(datam) + + return (items, modules) diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/monkeypatch.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/monkeypatch.py new file mode 100644 index 000000000000..1a54399fbfa1 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/monkeypatch.py @@ -0,0 +1,459 @@ +# Copyright 2021 Google LLC +# +# 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. + +import re +from docutils import nodes +from functools import partial + +from sphinx.util.docfields import _is_single_paragraph +from sphinx.util import docfields +from sphinx import directives, addnodes +from sphinx import addnodes + +from sphinx.addnodes import desc, desc_signature +from .utils import transform_node as _transform_node +from .nodes import remarks + +TYPE_SEP_PATTERN = '(\[|\]|, |\(|\))' + +def _get_desc_data(node): + assert node.tagname == 'desc' + if node.attributes['domain'] != 'py': + print( + 'Skipping Domain Object (%s)' % node.attributes['domain'] + ) + return None, None + + try: + module = node[0].attributes['module'] + full_name = node[0].attributes['fullname'].split('.')[-1] + except KeyError as e: + print("[docfx_yaml] There maybe some syntax error in docstring near: " + node.astext()) + raise e + + try: + uid = node[0].attributes['ids'][0] + except Exception: + uid = '{module}.{full_name}'.format(module=module, full_name=full_name) + print('Non-standard id: %s' % uid) + return full_name, uid + + +def _is_desc_of_enum_class(node): + assert node.tagname == 'desc_content' + if node[0] and node[0].tagname == 'paragraph' and node[0].astext() == 'Bases: enum.Enum': + return True + + return False + + +def _hacked_transform(typemap, node): + """ + Taken from docfields.py from sphinx. + + This does all the steps around gathering data, + but doesn't actually do the node transformations. + """ + entries = [] + groupindices = {} + types = {} + + # step 1: traverse all fields and collect field types and content + for field in node: + fieldname, fieldbody = field + try: + # split into field type and argument + fieldtype, fieldarg = fieldname.astext().split(None, 1) + except ValueError: + # maybe an argument-less field type? + fieldtype, fieldarg = fieldname.astext(), '' + typedesc, is_typefield = typemap.get(fieldtype, (None, None)) + + # sort out unknown fields + if typedesc is None or typedesc.has_arg != bool(fieldarg): + # either the field name is unknown, or the argument doesn't + # match the spec; capitalize field name and be done with it + new_fieldname = fieldtype[0:1].upper() + fieldtype[1:] + if fieldarg: + new_fieldname += ' ' + fieldarg + fieldname[0] = nodes.Text(new_fieldname) + entries.append(field) + continue + + typename = typedesc.name + + # collect the content, trying not to keep unnecessary paragraphs + if _is_single_paragraph(fieldbody): + content = fieldbody.children[0].children + else: + content = fieldbody.children + + # if the field specifies a type, put it in the types collection + if is_typefield: + # filter out only inline nodes; others will result in invalid + # markup being written out + content = [n for n in content if isinstance(n, nodes.Inline) or + isinstance(n, nodes.Text)] + if content: + types.setdefault(typename, {})[fieldarg] = content + continue + + # also support syntax like ``:param type name:`` + if typedesc.is_typed: + try: + argtype, argname = fieldarg.split(None, 1) + except ValueError: + pass + else: + types.setdefault(typename, {})[argname] = \ + [nodes.Text(argtype)] + fieldarg = argname + + translatable_content = nodes.inline(fieldbody.rawsource, + translatable=True) + translatable_content.source = fieldbody.parent.source + translatable_content.line = fieldbody.parent.line + translatable_content += content + + # grouped entries need to be collected in one entry, while others + # get one entry per field + if typedesc.is_grouped: + if typename in groupindices: + group = entries[groupindices[typename]] + else: + groupindices[typename] = len(entries) + group = [typedesc, []] + entries.append(group) + entry = typedesc.make_entry(fieldarg, [translatable_content]) + group[1].append(entry) + else: + entry = typedesc.make_entry(fieldarg, [translatable_content]) + entries.append([typedesc, entry]) + + return (entries, types) + + +def patch_docfields(app): + """ + Grab syntax data from the Sphinx info fields. + + This is done by monkeypatching into the DocFieldTransformer, + which is what Sphinx uses to transform the docutils ``nodes.field`` + into the sphinx ``docfields.Field`` objects. + + See usage in Sphinx + `here `_. + + This also performs the RST doctree to Markdown transformation on the content, + using the :class:`docfx_yaml.writers.MarkdownWriter`. + """ + + transform_node = partial(_transform_node, app) + + def get_data_structure(entries, types, field_object): + """ + Get a proper docfx YAML data structure from the entries & types + """ + + data = { + 'parameters': [], + 'variables': [], + 'exceptions': [], + 'return': {}, + 'references': [], + } + + def make_param(_id, _description, _type=None, _required=None): + ret = { + 'id': _id, + 'description': _description.strip(" \n\r\t") + } + if _type: + ret['type'] = _type + + if _required is not None: + ret['isRequired'] = _required + + return ret + + def transform_para(para_field): + if isinstance(para_field, addnodes.pending_xref): + return transform_node(para_field) + else: + return para_field.astext() + + def resolve_type(data_type): + # Remove @ ~ and \n for cross reference in parameter/return value type to apply to docfx correctly + data_type = re.sub('[@~\n]', '', data_type) + + # Add references for docfx to resolve ref if type contains TYPE_SEP_PATTERN + _spec_list = [] + _spec_fullnames = re.split(TYPE_SEP_PATTERN, data_type) + + _added_reference = {} + if len(_spec_fullnames) > 1: + _added_reference_name = '' + for _spec_fullname in _spec_fullnames: + if _spec_fullname != '': + _spec = {} + _spec['name'] = _spec_fullname.split('.')[-1] + _spec['fullName'] = _spec_fullname + if re.match(TYPE_SEP_PATTERN, _spec_fullname) is None: + _spec['uid'] = _spec_fullname + _spec_list.append(_spec) + _added_reference_name += _spec['name'] + + _added_reference = { + 'uid': data_type, + 'name': _added_reference_name, + 'fullName': data_type, + 'spec.python': _spec_list + } + + return data_type, _added_reference + + def extract_exception_desc(field_object): + ret = [] + if len(field_object) > 0: + for field in field_object: + if 'field_name' == field[0].tagname and field[0].astext() == 'Raises': + assert field[1].tagname == 'field_body' + field_body = field[1] + + children = [n for n in field_body + if not isinstance(n, nodes.Invisible)] + + for child in children: + if isinstance (child, nodes.paragraph): + pending_xref_index = child.first_child_matching_class(addnodes.pending_xref) + if pending_xref_index is not None: + pending_xref = child[pending_xref_index] + raise_type_index = pending_xref.first_child_matching_class(nodes.literal) + if raise_type_index is not None: + raise_type = pending_xref[raise_type_index] + ret.append({'type': pending_xref['reftarget'], 'desc': raise_type.astext()}) + + return ret + + for entry in entries: + if isinstance(entry, nodes.field): + # pass-through old field + pass + else: + fieldtype, content = entry + fieldtypes = types.get(fieldtype.name, {}) + if fieldtype.name == 'exceptions': + for _type, _description in content: + data['exceptions'].append({ + 'type': _type, + 'description': transform_node(_description[0]).strip(" \n\r\t") + }) + if fieldtype.name == 'returntype': + for returntype_node in content[1]: + returntype_ret = transform_node(returntype_node) + if returntype_ret: + # Support or in returntype + for returntype in re.split('[ \n]or[ \n]', returntype_ret): + returntype, _added_reference = resolve_type(returntype) + if _added_reference: + if len(data['references']) == 0: + data['references'].append(_added_reference) + elif any(r['uid'] != _added_reference['uid'] for r in data['references']): + data['references'].append(_added_reference) + + data['return'].setdefault('type', []).append(returntype) + if fieldtype.name == 'returnvalue': + returnvalue_ret = transform_node(content[1][0]) + if returnvalue_ret: + data['return']['description'] = returnvalue_ret.strip(" \n\r\t") + if fieldtype.name in ['parameter', 'variable', 'keyword']: + for field, node_list in content: + _id = field + _description = transform_node(node_list[0]) + if field in fieldtypes: + _type = u''.join(transform_para(n) for n in fieldtypes[field]) + else: + _type = None + + _para_types = [] + if fieldtype.name == 'parameter' or fieldtype.name == 'keyword': + if _type: + # Support or in parameter type + for _s_type in re.split('[ \n]or[ \n]', _type): + _s_type, _added_reference = resolve_type(_s_type) + if _added_reference: + if len(data['references']) == 0: + data['references'].append(_added_reference) + elif any(r['uid'] != _added_reference['uid'] for r in data['references']): + data['references'].append(_added_reference) + + _para_types.append(_s_type) + + + + _data = make_param(_id=_id, _type=_para_types, _description=_description, _required=False if fieldtype.name == 'keyword' else True) + data['parameters'].append(_data) + + if fieldtype.name == 'variable': + if _type: + # Support or in variable type + for _s_type in re.split('[ \n]or[ \n]', _type): + _s_type, _added_reference = resolve_type(_s_type) + if _added_reference: + if len(data['references']) == 0: + data['references'].append(_added_reference) + elif any(r['uid'] != _added_reference['uid'] for r in data['references']): + data['references'].append(_added_reference) + + _para_types.append(_s_type) + + _data = make_param(_id=_id, _type=_para_types, _description=_description) + data['variables'].append(_data) + + ret_list = extract_exception_desc(field_object) + for ret in ret_list: + # only use type in exceptions + data.setdefault('exceptions', []).append({ + 'type': ret['type'] + }) + + return data + + + class PatchedDocFieldTransformer(docfields.DocFieldTransformer): + + @staticmethod + def type_mapping(type_name): + mapping = { + "staticmethod": "method", + "classmethod": "method", + "exception": "class" + } + + return mapping[type_name] if type_name in mapping else type_name + + def __init__(self, directive): + self.directive = directive + super(PatchedDocFieldTransformer, self).__init__(directive) + + def transform_all(self, node): + """Transform all field list children of a node.""" + # don't traverse, only handle field lists that are immediate children + summary = [] + data = {} + name, uid = _get_desc_data(node.parent) + for child in node: + if isinstance(child, remarks): + remarks_string = transform_node(child) + data['remarks'] = remarks_string + elif isinstance(child, addnodes.desc): + if child.get('desctype') == 'attribute': + attribute_map = {} # Used for detecting duplicated attributes in intermediate data and merge them + + for item in child: + if isinstance(item, desc_signature) and any(isinstance(n, addnodes.desc_annotation) for n in item): + # capture attributes data and cache it + data.setdefault('added_attribute', []) + + item_ids = item.get('ids', ['']) + + if len(item_ids) == 0: # find a node with no 'ids' attribute + curuid = item.get('module', '') + '.' + item.get('fullname', '') + # generate its uid by module and fullname + else: + curuid = item_ids[0] + + if len(curuid) > 0: + parent = curuid[:curuid.rfind('.')] + name = item.children[0].astext() + + if curuid in attribute_map: + if len(item_ids) == 0: # ensure the order of docstring attributes and real attributes is fixed + attribute_map[curuid]['syntax']['content'] += (' ' + item.astext()) + # concat the description of duplicated nodes + else: + attribute_map[curuid]['syntax']['content'] = item.astext() + ' ' + attribute_map[curuid]['syntax']['content'] + else: + if _is_desc_of_enum_class(node): + addedData = { + 'uid': curuid, + 'id': name, + 'parent': parent, + 'langs': ['python'], + 'name': name, + 'fullName': curuid, + 'type': item.parent.get('desctype'), + 'module': item.get('module'), + 'syntax': { + 'content': item.astext(), + 'return': { + 'type': [parent] + } + } + } + else: + addedData = { + 'uid': curuid, + 'class': parent, + 'langs': ['python'], + 'name': name, + 'fullName': curuid, + 'type': 'attribute', + 'module': item.get('module'), + 'syntax': { + 'content': item.astext() + } + } + + attribute_map[curuid] = addedData + else: + raise Exception('ids of node: ' + repr(item) + ' is missing.') + # no ids and no duplicate or uid can not be generated. + if 'added_attribute' in data: + data['added_attribute'].extend(attribute_map.values()) # Add attributes data to a temp list + + # Don't recurse into child nodes + continue + elif isinstance(child, nodes.field_list): + (entries, types) = _hacked_transform(self.typemap, child) + _data = get_data_structure(entries, types, child) + data.update(_data) + elif isinstance(child, addnodes.seealso): + data['seealso'] = transform_node(child) + elif isinstance(child, nodes.admonition) and 'Example' in child[0].astext(): + # Remove the admonition node + child_copy = child.deepcopy() + child_copy.pop(0) + data['example'] = transform_node(child_copy) + else: + content = transform_node(child) + + # skip 'Bases' in summary + if not content.startswith('Bases: '): + summary.append(content) + + if "desctype" in node.parent and node.parent["desctype"] == 'class': + data.pop('exceptions', '') # Make sure class doesn't have 'exceptions' field. + + if summary: + data['summary'] = '\n'.join(summary) + # Don't include empty data + for key, val in data.copy().items(): + if not val: + del data[key] + data['type'] = PatchedDocFieldTransformer.type_mapping(node.parent["desctype"]) if "desctype" in node.parent else 'unknown' + self.directive.env.docfx_info_field_data[uid] = data + super(PatchedDocFieldTransformer, self).transform_all(node) + + directives.DocFieldTransformer = PatchedDocFieldTransformer diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/nodes.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/nodes.py new file mode 100644 index 000000000000..c61b99fe63fb --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/nodes.py @@ -0,0 +1,34 @@ +# Copyright 2021 Google LLC +# +# 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. + +# coding: utf-8 + +""" +This module is used to add extra supported nodes to sphinx. +""" + +from docutils import nodes + +class remarks(nodes.paragraph, nodes.Element): + """ + New node for remarks messages. + """ + + @staticmethod + def visit_remarks(self, node): + self.visit_paragraph(node) + + @staticmethod + def depart_remarks(self, node): + self.depart_paragraph(node) diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/settings.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/settings.py new file mode 100644 index 000000000000..2fb3d8382379 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/settings.py @@ -0,0 +1,23 @@ +# Copyright 2021 Google LLC +# +# 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. + +""" +Basic settings. You shouldn't need to touch this. +""" + +import os + + +SITE_ROOT = os.path.dirname(os.path.realpath(__file__)) +API_ROOT = 'docfx_yaml' diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/utils.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/utils.py new file mode 100644 index 000000000000..9bc8f88b3e1b --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/utils.py @@ -0,0 +1,56 @@ +# Copyright 2021 Google LLC +# +# 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. + +import re +from docutils.io import StringOutput +from docutils.utils import new_document +from docutils import nodes +from inspect import signature +from collections import namedtuple + +from .writer import MarkdownWriter as Writer + + +def slugify(value): + """ + Converts to lowercase, removes non-word characters (alphanumerics and + underscores) and converts spaces to hyphens. Also strips leading and + trailing whitespace. + + # From Django + """ + value = re.sub('[^\w\s-]', '', value).strip() + return re.sub('[-\s]+', '-', value) + + +def transform_string(app, string): + ret = [] + for para in string.split('\n\n'): + tmp = nodes.paragraph(para, para) + ret.append(transform_node(app, tmp)) + return '\n\n'.join(ret) + + +def transform_node(app, node): + destination = StringOutput(encoding='utf-8') + doc = new_document(b'') + doc.append(node) + + # Resolve refs + doc['docname'] = 'inmemory' + app.env.resolve_references(doctree=doc, fromdocname='inmemory', builder=app.builder) + + writer = Writer(app.builder) + writer.write(doc, destination) + return destination.destination.decode('utf-8') diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/writer.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/writer.py new file mode 100644 index 000000000000..bf63133efbb5 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/writer.py @@ -0,0 +1,1129 @@ +# Copyright 2021 Google LLC +# +# 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. + +# -*- coding: utf-8 -*- +""" +This is a forked version of the Sphinx text writer. + +It outputs DocFX Markdown from the docutils doctree, +allowing us to transform transformed RST in memory to markdown. + +It is certainly **not** complete, +and only implement as much logic as would be expected in normal docstring usage. +It is not intended to be a generic rst->markdown converter, +because rst contains myriad structures that markdown can't represent. +""" + +import json +import os +import re +import sys +import textwrap +from itertools import groupby + + +from docutils import nodes, writers +from docutils.utils import column_width +from docutils.nodes import TextElement, Text, Node + +from sphinx import addnodes +from sphinx.locale import admonitionlabels + +from .nodes import remarks + +class bcolors: + HEADER = '\033[95m' + OKBLUE = '\033[94m' + OKGREEN = '\033[92m' + WARNING = '\033[93m' + FAIL = '\033[91m' + ENDC = '\033[0m' + BOLD = '\033[1m' + UNDERLINE = '\033[4m' + + + +class TextWrapper(textwrap.TextWrapper): + """Custom subclass that uses a different word separator regex.""" + + wordsep_re = re.compile( + r'(\s+|' # any whitespace + r'(?<=\s)(?::[a-z-]+:)?`\S+|' # interpreted text start + r'[^\s\w]*\w+[a-zA-Z]-(?=\w+[a-zA-Z])|' # hyphenated words + r'(?<=[\w\!\"\'\&\.\,\?])-{2,}(?=\w))') # em-dash + + def _wrap_chunks(self, chunks): + """_wrap_chunks(chunks : [string]) -> [string] + + The original _wrap_chunks uses len() to calculate width. + This method respects wide/fullwidth characters for width adjustment. + """ + drop_whitespace = getattr(self, 'drop_whitespace', True) # py25 compat + lines = [] + if self.width <= 0: + raise ValueError("invalid width %r (must be > 0)" % self.width) + + chunks.reverse() + + while chunks: + cur_line = [] + cur_len = 0 + + if lines: + indent = self.subsequent_indent + else: + indent = self.initial_indent + + width = self.width - column_width(indent) + + if drop_whitespace and chunks[-1].strip() == '' and lines: + del chunks[-1] + + while chunks: + l = column_width(chunks[-1]) + + if cur_len + l <= width: + cur_line.append(chunks.pop()) + cur_len += l + + else: + break + + if chunks and column_width(chunks[-1]) > width: + self._handle_long_word(chunks, cur_line, cur_len, width) + + if drop_whitespace and cur_line and cur_line[-1].strip() == '': + del cur_line[-1] + + if cur_line: + lines.append(indent + ''.join(cur_line)) + + return lines + + def _break_word(self, word, space_left): + """_break_word(word : string, space_left : int) -> (string, string) + + Break line by unicode width instead of len(word). + """ + total = 0 + for i, c in enumerate(word): + total += column_width(c) + if total > space_left: + return word[:i-1], word[i-1:] + return word, '' + + def _split(self, text): + """_split(text : string) -> [string] + + Override original method that only split by 'wordsep_re'. + This '_split' split wide-characters into chunk by one character. + """ + def split(t): + return textwrap.TextWrapper._split(self, t) + chunks = [] + for chunk in split(text): + for w, g in groupby(chunk, column_width): + if w == 1: + chunks.extend(split(''.join(g))) + else: + chunks.extend(list(g)) + return chunks + + def _handle_long_word(self, reversed_chunks, cur_line, cur_len, width): + """_handle_long_word(chunks : [string], + cur_line : [string], + cur_len : int, width : int) + + Override original method for using self._break_word() instead of slice. + """ + space_left = max(width - cur_len, 1) + if self.break_long_words: + l, r = self._break_word(reversed_chunks[-1], space_left) + cur_line.append(l) + reversed_chunks[-1] = r + + elif not cur_line: + cur_line.append(reversed_chunks.pop()) + + +MAXWIDTH = 999 +STDINDENT = 3 + + +def my_wrap(text, width=MAXWIDTH, **kwargs): + w = TextWrapper(width=width, **kwargs) + return w.wrap(text) + + +class MarkdownWriter(writers.Writer): + """ + This writer is used to produce the markdown + written in yaml files (summaries), it is distinct from the + markdown outputter which process the whole documentation. + """ + supported = ('text',) + settings_spec = ('No options here.', '', ()) + settings_defaults = {} + + output = None + + def __init__(self, builder): + writers.Writer.__init__(self) + self.builder = builder + self.translator_class = MarkdownTranslator + + def translate(self): + visitor = self.translator_class(self.document, self.builder) + self.document.walkabout(visitor) + self.output = visitor.body + + +class MarkdownTranslator(nodes.NodeVisitor): + sectionchars = '*=-~"+`' + xref_template = "" + + def __init__(self, document, builder): + self.invdata = [] + nodes.NodeVisitor.__init__(self, document) + self.builder = builder + + newlines = builder.config.text_newlines + if newlines == 'windows': + self.nl = '\r\n' + elif newlines == 'native': + self.nl = os.linesep + else: + self.nl = '\n' + self.sectionchars = builder.config.text_sectionchars + self.states = [[]] + self.stateindent = [0] + self.list_counter = [] + self.sectionlevel = 0 + self.lineblocklevel = 0 + self.table = None + + @staticmethod + def resolve_reference_in_node(node): + if node.tagname == 'reference': + ref_string = MarkdownTranslator._resolve_reference(node) + + if not node.parent is None: + for i, n in enumerate(node.parent): + if n is node: # Replace the reference node. + node.parent.children[i] = Text(ref_string) + break + else: # If reference node has no parent, replace it's content. + node.clear() + node.children.append(Text(ref_string)) + else: + for child in node: + if isinstance(child, Node): + MarkdownTranslator.resolve_reference_in_node(child) + + def add_text(self, text): + self.states[-1].append((-1, text)) + + def new_state(self, indent=STDINDENT): + self.states.append([]) + self.stateindent.append(indent) + + def clear_last_state(self): + content = self.states.pop() + maxindent = sum(self.stateindent) + indent = self.stateindent.pop() + return content, maxindent, indent + + def end_state(self, wrap=False, end=[''], first=None): + content, maxindent, indent = self.clear_last_state() + result = [] + toformat = [] + + def do_format(): + if not toformat: + return + if wrap: + res = my_wrap(''.join(toformat), width=MAXWIDTH-maxindent) + else: + res = ''.join(toformat).splitlines() + if end: + res += end + result.append((indent, res)) + for itemindent, item in content: + if itemindent == -1: + toformat.append(item) + else: + do_format() + result.append((indent + itemindent, item)) + toformat = [] + do_format() + if first is not None and result: + itemindent, item = result[0] + result_rest, result = result[1:], [] + if item: + toformat = [first + ' '.join(item)] + do_format() # re-create `result` from `toformat` + _dummy, new_item = result[0] + result.insert(0, (itemindent - indent, [new_item[0]])) + result[1] = (itemindent, new_item[1:]) + result.extend(result_rest) + self.states[-1].extend(result) + + def visit_document(self, node): + self.new_state(0) + + def depart_document(self, node): + self.end_state() + self.body = self.nl.join(line and (' '*indent + line) + for indent, lines in self.states[0] + for line in lines) + # XXX header/footer? + + def visit_highlightlang(self, node): + raise nodes.SkipNode + + def visit_section(self, node): + self._title_char = self.sectionchars[self.sectionlevel] + self.sectionlevel += 1 + + def depart_section(self, node): + self.sectionlevel -= 1 + + def visit_topic(self, node): + # Skip TOC in the articles + raise nodes.SkipNode + + def depart_topic(self, node): + pass + + visit_sidebar = visit_topic + depart_sidebar = depart_topic + + def visit_rubric(self, node): + self.new_state(0) + self.add_text('-[ ') + + def depart_rubric(self, node): + self.add_text(' ]-') + self.end_state() + + def visit_compound(self, node): + pass + + def depart_compound(self, node): + pass + + def visit_glossary(self, node): + pass + + def depart_glossary(self, node): + pass + + def visit_title(self, node): + depth = -1 + element = node.parent + while (element is not None): + depth += 1 + element = element.parent + self.add_text(self.nl * 2 + (depth * '#') + ' ') + + + def depart_title(self, node): + pass + + def visit_subtitle(self, node): + pass + + def depart_subtitle(self, node): + pass + + def visit_attribution(self, node): + self.add_text('-- ') + + def depart_attribution(self, node): + pass + + def visit_desc(self, node): + pass + + def depart_desc(self, node): + pass + + def visit_desc_signature(self, node): + self.new_state(0) + + def depart_desc_signature(self, node): + # XXX: wrap signatures in a way that makes sense + self.end_state(wrap=False, end=None) + + def visit_desc_name(self, node): + pass + + def depart_desc_name(self, node): + pass + + def visit_desc_addname(self, node): + pass + + def depart_desc_addname(self, node): + pass + + def visit_desc_type(self, node): + pass + + def depart_desc_type(self, node): + pass + + def visit_desc_returns(self, node): + self.add_text(' -> ') + + def depart_desc_returns(self, node): + pass + + def visit_desc_parameterlist(self, node): + self.add_text('(') + self.first_param = 1 + + def depart_desc_parameterlist(self, node): + self.add_text(')') + + def visit_desc_parameter(self, node): + if not self.first_param: + self.add_text(', ') + else: + self.first_param = 0 + self.add_text(node.astext()) + raise nodes.SkipNode + + def visit_desc_optional(self, node): + self.add_text('[') + + def depart_desc_optional(self, node): + self.add_text(']') + + def visit_desc_annotation(self, node): + pass + + def depart_desc_annotation(self, node): + pass + + def visit_desc_content(self, node): + self.new_state() + self.add_text(self.nl) + + def depart_desc_content(self, node): + self.end_state() + + def visit_figure(self, node): + self.new_state() + + def depart_figure(self, node): + self.end_state() + + def visit_caption(self, node): + pass + + def depart_caption(self, node): + pass + + def visit_productionlist(self, node): + self.new_state() + names = [] + for production in node: + names.append(production['tokenname']) + maxlen = max(len(name) for name in names) + lastname = None + for production in node: + if production['tokenname']: + self.add_text(production['tokenname'].ljust(maxlen) + ' ::=') + lastname = production['tokenname'] + elif lastname is not None: + self.add_text('%s ' % (' '*len(lastname))) + self.add_text(production.astext() + self.nl) + self.end_state(wrap=False) + raise nodes.SkipNode + + def visit_footnote(self, node): + self._footnote = node.children[0].astext().strip() + self.new_state(len(self._footnote) + 3) + + def depart_footnote(self, node): + self.end_state(first='[%s] ' % self._footnote) + + def visit_citation(self, node): + if len(node) and isinstance(node[0], nodes.label): + self._citlabel = node[0].astext() + else: + self._citlabel = '' + self.new_state(len(self._citlabel) + 3) + + def depart_citation(self, node): + self.end_state(first='[%s] ' % self._citlabel) + + def visit_label(self, node): + raise nodes.SkipNode + + def visit_legend(self, node): + pass + + def depart_legend(self, node): + pass + + # XXX: option list could use some better styling + + def visit_option_list(self, node): + pass + + def depart_option_list(self, node): + pass + + def visit_option_list_item(self, node): + self.new_state(0) + + def depart_option_list_item(self, node): + self.end_state() + + def visit_option_group(self, node): + self._firstoption = True + + def depart_option_group(self, node): + self.add_text(' ') + + def visit_option(self, node): + if self._firstoption: + self._firstoption = False + else: + self.add_text(', ') + + def depart_option(self, node): + pass + + def visit_option_string(self, node): + pass + + def depart_option_string(self, node): + pass + + def visit_option_argument(self, node): + self.add_text(node['delimiter']) + + def depart_option_argument(self, node): + pass + + def visit_description(self, node): + pass + + def depart_description(self, node): + pass + + def visit_tabular_col_spec(self, node): + raise nodes.SkipNode + + def visit_colspec(self, node): + self.table[0].append(node['colwidth']) + raise nodes.SkipNode + + def visit_tgroup(self, node): + pass + + def depart_tgroup(self, node): + pass + + def visit_thead(self, node): + pass + + def depart_thead(self, node): + pass + + def visit_tbody(self, node): + self.table.append('sep') + + def depart_tbody(self, node): + pass + + def visit_row(self, node): + self.table.append([]) + + def depart_row(self, node): + pass + + def visit_entry(self, node): + if 'morerows' in node or 'morecols' in node: + raise NotImplementedError('Column or row spanning cells are ' + 'not implemented.') + self.new_state(0) + + def depart_entry(self, node): + text = self.nl.join(self.nl.join(x[1]) for x in self.states.pop()) + self.stateindent.pop() + self.table[-1].append(text) + + def visit_table(self, node): + if self.table: + raise NotImplementedError('Nested tables are not supported.') + self.new_state(0) + self.table = [[]] + self + + def depart_table(self, node): + lines = self.table[1:] + fmted_rows = [] + colwidths = self.table[0] + realwidths = colwidths[:] + separator = 0 + self.add_text(''.format(node.tagname)) + # self.add_text(''.format(json.dumps(self.table))) + + # don't allow paragraphs in table cells for now + # for line in lines: + # if line == 'sep': + # separator = len(fmted_rows) + # else: + # cells = [] + # for i, cell in enumerate(line): + # par = my_wrap(cell, width=colwidths[i]) + # if par: + # maxwidth = max(column_width(x) for x in par) + # else: + # maxwidth = 0 + # realwidths[i] = max(realwidths[i], maxwidth) + # cells.append(par) + # fmted_rows.append(cells) + + # def writesep(char='-'): + # out = ['+'] + # for width in realwidths: + # out.append(char * (width+2)) + # out.append('+') + # self.add_text(''.join(out) + self.nl) + + # def writerow(row): + # lines = zip_longest(*row) + # for line in lines: + # out = ['|'] + # for i, cell in enumerate(line): + # if cell: + # adjust_len = len(cell) - column_width(cell) + # out.append(' ' + cell.ljust( + # realwidths[i] + 1 + adjust_len)) + # else: + # out.append(' ' * (realwidths[i] + 2)) + # out.append('|') + # self.add_text(''.join(out) + self.nl) + + # for i, row in enumerate(fmted_rows): + # if separator and i == separator: + # writesep('=') + # else: + # writesep('-') + # writerow(row) + # writesep('-') + self.table = None + self.end_state(wrap=False) + + def visit_acks(self, node): + self.new_state(0) + self.add_text(', '.join(n.astext() for n in node.children[0].children) + + '.') + self.end_state() + raise nodes.SkipNode + + def visit_image(self, node): + try: + image_name = '/'.join(node.attributes['uri'].split('/')[node.attributes['uri'].split('/').index('_static')-1:]) + except ValueError as e: + print("Image not found where expected {}".format(node.attributes['uri'])) + raise nodes.SkipNode + image_name = ''.join(image_name.split()) + self.new_state(0) + if 'alt' in node.attributes: + self.add_text('![{}]({})'.format(node['alt'], image_name) + self.nl) + self.add_text('![image]({})'.format(image_name) + self.nl) + self.end_state(False) + raise nodes.SkipNode + + def visit_transition(self, node): + indent = sum(self.stateindent) + self.new_state(0) + self.add_text('=' * (MAXWIDTH - indent)) + self.end_state() + raise nodes.SkipNode + + def visit_bullet_list(self, node): + self.list_counter.append(-1) + + def depart_bullet_list(self, node): + self.list_counter.pop() + + def visit_enumerated_list(self, node): + self.list_counter.append(node.get('start', 1) - 1) + + def depart_enumerated_list(self, node): + self.list_counter.pop() + + def visit_definition_list(self, node): + self.list_counter.append(-2) + + def depart_definition_list(self, node): + self.list_counter.pop() + + def visit_list_item(self, node): + if self.list_counter[-1] == -1: + # bullet list + self.new_state(2) + elif self.list_counter[-1] == -2: + # definition list + pass + else: + # enumerated list + self.list_counter[-1] += 1 + self.new_state(len(str(self.list_counter[-1])) + 2) + + def depart_list_item(self, node): + if self.list_counter[-1] == -1: + self.end_state(first='* ') + elif self.list_counter[-1] == -2: + pass + else: + self.end_state(first='%s. ' % self.list_counter[-1]) + + def visit_definition_list_item(self, node): + self._classifier_count_in_li = len(node.traverse(nodes.classifier)) + + def depart_definition_list_item(self, node): + pass + + def visit_term(self, node): + self.new_state(0) + + def depart_term(self, node): + if not self._classifier_count_in_li: + self.end_state(end=None) + + def visit_termsep(self, node): + self.add_text(', ') + raise nodes.SkipNode + + def visit_classifier(self, node): + self.add_text(' : ') + + def depart_classifier(self, node): + self._classifier_count_in_li -= 1 + if not self._classifier_count_in_li: + self.end_state(end=None) + + def visit_definition(self, node): + self.new_state() + + def depart_definition(self, node): + self.end_state() + + def visit_field_list(self, node): + pass + + def depart_field_list(self, node): + pass + + def visit_field(self, node): + pass + + def depart_field(self, node): + pass + + def visit_field_name(self, node): + self.new_state(0) + + def depart_field_name(self, node): + self.add_text(':') + self.end_state(end=None) + + def visit_field_body(self, node): + self.new_state() + + def depart_field_body(self, node): + self.end_state() + + def visit_centered(self, node): + pass + + def depart_centered(self, node): + pass + + def visit_hlist(self, node): + pass + + def depart_hlist(self, node): + pass + + def visit_hlistcol(self, node): + pass + + def depart_hlistcol(self, node): + pass + + def visit_admonition(self, node): + self.new_state(0) + + def depart_admonition(self, node): + self.end_state() + + def _visit_admonition(self, node): + self.new_state(2) + + if isinstance(node.children[0], nodes.Sequential): + self.add_text(self.nl) + + def _make_depart_admonition(name): + def depart_admonition(self, node): + self.end_state(first=admonitionlabels[name] + ': ') + return depart_admonition + + def _make_depart_alert_box(name): + def depart_alert_box(self, node): + self.clear_last_state() + MarkdownTranslator.resolve_reference_in_node(node) + lines = node.astext().split('\n') + quoteLines = ['> {0}\n>'.format(line) for line in lines] + mdStr = '\n> [!{0}]\n{1}'.format(name, '\n'.join(quoteLines)) + self.add_text(mdStr) + return depart_alert_box + + visit_attention = _visit_admonition + depart_attention = _make_depart_admonition('attention') + visit_caution = _visit_admonition + depart_caution = _make_depart_alert_box('CAUTION') + visit_danger = _visit_admonition + depart_danger = _make_depart_admonition('danger') + visit_error = _visit_admonition + depart_error = _make_depart_admonition('error') + visit_hint = _visit_admonition + depart_hint = _make_depart_admonition('hint') + visit_important = _visit_admonition + depart_important = _make_depart_alert_box('IMPORTANT') + visit_note = _visit_admonition + depart_note = _make_depart_alert_box('NOTE') + visit_tip = _visit_admonition + depart_tip = _make_depart_alert_box('TIP') + visit_warning = _visit_admonition + depart_warning = _make_depart_alert_box('WARNING') + visit_seealso = _visit_admonition + + def depart_seealso(self, node): + self.end_state() + + def visit_versionmodified(self, node): + self.new_state(0) + + def depart_versionmodified(self, node): + self.end_state() + + def visit_literal_block(self, node): + try: + include_language = None + include_lines = None + include_highlight = None + include_caption = None + path = self.builder.confdir + relative_path = node.attributes['source'][len(path)+1:] + + + if 'language' in node.attributes: + include_language = node.attributes['language'] + + if 'language' in node.attributes: + include_language = node.attributes['language'] + + if 'caption' in node.attributes: + include_caption = node.attributes['caption'] + + include_language = (('-' + include_language) if (include_language is not None) else '') + include_caption = (('"' + include_caption + '"') if (include_caption is not None) else '') + + self.add_text(''.format(include_language, relative_path, include_caption)) + except KeyError as e: + pass + except ValueError as e: + pass + + self.new_state(0) + self.add_text(''.format(node.tagname, json.dumps(node.attributes))) + self.end_state(wrap=False) + + if 'language' in node.attributes: + self.add_text('````{}'.format(node.attributes['language'])) + else: + self.add_text('````') + self.new_state() + + + def depart_literal_block(self, node): + self.add_text(self.nl + '````') + self.end_state(wrap=False) + + def visit_doctest_block(self, node): + self.add_text(self.nl + '```') + self.new_state(0) + + def depart_doctest_block(self, node): + self.add_text(self.nl + '```') + self.end_state(wrap=False) + + def visit_line_block(self, node): + self.new_state() + self.lineblocklevel += 1 + + def depart_line_block(self, node): + self.lineblocklevel -= 1 + self.end_state(wrap=False, end=None) + if not self.lineblocklevel: + self.add_text('\n') + + def visit_line(self, node): + pass + + def depart_line(self, node): + self.add_text('\n') + + def visit_block_quote(self, node): + self.new_state() + + def depart_block_quote(self, node): + self.end_state() + + def visit_compact_paragraph(self, node): + pass + + def depart_compact_paragraph(self, node): + pass + + def visit_paragraph(self, node): + if not isinstance(node.parent, nodes.Admonition) or \ + isinstance(node.parent, addnodes.seealso): + self.new_state(0) + + def depart_paragraph(self, node): + if not isinstance(node.parent, nodes.Admonition) or \ + isinstance(node.parent, addnodes.seealso): + self.end_state() + + def visit_target(self, node): + if node.hasattr('refid'): + self.new_state(0) + self.add_text(''.format(node.attributes['refid'])) + self.end_state() + raise nodes.SkipNode + + def visit_index(self, node): + raise nodes.SkipNode + + def visit_toctree(self, node): + raise nodes.SkipNode + + def visit_substitution_definition(self, node): + raise nodes.SkipNode + + def visit_pending_xref(self, node): + if 'refdomain' in node.attributes and node.attributes['refdomain'] == 'py': + self.add_text(''.format(node.attributes['reftarget'])) + raise nodes.SkipNode + + def depart_pending_xref(self, node): + pass + + @classmethod + def _resolve_reference(cls, node): + ref_string = None + raw_ref_tilde_template = ":class:`~{0}`" + raw_ref_template = ":class:`{0}`" + if 'refid' in node.attributes: + ref_string = cls.xref_template.format(node.attributes['refid']) + elif 'refuri' in node.attributes: + if 'http' in node.attributes['refuri'] or node.attributes['refuri'][0] == '/': + ref_string = '[{}]({})'.format(node.astext(), node.attributes['refuri']) + else: + # only use id in class and func refuri if its id exists + # otherwise, remove '.html#' in refuri + # uri_fields[1] is class or function uid. e.g: + # case 0 - [module]#[class-uid] (go to if block to use class-uid instead) + # case 1 - [module]#module-[module] (go to else block to remove '.html#' in refuri) + # case 2 - [class]# (go to else block to remove path and '.html#' in refuri) + uri_fields = node.attributes['refuri'].split('#') + if len(uri_fields) > 1 and uri_fields[1] and not uri_fields[1].startswith('module'): + node.attributes['refuri'] = uri_fields[1] + else: + fname = os.path.split(node.attributes['refuri'])[-1] + pos = fname.find('.html') + if pos != -1: + node.attributes['refuri'] = fname[0: pos] + + if node.parent.rawsource == raw_ref_tilde_template.format(node.attributes['refuri']) or node.parent.rawsource == raw_ref_template.format(node.attributes['refuri']) or node.parent.tagname == 'document': + ref_string = node.attributes['refuri'] + else: + ref_string = cls.xref_template.format(node.attributes['refuri']) + else: + ref_string = '{}'.format(node.tagname, json.dumps(node.attributes)) + + return ref_string + + def visit_reference(self, node): + ref_string = MarkdownTranslator._resolve_reference(node) + self.add_text(ref_string) + raise nodes.SkipNode + + def depart_reference(self, node): + pass + + def visit_number_reference(self, node): + text = nodes.Text(node.get('title', '#')) + self.visit_Text(text) + raise nodes.SkipNode + + def visit_download_reference(self, node): + pass + + def depart_download_reference(self, node): + pass + + def visit_emphasis(self, node): + self.add_text('*') + + def depart_emphasis(self, node): + self.add_text('*') + + def visit_literal_emphasis(self, node): + self.add_text('*') + + def depart_literal_emphasis(self, node): + self.add_text('*') + + def visit_strong(self, node): + self.add_text('**') + + def depart_strong(self, node): + self.add_text('**') + + def visit_literal_strong(self, node): + self.add_text('**') + + def depart_literal_strong(self, node): + self.add_text('**') + + def visit_abbreviation(self, node): + self.add_text('') + + def depart_abbreviation(self, node): + if node.hasattr('explanation'): + self.add_text(' (%s)' % node['explanation']) + + def visit_title_reference(self, node): + self.add_text('*') + + def depart_title_reference(self, node): + self.add_text('*') + + def visit_literal(self, node): + self.add_text('`') + + def depart_literal(self, node): + self.add_text('`') + + def visit_subscript(self, node): + self.add_text('_') + + def depart_subscript(self, node): + pass + + def visit_superscript(self, node): + self.add_text('^') + + def depart_superscript(self, node): + pass + + def visit_footnote_reference(self, node): + self.add_text('[%s]' % node.astext()) + raise nodes.SkipNode + + def visit_citation_reference(self, node): + self.add_text('[%s]' % node.astext()) + raise nodes.SkipNode + + def visit_Text(self, node): + self.add_text(node.astext()) + + def depart_Text(self, node): + pass + + def visit_generated(self, node): + pass + + def depart_generated(self, node): + pass + + def visit_inline(self, node): + if 'xref' in node['classes'] or 'term' in node['classes']: + self.add_text('*') + + def depart_inline(self, node): + if 'xref' in node['classes'] or 'term' in node['classes']: + self.add_text('*') + + def visit_container(self, node): + pass + + def depart_container(self, node): + pass + + def visit_problematic(self, node): + self.add_text('>>') + + def depart_problematic(self, node): + self.add_text('<<') + + def visit_system_message(self, node): + print(bcolors.WARNING + "System message warnings: %s" % node.astext() + bcolors.ENDC) + raise nodes.SkipNode + + def visit_comment(self, node): + raise nodes.SkipNode + + def visit_meta(self, node): + # only valid for HTML + raise nodes.SkipNode + + def visit_raw(self, node): + if 'text' in node.get('format', '').split(): + self.new_state(0) + self.add_text(node.astext()) + self.end_state(wrap = False) + raise nodes.SkipNode + + def visit_math(self, node): + self.builder.warn('using "math" markup without a Sphinx math extension ' + 'active, please use one of the math extensions ' + 'described at http://sphinx-doc.org/ext/math.html', + (self.builder.env.docname, node.line)) + raise nodes.SkipNode + + visit_math_block = visit_math + + def visit_substitution_reference(self, node): + pass + def depart_substitution_reference(self, node): + pass + + visit_remarks = remarks.visit_remarks + + depart_remarks = remarks.depart_remarks + + def unknown_visit(self, node): + raise NotImplementedError('Unknown node: ' + node.__class__.__name__) \ No newline at end of file diff --git a/packages/gcp-sphinx-docfx-yaml/docs/How_to_Document_Python_API.md b/packages/gcp-sphinx-docfx-yaml/docs/How_to_Document_Python_API.md new file mode 100644 index 000000000000..370689bfb368 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/docs/How_to_Document_Python_API.md @@ -0,0 +1,354 @@ +How to Document Python API +=== + +This is a guidance for writing docstrings of your python code. The API reference will be hosted on [Microsoft Docs][docs]. +*** + +# Overview +We generate the API reference documentation from source code files automatically. Actually our tool is an extension for [Sphinx][sphinx]. If you are familiar with [Sphinx][sphinx], section [All Supported Sphinx Directives](#all-supported-sphinx-directives) and [All Supported Inline Markups](#all-supported-inline-markups) will be usefully. + +All the docstrings should be written in [reStructuredText][rst] (RST) format. + +Find our tool on [Github][docfx_yaml]. + +## Directives +Directives are a mechanism to extend the content of RST. Every directive declares a block of content with specific role. Start a new line with `.. directive_name::` to use the directive. + +For example, following directive declares a `See Also` content: + +``` rst +An empty line should be added between plain contents and directive blocks as below. + +.. seealso:: Content of seealso block. + Indents should be used for multiple lines contents. + +More plain contens. +``` + +### All Supported Sphinx Directives + +| directives | description | +| --------------------: | ------------------------------------------------------------------------------- | +| *.. seealso::* | Indicating `See Also` content. Read [See Also](#see-also) for more information. | +| *.. code-block::* | Indicating a code fragment. Read [Code](#code) for more information. | +| *.. literalinclude::* | Include contents from another file. Read more [here][literalinclude]. | +| *.. admonition::* | Read [Example](#example) for more information. | +| *.. title::* | Indicating a title. | +| *.. remarks::* | Detailed description of class. And other class descriptions should be limited to one or two sentences. See [Remarks](#remarks) | + + + +## Inline Markups + +Inline markups are used to describe detailed information of package members. Such as Modules, Classes, Class Methods, Class Attributes, Functions and Variables. Inline markups follows such fomat: + +``` rst +:inline_markup_name: Description for this markup. +``` + +For example, `:param:` describes parameter information of functions: + +``` python +def foo(arg1, arg2): + """ Docstring of function foo. + + :param arg1: Describing the first parameter of foo(). + :param arg2: Describing the second parameter of foo(). + """ + pass +``` + +### All Supported Inline Markups + +| inline markup | description | +| ------------: | --------------------------------------------------------------------- | +| *:param:* | Description of a function/method parameter. | +| *:parameter:* | Alias of :param: | +| *:arg:* | Alias of :param: | +| *:argument:* | Alias of :param: | +| *:key:* | Alias of :param: | +| *:keyword:* | Alias of :param: | +| *:type:* | Type of a parameter. Creates a cross-reference if possible. | +| *:raises:* | That (and when) a specific exception is raised. | +| *:raise:* | Alias of :raises: | +| *:except:* | Alias of :raises: | +| *:exception:* | Alias of :raises: | +| *:var:* | Description of a variable. Also used for describing class attributes. | +| *:ivar:* | Alias of :var: | +| *:cvar:* | Alias of :var: | +| *:vartype:* | Type of a variable. Creates a cross-reference if possible. | +| *:returns:* | Description of the return value. | +| *:return:* | Alias of :returns: | +| *:rtype:* | Return type. Creates a cross-reference if possible. | + +# Details + +Following contents will show how to write docstring for specific purposes in detail and give some examples. + +## Class + +### Attributes + +To describe attributes of a class, use `:var:` inline markup. `:vartype:` can be used to tell the type of attributes. + +Example: +``` python +class Foo(object): + """ Docstring of :class:`format.rst.foo.Foo` class in rst format. + + :var attr: Docstring of :class:`format.rst.foo.Foo.attr` from class docstring. + :vartype attr: ~format.rst.enum.EnumFoo + """ + + attr = EnumFoo.VALUE1 +``` + +### Constructor Parameters + +Although docstrings of magic methods and private methods will be ignored. You can still introduce the constructor parameters in class's doc string by using `:param:` and `:type:` + +Example: +``` python +class Foo(object): + """ Docstring of :class:`format.rst.foo.Foo` class in rst format. + + :ivar attr: Docstring of :class:`format.rst.foo.Foo.attr` from class docstring. + :vartype attr: ~format.rst.enum.EnumFoo + + :param init_arg1: Parameter init_arg1 from class docstring. + :type init_arg1: float + :param list[int] init_arg2: Parameter init_arg2 from class docstring. + """ + + attr = EnumFoo.VALUE1 +``` + +### Remarks + +`.. remarks::` is not a directive supported by Sphinx or RST, but only supported by our tool. + +Content of remarks should be as detailed as possible, other contents however, shall be terse enough. + +Example: +``` python +class DirectivesFoo(object): + """ Docstring of class :class:`format.rst.directives.DirectivesFoo`. + + .. remarks:: Remarks from class. + Multi-line content should be supported. + """ + pass +``` + +## Module + +Module's docstring should be the very first line below magic comments. Even before the `import` statements. + +For example: +``` python +# coding: utf-8 + +""" Docstring of :mod:`format.rst.foo` module. +""" + +from .enum import EnumFoo +``` + +## Package + +Packages' docstrings are contained in `__init__.py`. They should obey the same rule as module docstrings. + +Example: +``` python +# coding: utf-8 + +""" Package used to test rst-style, google-style and numpy-style docstrings. +""" +``` + +## Methods/Functions + +`:param:`, `:type:`, `:raises:`, `:returns:` and `:rtype:` are used to document a function or method. + +There are two kinkds of ways to describe function parameters and their type: + +``` python +def class_method(cls, arg1): + """ Docstring of :class:`format.rst.foo.Foo.class_method` @classmethod. + + :param cls: Class object of :class:`format.rst.foo.Foo`. + :type cls: class + :param str arg1: Parameter arg1 of :meth:`format.rst.foo.Foo.class_method`. + """ + pass +``` + +Content of `:returns:` shows what is the return value. + +`:raises:`, `:type:`, `:rtype:` will create cross references if possible. Contents of `:type:` and `:rtype:` can only be class name or type name. `:raises:` may contain both type name and description. For example: + +``` python +def method_exception(self): + """ Docstring of :meth:`format.rst.foo.Foo.method_exception`. + + :raises: :class:`format.rst.foo.FooException` This function raises + exception. + """ + raise FooException() +``` + + +## External Links + +External links can be written in two formats in RST: inline link and seperate link. Read more [here](http://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#external-links). + +But note that our tool only support inline external link format currently. As an example: + +``` python +def method_external_link(self): + """ Docstring of :meth:`format.rst.foo.Foo.method_external_link`. + Inline link should be transformed to markdown: `Link Text `_. + And seperated link will fail: `Seperated Link`_ + + .. _Seperated Link: http://seperated.external.link + """ + pass +``` + +## List + +Two kinds of RST list formats are fully supported in our tool. Read more about [Bullet Lists](http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#bullet-lists) and [Enumerated Lists](http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#enumerated-lists) + + + + +## Include + +If you want to include contents from another file, `.. literalinclude::` would be helpful. Further more, you can include certain lines of the files. See more details [here](http://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-literalinclude). + +## Example + +If you would like to show an example of how to use your API, use `.. amonition::` directive and include "Example" in the content. + +Example: +``` python +def method_example(self): + """ Docstring of :meth:`format.rst.foo.Foo.method_example`. + + .. admonition:: + This is Example content. + Should support multi-line. + Can also include file: + + .. literalinclude:: ../format/rst/enum.py + """ + pass +``` + +**NOTE**: If you are using Google or Numpy style docstring formating, just using the keyword "Example" will be fine. + +## Code + +To show a code block, use `.. code-block::` directive. Note that there should be an empty line between the directive and code content, as shown in below: + +``` python +def method_code(self): + """ Docstring of :meth:`format.rst.foo.Foo.method_code`. + + .. code-block:: python + + >>> import numpy as np + >>> a = np.ndarray([1,2,3,4,5]) + + Another way of code block:: + + import numpy as np + b = np.random.random(10) + """ + pass +``` + + + +## See Also + +`.. seealso::` creates a bolck of content showing readers more information. + +Example: +``` python +def method_seealso(self): + """ Docstring of :meth:`format.rst.foo.Foo.method_seealso`. + + .. seealso:: + Seealso contents. + Multi-line should be supported. + And reference to :class:`format.rst.foo.Foo` should be okay. + """ + pass +``` + +**NOTE**: `See Also` in Numpy-style docstring must begin with class name or type name. + +Example: +``` python +def method_seealso(self): + """ Docstring of :meth:`fomrmat.numpy.foo.Foo.method_seealso`. + + See Also + -------- + format.numpy.foo.Foo.mathod_note : See also target. + """ + pass +``` + + +## Cross Reference + +When you would like to insert a cross reference in your docstring, following markups will be helpful: + +1. `:func:`: Referencing a function. +2. `:meth:`: Referencing a class method. +3. `:class:`: Referencing a class. +4. `:mod:`: Referencing a module or a package. +5. `:any:`: Referencing anything. + +All contents of these markups should be the full name of objects. It means you have to use the physical path of a class even if you created a short alias by importing it in `__init__.py`. + +Example: +``` rst +:func:`package.module.class` +``` + +# Google/Numpy Style Docstring + +You are free to write your docstrings in these two kinds of styles. Examples are shown [here](http://www.sphinx-doc.org/en/master/usage/extensions/example_numpy.html?highlight=numpy). + +Although you are able to mix content in these two styles together with RST format contents, it is not recommended by us avoiding potential conflictions. + +## Supported Fields + +- Args (alias of Parameters) +- Arguments (alias of Parameters) +- Example +- Examples +- Methods +- Parameters +- Return (alias of Returns) +- Returns +- Raises +- References +- See Also + +[docs]: https://docs.microsoft.com +[sphinx]: http://www.sphinx-doc.org +[docfx_yaml]: https://github.com/docascode/sphinx-docfx-yaml +[rst]: http://docutils.sourceforge.net/rst.html +[literalinclude]: http://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-literalinclude +[latex]: https://en.wikibooks.org/wiki/LaTeX/Mathematics diff --git a/packages/gcp-sphinx-docfx-yaml/docs/Makefile b/packages/gcp-sphinx-docfx-yaml/docs/Makefile new file mode 100644 index 000000000000..00ed77ffc735 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/docs/Makefile @@ -0,0 +1,195 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# User-friendly check for sphinx-build +ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) +$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) +endif + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " applehelp to make an Apple Help Book" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + @echo " coverage to run coverage check of the documentation (if enabled)" + +clean: + rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/SphinxAutoAPI.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/SphinxAutoAPI.qhc" + +applehelp: + $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp + @echo + @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." + @echo "N.B. You won't be able to view it unless you put it in" \ + "~/Library/Documentation/Help or install it in your application" \ + "bundle." + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/SphinxAutoAPI" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/SphinxAutoAPI" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +coverage: + $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage + @echo "Testing of coverage in the sources finished, look at the " \ + "results in $(BUILDDIR)/coverage/python.txt." + +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." + +livehtml: + sphinx-autobuild -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html diff --git a/packages/gcp-sphinx-docfx-yaml/docs/Workflow.vsdx b/packages/gcp-sphinx-docfx-yaml/docs/Workflow.vsdx new file mode 100644 index 0000000000000000000000000000000000000000..42e836dfbdae33914d63707c46b8842a8aab2a4d GIT binary patch literal 88545 zcmeEtso^9Kru)M(z#|j>xmU>`?S(|xYj zwGa#=*0$h)N!83X+N=8+h>=iz#!fFvB#jY z$8U~RU_j4H*)GWOh-CHUTC8Pi=S37D-tsddEYmyE_Pb*+Q zmjm6*A1ic+E#~|X<*Lj6&*8y8vMSi2*1^Gih5E2BYrr7RHuMN;bb3pmR^?4pL@GaS zyX)Ts%se=5)E(IzHAg*n6ZF`-jTg5f_yY- z2V*NoI@*7X|DWOi57YX;Exj`FUkndC@;)f!4w6f>K~Qjo2!_YF6gNQRGms2SNh4L`1JM@h5($?0k z(y0TNh&3qjHWD8iPH_GGEgweC#f-poGFO~23<{hSlZT3T2;NAZ?CwL?uM4Xa&AcY^ zhudlq*7Rwc?8LD#SO5qVM6lft8XrlWAj?FbB?ztTaC|I9DJC?ATHcWXwy~2M!8y>q zCHDg|DW?NQnrTFF@)m<8FtR#Nit|@9CrM_r&f!5-B=d{j?0n6a>P4N81*$94GICo- z@f=c4_Y~Re6cA?fr_XNNP*r zHT&y{B{dxJ20Vw>fxI1`FK1xjTtMcKflArtdZZRs(htB{GiE=L0?*?^+Z;6W1EI{C zM5{Nanx>si%fX2Yt88l9oNMcd3^GyA=pLSrnICrdL;#~qZCkXvdNcmAqxZ9IZTU(c z9(Fa|ouNpxt{$=K2dk_tl#i9QeS(fQ@#=#>c(vQyEvqJYH2M0?L}TBnuK6`e9l-$ea{Jh)?(I zNwSGkZLFD`CKp89GZYc`D7Ehw9gwO^}`(OlD`Nxb$CWkoD7tB@;#Tlt_5a8k^4WQ6mDVS zNyl)E<^@O%;e(%1iT${3rZuxeoOT};vEjjzQPYh;&7=5A(csRqt51l1+Q%h_;6(2Z z2&_Xnc(JF(u< zUzf6B%7SYNX|zw-+s>PM8WnO~J%41LwrjL6P?Y1Y#3kFFYHVzl?eCUvIs#t{pzdg;zuUrt&olrtv_;Kf8rnu3 z{Od&o*x01l60E|d5=~v#M0=teUW?r@k8%@uuaHXQ!XQpU5X@6iYn_5hZTCCHa)kn! z+l-4*r{Db)$_~UIZB&eolvYzzBso&*ZrR8BibD$mb_lgy^-gE%FJ5}c9`>i{A_~!s zr1O}t%;_578492y2FU>vz%Ed4$6Huq7FzX+iIb5Nv+2Mh;bmJVBgmC@AkZwj7c=%3 zjIu%0e!GX1(GTr)j;nrf&#?NV^*OYCe}U>+fiXgkL9qs(>GEqiLU-^CigoHx zgP`nIWbK@Z+{nCIVO;%@V_J7O(zU2sVSQsl8tcT+DH3%a;#$q+7+>?W{*%fqb>qYM z4B?4}bH!}oeo^i-%=z>gmUd;3g|b(>3brQ%16W<&5L3J4JV))dqyRNKx_x)p9Posi z2&-RRtW_^)&z|-=udQn$g0obj?44KPZ!>G6`e^14HGvRE9m1`(JRKs-qqa3;fX9k_ z_uT!v%O18!)ENN4AZ$5hzrBgkG$la4+{`-o1!nmPjJcC~Ai@yH7HMe0X%z}n5-bgW zk6p=HrTvCiq0INi2{%|z92+WL>2^%JvO9B&ogk)kSsYY%PPH6bRcsRz7+#|>9BiCp z`^W4xw_qYLumTC?-);7t`*7&!0lORs&O_;x;hiV-!nqv?gZ#=OepXnf9fdT!hMyBTj| zN>S$rt>DjBbA6Pw+H`<{_L-nC{V$m81p2BHYnqPypR~qSUon+cn4Pa#eX+gSQEQ+| z2;=gF8KsS`m~DH65xOaZZ%`ZnOrYf~Bg~;s%9%gOcC;T5W^6_Lj%}U^xOMQR9?>XhTomTqp zL^*!7MF_DzU%TT?+571)Jv{{iMVxb~0@WvM9~_Rh<6>I5qFo)zT!cnUQF>J{x8*OUVOWDJIx8RRb zQSS_!16RG+pn2qLp8YX}&N@MeLGSm4ib2xN=&hwDy8R&^!9PL!qKQ#;TlD9W8b;}i zvYp+4*n)12g!RJ*7ZNq`LW9lXW8y_O$v;Q|2BB$15xds|Y!R<-NX{ZHYrS1nbzC08SrxP6dUv|nk8oK=!QB$Ji>Be&unosn zH4c@CTb-jus1lnj#T+&o0=y~Tl%OP}=PGh+K?=r}CgEp~0M`-ldxs?b$syf|akLB%`_#~6;I}59f(;qgYYJ$q7 zy-9Et_n*#p;DAt#=@P-Mrz5k7p+Up3?G3fFzAm*u@%E0GOSwV1NffYl7gVB)z}l81h+j;ZxpvzJdLt8Yjy8n^fZ z1!U(w4if`ki@SA%-LuHP;a4O6tA6S#3!XC&K&=sf)sva9ws)CRjcl%7VKq`2%Qs#7 zWUPFa-4mM#f~JHl`L(qo6&S-M?3>aVXx}Z$LCeo(^LXx@HW#P%Q8qD?NzgAK)JvD2 zA3@YJhf#BnmDb01e!XRLx?zdF+usebdUhA=&q~LrXZ(@w;8iYxx*&#)LM!k~&JuN-;0$oug(v!*!pO ziKGf1ac(yXc$V~~Sa`(u>_P4l9rCL1MYk#|{GbBq{zm6*GouTv6%5YKa0N+7RPg== z5CV*zt}-kcvEr82WD<67?3fd$oS|XeW)GS)S=iV1KHsYR3~_W@+`rK`H4jo$j76NMJwSh zMWd5a(5mObYr%P?uzCU)sT~%D;eX19m#~?cz0aGXM?IVqz8B+B`h`o*{UCduc5SS5 z)y(#(iKPUPPF1mKWg(q+tMk+gqAV?!$@6(&SZawC;?hj6{{UzUcXj|sIMD)mflFWQu5_Uex*Hr@pV-?0my zugJ_fTa;|dnac9`oc}?H5uzd7u*R_oeIoq0<+DX+iqPK};r3e}gXwQdQ4cd_Yk;ue zV*=QSX)g9Ro@5jz(cV}P0I92>V(|Fu5MY5(mSIdynba(7k?So>R51N&-7h}DxSNBl zdLAZ=c+G@Q=xcv{L-69~R(7=J!R*Z{8ACm3X~ z@_uz%`SzQT$N8L}1KF8PnBVCpYe~drUB2Y-on)zTb=#~_9OqD8raZuBvqU{$T)|LY zF&(^RxZj>BQs!J=;-t*pL{yOvxwIfZ<(iXw6=7}!)-h~KA1hK-`_rkZ_;)XP+DG*# z><8nnPTa?SVSmmpiPXv_Xl*e1_e=)3HAa+G;#KW;)wV@je4pMQR^nN^`D&(|6ez<0 zLcAEDc5ENr4o_Zoa;YImnU5soR;1X{%az-rtGVv)6!7Fe>y!RUjfZg?uAJ1n0J`UX zU<_QN9K`JzLolJYDy9!~WDLO!%Hf#w%Y-oi>oY-OYW)}`H%V_|jKt(j)St{nKqOwQi`I0G&RNR1MP9yF#7 zX|-1b7h)&#r3L|xT%0z70qnwI1B1}7Wm%<41kZvI?dD`IK_rK3+-pECOCWAiR)yr} z(5bW(hO0~j#H^MJv(IND#LO*?Gx@DzU}i!LY{WL@tDPOBl{Hh24y~_E9eYtxdDL#rB-iHmDQ10YkydSxut)^25)v=gd|@#z}Y=q z{*Z#cDfkZ3*#sQTm~|@eSXIbuYDveH#&`!FjI%_OG9plOky)^&k)${+ft6%DjlKSo z3{tmEW(H+Kc(n9>WFB0Zft1_QvmjTauzDd|h-Om&W1C`MdJI~3%7#JVs{*CBif*9w zRTiaweZ2)b;hFl=xY$eNaWu<5C?ArU+Ik3aW>B6EFP-5?`0`fgHUgXsy^D`64@J_@ zqls!wQVO_MO==2ur)C}QamrZ0mcBV#@Ok7w(%f0ACYSN}qAs1YO|_@Neo1!7&8#<7 zm#Zb&XVT7<@FugKNQ&|Bl?+t|wV*E%y&&kewdD;rB})0P}O8bV3^GGrtvR2e3T&LDyvDoiusLVq~0^f7am@Vb^IVu z2IHIfFIGrM55LQWuww90-tJ6sj#GSskFLyg?D%#(`pG+Kr%7RZiZlRDc0#bSUyw^ zX@NNG@jE-D3@cG5$DXxIc3;XwkS*bL@%z9#y`Ni2$DXaO)^doq*E%oLa@}C|+@D+M z&Z)kP62$GBIP+exW^e#sRr8fk>0be zkzVry|F?7hg}eK)3(S)yGiN|anph!7+EOY)K~`ec^ViemSSeMc<^&IlDEQ8-iM^ui()4jbtf4gpV!ZRp z9Pi5rP}Tz>7fBOO3+Q_xS+x-M#5&ouy^@-abTwdNbO^<#^(e}qF;MNnm%sw)=I?&5U? z*l^^(^jpWb7r1+1q@$j6MfZ@Q#_n{RqzDD>;wUSKwPL`$2r$eOf38kJau2)O@+ffm zbm_iDmZs_}mqnxrGbQ99iS>4NY{Y<}h-YOO&X@yz1a9ajsp4P+`_9xW<{mI$_=`QN zdS~bObs4BF@at2TW&+&(2HsjxpPKacOWznnE+^v*m{ZZ*2Qb#49@>q-=J!U$!nVQ% zM@|UE%d8}h@A0t=PS}7-BoF&it4H@GpQohg`trGTS$&(ZmOU1ea`Cp5lx;ZKW<()NZs7$S9W5A{^b!u#0!r{7JPD{BjWavs5;g3M-FDwpr>D^e;F-U;uC zBUytzsPcX0Nd1$X&s-h$H+Up%*xlCt^w{nq+P^Dj7Pcqwc1)|3V+jro6G*=}QER;Z zqx=ywjHe#4TLyOCl~Nl%QC@ zzgCFIdWg&BPguasKhhFqaz0}E1OD&YY1oI}CXw&}0R2t?0GR(O{9EfgIvG1S(*5WC zzv}-Pt!UrdY2V=8Zv*M~CfKLUTZnqL+#8K+#akU6y4P~p8&hAIpKl(t-cSk5Q3Vaj&r;Un0?ZL3`pi6*G!5ZaO@%qS zyx#Zw{jyA9;&HL_4a?LMXfvoJxKja^eBLg&F$wI^WNQubUR8sM;_OgKvV@J4?d50V zP52^J+*c1qRL-3cM5kGUV@)|lGy6swrMLTY_ncvjpNRwYMF2xOY@ebBA3&DI) z(;AV)Vu6Q>vmWZJ6tGd>pl$u{L5e3;6ZNNfTobSGx2?r%@o#v_K)|OJk zn2Og2tE$y>*5j@bd*1lV(Ggl+<6)KNX&`eBb9&z{sHk$$LfOdFCPKh!H061H=i zLTWT6wD-9oN*b(cMwhHQJ($u81)jlEeUK625HIX_Ie&x_IU-p8o)dR2C z1rK{WCn3;MDa+YJn}wGew+zy!2jll&Qr@F)jEzmI-klz7=rM=_(}IkuolIq@8i*7X zwrEWbAZknluDuNG*pGNaoannWWRWRv+bFs>`J^fu8ofyev?~fzi3O~z_Tn4c_y4iX z=aQLY(chAv-XK>A-iLYU$Dc85^w6y0BO2Np*#H^XozAsre8J{ zO8I&Q103#5mBz&0&1riSA{_Q9z#kPzwN+%LjtRn5ZGr1xFZ3<-qgNexq2MoIGEs$N3lbl)Fk_29?T3D&%l8Z=(Wr6L-#8!2&<$-Ycw6hMhGZ_dNZ=cJe zJvYe@H6ss@sgBXO&ATF#*uC}iN8k6d#W=T#XLrip2}bTqD8CM3-wZT0r9=4+bGu_r zl^lDp^IDb&G5khRyuYpwp_`pTCC}%}0Z!Om>x9?7M0rhK?Y~A$mFp1IgRa=Pxaji# zW!ZiriP_4jf>uoXffER}6&;F7l__1ebYnqIXDtEm_CueWR{6SvLaqEPvUej+;j* z%(!|V;p*6h+k2iuA@Q=S1>B0<2wJtp-J7*SL*51l1$QV_P6+dM*+D#dV2}Jgf!SS2 zqVyvXhKN%AZa^l zs+%NywjMR^K_ff02XwDlBKEI@Wb@uHOg6WaSXG7hnfXvI;eeC_ET7ylSiZ5HUcC7Y zeXd^A^71xOf`slW3!Rl&ql~kV%{dw&lSx*is*0EPnBp_iaj zTBWli8+l?<@Q(p^MM;6;?L9Gr4@s?iM*|-jir4~s#q2Zr&MHpa?EO}!$c5M3e$jzo z&4}nAwg3?2amvRM;ZSlZZ6hn%di7ihV2!T_9rQwsIo8^b()o)B>m4f1fPqu>$icPU z{4O0s?hC7fk9wq}XB4APt=p-oJ9vD7;lwd{^kZ}4opzW&nCNwZ6=LIQ+gW&b7-8zD z-*V+?i}c4F!7w|{En&$mun+vawTW{}n_}4in+gl05SW7>n9Idf#{DYv$AX^=%w!Jh z*Ht?M)U^g-Dd%^$3#WDY(}SBL-}tiY%q||7np)A36Oshf%iP0`M|<&CEqOup1Br)PHrOJ01Y;&y>7gP|pK ztT4>Sfp2UJT%PkIH$+_k_WC8Rb9Q95nlELOJv`vhjBd0Jvd7e|pF0tenfG#+ev(|i5{>AJQNxKxbJ<37i8DUr{!4Bz&PJnLuCzi;;m7?oG6`HHJXML2&pt>#H zDF=fNsQ@;LM#SjnqahbK8*)@fjEPS|(^)BOKK1 zUloHt$3SboDs)P~3e!xfOE5+h2whHTCkxM@&vs1J>O2c>&tytlhz7Oqx5!?JCe#b< zT|qt0AiEE)Brr^FU&9a~Q8^6GUOp{$^R2iW1CGu2l*RR*@eZKedSJ$W0maZr6bk}F z9cVwE{DSh*Qmz$4XNqTYwb-C!(NHaeo#{E2BD68UEe>37;AVR8BKH{gDphAytst+K z*xiML*gv=+_#FXJH@Am7vFI%`%e_R2V*F5wW3j~N61@7&;N+Y>BKG>s>2%@TjZh8h z5P;z?T;}gmg1Q{qita82ldMTGB)n;Yc>3LAqG96tB3cBGvUAM*0GM=W{;?zHr+vkI zn1L~x2mvvIMUxlj)m0w1E>HaO*Jb=gl)yQo4ps#v=Xl40JV;8EPIaEUr381V_GVQt zHg>0D?2k6|34y;SL*5}$mY=YY(b$}^LAn48T^C$XPDY!rv~)U)b6BTB2Z^Py#-ROr z5x_Dya7p%nqVn~Sh*OU-8&B*z$-zJP+4@mtgac^+k<8am%~z3J^XC1;&kG{2en-_p zk_-^G`v3w}dG2{56fg5U@B@>UVRaubHsIFcy@s!TJ@wSfU#{n@%DI#w9JIFMy5y0v zV`nam`{beQ07&J-q6gmj-lDk^2~2E)ld?!n(&EIa%D2W<-}WX{_u}yAuRazAvA~Sy z8Cm0f{``@cW}XP(L#C!_6|pgNW|+W&d5qa~RsuUTTd!YW5fHp7!|ghF1hW`1k27Sl zqVzk*Pn4jA%Se7W0#$hPAZD3D%9+U~+ei1^zHJFJ8Rq6`ziGb0VhwJw6fIeN?Jd>Z zRD?bq0|iKZ$r;zt-QOwVZz`Eq4WmIICX?E_YF}3H=2}%ig>amy_10b${Bw-xJ*#f& zc}~n`NoOT6qR^Y1dF710>7X%wgVjnuJHY@~feWaGllWvc#e5{7tH?mLV`s$LOZ)}6 z@Qzzkf-O^%2E0=FD&(req49YDoWdf3m@8SIow`$b+aUc@OuIi=)kk%D0mmLWm>m~` z4^m@Ad4$GY?{24yT4OceIS8fg2|cvxZRql>(^;=080RS&b5e*;_|5YRd4wKTkTmO8 zoOp?;W;)O51m`kX0vFb(L5!hh{e@X|#l_^j=ah#4ETg;DXrWWtpqg4zGEt#0cx2fJ zvuTfg`69t+U?)|LDC+pw`>%1M31NP^nteq+K9S30qdlqBYwBmGTThn7`h)Z9BEa+I zGs|Uf%Q&J|*$75n-V&%P%)x2Z#pKu3S)Y8wbOu|850d9hUx*T@5HGVRckl)=Ce}{M zk%6Sm6bH5Mj$w)}+A5+#{D$hh>2^-0RN4&OJV-O z6WX5Qcd2%g_(sxo>RrT}tWMt%vqLad>%A3MzDjONxHfaPzl9jeK%HV?VppHt>S=ialKR zFur*{jpnytn5Np?V|NqeZv3dTZ08HwtK3(y>$MCSg#2kI*7GUs;XUm6b+kWGePdbs zM<_=Ip#}AJ;GF2ERRq(QH`sLq>;98m_B-MlC`uSgvn^Pu8($#nV?}iE59=*YrNa(k zf~M-VW3}*D8~Mv4r?0>7`pE?H!>{p$j#mf$-5=;_bXL2(&k-s~bvP(e`xvSh4s_ z2cP$#b4-;mP4h^M5y=@#{-~nNhs}r8`*DTpBA)!u@DZ&oR)C!Oh@Il-oS4ud0BVz2 z#_1YF(l2CG{Q(ohA(eo!-)R^pDA(%*7ert_1K|uqWfn#}kmdNm-^RPO^&aTo)s3~IN7I4uuYk*?Vjd-?auG%&fpUA4SB@^?1qRq>kKe% zy_PG82?q#hFuqtJMKR-?z4g%)vbS*gC?(eWe|Tt)WX!8=M4`)2&ng_8*ozOyZ@Zzz z4B{en8pii(_6fY-`2MYQZ)N{V6Z)?hmJJdB0QFxPyq&(Ou_N6-$A4t+o63^5>--4a zs^`A9*0O!vf~bU2N&MpRa$)r1V`b~BhMr4L)g3wnk1MV&*1fc`&p2>m9S>KNUOU{I zJ>Ify4PbwmD7fb>n8SgI;s}xJL{&K3+X<(yb{|TJ`|CG7E{-r^dw-<`;4ET|_L`hYiQoy~#WDw*#-P0gvBt ztWTPU#q-nLc`cl}Xk6Jmy)XS*ar-!G_gtXxF{bAOoSjaBynR}B8|XD0e%ovGbM4}T zeHYr@bf-pon-*sp?}6k+kmMYnC9T~{JlVc7BR#?UNDSPi`FOSP$sv^ z@%u&7R6gwYxW_(li$irYlV%QhJ z2oP~+OxEOm{1~(pM)he`9F+U;sbq$9mJ8qpFF9&%{TBu{E%M@@YQ1M z@(eiAIZRukAnx%zjS891^b~j)SNVuwY^k_e$BKr16f8OZ=U>tI|CEzg#{TW<{+$W> zdoBd`U+no0QTczDzy4ETUYO8l@%QM!@0;N7z*SEgE}EjG(Y7T1YLYJi!WwINNh)Fz z^Y3oS^MuycwnJi}mFRK-JIs%2|?m1w0CA&e8 ziuZ4ux0t}`Px*6eu>fr^h1nAvog%4X(Go=gK%SjOl&op)VHq%MUguB;`Q#Z!9S?q< zJCqC&flcOEg65IlL%!|lbg}StEer<-TMmE>m7_%^yh_{CxYgeya18Eg(F?D? zRC>5Z$2Q7({w;VmJXAVRe`jpL004;p1>S!Z5B~$i|5if$Cx(qn|G*FiY}Zr&2Ej=e zr^tFehO-OS19uBJbx^t=iEFjE(w46egWB*^2{-!g=d5RRWZ{I_gbjOtHw$bMdbHBg zi>p;;;N$4Y9bR2(xXI*k+M;y>qU7D&*{h*I{E_^50EbD!US23?{xe_6%7ZH{^<#~* zz3rVo?f1xR*%~u`aYH$EghcQTrW_q(gJT6@rsh4}OWGmd+QKXd{uj$pbk3r6E)Yt@ z5Tnu@#u(T*eO`n3z>9m%f?Do3x;>4+emaw|n98Pj(xyFbT@pdvp%h{Qs(c~wN?ig1 zmCWz7gwZt3@MKMy-|NA#x;$!j$07lncKZT?+@E021*{vSyG%b5QYN3EF|sQ$k=-gfMAC2eZ6!4uWHu<5JLfs<=rMqJ>h6TLqVXFOmC z`sjB1xCIMy*Tu=o3#>E}(62MUouX`3pKKw5C?k_K6ox@dX{L!O~9U8N`9AHoSXyzHcxAfCVGsr|qvOnk7+DS|Nx!koD zPr7cZqZlnY0g7_D!aCv(rB20psC(6EHW*+LSSP$h}|A&AEFh3meSomlEA zUhy$Wgtyo9-N}vDh`EpFomL|uci|*kZM7K&;*JUQc@0cwO!A2;hPP#x?+T8({%^O? zH^jRFgg!<-=2~RozNYe!W+84WC2k8xw0h&h)k(!Q2XX6s8*+A4%XA$@p2&B0b%uNpCkk=>_W}X1gn*v72jBpDhA*2uz(_6 zal->N9}daPRO`Nh{bX{rcQ$6TH)bkbrY$wuKOCCegXJ_-9q#MHhgt#N{p;k(5SARO zcz6@787PjT?f@xV9Gc{UOji!g^%65Jn1MMJTP?6G>hO#Kf1v*IlxmfPY^|s>fQvr8 za>aPV3!7gEz;aR!|4{Erqh8(TL$q4=~RIzhoF{3K!CiUa%o;V}? zlEu)==PCdPd9XuN2?wc?amf<7U+zaJweL5jrDeDMLxv^2FLo4wY6e%JJRuje)NQun za#PfhV~O7*qT^wx<@6mxyWBikMDmzy{6Jp8(V)9Q2}ov9LI;* z+L!r9se7eK45^ztO+BrIMb_)P)PB{ zS?pdBwGjK0@C0#&!bo{O-YNHm3f|1*oy6MmtCf=01EAJz;3rVy^Tzz^-}(l$upN`z zzs!#L+g$qJ8cU4-VD_P^r0oVfLO1&APwy38Dq0m@b0VogQh!s{Apd21(|%z|aQQ4+ zT>`mWW5(mkO_)b~^5*acUPLu*z^MBj_B2~TLkqlo7;8{T(hyuTEc7p=kIU>~D)5@2 z`zHnw+nFCX7uGukfmgqwfI%YRT(lB6xF9hZX{IM&B=<5z`J9F%n&7>LQKJcxr|`Bs zz0FHCmysxLtOKo=B(_F%L4(>3Bkud(7WCbeQZQ*fF}*Yxbum&hg0lRr=KP6D8eG!I zGh}cw?Bb9+2wpy{@SQ=0L)g)waJ++~-ctM$Hu_G|hK%U3gq2PV?Ya7DzHNsBO1dYe zz(^rx=ewBEH}o3pt$}mVfg_4m78yA%Hrw-_h=&~_;6&zTx`^#iK}ogItp1kAs@K*7 z)zP`o;F1q?G;&Hn<1F{7)CbbW%!;F1)|QV4%3?+^cCZA4d#4I4Ziw^5d_7HFT5j?w zdnk^pTS1m%-Y_279Lq~bkJ-`% zBWyC!5l$15(Y1O9G`WR@m924UP-jKisWRhCoR{|Y5yt#0?!NZy&4PhnUxG>kO{L}P zD%1AD{e#AkPsY4x%wL}0YfPU6?+-QGdl}o|9>;)^c<#>n6?9I!J^bo<1>)i$X1#9x zt<-A3dAukIN>cLj6)zzcYRkvmkmmAG=Q=92EzW6bA;!)vc_v`GztTNQIgji2LNez42<564Y~5pz`lXeANV~w)n5`7M190GPXlq-+-&t0IG>%YM*lz z-_86S#-xGXSitW@f>5cvkX~8P|XePe8UV^^xc!B7P#Wy{{x0GdT);L0QYFFWYV`p8$T$x8r$= z*L7!D6-zzu627Q#8An!g>0|HLbMKpc%u2lR%@;1$i4aZ>1-$F5p7@-#h|ln~dAuV9 zm)Ng%2tL<--i_+fs!37p2tZo1e!j5yR7fXn4Jpxh;m4B#TBecHrCV>B6E-nP(0qv} zZsViUgt40Z$V;8qGaflXACd0dI$E6bEuH-Qjj;b`{4EB}<(2UF47V`D|86Fj{@H)l zv{pQ5M*H?LeaGK)I!=EyK_)|3z0__-M(Sq_t|jp|=G(dh3wB$s<8Bs`^!1L7A=a!v zw92J8nog#JN%q>#E_g7xdoI~Y&U2JaV9uS(+pzJd7Rtx$g3a#`a{V)<+vSp#v+ey- z({kdI9&f~75cOOAyw_6R{-P{p#5-EM&eK~W^ICA==FRJkxm|*+d z?MlY-3_N~f$2$?jb|LjQzpG4QQBIL``X(fj5T_=MKMlg&vnC|u7tEkExi zZ6{gZ7SRFK`2!Q@#GB_7u$-yWDbXMNu3{1Yn?uH0lID0tnwv{eS3&`m>~RYeFb35{ zH|o;z4mxqHPnqens$e9h`w>CHnltx~BK(y$pa~iI@w1PEhl7jnHJK{6y5-yStSCH)GVvZh{CH*Ub(2mDroUqL7>c0f>(v#MClcUYyvH z5w?Zck^|gm3eIU_IACbb8*vO-bDYVzS?9QK+xs=!X|#zO-_;8|Cl)U-W*;$!xQCw1 zEcGq@kwK1>kx|T9;$q0ZslNUDZpf>_IfQJFHDffX(J&l{;~W(`!0va-qw4dDpE;aC zR=hiFcmRe@U%tR|0!5v5yD0Mq)gWlSCVC1f zqWEs3x4UfOu4{$;#_4t}qm9f{I`P_aI2`cLv;+##&#x_h_T?e3Y^07{orW#p`T-^% zK~b(rfsEbd@*^yaVV%0egjsrPApOB|dy7lc{gf6-Gi*x0V$TezgdCw51* zMp`ODdkVf37`9>PaopMTCB@~xYE8i^R4e&rlKnQc)enq)#as$Qu53anYhfimvNal2q@QOZDEvuRnO`bzeVVO{DsMRP z9R!@>rLLY*O8#PU+Uc{zA8B@PtBy2@falb5 zO6qqz-;CdMm-efqrV_YPE|p@Xn3A93J|GflE%F_O6{pFY%UCQTg~e})fD?yqoa-Ef zYb0rrj#~Muwo!D&sFGM`J&^MXd!<6hffm(k@>5jd)_v*7 zjk_9^-W$CUM)JW_`B0vW?UkI>Mat040pMJDn*J(zsv;`d@5lba_%(vh5P3(V`yyYn z8Yx$+$D-z%yT>3jr)ZWttewqZ6g7&~M9q`$T4oRm;PJym$R2=vM#iAT8{B2d>mgXa z*b0=t6ey4F(h_7SBmOHjsJ?Jm_ zMFE!6k))xz4Zwx`Y6g&|+1-!5@8B52lH@Pd(Kf-d6n}O!nu|F^d{U%8=+7Dn8-+Ck zBCL~c6BT@_0z>{9ADjbg%yjw;Hu8PwQpLx>(K_+wnqO8w99tEnuUs=uslhWlzqoP4%vk{FYO=O zyfr3n=blZV`*aJX+5@Fm$2xhuV8B8jL{J-6krlqft+GTvj8h%9sp!=kO0Sg~<`^!h zkxM39v`Z=GQ@{i1x{fOJ8(6jp6|(i`iKpLFE=?=Hq51Ai?cxzCC%O$&ED4rTA~;LB zJ~Y10#ykxWgxpiijO_$Z6O6_JE#vSMT}EUd*Ch!4KCDbWd)4RmXyl0cSb4^vPlrHm z*6hLZ(Cc#w3OmW%>|vp$j8%r*<3TYEugKu5=vt&GJx=z9pAm7Sfr@XlKd4c?RmJ9K zFfm&OX67X?9;)}wSdmAZF3|v;B|_?}t1v1nHp(F)!%ZoD8IjT$7k|J~D!DX49@g3^ znlgFQI^c!x#r$c786snzN8_el+zTPCz>7-P7+OjeZKJk4KU?t%EoG21E0vZQRb3mA zqH)n95$39OP%bUk2v-&Alvwopb3-s>u{ZQ6?U-yaq1m`Ic-@>t03~?DEgoJ0)TIt( zsiNxdV|_@#qXa9LeKZbu&z7P1oOLLD><@PGI^tDriAHd{jo?gR<$794`R zySux)ySux)ySr?5fB?bW-Q9JghkvHdxtclmUG;qzU0waGcdgYL&{lG#A(nztp(@P@ zPIhbZ$N3k~h1=C#2TQsY9`-+wt+a#qp-}xCS|8)J<)PRAA*O~g8T-pgLZ~RHfG=cd zfYBi`YQmQ&CEheN$XNEgVH8`Pvolv^x;g2Za!%WAE|(!#yc$hWt`FF1sbJCdJRz!v zzvTy|eE?CeKK@4~0}$~>g!vr|Ea?BkJHP*1$OU`euiLMv!O5v zH-K>X};w}-s67hoRoKsACg!htdXbM=R6Y?fy2&@dz^KpPeb z`@khtlUUZKOKS&ZMVmHijc(X>MKS<(d|0n>$Rdk`dP5U71vh+QJz6dl;LgwzuJ1-gzeiurCHKn=UQ04McfnD^cG1# zIOCwd)#!&hhVN2Pb-P)q{*UF3^MEunL!Ed0Jjpd?UL}rifoRCGH&LvkqRO0~DDG3l z_{FB;ehn(zpQ?ncO%}cC=q|v})ny1p~Rz8_`W#66RfST~UEab$y;Y=J}vc$Z(EjT?-;4nbLrbIw$*OUK3{_UgRA4g8k zN)*G}%rXX1+#`HHPbN4uGqeasE{8dYUB#OEI>X;md0D4^UFI$pjCSsy zzPY%5$J~_b2uw(3%#Awp8fwZ@lq)Hx{i~;%m_?Cp+QMeYK-7LSB(O(aESW`EK?qBN z^0zbRFJ?#N=eHH%2uUQ5z@~Zw24jPcgjXvfKbLY&6o#smf$;(@RMrSLhT*LK?(CS& zA~ctcfnQ+raFpl>A&B<71wn#JBMl=IwIw^M&|2JqKw~X?=j_@;&0dSygUsW@n!88a z%cghTZXWuZPtSC-12J%Tp_y^?eqNPRnVt(c)~*Zb_oqr9M1T!qd=V_Q75o{-#T3s~ z{coEi!4qM-TF&X13bZ^&to8^BDr4?thb-9C2^qthtRYI3UIy74O%Wi@9+`x!;zufG9{1v{AC2k{_OIjIk8iL9Pw5pTv3_#{q&uRM%pYRE}88S!dYw6$O zSxRtMe!hQZSlDiw>AYX6mXzM-K>nRDKVpH-sOb-_N57b9Kd6YHW`RidE467yH}&d< z3BxMOGSCzqlXOo-IMZHy&tC+mHB35*wa*`ifLSo zbW+}zBxAem7j9hI38nd7V+Lu{DU&SrV(GSA`Oqx0y~qL{-raK>b`0-CPM~%6NT%!| zvTvQvS+wu84;D_8A_ylots$m@66W=}3DZ*o8!o7SsinM=hdyHN*Exu(B`+giFE31X zhRHDebN39VHe7R0gb|7x#$4rsB4nDvQMBB2%+W&(Z>*(0{@wmxD9ZCD5Lv2oUT|*T zXj}9$Zu5h&YldWV2k5#!d!wz>F>e;PGh<`0lYDWQry2TcednY_e;o!Jap=RJ1TuH* zcZfn9`(ega%#XtNPIeyd2W~v1wb3J)A_x8iO?smZDdRx1pu1p{0Q2;9wmg~#Z?o;6 z45qS(q5p$GDR=sli!~<=&f7Vo&btT}Xmj5|=bUnc9$`O}#T7t{#@cxa*v342+vJRR z&%T2G=0GT$vw|hqO!H)_h(htChf!p8G$yFNzLk|otKPd1dgET@#dWC2ux0qRNU2WU zkjD`xWQ#Vn4SB3?JzWP|c~%HnlB7S5ug`fDefinUcJvQXWGh3V|Dm8?_a|-`f4Q=! zl$8oAmNrD2k>sCI@okxcyacQloapY288q)DEHb=^el}X+GwMfvWMw5`FbCFA%M~Z#ED$2Iht<%7^fhZXqM623F$VfM-y|Rp%r{jF$>vBo` zFGUYu9$BolKR-XoBD60&pH9Y1#ecGt%CT-np&J^W`BlPB6qwYD5Ip}$*Yco)^7%;n zg+ZLdsM4nfm~O5Mu1NoMQSixKFtUA%uLJ9v`o5B`UNZ09jlg|0*1&4o;u#n;9`p(~ zS&O81nGU}i-Dtz0L{+u7uQmbx{-0kXg)ay~aHi$A_^I1N&i}16W6eruTGd6`4!0KS z$L#d8$scCUoVd0)2{*yRUA**tR_(oJOVMoR{A%H1S7nPeitd!uH`;O z1eHL9p|Y?QTWCyk7Bcow8~W*Qwlhzr#x%R47%ecgF(b#!{EavrZQz(5gUqWS)5 z>K8A&jiOoVf!+bzjt-6mm+`e5ZZ>ywEs4eOFo)m1SjboZi-q8o@@gC8+{QxB1Wt)2 zGc5XL{~&8xfrGOn*OW>N?=c%S6W8qKQ%u^az|Y;{lU}OT&RS-oa;k@rzfUYy_%n0b zumSa1P}obI$gujn^LT|@Dtb@;Ok5jhb|$ga6T{$Qk1tL`B)@T;Q<3qe;&%KstLPKa z%nZc;{86mZ@Gr7Y9_Y8eqJdLe2(>wTrcj)4uVS^0W?k8bdZbqzHdnEux16PhWH^j9 zN_=Ljr9u`p*3tp}t4=(nw=oTD=V<#JP3l+E?53@22QVC1u0TBW_~;gmwY;|G#T%SH zR@emPBm%3~4X%q!xE(yKIu*K0ihvqj;l7OP8&b1ZEnH_PPi3MWHr5=iMNTxCwV@_X z`Y#r}+>-0MxVXrmW*$0)3yNa>+Ek*dk4CQaj0X7q3x~|W61C-a(syqm@mZ)Kupj$M z8q&%R%$wXRTfztmW^1%CD&jO(Out{4wp!Hv$JuDDXqycx0`;f(SW+lR} z9x=L<{lsvlQEw~P=#CoV&Kd3sUYWv2SXETfIqSl)>+we|L3_adSt~``(ySH!GRvDW zu70H#Z>)#`NAj^FBN9yQ!&sbX;~ZC?sZal_<~G@4$GfE@<2CPrP$yiFq?C#tU2D)} zp?1$UV;IWR#y@q2lq5K8w(!}oWif+`^jWDF&KGcRxni=kykAWJ2<(`!HO@W*7E8;d zY}bN+@bs;NN_5rAsivIM>uI~sdsbJl=vlwKoXN=Bbl&m}K){wyV4ZY{|88-TQ{KMg z=GMm9xuf{R#_1R$jDMck25U?e2;6v2^wf}r=22}$^UD1SBQH>I^OU`i;|n|F%q9oq(eg&M%;jX8qN8bO2iQo`nVjS5 zD2>pM>U8XRX_$(uTMMv1?jTz`N@p|ymKx}@V-Wo{v@}&|7KtRI2w9acBQjc}F~?fh zo`oCuCJtux(E`Y0R#p@nN5785aq~PQpCo!@NNoFjZGPxUHhnKF=qQMfIwLKdEvv=6 zRWSa?E7hQmJ&Zs)%YpMM7>rw1kclB0I$FKyMtVUG_eO$qE(&#`Z=yO#GRSC7gLy-y{OQ2UNGs3MbSqiia z`R{>x2$poE{-))4xYDwAC$;W;2RgqA)M_1dQ5l6{CxeOFC1Qp4(KS+kJ&Sg(9j)I$ zC5>SRxGGf{^G^-8p~Ct8SjbWFk^Kq{40-1m}*1QESI8$xw!YgI+bg?B3q%L&Sf5y3Cas$CJKp%ll8yrqyrlhsr%jIR00PUpW-SNC8(7 zBFf=ItZ1<;n7)KL%Ay?vw6&mRvbv?k_j*F3Lpy5tEdx6iUds8kqXTPpLBpgQf>Vr3YUF|=w4ZO=& zya0eTF5V5lTGq#QWMpLbEC7ToFVFcq;%@iyQ{s#ol%7L%!CBj^(zL4f3}Pw0ZLfZp z=N{ro$OW6ZxMF>+P9KEzF9Oa;dCtf`*LdE0u%_WSt-*kP&L6{@`O6|;5|lq*GxX*5=kEXsXBCP1lgrU#Z?Nem8vT;p&@mP6 zeoIg5@|guH=I?=K%d54%#ki@mi7TOZ5yjFxfC0rDy`yDhTQo2FwXVlqWQe;*--%oq z{r494WebV+i==C&EE@k0c-3{;6cR$+NgfDSN%W)$;*Kx{Xor5JAu5Qg1`54K|0gC< zx^7|Rbpxt4p{>2gw8uXg`CV~Wn>kohfe*lc(>Wi}2#Dfo1?j?)U1#57E3@|vvx%ww zjUctm`|pl}UHz;^lnTHrBpGc+uRe=Fpipw7_$TFHC zs(`+syTPBy2#$~uwv%uK^>+^Nu@LY5>d+q@*n#%@A+JGJbahS2OG_#q6Ic)7ALvceaPNnQfbpnFUT0Qpyv zXim1;B!faX=VY4g)w+BKE|0^^w2rdOvbE}GYwR?TH|O2I^)!N_$RDin-MFjla!Na^ zx*CZ~t6EWw{Hm{pkT6|I;BKhsp3EK=Ss-DCaF{ly3gjvsyc!!8gLeFjWenbOE77)v zlRMDUoO~EnF4|@*f}F!y{VIl7UeiH-6!myj;!uSV;5f+f_h5kyOetA6ida@igvuJB ze&57V-<rK#n+z=;Ww(67Ywjimgdu)-q0TL`O2=Jp zz`ErtDOKv73v{;iJ~B75oI`)q1ZeA(99*>I+@i+=wrNQusd!p?axOseWQ7}%NA|TR~$TGq(bPl!6#IO#)%?X}C!> zMqud*U=+KIf|&bbr%Dk5tR(nk=RB`0A=wm4Xcezd7#Tgn~%EV=9nz^Fl8l8xd56- zkj*R%QYi3KYG6{Ptq*LneF2YvGi?}%0Bn2PP4RP`elRvN`Y>gSe9DHFC? z40!ysrbgRbomX$zy>`YAm`7S{0=knM!?4!D2?{OEha&7~qmB%WG=UT*T~x0_-N&l7 zj${R=Fhhi_IBqq@A2c7k089mjnYfHU&vPZ%B+goj5L=yHTB3|2Kc>;y$5JRxZ`Ooo zCxMExcHiG+J@qX2rC0|ZcxE3ZQ~s^%FV^R0+jL->(T?+GktIy-rUy z9R3c)BskOCn!UtiAA{Bj4-EG9p`D z{GmCYHkclXz6r}n&jU75H#zTCU?$@kiF z^P{6d`{CqIozSfhP&{A+1X>)sx&(4{dpP@_QF4|mek4D3727d)eg4yVxVx?XaCP%~ z;OjpBSd8D=;P)A!=Tnm(50rJMDKDPFs z`PD(8r`1#Cl!i|iX`rg^3HICJ(T5f17Hxd*W*gA0x*Nl0u6)zPNowBLADWdf(tmR5 z>wR*1hhWXk{gZ+Q_CdS?bFOmpbKkzw3X|vI>d*}F$eVbdXV(Xh5P;>GeIF+$4E-48 zDsB|R+m(BtO*FRWr?Zg*7e5Mw^7P4GJ!d{w_!d8UI>mwS82wme7?;9go~P+^wdE3{ z!*`CBGms@_xm2wn??*a$)K0+;%gkw?0!z9j0=^ADCy%$o@TIl5b?)1%e8O`wZscU> zEfXy3!>k^F7gHYKhbht2oK-o*UGQvRt3Li2r8ixV|AjriJVX6^F6CTx^+~w3|3&%8 z`RTcdPp`M%BfWRSU)0m%ZI7qthrYQBueRkCIl`AQq|F{LKrWxhwJfnI_i(*GkH>Xw zXV4G#uHBJ?@aS|xe!RQ_6n~+)k02py=W8E&=9~Avo#w0f_V_LNkW6Ly9JT_hnd&8tp{vVE8@21 zE6SsEnEsVW?eFxUr|KnpKfBzX&+ByH<63T?0z)@D;O#fO8^v2&tM9FWbjPXJ*c&=fkEX4HlkmUcM>CB+ofA@U30r z>Xe#?P``(J-Q7Q5hv&`ah3($K8J@j6 zIfsA?K14rkxqjNmIp27_biWZdtA28IdoeT(ZUOSIjht>~=x)4j+i$|hhK*9&{f@fm zzG7n`D_Nj25t4+P^0g@n^?FMCb^y_)bH6(CEG@F|M=*{_&U@M?}J0h-fH>iAk@L0yrl{H!S@kHj02YMx~K$md+-8q{3i_!&E z$#HOT!DVcQ2Iw-TyOyFg*}%8#*fNWhGq;A3bvow6br#;~=yln<&i;MEJ;&B`m{(fN z@{YkXcDse0wUi99comfGvJZxS$&{t9j1w#J=0rL{X0S5Gi+-Lf9f<>%Y-x@*wg^k;Im zG*(GVpPZhg5L8189oB1o+HqvZB-~$IeKUCC;ntOq@KJ<_!lD_Pk(uq(5|RO*_92Wm z$0-z+Q9smt0|M>)5Hr1tYBT(SpClmA8#e@x*&~T9*Nusyg%p&vk8AtS`q?(pea05v zA$dRc%pFm|Hmx;Rp1jXf#_G`h9!Q8oyoDyPXu;=;^V8&tR~=Fs;>CQgQ2Pj9?X>G> z4l}reW8EIq8}wZL#w^bJF(_)~!)gCRdGkz8bmY1s(RUKn`V;i>R#0;wdp!_z zK*zr?f1gTtNl2(p_cF7;`@0MekEH{7=_o{QCu!q5C9TG$QxMOjI$Ho@7sjxhL9P~? z17Y11)JC>xFyxpvn*)j(c-WFl*_#}OC9B)2HDiLA*6dWMiH1unc+P}P~ zYB>SQm|t9mPxr4Uk}}lid3-KCM1=a;SnE~T7(yud?-L=anE%kB*Y#@cdwQeu!Clcb zR7if{gRvnXPXwm~fd`kQ8nXSMu7PcS*NBCDEF-K?$?Wb?kE!!k7FTnfX|43;fJR?< zqE_sB>Ex_|RH^rIZpJf+`&hJ4dsvD$H>Nsd_Fzil3_7u{lWn9-3MZJtdqXwiJWx8B z${upYAfAoh7i!tZ45MQs-{uQ@TBAk>nw6nFAeyI;FGk#Tp{-TEn0n9M-Q67I@K}7G zUU8mBR;ML-2YA20RvTf){!v%(MapqRN;6SJI)eTzJil~t^18plx_=rm;oE8fno=o{ z^qC|_YqvtYW<=}+^vWbI4iFW5uMk z*W9B~OTnThAbb+_#4+=@b(DjA@cDQlT}Veg*g+2iT8!zo@|nljrLlZ1<{aQp=UG%Y z1yAFsxE`L_|MV+?J+#r$#&k(Z#d{rN)Bjll2CcubH2+tnpAaZur-w-kFvJ`9UR&xg z;-ePlCQH?0*7DkOD&iqhs`u!eA=#~q!S04CRX9KR6801y@#Kd0UaK~V%v&E?M;`a7 zlj|7DrdYn245(94^Y7JJw(6GyNU)yI=f7y%XdE~Bno=^`gK#mk^zQC$NA}}$e}(P1 zpS~blN9Ox>Vb4|1}shKTXO8};6{C}YUl z`5siT_3-1A@hZ$Y5-wLCWa;z4WIvZ=rzcVF{_h)MMIg$#>?a8HoIcX|dbU&f;T;yG zO3%RV3o_!_nZ{dE4#JL7T^AopE%tmmw=Kbv>jJm5qVqZ<3ngIataBl$;wJUpw;!r{ zpXT~W<_RaEoteQprBGYR<_ux3Nff(4@n?-+i=V$Jr&0gT<)X>|5W)?R1*!8TccW(4 zu!4?XH`JkLvo5n|YbW)qu+{-~j}2EDW+=j!+%!d9g5y!v)mZp6l)9D?bJ89RO4UoH z<#kxo`YK%_ZZ{nib4@Dp*`&ZZuT^7AMX8Q96#I*!lxuzcNVtzNR`i5!{>OLUcw74n zdqi&?0SRojeg0|dI^nu*TR0yfW6@JkeZ2_pr>XC(lpph{sV-LhT?)#47l$ux<<&5@ z-G|3hI%vVh$LWDX8i9u`6Ek1Z>%4FtPNWBWl&$t!xiMIc=;K~$K-g|e@!urJD6Syz z*IcuT_2F4%J(ZU=n}!tT53`hq;yX!IcJ(}?kpapd*XtkHSP0cDc%fqfA4FOnw*$yi z58!mXR)BM;$u&W6zO0Dcb`>wt!9UWT80I(m>$;D~3#RmbQJgN&2#TDgD0C6R^Zzim z!@}U|MCH3fKB~}&fw=Pr;_OEupLcG|#zDE3fqK7m;Q`2={aRMmt!c_SJIF6{+|sV9 zif9Wy)o>5iV)wCK24m3%vFUrOH z=`_;aqOLwt9d_wFR`S;0XcnTL$jKDj?HrPFGU(@*%H1HsE#Csxjvj*VA`uR2Sh2Y9 z<_#60AXWNRT6GlCUj)*Vgy{-^ghV-X1H=LhFbMAQ2AET;T2b2-m56Pp>3{8oK?eXlxGgvMB(+`5MN5rgH|YD?}( zf9oW;p_9>WAwY1DHrp>;#>|ZVlY@`5uopXMlF7xje5=@gQdkyKT`O>U%U>6+6++RivAtv<4P zyxBk9vr#&e!lBk|(bTlnH=|>**_>ET!UjUlS+yxVn$1MT2#fBFM!X$!Mbex;8q5@h zR$WNXKtfW%g|+Vx=)UmE*vHXFw>)e#fm}>L@7D+HuN-XrIz2eRY`olrvR+Ji2jQ}c zPaXH}7WFRuRqd-Vv5jHNEbHf}nv?ojmd9K`qVKnk%;4*v_l}fhWKUe4}Cqg&q!Oy7@c^vY5Z z=+sRR{&It%n3YC9PMP`XzApLT`_|5#Xr||OxjpSI+^_s?->O9ZEt%tOx9Osw5%(F^ku&SY2m*B3w@0?^tik>R7;9LjZN(j?b<9Wx2mt^-G~!V)06uKooOk&+o?d zygW9>#qm3l--zaEEj6f{+aKhJatGcYU8?7;aloty85|6M1Yv+24#Gc* zVjnARmk-*t>CkO!ZvfzPINNqsHzE+!oz=730G&<;|H3Ie$EiBwrmJV=CC;;3W+n}u z`eX*6N=*c9-2~*pQxhFhWRFdY7b`=!lhWe;go0HmN>C-ccxJ=l#7Fu1VEZ~9*hEu$ z&AX0Id&$CCukBXDW7wFEN-|)>vinjSExt3{KZWm^;(bvT|Hff*$}hH1n4Np;u{TkY zZ!167%zplsL%6j@QveEg_ac@d50nRE+@$(fxyO#ahqfXn91i;Zj*v3lvmm_rj_NfT zH`Z9s3ucqF4~rb?mQUnvb^v@zx#vD%%Ov)#G<@}C5kP)*{BGj3aQZ%YX13?bsX*o3 zt{v(0VGW6Fse6Gr*3FVadIe0`7{k+TlOyQX3ZM3;0j7dhgVOg!3IFvF)YH1(n9p4O zQ${*D+zjuyZdIcJL?S}&B2SPm6I>^qOa6)Du8)J1N^Eb#HcZbxRZlWSRPb!#7alrW zbnkq22)S^u60)(oUa~>i9Yd=X?JykPd&iX9RWi3CC zNbQGRoZjX3dtf!z@6 z`LTEEa9!ao`1+iOk47(R`yN@gOuH)<_T)>{UIWrRoDj|<#UO6gnY=LY!p-<4ji$m? zZdLHKF!x`8Y_+qk)of7(M8M7qgwBB(Dx=`mxU>GOmvM|(h{<3nf4B4)&-*`Yy>|km z#+FGk`)%I8rR*TDTI^N>eOYGH9`^SrqZ!#00-4PlHZVv37VwrUx>TC{x6^vkRFwPT z3GxwFSBizYL1H|h$Hf(&n#VGgNLO|P=?UN!J z4Q$W@PXdmo=EzM&4{e^omDyfdpOxd>Hp8aV+EOcb>=mnABHtuJ5HP*bbcHMPQ<=H& zLwnWETlJdN?$jlxf21|D+HF*KTef$It6LJpx|o|}^lBu8Y3hhK_Wn@&>Zm4*fFkoEAR|E;i)1{9S-B`W&(AXc&`Boj?%N^6D zrtP*1(0u(%zsUFm^u-{okIsicHoRAy*A0<#XouU-E{u!CfAc?0D5kvOCf_}l?OMIJ zJRE6NF>rjXeB-M=FViRLtb6NR<+?BtH!f5Bdc7#^>)ZZYTnWstt*za-yQACec>S>IWzAL){8-y>DYdLx4;Ael zRKGG|qUafkIImXTC9O-JV?auv$BmYG$hv0vR_f*JEi2Onn$Qxc7q!XRk}GWEtf}vN zWK}q^-a7lz#IQMJ`#YkPl=GSt)gh|Tm!^U+86l!j6d$JxcHOjGj62OMe?TS6;~Whxt+v8vk*6mC2Cvxino3(jgInZ zd-QFDqnFCmxo_pQ-4^yUmiyDb{oa}5HF=NJaO;!qhCuU&-PTt=0Balp8gGcEVa{7V z#i4v^S0pC&(O5lrs#teCOS8pVEPgkq-JFr-T+Oeh5pRi_Rot|eO{?49ZA)Ckda)cF zm7Xu(qpbaHu8{6dv>7=Yhi+N%LO1ha4o}w{!DIL874`a0bsW=z>EJu(&1qjT{`1T8 zlHOaWdV2v|%Z2n)obi8GM3ztEZUaa!m$CwUyK563tqW{x4^w7q*LnL(yY*SIA*Cz% zN}Jx9v$lv`068ux?-7f6NPegI24Hpl`cyqFpg1Cr8=p|s&?wI2r#nNjxDrJaR&Yt_ znWd9mgc3PgQEQUj{jt~!_*q1en?c;9GC9-Hd8JWy9FOX1a4%=HKx&=0c@O0?T2;qy zFFlm>mdEirIOdh=#|>3eUs5-2ElxaGuo?X98s(_I;l7G4Wgm}rl0Wm0X!H^7WZ%#k z`quQYVlV&$+_qMx(il~jfzC6gi@mc%*wGeZ6Q4=y%GuFaHoweUA=jkbl(I3$jC$Gi zihrsefYxCgA47>G4&ehACfM!xB;Fvndfb5pGBQE3(gnOtU_BM!MU`jPBTFA{RwVqm z=w?ObR^R}s#`H`Kp_b!bJU?xIH=SmSbL$E=`-LzoEuc6l$&JS?tT^~$4g4RmIKu{} zV%hHosahP49;Z!<9&tiPJ+={Be+OWI7`3(;|2lL>e)34Br449`^ZU@*nVn8pKO31% z%M>*HnGUNzcw*UlC0(A#7N>25Ar`b4^IQ_51+HeET!HrpC=FoyGr1kAfe(f*VA5nW z5(?APmauS@FlGFxE`o^RBGjL(v|9G&=iJd%9TI$oQ0;EjX48nGy5Yg83{%J9aGb}?I@^9S+L@!NoH8}UwHB|3=5 zl|1Hhy&Avs-dQvM@t;~t|2l5J8u>>5zB6{TkYCk$=k#EHr9Za*u&Iw3GO_b>m)90i z4W{t14C0DEN_cqkHO3J+Ej25pUEbC0g(Eu0vI>YK3(MMUa-kihYc@MyEsya~NoApD zIMn>jb5+G2@1d~-=;R}`pAMyHMb^Pb6u+(gOECyx4r-Z&(0|SIVvZ4asq>sFJyLr8 zvjDOP(4#m@@RXxy(#mdWyfJyK8zcrYc>)~H$VDoBw~rGVtO=h+-Qy8jJLrQ`kCpi< zUnt{`Yf593jV@EK@D=rzdY_nonabExx!ZF4-}jmPvXqpO9Mu%Y5p&Pu;^t3=(3zato_h zXgPfv0kkm%MRA)HZnIJ~)(OMTapG1}6nQBXvl^4&((zLv~<@Go!1U6 zhnCBKNK#x=le^zxQ%5PR0s0(L?z;yB&6m$&NhnuNTe;s&GRg+r+T}&c-8^E0V_gu3 zey)qfJUCWunvZ9{S1+?+9;U8~#dx7@{Yb|cOfhlgIfHAyP_ zkWJ*~OM>)Fe z-xvyoFiV5 zIB}-9>LV``xF~tbYRnScCn@12XC{;ozW8+WGP?i>W<;4uyes8n9dWS#j=LCB%p-J@ z20i-un;h+gUOSL5C1MV zt+i}2*aA^!bYrDG7(&ZCB_O>N3-*6;^4j_V3jjuOG$+arYtK}=&&$$ga29KWyj0Mj zNv!!Jt#wOFWlK7Y)b)!tsMrn0D2!uIhvODsw#6|D5?nafwfSH;p95~&uSp_Xp@ zR^g|_giDxa{Ii|d*F3Y=?mW0GEO#fJ;$0lFAJt|r^aaE{nd z$omgby_@|qt{X=VLGO^lN0LjD;OfP81p;Rm{xH~A6dr-_MbWkWpcDrFpOv*MYvYS17$Xp(8R(w)1ESj(rx=XlZt08fU#?eRsbiLGI5OrB}{JjZEqD<*a|eYE3h-5h^ylE6wHDw`TD7cA6ckwqfp}UK=@Fq7y~%<%Y(4{1w)D z05w@;$!281@Zy)iX&ew$&{x9A_LEe_*Y{mTQ*l*He4aQFR26ojcDHawiPcT;bWLGB z1JT&sRejFg`H-af*4bjHS1kB))&?e%b4IeO<&%q)ds?3Yt2lA#8>^{Q?LN6K*pbcjT4a>`ZpoNWh-^*sU>ht ze$7AxO6V4r)U9ElD(w%#008?k;kZLrAAO3P5&cmwBE?@V!j!_ZKRWwWr{vw_DyEEZN z?;I1W1@OYt4l~Lj0y6#T@fZ0m!(KTeiVRT zt&nqG4m8vK+sR^rD?#g6kf;X4?$;}T0>@7PZwxac4ndiD-Ed8K4AFDq!X7UA@gL%6HBg zUycCV6DU%3!{7cyIBXr^ap1`Uc?DT|6nH<_evVtg$STvu@s$d&nHWbfQPM%ET8-1Z z;3bdf5r^wiB*?b#lF%@Mk)8a6L~DacFX9YKXkUYjj7F7(iNBE5Cb2T)S0)vSy^mVSu$-{FJm_)WtFTNK&cu zEd2P5Vp;1s(pvP78q+guFOG)xRF31eg@ay?0E!{FOSN3xrnQY*e2-Jf(h2b?ESTE} z^1U}C6?!?ip*R4iQqd=McOg8hRXmtLVJcz+M$hCNfM-7Ove~y1);U6Ta zwlQ{SwGne1ee22HQsetnnV5@r5Se_ztrnqbSOK$8Jyto3za$(;S-av!4wGpK%h?Hj z*Y=&MrRgcE`S#0mY^oZFKpF)s;wUBt=#@tbHbz~M&=n1^a)OoTkcV)%CpmpP9@6(v*LUF=xpdIV{>#{~V7bXcRm zz5)&rIbP3x?>PRVc&K5P5=9ejI^LX4;4CYwU#%UzY=2?8`$X;~GIke{z{Ky}oCKZ3 zQIXdp>>5B|A|Zb`%vA&a>P<)Rpazf$Apqp3m^&_X@qE@HK<&ha9$F+Je;6NS?RTyr zhm!yPW_2tnYm7}?8#s_DASxIFg+#`RqsRG+=y4W;A-ThNFxs)dPKVKQN9Za^{o9&6 z5${9lFJr6wg%=%21=%CWasB2%UgGFzAs8r-7Zx=yyc|U&!Fhv70HYxl>mY=Zi>%7jE{9+h6kCXeM2^mwlt|_4!7`L4 ztRSSJlyX{O9|G!9(LmxGE^-xO^&n6p6DbXmY~=kmxtm|y9bibej{8Uj{u^}TmcAV? zga(L8GBL8Ad3{@>GM-}ZKpmG9$=q9%SP9n~biN2^`gYyU)(_2vc7)UaJCjBPCS)k~ z$~1(lJng%LW{@LbJl0wEH$vp#zDm-rSMl`UiWe;LG$AJ|{{R?pwuqSB2-Ey1JyelC zJO#TjSP09m21?pv3l`=kjp;B0LAlrlUB;H5wlLe%3;4%Ntk&P(rC?-Z#LdL+&0$So zyix1jLcA^tYdWWn(2uDsjfkH~uvqp~njIM^0tk{YQ3>I4U<8EnjX1yzR)yqtgMw;< zseew09)<}02E<^Y6WMrfQB|q-i~7a{;-PT|5C`QGK_#d%{BWBiW`}^8hKjf-8F~fc zOGXwVphpL@BmNtb!2H`K`@y3C>lEuzzJ2+^<8=BrPfs6{4BQq`NQ@XCKTJjX!dnSy0lrOkG~n{vWLXPyn<4&>XHmDdpWm8 zFWP@-1P`l3!0QL7sr-zf!LPB}^*z1|-0g%HluE3J4nGlu?%)jcB@%@u1e^*z7~2>Z zp!8<*O%{x)Z)I>cWPH+h^>NYrvDMePi`dX17#&Z2TDOy;WP0H* z^ZV?HRlr;<)AGSLQ#lIsYd>OwW%%KD74wi9DG$aC?;WA=%O5qobmzjeQUpgzdDEiLOUM8Zi9Vl;szRomuXNZ(1 ze^A%(VQOuDwZ&qEhBjAB`;@z@0q)E#T6hvZ%;0}gVPUn&J4$0hbrwvFfFIa<=s?qX2E}5YduW#r-i3P&Vn&uqiP4E%c&(!eLgqn{{@2oq;b%!N(_@a*a(KNNM1chvCFWAtQ1^|DsYs`^*WIscFN1``6hV?(Co3)uzr6rsOWxNVz=dgX7h zL62NYgfJ^#s#>rW)!`nu=(M4g{4^feT9>`SvnFG-N?tT%a2s8+;U1Q}m<>9CNG?b- zP>Wx!8Ekdw8udJs!?qA!UaT`XSy&{Be^U&nNn{ItvRU)av9@kJjzTa|7ernCfLfEFd8(O5)PvzI%cS> zfiD&PyDUBE#n$-d3|~Wu4QhknM#RS4_HGvjBUuWyM(**%z1u3;Eyb7~<8*>PBTE>d zpIQ)UZbcLwQzrZlCiPrl*iX8uE*b=WLsFXg4VgoGg=(CjOM!$h>&H03pTDOJV=J0p z>$OLjW#3$?1#Ql_rCJb3Zgj?lCJQH6u=*Jq?7>{FPJ~mcRS*9Q`;t=CKz1$Zp$$XC zao`}sM4u@6N|;Imqq^g@7VRwMw&siERm!7ES$UY+pFb9l-3pNjeonmn&^xUgrwVpVu#pS!cepWkc9k2D(V= za(UN2=MW@aBSTE;Zp|JwOxLFGu@EmN;&}AHZDMf;t=_PY{E65-tN?EOri{%JV8myaVE+G zW}}}=9OJlS^|phoTp}rDJ!9m6CQQ#$;B_xUG^9&WTjbf2-N3na6G-_rkX?N(&hA3zwCjM>tH!z=XS zGUW~3M`z6R@qCB@ECt$S~tHcRN3=%!LiB*ezM;t#vqqid7&d1qO;VwYR&9!K8QysjV+}(SfGBQ6NAFQ z^U=Q-_3t*D?ECDQsDKtlt2xEcK@PDb%Fut&*O==Ey_eUrnn>c+A1+;)k9Pl zgdk~#^h8@tE4*u#R_u;|50XYC#q`KBi+jm=BHpdnF8o|B8246AlOI>xuw6z69&tE# zIaN~ACQ906f_zsl+hyS(&0(}+jo17QN)lHEEDBRS$uSipt#gp8jM81_s@5CSbN)&- z18Jr}WVB-FkzYrg#WN}krLj*{9VgB07#Hw})>F|bOsDY>D<_JOlLUZzo?eFLT zd?i_>5@1Gt?(A}SVSxicmD(wsvBD==tE4|3IDrnv?PQ}?O}_KVd|t}NEDT5s)6E!y z6FE?dS^&|59Er8o{?w4achWHwaL&ZI)9p0zSl4hZxTO?@RKe)+2o3fS?(s2V?Dh(g z#ctpzrF%Ehh&JLo{YZ-nG(!L!bd(+TBi^74b}q_xt7*FVDF~>NZRjlu6*6~w#fa)) zR6uM8>T*|+woQx$kI0RR_X-u8;-fqe{kORi^B=8X#^b%VWa74bPRZW znqHYC{>gJ;dv+Cno?*YA{L4%%1flS-$ku~ovpx`ON}{`2k#?}8Eq@X(CkQZ*2&ati z0J?tZ6-12F?9qUv4T9-I3@zCUM~HqChop>;yidFAt$Js_`e)It?iza$m5vOhEhNnxN zY!4h{o$801uA}$v39Wb=i&O8wg>;o|a9-s6#fr51gJ{qB(A6I|w zy8XY(L^!fy)XKy=mp0iRWur`KVesvRRVqh7uXlryl(TKaLLAP({5>HVC`x9WjeqUq zd~`nt4_K@<^3F*`$VkOQd2AA~CS@tkBf%k9x?Us83up4Atrf$*adu3&G%nx(gR|C@ z1RWt#VQGhc1q4S1v~!wvr0h2KhA6rnW*dQuwj zmJ@Up1|rTiV=DX}IBtR_=RBF*LfUW^E(ZG;@CzqNavxTc94gqRzJ^ao=&@?25xYKQ z!F*F;%slo6+dXUfxf4e3pD&`NmumFwJ!)(2D5|tXG*@S=`#9+sCeAj+rK0}GdVE>0 zG`m%4YiOcqnftgO1s-}B1DhU%4U2&VMqJZGsY)O*_y>uk!8yh&MC)`e&VZ>%MZaDu zy>g-m>LW~t39*Sc>Pd?_)`awoQn*k{T;06m3rFfVQpX%S>HVLt^8IemFm>FPP;uj|k~xr#{_6P$6P zq`k0TNz8kdp*R7N7h@yCI8Xt4)C`nlrb3wseqG!M%8mcgmh0NDK0AZn&Iw%-D{Z*4 zG7kXYcUjKtj)txEGZznZeUtW?q%`@#tXw^Bw2fzxTi}V0EP)^wor< z55cd4P-GP({FX+uR(J?E^Ki?nQJ^QJK>JV<{;X~_%W{iyl1VYN5Z_k1B>S#6JKtzF zNfPIzgO!C1yJo4bKH`RvS`c&gp)%l{CM*B!wg!$_t&81{v%~fKWqZM?LkhccfCn{HO7&x} z{*f5aQ9Y0C1jQaH%hmw11RX}bFup0}9P}ne93}x2nAB4{P^N<8kvqox^>5{F(hN*#3Rn^KMuMWSc5-Q>n^Tghb-+IT}HZsj|Lt{w9@mmeruJKy_0$^QQaCeZX4AHzJPHfOw29Y?xSMW^f}z#J?Spu%>lldO-6df> zD0c=?R_!_MtCI?I!<|s7RUxW-v0u3}2;UWvu;Bg9XJEm6Y$VQ^{AOHQhlWn_!MLE!Kj?XQZLb z@@xd~tlf&6w$nNK?U?)Bn!wZf`$dPZYfw0#NTpN>0ma#IK!Qn9h! zUUhm&wrWL>vye$owg-nvEc^_@U;$g;5!Z~@#o0u#gDf&}wtgtW2VIeF={77SPGm;g zqo9!E5pK>Ip*g6DDP69S9l{C1Fc;(|`{$8YJx(GAh0_jaG}1m{ywuJE3>1ellT;^& zok}G>6Mo%}r@hBll%8fNfru&!?{q*4aeT*7%(N)1VVt-xGjX;frbiMJMh~UMpo(&p zOh8sdt;UtH9^OBH^y0xDaO4Z!qmX*r(4DG)xTKGkYdB_cFb?Ygf~MH`s9IBU!*7dH zhU)?(M~klZ*P#hW3+7dkL^aG5uD=ChxQgd`=*1BsqBcJu-Gxgs+SD6{A`8!C8cCeOA}&tmTH0(dOmi|Q;@(FkIIwHI4`dnQoXH)QeXB=A9u!{nCf zx6&znG{?l5xVAnV84J0vMHq|w1g#)cR(cs*Oy=VRlm`nOOCXQs#x$wC2nnY@5A3># z*%E7zSu>Q~Y*Njjh9dtgRSc>#p`tQpZzyY?f{;!?T8 z8P!3gEAjR{&<7~z2%SgPx@z}sDF!HWun(Lm6+lQ-USd=5i4LT2W4bZIv40*Nly?K* z@sY-Y(Uqr3tENNZgZar9Wllm|_e3m9Nf5dD0k$D}jkw(bC~kg96>!k%=qY5(<=wTM zqxx?+{YCIxi<;SBe3 z&mHA^yOv;f4s!H1bpaZ4yINFACxAf(_j6Q*CsG8@3}DijyYo8pWU~!(k!D&Ps9%pQ ziCY|`ij8o_e_~!vmbhzYnpB*Ob_8v+@WZHD#=^KtuI)}HDC|zNHKqpC{uu8<;nL|^ zs0$WDQ(3j$)wDgoO0Gb=;T%Mld|WWaErdmvZ8>A3ouacV+euy#;W3e`jBLDigV~h) z*KGy`ih{sFE_x1CgC9q?7dbe-9P~6gi6g{yk>$c+2V<@(Jj-aJdF8Us@o|0?uH~>T z7N^z-8;(dWT1uElWFrECAr@=G#VRTzYq{RILW{`m(FMsHbRE5(T-u)0!LP#kW+caNLnCY>gebBYwaMrR%1$^4Fs`H!jWSGSiPiaADCdL= zT`72O_yvP(D-y;m?#Vj~gWu}1Hl@pyL>_S|F~vbS2bWvv!x)CqPu=IOWMZ=2$M#4p zR<2GWo$eBMPB%^p>7`oWB37`}XER%iz#&s8>lP~xfaXg619Qflem<0%3OQ#y^z6fuY!e)tA@i!YA9kta(eMu}637@ahadk6mH@%Cz2cbpHzOAGr>XbjLo z$Piod2f@mP94>Y<9^K!NsA(5Xu4sLd3C za3l7XX?w?>j24e_4z(ZK9R!7gj?Jxaam#|X|JCGKHe-)31NfwCCTJkFhlT3r^AJEq zlkmnNnb1von#`x<#-L}B2gOfpTzflzp0H8ZupqJ_r35TA_#%hDv4J|13bZCcV? zhp@dBG#-phs;9(2JmRPBR4W>9S~3fJXHHao^fF)q@FaU4t*4+WLFSxrw%^EllQ|?k zMru>;k(MttOQPga0x^fy*t5U-+h(r@8$@IbfD34>ghX06qj#+CPAN~K(h1OsI-I>ef; zM2%JxRWykfS6N+BSFC#opZG0d46oM#>75QGhymex$ z$*$N}J*@(cjfHsJWq$S z|2xmTip4+!!pONEfkS-MuH!g^Rmmg=z-wne4-I)(ct}5rPR>e3a4FUrXZ*{WEva37 zZ;0k_x019u%1=gC8dK1WR)z50w?`fvE#1Y7bh!Cz@v<=sV2ix#L>oM&jXE^V&h7?vU(}EphUJEa4C34G>jx*hUdE9}&eb&L|-3`3mzqG1M+* z=v_8N3}55US@*ohP`roPSG@UdmmIaay^^9Og}9IJ2D;&Uuk;%03$xqS@?=>_WVZyX z1LoU~9nm!5d$3Fr7RmN6Ggy4q=hauqG-GjrDi5@Gnpfa-XXcA(ac@S{Y)NgY^Lr6S zBMUa>Q<0?pON1fbqDl0tts``DXxljZKP6*WhvR7N$p^%YumwZAku_B}Io&9}!-V6( z;Jf?f&(R`R;&5W9cn_V^saZkXgIgluuM>=m>~)B^NXC|vb#W5)bDC{PAEPExbkKtW zu4tI709|t00a>vi^vPntbfN|6ZJJ8KIBn)|DL1*gcaf?-tYVG2PZ%y#2%;VTs`TDE z6>ZMo?4zaZyTu@lWG*|Y^Sa?EjB;mmX|o_|@3tvNG_tLq0=98z^ggj3Y(tPPt$lHP zZ@MBpP@Ylb&o)15yi1zdH2tXjKPjdZMrqnHG(rC%8)EFn!eWJUqku{$j!T`fyST~} z7=6#k`KekV?*Rua)J6Jam~DuW%Dv_4!=96Z_S;uHl$Uy`y%eBFTE?0aW)mYnYVU;_ zqW{`UrurHmX*ZsAl-c+}pscC!-N(tTkVqm2%AVmXnui9q<IxGnhdUE3S?y4mlk1 zqyJQlQ_5z|U>irJ0+}^Hg}Z@u(h;&fk}+O;7V<@#Azte{H2C>)|dlVpUB+Hc|*09NPB$-^ZTpZ%xt z5-~a;8*RUY-hj;Sw+H*ld+h;LaKa$}Ur(Z&< zq61(6vk$J|mJ(}A<1uZx13{W^o%boitgNF17xr*F#>Zx@gia@oU_|a$X(N!-mvkek zCT=WaqHK;rM=JsoafDC=>(IHF48F6PPwOZpCx1Y~iINFKA0{uTN_cX(2*q6Q`8BNn z)SzqRu-5J&&+G{^s;==OFk3QlO!=*LwpZ)biFzB_At3?O@V0y z3Zo7tuILrIs7TJGz-)8@GvAn&c$!#wOeUjv5xkf>StJxN3R5E{BD?S3sMtg8Oac42 zH(i?cOP_WTx|NGTCRv#)JX&=AwqKjZdMP8QgyB_)M~U|BqX0|TniV1M_0a5VCUP!0 zEJDWSlj282+ohCQ>1t?h@(pQIK>{-@ns~ljsS2&6zhC7~HdwSu?i4tZMm*Kz;zovW zVjUB>RRHBD_mw-y$)VFA@h|hXMDbaNE>Uj;N)cL;d8QepRs#A3%+R6=_6U#;n_Y1+ z+e8ks!%5Z*n+y=1u`CBP6km%ulz@^9&O}QACM%J9+EpEtrEnVDa$$lX?aP10)^j1E zGRlbtLkL+mXiSND1=Q+UQY7_NF#L}$U|ysZ&jkhN?iftW`nWJ!H_~SHA#_S5XQBB6 zh!3zhM>!e6xs!=}GzLY)T}3ZIWx@QIRC??^Ow{xYP#ILDaxexqVeCj;ZShXf$x$Lb zfqL#{7OnO94@veP%V7oGFc|F?Ins$2&F-oE@#3Z!9s8PU=%ET0hh}9gHz%MbDZSz~ zOn9<$ek3DdUN>NWJW*b%^H{o3Qg_%(VHizM6!2u_vqxU5M;f~9@-0PjdT7nQweK>;t79gOIKKb$^wniV8x5KFEh@3hRWm95^=R9 zbStu0%wAI22fz?ywa-EuB+9quz%VyCJHTl$6B# z+(&Ey+`Nm#eX+}YrUXRzlu`=F^wr{Gu{%;P2vlsbG&V}P|XI-%CHN$X8&%E*g^ zx?pdHSOe^!1SUaIv2UuAm@#DzraSW*s#9`^f6ecVdQ;T%ioLI%*ng6yLA=@T5xC^cz;2 z@hna|El5%=YxJUnmj0y(FPoSeZmmu7rX;EYql}(%tT2#Q*j1TY#(N)yHC4?)*yz_B zZO=LwzW9ic)aBaZ0*llUg@F*cDJ)AB-wb&KricW)34RO%q~Lw7%T|;KAlExhhf2n< z6TfrOBz=pU9kiqQmty>Mz{1ny-StQ zvQr_N(FwC4;t$N3?f7tbZfv2PF0hP7nfa0Rl^4<;S3!=88zlr$XVBfi{1^TLiWvdJ z*FPQSDQ(Hrx^UD;@r17JyZtaQ{yhgNDhyzS{5!}dn8wYYDx)V9@cHUP@YK@{_9qqR z5c&E1$ph%^eoYl+U_x%~utUfkpEeTaf=4~WqE?5)r6DX2 z0%rT9X(DAQw*X?miR}x=sHPLJv3_K6W$N&Jd9c-(b%Wq?yjvEIf@YZ*l&(Siqq*4{ z)-$HQRIDe23}{FNA65BqK%~S?aCqr_l&(#bdFT+GoeOmTTM3Q)!AO(=M__ zL`~tq#79NI8qRnD1F2Q+>h&qRNfkeSWA;-yX#Ds1J`Pi_i7L-JHEHpD@N+W9ao@9O zZh-q{qbN6XtKa3$Pm?hbO0Y7qUnuj~CN&+|4!B;ldWvAs;tFU;q$39z5&xRXcY=t=Xbx;A z3NU)IODN@G%Bw)u!kiGYebdl6h1cc7vtTl*gySk8hM=^?YIc`UcfRXY#kw4VgV|$P zImIRAO=H{BX>tP#9AQB+5zi^QD$S?64Mkpdz;^5aiJ>{UiP3AajZ~CSr#zNaK&v@8 zFhyb*no}2$xoOsDq6&clYSI)s5rcdp_83JCx5438#B|?xVZ!3sCJV6;9%7UwTV<5Q z^m1a}?J(mgz}%)I(~0D2>+~;9Bbd2{E9vS?_Ez_KHlYgoR)T@lSCLcb9|Ja*M(=wi z1e!@ml$BcLgwpS*2gL6ZeK=&{cec*~ebB!JG)7C#%&4aoU!eZUh??K^=Dr1QTw_zU zlzP8AJ2A}wNqNg@GlGE$GFoIBLc*LJZy_*=7V%~9 zzN%8}oLpSeAZS@6NtQC)Kw}BC_184P&?nWt#YJuf#fiiC0_7bqqvcHozCCMR#y)}z z7%L)*EQRAix>TZLx;4SFybkk^IV;hkwMIw>M6sax&XU15H^TrJ4b+#Sr8u143g=%P zb>7EW(+79A{*_EY{Z53HsPvfh~5hD3iW)P$6OO{<>?z590lgaeLi!3(AlPA zrypp)$xmn%B&HmTbiTjb52Yt?IZsD)QO)%U`11jFo;><|_;dBY*aMtDE!=#Z12|ao zaBL+4VqQ=zYTG4A$cVPhPy2bB_(}iC^#RSb?0lI0oLel+x(Idr{WZVWxN z{fKv9{BnG-yW7->Ciu*|9xkChk~-5r4tV;eP`EkkabNy(zVj6=8LMNe4*2Ks;NZsI zktOd)8({F;>3z$w=DJ(#WpBca*M}`YfDfQj#Ky`MMt|-1;M?@v!`;_IpfJWkm)Gn6 zVcBFk#g|=6v;AwAhW=})r>T!fi0|`gZ)v7(Wv;LH2M{s_YhmgBHalg^c&_+1G+$}R zF%P(V_LeC2;_UPJ&xO5LfH42--iAHUPKi)ZK!8)~`Qg28;bG%sM@VXEBdMaXx_IL8 z$I=v+W9*y4*XDZn`etHYcbsK9_R_@6VcS+*@x+4J9#Ot z;!~pHHGvJ=#BeT2N~9ur1R*_5$~5nEw%Hk~aDKd}KG_(9Z=3T7cpmQB{U(>ctcRs( zzF@7bR%~ceQ%pT_Xg28(`V3=Vvtom2vmagG72wy5=UN3MgmIrZ1_TPD zZ7I)7YBdRfMHyQ1Zl;gw9#I+g4q=fz6T^Zu&OB3oAmz1W+fv_^eNHzT+MGwrnf{gS z#*H7T8~>ZOEQerzPH%35fr#x~Anz8i1KOYM?#52+R4=w^5Z00%DEl6dqn?VABUJ(?wt!qr`P_mN zbbk#?R%4{_MwXry3@aVGq?pvRbhR`ILsKm6JpN1xZCcALe}m}+PI{{N9^Y4g4C%!x zbxrLN3GSHhI(9YAXT_lj2$d&ME6!*Oj2Ra&rlkr~60Q^rJ&}Xim27Grc%TSN2(9uHTR5XgvHon&Ks=RbgFhLJP2>EUDAf0q0TznHmu&Fq3MT+MN6H@z6kSy1I1oLU$; zxl35EB>J?jN^7Z!VZ0d}SMz@k5Wz&Vm)$n>qF;7zE zb?{$asx*)D*7NbsS%KgCh6G}M$De5GnGpBWxKg|tPQp-|ReB@m|Hq7V_4H#;~ zME5J1)9XvqX~PIe1vNY~FUn$*r5R_SFcsxda2dn;2v~;j2wq7a@}qBkkjflrDXZ6x z*~=1JUXTuaO(Gra$ZugH&~4c0+ypuF*@?jve^NE!)c5|U^~P>r8mE#J!jamXiW|V% z+aW--Yp9yZ9fZZIgk0 zxstvl)kKwiuL@TLw<8D5M#!~(evxV1bfj)hA#$pxy=gTAyQI_kBivLoaqyaDFKmH0 zq?}qhE)wgRD;Zw6gmpE*7ew;@ccI|2IA1@h^csz}pRn7_BBx}hjFT_95-bqEViaD0 zWiEiifhwr}{Rv4;=Y7CukpeqN#;V^4{p?1wMQ!XCW^7AnF4&IZnoh=_`o5{%Z8FH$ zutsS`LMONa7wi=cZbEadwcSU}T(GcTt#HD|zOpm35~b|(sc#c9p$REYk4gV*enAkT z9%-JyCkPx$f>T%xj+X!aQOeG0SuzXv6tB+hrLlIR-A~R~?;CGY~er z#M*~MZw9%DI89NaCW@wJx>u|zVAN?C?x|C$GL1L^)pBJFm~KXB(w->QBs*psE#402 z>TE1}6wi-w)L)X}Q}pY#pg%7B-ap@M3@Vvs)daX z8pA;$1xxc7{aHgfcbQYnj#?Xd$6_u51%d2CgJJ6_#GpM59f;e4cOYcL1c~CXkl0iq zdT{z9(vSXgLu(Y2k(3Hq6rAHvOzLrnEF6UNiy3B=KSleL>eRC^aYjFO63NcMB;h2N zMIiF-xXmH_|^ZUc;MC{T*AU+X+ecHfe`nI^uE8#=D4Rag6e{zxR}H1#$_Xj{goP1(-r>nDb7Fo1499lVYb|6$yUyS%H2M`sQCCH zZu#-iI-~6n%BJndQH7vV)5B%swIei2o>7RPto`@{zxL$%z^L^kbNUOR_hQf6TD$4R zj8xSzeI4}sNpC1AsBwD7?N8{Uiegd2fb*asxl9uBOl5~@C3H<1>DYb{Ira;_BCmxu zmuAQ9mhQnIKj~)scO~MXo|Fl-@B#s-BZy zg)J_eCWU(lQt-bp+0yU!)1DyEI4n@R0hh^(aJcA0x)@! z03kTW%r7_u$l9Z2j$#tC zgStxT{>ws^goZ{m5qZSR0>1wqqc&v}NO9?J#GH5iC|q{J{f)fsk7mAPrn>FZLR_s#OV!WlO*E!dTB`6IK{c-|>GYM+y#(FRHS^(1_Ku z7M9LaW0@at4$BgJ@bWzUe1$LeUD=^Hvs9MxaSpY}^z($NdZD$L{3$`l0x`_UMaP;I zoO9)n7!4|qCoIaR$)JYTl$9tJSzv$7CO3%F?9Ih`&9kW*LAoX^^Q-V&3F|bXq~BYf ziN)t}qKpg_pX2u&Nj<|^5m}w5o5*wms4mj74BGGaIZO9uyVermQBMRsYeecb$G0=0 zo}oOrhvx@n?Pa}^K5S`A?)AA0)juQ&;$hMXgNprUfd&~I-+pxgJ}d@RbRZCwV+o%X zL0ru|RZ!9u2Qu{~7YB$yHmKFVQnBwD!aNMEEEpNdY9NW~8J)vFWxY;T#$}|5J2SyS!*hOfEfpoX5j>cS5+1++V)lv3?ITzf2=~tv4n+Dm-ZmJ_=SX z1ZDA&P8d|2kUM>zZHmmtNZ)B`0V06Besdy!QevUX^u)H6H%r8mzsubnp28wt%Ld|> zeuLTwIPHQm%TU@pg(hb*`dj)f1*H+doU%c6TOuCN?9g1@c}CBM`$gxvBBRL+;RU7g zwNDRID8GfE2jomPup}5h+)X@2au?G8$tb~QTL3!9OAQvR3}3A_C0zVofMi)rvk_)Q zQ8>@G)t;OX7WJ>tGaS3b(ezZM&V8+5s4E3+@XD1ky7u9gYEbsZzZ);A?xNxH*cG^ zM6=tml@zgsh&V{^fspxnB2^cqB#TN@st$pmRmdyix09hqs{l_&@R1H0s4}CowaC~I zGqq-ZuH*?PCCA=|maG&Qp{22oLZ*ZIg2QX$kFginq?o$iZ_FyD^IUpsqJUB|g8Yr`!(60b2~i)WD*B{BO>rdjze6p#1mpRw97p0j$8kQ% zZ^FviV6x0R)a?`l)RiBUqTMg@Ru99UvG5P>kllsESa`4c-GY|su)eeCH8SpHPq^V_ zyJ&>~S1gD=mjBXk{8J?eJ#nVEg^oi^IWN>g)+svFS~KnzSuMm?P?VKpdPe=#5?^A` zTwS?{95A1vg(S&iN&f@INvF7Gzs&V@(74it+&(L&>z&lbRM2l9%p}ZvZ8}b~lR;0q z9#zAa?}MPmLx|K{m^_J9%|==VElYz{0F{VzX7t_D1XY9AOSqm6D(MLb!xXL1GN*wj zlP9+fYiw-;#BLmfhhgj~S)4DCC#{A#m{2~|P8m*>>B;|TDB>VlZCAX!dPcP-xuJk5 zi8-+x3s@_;80RMAlWPnnFW1{&3AZng5k{&UiP(h-u z?8RO+&xH+rM`d;f=i>i*P&{MY7Z~{TRm)Jj*JqTgrI@70g0YhD`D7`!7kTtS3E#uA0jw>+SxgMJ7if0l$I6Jd4~f z@6DYutCmzZTE<0kk(4(eSM`tHXZ_^}+=H&a4v+rRC(`hLo)R3L60(*BIld}4I!-;U z6MQha+$j_D*&Gl) zpAYPsw+h;@YB)dksuL>0b)BL#ViU9^n0$xE#>9=@>pojHenOJyPn7+Ou}HXTDW2jZ zh2|TZCrEH}WvIn1A30#-;sFIyH;V)X0|b)CI#33ePecSS6WM)E%kTa!KKDFGiJfRC z{xa#^xY9b6n%nJ5$^ZTC;_W)YykA>;9f`b%ymaj^^zQJPy_@COld-Ko2_kjCTxs2N zh4QoGavc3AeVW$z95u#8xNB;g%JWIV=3BdI`{X>>BUM4z1Cd{R;{=UNP?B zZ}RRF$X02Zlp;s1wk%(vgc08S@e^N?8dTouzG6t`&^FSL5#9Ccu!AHdiuC8-beHLN z@$fZ6@lzAH4%_y>-G-r&u^(uEf4!RSkXmoFWh(Jvm%y|W172l9Fh1VibujW?ESQsp z&QcY>K5uSs%XB{l!BdFx`Mp(vlE2?|1K6{1wSZEZyMTb6ktt=oYX{E8veyUqmX6Zd z>!j&S$DYCC2;ZOeg`x9uUp5IC1U&Y888{tNoX*+b_cNrHJOH7WSN8eqiI-aCJeL89 zXJsWaC>W8|io+r_)t{VwIX`+LVFOT4EPrD9v*dPn^&;-3J6bNu)@q*Q>NlsPgEc{C z#=Ru<`Qds0yLEHc9jW03HHa*pqEAlEL zK|6N7^??!)$X#m)HOTJ%J`>mJQZ8eS;ahF}?o3o#b4%QX4ggU9J9Dz!$1~M9Dd!d&A)2c z$j!ep$i=ipT$fjqv|K3MQ(Y)*wfmb7Ew8Z-I_Y(i^OL%D+Y|EYDbn=Y4@H-Q&RdH_ zs=fd(m zt{*uJ+5>;^*4s6CT=!&feEj_NKGwx1G$q4Z;;gvO@A{{K`@AcbU+H)2mQFpfoX~xm zapEFy)|IJXiZgd^D5#l86y^7oduPwnBC=_^&>JU5UKwn($W>06oX{M9)^B)JGC)mQ z0alpX?`Ac$SDuV)hCy;MYsaQxWa(W6)#Rjy;P&fX1?&J(*4s56+{Yb(wM+rZdbo1^ zV|L&KdmzxrY|VYt7~^N3#o=@J%j4%xqIeS9X&1J!-vRHMf7@|u%YvTkgQ-_KlT-Wo zW#yDm;!Qx(J+AwEDpdG;{4-ew-&Gg&QDi)0aNQyA28P~vsiqdv{##T*ReY5VemLxI z6w5dKvYJT->r-U*Bv%5>b$`s||KOLk@2 zRlG_cFP~;%X(=x&D;W8L(b#8MU%v+bp#LxYvIW2>g)E%8P`AJw;ywsFt#OPkm9nug zb8#?XCZ!fLoI$B#C2|ZNos6q62m)ykxxs{;&edjEuO0CGfwz9&YqOC^nP464ayzvF zn}x&&J)6l-HJexltB^F8cYqLN`C{}JhIZFm{w5Uycnb{G>Ua9{Oz{!-0cflZH7GaB zQ#xP{#+6yM71DLCb3+Xoy1!Rj8IMh6MDJDO{6G4oTx+!blt9Vr8Z-9rFD`6RJmy;+ zhXQMPRc?oT!Fl#~Q@vS+62lbsHnZz zQ7hx+?D5DTehmsOufVaDCVIb|mT7<^gW=o_g=FKCVwlU`yBD;l4K^D@} zp04=UjzKZU0XTbb5(!Z{RGg;sh##E(;%J=FNBg?sk0+e5R5a0C9#G?6(Rjp9eq$C? zJf&qh9$g?aI2w|`(YeTYeMS$Qps)ec@>V=x!SJG1&dpk6|3cn-YH((V1U;h{U-rKJ z@yYrMyUJ~s#8x~@VKCx3ji^k@4%87;#SfOLuW7+G#pHUW${_Kl-xHa7O zd)ei-n(F10*$3;vG#BX2`fuHA`jiwIb;NA2+qxH0jpK_0IlCiOqr4aE>H z7P&|yzXuEpW7Jr|s<5_oq_ z_pYOjQF=OR6y-3|UzFDlS65rJ68%A?mLK^?*V8uL{fD%F>6~wT+j+%Y=G;zct}>x5 zH{p-nJ$H7CczgS~I#&J+RLJdr2v}=JAsK!A=%+?dOfy#WV>u~!SQ+0mhgaQZMs?TG zI{#B%I5irHE(-+;pGoT0A$}g};!q96gy?C&WEfi1f*$%AaL@jg_U`dqX^OIIlybxO z)FqoU?}Nyp$0gy37=3bp})f$CwFSOI@|%_b9Lv!$QB>_Vm*}BE&E2N}2LfP4sn--n=wT zrC)nR>XxGS*l&x5m-O$;$ba|*Zm50J^=lox4n}=c>bkn>KKc5U5dN?+z$A8yHPLcY zy2;!hY!G>#B{ zND6cRToHLhV^AHQ39)z~Ml8vn#%H_?DC%jbP-PN_S~Pqqk@NE%z7{KiehIc8#7?Tg zqPAwBE;g~211hDBzUeLmt%{ba1b5BSS&SwcF8DD)ZZ4!YnUq&~npu+pYp`i;2xDLO zTjj{2ojTXNdwlzUS<3F}LD=nk>m6c03wDz>jB`9&ueN0EYE(SOse>malF?{1G}}n} zUM*N!@iKE{c1SIkMLCw6>lS!_!79hP6ogoJ5Mip$h)sH521v5m3Bi>bVm6f1s0+5i zhIYE&=0#%HrmKbWf2UxfTMSu-KGY}(rPP*;#Fh@jydZdtb#*$%F|XL;i^@F7gtA~G zu9Yp`e|egAkqW;}akRBZbT!ZuZ@!pwU|`)WfLX&uWx0O@n4h; z&wrGS+CeMUXMp8Zpwm*O?PB&fgM@m+p%oo%kQEy&9Rf?xUB4J*jyG-0!|JrIPf9A8 zLC1x2zWHc2jfpSmu(jXB_?tJ?4L@4S1! z`^{Wnx6pG_PKg-cn0%HEnlQGhw`=_V(4Z?9629?)%@G%hX6A(d8LZQ8>6ITr`i%u* z?{Y`cv#sZ0X#HreS1zvHTGS+wul#gzjxC`KS#&rGs+z(MUX&O5GF3bP>C7UQc|v)! zi~bgT(K990jNG66D)MzX{X8fB-&ODVbRL>^xY{pQtWmQpAqnQjW8MSin8_b( zceaM_|84@Li^ek_cBYtn-E*^hyUxFr4IlocPtX2!{o0lmwm;nUeYke1f*<+b5a}`7 z|M2xrVV*=?muK3lO53(=qta%j&40Smwr$(CZQHiZ$@lxZduE>L>6?giaqi+d5x-b_ z@3qcAO<5?K&Rw_tpZ2@L6}!$|)4;mo%6p1dgyM>sp1B@Ea;mGMgUow)ub@-MeS2v5n6uMY3u@2B^!%I162%$~Wn+tQoHGNE^j#E>m#=fvtJ8G9J^@W_sIX$s9Z=HB(|K`n3(o5= z_i-jK4`I%+vMYl zh%MT+Ro(9rSQk2jmjsl{+l@_&Rv>Y~dxi3vghjbv2=eAM zTC}3Q)w0v16tIl(AVsJ*%0@oQe4aT#TTA~}zW3FC^1X4rmo?;@g&=$P%jz78BUO+c zmdsTdZ~rpYrMDXV8>%+R^g>%F9xp$K-A`9%e1#x8^x;qk01^&#r)vTaM;4JKM9TIZ znj>TV1|Xs)n8?q;{mXMqpxM6H{wv=b)bR@QKl$FaKl$Es+1c@~Kl$F{sY%St<3--iqE%SrVkxm(7|hZRBVV4}od zKk5(?-Y_g0<)eCFLv=r_YVV)Jwi#qYE_Uz45z}l;9t*ynmyJ8niK@<*72}loVI?Sx}ogX?~9m93!+Wt!c*FApf*t z{KB+m(ks2oGQ8wE0_*_*=Fjo}u%d?XZEv{HnERWWOw~?tD@;5g!q15WC-l-n|1$U| z8?z)CPMy*M#*JN6x)3S>3mLbTdQDM%%2EnE6cJJn2?{hpZf5dgkmVU!NSMqC(1Y;# zjbsa${nGa;2j|vuzAzE{TCue-h0+@4%uLDy0+grfSyh|mvY-Cf)6Jw zr)>s{<$qdu_?f=;Z*#EgR^j#C!!7i`zquy={Y`29EsCkJ=-A6pl2XxF%qla6Na^#8 zdbJ$(FZ1brt0o(*$kC*4bxB@)if=lO{`U*|`drrQe}T?CZwoA zrI*P=^1Hc$^c}w5PvRf?Vx1^{Cp$sJm_wfXkNAR1K}Ge47m^C0|q7=Vw_OE5N8us8;C zF4BWdnzH@mcr5eNwDXNR*nz}%MJS|8wO>;U*5cSeT)ML8Tl`i;snzDH{r^XfPUJzRbNhEbD{ z5XKpS9SOtD>6j(T9@enKDnk23b+@W?9jWvbiFVSVMHD?s(#Gal@ir~r*TXrJ1D<4B zAj?&|PW3()3Brjd2LHpR3ZM7=mXp`p!!f@n&;J8*bpHqB2><^>&fcYN@wz4bCxi2A zJHFz+by^I@$&`89!~I15sXqZ@UatkTm9NCH4mW9RwtveikqlG86QT5n&%-7ODW)WT z==F+~2<5 zPVW5pT6L|MIdyEUk83C$x*ZK87856A4A@o`zdV_D$UlErqC)8XA`POxTD0Tz0*lA| z#DOPXAy4R0cCvTlNyXis>dKIPVkt7im?wduJ@Ft@V9J-oAjnN;cz-@zyv#(WN%DR@ z=jOQQR;eTWlQjo&xJPeFZ^ku&m;pHbZ~bOAi+32)Cv!JEm00F=%P^prU=!3jN0o@>z9^wqz@YWt($W;e`Jpq=ca&{FR58)z5ts zRJrFQqW#1*8nXn_q|)L)@(uid%QsLz@{N)qKXP}Q&X0Tp&46uT@zp++M>_m{Mnj=R z=wGv6RueZrln2eVF3FY>agkP4lAWqvFDnxMHak=P4*QvI$M^<8a|mkRbaW&jsk>g< z?{IcTNJ6)G9Jf2Feo3$OoFn)Rd2?Z$q8`#u=)X z;@1+aFPVS0ubg1DY*sSf4-VZG_pi2UgcFAO`*@_uLG^a4RLNGP0G02_C09E(UK_UWE)!xrsm548Fg-U)*x5Tk zA<_JjZUd3wiwf2@D@31jP%qYf4}=l&IR&M)CH9B`dr_~11}!N1mn}x(?jTnGUvBe` zA%+@_?EwZUsdX%fI(17799ukQHYiMNF!Z5$3&EC~OwE|aTr~f*x?Hr*oVmtuLJovl zf>#_J?S6I9sg3qZgy^T6cN~+!myS)#TZJF(W}4+?2S=<@Kpbwr5$(kJ0W6!(=8X;x zPCxu_-czm18v^I7TJsOmpb*6j(N(cwf!ddInmMt6w#FZ@NCta(5Qz_KrpX^!R#-U~ z-Dn8NttCPvHTSk4{$^(zzR?M79$ciug{1&Zt7`W4p>Z@rfHjkkHYm8a5G<1^X0Yl& zK@-()W5meQVXQg1nEKO#s7|Zx;)m{xj8~-xhE+(p0g;OC7>^EFx<>{Vu_Ucu8<@U8 znx5iafc$C#fq!g9lg(M&OmmkE(0+Ywq(i@<=>7@hrH~;-wT?-@Q!WU!v1)O9Qg}j8 z<>Vz~%BO&pDi}WD&Yi;O8mlJK!>`dqSY<^R?eb0@UQmpTdGNkT;oVO;?_QObNw^aL zJ#q4D{jN}2LKm#QPq3vez6gQE7%a%qT+M zX?Qk)OwcRlLWFa2?rh$>NSThz|IuiQRJ1*tG_ytDov5BNbJbgH4eON}n;2NA(9TiY zgyX7}qWQ7hwJmdUYFNcc)S8!%>qEYJu^N~8VEG?GTX3P=jkl}H8xgLNHO|kSp0~^S zgYO(L0;IQ)G%+)f+DP2q4zLQy6LdC^X={H2eijV%yxDXo^h?LJ)7>hT=59i_Nvjlr z+^nLn15;3m)100GfSSBSsB zQ>^i1;jWhJWotyhs|`f$Ojt-)Y}I=@a}aQ(Gw4?Z2I-m&h=Y1QfkwCe(p`b{p z%v|Djg3#l-%R7n`)K7aPSnNOHw zK1i7{0d=5j> zyxWL3n%VjH!ObcE|CU||rK8hAf9OT%|3oj0|C3(UIgtLV`sC4?%6wWFg{(VIeHjn{ z1VG~WP2tgYiy7#8rjECsTiE?okZ2^Ggah)2lAX7U!S!%+k?)-&Mu5Rb$?$2S&qy%I?V-Gf6J=9(iw0B9y__^8ENYBqrYdvij3lpslc8IVGpyhRZx4Jufr`X9~Q@L)cub;&7D!|)%Luk+tPMz>4lH1 z+{Z|3STI0r)l(v?Vtt7Ks(-JV@h#)fyYt_=u)Z0*%Vj-5TV18JMKQwrs)ens)sHuL zduc_Rs+!YUI(BBHs<`eWVasTd$7+!bhe+=wiy_MEE8`R3wW|J46Z1-=?>P0c0!K}v z45U;ZEavjvn2jSg5z^sU9)vzpeWXP+r<&U%r<6ba3D`CUhXS!T1=|5vRlDw6Z6&P1 zDx(=E-v<9`_XS?{Vi>w5{Ia=iM&xsRF<+j} zUQU-U^Q-jTHm&E@;O}@**YP-qAM}=!)mkjF70AEDRT0SJ`t zdTWv7u&|mwB~zVrK{VYK(&=+PJli7?f`)F64(5RFsu*kGT$WBSqBdPa>{v%-JdASU zN-Zc6QYdbO2HxT~A>>leM>s=jPNH4*;dx3^O$G}t6~+KnjU=|_Rq5`~7FdtLl*ccl zzHJ}L4;-jogFQ()@A+)0sEBE3u*jI+XE{fBH<3=BkkhHqEzIlv*f}|TZ2fdi84@jXZcLN8`V;&8Ytyc+z?5I2(_0An5XX(ZSi!Zr z8-Oyq6x{({kVIpOxCt>U=yzNziyiRnn)O&DXf|Vbv5C-$xnIJNVTu_AQ2-AX#AF^2 ze<3&UkUyO$B_>}Snl~2K?N4}$&7;mOu*#Ws!$Egj&K^{}4-?n-#x1D%V-G5Us`mmBBXnER=NJLpw&JHk zRl+qHVX-Ay0kf2m3%u<2WC%JQE{a;^L!}YFtD(}8R03hu3Wt?T?W?+{CZ4c5TqB{_grqXeIR& zn*pBBlN?N8+`14**qWJ>>!AB0B5l-Igt_-8d z{i|Hs!fP)(j&|%`y^FhGl;QyAzw+HWD><+1n0tNKEi3kwTlf0PEW?`qJ2VtVFQ94} zKDEz(cbo?f%Vc^wAry2XSvu8=sCy`Sx(=dGB#eZ{7Y`n#`S?ey>F{dyF_yiuvkk|h zkc0NMj&uZ>rM(`~UD&0p?JP}oyUSRy^biF$;c6=k+ISPW-g7bLoagBTLZU_S#Gobz z#T@i#`E$M~Mvusu|vJXK=%=XcNZ9m zegOuvu4EK=zerR9$qeuhT`Mu;qwP6e5 zB3UZjt{LY=!i90mp4Z%t_2$}(!x+uAl46135O58uJJ?!MM`Y~W86GyG{PnXiGjZoj z+mjnQjvemOp#EGy>bI`<61rMCutwb^J`It*!EN;$bewC?^$79{yOn#9l6y-GfjKW!wNYr`xUHD%T*a>xoDW##tz6_z;zHL0On5`UiB@NdT50#i*1 z*SL-5q}XKzX3NlLu7I7AP|p~@vmwP76=$*shHAUaigXFSmQKMQ^%lXdLNzP9i*icQ z+O7X8xwgHON`}A0UC1P+U4+x zL9+nwDM{c2KmxEz00xk;sX(H(2p4oHt}I73|y6-V~sg2xq=8AhEa!#I4qbmadExcuGT3NY6OD*w`o*Wd1HsQee! z1T~!MdKfD9?)Q_oXZ`0_P|b$vM?f);kcP8I_)a5F$L1Cs!FYw+wwHjbxz=`oRffkx z^Yzy)dcW#9tR4OMGq5iGx=popJA~1r(ukCRYH^Hs1D#UfYzEXF?BR$V14P3gX>+ex z)=RZ9FXI(CNe793=D8TJ?b~|hC#qmrhMR@E1+ z#4P+V!VPdy%Z*)gNaz=`^aK=Wk)_SZgdAIgK5R+pzhUs4xG7V9m1I!x@*($S1W>+i!9`~8w{W<8J%W=?3uDF-Hx^1! zO@;}9X(&B-1^cPJ5iDXxbz|cMQMu1&j$MwKBY~HA1-2Yj7q5Q<|L;z?mOy)L9?8!M zU;jUxaOVH|Md3A9!j`Pt)*JYOya;Xfp*6yV3eD7KYq1LHSwXyk`+5)xf_M;)QcZ=WWckgWj~KREHrXt?81qt zYEHT~RkQ3oEcE_*Y5soOwf5$cCTriHrNNvmlAf_<+0^VxoxJ+GJzIR(BWt~sJ8$+6 zA9dyGN?W8KYOWqqQ}Yi$SgZ!c_)saIwd!oUL=+p}c*c*HxxUq5^0TiVieLY-(!`gm z+C=)dAO5bDf(Bu3)saTh{{`2RxdnGs#InX;vmNB6C!(ZjXlV~piXB2w#7tbTp#;$iK>ly~msxcBfP zNVEA719Eid&15M51k@?A0b+AA8 z5XJ$>k?XzwyOHhT~CIc|F~e$Iy+|Hwpju$YJ`z$_Q=? zu~#fck(o6z>jJ*WrT+_G{O3u;=vFs!MF!1+&$Q|}zxRh{BjT_pRJC8})}(8WArza* zKG8$gGb7CeEUvJ?-J}Eu4m?@+Te2i96kLs zJ?+KEqs!O_SokJR?f7HEPfAo|!Ghw)9{+U+1hI+#D9EMJ7nbmP0YwVbYU1ert=0)dj(%Viq*hc{xqyzdhbtK4V6%Uq`$rX zc5}yX2gLew`m+#Gv}>Wo9jVSLvZ_Z0vm(Nh+Bj)6t4PAoUny<5G0T3tZU{;A=>n*|p~*%42A zUCfta?1!H0rQQ_}9onPou-J`1Rb-?hH!a%$){z}yd#yfkdrO@%EW?(*p*L|wZgmM; ztZDSXi&#>BQHzQ7Xi`pm&VXg-Zs+=8V9V6?kKKK{TUM6-t%iiEl2VvjW@21BA#8|A z8UI%#B852$s*vIFW_$ji4=*0RPYS%`LYB!#eD6;a!)!dz^b-%nlV3m)u*>jsz6Q$H z(VKw?pX8Sle+o%5DVK?A;MrX5_xs?@SDoWS=j|;997XA^P?}RrPa0#J7fs&z?wzD= z>K@YuP{(+R$jupq7u>6f+2d0ItTiZBquAwTdnckezAPZEg4ObTsh(ml7S3yVI?Z9*Bn!bDr=e_c?Nn~F zi>!$EB6plDXn@qQq(urZ=6NZ@Kfe!`8~>i-b0U`g5d*Vp(aLw}0gFD?ru4Z6*``;w zcFDp~_qUGH^>WTN72BGXbNPH6qxIq6H0@q*BVYduKC+@o9+~w`*~(Q)u?E=j=YcxMkgwwB7(BB0|f_g7rZq5IqR`5^wJ{j znJ-ABT8)poPM||Ndo*!A zK^hDTjs_nvC(EG3AVDPAm@m$N{3UDO&q@oYeqAmTr|$NP9dF7}F5Z=`bvbBx_zAB? zPC}x0hP-b4|TCW@j{BFRou4li8D+gj4^ z0f!`#D3dpYK2Z!tO*1O2p()Ym3nM6`Ybj2MOk|dFKXiCQ@`wC&Njbv5(olT}tD^0H zX0VCMU~?n(HGyuRrzd~;Qyg!D?pKq4wx{Dv;YW~vo46$R^#J;V_Ln~i@C4plP^4~j z#Bprw|7Q87V`Uj1EDo-m>&!SJsX!kJhX}c;(xnT~YNKphIXpukhc1@u-Y65@pOqpu zq~jhxeOi4C1>#Ts908=B{oCI!C(Y0Od>|MgJik~Pn}>H;2}N^jKVS(;ae2k+REA&T z_DE|~XTQ%63Z3sU{*08l;zTkq`Sn?3JJu<`Fp;XhyDru&P^C)sc&1V~FKB8&iw?kW zUSgX6nNJQq6oVL-(j2vH`CHcbG%iw~E~vC1yA&I8`nnc#VH{(ntU=q&#=>52Mg?oR zWYk>d9T~Q|(8aZmZ<2tlUJ0-vtX&$0dPpu!oUGVa3NlPf)LSqp?YNaOpB&0hTDppL#IWbQ?+74Qhe290kPI!(TZK-sk_y51+o~&Rx>{rV~fhLX?)2LC-c2<*mo8lBUzOCCX!dtOd3Dcdmna;>@FU2hnR!|O^S8tYd(pjxO^90KJO zyCNhCq_`4juRQ-ka9veZG%8cQ6DE~vuYI1EJCKv;J0R>ifq6D>cT@c?vdoecRopfJ zSs1cv3B}dc)?IP=uy;OEXMn|*}^(al=I0h1Cd z%Stu@mORX_X2g_1)H_LOTe3{2v(}Y7YScs%UWryyebNsYWq#|JG*%Xgk1PO@TE@3PB6RaziI67%7Tm}L)m)5&=`vvhAB1EwXSUWKq%7$taWA% zg$|Dw2mM}=LbpL{#iK}hrCn`vR{nVMCnZ)Y&QtP3C(ylPX=+0!p7DDo@)pn83YRC+ zXrXvt%gCqg|TaC=zm1$lpXPw zP?)1pkoE23*T7Js^)%f?D8S}{uHv)?R)%4RdP@v<3yd4ZYB5{nR2n>j$decr3y@*= zxs@|^AM~C-p%eOKa#mP%VbA}hwoF3?^r?=wP0LpvTGiMdZpYtXUBqHg`vF|U7fM)SBB0@WWYcWHoC8~`H()h^{ zfqr4kgPH_gIa11tLvt>6+(MC`_$2xxAlQeh@#{bDVX4VUX={iUy`=0zOU{&prjswzbVeHQk)3hL>=Tp`;2t zm@HOD@5wFdSGM>Epy);`Woo#7AlqA#w}c9f9O7D=5N=WFkIA?hFPX+9!#}V zVTkb?3KnY8KvAXKTKVJOyc>Im=95h4Z*f97ZY;u zqhs-}IMbZ0#Rw(!)3UZAyvNPkVl6n&wg<`bX$SEZs%NCbNQt9!%|H-;jE^vHTJIq) zB1W(Ra#H-@L==XmmMA64kPeKGZzkHIhrseB%6pFmS1qvghoIs&QA)_jQ zxN?<*L8qwN`?)#;hqOmPJl5PB(wavBTOw@=8(1QZ`iAyx8qF8C?Gp)lt*?z^>pwXY zg=_H<++;#h)SgNsx%e~xuNITu+m{FGy0}Vrxqsgzik2PfGjy{wKxwb7Lw5KGZyS>k zc0+dm90-p%Em5V<$`#w=ctV=Yd(9Wwm($M)9(U4PtYy$*(Wxg{ODfD9FA4K;b*IlF zWvdM(a*HQU+s~JTGF)u6V0(4dp#bok8xZaYjZ;`BVPKU;0(mr3Yu38*4wcIDVR*30 zRTqrKgl*kG*(t+zjiQ=TL;ybM@_K3Lc`+KZa=%3D#p8y$HPW}Zii#AokiSOo4eQda zKr#30oxVv`*}X?=B_V7On$y%80|xw!6G(H4*_PIiD*)_O3oJ7@b>+wUBr9KIQp?SQ zf-ghNSN>Tbk&D~>RyzRpR$O6D#`Z6O$)f0mX1kw`C3m|?>nD)oasi^b>~9qlIU;zPBf9~p*0ikL+J zO4>^bNPq~6&OjlzL%1?K^p77J_>ik3x?4F{=^18Pqz=+)!FCbXsCuq}giBm=S-cQi z=2~)ADp~1OfP;eRqJWc%`hn9F3*)AWzI=kjn`eb#lZ^xenac2Jp`@3~rOJWhcS&aq zLj%zcZ6obrvVX6} z`bT<)2P-Ue?)T&1a+5$KjLKQ;;0U#~ypT?UUt;aXquK06f@CfV{1d*CWB(AXmS=IL z{IA@W8Is_Y-nLcfuB|sLhcQokcq5cCLqbBD&&m|C;*^o%R}x1(p?c9U^FCRsB=X?N z;?=0#YpYEemBO7?yKdBU*u7O}Cij{bt8FR71E~?$#{OhAcLLv}Kq}A(a!7M(O3=Ti z*}_?lu3~*v&g+>bUCT>%hS6I- zbuiODCc80~Z}itNN_#TpI!}svrvvL64ieL9%rNURy9IS$wMrF&Mg3#5u*;sz*KWFhJ!;4aL8ZK#IT0nK&$b6>TP`F|WNE#ltT)C0`*a>`wFBeSJY};#IzTGG zC*6P1JSv1TIRBtC$0$vP52rj}0PS-g?kWJeQhjzF$_uAO4M-+%B=vlG2r?zie%6d{ z@H$?RHL-B?LFYLso!}O^@c2a8YI(7~5HgmzknSy>dzH*t+XrdV1ULb82(*9Pn+4Hx zhL2?GP6LYE9U;2Ebn7@I5AFtMXbJS+!+h_@$1boS4+r(0xp+-JdZwfbh@jsqt_~t> z;8D$8+328S;QVj8XSbJ|aPo$YVxyRAGF>@X#GNdI>h=K+QC0e9gvOiP6rlwQ!i0Ps+~@fP&lvg(c^%QJf{+DDwCLLAJmxafr*R5^RtY|?s1XzCgF&ULHa(6~w6 z{7tRkyx)iWlt)c%2mR&{mPijS4jd2pZ+YYfExjp~or$nVrOU z?#^4DKEelcctyV7J+b55Vmi2B0C`#%NZVE)umO~0X)6#QyDfO0@#r7RDe`IkkBs{7(;Wz5r?7n~BS8@252+RUQ*aCnaXrsh*Be+Fy0X2fulyAw zNn-26lkbh2eoVfPDjC9$Q%R{4`bp3a*L4A$FBVI5Uwm~kP7~FWi&$4xEno2d2xf>>*mywD zdtl@@tYz;VRA?$i(llu6{lMr$rF%rek<*AjUp$i#yElIFt9R6e(?O|o@X0D*RV3wR z03?z%D5e%&(58IISjFJg>35-n%?xa zgi&EAW+YxKC7)<~NN}%N_gz*o3eexJXvoSBNLQHzK;hHu zXt0HG<+Mo5(pX5iWC=l_UH6F=i)G;RgRsys2x-3L%)yS(J#Py}(A4Qv3KuvTa1`c$ z(;FLOG*gg8nC2%TK~jn++$#Vvqgyb?en9WZ%aRGx-21Cm9_NN&4av$&$h@6v0GkJ1 z%G2i?)ZJ@)-V(3yh%Xd36ewrI2NTsKpyD{$$BpVHHfOD+`SVnlKP&vSb(e!X>Fwwa zj6UH44O1nZjN^W`R=j50LL&rpd`UwBWM^DU<0 z4UyR-%YtAg6LH|t$xNym1waIaHO3Zi2w`$;kPk<|dHW}slYgN5WZri|b>jP!{tcLj ztjV&=phc8&nEr0gk}M+*Pnh+4lwT@|<-BM?V|zI1ewQDWe-(Fo3qF2Zj-Je}5YL4U+PTP)oBNy%(F5)pg>t{M|5}nIJ1Xw;qnb>z$eDeN{zg5@Fb z5$Dt-CLWJQPzO^MjLDJu6!a}%ysKVLVC|iOIGu39edQU`f@wR2TDE0`%%nd67@2_i zca5$t-D`{9-pIujd5s^QvKeGCB}vng#T5~5spc5}Y#KK8aDp}2Pe5saa!UPV^Rf)= z8Yh=P?`JeOesf+Y%t}Y)1#5$NO0qDCgb4v-I$6*j%tbays>7-Fw0isjYND*zJks+g zjIT+syb?;V0s#7#7Ostq7k$oNuj7>&r1FsQQOWvWEEO zFi=!>&7HwfBLbi}s40h0g`+t1BncaeOcQV1NB)Jzi7lSXsm+yG5b`P|6%9 zpHuV{G!dv>U;sBLKGrXPh#C4vH*;6oAw3&%@Hb*8rvj8|s8Q%v^6&NmJ(&HBbh)lk zt|`bjzty9P)Vz{6)6l=Byf97yEh+nU5iRmXu#}wa!<+ggK8^%)!?L+oCYdQ?6heME zNP{_XB=cigGz9bEhU$B4;8LR3)OsFUVY*6J@LdWfar+8Lm?&1R_KQKSeR~!iX`E=X zwJSP?w%JC7{)63SYV(8FOaY?8pYerq8>FBV*a$7afj=(Qb@xNb;`wtzrBpFo!lT3W zg0qV>T_OQwR4%-%`5&rzC~6uiu7iLPs(vQ)CL+#TEtOFUAaiXut=YWtWZ+I}xJ3Kb zEP-YS3TTziV^|~&e2Xt@gN5zrAzq{KNtVTygV0bi951X23~q8^g{2c(4;71A*WdH^ z-~u{-Y)Gm{Du8|F~Dr3)~KFMRzx#PbXB6dsCcpmX;aWUzr}+8TRk0wtH{QKWVsHui3X^%=g!shG=OSg0wjCn;QXg?G67k4>}rX&(Wd2#-Gqlc zML~ni@J{R_-@aYwc)mst6Q~~Ax><8J7|Ec!VVQ`t=B6w?D`S5vnTcm-m*Lz7VtiUi zH#T(PL0ea&g>0{liILSa~fmcZYH0>=hBei_9( zZ9!Gh2=wz-Dr|tAdInKZM_1WW!NjFj^$ly@rcbO>F*+Xur5k#rf(^#kI;M4m`rJ^A=YZ#*a$ zd|0tH0AU&p?o4k~P{xyF;xk>=njwXhIdzcOP+p%-BGE8zeD5MCh$+j*>IoApRZ*v~ zQAvSIMC$=A+La4*Y&bMhrTSz`N!aohl7B8pTB&*3aWTzK{(v;FvL#vh}A5rp{@CDv=UD z*<=JY$**|F?a~#ZB&OA`9ahbHUV8q!<07ohs?mc6$cTC)>6p$<;Te+Sv{IszC7OY( zS^}?X$Iv=PiF~4Habi>h4x#j_R66DJPf!*2ZMS;dhjF`_9_E#gDD$!-3%v?BJ^fQRiDC)@(R~R6uSs>X=GD{C{ z;EU%@=d|J^=n22HQvumJr4G+rt2ESJ*8wg*txTP`UY1M_6@nu=Nv;V%3&hG^a%#+| zD9TB1qwCrUZst)BwAFIcsaANlA37o}HuGSMMqovK^I>{*EWc?C?EPMi@6a9IM)~|b zPY#Utp`%;}?6JzZzN-5|Rc7Dy!TTZ4yGP&o)Lbx6bucE`enN)!Gq0S;yteS~pQAl< zR!4U0{mWOe_R;pgBN-;0y{hJE5?u!hAOMCVboqp!t=@_Vee?k9%a4Wsr$`tt8`$R5 z3;WeVp|rS>9pvwp8?2la+;upJo-AvMC$<^Zzhzp%T7M$(UpcSSASck?W(c$P9Zi=) z&)kxUwn;`S=(g$e4gH%4Ack|XVKyjk=L1$1Xx{BnJY8%pmEtve)A;6+V#9cYhDRyPae?#(T`4^777~=I2()L4n!VC zCZ6o1V4?wR&1s^?268hp2HYwcp;F3u%r#u8m@W2;v86?{Tr5ENQok60d6; zq?(mEFk;ZSu?5u`*TjmsPz}QcMr-Mh?vG`gjx8 z1W+e0GUIV%2x%8JY~R9>U)Jnh;G|5BShI*hd>wHb>{CilG*m_?)-Zy{cK)mlMN-!_ z?^%y`n)0w%w@K$Bc-6KQ3e&^;zzp3ZOy45-A&Dm^5__KZ8+-|vGz2DHL2pQ;MVLUv zadsi@I<4sje^MJL9aaT^(bp0*8Ka$p;GdS(5+W`UL2Be6^om_uWP3w3A2Wv zpj^K_M$^$RAvXKlgS>nZLrAf3XmLme(Tc<97K=JmVrE9KdJM0T34jp;`3HK*p=F|R zp**O!l4+|`PRK{^59-K`TUmvubYLas?_!|eq~7Y(HYu*?T#q7xnefM=Ks+p~j6?$# z>GqH|+@V%-2((GuEAdPZeyar8^sy5@l? z<2+2{P_BK&iXi940npig+MHT5{va^(X8RPUd3~2tfEdx}nQ}PtCTp)5hS5K2jGW+_Q#tKUP$L>4Ld}pE8(|y2dJvsa zKd%owqPMMN1xGxDC|p@wS5xS*pE_?3mkeY2%i}khNoJ{N=}(_TX9J-+`^5TgmhYU+ zUGtle%TfI1Ztwb+V^U9IZ9ZlIWD)<@|9<#F!t!_bG64{f{v{9)>i-%YwbM5>2GIZK z`rmUGI_3cEpO%j=Z%7+{nbFSb9CoJ-hn_B+o;Ji&qpYP z0!UwDP+p-{ehn`iEOmz`Ra=T`yWCIZ#f`HKmB@$(mAP?5bjjh~^~uZUxb$p?En(rs z>yJ(h8WQhbrk2oHm)DE0mBd>_Kv!)E4_rtf+CjxR+~js*1KvlGj~VuzSErWp?gTw3 zxVmF@3?svdL2`IJ+{~S^a+QejeFFA&q0|KROagmv<49vuD&82HJ>tnP%Ial`Jw-ni zR6f;I7}E>|J{eL(1+*SeU1gZUgbuEO`TkCUaX&NY33)_beHfi&vS}+7XlitVS&}i) z!7e)W(g}nW?aQ6BqtF}GisFsRWV7gX<*V;ivB^zGyQ>2A*{gx%!?XcEK;BOW8r;f8 zmbskVl|E-$7^O$(t|K3D!I(Lw>V4!v*qMRrV9|%;#Mg^HGC#8^nr`Nsvpe(0m@TT_ zKy1UIFoFsKPE3t;*_XS=@%41604-#MPInXXX4&uu>F1@Cv*+QWrl;N`x@b<}5M6jY)({|V|;G~AsI1%GN2VS!CCam9y_G&=V!(LrlclGY zZVKFxVPGv((3ohsq(@Oly(uYg37cULUKbl_z9P^`Q#G0oN;A+HY}suiN!=V89M$Ux zOQ=*8I}N#LolOjCtuk;Q{a0$a7$r*MP>qVFTy-$W`H2cUSm4BxvklJCNTmlGX?cBp zv%D|)p$Y|A1vGkSRzpzS0$!@=%`Zp^By5~DXDqgwM_wHcm3V%>UiM+MRyLTWe`)$V zcDlI!;qojNNHGnwiYKus%O$vOG8AW>veqbT5%;O(fr0{0Y6hrP(W}NIvBm6S440*3_u4${1o% z1hV2{&ofoArTT2SSbQr#81E{r@E7=Bq7!T_GSyZL z_2^RK8vzGssJsMCl}NH=yy@9DGMMMp2Jn_b0c_2eXZ}v;AAjkY=Zx!8$X63qi(m%lC$Mk15b@{s(-gAKoc^?uE$DXy8RCH(vQ!-|n^( z``(T`_UHc=7b!^S2J{_6Kv@nP`nO%y@-|_sX(cgWQggLnXRmsp_6RQuf@~iSh!vA$ zxsaS|@HOFM=;MWneX%1xIg`O_P|t8RNWSwHTqrGQ`tP`F*nB$swXLIUDAAa=U=^|A zy>{FJ1eM6T;~CJtIgJ)ccZQ@cx-5CfW{b4FvVDCqLM?`*uXPqs=}8@OEApgk@sChMZ=TqzNO>As4R25|7LCW?yzju6pAbH*?%b zeX4Bc1aA>H9mfj4NPx(zv3kz_Y~Z+_svG63$_wZEMw#P^HRz^;|)emu5yU zob_ZBsa@c5-coCVLz|qYg9C9kQ!3y;vzY4P3YX5Wxa$(Rj(e=UoS|>8q6Pbz%ofp3 zQHhu7G3j1AbI$5g_W%+0I%La1>3rJKtikDvqtX?1~Nw3-kz?UV0 zIoEJ!qm;^+k#;^{bDQUMhn)q}rFO<)j^cmQiT8UYf4k64SVY{}JC4vPsDyhiaV%#Z^ee;KOaWajG8got33H9!UCQliS!yd+cO()+*? zSXCgpRC^;)Tt42U9kvWz$BoxT59Ew*nXY67vF+McPUJSG^fu(7Rh`f~$29UGi|x5z?= z(S8=%R67lbFh?joMIZUl11zB_b3S1QkH`1%y|01m*EH#J#?`-ytVYId8>9@9r#sE- z>g8-(wPImHwBfFU;-2!hAjhfjqsUq8yb;!YHF+g(g3D|sg}=B5aK8x|SsFhx*{3LH zfdKrx&w(+!EE!w2I@;F6i68b@b!FlF;O-0vyh4dXMPRfAb>R8ixq;2mcj=Sweqgc$ zue>iXV=0qnW?(D;bkDmq*&3BT+N49C^dx>lbRR@9%X1`Ssp$BP8g4Il&gX|+a@sEN ziz*~**IZPPb5nnacN&CX2V#Ip(7y;IuQcL(6%x^ep$_P-nmCQLIlX98y-|HTOBgQp zW+>UX=J;vNWqhTw?325V{Zvf1ii{n0NBYOFT1$#x$9kPE&SUcH*sUp*A553l=CTI% zgbjY8eDL#lf1dWSQiA{-W(LNj=kP!>nquzzEWg@QE-T))Yi2Qadx7|cX%$r#&i&%2 zyVLbHpvl3|{@tQeO{G?Cx&oB3Q+cA#Z5SGzz%WmEhwg}!!&0y!)H!E#1CLYKYTQA& z&Mb`6J{jCN6p6r4ksq|o1mjZZ(vnmpbn^k71=;QzzAk*vPOF`7-%MY@3$!lMyEd!h z3?u%WM)hi)LtT_BByX~TO!0sNW}kbazZBZwa9XgPkyDOq`OQN8?PQ#1ae+{SJ-bRIC@d3P~VQrI8DA7(A&MAd3f$gm%2BI%$J*;v-82s<@tDf;2h|Y zr6Pg-)~*N?0KZ$04=%?%_(@u&*__gRPnVyh);enWtYg6eYm=NfeaM}XA(Lq?R~0V$ zy3@nnp+tn#$AXn0rGPC?qEHO4CrXG>c&sz?UoYd?^bo3r36W+CP6nkF|2YK;qHqcP zu*ZQhs@TEXhMX;rnN!nN>7MjV`ji~s)M;;S7Bwjv8YL51#@>(j!|UPcSpr#1^r9E{ zyPsBvmb-m5rLas-kr z2~k+vKbRo_uuy-}WAK@}(9r`nc%)3Ob2@CxLmCQ&nqCk8)PH<+&zzB;lOKkO0zBc3a zIw~fmD|0P2BxF#)+Kyvmi@5|8 zD9jiC^Ar+5VoLzsG3Ai$Z~8m6gm*{9ytZApppU0FkpM~9Ip zJz=d(L{ei2YCe(Fh+eNt3zkw!SbI~6#3A)Cu?6~&8M6lN($i4oaar?1VRa*`8vuOW z3DI$}fn#LaPe`cE2gK1(^#bRO5VY6Z_bsbn5$08YTY=BpfO3%Dv{@)8evRIc>RXgQ zs}`m8tL5fpZ&3Z1T8JN_t5C6Se$bW$m1|d}sMeYl6fUAGbK-XpA?d3qiVUd?l{Z$5 zulCv-S*oFyk#>;s2#0O8#mZdKhQ7on)pjYxRo9T|Kir4zo(AgiyR#>ZZZ|tF#sC6$p4}DVM1hCHY^s0&oM?qgMNb; z1?;rZ4*+Pes0`u#iKG?J75lApxU2Y}Pjy_GnU{OcX>*h=kD9RI*3IwKP-|$QK6VXS zQwX}lHNjV~=;K~{J2tnTJaS~XC?4Z#=Y(Tr#n8IImR(UNp0|Sce(->aa2QqHzErz; zE$h?m*UQiRUe}-n(BPa{JcI&_FmaMV3_c*QWHio!8vcjxj&z>~%Tw)B-2_oIYAY?E z0kij2fPW*$yj4Xl)Zi!k5dB^LB7oYX9*ic;X!P))57LoTGS3B)b~ z2Kp6qXM0sn!ydAXXk>0aXF;$j{o0|Bn;=HchoP3;;K&SR*aFa>hnwFG-q3Ru4^5q7 zfgi@6Tca$%|4zsccPvn}UTP-SFfMH-lE(m$FBxjX5!U$CGK=jD+&5Th$L*KPN9W=n z$zl{DFamqS3R4ne09%X`N7cjo!({p{@60vCH+5C(s zoAc;pTgv}_Tc?=&%A0lW)?4>%7TO6%v@UBF4qMitm?7B66V-2gC&+m(Lb~tcDgkl{ zh-4p~bUZ?7)ka{KKI1S}#jB5qCm+P{311)|!&{Boy5oN9Gz_~HrOxcJVPgRHntRNX{b`{dbx4$y z5XWbKkI^L9htot6u2*|?80o+@$=bLIH>pA!S?=dZfGBib&&cZY$Eil+#Knd$OfL^v zyT9X7{&&6C2slk+fE{_0j4WAU~qFiz8@2Vb27LR0x~)S<-=;X}CjNt{0tiD~}P?ltU5vIH*7 zRmRZ>i??v&_;t@)%#cpQ-F5f@6>pxWwjIuVaXDq&gSYTTD)f8vLh$)KL`U^N@O(xZ zQ}dR9As`#)Et~i7`Y?>WZ|NBOMkZUSXX`}&Phd&N$3UfAfR^>-QcNgZ7@17oSDLq& z5O@frz#CGgb5uTIRY5}{Txq7*WuV!`rYuSZ_ICA?aXaBbseG@Nd-fPcyIt!I>V34%e zLWnj9&L*us#NTflGZLeLmv(QZq4h|0_WwkW$IjEwW~Nq+*s%l>TMurU1q`9K=dB-* z43N3ElcOtEPJk_*@BdL(G=Zr+>Sc*AD^Bi@*=08!l7(kNq3c=^Aal~$#n{4=?eoXQ zz-!BdDu0O1PpBD6?`MF@E*D59!2r%d*fHuE;J?90rCSTf zkhVp#5+rDrJB@xl0TrlA=#nn87S0W-sGEA^%$VL($O0dR@pWZR(yj|AJMI9wwh#`t zZDE^2#Icjg0GUzcQNauq1OYqXgj)9it+44oaiJL&gf6^a!ry-$q&LWsH+_4cr>NLD zh+_^z1{A>XY`gzsEALQA)KA-!>N0thY)BY~$vmNXtJ5d{q8{O?s8e)A;>kQPBKgo1 zjTu8nSB$}!qsSaTPOl_Odb*tu;EOACSU;VSwvsnDg2Oi`HR`Gd>;3)Z5o*qj|DtRn z^HYD6AB(T3Gmrl8v-jvV#-5k974ul(q+dR5j=2`gmu8~DxHLnjC_v88Rt(XxJi8+G zXH;Tfj|I}5e!I$2XZdKzR;ddj$1pTjaua8k7?Rlt^d#D9E!9-+r2*m%>m=6K!FR^1 zzHyu^P(ZnZ=*FbVGP1j`U!)MnQuc=$7d8-2<5hcg`$`J7p8*qc9}&j7d=y?t<8Al9 zsa?;7lLsfpS3|QXqh(*<983LvwJs;aAj0I2A{}O&iDQk6`9d`#e~UTL>=%ti+RgR5 zV9U@$)IvlY--I2GXvw=Nj%vr-sPu#i;CmXo@^QfHx;YA8!ba=kkMyHrUx^`o?J=5W zuER`kUQ-Zh{Ku_|$h#|=*2_0_0y~%6TwTi=Rn!=!X4?}VxUh>3Jh=${OeB}f+IFD; zoh(G?T|+{51F6ZTFn)KHf!b4e;*3*dKEy;aOjo*z$2i8GCX=B%sV&#@>$VC%WGiGP zR%lv`mak?lI3_pP>GwAPq}o1q#BWv1G)b<8E%)tSd8fjga1k~h9hrB4^%A}xr|uibS-TnjE#^BnHM@#xqNip^Wu`2dp9?ix3dzT$u4`gFek ziR*v9dY1_B;qthO0Ru4KwfKR>*UR?zWRf+^vDIA?z*db@)fp82g(r z?~)$>h1DY;zmLz$p~gI&LmF48RK6E9ooejWU|Aq_ugNNI@`S>fQawmI-_A)`BEh5e zME+LGU;I4Qa2ciT!+bJjX=~LAb1lHnUn`4M=tbh)*wp=ygztn>sH-!c^tMA=@!z2V z^4`ag=Db^RH4Gyb7SctWpc~T$;mcM6ZDG1@bdY*Kcu+US42bq`P_X(hKlxmeW-E$4LLVb z@~KCfN@kpxaX23(xBGR?$sZq$KXT2#y1FOjKtY&B4VP%zev+TO{JXd+IsdS<<%^fJ zOoqVn{iEiw4mZughgUPf-9~_1Ilf|y+YR#67ecV1B{1APryheZcNt>GeigDy@j-x% z{XxJi{!n{oHMU;Z@7u!41u|h{JzeA67uuNE(KIH)U%hW#Jrx*T(a6T0S=%f<81+X} zIUebp{xuA+T36qfyN$CuZSDnpn(G1!*WnL^7Cv9MT4W6!590aD+x`vsc=7&oJACW( z`sKjge5411X>s`02AU%&srF0^-H9(p&dl&i^~oj(mym6GiZl9>Jj)ZuDeOvUt8kPB z$6v-Ai}CdH9$`f$2+w5!=PI*^0#w1NHS4^(f^A&qWdTKacT0N*zb4UBE}XlQBR7`U z3QTIc6Sh|MZ>#NQPc;Kk*`RTU5R=e|Q(J$o&`ENB(O4Q9it{YkqgKfmt^pPn^U&NB zeA%Z@Q4rTrJBpB1Et*<&^;3v|`{@G2mT?ejd1>T7O!C#iVE%F(ZgcsidM}%nb^#VB zi1r8n?zw5=32*ZdfTj=W6|?v73TT(A8wa~MTfsnr;YavEA%aN}lbdq#YPlEg|GpTDz4rFJ_;gVvxU-rpG6ItWRqIRA=I#X{q zCAGZl;Nm=2B{BD>n!TG&uQqB6Jwq*%BYhmAo%v{gcQJ0V!wHQn^28R0feYj2;myxa zFT)y^eK5F%m3MV`(XuVY;; zq**yki|dc1B(dn5ESn-C_YDT(RqD-!jQCw|8!^$s^egLDEu_G6GX;`7fAen<>l^KfdA2^*3coxf4Q zi)MXlq_tku$n)Z342j&xu4~~5u#V-z;93}$_P=;yhg~w^$Suf3dEI_$%(pSHg;5Cv zIk-?ef`?Il_JfdwXT2l({}fkRhuMdk(9?K^TC8PFj^x_4J&`Bs)EqWLsR61zY!>(E zA5rCGsZ)<6Bg;L;tdVmGeg)#Ix?Cvc3g-^XO^4B3vZFMZP+xgBev3YR{OX(2Q3 zqpwB0N66tD62>Lx#7DjxH4dea5P-_KD(uf#3IOhmxHyMNtM|~>eS*sf^uj8~*hvNU z*+%1<2d#S!+E6=RLU5W7tjC+ge1yNrp3&SVoGW)Nq|d8P>975Qiz=-JMw8~88N z4qvcHV&|y@t#=I8v^dG1uaJ=Dq7*GR4bJcEAyC$>-EU!scs}BW znHNp_1|r`>yLXYTeIKpeLu($yYnrlZeZ|w^R8f>z%^==lz?CI;A#pE}r{fsJug>Uj z<#<@M7;)t!aizU4?Mk81+}|$5&SzUwC?}fYmH6%qDNsqaQN%0oWnzxwep0YlBZ*n` ztbQMM>!UrNY&AmtM!u%KUNMDig5Hg(tMu9yfYJ7O^*=LSmcl=TR(}-`3BQb|UqQtG zf@uG@5<=I(*y{h#L(u-`v@w3dVt^iA_$Bx=Fx8v6Sy6%_u7S!(a~=-6lH(1qpP5(>VOzL55_Na)i;K`Px9VzuH`<_S1yFN3Z-q zFBdxmr*wfP;th_=O%<`kafueR(}Mzkwpm?3-av`6zt*_Wg8$+JW#>djQlR(eXlwlb zI<8Y&eVe!PyR-SLgo{?C><8?BBHvJ)G+v$levz49Kqtcg{wl8KHb%Ctj{gDP3@VM; zY|z7Zp`G%b79Yx4Hdw92A``ougNb1hNhF}s%h5AhBPEIX7p8oAhiIU4XwDIudC@b+ z3>!4$FVu3A#z1W?Ba`j6)RPCr=*z zx&P`mU7kggN~Xd{1IC*6Q!EReOiCP@tru$V=RnNLEX;&#j?GFuLe-=e3$KFl@1R+6 z(V`L!TJ{Y29J5i;`*T8zJ`;zGGo12-V3=I(=!T4K@IoEUMC>1>7AKHc0we6NfSm?9 z0`vgGdXOGv&l)Y|W<7NE-tAY&AgYPK;}<4`C^vHL`Bjb7x@EG5P3Kn`U$Q;*2ZE<0 ztVy6R*S}E!m!C+4WOk^t-6cGEm3h(kEgvhOMLe9*xyiiL3NLqrw@iDJpB$LilJrD8W52Wrw63*RG%8z38Pe)?z1pvQ8&UNxlsz zl3XU~QBkCHkwf;@F22e>pa>*Om>Z(1i(QJG^3h@juHD*uUTP_T;fEf3OJz3P(G zt~JG2dcP%7S-EnD*i>4lvv-jQDW_Y^$MPsii!e1FKTtGagHHh_Ut<3&n40=*yP!dDKZbyH^0(JSBH3Z2Fb|S$-_j8W7tQ! zm+bcx&SesD$!}Bgkch6eHPHZ!gvW#Gs+E#zWyNnnZlWAWQsgzbY=^ z-H{#KleEX!L}iUbGT^5`#@Ki-rN{*@560GxC}UH6WtQ;~a;p17quWHKz#ZPN2Rytv zdmhQ-Fp#f@bM!1|6Xz~=Ue0onTTErVaN+m?+l2hg0?hQIM>DN_Jo;;Hu6g7k&h!Fi zJTZ>+fm#MklBZooE{nvzS$FL{w1UdcK0{KT*}JZAz;cIoo>7T2Kw~oC;7^!nUTI*%-Pv3zfm)CHA)Zp|Nm2?%DaB#Bo^-{86KXX>XFHX8C zf;0-of^gbv@=}`3glvsbVqq`?AC|Xg2ZG*GkL(<9SfIY8o|wF{qQ>$l3GV}?sdy*} z;+zuExC*tzv$o1ygwKG>f{AS7DGv$$kjKIsC9Wp~@Ip(<@~#l~Bp-4#O0|l}gFOY(q$;uk(oAJtYErf5jEK$Dy&@SyCo( z_JRnjBzphS)^@_Q2>)=ZK#erM7h6_J#f2DZcmu1TY&exM?d_!|_eLr!T2lM}=c=Je zCKTLnGSaD5XxwP?H6Cwy=^3~IXI!97gsWy!H-ixGvZfkMz{)CseMo}jcB{nTHatDzE_%S>_0>Z5(6tbL^f!K>xb>*th)r#A;p>|Vsy#ER(-;~dJ z)bK!!!#OSF-~ADsWc@4bpXbJGq3>ahq-2!VzO5K;9T3jKrQkX3o{_t`dMkj*NsnxU zq*Uqt7jK32Z&=qnQvhOz5aJxak)(>+yYEMNL_*z07P7mv>Wt1Jx2P|&F?5e%D|GU@ zR(THU7zm+V=zwJ6j$kH97U~lgNP}eDK6$G~t2B_g94LP(XIpHnO;f|8+`)fqa3|ENCc) zaYvAFS0>bMr{#?49yf$2BjBd`p>Bg+%9vn$iKDq26+k!7!?gM?{S>30h^y{se8X_) z>2qXYw}$`*V&u8#XJU6U#i2P+??T58hlZ`mQ9UZd*}l~%AZ!HT1Jo>JUoM(z-pKTs zOPcJ^Xw8jUt7Qib=-B3N->6&S^)rWIjC1i2ka19XN&q>YE+R+kx@I+hW zmz9T5q!(*WS;{lYHv(-m$2^?PtQ-g8D&#}jtm)(;egxTqnauBP?q8WKJP~ltG{>oX zI$r0~*zRr>sD;z*vUTag5Inf;6qp{k?UrKfm#5|OUqQ9)3XXS=+|_8{BqufqBO(az zHKr>$73v9y{aHumCEpzuQQjG~BGjO^2Wj_V5QEK(cM3_&XemkN=)ElFvH77f{E+$$ ze#(e9@_;P@P~t46A4I+I&5U;d|B^aUCKW&bPC z;P(kD4&AO6yI)CS2&6Mn+;U@ns4t=}7ww@UHSd%g2Cvk$%!8+;SIr@r$-sXdaTdoI zwPk)%cev9nqPeY^Q%%BuIY}I$>e6DL+bMHl%MxgWV0UYBZe)lC>{erDx1yY7q{$sJoxVzZu}2+oT$G z;M>kk^XPlJq@mR-kytKl)GBRE^;yj-Ky^Hz3B7h0cxC~(KAO}hrD)eRX|$U7(;Xg0 zS3e{v6ey|hn;h$Za^MP)UrzX-HdXwhPVwQV1u3c0n?(q) z>X{t5W!B{vQ94pgZ{#P)Mg{@#L54jf7 zexJ<~Hh~RGe1gJ0ijY_qVZ8QCBucz8?yPFzfTYCFrOG6WIM+`=${8ES(EnP)`&mrF}0=a?acG z%#qk;f#JA+6sWPy9urAJNiG4JVwMt?GxNiC{T3nG38XZ!tmpI7bq64`vo-x0MkD$> zxkI_qby-fjD;lrf^VcSE!a}uaCFfwsyi;n+QfRRC;MEjdf6*thvB2U`G0P9kr%Z4o zQIOqXFD&MC^zvMdeZDFC-nG-7$UC#PuQjcrTx_*^-eBs1nYRVJbh+31;A`Qweq0v+ zQf%iaR9axr#Z6}`g=!jgG+8EDJ*oIyx~=Sk^YXYm&v$D;w>iVn*-f>NRNEC|6IK#B zD1ICj{o5*4VY?aa08GD2sWRQV{q^PC-)iKU%6B&X44>X{QW`!y=i!UfsC?ZVOu zXl+(a=_!IeR$hbg@8Hx+xSDP(md4{ubPD`#HCYt?ycT{kKJV8ls=*rz%vp5 z%U~aBs%RL;U@n*J?d{fUs>zP*7Y&83Fu>v>jCNQ@Rcoy3ckp(ol!L#gcF!tv+-!0% z9ftf^UMijlY|+L&i9I*wO|YUf_It5y9H6Fef^94z1tDfK<0$E1(y0 z+*pkxA!IvF)@zHEv-3_9uwDfWsO;~lvEw`0sVf!fS}qU}P+VTxP>m?fXnVILw6BYH zQ)W+23Ez+-;VhrhNUQEaJ9|IZICMCZ$=|C}(E<+}5eyiO(1N{@Ez)Vlq$=$mtu4+Ja+ zRp6bzQke;Zw$+Jyu#AYtQk(%?+NVz^>p)WNXUa%~4$XU?pq`TZPf~yecfshpy`^}* z=t5ieWuWLbjGWp=l0ANSFS-b;YQyGG4k6z)>WQz2<|G2Tb=tBZ{-9%EO^6T-{jP1{ zm0Jurt=ZMl$br<4BU8($D#SbM{m8+%l0D47AbD-r<)lGZF6g7x7##J68pWvY(WYzi zNbWAWV1#0ry6rc%!VHFzW1pV!#^x*oJH-R~B=$`FV1V&Ru-CS z&KaiZNS8f5ys@00x0AaeDj_*u>7b9_%CB`=!VYE}f<32?Oj3=h;=N2vkiU~O@$rB> zu84!a2!d`>LkHXy=t%m5IbDQg+{&F#doRASpGYqAp+xH@4&L`3k76LfpQY!6Ntl;Bpy(Y=i5lIzQa#P%gHeqs&j|Gm>qNW$?fnLYHv zx63R9k%OsW;w)^yUCNyZvHUUZd7#|>)_7X-Ka;G(W&uv9U;qI8Wd6HbV`OV6=U{8+ z_}iy(wl=WQH@BiSwl=xcvb53~Lg_XyTi3NNQc+eeLn+rNQ}~H3=X)K=>EICxC*|)K?mWm`y8AE_>&S)cp}%FZmXAZ+ZlKWOMYau!gt4Glr!~sqt|S(Y+qsQ-LxgL0~-NOcjRG zu11}{)+71}^BKnQ4c!UaHEEi0FI-5zL#!gIcQ;ppOAH?dpX^tH+fMXCfSs&}2i6`d zd-AA9do)A+g#MtNW@k%#G=T+`T=(Yn6c(mIjmx8<#1)YxjBvA~dwEG+Zb5Oc&idrA*+Iryn;}r>3NGMvOEZ!lsq5+O!{qz@zhXPqD|NPqNPcQ>r82qvM1gqQqNfu>OZNK}NKe7+tmo>`e*U4%@Mo z3A_HJ3!%|Lirf}PLMDUhWcF;ajzr}3z@KDnZ$g$kCyzTPf}FSv5xy2^Ql7bP?}03y zfsYuN8@gdGeU=ELn`wUetF*JrH2FJ}Q2x$`Rr>zv-dh=V7yK$KgG4q%()<%!(*+=* z$ITmj2QI1mGck*M_lRF#*1kX8bpMPe^a7IX2-i)cKkB!b&Vm!5gQaTa!bV9&C=G!4 z;}2*Ygo{<#-F&8M7a2&KwhsKqP-?W*>ea$g4TMX(xGw4Y1We0@#M?X`Kdl=>^{*E% z)|L5E(IrjQ!uwI-noI<$G=4qPXU7F#UN#xGp1#hiFTScR^)c;J-Cs^9b_mL&+v#^$ zQg6Oh25w|tHJjks6EEFr$AxJ56E4(bDYHBNaL{031%ZphwnoGP|Isr-&6rb{4H(+D zECJI@$KQ=uVEs^m-^^9v=xol7nkXY&*Vitvkj^m zCrHTb@19<2qs6+L>*j+8zZ84>rCJYyxC+!y4H+8u`H4Z_&>SkDO659FTdqXvVrRZ0 zW$OGgt)Ol!zD?3MnI~9KkZ>9{X+Bl;WsPbY`$ODI38$2?IpAo`YzrXBf+5u>`(t0dYvT-+Z%z`3>d}s(aPcYBjS>}OO@Fj z*~W%+&O33WGVV)^gcJMG=>GgVI?7~Nq(JvDwZlcEk>5gOoV?I69nZA<+-6HBS zgo)U8J5qO`i|hMzp*G=O*_Z=@D3}_I%;ZnpuXIR_;6R-MXf3WFK2E&ebGy8Ht23La zu4ByV!Q1+p?VC5zbL)c7J33|mi>QisMB56wT?aLK%$1}*KaLWTa&9P(&8Ei`QsQP9 zHFoe2lhMJr$|YkQ5MYhIs1P6^GaYy8GBAkC2SviyQ;&}mtkuFGg|$?j^V-ADdE}oU zoJIIf-v;rVU)7Ia5xgDKYZ|xAxFJuA2c)|(8FnfWJ>NP zXrq-{wp%UOcnnWHT#%H5?!XYL54Hy)*|m{O1&9rAh(!R6OXpTYNKQ9YP!8t~Xo62p zs_m2@Fjc0Z9mr5?(^6-IO*KNYa2FmAd)yw!MkI=<^N>u{Yig*W!3~ukP0V!PH2=GZ ziiE!W<2elD+1_==@98Qykp)wt-I2}NII-}r5Q+ha!&=q3pZ7P)IK2dXc8X((UazM!_uYAFcv+?6OqBGM7 zh3X}lQPBkxodm|N;>UdfIccx&^|4h9x%~%e)60zzb{EzoUQ&j?9247^LBHw1OhAVY z8#5|4C8t_x5s97nlMa!zzD0^Y6!6SsSSZJ_jxQwa@O7bSXb_0->MnT_lhi+K$Ggz1 zUCC(VPddI7enRRxHLNGHq~Z<+67^Hr*ucFJn{1?jWRw|g5(NJ+bN$rgp}$s0_=83E z0>O}D2E+oxgOg(z1ik+-Yc0tkz!d5B#v%p?z6T=1gbkj>$)pN3YVmN0!vc&`?Tqyy z2rnf*K|qt0$H@YCCr)&ei6K0t4i%Kmhl#PS(9YX9d&7DOjy!FS zPEhHgj<;Zg<)LU*vH8sS{L?QQaHfy$8lyZjq$7tyaF3EQAb2a`|I%)av2`1_xKx$R zwIKz2EdwUpv$+~LUhj}>QqA$cO=(v#P#iuU4mO}-;F}`=7ej=>c!VC!wRtt(L}#)J zr|yE-as($vs6V@6G~gUf(tP!$foG*P?#M3Bmky|-Pg3_o)e9O@cJ(?|V_pkeVxPS|==$jmUWM zqv>^yGAwjWF<11R-2r39Z{=uuji9=_zZSaD%ad&Joh+!fuXw|?$$T~49BRLDY~mkyB#TnH$q z&9Ap#&_;s3Y~v05GZJMC5>(!mUz_n&yyQ5u9@(ThpMMC=Y86jd6`(-p=jXyzCl2w1;m<9EX93_ckX-kVlp=E z1s+_jsNe)6^YvjtxO!mZo2JIIf@Tu^Mp(Xo3xw79r9E#>>_;DHNh4vcorFe#qVvH5 z$>Sv{)10I6gK6m22Kq|GhawZ2zmv95;A9;rHX3TrAWKhm2u8x8A>QRIrRZs90~FP) z{r?m!*KrS1M*I=&pgdC5Wz46~tiZ0P_&KMiU}`B?SuLd@9b9p$;lDUt%RP-pC3mgN zwVGn6!&*TdtqB-QCy`T>vQrc%u$?6Gqct+bhd)38JhFo}nCjZZ2EBkoGQ7iCEzsCa zg;4wv$yCbNGZTTXiN^K9Nkb+A$Au?m3n^XMoOmA~?sCE$=MM*5Yna9d2khAg;GKm@ z%(IPaIG(eK4tNTI>;x7mwWIiD7eP~ctPj>Y z$ZWVE6pmVCXJ*o;b_9I;>&`zV4mlSv*K8LLte4oTCArK+x;d%-?iv%TauN=c#Obe*l98J^qyD0*N{0dC+@4G^~qdXpDSr-%Z)R6HO%pdP_E`}r8 zu|-c|gl8oqWbvQJMN0qA);K+1dhv6H)jSuTtp+o%9JQ(P$alZ5^o;oh&y5ydp zrvuw2ZF%sqa6&$dMvOqxq~=d29^X6oULb4hHHEqU6{2aPT?sOuKk>gT72W9mA>#84 zcTo#YD}nh|Yi)s-2iomO;bpCo3tnSu{;crUM&0$3GABD6yLm(`o7L`u_I~!iuQPwl zijP*hYpr89)p6nfx$6(M3P<^{CzTXPckW0PI~7X-fM{KCA}I!*J(^2sjdQBm6z zrE-*w_qD`D+T-I=p&(V!`x#CFi+J&NeSr zd%dPrQ}>1KPOI0`ulWBvxGXKw|NH9_zPUAY3-59orVW0dnO;uZZ;4(_P+Tq|D@ffS-GoM99`9VDD2d;svAoqdUFq`OgfU6 z`ldcUEB$5S^0hogC#v;p_P=iyum9zj^|oQhfgZL4G7bwAqc#X#j%A43w9}4p)&xu4 z&$9wW8kB_+r0(7SseMlBh^m`Yuuup~f_~~_$u^B|9Z!-L91HQ)I_9Ytda|5twN}i6 z7ExWt5Gk=1<;5ATDK7bXMGw|Imwl42>K!)cPG@OZ&Xl_s{)^dXiB8PaoqKkeCC@4Q_$T;~J}|r?sg#jPmqCPqjRCmmi$RgWxIffmBQTvR zae>k)I*4}8&nrpID~S)OEJ!Vm1*O^mZ&U-8M;zL!3N#=Nn9#XV^uGd%Ko-}5*VLhF z%>2L`c2b;yL1rEUgAj^F2X@#BJzyiMG#6+;HjAa7)TVXwGcX(~VPKF%(Qhda)1RAI zT#{N;tPiEJ8FT&7+h}f}OU;27Jc15MLV(|TFk=u$CV`j5q5EV_{{&wqU=Xwb>r7dM zejv-z2xbH%AdvloHBj=KM!)jvx;hArC0L|eB znyP?g9x&icU?!q3garE%t7++ai(3{0L(332k$@WLJ4|7w!Q2O-!HcEPLrkpWe%c41 zF@3=JLp5fSC3a)LS8Spi;{lxTngmS8uE5*HQH|MYi`^JwY)N2m#~%eT76yhU4A(Td zVK>GEn=wV3^{V#*UDIoT?wa#n*o`s8X3W(f5vIMs=#P>^H|B6Kc4N%28MF1Qz>~X4 z3=F?wnb5*!dlYtK%&{5sjeqH}#XwKBV|eQHUhKwLU^7N-vzp2}pfNKrj9GdNyD^s7 zjM;86X+s;(7&%~sOQ9s@uJhQ9F*Lwt4*Iq92%|iJ%Y@4^i!<|KWd@Ws#F~!LZ-+&g z!}$=0Iam`i`W=)Ab6!8eVGh=mjDF%9!knX=j3}#~;pe}h=PC51(g-8YYoQu}ZQ(S! zY3NIg5vD!WhM9)6;22#y`ch1U_CI^E3o_k)kU%lPk?pl K^FUzP&j0|SoS8%b literal 0 HcmV?d00001 diff --git a/packages/gcp-sphinx-docfx-yaml/docs/api.rst b/packages/gcp-sphinx-docfx-yaml/docs/api.rst new file mode 100644 index 000000000000..ebcd65e5cf31 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/docs/api.rst @@ -0,0 +1,14 @@ +API +=== + +.. automodule:: tests.test_yaml + :members: + :undoc-members: + +.. automodule:: docfx_yaml.extension + :members: + :undoc-members: + +.. automodule:: docfx_yaml.monkeypatch + :members: + :undoc-members: diff --git a/packages/gcp-sphinx-docfx-yaml/docs/conf.py b/packages/gcp-sphinx-docfx-yaml/docs/conf.py new file mode 100644 index 000000000000..9b798dfc5ea5 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/docs/conf.py @@ -0,0 +1,312 @@ +# Copyright 2021 Google LLC +# +# 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. + +# -*- coding: utf-8 -*- +# +# Sphinx DoxFX YAML documentation build configuration file, created by +# sphinx-quickstart on Wed Apr 22 15:38:18 2015. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.napoleon', + 'docfx_yaml.extension', +] + +import os, sys + +sys.path.insert(0, os.path.abspath('..')) + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'Sphinx DoxFX YAML' +copyright = u'2015, Read the Docs, Inc' +author = u'Read the Docs, Inc' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '1.1.0' +# The full version, including alpha/beta/rc tags. +release = '1.1.0' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +#keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = False + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. + +html_theme = 'alabaster' +html_sidebars = { + '**': [ + 'about.html', + 'navigation.html', + 'relations.html', + 'searchbox.html', + ] +} + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +#html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. + + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr' +#html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# Now only 'ja' uses this config value +#html_search_options = {'type': 'default'} + +# The name of a javascript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +#html_search_scorer = 'scorer.js' + +# Output file base name for HTML help builder. +htmlhelp_basename = 'SphinxDoxFX YAMLdoc' + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + #'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + #'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + #'preamble': '', + + # Latex figure (float) alignment + #'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'SphinxDoxFX YAML.tex', u'Sphinx DoxFX YAML Documentation', + u'Read the Docs, Inc', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'sphinxDoxFX YAML', u'Sphinx DoxFX YAML Documentation', + [author], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'SphinxDoxFX YAML', u'Sphinx DoxFX YAML Documentation', + author, 'SphinxDoxFX YAML', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False + +def setup(app): + app.add_object_type('confval', 'confval', + objname='configuration value', + indextemplate='pair: %s; configuration value') + diff --git a/packages/gcp-sphinx-docfx-yaml/docs/design.rst b/packages/gcp-sphinx-docfx-yaml/docs/design.rst new file mode 100644 index 000000000000..9be8b7894572 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/docs/design.rst @@ -0,0 +1,103 @@ +Sphinx DocFX YAML Reference Design +================================== + +This document will provide basic thoughts of the design of the DocFX YAML converter for the Sphinx Python Domain. + +Goals +----- + +The primary goal of this project is to generate YAML that can be consumed by the ``docfx`` tool. +It will be rendered from the internal doctree representation in Python. +This allows for the largest amount of compatability across Python domain implementations, +for example supporting both autodoc and manual domain entries. + +Architecture +------------ + +Two approaches were tried in the design of this system. +The first was based on the Docutils doctree implementation. +The second was a signal implementation. +Below we cover the trade offs and where we ended up. + +Doctree +~~~~~~~ + +Sphinx autodoc is used to generate the API documentation for most Python projects. +It imports the code via standard Python ``import`` mechanisms, +and then generates the proper rST in the Sphinx Python domain_. +This is then parsed until the ``doctree`` that is used internally in Sphinx. + +The initial attempt (``docfx_yaml/extract_nodes.py``) was to take this ``doctree`` and transform it into the YAML structure. +This worked for the majority of the Pytho metadata, +but ran into issues when attempting to get the raw Python docstrings. +These docstrings were parsed as rST and only available as a doctree object. +This meant that docstrings written in Markdown would be improperly parsed as rST and unable to be transformed back. + +Monkeypatch +``````````` + +We use the **Doctree** approach for some of our data. +In particular, +to get the :ref:`info field lists` from Sphinx, +we insert a monkeypatch in the Sphinx rendering. +This lives in the ``docfx_yaml/monkeypatch.py`` file. + +We used this approach because we needed to get the pre-transformed doc field information. +After Sphinx's transformation of the doctree important semantic information is lost. +So we needed to monkeypatch the ``DocFieldTransformer`` in Sphinx to get the information before it is transformed. + +Signals +~~~~~~~ + +The approach that we settled on for getting the full docstring text is the `autodoc-process-docstring `_ signal implemented in autodoc. +It lives in the ``docfx_yaml/extension.py`` file. +This signal is triggered at the processing of the docstring, +passing it along unprocessed. +This allows us to properly get the content of the docstring, +as well as derive the unique ID (uid) of the object. + +Another important part of the ``autodoc-process-docstring`` signal is that it passes the actual Python object along with it. +This allows us to introspect it with the ``inspect`` Python module, +and pull off argument listings, +default values, +line numbers, +and other information about the actual object. +This was required because we wanted more information about the objects than Sphinx outputs in it's normal output around autodoc. + +.. warning:: + This will only work for autodoc generated strings. + Any other use of the Python domain will be ignored, + as it isn't using the ``autodoc`` module. + +YAML syntax +----------- + +The ``docfx`` tool does not have support for Python concepts. +As such, +we have done a lossy mapping of the Python concepts onto the equivalent C# concepts. +This is lossy becuase there are things that can be expressed in Python that can't be in C#, +for example functions that live outside of a class. + +The `YAML Syntax`_ is documented and should be output properly from this module. +The mapping is done as follows: + +.. literalinclude:: ../docfx_yaml/extension.py + :start-after: TYPE_MAPPING = { + :end-before: } + +Along with this mapping, +all module-level functions will be added to a proxy class called ``Global``. +This will allow them to be attached to a proper class, +and be defined with ``docfx``. + +.. _domain: http://www.sphinx-doc.org/en/1.5.1/domains.html +.. _YAML Syntax: https://dotnet.github.io/docfx/spec/metadata_dotnet_spec.html + +Sphinx Implementation +~~~~~~~~~~~~~~~~~~~~~ + +The user will run a normal ``make html`` as part of their build. +The generation and loading will be done as an extension that can be configured. + +They will then be output into ``docfx_yaml`` inside the documentation directory. + diff --git a/packages/gcp-sphinx-docfx-yaml/docs/docfx.json b/packages/gcp-sphinx-docfx-yaml/docs/docfx.json new file mode 100644 index 000000000000..9cc171b94764 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/docs/docfx.json @@ -0,0 +1,22 @@ +{ + "build": { + "content": [ + { + "files": [ "**/*.yml" ], + "cwd": "_build", + "dest": "api" + }, + ], + "resource": [ + { + "files": [ "articles/images/**"] + } + ], + "overwrite": "specs/*.md", + "globalMetadata": { + "_appTitle": "docfx seed website", + "_enableSearch": true + }, + "dest": "_site" + } +} diff --git a/packages/gcp-sphinx-docfx-yaml/docs/index.rst b/packages/gcp-sphinx-docfx-yaml/docs/index.rst new file mode 100644 index 000000000000..72a33558153f --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/docs/index.rst @@ -0,0 +1 @@ +.. include:: ../README.rst diff --git a/packages/gcp-sphinx-docfx-yaml/docs/layout.rst b/packages/gcp-sphinx-docfx-yaml/docs/layout.rst new file mode 100644 index 000000000000..c5d6dc07e10e --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/docs/layout.rst @@ -0,0 +1,19 @@ +Layout of the project +===================== + +This project has a couple components: + +* This repo, which houses the YAML conversion code: + * https://github.com/ericholscher/sphinx-docfx-yaml/ +* There is a Travis CI build that tests the actual Python YAML generation code on Python 2 & 3: + * https://github.com/ericholscher/sphinx-docfx-yaml/blob/master/.travis.yml +* The Appveyor CI build that works as an integration test for the Python SDK library: + * https://github.com/ericholscher/sphinx-docfx-yaml/blob/master/appveyor.yml +* The HTML output of the CI build, which does a full life cycle Sphinx->YAML->Docfx conversion: + * https://ci.appveyor.com/project/ericholscher/sphinx-docfx-yaml/build/artifacts + * The YAML is in the ``doc/_build/html/docfx_yaml`` directory + * The rendered HTML is in the ``doc/_site/api/html/docfx_yaml`` directory + * The generated YAML is also checked into GitHub here: https://github.com/bradygaster/python-sdk-dev/tree/eric-full-yaml-test/python-sdk-dev/docfx_yaml +* A forked version of the Python SDK that adds integrates the YAML output and the docfx configuration: + * https://github.com/Azure/azure-sdk-for-python/compare/master...ericholscher:add-docfx-yaml + * This is used in the CI steps above to make sure we properly generate the YAML & docfx docs diff --git a/packages/gcp-sphinx-docfx-yaml/old_appveyor.yml b/packages/gcp-sphinx-docfx-yaml/old_appveyor.yml new file mode 100644 index 000000000000..05a85f6ba8f6 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/old_appveyor.yml @@ -0,0 +1,57 @@ +# Copyright 2021 Google LLC +# +# 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. + +build: false +before_build: + - nuget restore +environment: + matrix: + - PYTHON: "C:/Python27" +install: + - ps: (new-object net.webclient).DownloadFile('https://bootstrap.pypa.io/get-pip.py', 'C:/get-pip.py') + - "%PYTHON%/python.exe C:/get-pip.py" + - "%PYTHON%/Scripts/pip.exe --version" + - "%PYTHON%/Scripts/pip.exe install tox" +test_script: + - "docfx init -q" + - "git clone https://github.com/aspnet/Identity %APPVEYOR_BUILD_FOLDER%/tests/dotnetexample/example/Identity" + - "%PYTHON%/Scripts/tox.exe -e py27" + + +# V2 + +environment: + matrix: + - PYTHON: "C:/Python27" + +clone_folder: c:\projects\sphinx-docfx-yaml + +install: + # .NET + - ps: (new-object net.webclient).DownloadFile('https://github.com/dotnet/docfx/releases/download/v2.10.2/docfx.zip', 'c:\projects\sphinx-docfx-yaml\docfx.zip') + - cd c:\projects\sphinx-docfx-yaml + - 7z e docfx.zip -oc:\projects\sphinx-docfx-yaml\docfx + # Python + - ps: (new-object net.webclient).DownloadFile('https://bootstrap.pypa.io/get-pip.py', 'C:/get-pip.py') + - "%PYTHON%/python.exe C:/get-pip.py" + - "%PYTHON%/Scripts/pip.exe --version" + - "%PYTHON%/Scripts/pip.exe install tox sphinx sphinx_rtd_theme ." + +build_script: + - cd c:\projects\sphinx-docfx-yaml\docs + - "%PYTHON%/Scripts/sphinx-build.exe -b html -d _build/doctrees . _build/html" + - ..\docfx\docfx.exe build + +artifacts: + - path: 'docs' diff --git a/packages/gcp-sphinx-docfx-yaml/prospector.yml b/packages/gcp-sphinx-docfx-yaml/prospector.yml new file mode 100644 index 000000000000..42f01dfdb10e --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/prospector.yml @@ -0,0 +1,40 @@ +# Copyright 2021 Google LLC +# +# 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. + +strictness: low + +test-warnings: false +doc-warnings: true + +ignore-paths: + - docs + +ignore-patterns: + - ^docfx_yaml/writer.py$ + +pep8: + full: true + options: + max-line-length: 100 + +pylint: + max-line-length: 100 + disable: + - interface-not-implemented + +mccabe: + run: false + +pep257: + run: false diff --git a/packages/gcp-sphinx-docfx-yaml/readthedocs.yml b/packages/gcp-sphinx-docfx-yaml/readthedocs.yml new file mode 100644 index 000000000000..4966103142b9 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/readthedocs.yml @@ -0,0 +1,22 @@ +# Copyright 2021 Google LLC +# +# 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. + +# Don't build any extra formats + +formats: + - none +python: + version: 3 + setup_py_install: true + diff --git a/packages/gcp-sphinx-docfx-yaml/requirements.txt b/packages/gcp-sphinx-docfx-yaml/requirements.txt new file mode 100644 index 000000000000..ee0595be3838 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/requirements.txt @@ -0,0 +1,2 @@ +-e . +tox diff --git a/packages/gcp-sphinx-docfx-yaml/setup.cfg b/packages/gcp-sphinx-docfx-yaml/setup.cfg new file mode 100644 index 000000000000..5e4090017a9b --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/setup.cfg @@ -0,0 +1,2 @@ +[wheel] +universal = 1 diff --git a/packages/gcp-sphinx-docfx-yaml/setup.py b/packages/gcp-sphinx-docfx-yaml/setup.py new file mode 100644 index 000000000000..a2b59f69ce8c --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/setup.py @@ -0,0 +1,40 @@ +# Copyright 2021 Google LLC +# +# 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. + +import codecs +from setuptools import setup, find_packages +extra_setup = dict( +install_requires=[ + 'PyYAML', + 'wheel>=0.24.0', + 'sphinx', + 'unidecode', +], +setup_requires=['pytest-runner'], +tests_require=['pytest', 'mock'], +) + +setup( + name='sphinx-docfx-yaml', + version='1.2.76', + author='Eric Holscher', + author_email='eric@ericholscher.com', + url='https://github.com/ericholscher/sphinx-docfx-yaml', + description='Sphinx Python Domain to DocFX YAML Generator', + package_dir={'': '.'}, + packages=find_packages('.', exclude=['tests']), + # trying to add files... + include_package_data=True, + **extra_setup +) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/__init__.py new file mode 100644 index 000000000000..690df65fb6bc --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/__init__.py @@ -0,0 +1,14 @@ +# Copyright 2021 Google LLC +# +# 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. + diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/conflict/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/example/conflict/__init__.py new file mode 100644 index 000000000000..3f7e879b9928 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/example/conflict/__init__.py @@ -0,0 +1,22 @@ +# Copyright 2021 Google LLC +# +# 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. + +# coding: utf-8 + +""" Package used to test YAML file conflicting. +""" + +from .foo import Foo + +__all__ = ['Foo'] \ No newline at end of file diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/conflict/foo.py b/packages/gcp-sphinx-docfx-yaml/tests/example/conflict/foo.py new file mode 100644 index 000000000000..3f8b49c3e1aa --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/example/conflict/foo.py @@ -0,0 +1,184 @@ +# Copyright 2021 Google LLC +# +# 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. + +# coding: utf-8 + +""" Docstring of :mod:`conflict.foo` module. +""" + +foo_var = [] +""" Docstring of module variable :any:`conflict.foo.foo_var`.""" + + +def function(arg1, arg2, arg3, arg4): + """ Docstring of :func:`conflict.foo.function` function. + + :param int arg1: Parameter arg1 of :func:`~conflict.foo.function`. + :param float arg2: Parameter arg2 of :func:`~conflict.foo.function`. + :param boolean arg3: Parameter arg3 of :func:`~conflict.foo.function`. + :param str arg4: Parameter arg4 of :func:`~conflict.foo.function`. + """ + pass + + +class Foo(object): + """ Docstring of :class:`conflict.foo.Foo` class in rst format. + + :var attr: Docstring of :class:`conflict.foo.Foo.attr` from class docstring. + :vartype attr: ~conflict.enum.EnumFoo + + :param init_arg1: Parameter init_arg1 from class docstring. + :type init_arg1: float + :param list[int] init_arg2: Parameter init_arg2 from class docstring. + """ + + attr = 1 + """ Docstring of :class:`conflict.foo.Foo.attr` from attrbute docstring.""" + + def __init__(self, init_arg1, init_arg2): + """ Docstring of constructor of Foo. Will not be shown. + + :param init_arg1: Parameter init_arg1 from constructor's docstring. + :type init_arg1: float + :param list[int] init_arg2: Parameter init_arg2 from constructor's docstring. + """ + + @property + def attr_getter(self): + """ Docstring of :meth:`conflict.foo.Foo.attr_getter` @property. + """ + return self.attr + + @classmethod + def class_method(cls, arg1): + """ Docstring of :class:`conflict.foo.Foo.class_method` @classmethod. + + :param cls: Class object of :class:`conflict.foo.Foo`. + :type cls: class + :param str arg1: Parameter arg1 of :meth:`conflict.foo.Foo.class_method`. + """ + pass + + @staticmethod + def static_method(): + """ Docstring of :meth:`conflict.foo.Foo.static_method` @staticmethod. + """ + pass + + def method(self): + """ Docstring of normal class method :meth:`conflict.foo.Foo.method`. + """ + pass + + def method_return(self): + """ Docstring of :meth:`conflict.foo.Foo.method_return`. + + :return: This method returns a value. + :rtype: boolean + """ + return False + + def method_multiline(self): + """ Docstring of :meth:`conflict.foo.Foo.method_multiline`. + This docstring has multiple lines of contents. + And this should work perfectly. + """ + pass + + def method_exception(self): + """ Docstring of :meth:`conflict.foo.Foo.method_exception`. + + :raises: :class:`Exception` This function raises + exception. + """ + raise Exception() + + def method_external_link(self): + """ Docstring of :meth:`conflict.foo.Foo.method_external_link`. + Inline link should be transformed to markdown: `Link Text `_. + And seperated link will fail: `Seperated Link`_ + + .. _Seperated Link: http://seperated.external.link + """ + pass + + def method_seealso(self): + """ Docstring of :meth:`conflict.foo.Foo.method_seealso`. + + .. seealso:: + Seealso contents. + Multi-line should be supported. + And reference to :class:`conflict.foo.Foo` should be okay. + """ + pass + + def method_note(self): + """ Docstring of :meth:`conflict.foo.Foo.method_note`. + + .. note:: + This is content of note. + Another line of note contents. + """ + pass + + def method_warning(self): + """ Docstring of :meth:`conflict.foo.Foo.method_warning`. + + .. warning:: + This is content of warning. + """ + pass + + def method_code(self): + """ Docstring of :meth:`conflict.foo.Foo.method_code`. + + .. code-block:: python + + >>> import numpy as np + >>> a = np.ndarray([1,2,3,4,5]) + + Another way of code block:: + + import numpy as np + b = np.random.random(10) + """ + pass + + def method_example(self): + """ Docstring of :meth:`conflict.foo.Foo.method_example`. + + .. admonition:: + This is Example content. + Should support multi-line. + Can also include file: + + .. literalinclude:: ../format/rst/enum.py + """ + pass + + def method_default_value(self, arg1='default string', arg2=None): + """ Docstring of :meth:`conflict.foo.Foo.method_default_value`. + + :param str arg1: Parameter arg1 of :meth:`conflict.foo.Foo.method_default_value`, default value is 'default string'. + :param object arg2: Paremeter arg2 of :meth:`conflict.foo.Foo.method_default_value` default value is None. + """ + pass + + def method_default_value_comma(self, arg1=(1,2,3)): + """ Docstring of :meth:`conflict.foo.Foo.method_default_value_comma`. + The default value of method parameter contains comma thus will fail to parse. + + :param tuple arg1: Parameter arg1 of :meth:`conflict.foo.Foo.method_default_value_comma`, default value is (1,2,3). + """ + pass diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/doc/conf.py b/packages/gcp-sphinx-docfx-yaml/tests/example/doc/conf.py new file mode 100644 index 000000000000..5f118fa62c85 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/example/doc/conf.py @@ -0,0 +1,40 @@ +# Copyright 2021 Google LLC +# +# 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. + +import sys +import os + +sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) + +source_suffix = '.rst' +master_doc = 'index' +project = u'example' +copyright = u'2018, Microsoft' +author = u'Yiding Tian' +version = '0.1' +release = '0.1' +language = None +exclude_patterns = ['_build'] +pygments_style = 'sphinx' +todo_include_todos = False +html_theme = 'alabaster' +html_static_path = ['_static'] +htmlhelp_basename = 'Example Document' +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.napoleon', + 'sphinx.ext.intersphinx', + 'docfx_yaml.extension' +] +intersphinx_mapping = {'python': ('https://docs.python.org/3.6', None)} diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/doc/format.google.rst b/packages/gcp-sphinx-docfx-yaml/tests/example/doc/format.google.rst new file mode 100644 index 000000000000..61d4bde179b7 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/example/doc/format.google.rst @@ -0,0 +1,22 @@ +format\.google package +====================== + +Submodules +---------- + +format\.google\.foo module +-------------------------- + +.. automodule:: format.google.foo + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: format.google + :members: + :undoc-members: + :show-inheritance: diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/doc/format.numpy.rst b/packages/gcp-sphinx-docfx-yaml/tests/example/doc/format.numpy.rst new file mode 100644 index 000000000000..f254b16908b7 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/example/doc/format.numpy.rst @@ -0,0 +1,22 @@ +format\.numpy package +===================== + +Submodules +---------- + +format\.numpy\.foo module +------------------------- + +.. automodule:: format.numpy.foo + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: format.numpy + :members: + :undoc-members: + :show-inheritance: diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/doc/format.rst b/packages/gcp-sphinx-docfx-yaml/tests/example/doc/format.rst new file mode 100644 index 000000000000..fde29cdb7c98 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/example/doc/format.rst @@ -0,0 +1,19 @@ +format package +============== + +Subpackages +----------- + +.. toctree:: + + format.google + format.numpy + format.rst + +Module contents +--------------- + +.. automodule:: format + :members: + :undoc-members: + :show-inheritance: diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/doc/format.rst.rst b/packages/gcp-sphinx-docfx-yaml/tests/example/doc/format.rst.rst new file mode 100644 index 000000000000..fd7516a91412 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/example/doc/format.rst.rst @@ -0,0 +1,38 @@ +format\.rst package +=================== + +Submodules +---------- + +format\.rst\.directives module +------------------------------ + +.. automodule:: format.rst.directives + :members: + :undoc-members: + :show-inheritance: + +format\.rst\.enum module +------------------------ + +.. automodule:: format.rst.enum + :members: + :undoc-members: + :show-inheritance: + +format\.rst\.foo module +----------------------- + +.. automodule:: format.rst.foo + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: format.rst + :members: + :undoc-members: + :show-inheritance: diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/doc/index.rst b/packages/gcp-sphinx-docfx-yaml/tests/example/doc/index.rst new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.native.native_foo.rst b/packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.native.native_foo.rst new file mode 100644 index 000000000000..904c1defc1fd --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.native.native_foo.rst @@ -0,0 +1,10 @@ +nspkg\.native\.native\_foo package +================================== + +Module contents +--------------- + +.. automodule:: nspkg.native.native_foo + :members: + :undoc-members: + :show-inheritance: diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.pkg_resources.pkg_resources_foo.rst b/packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.pkg_resources.pkg_resources_foo.rst new file mode 100644 index 000000000000..ad10d564040b --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.pkg_resources.pkg_resources_foo.rst @@ -0,0 +1,10 @@ +nspkg\.pkg\_resources\.pkg\_resources\_foo package +================================================== + +Module contents +--------------- + +.. automodule:: nspkg.pkg_resources.pkg_resources_foo + :members: + :undoc-members: + :show-inheritance: diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.pkg_resources.rst b/packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.pkg_resources.rst new file mode 100644 index 000000000000..f72402973d3a --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.pkg_resources.rst @@ -0,0 +1,17 @@ +nspkg\.pkg\_resources package +============================= + +Subpackages +----------- + +.. toctree:: + + nspkg.pkg_resources.pkg_resources_foo + +Module contents +--------------- + +.. automodule:: nspkg.pkg_resources + :members: + :undoc-members: + :show-inheritance: diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.pkgutil.pkgutil_foo.rst b/packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.pkgutil.pkgutil_foo.rst new file mode 100644 index 000000000000..60ec1af00c05 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.pkgutil.pkgutil_foo.rst @@ -0,0 +1,10 @@ +nspkg\.pkgutil\.pkgutil\_foo package +==================================== + +Module contents +--------------- + +.. automodule:: nspkg.pkgutil.pkgutil_foo + :members: + :undoc-members: + :show-inheritance: diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.pkgutil.rst b/packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.pkgutil.rst new file mode 100644 index 000000000000..592411ee6476 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.pkgutil.rst @@ -0,0 +1,17 @@ +nspkg\.pkgutil package +====================== + +Subpackages +----------- + +.. toctree:: + + nspkg.pkgutil.pkgutil_foo + +Module contents +--------------- + +.. automodule:: nspkg.pkgutil + :members: + :undoc-members: + :show-inheritance: diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.rst b/packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.rst new file mode 100644 index 000000000000..364d7680674f --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.rst @@ -0,0 +1,18 @@ +nspkg package +============= + +Subpackages +----------- + +.. toctree:: + + nspkg.pkg_resources + nspkg.pkgutil + +Module contents +--------------- + +.. automodule:: nspkg + :members: + :undoc-members: + :show-inheritance: diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/format/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/example/format/__init__.py new file mode 100644 index 000000000000..b7b328fd9f4c --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/example/format/__init__.py @@ -0,0 +1,18 @@ +# Copyright 2021 Google LLC +# +# 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. + +# coding: utf-8 + +""" Package used to test rst-style, google-style and numpy-style docstrings. +""" \ No newline at end of file diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/format/google/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/example/format/google/__init__.py new file mode 100644 index 000000000000..58f06daa0467 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/example/format/google/__init__.py @@ -0,0 +1,16 @@ +# Copyright 2021 Google LLC +# +# 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. + +# coding: utf-8 +# This package is used to test google style docstring. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/format/google/foo.py b/packages/gcp-sphinx-docfx-yaml/tests/example/format/google/foo.py new file mode 100644 index 000000000000..e2efbf55700b --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/example/format/google/foo.py @@ -0,0 +1,181 @@ +# Copyright 2021 Google LLC +# +# 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. + +# coding: utf-8 + +""" Docstring of :mod:`format.google.foo` module. +""" + +foo_var = [] +""" Docstring of module variable :any:`format.google.foo.foo_var`.""" + + +def function(arg1, arg2, arg3, arg4): + """ Docstring of :func:`format.google.foo.function` function. + + Args: + arg1 (int): Parameter arg1 of :func:`format.google.foo.function`. + arg2 (float): Parameter arg2 of :func:`format.google.foo.function`. + arg3 (boolean): Parameter arg3 of :func:`format.google.foo.function`. + arg4 (str): Parameter arg4 of :func:`format.google.foo.function`. + """ + pass + + +class Foo(object): + """ Docstring of :class:`format.google.foo.Foo` class in google format. + + Attributes: + attr (:class:`~format.rst.enum.EnumFoo`): Docstring of :any:`format.google.foo.Foo.attr` from class docstring. + + Arguments: + init_arg1 (float): Parameter init_arg1 from class docstring. + init_arg2 (list[int]): Parameter init_arg2 from class docstring. + """ + + attr = 1 + """ Docstring of :any:`format.google.foo.Foo.attr` from attrbute docstring.""" + + def __init__(self, init_arg1, init_arg2): + """ Docstring of constructor of :class:`format.google.foo.Foo`. + + Parameters: + init_arg1 (float): Parameter init_arg1 from constructor's docstring. + init_arg2 (list[int]): Parameter init_arg2 from constructor's docstring. + """ + + @property + def attr_getter(self): + """ Docstring of :meth:`format.google.foo.Foo.attr_getter` @property. + """ + return self.attr + + @classmethod + def class_method(cls, arg1): + """ Docstring of :meth:`format.google.foo.Foo.class_method` @classmethod. + + Args: + cls (class): Class object of :class:`format.google.foo.Foo`. + arg1 (str): Parameter arg1 of :meth:`format.google.foo.Foo.class_method`. + """ + pass + + @staticmethod + def static_method(): + """ Docstring of :meth:`format.google.foo.Foo.static_method` @staticmethod. + """ + pass + + def method(self): + """ Docstring of normal class method :meth:`format.google.foo.Foo.method`. + """ + pass + + def method_return(self): + """ Docstring of :meth:`format.google.foo.Foo.method_return`. + + Return: + bool: This method returns a value. + """ + return False + + def method_multiline(self): + """ Docstring of :meth:`format.google.foo.Foo.method_multiline`. + This docstring has multiple lines of contents. + And this should work perfectly. + """ + pass + + def method_exception(self): + """ Docstring of :meth:`format.google.foo.Foo.method_exception`. + + Raises: + format.rst.foo.FooException: This function raises + exception. + """ + raise FooException() + + def method_external_link(self): + """ Docstring of :meth:`format.google.foo.Foo.method_external_link`. + Inline link should be transformed to markdown: `Link Text `_. + And seperated link will fail: `Seprated Link`_ + + .. _Seprated Link: http://seperated.external.link + """ + pass + + def method_seealso(self): + """ Docstring of :meth:`format.google.foo.Foo.method_seealso`. + + See Also: + Seealso contents. + Multi-line should be supported. + """ + pass + + def method_note(self): + """ Docstring of :meth:`format.google.foo.Foo.method_note`. + + Note: + This is content of note. + Another line of note contents. + """ + pass + + def method_warning(self): + """ Docstring of :meth:`format.google.foo.Foo.method_warning`. + + Warning: + This is content of warning. + """ + pass + + def method_code(self): + """ Docstring of :meth:`format.google.foo.Foo.method_code`. + + .. code-block:: python + + >>> import numpy as np + >>> a = np.ndarray([1,2,3,4,5]) + + Another way of code block:: + + >>> import numpy as np + >>> b = np.random.random(10) + """ + pass + + def method_example(self): + """ Docstring of :meth:`format.google.foo.Foo.method_example`. + + Example: + This is example content. + Should support multi-line. + Can also include file: + + .. literalinclude:: ../format/rst/enum.py + """ + pass + + +class FooException(Exception): + """ Docstring of :class:`format.google.foo.FooException`. + Another class of :mod:`format.google.foo` module. + """ + + class InternalFoo(object): + """ Docstring of internal class :class:`format.google.foo.FooException.InternalFoo`. + This class is an internal class of :class:`format.google.foo.FooException`. + """ + pass diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/format/numpy/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/example/format/numpy/__init__.py new file mode 100644 index 000000000000..ea6283339a06 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/example/format/numpy/__init__.py @@ -0,0 +1,16 @@ +# Copyright 2021 Google LLC +# +# 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. + +# coding: utf-8 +# This package is used to test numpy style docstring. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/format/numpy/foo.py b/packages/gcp-sphinx-docfx-yaml/tests/example/format/numpy/foo.py new file mode 100644 index 000000000000..4a4606a95606 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/example/format/numpy/foo.py @@ -0,0 +1,204 @@ +# Copyright 2021 Google LLC +# +# 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. + +# coding: utf-8 + +""" Docstring of :mod:`format.numpy.foo` module. +""" + +foo_var = [] +""" Docstring of module variable :any:`format.numpy.foo.foo_var`.""" + + +def function(arg1, arg2, arg3, arg4): + """ Docstring of :func:`format.numpy.foo.function` function. + + Args + ---- + arg1 : int + Parameter arg1 of :func:`format.numpy.foo.function`. + arg2 : float + Parameter arg2 of :func:`format.numpy.foo.function`. + arg3 : boolean + Parameter arg3 of :func:`format.numpy.foo.function`. + arg4 : str + Parameter arg4 of :func:`format.numpy.foo.function`. + """ + pass + + +class Foo(object): + """ Docstring of :class:`format.numpy.foo.Foo` class in numpy format. + + Attributes + ---------- + attr : :class:`~format.rst.enum.EnumFoo` + Docstring of :any:`format.numpy.foo.Foo.attr` from class docstring. + + Arguments + --------- + init_arg1 : float + Parameter init_arg1 from class docstring. + init_arg2 : list[int] + Parameter init_arg2 from class docstring. + """ + + attr = 1 + """ Docstring of :any:`format.numpy.foo.Foo.attr` from attrbute docstring.""" + + def __init__(self, init_arg1, init_arg2): + """ Docstring of constructor of :class:`format.numpy.foo.Foo`. + + Parameters + ---------- + init_arg1 : float + Parameter init_arg1 from constructor's docstring. + init_arg2 : list[int] + Parameter init_arg2 from constructor's docstring. + """ + + @property + def attr_getter(self): + """ Docstring of :meth:`fomrmat.numpy.foo.Foo.attr_getter` @property. + """ + return self.attr + + @classmethod + def class_method(cls, arg1): + """ Docstring of :meth:`fomrmat.numpy.foo.Foo.class_method` @classmethod. + + Args + ---- + cls : class + Class object of :class:`format.numpy.foo.Foo`. + arg1 : str + Parameter arg1 of :meth:`fomrmat.numpy.foo.Foo.class_method`. + """ + pass + + @staticmethod + def static_method(): + """ Docstring of :meth:`fomrmat.numpy.foo.Foo.static_method @staticmethod`. + """ + pass + + def method(self): + """ Docstring of normal class method :meth:`fomrmat.numpy.foo.Foo.method`. + """ + pass + + def method_return(self): + """ Docstring of :meth:`fomrmat.numpy.foo.Foo.method_return`. + + Returns + ------- + bool + This method returns a value. + """ + return False + + def method_multiline(self): + """ Docstring of :meth:`fomrmat.numpy.foo.Foo.method_multiline`. + This docstring has multiple lines of contents. + And this should work perfectly. + """ + pass + + def method_exception(self): + """ Docstring of :meth:`fomrmat.numpy.foo.Foo.method_exception`. + + Raises + ------ + format.rst.foo.FooException + This function raises + exception. + """ + raise FooException() + + def method_external_link(self): + """ Docstring of :meth:`fomrmat.numpy.foo.Foo.method_external_link`. + Inline link should be transformed to markdown: `Link Text `_. + And seperated link will fail: `Seprated Link`_ + + .. _Seprated Link: http://seperated.external.link + """ + pass + + def method_seealso(self): + """ Docstring of :meth:`fomrmat.numpy.foo.Foo.method_seealso`. + + See Also + -------- + format.numpy.foo.Foo.mathod_note : See also target. + """ + pass + + def method_note(self): + """ Docstring of :meth:`fomrmat.numpy.foo.Foo.method_note`. + + Note + ---- + This is content of note. + Another line of note contents. + """ + pass + + def method_warning(self): + """ Docstring of :meth:`fomrmat.numpy.foo.Foo.method_warning`. + + Warning + ------- + This is content of warning. + """ + pass + + def method_code(self): + """ Docstring of :meth:`fomrmat.numpy.foo.Foo.method_code`. + + .. code-block:: python + + import numpy as np + a = np.ndarray([1,2,3,4,5]) + + Another way of code block:: + + import numpy as np + b = np.random.random(10) + """ + pass + + def method_example(self): + """ Docstring of :meth:`fomrmat.numpy.foo.Foo.method_example`. + + Examples + -------- + This is Example content. + Should support multi-line. + Can also include file: + + .. literalinclude:: ../format/rst/enum.py + """ + pass + + +class FooException(Exception): + """ Docstring of :class:`format.numpy.foo.FooException`. + Another class of :mod:`format.numpy.foo` module. + """ + + class InternalFoo(object): + """ Docstring of internal class :class:`format.numpy.foo.FooException.InternalFoo`. + This class is an internal class of :class:`format.numpy.foo.FooException`. + """ + pass diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/format/rst/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/example/format/rst/__init__.py new file mode 100644 index 000000000000..e67d510b06ff --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/example/format/rst/__init__.py @@ -0,0 +1,23 @@ +# Copyright 2021 Google LLC +# +# 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. + +# coding: utf-8 + +""" Docstring of package :mod:`format.rst`. +""" + +def module_function(): + """ Docstring of module function :func:`format.rst.module_function`. + """ + pass diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/format/rst/directives.py b/packages/gcp-sphinx-docfx-yaml/tests/example/format/rst/directives.py new file mode 100644 index 000000000000..b2985d5d7727 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/example/format/rst/directives.py @@ -0,0 +1,85 @@ +# Copyright 2021 Google LLC +# +# 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. + +# coding: utf-8 + +""" Docstring of module :mod:`format.rst.directives`. +This module is used for testing self-defined directives. + +.. remarks:: Remarks from module directives. +""" + +module_var = '' +""".. remarks:: Remarks from module variable.""" + + +def func(): + """ + .. remarks:: Remarks from module function. + """ + pass + + +class DirectivesFoo(object): + """ Docstring of class :class:`format.rst.directives.DirectivesFoo`. + + .. note:: + Note content from class docstring. + Second line of note content. + many lines of content. + + .. warning:: + Warning message from class docstring. + Second line. + + .. tip:: + Tip content. :class:`format.rst.foo.Foo` + + .. important:: + Important content. + + .. caution:: + Caution content. + + .. remarks:: Remarks from class. + Multi-line content should be supported. + + .. note:: + Note conetnt under class remarks. + Second line of note content. + + .. warning:: + Warning content under class remarks. + Second line. + :class:`format.rst.foo.Foo` + + .. tip:: + Tip content. + + .. important:: + Important content. + + .. caution:: + Caution content. + """ + + var_remarks = '' + """ .. remarks:: Remarks from class attribute :class:`format.rst.directives.DirectivesFoo.var_remarks`.""" + + def method_remarks(self): + """ + .. remarks:: Remarks from class method :meth:`format.rst.directives.DirectivesFoo.method_remarks` + Another reference: :class:`format.rst.directives.DirectivesFoo` + """ + pass diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/format/rst/enum.py b/packages/gcp-sphinx-docfx-yaml/tests/example/format/rst/enum.py new file mode 100644 index 000000000000..368dd77fb3ae --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/example/format/rst/enum.py @@ -0,0 +1,24 @@ +# Copyright 2021 Google LLC +# +# 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. + +# coding: utf-8 + +from enum import Enum + +class EnumFoo(Enum): + """ Docstring of :class:`format.rst.enum.EnumFoo` class. + """ + + VALUE0 = 0 #: Inline docstring of VALUE0 + VALUE1 = 1 #: Inlune docstring of VALUE1 diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/format/rst/foo.py b/packages/gcp-sphinx-docfx-yaml/tests/example/format/rst/foo.py new file mode 100644 index 000000000000..fd79ea5a3600 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/example/format/rst/foo.py @@ -0,0 +1,203 @@ +# Copyright 2021 Google LLC +# +# 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. + +# coding: utf-8 + +""" Docstring of :mod:`format.rst.foo` module. +""" + +from .enum import EnumFoo + +foo_var = [] +""" Docstring of module variable :any:`format.rst.foo.foo_var`.""" + + +def function(arg1, arg2, arg3, arg4): + """ Docstring of :func:`format.rst.foo.function` function. + + :param int arg1: Parameter arg1 of :func:`~format.rst.foo.function`. + :param float arg2: Parameter arg2 of :func:`~format.rst.foo.function`. + :param boolean arg3: Parameter arg3 of :func:`~format.rst.foo.function`. + :param str arg4: Parameter arg4 of :func:`~format.rst.foo.function`. + """ + pass + + +class Foo(object): + """ Docstring of :class:`format.rst.foo.Foo` class in rst format. + + :var attr: Docstring of :class:`format.rst.foo.Foo.attr` from class docstring. + :vartype attr: ~format.rst.enum.EnumFoo + + :param init_arg1: Parameter init_arg1 from class docstring. + :type init_arg1: float + :param list[int] init_arg2: Parameter init_arg2 from class docstring. + """ + + attr = EnumFoo.VALUE1 + """ Docstring of :class:`format.rst.foo.Foo.attr` from attrbute docstring.""" + + def __init__(self, init_arg1, init_arg2): + """ Docstring of constructor of Foo. Will not be shown. + + :param init_arg1: Parameter init_arg1 from constructor's docstring. + :type init_arg1: float + :param list[int] init_arg2: Parameter init_arg2 from constructor's docstring. + """ + + @property + def attr_getter(self): + """ Docstring of :meth:`format.rst.foo.Foo.attr_getter` @property. + """ + return self.attr + + @classmethod + def class_method(cls, arg1): + """ Docstring of :class:`format.rst.foo.Foo.class_method` @classmethod. + + :param cls: Class object of :class:`format.rst.foo.Foo`. + :type cls: class + :param str arg1: Parameter arg1 of :meth:`format.rst.foo.Foo.class_method`. + """ + pass + + @staticmethod + def static_method(): + """ Docstring of :meth:`format.rst.foo.Foo.static_method` @staticmethod. + """ + pass + + def method(self): + """ Docstring of normal class method :meth:`format.rst.foo.Foo.method`. + """ + pass + + def method_return(self): + """ Docstring of :meth:`format.rst.foo.Foo.method_return`. + + :return: This method returns a value. + :rtype: boolean + """ + return False + + def method_multiline(self): + """ Docstring of :meth:`format.rst.foo.Foo.method_multiline`. + This docstring has multiple lines of contents. + And this should work perfectly. + """ + pass + + def method_exception(self): + """ Docstring of :meth:`format.rst.foo.Foo.method_exception`. + + :raises: :class:`format.rst.foo.FooException` This function raises + exception. + """ + raise FooException() + + def method_external_link(self): + """ Docstring of :meth:`format.rst.foo.Foo.method_external_link`. + Inline link should be transformed to markdown: `Link Text `_. + And seperated link will fail: `Seperated Link`_ + + .. _Seperated Link: http://seperated.external.link + """ + pass + + def method_seealso(self): + """ Docstring of :meth:`format.rst.foo.Foo.method_seealso`. + + .. seealso:: + Seealso contents. + Multi-line should be supported. + And reference to :class:`format.rst.foo.Foo` should be okay. + """ + pass + + def method_note(self): + """ Docstring of :meth:`format.rst.foo.Foo.method_note`. + + .. note:: + This is content of note. + Another line of note contents. + """ + pass + + def method_warning(self): + """ Docstring of :meth:`format.rst.foo.Foo.method_warning`. + + .. warning:: + This is content of warning. + """ + pass + + def method_code(self): + """ Docstring of :meth:`format.rst.foo.Foo.method_code`. + + .. code-block:: python + + >>> import numpy as np + >>> a = np.ndarray([1,2,3,4,5]) + + Another way of code block:: + + import numpy as np + b = np.random.random(10) + """ + pass + + def method_example(self): + """ Docstring of :meth:`format.rst.foo.Foo.method_example`. + + .. admonition:: + This is Example content. + Should support multi-line. + Can also include file: + + .. literalinclude:: ../format/rst/enum.py + """ + pass + + def method_default_value(self, arg1='default string', arg2=None): + """ Docstring of :meth:`format.rst.foo.Foo.method_default_value`. + + :param str arg1: Parameter arg1 of :meth:`format.rst.foo.Foo.method_default_value`, default value is 'default string'. + :param object arg2: Paremeter arg2 of :meth:`format.rst.foo.Foo.method_default_value` default value is None. + """ + pass + + def method_default_value_comma(self, arg1=(1,2,3)): + """ Docstring of :meth:`format.rst.foo.Foo.method_default_value_comma`. + The default value of method parameter contains comma thus will fail to parse. + + :param tuple arg1: Parameter arg1 of :meth:`format.rst.foo.Foo.method_default_value_comma`, default value is (1,2,3). + """ + pass + +class FooException(Exception): + """ Docstring of :class:`format.rst.foo.FooException`. + Another class of :mod:`format.rst.foo` module. + """ + + class InternalFoo(object): + """ Docstring of internal class :class:`format.rst.foo.FooException.InternalFoo`. + This class is an internal class of :class:`format.rst.foo.FooException`. + """ + pass + +class InheritFoo(Foo, dict): + """ Docstring of :class:`format.rst.foo.InheritFoo`. + This class inherit from two classes: :class:`format.rst.foo.Foo` and :class:`format.rst.foo`. + """ + pass \ No newline at end of file diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/__init__.py new file mode 100644 index 000000000000..93af25cd734c --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/__init__.py @@ -0,0 +1,18 @@ +# Copyright 2021 Google LLC +# +# 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. + +# coding: utf-8 + +""" Package used for namespace package test. +""" \ No newline at end of file diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/native/__init__.pyi b/packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/native/__init__.pyi new file mode 100644 index 000000000000..b15d3b22ce25 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/native/__init__.pyi @@ -0,0 +1,2 @@ +# coding: utf-8 +# .pyi is used to declare that this folder is a namespace package. \ No newline at end of file diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/native/native_foo/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/native/native_foo/__init__.py new file mode 100644 index 000000000000..d5e5048bcc9c --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/native/native_foo/__init__.py @@ -0,0 +1,19 @@ +# Copyright 2021 Google LLC +# +# 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. + +# coding: utf-8 + +from format.rst.foo import Foo + +__all__ = ['Foo'] \ No newline at end of file diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/pkg_resources/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/pkg_resources/__init__.py new file mode 100644 index 000000000000..ae64cf512547 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/pkg_resources/__init__.py @@ -0,0 +1,19 @@ +# Copyright 2021 Google LLC +# +# 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. + +# coding: utf-8 +# Used for testing pkg_resources-style namespace package. +# See more: https://packaging.python.org/guides/packaging-namespace-packages/#pkg-resources-style-namespace-packages + +__import__('pkg_resources').declare_namespace(__name__) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/pkg_resources/pkg_resources_foo/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/pkg_resources/pkg_resources_foo/__init__.py new file mode 100644 index 000000000000..d5e5048bcc9c --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/pkg_resources/pkg_resources_foo/__init__.py @@ -0,0 +1,19 @@ +# Copyright 2021 Google LLC +# +# 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. + +# coding: utf-8 + +from format.rst.foo import Foo + +__all__ = ['Foo'] \ No newline at end of file diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/pkgutil/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/pkgutil/__init__.py new file mode 100644 index 000000000000..57feff0c84eb --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/pkgutil/__init__.py @@ -0,0 +1,19 @@ +# Copyright 2021 Google LLC +# +# 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. + +# coding: utf-8 +# Used for testing pkgutil-style namespace package. +# See more from: https://packaging.python.org/guides/packaging-namespace-packages/#pkgutil-style-namespace-packages + +__path__ = __import__('pkgutil').extend_path(__path__, __name__) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/pkgutil/pkgutil_foo/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/pkgutil/pkgutil_foo/__init__.py new file mode 100644 index 000000000000..d5e5048bcc9c --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/pkgutil/pkgutil_foo/__init__.py @@ -0,0 +1,19 @@ +# Copyright 2021 Google LLC +# +# 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. + +# coding: utf-8 + +from format.rst.foo import Foo + +__all__ = ['Foo'] \ No newline at end of file diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/setup.cfg b/packages/gcp-sphinx-docfx-yaml/tests/example/setup.cfg new file mode 100644 index 000000000000..5e4090017a9b --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/example/setup.cfg @@ -0,0 +1,2 @@ +[wheel] +universal = 1 diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/setup.py b/packages/gcp-sphinx-docfx-yaml/tests/example/setup.py new file mode 100644 index 000000000000..7c8ea3bc8c2d --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/example/setup.py @@ -0,0 +1,27 @@ +# Copyright 2021 Google LLC +# +# 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. + +from setuptools import setup, find_packages + +setup( + name='example', + version='0.1', + author='Yiding Tian', + author_email='yitian@microsoft.com', + url='https://github.com/docascode/sphinx-docfx-yaml/tree/master/tests/example', + description='Test Package for sphinx-docfx-yaml', + package_dir={'': '.'}, + packages=find_packages('.', exclude=['doc']), + include_package_data=True +) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/test_yaml.py b/packages/gcp-sphinx-docfx-yaml/tests/test_yaml.py new file mode 100644 index 000000000000..a1bba0994633 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/test_yaml.py @@ -0,0 +1,534 @@ +# Copyright 2021 Google LLC +# +# 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. + +import os +import re +import yaml +import shutil +import unittest + +from contextlib import contextmanager + +from sphinx.application import Sphinx + + +@contextmanager +def sphinx_build(test_dir): + """ Use contextmanager to ensure build cleaning after testing. + """ + + os.chdir('tests/{0}'.format(test_dir)) + + try: + app = Sphinx( + srcdir='./doc', + confdir='./doc', + outdir='_build/text', + doctreedir='_build/.doctrees', + buildername='html' + ) + app.build(force_all=True) + yield + finally: + shutil.rmtree('_build') + os.chdir('../..') + + +class YamlTests(unittest.TestCase): + build_path = '_build/text/docfx_yaml' #: Path of all the yaml files. + + yaml_files = { #: yaml files needed to be tested. + "class_files": { + "google": [ + "format.google.foo.Foo.yml", + "format.google.foo.FooException.InternalFoo.yml", + "format.google.foo.FooException.yml" + ], + "numpy": [ + "format.numpy.foo.Foo.yml", + "format.numpy.foo.FooException.InternalFoo.yml", + "format.numpy.foo.FooException.yml" + ], + "rst": [ + "format.rst.directives.DirectivesFoo.yml", + "format.rst.enum.EnumFoo.yml", + "format.rst.foo.Foo.yml", + "format.rst.foo.FooException.InternalFoo.yml", + "format.rst.foo.FooException.yml", + "format.rst.foo.InheritFoo.yml" + ], + "namespacepackage": [ + "nspkg.native.native_foo.Foo.yml", + "nspkg.pkgutil.pkgutil_foo.Foo.yml", + "nspkg.pkg_resources.pkg_resources_foo.Foo.yml" + ] + }, + "module_files": { + "google": [ + "format.google.foo.yml" + ], + "numpy": [ + "format.numpy.foo.yml" + ], + "rst": [ + "format.rst.directives.yml", + "format.rst.enum.yml", + "format.rst.foo.yml" + ] + }, + "package_files": { + "namesapcepackage": [ + "nspkg.yml", + "nspkg.native.native_foo.yml", + "nspkg.pkgutil.yml", + "nspkg.pkgutil.pkgutil_foo.yml", + "nspkg.pkg_resources.yml", + "nspkg.pkg_resources.pkg_resources_foo.yml" + ], + "format": [ + "format.yml", + "format.rst.yml", + "format.google.yml", + "format.numpy.yml" + ] + } + } + + def test_uid(self): + """ + Test whether uids are generated correctly. + """ + with sphinx_build('example'): + with open(os.path.join(self.build_path, self.yaml_files['class_files']['rst'][0]), 'r') as f: + # Test uids in format.rst.directives.DirectivesFoo.yml + data = yaml.safe_load(f) + + self.assertEqual( + data['items'][0]['uid'], + 'format.rst.directives.DirectivesFoo' + ) + + with open(os.path.join(self.build_path, self.yaml_files['module_files']['rst'][1]), 'r') as f: + # Test uids in format.rst.enum.yml + data = yaml.safe_load(f) + + self.assertEqual( + data['items'][0]['uid'], + 'format.rst.enum' + ) + + with open(os.path.join(self.build_path, self.yaml_files['package_files']['format'][2]), 'r') as f: + # Test uids in format.google.yml + data = yaml.safe_load(f) + + self.assertEqual( + data['items'][0]['uid'], + 'format.google' + ) + + def test_name(self): + """ + Test whether names are generated correctly. + """ + with sphinx_build('example'): + with open(os.path.join(self.build_path, self.yaml_files['class_files']['rst'][0]), 'r') as f: + # Test names in format.rst.directives.DirectivesFoo.yml + data = yaml.safe_load(f) + + self.assertEqual( + data['items'][0]['name'], + 'DirectivesFoo' + ) + + self.assertEqual( + data['items'][1]['name'], + 'method_remarks()' + ) # Test name of method format.rst.directives.DirectivesFoo.method_remarks + + with open(os.path.join(self.build_path, self.yaml_files['module_files']['rst'][1]), 'r') as f: + # Test names in format.rst.enum.yml + data = yaml.safe_load(f) + + self.assertEqual( + data['items'][0]['name'], + 'enum' + ) + + with open(os.path.join(self.build_path, self.yaml_files['package_files']['format'][2]), 'r') as f: + # Test names in format.google.yml + data = yaml.safe_load(f) + + self.assertEqual( + data['items'][0]['name'], + 'google' + ) + + def test_alert_box(self): + """ + Test whether alert boxes are generated correctly. + Avaliable alert boxes are Note, Warning, Tip and Important + """ + with sphinx_build('example'): + with open(os.path.join(self.build_path, self.yaml_files['class_files']['rst'][0]), 'r') as f: + # Test alert boxes in format.rst.directives.DirectivesFoo.yml + data = yaml.safe_load(f) + + self.assertEqual( + data['items'][0]['summary'], + 'Docstring of class .\n\n\n> [!NOTE]\n> Note content from class docstring.\n>\n> Second line of note content.\n>\n> many lines of content.\n>\n\n\n> [!WARNING]\n> Warning message from class docstring.\n>\n> Second line.\n>\n\n\n> [!TIP]\n> Tip content. \n>\n\n\n> [!IMPORTANT]\n> Important content.\n>\n\n\n> [!CAUTION]\n> Caution content.\n>' + ) # Test alert box in summary section + + self.assertEqual( + data['items'][0]['remarks'], + 'Remarks from class.\nMulti-line content should be supported.\n\n\n> [!NOTE]\n> Note conetnt under class remarks.\n>\n> Second line of note content.\n>\n> [!WARNING]\n> Warning content under class remarks.\n>\n> Second line.\n>\n> \n>\n> [!TIP]\n> Tip content.\n>\n> [!IMPORTANT]\n> Important content.\n>\n> [!CAUTION]\n> Caution content.\n>\n' + ) # Test alert box in remarks section + + def test_summary(self): + """ + Test module/package/class summary being extracted. + """ + with sphinx_build('example'): + with open(os.path.join(self.build_path, self.yaml_files['class_files']['rst'][3])) as f: + # Test summary in format.rst.foo.FooException.InternalFoo.yml + data = yaml.safe_load(f) + + self.assertEqual( + data['items'][0]['summary'].replace('\n', ' ').strip(), + 'Docstring of internal class . ' + 'This class is an internal class of .' + ) + + with open(os.path.join(self.build_path, self.yaml_files['module_files']['numpy'][0])) as f: + # Test summary in module format.numpy.foo.yml + data = yaml.safe_load(f) + + self.assertEqual( + data['items'][0]['summary'].strip(), + 'Docstring of module.' + ) + + with open(os.path.join(self.build_path, self.yaml_files['package_files']['format'][1])) as f: + # Test summary in format.rst.yml + data = yaml.safe_load(f) + + self.assertEqual( + data['items'][0]['summary'].strip(), + 'Docstring of package .' + ) + + def test_references(self): + """ + Test references are properly inserted. + """ + with sphinx_build('example'): + with open(os.path.join(self.build_path, self.yaml_files['class_files']['rst'][2])) as f: + # Test format.rst.foo.Foo.yml + data = yaml.safe_load(f) + + self.assertIn( + 'references', + data + ) # Test references is added. + + self.assertEqual( + data['references'][0]['parent'], + 'format.rst.foo.Foo' + ) # Test reference value + + self.assertEqual( + data['references'][-1]['spec.python'][2]['uid'], + 'int' + ) # Test reference spec + + def test_inheritance(self): + """ + Test multiple inheritance is properly resolved. + """ + with sphinx_build('example'): + with open(os.path.join(self.build_path, self.yaml_files['class_files']['rst'][5])) as f: + # Test format.rst.foo.InheritFoo.yml + data = yaml.safe_load(f) + + self.assertEqual( + data['items'][0]['inheritance'][0]['type'], + 'format.rst.foo.Foo' + ) + + self.assertEqual( + data['items'][0]['inheritance'][1]['type'], + 'builtins.dict' + ) + + def test_source(self): + """ + Test source info is parsed properly. + """ + with sphinx_build('example'): + with open(os.path.join(self.build_path, self.yaml_files['class_files']['namespacepackage'][1])) as f: + # Test source info of class Foo in nspkg.pkgutil.pkgutil_foo.Foo.yml + data = yaml.safe_load(f) + + self.assertIn( + 'source', + data['items'][0] + ) + + self.assertEqual( + data['items'][0]['source']['id'], + 'Foo' + ) + + self.assertIn( + 'format{sep}rst{sep}foo.py'.format(sep = os.sep), + data['items'][0]['source']['path'] + ) + + self.assertEqual( + 23, + data['items'][0]['source']['startLine'] + ) + + with open(os.path.join(self.build_path, self.yaml_files['module_files']['rst'][1])) as f: + # Test source info of module format.rst.enum in format.rst.enum.yml + data = yaml.safe_load(f) + + self.assertIn( + 'source', + data['items'][0] + ) + + self.assertEqual( + data['items'][0]['source']['id'], + 'enum' + ) + + self.assertIn( + 'format{sep}rst{sep}enum.py'.format(sep = os.sep), + data['items'][0]['source']['path'] + ) + + self.assertEqual( + 0, + data['items'][0]['source']['startLine'] + ) + + with open(os.path.join(self.build_path, self.yaml_files['package_files']['format'][2])) as f: + # Test source info of package google in format.google.yml + data = yaml.safe_load(f) + + self.assertIn( + 'source', + data['items'][0] + ) + + self.assertEqual( + data['items'][0]['source']['id'], + 'google' + ) + + self.assertIn( + 'format{sep}google{sep}__init__.py'.format(sep = os.sep), + data['items'][0]['source']['path'] + ) + + self.assertEqual( + 0, + data['items'][0]['source']['startLine'] + ) + + def test_external_link(self): + """ + Test external link should be written in markdown format. + """ + with sphinx_build('example'): + with open(os.path.join(self.build_path, self.yaml_files['class_files']['rst'][2])) as f: + # Test format.rst.foo.Foo.yml + data = yaml.safe_load(f) + + for item in data['items']: + if item['uid'] == 'format.rst.foo.Foo.method_external_link': + summary = re.sub(r'\n+', '\n', item['summary']).strip() + summary_lines = summary.split('\n') + + self.assertIn( + '[Link Text](http://inline.external.link)', + summary_lines[1] + ) + + self.assertNotIn( # Seperated link not supported. + '[Seperated Link](http://seperated.external.link)', + summary_lines[2] + ) + return + + self.fail() + + def test_google_format(self): + """ + Test google-style docstring. + """ + with sphinx_build('example'): + with open(os.path.join(self.build_path, self.yaml_files['class_files']['google'][0])) as f: + # Test format.google.foo.Foo.yml + data = yaml.safe_load(f) + + for item in data['items']: + if item['uid'] == 'format.google.foo.Foo.method_seealso': + self.assertEqual( + item['seealsoContent'].strip(), + 'Seealso contents.\n Multi-line should be supported.' + ) + + def test_numpy_format(self): + """ + Test numpy-style docstring. + """ + with sphinx_build('example'): + with open(os.path.join(self.build_path, self.yaml_files['class_files']['numpy'][0])) as f: + # Test format.numpy.foo.Foo.yml + data = yaml.safe_load(f) + + for item in data['items']: + if item['uid'] == 'format.numpy.foo.Foo.method_seealso': + self.assertEqual( + re.sub(r'\s+', ' ', item['seealsoContent']).strip(), + ' See also target.' + ) # Test see also centent from numpy format. + + def test_toc(self): + """ + Test toc structure. + """ + with sphinx_build('example'): + with open(os.path.join(self.build_path, 'toc.yml')) as f: + # Test toc.yml + data = yaml.safe_load(f) + + self.assertEqual( + data[0]['uid'], + 'project-example' + ) # Test project name node + + self.assertEqual( + len(data[0]['items']), + 3 + ) # Test there are three package nodes. + # Actually should be two, cuz namespace package should be placed in father nodes. + # TODO: To be fixed in future. + + self.assertEqual( + data[0]['items'][0]['uid'], + 'format' + ) # Test format package in toc. + + self.assertEqual( + data[0]['items'][1]['uid'], + 'nspkg' + ) # Test nspkg package in toc. + + def test_index(self): + """ + Test index information of project. + """ + with sphinx_build('example'): + with open(os.path.join(self.build_path, 'index.yml')) as yml_file: + # Test index.yml + data = yaml.safe_load(yml_file) + + self.assertEqual( + 'project-example', + data['items'][0]['uid'] + ) # Test there is only one item for project-example + + self.assertIn( + 'format', + data['items'][0]['children'] + ) # Test format package is in index.yml + + self.assertIn( + 'nspkg', + data['items'][0]['children'] + ) # Test nspkg package is in index.yml + + self.assertIn( + 'nspkg.native.native_foo', + data['items'][0]['children'] + ) # Test nspkg.native.native_foo package is in index.yml + # Actually this should not be in index. + # TODO: To be fixed in future. + + def test_examples(self): + """ + Test example contents + """ + with sphinx_build('example'): + with open(os.path.join(self.build_path, self.yaml_files['class_files']['rst'][2])) as f: + # Test format.rst.foo.Foo.yml + data = yaml.safe_load(f) + + for item in data['items']: + if item['uid'] == 'format.rst.foo.Foo.method_example': + self.assertIn( + 'example', + item + ) # Test example field existance + + self.assertIn( + 'VALUE0 = 0 #: Inline docstring of VALUE0', + item['example'][0] + ) # Test example content + + def test_seealso(self): + """ + Test seealso contents + """ + with sphinx_build('example'): + with open(os.path.join(self.build_path, self.yaml_files['class_files']['rst'][2])) as f: + # Test format.rst.foo.Foo.yml + data = yaml.safe_load(f) + + for item in data['items']: + if item['uid'] == 'format.rst.foo.Foo.method_seealso': + self.assertIn( + 'seealsoContent', + item + ) # Test seealso field existance + + self.assertIn( + 'Seealso contents.\n Multi-line should be supported.', + item['seealsoContent'] + ) # Test seealso content + + def test_enum(self): + """ + Test enum type support + """ + with sphinx_build('example'): + with open(os.path.join(self.build_path, self.yaml_files['class_files']['rst'][1])) as f: + data = yaml.safe_load(f) + for item in data['items']: + if item['uid'] == 'format.rst.enum.EnumFoo': + self.assertEqual( + item['children'], + ['format.rst.enum.EnumFoo.VALUE0', 'format.rst.enum.EnumFoo.VALUE1'] + ) # Test containing all enum values + if item['uid'] == 'format.rst.enum.EnumFoo.VALUE0': + self.assertEqual( + item['syntax'], + {'content': 'VALUE0 = 0', 'return': {'type': ['format.rst.enum.EnumFoo']}} + ) # Test enum value syntax + self.assertEqual( + item['type'], + 'attribute' + ) # Test enum value type diff --git a/packages/gcp-sphinx-docfx-yaml/tox.ini b/packages/gcp-sphinx-docfx-yaml/tox.ini new file mode 100644 index 000000000000..a547cf269cee --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tox.ini @@ -0,0 +1,30 @@ +[tox] +envlist = py35,py36,lint,docs + +[testenv] +setenv = + LANG=C +deps = -r{toxinidir}/requirements.txt + pytest + mock +commands = + py.test {posargs} + +[testenv:docs] +deps = + sphinx_rtd_theme + {[testenv]deps} +changedir = {toxinidir}/docs +commands = + sphinx-build -b html -d {envtmpdir}/doctrees . {envtmpdir}/html + +[testenv:lint] +deps = + {[testenv]deps} + prospector + pylint<1.7.0 +commands = + prospector \ + --profile-path={toxinidir} \ + --profile=prospector \ + --die-on-tool-error From 3e934aa0085c051b4c9447c0053464e5813ba7dc Mon Sep 17 00:00:00 2001 From: Dan Lee Date: Mon, 22 Mar 2021 15:12:25 -0400 Subject: [PATCH 002/279] chore: adding CODEOWNERS and COC --- .../gcp-sphinx-docfx-yaml/.github/CODEOWNERS | 9 +++ .../.github/PULL_REQUEST_TEMPLATE.md | 12 ++++ .../.github/sync-repo-settings.yaml | 37 +++++++++++ .../gcp-sphinx-docfx-yaml/code-of-conduct.md | 63 +++++++++++++++++++ 4 files changed, 121 insertions(+) create mode 100644 packages/gcp-sphinx-docfx-yaml/.github/CODEOWNERS create mode 100644 packages/gcp-sphinx-docfx-yaml/.github/PULL_REQUEST_TEMPLATE.md create mode 100644 packages/gcp-sphinx-docfx-yaml/.github/sync-repo-settings.yaml create mode 100644 packages/gcp-sphinx-docfx-yaml/code-of-conduct.md diff --git a/packages/gcp-sphinx-docfx-yaml/.github/CODEOWNERS b/packages/gcp-sphinx-docfx-yaml/.github/CODEOWNERS new file mode 100644 index 000000000000..c51369c19ced --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/.github/CODEOWNERS @@ -0,0 +1,9 @@ +# Code owners file. +# This file controls who is tagged for review for any given pull request. +# +# For syntax help see: +# https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners#codeowners-syntax + + +# The onramp team is responsible for all doc generation pipelines +* @googleapis/onramp diff --git a/packages/gcp-sphinx-docfx-yaml/.github/PULL_REQUEST_TEMPLATE.md b/packages/gcp-sphinx-docfx-yaml/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000000..9be497473456 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,12 @@ +Before you open a pull request, note that this repository is forked from [here](https://github.com/docascode/sphinx-docfx-yaml/). +Unless the issue you're trying to solve is unique to this specific repository, +please file an issue and/or send changes upstream to the original as well. + +__________________________________________________________________ + +Fixes # + +> It's a good idea to open an issue first for discussion. + +- [ ] Tests pass +- [ ] Appropriate changes to README are included in PR diff --git a/packages/gcp-sphinx-docfx-yaml/.github/sync-repo-settings.yaml b/packages/gcp-sphinx-docfx-yaml/.github/sync-repo-settings.yaml new file mode 100644 index 000000000000..91b830aca223 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/.github/sync-repo-settings.yaml @@ -0,0 +1,37 @@ +# Whether or not rebase-merging is enabled on this repository. +# Defaults to `true` +rebaseMergeAllowed: true + +# Whether or not squash-merging is enabled on this repository. +# Defaults to `true` +squashMergeAllowed: true + +# Whether or not PRs are merged with a merge commit on this repository. +# Defaults to `false` +mergeCommitAllowed: false + +# Rules for master branch protection +branchProtectionRules: +# Identifies the protection rule pattern. Name of the branch to be protected. +# Defaults to `master` +- pattern: master + # Can admins overwrite branch protection. + # Defaults to `true` + isAdminEnforced: true + # Number of approving reviews required to update matching branches. + # Defaults to `1` + requiredApprovingReviewCount: 1 + # Are reviews from code owners required to update matching branches. + # Defaults to `false` + requiresCodeOwnerReviews: true + # Require up to date branches + requiresStrictStatusChecks: true + # List of required status check contexts that must pass for commits to be accepted to matching branches. + requiredStatusCheckContexts: + - "cla/google" +# List of explicit permissions to add (additive only) +permissionRules: + # Team slug to add to repository permissions + - team: googleapis/onramp + # Access level required, one of push|pull|admin|maintain|triage + permission: push diff --git a/packages/gcp-sphinx-docfx-yaml/code-of-conduct.md b/packages/gcp-sphinx-docfx-yaml/code-of-conduct.md new file mode 100644 index 000000000000..f8b12cb550a3 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/code-of-conduct.md @@ -0,0 +1,63 @@ +# Google Open Source Community Guidelines + +At Google, we recognize and celebrate the creativity and collaboration of open +source contributors and the diversity of skills, experiences, cultures, and +opinions they bring to the projects and communities they participate in. + +Every one of Google's open source projects and communities are inclusive +environments, based on treating all individuals respectfully, regardless of +gender identity and expression, sexual orientation, disabilities, +neurodiversity, physical appearance, body size, ethnicity, nationality, race, +age, religion, or similar personal characteristic. + +We value diverse opinions, but we value respectful behavior more. + +Respectful behavior includes: + +* Being considerate, kind, constructive, and helpful. +* Not engaging in demeaning, discriminatory, harassing, hateful, sexualized, or + physically threatening behavior, speech, and imagery. +* Not engaging in unwanted physical contact. + +Some Google open source projects [may adopt][] an explicit project code of +conduct, which may have additional detailed expectations for participants. Most +of those projects will use our [modified Contributor Covenant][]. + +[may adopt]: https://opensource.google/docs/releasing/preparing/#conduct +[modified Contributor Covenant]: https://opensource.google/docs/releasing/template/CODE_OF_CONDUCT/ + +## Resolve peacefully + +We do not believe that all conflict is necessarily bad; healthy debate and +disagreement often yields positive results. However, it is never okay to be +disrespectful. + +If you see someone behaving disrespectfully, you are encouraged to address the +behavior directly with those involved. Many issues can be resolved quickly and +easily, and this gives people more control over the outcome of their dispute. +If you are unable to resolve the matter for any reason, or if the behavior is +threatening or harassing, report it. We are dedicated to providing an +environment where participants feel welcome and safe. + +## Reporting problems + +Some Google open source projects may adopt a project-specific code of conduct. +In those cases, a Google employee will be identified as the Project Steward, +who will receive and handle reports of code of conduct violations. In the event +that a project hasn’t identified a Project Steward, you can report problems by +emailing opensource@google.com. + +We will investigate every complaint, but you may not receive a direct response. +We will use our discretion in determining when and how to follow up on reported +incidents, which may range from not taking action to permanent expulsion from +the project and project-sponsored spaces. We will notify the accused of the +report and provide them an opportunity to discuss it before any action is +taken. The identity of the reporter will be omitted from the details of the +report supplied to the accused. In potentially harmful situations, such as +ongoing harassment or threats to anyone's safety, we may take action without +notice. + +*This document was adapted from the [IndieWeb Code of Conduct][] and can also +be found at .* + +[IndieWeb Code of Conduct]: https://indieweb.org/code-of-conduct From b6399c2d98b4d0f69aca8f915cabbfd3b0d1d97a Mon Sep 17 00:00:00 2001 From: Bu Sun Kim <8822365+busunkim96@users.noreply.github.com> Date: Wed, 24 Mar 2021 17:15:08 -0600 Subject: [PATCH 003/279] chore: add python repo templates (#2) * chore: add python repo templates * fix: address review comments --- .../.github/ISSUE_TEMPLATE/bug_report.md | 43 ++ .../.github/ISSUE_TEMPLATE/feature_request.md | 18 + .../.github/ISSUE_TEMPLATE/support_request.md | 7 + .../.github/header-checker-lint.yml | 15 + .../.github/release-please.yml | 1 + .../.github/snippet-bot.yml | 0 packages/gcp-sphinx-docfx-yaml/.gitignore | 63 +++ .../gcp-sphinx-docfx-yaml/.kokoro/build.sh | 59 +++ .../.kokoro/continuous/common.cfg | 27 + .../.kokoro/continuous/continuous.cfg | 1 + .../.kokoro/docker/docs/Dockerfile | 98 ++++ .../.kokoro/docker/docs/fetch_gpg_keys.sh | 45 ++ .../.kokoro/populate-secrets.sh | 43 ++ .../.kokoro/presubmit/common.cfg | 27 + .../.kokoro/presubmit/presubmit.cfg | 1 + .../gcp-sphinx-docfx-yaml/.kokoro/release.sh | 32 ++ .../.kokoro/release/common.cfg | 40 ++ .../.kokoro/release/release.cfg | 1 + .../.kokoro/trampoline.sh | 28 + .../.kokoro/trampoline_v2.sh | 487 ++++++++++++++++++ .../.pre-commit-config.yaml | 17 + .../gcp-sphinx-docfx-yaml/.repo-metadata.json | 10 + packages/gcp-sphinx-docfx-yaml/.trampolinerc | 52 ++ .../gcp-sphinx-docfx-yaml/CODE_OF_CONDUCT.md | 95 ++++ packages/gcp-sphinx-docfx-yaml/MANIFEST.in | 1 - packages/gcp-sphinx-docfx-yaml/renovate.json | 6 + .../scripts/decrypt-secrets.sh | 46 ++ .../scripts/readme-gen/readme_gen.py | 66 +++ .../readme-gen/templates/README.tmpl.rst | 87 ++++ .../readme-gen/templates/auth.tmpl.rst | 9 + .../templates/auth_api_key.tmpl.rst | 14 + .../templates/install_deps.tmpl.rst | 29 ++ .../templates/install_portaudio.tmpl.rst | 35 ++ packages/gcp-sphinx-docfx-yaml/setup.cfg | 2 - packages/gcp-sphinx-docfx-yaml/setup.py | 65 ++- packages/gcp-sphinx-docfx-yaml/synth.metadata | 18 + packages/gcp-sphinx-docfx-yaml/synth.py | 46 ++ .../gcp-sphinx-docfx-yaml/testing/.gitignore | 3 + 38 files changed, 1606 insertions(+), 31 deletions(-) create mode 100644 packages/gcp-sphinx-docfx-yaml/.github/ISSUE_TEMPLATE/bug_report.md create mode 100644 packages/gcp-sphinx-docfx-yaml/.github/ISSUE_TEMPLATE/feature_request.md create mode 100644 packages/gcp-sphinx-docfx-yaml/.github/ISSUE_TEMPLATE/support_request.md create mode 100644 packages/gcp-sphinx-docfx-yaml/.github/header-checker-lint.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/.github/release-please.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/.github/snippet-bot.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/.gitignore create mode 100755 packages/gcp-sphinx-docfx-yaml/.kokoro/build.sh create mode 100644 packages/gcp-sphinx-docfx-yaml/.kokoro/continuous/common.cfg create mode 100644 packages/gcp-sphinx-docfx-yaml/.kokoro/continuous/continuous.cfg create mode 100644 packages/gcp-sphinx-docfx-yaml/.kokoro/docker/docs/Dockerfile create mode 100755 packages/gcp-sphinx-docfx-yaml/.kokoro/docker/docs/fetch_gpg_keys.sh create mode 100755 packages/gcp-sphinx-docfx-yaml/.kokoro/populate-secrets.sh create mode 100644 packages/gcp-sphinx-docfx-yaml/.kokoro/presubmit/common.cfg create mode 100644 packages/gcp-sphinx-docfx-yaml/.kokoro/presubmit/presubmit.cfg create mode 100755 packages/gcp-sphinx-docfx-yaml/.kokoro/release.sh create mode 100644 packages/gcp-sphinx-docfx-yaml/.kokoro/release/common.cfg create mode 100644 packages/gcp-sphinx-docfx-yaml/.kokoro/release/release.cfg create mode 100755 packages/gcp-sphinx-docfx-yaml/.kokoro/trampoline.sh create mode 100755 packages/gcp-sphinx-docfx-yaml/.kokoro/trampoline_v2.sh create mode 100644 packages/gcp-sphinx-docfx-yaml/.pre-commit-config.yaml create mode 100644 packages/gcp-sphinx-docfx-yaml/.repo-metadata.json create mode 100644 packages/gcp-sphinx-docfx-yaml/.trampolinerc create mode 100644 packages/gcp-sphinx-docfx-yaml/CODE_OF_CONDUCT.md delete mode 100644 packages/gcp-sphinx-docfx-yaml/MANIFEST.in create mode 100644 packages/gcp-sphinx-docfx-yaml/renovate.json create mode 100755 packages/gcp-sphinx-docfx-yaml/scripts/decrypt-secrets.sh create mode 100644 packages/gcp-sphinx-docfx-yaml/scripts/readme-gen/readme_gen.py create mode 100644 packages/gcp-sphinx-docfx-yaml/scripts/readme-gen/templates/README.tmpl.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/scripts/readme-gen/templates/auth.tmpl.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/scripts/readme-gen/templates/auth_api_key.tmpl.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/scripts/readme-gen/templates/install_deps.tmpl.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/scripts/readme-gen/templates/install_portaudio.tmpl.rst delete mode 100644 packages/gcp-sphinx-docfx-yaml/setup.cfg create mode 100644 packages/gcp-sphinx-docfx-yaml/synth.metadata create mode 100644 packages/gcp-sphinx-docfx-yaml/synth.py create mode 100644 packages/gcp-sphinx-docfx-yaml/testing/.gitignore diff --git a/packages/gcp-sphinx-docfx-yaml/.github/ISSUE_TEMPLATE/bug_report.md b/packages/gcp-sphinx-docfx-yaml/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000000..d5bf92535d03 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,43 @@ +--- +name: Bug report +about: Create a report to help us improve + +--- + +Thanks for stopping by to let us know something could be better! + +**PLEASE READ**: If you have a support contract with Google, please create an issue in the [support console](https://cloud.google.com/support/) instead of filing on GitHub. This will ensure a timely response. + +Please run down the following list and make sure you've tried the usual "quick fixes": + + - Search the issues already opened: https://github.com/googleapis/sphinx-docfx-yaml/issues + - Search StackOverflow: https://stackoverflow.com/questions/tagged/google-cloud-platform+python + +If you are still having issues, please be sure to include as much information as possible: + +#### Environment details + + - OS type and version: + - Python version: `python --version` + - pip version: `pip --version` + - `sphinx-docfx-yaml` version: `pip show sphinx-docfx-yaml` + +#### Steps to reproduce + + 1. ? + 2. ? + +#### Code example + +```python +# example +``` + +#### Stack trace +``` +# example +``` + +Making sure to follow these steps will guarantee the quickest resolution possible. + +Thanks! diff --git a/packages/gcp-sphinx-docfx-yaml/.github/ISSUE_TEMPLATE/feature_request.md b/packages/gcp-sphinx-docfx-yaml/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 000000000000..6365857f33c6 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,18 @@ +--- +name: Feature request +about: Suggest an idea for this library + +--- + +Thanks for stopping by to let us know something could be better! + +**PLEASE READ**: If you have a support contract with Google, please create an issue in the [support console](https://cloud.google.com/support/) instead of filing on GitHub. This will ensure a timely response. + + **Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + **Describe the solution you'd like** +A clear and concise description of what you want to happen. + **Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + **Additional context** +Add any other context or screenshots about the feature request here. diff --git a/packages/gcp-sphinx-docfx-yaml/.github/ISSUE_TEMPLATE/support_request.md b/packages/gcp-sphinx-docfx-yaml/.github/ISSUE_TEMPLATE/support_request.md new file mode 100644 index 000000000000..995869032125 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/.github/ISSUE_TEMPLATE/support_request.md @@ -0,0 +1,7 @@ +--- +name: Support request +about: If you have a support contract with Google, please create an issue in the Google Cloud Support console. + +--- + +**PLEASE READ**: If you have a support contract with Google, please create an issue in the [support console](https://cloud.google.com/support/) instead of filing on GitHub. This will ensure a timely response. diff --git a/packages/gcp-sphinx-docfx-yaml/.github/header-checker-lint.yml b/packages/gcp-sphinx-docfx-yaml/.github/header-checker-lint.yml new file mode 100644 index 000000000000..fc281c05bd55 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/.github/header-checker-lint.yml @@ -0,0 +1,15 @@ +{"allowedCopyrightHolders": ["Google LLC"], + "allowedLicenses": ["Apache-2.0", "MIT", "BSD-3"], + "ignoreFiles": ["**/requirements.txt", "**/requirements-test.txt"], + "sourceFileExtensions": [ + "ts", + "js", + "java", + "sh", + "Dockerfile", + "yaml", + "py", + "html", + "txt" + ] +} \ No newline at end of file diff --git a/packages/gcp-sphinx-docfx-yaml/.github/release-please.yml b/packages/gcp-sphinx-docfx-yaml/.github/release-please.yml new file mode 100644 index 000000000000..4507ad0598a5 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/.github/release-please.yml @@ -0,0 +1 @@ +releaseType: python diff --git a/packages/gcp-sphinx-docfx-yaml/.github/snippet-bot.yml b/packages/gcp-sphinx-docfx-yaml/.github/snippet-bot.yml new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/gcp-sphinx-docfx-yaml/.gitignore b/packages/gcp-sphinx-docfx-yaml/.gitignore new file mode 100644 index 000000000000..b4243ced74e4 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/.gitignore @@ -0,0 +1,63 @@ +*.py[cod] +*.sw[op] + +# C extensions +*.so + +# Packages +*.egg +*.egg-info +dist +build +eggs +.eggs +parts +bin +var +sdist +develop-eggs +.installed.cfg +lib +lib64 +__pycache__ + +# Installer logs +pip-log.txt + +# Unit test / coverage reports +.coverage +.nox +.cache +.pytest_cache + + +# Mac +.DS_Store + +# JetBrains +.idea + +# VS Code +.vscode + +# emacs +*~ + +# Built documentation +docs/_build +bigquery/docs/generated +docs.metadata + +# Virtual environment +env/ + +# Test logs +coverage.xml +*sponge_log.xml + +# System test environment variables. +system_tests/local_test_setup + +# Make sure a generated file isn't accidentally committed. +pylintrc +pylintrc.test diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/build.sh b/packages/gcp-sphinx-docfx-yaml/.kokoro/build.sh new file mode 100755 index 000000000000..b3bb5c2b7a1a --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/build.sh @@ -0,0 +1,59 @@ +#!/bin/bash +# Copyright 2018 Google LLC +# +# 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 +# +# https://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. + +set -eo pipefail + +if [[ -z "${PROJECT_ROOT:-}" ]]; then + PROJECT_ROOT="github/sphinx-docfx-yaml" +fi + +cd "${PROJECT_ROOT}" + +# Disable buffering, so that the logs stream through. +export PYTHONUNBUFFERED=1 + +# Debug: show build environment +env | grep KOKORO + +# Setup service account credentials. +export GOOGLE_APPLICATION_CREDENTIALS=${KOKORO_GFILE_DIR}/service-account.json + +# Setup project id. +export PROJECT_ID=$(cat "${KOKORO_GFILE_DIR}/project-id.json") + +# Remove old nox +python3 -m pip uninstall --yes --quiet nox-automation + +# Install nox +python3 -m pip install --upgrade --quiet nox +python3 -m nox --version + +# If this is a continuous build, send the test log to the FlakyBot. +# See https://github.com/googleapis/repo-automation-bots/tree/master/packages/flakybot. +if [[ $KOKORO_BUILD_ARTIFACTS_SUBDIR = *"continuous"* ]]; then + cleanup() { + chmod +x $KOKORO_GFILE_DIR/linux_amd64/flakybot + $KOKORO_GFILE_DIR/linux_amd64/flakybot + } + trap cleanup EXIT HUP +fi + +# If NOX_SESSION is set, it only runs the specified session, +# otherwise run all the sessions. +if [[ -n "${NOX_SESSION:-}" ]]; then + python3 -m nox -s ${NOX_SESSION:-} +else + python3 -m nox +fi diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/continuous/common.cfg b/packages/gcp-sphinx-docfx-yaml/.kokoro/continuous/common.cfg new file mode 100644 index 000000000000..6dc372500e3b --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/continuous/common.cfg @@ -0,0 +1,27 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +# Build logs will be here +action { + define_artifacts { + regex: "**/*sponge_log.xml" + } +} + +# Download trampoline resources. +gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline" + +# Download resources for system tests (service account key, etc.) +gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/google-cloud-python" + +# Use the trampoline script to run in docker. +build_file: "sphinx-docfx-yaml/.kokoro/trampoline.sh" + +# Configure the docker image for kokoro-trampoline. +env_vars: { + key: "TRAMPOLINE_IMAGE" + value: "gcr.io/cloud-devrel-kokoro-resources/python-multi" +} +env_vars: { + key: "TRAMPOLINE_BUILD_FILE" + value: "github/sphinx-docfx-yaml/.kokoro/build.sh" +} diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/continuous/continuous.cfg b/packages/gcp-sphinx-docfx-yaml/.kokoro/continuous/continuous.cfg new file mode 100644 index 000000000000..8f43917d92fe --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/continuous/continuous.cfg @@ -0,0 +1 @@ +# Format: //devtools/kokoro/config/proto/build.proto \ No newline at end of file diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/docker/docs/Dockerfile b/packages/gcp-sphinx-docfx-yaml/.kokoro/docker/docs/Dockerfile new file mode 100644 index 000000000000..412b0b56a921 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/docker/docs/Dockerfile @@ -0,0 +1,98 @@ +# Copyright 2020 Google LLC +# +# 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. + +from ubuntu:20.04 + +ENV DEBIAN_FRONTEND noninteractive + +# Ensure local Python is preferred over distribution Python. +ENV PATH /usr/local/bin:$PATH + +# Install dependencies. +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + apt-transport-https \ + build-essential \ + ca-certificates \ + curl \ + dirmngr \ + git \ + gpg-agent \ + graphviz \ + libbz2-dev \ + libdb5.3-dev \ + libexpat1-dev \ + libffi-dev \ + liblzma-dev \ + libreadline-dev \ + libsnappy-dev \ + libssl-dev \ + libsqlite3-dev \ + portaudio19-dev \ + redis-server \ + software-properties-common \ + ssh \ + sudo \ + tcl \ + tcl-dev \ + tk \ + tk-dev \ + uuid-dev \ + wget \ + zlib1g-dev \ + && add-apt-repository universe \ + && apt-get update \ + && apt-get -y install jq \ + && apt-get clean autoclean \ + && apt-get autoremove -y \ + && rm -rf /var/lib/apt/lists/* \ + && rm -f /var/cache/apt/archives/*.deb + + +COPY fetch_gpg_keys.sh /tmp +# Install the desired versions of Python. +RUN set -ex \ + && export GNUPGHOME="$(mktemp -d)" \ + && echo "disable-ipv6" >> "${GNUPGHOME}/dirmngr.conf" \ + && /tmp/fetch_gpg_keys.sh \ + && for PYTHON_VERSION in 3.7.8 3.8.5; do \ + wget --no-check-certificate -O python-${PYTHON_VERSION}.tar.xz "https://www.python.org/ftp/python/${PYTHON_VERSION%%[a-z]*}/Python-$PYTHON_VERSION.tar.xz" \ + && wget --no-check-certificate -O python-${PYTHON_VERSION}.tar.xz.asc "https://www.python.org/ftp/python/${PYTHON_VERSION%%[a-z]*}/Python-$PYTHON_VERSION.tar.xz.asc" \ + && gpg --batch --verify python-${PYTHON_VERSION}.tar.xz.asc python-${PYTHON_VERSION}.tar.xz \ + && rm -r python-${PYTHON_VERSION}.tar.xz.asc \ + && mkdir -p /usr/src/python-${PYTHON_VERSION} \ + && tar -xJC /usr/src/python-${PYTHON_VERSION} --strip-components=1 -f python-${PYTHON_VERSION}.tar.xz \ + && rm python-${PYTHON_VERSION}.tar.xz \ + && cd /usr/src/python-${PYTHON_VERSION} \ + && ./configure \ + --enable-shared \ + # This works only on Python 2.7 and throws a warning on every other + # version, but seems otherwise harmless. + --enable-unicode=ucs4 \ + --with-system-ffi \ + --without-ensurepip \ + && make -j$(nproc) \ + && make install \ + && ldconfig \ + ; done \ + && rm -rf "${GNUPGHOME}" \ + && rm -rf /usr/src/python* \ + && rm -rf ~/.cache/ + +RUN wget -O /tmp/get-pip.py 'https://bootstrap.pypa.io/get-pip.py' \ + && python3.7 /tmp/get-pip.py \ + && python3.8 /tmp/get-pip.py \ + && rm /tmp/get-pip.py + +CMD ["python3.7"] diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/docker/docs/fetch_gpg_keys.sh b/packages/gcp-sphinx-docfx-yaml/.kokoro/docker/docs/fetch_gpg_keys.sh new file mode 100755 index 000000000000..d653dd868e4b --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/docker/docs/fetch_gpg_keys.sh @@ -0,0 +1,45 @@ +#!/bin/bash +# Copyright 2020 Google LLC +# +# 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. + +# A script to fetch gpg keys with retry. +# Avoid jinja parsing the file. +# + +function retry { + if [[ "${#}" -le 1 ]]; then + echo "Usage: ${0} retry_count commands.." + exit 1 + fi + local retries=${1} + local command="${@:2}" + until [[ "${retries}" -le 0 ]]; do + $command && return 0 + if [[ $? -ne 0 ]]; then + echo "command failed, retrying" + ((retries--)) + fi + done + return 1 +} + +# 3.6.9, 3.7.5 (Ned Deily) +retry 3 gpg --keyserver ha.pool.sks-keyservers.net --recv-keys \ + 0D96DF4D4110E5C43FBFB17F2D347EA6AA65421D + +# 3.8.0 (Łukasz Langa) +retry 3 gpg --keyserver ha.pool.sks-keyservers.net --recv-keys \ + E3FF2839C048B25C084DEBE9B26995E310250568 + +# diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/populate-secrets.sh b/packages/gcp-sphinx-docfx-yaml/.kokoro/populate-secrets.sh new file mode 100755 index 000000000000..f52514257ef0 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/populate-secrets.sh @@ -0,0 +1,43 @@ +#!/bin/bash +# Copyright 2020 Google LLC. +# +# 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. + +set -eo pipefail + +function now { date +"%Y-%m-%d %H:%M:%S" | tr -d '\n' ;} +function msg { println "$*" >&2 ;} +function println { printf '%s\n' "$(now) $*" ;} + + +# Populates requested secrets set in SECRET_MANAGER_KEYS from service account: +# kokoro-trampoline@cloud-devrel-kokoro-resources.iam.gserviceaccount.com +SECRET_LOCATION="${KOKORO_GFILE_DIR}/secret_manager" +msg "Creating folder on disk for secrets: ${SECRET_LOCATION}" +mkdir -p ${SECRET_LOCATION} +for key in $(echo ${SECRET_MANAGER_KEYS} | sed "s/,/ /g") +do + msg "Retrieving secret ${key}" + docker run --entrypoint=gcloud \ + --volume=${KOKORO_GFILE_DIR}:${KOKORO_GFILE_DIR} \ + gcr.io/google.com/cloudsdktool/cloud-sdk \ + secrets versions access latest \ + --project cloud-devrel-kokoro-resources \ + --secret ${key} > \ + "${SECRET_LOCATION}/${key}" + if [[ $? == 0 ]]; then + msg "Secret written to ${SECRET_LOCATION}/${key}" + else + msg "Error retrieving secret ${key}" + fi +done diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/presubmit/common.cfg b/packages/gcp-sphinx-docfx-yaml/.kokoro/presubmit/common.cfg new file mode 100644 index 000000000000..6dc372500e3b --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/presubmit/common.cfg @@ -0,0 +1,27 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +# Build logs will be here +action { + define_artifacts { + regex: "**/*sponge_log.xml" + } +} + +# Download trampoline resources. +gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline" + +# Download resources for system tests (service account key, etc.) +gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/google-cloud-python" + +# Use the trampoline script to run in docker. +build_file: "sphinx-docfx-yaml/.kokoro/trampoline.sh" + +# Configure the docker image for kokoro-trampoline. +env_vars: { + key: "TRAMPOLINE_IMAGE" + value: "gcr.io/cloud-devrel-kokoro-resources/python-multi" +} +env_vars: { + key: "TRAMPOLINE_BUILD_FILE" + value: "github/sphinx-docfx-yaml/.kokoro/build.sh" +} diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/presubmit/presubmit.cfg b/packages/gcp-sphinx-docfx-yaml/.kokoro/presubmit/presubmit.cfg new file mode 100644 index 000000000000..8f43917d92fe --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/presubmit/presubmit.cfg @@ -0,0 +1 @@ +# Format: //devtools/kokoro/config/proto/build.proto \ No newline at end of file diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/release.sh b/packages/gcp-sphinx-docfx-yaml/.kokoro/release.sh new file mode 100755 index 000000000000..1b24c74bef86 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/release.sh @@ -0,0 +1,32 @@ +#!/bin/bash +# Copyright 2020 Google LLC +# +# 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 +# +# https://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. + +set -eo pipefail + +# Start the releasetool reporter +python3 -m pip install gcp-releasetool +python3 -m releasetool publish-reporter-script > /tmp/publisher-script; source /tmp/publisher-script + +# Ensure that we have the latest versions of Twine, Wheel, and Setuptools. +python3 -m pip install --upgrade twine wheel setuptools + +# Disable buffering, so that the logs stream through. +export PYTHONUNBUFFERED=1 + +# Move into the package, build the distribution and upload. +TWINE_PASSWORD=$(cat "${KOKORO_KEYSTORE_DIR}/73713_google_cloud_pypi_password") +cd github/sphinx-docfx-yaml +python3 setup.py sdist bdist_wheel +twine upload --username gcloudpypi --password "${TWINE_PASSWORD}" dist/* diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/release/common.cfg b/packages/gcp-sphinx-docfx-yaml/.kokoro/release/common.cfg new file mode 100644 index 000000000000..0668ac6665f8 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/release/common.cfg @@ -0,0 +1,40 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +# Build logs will be here +action { + define_artifacts { + regex: "**/*sponge_log.xml" + } +} + +# Download trampoline resources. +gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline" + +# Use the trampoline script to run in docker. +build_file: "sphinx-docfx-yaml/.kokoro/trampoline.sh" + +# Configure the docker image for kokoro-trampoline. +env_vars: { + key: "TRAMPOLINE_IMAGE" + value: "gcr.io/cloud-devrel-kokoro-resources/python-multi" +} +env_vars: { + key: "TRAMPOLINE_BUILD_FILE" + value: "github/sphinx-docfx-yaml/.kokoro/release.sh" +} + +# Fetch PyPI password +before_action { + fetch_keystore { + keystore_resource { + keystore_config_id: 73713 + keyname: "google_cloud_pypi_password" + } + } +} + +# Tokens needed to report release status back to GitHub +env_vars: { + key: "SECRET_MANAGER_KEYS" + value: "releasetool-publish-reporter-app,releasetool-publish-reporter-googleapis-installation,releasetool-publish-reporter-pem" +} \ No newline at end of file diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/release/release.cfg b/packages/gcp-sphinx-docfx-yaml/.kokoro/release/release.cfg new file mode 100644 index 000000000000..8f43917d92fe --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/release/release.cfg @@ -0,0 +1 @@ +# Format: //devtools/kokoro/config/proto/build.proto \ No newline at end of file diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/trampoline.sh b/packages/gcp-sphinx-docfx-yaml/.kokoro/trampoline.sh new file mode 100755 index 000000000000..f39236e943a8 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/trampoline.sh @@ -0,0 +1,28 @@ +#!/bin/bash +# Copyright 2017 Google Inc. +# +# 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. + +set -eo pipefail + +# Always run the cleanup script, regardless of the success of bouncing into +# the container. +function cleanup() { + chmod +x ${KOKORO_GFILE_DIR}/trampoline_cleanup.sh + ${KOKORO_GFILE_DIR}/trampoline_cleanup.sh + echo "cleanup"; +} +trap cleanup EXIT + +$(dirname $0)/populate-secrets.sh # Secret Manager secrets. +python3 "${KOKORO_GFILE_DIR}/trampoline_v1.py" \ No newline at end of file diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/trampoline_v2.sh b/packages/gcp-sphinx-docfx-yaml/.kokoro/trampoline_v2.sh new file mode 100755 index 000000000000..4af6cdc26dbc --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/trampoline_v2.sh @@ -0,0 +1,487 @@ +#!/usr/bin/env bash +# Copyright 2020 Google LLC +# +# 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. + +# trampoline_v2.sh +# +# This script does 3 things. +# +# 1. Prepare the Docker image for the test +# 2. Run the Docker with appropriate flags to run the test +# 3. Upload the newly built Docker image +# +# in a way that is somewhat compatible with trampoline_v1. +# +# To run this script, first download few files from gcs to /dev/shm. +# (/dev/shm is passed into the container as KOKORO_GFILE_DIR). +# +# gsutil cp gs://cloud-devrel-kokoro-resources/python-docs-samples/secrets_viewer_service_account.json /dev/shm +# gsutil cp gs://cloud-devrel-kokoro-resources/python-docs-samples/automl_secrets.txt /dev/shm +# +# Then run the script. +# .kokoro/trampoline_v2.sh +# +# These environment variables are required: +# TRAMPOLINE_IMAGE: The docker image to use. +# TRAMPOLINE_DOCKERFILE: The location of the Dockerfile. +# +# You can optionally change these environment variables: +# TRAMPOLINE_IMAGE_UPLOAD: +# (true|false): Whether to upload the Docker image after the +# successful builds. +# TRAMPOLINE_BUILD_FILE: The script to run in the docker container. +# TRAMPOLINE_WORKSPACE: The workspace path in the docker container. +# Defaults to /workspace. +# Potentially there are some repo specific envvars in .trampolinerc in +# the project root. + + +set -euo pipefail + +TRAMPOLINE_VERSION="2.0.5" + +if command -v tput >/dev/null && [[ -n "${TERM:-}" ]]; then + readonly IO_COLOR_RED="$(tput setaf 1)" + readonly IO_COLOR_GREEN="$(tput setaf 2)" + readonly IO_COLOR_YELLOW="$(tput setaf 3)" + readonly IO_COLOR_RESET="$(tput sgr0)" +else + readonly IO_COLOR_RED="" + readonly IO_COLOR_GREEN="" + readonly IO_COLOR_YELLOW="" + readonly IO_COLOR_RESET="" +fi + +function function_exists { + [ $(LC_ALL=C type -t $1)"" == "function" ] +} + +# Logs a message using the given color. The first argument must be one +# of the IO_COLOR_* variables defined above, such as +# "${IO_COLOR_YELLOW}". The remaining arguments will be logged in the +# given color. The log message will also have an RFC-3339 timestamp +# prepended (in UTC). You can disable the color output by setting +# TERM=vt100. +function log_impl() { + local color="$1" + shift + local timestamp="$(date -u "+%Y-%m-%dT%H:%M:%SZ")" + echo "================================================================" + echo "${color}${timestamp}:" "$@" "${IO_COLOR_RESET}" + echo "================================================================" +} + +# Logs the given message with normal coloring and a timestamp. +function log() { + log_impl "${IO_COLOR_RESET}" "$@" +} + +# Logs the given message in green with a timestamp. +function log_green() { + log_impl "${IO_COLOR_GREEN}" "$@" +} + +# Logs the given message in yellow with a timestamp. +function log_yellow() { + log_impl "${IO_COLOR_YELLOW}" "$@" +} + +# Logs the given message in red with a timestamp. +function log_red() { + log_impl "${IO_COLOR_RED}" "$@" +} + +readonly tmpdir=$(mktemp -d -t ci-XXXXXXXX) +readonly tmphome="${tmpdir}/h" +mkdir -p "${tmphome}" + +function cleanup() { + rm -rf "${tmpdir}" +} +trap cleanup EXIT + +RUNNING_IN_CI="${RUNNING_IN_CI:-false}" + +# The workspace in the container, defaults to /workspace. +TRAMPOLINE_WORKSPACE="${TRAMPOLINE_WORKSPACE:-/workspace}" + +pass_down_envvars=( + # TRAMPOLINE_V2 variables. + # Tells scripts whether they are running as part of CI or not. + "RUNNING_IN_CI" + # Indicates which CI system we're in. + "TRAMPOLINE_CI" + # Indicates the version of the script. + "TRAMPOLINE_VERSION" +) + +log_yellow "Building with Trampoline ${TRAMPOLINE_VERSION}" + +# Detect which CI systems we're in. If we're in any of the CI systems +# we support, `RUNNING_IN_CI` will be true and `TRAMPOLINE_CI` will be +# the name of the CI system. Both envvars will be passing down to the +# container for telling which CI system we're in. +if [[ -n "${KOKORO_BUILD_ID:-}" ]]; then + # descriptive env var for indicating it's on CI. + RUNNING_IN_CI="true" + TRAMPOLINE_CI="kokoro" + if [[ "${TRAMPOLINE_USE_LEGACY_SERVICE_ACCOUNT:-}" == "true" ]]; then + if [[ ! -f "${KOKORO_GFILE_DIR}/kokoro-trampoline.service-account.json" ]]; then + log_red "${KOKORO_GFILE_DIR}/kokoro-trampoline.service-account.json does not exist. Did you forget to mount cloud-devrel-kokoro-resources/trampoline? Aborting." + exit 1 + fi + # This service account will be activated later. + TRAMPOLINE_SERVICE_ACCOUNT="${KOKORO_GFILE_DIR}/kokoro-trampoline.service-account.json" + else + if [[ "${TRAMPOLINE_VERBOSE:-}" == "true" ]]; then + gcloud auth list + fi + log_yellow "Configuring Container Registry access" + gcloud auth configure-docker --quiet + fi + pass_down_envvars+=( + # KOKORO dynamic variables. + "KOKORO_BUILD_NUMBER" + "KOKORO_BUILD_ID" + "KOKORO_JOB_NAME" + "KOKORO_GIT_COMMIT" + "KOKORO_GITHUB_COMMIT" + "KOKORO_GITHUB_PULL_REQUEST_NUMBER" + "KOKORO_GITHUB_PULL_REQUEST_COMMIT" + # For FlakyBot + "KOKORO_GITHUB_COMMIT_URL" + "KOKORO_GITHUB_PULL_REQUEST_URL" + ) +elif [[ "${TRAVIS:-}" == "true" ]]; then + RUNNING_IN_CI="true" + TRAMPOLINE_CI="travis" + pass_down_envvars+=( + "TRAVIS_BRANCH" + "TRAVIS_BUILD_ID" + "TRAVIS_BUILD_NUMBER" + "TRAVIS_BUILD_WEB_URL" + "TRAVIS_COMMIT" + "TRAVIS_COMMIT_MESSAGE" + "TRAVIS_COMMIT_RANGE" + "TRAVIS_JOB_NAME" + "TRAVIS_JOB_NUMBER" + "TRAVIS_JOB_WEB_URL" + "TRAVIS_PULL_REQUEST" + "TRAVIS_PULL_REQUEST_BRANCH" + "TRAVIS_PULL_REQUEST_SHA" + "TRAVIS_PULL_REQUEST_SLUG" + "TRAVIS_REPO_SLUG" + "TRAVIS_SECURE_ENV_VARS" + "TRAVIS_TAG" + ) +elif [[ -n "${GITHUB_RUN_ID:-}" ]]; then + RUNNING_IN_CI="true" + TRAMPOLINE_CI="github-workflow" + pass_down_envvars+=( + "GITHUB_WORKFLOW" + "GITHUB_RUN_ID" + "GITHUB_RUN_NUMBER" + "GITHUB_ACTION" + "GITHUB_ACTIONS" + "GITHUB_ACTOR" + "GITHUB_REPOSITORY" + "GITHUB_EVENT_NAME" + "GITHUB_EVENT_PATH" + "GITHUB_SHA" + "GITHUB_REF" + "GITHUB_HEAD_REF" + "GITHUB_BASE_REF" + ) +elif [[ "${CIRCLECI:-}" == "true" ]]; then + RUNNING_IN_CI="true" + TRAMPOLINE_CI="circleci" + pass_down_envvars+=( + "CIRCLE_BRANCH" + "CIRCLE_BUILD_NUM" + "CIRCLE_BUILD_URL" + "CIRCLE_COMPARE_URL" + "CIRCLE_JOB" + "CIRCLE_NODE_INDEX" + "CIRCLE_NODE_TOTAL" + "CIRCLE_PREVIOUS_BUILD_NUM" + "CIRCLE_PROJECT_REPONAME" + "CIRCLE_PROJECT_USERNAME" + "CIRCLE_REPOSITORY_URL" + "CIRCLE_SHA1" + "CIRCLE_STAGE" + "CIRCLE_USERNAME" + "CIRCLE_WORKFLOW_ID" + "CIRCLE_WORKFLOW_JOB_ID" + "CIRCLE_WORKFLOW_UPSTREAM_JOB_IDS" + "CIRCLE_WORKFLOW_WORKSPACE_ID" + ) +fi + +# Configure the service account for pulling the docker image. +function repo_root() { + local dir="$1" + while [[ ! -d "${dir}/.git" ]]; do + dir="$(dirname "$dir")" + done + echo "${dir}" +} + +# Detect the project root. In CI builds, we assume the script is in +# the git tree and traverse from there, otherwise, traverse from `pwd` +# to find `.git` directory. +if [[ "${RUNNING_IN_CI:-}" == "true" ]]; then + PROGRAM_PATH="$(realpath "$0")" + PROGRAM_DIR="$(dirname "${PROGRAM_PATH}")" + PROJECT_ROOT="$(repo_root "${PROGRAM_DIR}")" +else + PROJECT_ROOT="$(repo_root $(pwd))" +fi + +log_yellow "Changing to the project root: ${PROJECT_ROOT}." +cd "${PROJECT_ROOT}" + +# To support relative path for `TRAMPOLINE_SERVICE_ACCOUNT`, we need +# to use this environment variable in `PROJECT_ROOT`. +if [[ -n "${TRAMPOLINE_SERVICE_ACCOUNT:-}" ]]; then + + mkdir -p "${tmpdir}/gcloud" + gcloud_config_dir="${tmpdir}/gcloud" + + log_yellow "Using isolated gcloud config: ${gcloud_config_dir}." + export CLOUDSDK_CONFIG="${gcloud_config_dir}" + + log_yellow "Using ${TRAMPOLINE_SERVICE_ACCOUNT} for authentication." + gcloud auth activate-service-account \ + --key-file "${TRAMPOLINE_SERVICE_ACCOUNT}" + log_yellow "Configuring Container Registry access" + gcloud auth configure-docker --quiet +fi + +required_envvars=( + # The basic trampoline configurations. + "TRAMPOLINE_IMAGE" + "TRAMPOLINE_BUILD_FILE" +) + +if [[ -f "${PROJECT_ROOT}/.trampolinerc" ]]; then + source "${PROJECT_ROOT}/.trampolinerc" +fi + +log_yellow "Checking environment variables." +for e in "${required_envvars[@]}" +do + if [[ -z "${!e:-}" ]]; then + log "Missing ${e} env var. Aborting." + exit 1 + fi +done + +# We want to support legacy style TRAMPOLINE_BUILD_FILE used with V1 +# script: e.g. "github/repo-name/.kokoro/run_tests.sh" +TRAMPOLINE_BUILD_FILE="${TRAMPOLINE_BUILD_FILE#github/*/}" +log_yellow "Using TRAMPOLINE_BUILD_FILE: ${TRAMPOLINE_BUILD_FILE}" + +# ignore error on docker operations and test execution +set +e + +log_yellow "Preparing Docker image." +# We only download the docker image in CI builds. +if [[ "${RUNNING_IN_CI:-}" == "true" ]]; then + # Download the docker image specified by `TRAMPOLINE_IMAGE` + + # We may want to add --max-concurrent-downloads flag. + + log_yellow "Start pulling the Docker image: ${TRAMPOLINE_IMAGE}." + if docker pull "${TRAMPOLINE_IMAGE}"; then + log_green "Finished pulling the Docker image: ${TRAMPOLINE_IMAGE}." + has_image="true" + else + log_red "Failed pulling the Docker image: ${TRAMPOLINE_IMAGE}." + has_image="false" + fi +else + # For local run, check if we have the image. + if docker images "${TRAMPOLINE_IMAGE}:latest" | grep "${TRAMPOLINE_IMAGE}"; then + has_image="true" + else + has_image="false" + fi +fi + + +# The default user for a Docker container has uid 0 (root). To avoid +# creating root-owned files in the build directory we tell docker to +# use the current user ID. +user_uid="$(id -u)" +user_gid="$(id -g)" +user_name="$(id -un)" + +# To allow docker in docker, we add the user to the docker group in +# the host os. +docker_gid=$(cut -d: -f3 < <(getent group docker)) + +update_cache="false" +if [[ "${TRAMPOLINE_DOCKERFILE:-none}" != "none" ]]; then + # Build the Docker image from the source. + context_dir=$(dirname "${TRAMPOLINE_DOCKERFILE}") + docker_build_flags=( + "-f" "${TRAMPOLINE_DOCKERFILE}" + "-t" "${TRAMPOLINE_IMAGE}" + "--build-arg" "UID=${user_uid}" + "--build-arg" "USERNAME=${user_name}" + ) + if [[ "${has_image}" == "true" ]]; then + docker_build_flags+=("--cache-from" "${TRAMPOLINE_IMAGE}") + fi + + log_yellow "Start building the docker image." + if [[ "${TRAMPOLINE_VERBOSE:-false}" == "true" ]]; then + echo "docker build" "${docker_build_flags[@]}" "${context_dir}" + fi + + # ON CI systems, we want to suppress docker build logs, only + # output the logs when it fails. + if [[ "${RUNNING_IN_CI:-}" == "true" ]]; then + if docker build "${docker_build_flags[@]}" "${context_dir}" \ + > "${tmpdir}/docker_build.log" 2>&1; then + if [[ "${TRAMPOLINE_VERBOSE:-}" == "true" ]]; then + cat "${tmpdir}/docker_build.log" + fi + + log_green "Finished building the docker image." + update_cache="true" + else + log_red "Failed to build the Docker image, aborting." + log_yellow "Dumping the build logs:" + cat "${tmpdir}/docker_build.log" + exit 1 + fi + else + if docker build "${docker_build_flags[@]}" "${context_dir}"; then + log_green "Finished building the docker image." + update_cache="true" + else + log_red "Failed to build the Docker image, aborting." + exit 1 + fi + fi +else + if [[ "${has_image}" != "true" ]]; then + log_red "We do not have ${TRAMPOLINE_IMAGE} locally, aborting." + exit 1 + fi +fi + +# We use an array for the flags so they are easier to document. +docker_flags=( + # Remove the container after it exists. + "--rm" + + # Use the host network. + "--network=host" + + # Run in priviledged mode. We are not using docker for sandboxing or + # isolation, just for packaging our dev tools. + "--privileged" + + # Run the docker script with the user id. Because the docker image gets to + # write in ${PWD} you typically want this to be your user id. + # To allow docker in docker, we need to use docker gid on the host. + "--user" "${user_uid}:${docker_gid}" + + # Pass down the USER. + "--env" "USER=${user_name}" + + # Mount the project directory inside the Docker container. + "--volume" "${PROJECT_ROOT}:${TRAMPOLINE_WORKSPACE}" + "--workdir" "${TRAMPOLINE_WORKSPACE}" + "--env" "PROJECT_ROOT=${TRAMPOLINE_WORKSPACE}" + + # Mount the temporary home directory. + "--volume" "${tmphome}:/h" + "--env" "HOME=/h" + + # Allow docker in docker. + "--volume" "/var/run/docker.sock:/var/run/docker.sock" + + # Mount the /tmp so that docker in docker can mount the files + # there correctly. + "--volume" "/tmp:/tmp" + # Pass down the KOKORO_GFILE_DIR and KOKORO_KEYSTORE_DIR + # TODO(tmatsuo): This part is not portable. + "--env" "TRAMPOLINE_SECRET_DIR=/secrets" + "--volume" "${KOKORO_GFILE_DIR:-/dev/shm}:/secrets/gfile" + "--env" "KOKORO_GFILE_DIR=/secrets/gfile" + "--volume" "${KOKORO_KEYSTORE_DIR:-/dev/shm}:/secrets/keystore" + "--env" "KOKORO_KEYSTORE_DIR=/secrets/keystore" +) + +# Add an option for nicer output if the build gets a tty. +if [[ -t 0 ]]; then + docker_flags+=("-it") +fi + +# Passing down env vars +for e in "${pass_down_envvars[@]}" +do + if [[ -n "${!e:-}" ]]; then + docker_flags+=("--env" "${e}=${!e}") + fi +done + +# If arguments are given, all arguments will become the commands run +# in the container, otherwise run TRAMPOLINE_BUILD_FILE. +if [[ $# -ge 1 ]]; then + log_yellow "Running the given commands '" "${@:1}" "' in the container." + readonly commands=("${@:1}") + if [[ "${TRAMPOLINE_VERBOSE:-}" == "true" ]]; then + echo docker run "${docker_flags[@]}" "${TRAMPOLINE_IMAGE}" "${commands[@]}" + fi + docker run "${docker_flags[@]}" "${TRAMPOLINE_IMAGE}" "${commands[@]}" +else + log_yellow "Running the tests in a Docker container." + docker_flags+=("--entrypoint=${TRAMPOLINE_BUILD_FILE}") + if [[ "${TRAMPOLINE_VERBOSE:-}" == "true" ]]; then + echo docker run "${docker_flags[@]}" "${TRAMPOLINE_IMAGE}" + fi + docker run "${docker_flags[@]}" "${TRAMPOLINE_IMAGE}" +fi + + +test_retval=$? + +if [[ ${test_retval} -eq 0 ]]; then + log_green "Build finished with ${test_retval}" +else + log_red "Build finished with ${test_retval}" +fi + +# Only upload it when the test passes. +if [[ "${update_cache}" == "true" ]] && \ + [[ $test_retval == 0 ]] && \ + [[ "${TRAMPOLINE_IMAGE_UPLOAD:-false}" == "true" ]]; then + log_yellow "Uploading the Docker image." + if docker push "${TRAMPOLINE_IMAGE}"; then + log_green "Finished uploading the Docker image." + else + log_red "Failed uploading the Docker image." + fi + # Call trampoline_after_upload_hook if it's defined. + if function_exists trampoline_after_upload_hook; then + trampoline_after_upload_hook + fi + +fi + +exit "${test_retval}" diff --git a/packages/gcp-sphinx-docfx-yaml/.pre-commit-config.yaml b/packages/gcp-sphinx-docfx-yaml/.pre-commit-config.yaml new file mode 100644 index 000000000000..32302e4883a1 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/.pre-commit-config.yaml @@ -0,0 +1,17 @@ +# See https://pre-commit.com for more information +# See https://pre-commit.com/hooks.html for more hooks +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v3.4.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml +- repo: https://github.com/psf/black + rev: 19.10b0 + hooks: + - id: black +- repo: https://gitlab.com/pycqa/flake8 + rev: 3.9.0 + hooks: + - id: flake8 diff --git a/packages/gcp-sphinx-docfx-yaml/.repo-metadata.json b/packages/gcp-sphinx-docfx-yaml/.repo-metadata.json new file mode 100644 index 000000000000..180f0c621e3d --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/.repo-metadata.json @@ -0,0 +1,10 @@ +{ + "name": "sphinx-docfx-yaml", + "name_pretty": "Sphinx DocFX YAML Generator", + "client_documentation": "", + "issue_tracker": "https://github.com/googleapis/sphinx-docfx-yaml/issues", + "release_level": "ga", + "language": "python", + "repo": "googleapis/sphinx-docfx-yaml", + "distribution_name": "sphinx-docfx-yaml" +} diff --git a/packages/gcp-sphinx-docfx-yaml/.trampolinerc b/packages/gcp-sphinx-docfx-yaml/.trampolinerc new file mode 100644 index 000000000000..383b6ec89fbc --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/.trampolinerc @@ -0,0 +1,52 @@ +# Copyright 2020 Google LLC +# +# 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. + +# Template for .trampolinerc + +# Add required env vars here. +required_envvars+=( + "STAGING_BUCKET" + "V2_STAGING_BUCKET" +) + +# Add env vars which are passed down into the container here. +pass_down_envvars+=( + "STAGING_BUCKET" + "V2_STAGING_BUCKET" + "NOX_SESSION" +) + +# Prevent unintentional override on the default image. +if [[ "${TRAMPOLINE_IMAGE_UPLOAD:-false}" == "true" ]] && \ + [[ -z "${TRAMPOLINE_IMAGE:-}" ]]; then + echo "Please set TRAMPOLINE_IMAGE if you want to upload the Docker image." + exit 1 +fi + +# Define the default value if it makes sense. +if [[ -z "${TRAMPOLINE_IMAGE_UPLOAD:-}" ]]; then + TRAMPOLINE_IMAGE_UPLOAD="" +fi + +if [[ -z "${TRAMPOLINE_IMAGE:-}" ]]; then + TRAMPOLINE_IMAGE="" +fi + +if [[ -z "${TRAMPOLINE_DOCKERFILE:-}" ]]; then + TRAMPOLINE_DOCKERFILE="" +fi + +if [[ -z "${TRAMPOLINE_BUILD_FILE:-}" ]]; then + TRAMPOLINE_BUILD_FILE="" +fi diff --git a/packages/gcp-sphinx-docfx-yaml/CODE_OF_CONDUCT.md b/packages/gcp-sphinx-docfx-yaml/CODE_OF_CONDUCT.md new file mode 100644 index 000000000000..039f43681204 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/CODE_OF_CONDUCT.md @@ -0,0 +1,95 @@ + +# Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of +experience, education, socio-economic status, nationality, personal appearance, +race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, or to ban temporarily or permanently any +contributor for other behaviors that they deem inappropriate, threatening, +offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +This Code of Conduct also applies outside the project spaces when the Project +Steward has a reasonable belief that an individual's behavior may have a +negative impact on the project or its community. + +## Conflict Resolution + +We do not believe that all conflict is bad; healthy debate and disagreement +often yield positive results. However, it is never okay to be disrespectful or +to engage in behavior that violates the project’s code of conduct. + +If you see someone violating the code of conduct, you are encouraged to address +the behavior directly with those involved. Many issues can be resolved quickly +and easily, and this gives people more control over the outcome of their +dispute. If you are unable to resolve the matter for any reason, or if the +behavior is threatening or harassing, report it. We are dedicated to providing +an environment where participants feel welcome and safe. + + +Reports should be directed to *googleapis-stewards@google.com*, the +Project Steward(s) for *Google Cloud Client Libraries*. It is the Project Steward’s duty to +receive and address reported violations of the code of conduct. They will then +work with a committee consisting of representatives from the Open Source +Programs Office and the Google Open Source Strategy team. If for any reason you +are uncomfortable reaching out to the Project Steward, please email +opensource@google.com. + +We will investigate every complaint, but you may not receive a direct response. +We will use our discretion in determining when and how to follow up on reported +incidents, which may range from not taking action to permanent expulsion from +the project and project-sponsored spaces. We will notify the accused of the +report and provide them an opportunity to discuss it before any action is taken. +The identity of the reporter will be omitted from the details of the report +supplied to the accused. In potentially harmful situations, such as ongoing +harassment or threats to anyone's safety, we may take action without notice. + +## Attribution + +This Code of Conduct is adapted from the Contributor Covenant, version 1.4, +available at +https://www.contributor-covenant.org/version/1/4/code-of-conduct.html \ No newline at end of file diff --git a/packages/gcp-sphinx-docfx-yaml/MANIFEST.in b/packages/gcp-sphinx-docfx-yaml/MANIFEST.in deleted file mode 100644 index bb37a2723dae..000000000000 --- a/packages/gcp-sphinx-docfx-yaml/MANIFEST.in +++ /dev/null @@ -1 +0,0 @@ -include *.rst diff --git a/packages/gcp-sphinx-docfx-yaml/renovate.json b/packages/gcp-sphinx-docfx-yaml/renovate.json new file mode 100644 index 000000000000..f08bc22c9a55 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/renovate.json @@ -0,0 +1,6 @@ +{ + "extends": [ + "config:base", ":preserveSemverRanges" + ], + "ignorePaths": [".pre-commit-config.yaml"] +} diff --git a/packages/gcp-sphinx-docfx-yaml/scripts/decrypt-secrets.sh b/packages/gcp-sphinx-docfx-yaml/scripts/decrypt-secrets.sh new file mode 100755 index 000000000000..21f6d2a26d90 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/scripts/decrypt-secrets.sh @@ -0,0 +1,46 @@ +#!/bin/bash + +# Copyright 2015 Google Inc. 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. + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +ROOT=$( dirname "$DIR" ) + +# Work from the project root. +cd $ROOT + +# Prevent it from overriding files. +# We recommend that sample authors use their own service account files and cloud project. +# In that case, they are supposed to prepare these files by themselves. +if [[ -f "testing/test-env.sh" ]] || \ + [[ -f "testing/service-account.json" ]] || \ + [[ -f "testing/client-secrets.json" ]]; then + echo "One or more target files exist, aborting." + exit 1 +fi + +# Use SECRET_MANAGER_PROJECT if set, fallback to cloud-devrel-kokoro-resources. +PROJECT_ID="${SECRET_MANAGER_PROJECT:-cloud-devrel-kokoro-resources}" + +gcloud secrets versions access latest --secret="python-docs-samples-test-env" \ + --project="${PROJECT_ID}" \ + > testing/test-env.sh +gcloud secrets versions access latest \ + --secret="python-docs-samples-service-account" \ + --project="${PROJECT_ID}" \ + > testing/service-account.json +gcloud secrets versions access latest \ + --secret="python-docs-samples-client-secrets" \ + --project="${PROJECT_ID}" \ + > testing/client-secrets.json diff --git a/packages/gcp-sphinx-docfx-yaml/scripts/readme-gen/readme_gen.py b/packages/gcp-sphinx-docfx-yaml/scripts/readme-gen/readme_gen.py new file mode 100644 index 000000000000..d309d6e97518 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/scripts/readme-gen/readme_gen.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python + +# Copyright 2016 Google Inc +# +# 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. + +"""Generates READMEs using configuration defined in yaml.""" + +import argparse +import io +import os +import subprocess + +import jinja2 +import yaml + + +jinja_env = jinja2.Environment( + trim_blocks=True, + loader=jinja2.FileSystemLoader( + os.path.abspath(os.path.join(os.path.dirname(__file__), 'templates')))) + +README_TMPL = jinja_env.get_template('README.tmpl.rst') + + +def get_help(file): + return subprocess.check_output(['python', file, '--help']).decode() + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('source') + parser.add_argument('--destination', default='README.rst') + + args = parser.parse_args() + + source = os.path.abspath(args.source) + root = os.path.dirname(source) + destination = os.path.join(root, args.destination) + + jinja_env.globals['get_help'] = get_help + + with io.open(source, 'r') as f: + config = yaml.load(f) + + # This allows get_help to execute in the right directory. + os.chdir(root) + + output = README_TMPL.render(config) + + with io.open(destination, 'w') as f: + f.write(output) + + +if __name__ == '__main__': + main() diff --git a/packages/gcp-sphinx-docfx-yaml/scripts/readme-gen/templates/README.tmpl.rst b/packages/gcp-sphinx-docfx-yaml/scripts/readme-gen/templates/README.tmpl.rst new file mode 100644 index 000000000000..4fd239765b0a --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/scripts/readme-gen/templates/README.tmpl.rst @@ -0,0 +1,87 @@ +{# The following line is a lie. BUT! Once jinja2 is done with it, it will + become truth! #} +.. This file is automatically generated. Do not edit this file directly. + +{{product.name}} Python Samples +=============================================================================== + +.. image:: https://gstatic.com/cloudssh/images/open-btn.png + :target: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor={{folder}}/README.rst + + +This directory contains samples for {{product.name}}. {{product.description}} + +{{description}} + +.. _{{product.name}}: {{product.url}} + +{% if required_api_url %} +To run the sample, you need to enable the API at: {{required_api_url}} +{% endif %} + +{% if required_role %} +To run the sample, you need to have `{{required_role}}` role. +{% endif %} + +{{other_required_steps}} + +{% if setup %} +Setup +------------------------------------------------------------------------------- + +{% for section in setup %} + +{% include section + '.tmpl.rst' %} + +{% endfor %} +{% endif %} + +{% if samples %} +Samples +------------------------------------------------------------------------------- + +{% for sample in samples %} +{{sample.name}} ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +{% if not sample.hide_cloudshell_button %} +.. image:: https://gstatic.com/cloudssh/images/open-btn.png + :target: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor={{folder}}/{{sample.file}},{{folder}}/README.rst +{% endif %} + + +{{sample.description}} + +To run this sample: + +.. code-block:: bash + + $ python {{sample.file}} +{% if sample.show_help %} + + {{get_help(sample.file)|indent}} +{% endif %} + + +{% endfor %} +{% endif %} + +{% if cloud_client_library %} + +The client library +------------------------------------------------------------------------------- + +This sample uses the `Google Cloud Client Library for Python`_. +You can read the documentation for more details on API usage and use GitHub +to `browse the source`_ and `report issues`_. + +.. _Google Cloud Client Library for Python: + https://googlecloudplatform.github.io/google-cloud-python/ +.. _browse the source: + https://github.com/GoogleCloudPlatform/google-cloud-python +.. _report issues: + https://github.com/GoogleCloudPlatform/google-cloud-python/issues + +{% endif %} + +.. _Google Cloud SDK: https://cloud.google.com/sdk/ \ No newline at end of file diff --git a/packages/gcp-sphinx-docfx-yaml/scripts/readme-gen/templates/auth.tmpl.rst b/packages/gcp-sphinx-docfx-yaml/scripts/readme-gen/templates/auth.tmpl.rst new file mode 100644 index 000000000000..1446b94a5e3a --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/scripts/readme-gen/templates/auth.tmpl.rst @@ -0,0 +1,9 @@ +Authentication +++++++++++++++ + +This sample requires you to have authentication setup. Refer to the +`Authentication Getting Started Guide`_ for instructions on setting up +credentials for applications. + +.. _Authentication Getting Started Guide: + https://cloud.google.com/docs/authentication/getting-started diff --git a/packages/gcp-sphinx-docfx-yaml/scripts/readme-gen/templates/auth_api_key.tmpl.rst b/packages/gcp-sphinx-docfx-yaml/scripts/readme-gen/templates/auth_api_key.tmpl.rst new file mode 100644 index 000000000000..11957ce2714a --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/scripts/readme-gen/templates/auth_api_key.tmpl.rst @@ -0,0 +1,14 @@ +Authentication +++++++++++++++ + +Authentication for this service is done via an `API Key`_. To obtain an API +Key: + +1. Open the `Cloud Platform Console`_ +2. Make sure that billing is enabled for your project. +3. From the **Credentials** page, create a new **API Key** or use an existing + one for your project. + +.. _API Key: + https://developers.google.com/api-client-library/python/guide/aaa_apikeys +.. _Cloud Console: https://console.cloud.google.com/project?_ diff --git a/packages/gcp-sphinx-docfx-yaml/scripts/readme-gen/templates/install_deps.tmpl.rst b/packages/gcp-sphinx-docfx-yaml/scripts/readme-gen/templates/install_deps.tmpl.rst new file mode 100644 index 000000000000..a0406dba8c84 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/scripts/readme-gen/templates/install_deps.tmpl.rst @@ -0,0 +1,29 @@ +Install Dependencies +++++++++++++++++++++ + +#. Clone python-docs-samples and change directory to the sample directory you want to use. + + .. code-block:: bash + + $ git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git + +#. Install `pip`_ and `virtualenv`_ if you do not already have them. You may want to refer to the `Python Development Environment Setup Guide`_ for Google Cloud Platform for instructions. + + .. _Python Development Environment Setup Guide: + https://cloud.google.com/python/setup + +#. Create a virtualenv. Samples are compatible with Python 2.7 and 3.4+. + + .. code-block:: bash + + $ virtualenv env + $ source env/bin/activate + +#. Install the dependencies needed to run the samples. + + .. code-block:: bash + + $ pip install -r requirements.txt + +.. _pip: https://pip.pypa.io/ +.. _virtualenv: https://virtualenv.pypa.io/ diff --git a/packages/gcp-sphinx-docfx-yaml/scripts/readme-gen/templates/install_portaudio.tmpl.rst b/packages/gcp-sphinx-docfx-yaml/scripts/readme-gen/templates/install_portaudio.tmpl.rst new file mode 100644 index 000000000000..5ea33d18c00c --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/scripts/readme-gen/templates/install_portaudio.tmpl.rst @@ -0,0 +1,35 @@ +Install PortAudio ++++++++++++++++++ + +Install `PortAudio`_. This is required by the `PyAudio`_ library to stream +audio from your computer's microphone. PyAudio depends on PortAudio for cross-platform compatibility, and is installed differently depending on the +platform. + +* For Mac OS X, you can use `Homebrew`_:: + + brew install portaudio + + **Note**: if you encounter an error when running `pip install` that indicates + it can't find `portaudio.h`, try running `pip install` with the following + flags:: + + pip install --global-option='build_ext' \ + --global-option='-I/usr/local/include' \ + --global-option='-L/usr/local/lib' \ + pyaudio + +* For Debian / Ubuntu Linux:: + + apt-get install portaudio19-dev python-all-dev + +* Windows may work without having to install PortAudio explicitly (it will get + installed with PyAudio). + +For more details, see the `PyAudio installation`_ page. + + +.. _PyAudio: https://people.csail.mit.edu/hubert/pyaudio/ +.. _PortAudio: http://www.portaudio.com/ +.. _PyAudio installation: + https://people.csail.mit.edu/hubert/pyaudio/#downloads +.. _Homebrew: http://brew.sh diff --git a/packages/gcp-sphinx-docfx-yaml/setup.cfg b/packages/gcp-sphinx-docfx-yaml/setup.cfg deleted file mode 100644 index 5e4090017a9b..000000000000 --- a/packages/gcp-sphinx-docfx-yaml/setup.cfg +++ /dev/null @@ -1,2 +0,0 @@ -[wheel] -universal = 1 diff --git a/packages/gcp-sphinx-docfx-yaml/setup.py b/packages/gcp-sphinx-docfx-yaml/setup.py index a2b59f69ce8c..fd4b902593e9 100644 --- a/packages/gcp-sphinx-docfx-yaml/setup.py +++ b/packages/gcp-sphinx-docfx-yaml/setup.py @@ -1,40 +1,49 @@ -# Copyright 2021 Google LLC -# -# 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. - +# Copyright 2021 Google LLC +# +# 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. + import codecs -from setuptools import setup, find_packages -extra_setup = dict( -install_requires=[ +import setuptools + +name = 'gcp-sphinx-docfx-yaml' +description = 'Sphinx Python Domain to DocFX YAML Generator' +version = '0.1.0' +dependencies = [ 'PyYAML', 'wheel>=0.24.0', 'sphinx', - 'unidecode', -], + 'unidecode' +] + +packages = setuptools.find_packages('.', exclude=['tests']) + +extra_setup = dict( setup_requires=['pytest-runner'], tests_require=['pytest', 'mock'], ) -setup( - name='sphinx-docfx-yaml', - version='1.2.76', - author='Eric Holscher', - author_email='eric@ericholscher.com', - url='https://github.com/ericholscher/sphinx-docfx-yaml', - description='Sphinx Python Domain to DocFX YAML Generator', +setuptools.setup( + name=name, + version=version, + description=description, + author='Google LLC', + author_email='dandhlee@google.com', + license='Apache 2.0', + url='https://github.com/googleapis/sphinx-docfx-yaml', package_dir={'': '.'}, - packages=find_packages('.', exclude=['tests']), - # trying to add files... + packages=packages, + install_requires=dependencies, include_package_data=True, + zip_safe=False, **extra_setup ) diff --git a/packages/gcp-sphinx-docfx-yaml/synth.metadata b/packages/gcp-sphinx-docfx-yaml/synth.metadata new file mode 100644 index 000000000000..1e5a933879e6 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/synth.metadata @@ -0,0 +1,18 @@ +{ + "sources": [ + { + "git": { + "name": ".", + "remote": "git@github.com:googleapis/sphinx-docfx-yaml.git", + "sha": "0ae51aa102e4153bf20aa4f28b94708a0ee3fe4c" + } + }, + { + "git": { + "name": "synthtool", + "remote": "https://github.com/googleapis/synthtool.git", + "sha": "bb854b6c048619e3be4e8b8ce8ed10aa74ea78ef" + } + } + ] +} \ No newline at end of file diff --git a/packages/gcp-sphinx-docfx-yaml/synth.py b/packages/gcp-sphinx-docfx-yaml/synth.py new file mode 100644 index 000000000000..e44e73bd48d0 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/synth.py @@ -0,0 +1,46 @@ +# Copyright 2021 Google LLC +# +# 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. + +"""This script is used to synthesize generated parts of this library.""" +import os + +import synthtool as s +import synthtool.gcp as gcp + +common = gcp.CommonTemplates() + +# ---------------------------------------------------------------------------- +# Add templated files +# ---------------------------------------------------------------------------- + +# Just copy templates for releases for now +templated_files = common.py_library(cov_level=100) +s.move( + templated_files, + excludes=[ + ".flake8", + "MANIFEST.in", + "setup.cfg", + ".coveragerc", + "noxfile.py", # repo uses nox + "docs/**/*", # no docs to publish + ".kokoro/docs/", + ".kokoro/publish-docs.sh", + ".kokoro/samples/**", # no samples + ".kokoro/test-sample*", + "CONTRIBUTING.rst", # repo has a CONTRIBUTING.md + ".github/CONTRIBUTING.md", + ".github/PULL_REQUEST_TEMPLATE.md" + ], +) diff --git a/packages/gcp-sphinx-docfx-yaml/testing/.gitignore b/packages/gcp-sphinx-docfx-yaml/testing/.gitignore new file mode 100644 index 000000000000..b05fbd630881 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/testing/.gitignore @@ -0,0 +1,3 @@ +test-env.sh +service-account.json +client-secrets.json \ No newline at end of file From 6eef472d91e0409ec07a1927c512662c86926891 Mon Sep 17 00:00:00 2001 From: Bu Sun Kim <8822365+busunkim96@users.noreply.github.com> Date: Wed, 24 Mar 2021 17:45:35 -0600 Subject: [PATCH 004/279] chore: fix distribution name to match setup.py (#4) --- packages/gcp-sphinx-docfx-yaml/.repo-metadata.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/.repo-metadata.json b/packages/gcp-sphinx-docfx-yaml/.repo-metadata.json index 180f0c621e3d..f6de43400193 100644 --- a/packages/gcp-sphinx-docfx-yaml/.repo-metadata.json +++ b/packages/gcp-sphinx-docfx-yaml/.repo-metadata.json @@ -1,10 +1,10 @@ { - "name": "sphinx-docfx-yaml", + "name": "gcp-sphinx-docfx-yaml", "name_pretty": "Sphinx DocFX YAML Generator", "client_documentation": "", "issue_tracker": "https://github.com/googleapis/sphinx-docfx-yaml/issues", "release_level": "ga", "language": "python", "repo": "googleapis/sphinx-docfx-yaml", - "distribution_name": "sphinx-docfx-yaml" + "distribution_name": "gcp-sphinx-docfx-yaml" } From f74f5e2c8eda75f3baa3f3c0eaa991f4c9620f89 Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Thu, 25 Mar 2021 14:02:46 -0400 Subject: [PATCH 005/279] docs: keep Python COC, update README (#6) * docs: keep Python COC, update README * Update README --- packages/gcp-sphinx-docfx-yaml/README.rst | 4 +- .../gcp-sphinx-docfx-yaml/code-of-conduct.md | 63 ------------------- 2 files changed, 2 insertions(+), 65 deletions(-) delete mode 100644 packages/gcp-sphinx-docfx-yaml/code-of-conduct.md diff --git a/packages/gcp-sphinx-docfx-yaml/README.rst b/packages/gcp-sphinx-docfx-yaml/README.rst index 61aee5f456ba..38291eeaf1d9 100644 --- a/packages/gcp-sphinx-docfx-yaml/README.rst +++ b/packages/gcp-sphinx-docfx-yaml/README.rst @@ -35,11 +35,11 @@ Basic Workflow Install ------- -First you need to install docfx-yaml: +To use this forked version, install GCP docfx-yaml: .. code:: bash - pip install sphinx-docfx-yaml + pip install gcp-sphinx-docfx-yaml Then add it to your Sphinx project's ``conf.py``: diff --git a/packages/gcp-sphinx-docfx-yaml/code-of-conduct.md b/packages/gcp-sphinx-docfx-yaml/code-of-conduct.md deleted file mode 100644 index f8b12cb550a3..000000000000 --- a/packages/gcp-sphinx-docfx-yaml/code-of-conduct.md +++ /dev/null @@ -1,63 +0,0 @@ -# Google Open Source Community Guidelines - -At Google, we recognize and celebrate the creativity and collaboration of open -source contributors and the diversity of skills, experiences, cultures, and -opinions they bring to the projects and communities they participate in. - -Every one of Google's open source projects and communities are inclusive -environments, based on treating all individuals respectfully, regardless of -gender identity and expression, sexual orientation, disabilities, -neurodiversity, physical appearance, body size, ethnicity, nationality, race, -age, religion, or similar personal characteristic. - -We value diverse opinions, but we value respectful behavior more. - -Respectful behavior includes: - -* Being considerate, kind, constructive, and helpful. -* Not engaging in demeaning, discriminatory, harassing, hateful, sexualized, or - physically threatening behavior, speech, and imagery. -* Not engaging in unwanted physical contact. - -Some Google open source projects [may adopt][] an explicit project code of -conduct, which may have additional detailed expectations for participants. Most -of those projects will use our [modified Contributor Covenant][]. - -[may adopt]: https://opensource.google/docs/releasing/preparing/#conduct -[modified Contributor Covenant]: https://opensource.google/docs/releasing/template/CODE_OF_CONDUCT/ - -## Resolve peacefully - -We do not believe that all conflict is necessarily bad; healthy debate and -disagreement often yields positive results. However, it is never okay to be -disrespectful. - -If you see someone behaving disrespectfully, you are encouraged to address the -behavior directly with those involved. Many issues can be resolved quickly and -easily, and this gives people more control over the outcome of their dispute. -If you are unable to resolve the matter for any reason, or if the behavior is -threatening or harassing, report it. We are dedicated to providing an -environment where participants feel welcome and safe. - -## Reporting problems - -Some Google open source projects may adopt a project-specific code of conduct. -In those cases, a Google employee will be identified as the Project Steward, -who will receive and handle reports of code of conduct violations. In the event -that a project hasn’t identified a Project Steward, you can report problems by -emailing opensource@google.com. - -We will investigate every complaint, but you may not receive a direct response. -We will use our discretion in determining when and how to follow up on reported -incidents, which may range from not taking action to permanent expulsion from -the project and project-sponsored spaces. We will notify the accused of the -report and provide them an opportunity to discuss it before any action is -taken. The identity of the reporter will be omitted from the details of the -report supplied to the accused. In potentially harmful situations, such as -ongoing harassment or threats to anyone's safety, we may take action without -notice. - -*This document was adapted from the [IndieWeb Code of Conduct][] and can also -be found at .* - -[IndieWeb Code of Conduct]: https://indieweb.org/code-of-conduct From 632c8cf39bb0dcd1fd58c9a8882138b2944cf700 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Thu, 25 Mar 2021 14:03:22 -0400 Subject: [PATCH 006/279] chore: release 0.1.0 (#7) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/gcp-sphinx-docfx-yaml/CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 packages/gcp-sphinx-docfx-yaml/CHANGELOG.md diff --git a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md new file mode 100644 index 000000000000..b8f7d6d6a75b --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md @@ -0,0 +1,8 @@ +# Changelog + +## 0.1.0 (2021-03-25) + + +### Documentation + +* keep Python COC, update README ([#6](https://www.github.com/googleapis/sphinx-docfx-yaml/issues/6)) ([3a60b1a](https://www.github.com/googleapis/sphinx-docfx-yaml/commit/3a60b1af9c2c39fe1bb974fb899f87c81efc0274)) From daba30adecd8e57a6dfadf3f117af1ebc99921b0 Mon Sep 17 00:00:00 2001 From: Yoshi Automation Bot Date: Tue, 30 Mar 2021 10:15:02 -0700 Subject: [PATCH 007/279] changes without context (#8) autosynth cannot find the source of changes triggered by earlier changes in this repository, or by version upgrades to tools such as linters. --- .../.github/ISSUE_TEMPLATE/bug_report.md | 2 +- packages/gcp-sphinx-docfx-yaml/synth.metadata | 39 ++++++++++++++++++- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/.github/ISSUE_TEMPLATE/bug_report.md b/packages/gcp-sphinx-docfx-yaml/.github/ISSUE_TEMPLATE/bug_report.md index d5bf92535d03..56e36c6b2468 100644 --- a/packages/gcp-sphinx-docfx-yaml/.github/ISSUE_TEMPLATE/bug_report.md +++ b/packages/gcp-sphinx-docfx-yaml/.github/ISSUE_TEMPLATE/bug_report.md @@ -20,7 +20,7 @@ If you are still having issues, please be sure to include as much information as - OS type and version: - Python version: `python --version` - pip version: `pip --version` - - `sphinx-docfx-yaml` version: `pip show sphinx-docfx-yaml` + - `gcp-sphinx-docfx-yaml` version: `pip show gcp-sphinx-docfx-yaml` #### Steps to reproduce diff --git a/packages/gcp-sphinx-docfx-yaml/synth.metadata b/packages/gcp-sphinx-docfx-yaml/synth.metadata index 1e5a933879e6..14447d636a66 100644 --- a/packages/gcp-sphinx-docfx-yaml/synth.metadata +++ b/packages/gcp-sphinx-docfx-yaml/synth.metadata @@ -3,8 +3,8 @@ { "git": { "name": ".", - "remote": "git@github.com:googleapis/sphinx-docfx-yaml.git", - "sha": "0ae51aa102e4153bf20aa4f28b94708a0ee3fe4c" + "remote": "https://github.com/googleapis/sphinx-docfx-yaml.git", + "sha": "a48db293a73e43f00bbf950219741e4a18fa0cf4" } }, { @@ -14,5 +14,40 @@ "sha": "bb854b6c048619e3be4e8b8ce8ed10aa74ea78ef" } } + ], + "generatedFiles": [ + ".github/ISSUE_TEMPLATE/bug_report.md", + ".github/ISSUE_TEMPLATE/feature_request.md", + ".github/ISSUE_TEMPLATE/support_request.md", + ".github/header-checker-lint.yml", + ".github/release-please.yml", + ".github/snippet-bot.yml", + ".gitignore", + ".kokoro/build.sh", + ".kokoro/continuous/common.cfg", + ".kokoro/continuous/continuous.cfg", + ".kokoro/docker/docs/Dockerfile", + ".kokoro/docker/docs/fetch_gpg_keys.sh", + ".kokoro/populate-secrets.sh", + ".kokoro/presubmit/common.cfg", + ".kokoro/presubmit/presubmit.cfg", + ".kokoro/release.sh", + ".kokoro/release/common.cfg", + ".kokoro/release/release.cfg", + ".kokoro/trampoline.sh", + ".kokoro/trampoline_v2.sh", + ".pre-commit-config.yaml", + ".trampolinerc", + "CODE_OF_CONDUCT.md", + "LICENSE", + "renovate.json", + "scripts/decrypt-secrets.sh", + "scripts/readme-gen/readme_gen.py", + "scripts/readme-gen/templates/README.tmpl.rst", + "scripts/readme-gen/templates/auth.tmpl.rst", + "scripts/readme-gen/templates/auth_api_key.tmpl.rst", + "scripts/readme-gen/templates/install_deps.tmpl.rst", + "scripts/readme-gen/templates/install_portaudio.tmpl.rst", + "testing/.gitignore" ] } \ No newline at end of file From 5f20ccd05b3d68c1db219c75448218611dd023ca Mon Sep 17 00:00:00 2001 From: Yoshi Automation Bot Date: Wed, 7 Apr 2021 06:14:07 -0700 Subject: [PATCH 008/279] chore: Add license headers for python config files (#9) Source-Author: Anthonios Partheniou Source-Date: Tue Apr 6 11:32:03 2021 -0400 Source-Repo: googleapis/synthtool Source-Sha: 5b5bf6d519b2d658d9f2e483d9f6f3d0ba8ee6bc Source-Link: https://github.com/googleapis/synthtool/commit/5b5bf6d519b2d658d9f2e483d9f6f3d0ba8ee6bc --- .../gcp-sphinx-docfx-yaml/.pre-commit-config.yaml | 14 ++++++++++++++ packages/gcp-sphinx-docfx-yaml/synth.metadata | 4 ++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/.pre-commit-config.yaml b/packages/gcp-sphinx-docfx-yaml/.pre-commit-config.yaml index 32302e4883a1..8912e9b5d7d7 100644 --- a/packages/gcp-sphinx-docfx-yaml/.pre-commit-config.yaml +++ b/packages/gcp-sphinx-docfx-yaml/.pre-commit-config.yaml @@ -1,3 +1,17 @@ +# Copyright 2021 Google LLC +# +# 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. +# # See https://pre-commit.com for more information # See https://pre-commit.com/hooks.html for more hooks repos: diff --git a/packages/gcp-sphinx-docfx-yaml/synth.metadata b/packages/gcp-sphinx-docfx-yaml/synth.metadata index 14447d636a66..cd5ad2d18bd2 100644 --- a/packages/gcp-sphinx-docfx-yaml/synth.metadata +++ b/packages/gcp-sphinx-docfx-yaml/synth.metadata @@ -4,14 +4,14 @@ "git": { "name": ".", "remote": "https://github.com/googleapis/sphinx-docfx-yaml.git", - "sha": "a48db293a73e43f00bbf950219741e4a18fa0cf4" + "sha": "b58f089eca390a4d8ec25101f6d9482163f06eab" } }, { "git": { "name": "synthtool", "remote": "https://github.com/googleapis/synthtool.git", - "sha": "bb854b6c048619e3be4e8b8ce8ed10aa74ea78ef" + "sha": "5b5bf6d519b2d658d9f2e483d9f6f3d0ba8ee6bc" } } ], From 19251b98241dfcd6cff7b1e0bbc466ef70970c82 Mon Sep 17 00:00:00 2001 From: Yoshi Automation Bot Date: Mon, 12 Apr 2021 13:39:00 -0700 Subject: [PATCH 009/279] chore: add constraints file check for python samples (#10) This is the sibling PR to https://github.com/GoogleCloudPlatform/python-docs-samples/pull/5611 and this is the issue opened for it https://github.com/GoogleCloudPlatform/python-docs-samples/issues/5549 If you look at the files in [this example repo](https://github.com/leahecole/testrepo-githubapp/pull/31/files), you'll see that renovate successfully opened a PR on three constraints files in `samples` directories and subdirectories, and properly ignored `constraints` files at the root level cc @tswast TODO: - [x] update renovate to check for samples/constraints.txt dependency updates - [x] run lint locally to double check that I'm not introducing lint error Source-Author: Leah E. Cole <6719667+leahecole@users.noreply.github.com> Source-Date: Fri Apr 9 22:50:04 2021 -0700 Source-Repo: googleapis/synthtool Source-Sha: 0a071b3460344886297a304253bf924aa68ddb7e Source-Link: https://github.com/googleapis/synthtool/commit/0a071b3460344886297a304253bf924aa68ddb7e --- .../gcp-sphinx-docfx-yaml/.github/header-checker-lint.yml | 2 +- packages/gcp-sphinx-docfx-yaml/renovate.json | 5 ++++- packages/gcp-sphinx-docfx-yaml/synth.metadata | 4 ++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/.github/header-checker-lint.yml b/packages/gcp-sphinx-docfx-yaml/.github/header-checker-lint.yml index fc281c05bd55..6fe78aa7987a 100644 --- a/packages/gcp-sphinx-docfx-yaml/.github/header-checker-lint.yml +++ b/packages/gcp-sphinx-docfx-yaml/.github/header-checker-lint.yml @@ -1,6 +1,6 @@ {"allowedCopyrightHolders": ["Google LLC"], "allowedLicenses": ["Apache-2.0", "MIT", "BSD-3"], - "ignoreFiles": ["**/requirements.txt", "**/requirements-test.txt"], + "ignoreFiles": ["**/requirements.txt", "**/requirements-test.txt", "**/__init__.py", "samples/**/constraints.txt", "samples/**/constraints-test.txt"], "sourceFileExtensions": [ "ts", "js", diff --git a/packages/gcp-sphinx-docfx-yaml/renovate.json b/packages/gcp-sphinx-docfx-yaml/renovate.json index f08bc22c9a55..c04895563e69 100644 --- a/packages/gcp-sphinx-docfx-yaml/renovate.json +++ b/packages/gcp-sphinx-docfx-yaml/renovate.json @@ -2,5 +2,8 @@ "extends": [ "config:base", ":preserveSemverRanges" ], - "ignorePaths": [".pre-commit-config.yaml"] + "ignorePaths": [".pre-commit-config.yaml"], + "pip_requirements": { + "fileMatch": ["requirements-test.txt", "samples/[\\S/]*constraints.txt", "samples/[\\S/]*constraints-test.txt"] + } } diff --git a/packages/gcp-sphinx-docfx-yaml/synth.metadata b/packages/gcp-sphinx-docfx-yaml/synth.metadata index cd5ad2d18bd2..bd535bfb256e 100644 --- a/packages/gcp-sphinx-docfx-yaml/synth.metadata +++ b/packages/gcp-sphinx-docfx-yaml/synth.metadata @@ -4,14 +4,14 @@ "git": { "name": ".", "remote": "https://github.com/googleapis/sphinx-docfx-yaml.git", - "sha": "b58f089eca390a4d8ec25101f6d9482163f06eab" + "sha": "ad9432421839b12f2edb693e2ec65d90dac108df" } }, { "git": { "name": "synthtool", "remote": "https://github.com/googleapis/synthtool.git", - "sha": "5b5bf6d519b2d658d9f2e483d9f6f3d0ba8ee6bc" + "sha": "0a071b3460344886297a304253bf924aa68ddb7e" } } ], From 8d85b1f39b09b0dc2d88e61ef98ed85ee75a045a Mon Sep 17 00:00:00 2001 From: Yoshi Automation Bot Date: Thu, 15 Apr 2021 09:26:40 -0700 Subject: [PATCH 010/279] build: use PyPI API token in secret manager (#11) Migrate python libraries onto the PyPI API token stored in secret manager. A PyPI API token is limited in scope to uploading new releases. https://pypi.org/help/#apitoken Verified that this works with [build](https://fusion2.corp.google.com/invocations/14bae126-83fa-4328-8da9-d390ed99315c/targets/cloud-devrel%2Fclient-libraries%2Fpython%2Fgoogleapis%2Fpython-vision%2Frelease%2Frelease;config=default/log) on https://github.com/googleapis/python-vision/pull/136 Source-Author: Bu Sun Kim <8822365+busunkim96@users.noreply.github.com> Source-Date: Wed Apr 14 17:46:06 2021 -0600 Source-Repo: googleapis/synthtool Source-Sha: 043cc620d6a6111816d9e09f2a97208565fde958 Source-Link: https://github.com/googleapis/synthtool/commit/043cc620d6a6111816d9e09f2a97208565fde958 --- packages/gcp-sphinx-docfx-yaml/.kokoro/release.sh | 4 ++-- .../.kokoro/release/common.cfg | 14 ++------------ packages/gcp-sphinx-docfx-yaml/synth.metadata | 4 ++-- 3 files changed, 6 insertions(+), 16 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/release.sh b/packages/gcp-sphinx-docfx-yaml/.kokoro/release.sh index 1b24c74bef86..8fdf97fc49b5 100755 --- a/packages/gcp-sphinx-docfx-yaml/.kokoro/release.sh +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/release.sh @@ -26,7 +26,7 @@ python3 -m pip install --upgrade twine wheel setuptools export PYTHONUNBUFFERED=1 # Move into the package, build the distribution and upload. -TWINE_PASSWORD=$(cat "${KOKORO_KEYSTORE_DIR}/73713_google_cloud_pypi_password") +TWINE_PASSWORD=$(cat "${KOKORO_GFILE_DIR}/secret_manager/google-cloud-pypi-token") cd github/sphinx-docfx-yaml python3 setup.py sdist bdist_wheel -twine upload --username gcloudpypi --password "${TWINE_PASSWORD}" dist/* +twine upload --username __token__ --password "${TWINE_PASSWORD}" dist/* diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/release/common.cfg b/packages/gcp-sphinx-docfx-yaml/.kokoro/release/common.cfg index 0668ac6665f8..01d29a195724 100644 --- a/packages/gcp-sphinx-docfx-yaml/.kokoro/release/common.cfg +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/release/common.cfg @@ -23,18 +23,8 @@ env_vars: { value: "github/sphinx-docfx-yaml/.kokoro/release.sh" } -# Fetch PyPI password -before_action { - fetch_keystore { - keystore_resource { - keystore_config_id: 73713 - keyname: "google_cloud_pypi_password" - } - } -} - # Tokens needed to report release status back to GitHub env_vars: { key: "SECRET_MANAGER_KEYS" - value: "releasetool-publish-reporter-app,releasetool-publish-reporter-googleapis-installation,releasetool-publish-reporter-pem" -} \ No newline at end of file + value: "releasetool-publish-reporter-app,releasetool-publish-reporter-googleapis-installation,releasetool-publish-reporter-pem,google-cloud-pypi-token" +} diff --git a/packages/gcp-sphinx-docfx-yaml/synth.metadata b/packages/gcp-sphinx-docfx-yaml/synth.metadata index bd535bfb256e..5a5c8a97049f 100644 --- a/packages/gcp-sphinx-docfx-yaml/synth.metadata +++ b/packages/gcp-sphinx-docfx-yaml/synth.metadata @@ -4,14 +4,14 @@ "git": { "name": ".", "remote": "https://github.com/googleapis/sphinx-docfx-yaml.git", - "sha": "ad9432421839b12f2edb693e2ec65d90dac108df" + "sha": "2deb23a9d5785703d1d5c822bb3a80c5b7accf3b" } }, { "git": { "name": "synthtool", "remote": "https://github.com/googleapis/synthtool.git", - "sha": "0a071b3460344886297a304253bf924aa68ddb7e" + "sha": "043cc620d6a6111816d9e09f2a97208565fde958" } } ], From cd655a1212cf73e5f598b2099f2e32e8bbc6e4d5 Mon Sep 17 00:00:00 2001 From: "google-cloud-policy-bot[bot]" <80869356+google-cloud-policy-bot[bot]@users.noreply.github.com> Date: Fri, 30 Apr 2021 13:19:46 -0400 Subject: [PATCH 011/279] chore: add SECURITY.md (#13) Co-authored-by: google-cloud-policy-bot[bot] <80869356+google-cloud-policy-bot[bot]@users.noreply.github.com> --- packages/gcp-sphinx-docfx-yaml/SECURITY.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 packages/gcp-sphinx-docfx-yaml/SECURITY.md diff --git a/packages/gcp-sphinx-docfx-yaml/SECURITY.md b/packages/gcp-sphinx-docfx-yaml/SECURITY.md new file mode 100644 index 000000000000..8b58ae9c01ae --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/SECURITY.md @@ -0,0 +1,7 @@ +# Security Policy + +To report a security issue, please use [g.co/vulnz](https://g.co/vulnz). + +The Google Security Team will respond within 5 working days of your report on g.co/vulnz. + +We use g.co/vulnz for our intake, and do coordination and disclosure here using GitHub Security Advisory to privately discuss and fix the issue. From 6f79b1c2fd267e928fc1cbdcb61e34426ae868ee Mon Sep 17 00:00:00 2001 From: Yoshi Automation Bot Date: Thu, 6 May 2021 12:15:31 -0700 Subject: [PATCH 012/279] chore: Authsynth synthtool update (#14) making upgrades to the rev as requested by the Synthtool --- packages/gcp-sphinx-docfx-yaml/.pre-commit-config.yaml | 2 +- packages/gcp-sphinx-docfx-yaml/synth.metadata | 9 +-------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/.pre-commit-config.yaml b/packages/gcp-sphinx-docfx-yaml/.pre-commit-config.yaml index 8912e9b5d7d7..1bbd787833ec 100644 --- a/packages/gcp-sphinx-docfx-yaml/.pre-commit-config.yaml +++ b/packages/gcp-sphinx-docfx-yaml/.pre-commit-config.yaml @@ -26,6 +26,6 @@ repos: hooks: - id: black - repo: https://gitlab.com/pycqa/flake8 - rev: 3.9.0 + rev: 3.9.1 hooks: - id: flake8 diff --git a/packages/gcp-sphinx-docfx-yaml/synth.metadata b/packages/gcp-sphinx-docfx-yaml/synth.metadata index 5a5c8a97049f..f3c44afcb479 100644 --- a/packages/gcp-sphinx-docfx-yaml/synth.metadata +++ b/packages/gcp-sphinx-docfx-yaml/synth.metadata @@ -4,14 +4,7 @@ "git": { "name": ".", "remote": "https://github.com/googleapis/sphinx-docfx-yaml.git", - "sha": "2deb23a9d5785703d1d5c822bb3a80c5b7accf3b" - } - }, - { - "git": { - "name": "synthtool", - "remote": "https://github.com/googleapis/synthtool.git", - "sha": "043cc620d6a6111816d9e09f2a97208565fde958" + "sha": "72eed3a8fdff8dffc6e5948a91376435befb9632" } } ], From 66687fe9f41c9cfe1caf41ff29a99e90bc613240 Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Thu, 13 May 2021 13:43:54 -0400 Subject: [PATCH 013/279] feat: clarify names in the left nav (#16) * feat: clarify names in the left nav * fix: improve disambiguation and parsing names --- .../docfx_yaml/extension.py | 75 ++++++++++++++++--- 1 file changed, 66 insertions(+), 9 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index 04c108130354..8a17f452b28b 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -21,6 +21,7 @@ import os import inspect import re +import copy from functools import partial from itertools import zip_longest @@ -562,9 +563,35 @@ def build_finished(app, exception): """ Output YAML on the file system. """ + + # Used to get rid of the uidname field for cleaner toc file. + def sanitize_uidname_field(toc_yaml): + for module in toc_yaml: + if 'items' in module: + sanitize_uidname_field(module['items']) + module.pop('uidname') + + # Parses the package name and returns package name and module name. + def find_package_name(package_name): + for name in package_name: + if name != "google" and name != "cloud": + return [name, package_name[-1]] + + # Used to disambiguate names that have same entries. + def disambiguate_toc_name(toc_yaml): + names = {} + for module in toc_yaml: + names[module['name']] = 1 if module['name'] not in names else 2 + if 'items' in module: + disambiguate_toc_name(module['items']) + + for module in toc_yaml: + if names[module['name']] > 1: + module['name'] = ".".join(find_package_name(module['uidname'].split("."))) + def find_node_in_toc_tree(toc_yaml, to_add_node): for module in toc_yaml: - if module['name'] == to_add_node: + if module['uidname'] == to_add_node: return module if 'items' in module: @@ -572,7 +599,6 @@ def find_node_in_toc_tree(toc_yaml, to_add_node): found_module = find_node_in_toc_tree(items, to_add_node) if found_module != None: return found_module - return None def convert_module_to_package_if_needed(obj): @@ -756,6 +782,13 @@ def convert_module_to_package_if_needed(obj): raise ValueError("Unable to dump object\n{0}".format(yaml_data)) from e file_name_set.add(filename) + + # Parse the name of the object. + # Some types will need additional parsing to de-duplicate their names and contain + # a portion of their parent name for better disambiguation. This is done in + # disambiguate_toc_name + + node_name = obj.get('class').split(".")[-1] if obj.get('class') else obj['name'] # Build nested TOC if uid.count('.') >= 1: @@ -764,16 +797,40 @@ def convert_module_to_package_if_needed(obj): if found_node: found_node.pop('uid', 'No uid found') - found_node.setdefault('items', [{'name': 'Overview', 'uid': parent_level}]).append({'name': uid, 'uid': uid}) + found_node.setdefault( + 'items', + [{'name': 'Overview', 'uidname': parent_level, 'uid': parent_level}] + ).append({ + 'name': node_name, + 'uidname': uid, + 'uid': uid + }) else: - toc_yaml.append({'name': uid, 'uid': uid}) + toc_yaml.append({ + 'name': node_name, + 'uidname': uid, + 'uid': uid + }) else: - toc_yaml.append({'name': uid, 'uid': uid}) + toc_yaml.append({ + 'name': node_name, + 'uidname': uid, + 'uid': uid + }) if len(toc_yaml) == 0: raise RuntimeError("No documentation for this module.") + # Perform additional disambiguation of the name + disambiguate_toc_name(toc_yaml) + + # Keeping uidname field carrys over onto the toc.yaml files, we need to + # be keep using them but don't need them in the actual file + toc_yaml_with_uid = copy.deepcopy(toc_yaml) + + sanitize_uidname_field(toc_yaml) + toc_file = os.path.join(normalized_outdir, 'toc.yml') with open(toc_file, 'w') as writable: writable.write( @@ -789,12 +846,12 @@ def convert_module_to_package_if_needed(obj): index_file = os.path.join(normalized_outdir, 'index.yml') index_children = [] index_references = [] - for item in toc_yaml: - index_children.append(item.get('name', '')) + for item in toc_yaml_with_uid: + index_children.append(item.get('uidname', '')) index_references.append({ - 'uid': item.get('name', ''), + 'uid': item.get('uidname', ''), 'name': item.get('name', ''), - 'fullname': item.get('name', ''), + 'fullname': item.get('uidname', ''), 'isExternal': False }) with open(index_file, 'w') as index_file_obj: From 0334f4dd9375b3622c17dece84cde990cebadf22 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Thu, 13 May 2021 13:45:24 -0400 Subject: [PATCH 014/279] chore: release 0.2.0 (#19) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/gcp-sphinx-docfx-yaml/CHANGELOG.md | 7 +++++++ packages/gcp-sphinx-docfx-yaml/setup.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md index b8f7d6d6a75b..90807a75edc0 100644 --- a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md +++ b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.2.0](https://www.github.com/googleapis/sphinx-docfx-yaml/compare/v0.1.0...v0.2.0) (2021-05-13) + + +### Features + +* clarify names in the left nav ([#16](https://www.github.com/googleapis/sphinx-docfx-yaml/issues/16)) ([14cac76](https://www.github.com/googleapis/sphinx-docfx-yaml/commit/14cac765681b5cebca4361adbdf7010a7728c227)) + ## 0.1.0 (2021-03-25) diff --git a/packages/gcp-sphinx-docfx-yaml/setup.py b/packages/gcp-sphinx-docfx-yaml/setup.py index fd4b902593e9..9e8f1a92a4c6 100644 --- a/packages/gcp-sphinx-docfx-yaml/setup.py +++ b/packages/gcp-sphinx-docfx-yaml/setup.py @@ -17,7 +17,7 @@ name = 'gcp-sphinx-docfx-yaml' description = 'Sphinx Python Domain to DocFX YAML Generator' -version = '0.1.0' +version = '0.2.0' dependencies = [ 'PyYAML', 'wheel>=0.24.0', From 9ca911bc9fb3eaa6f53497e9a6540f81d26541ec Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Fri, 14 May 2021 22:56:11 -0400 Subject: [PATCH 015/279] test: add GitHub Action config for testing (#20) * test: add GitHub Action config for testing using tox * chore: update ci.yaml placement * chore: remove empty file directory * chore: update README and tox environment file * chore: update README to include instructions for testing * chore: remove failing build status on README --- .../.github/workflows/ci.yaml | 25 +++++++++++++++++++ packages/gcp-sphinx-docfx-yaml/.gitignore | 1 + packages/gcp-sphinx-docfx-yaml/README.rst | 15 ++++++++--- packages/gcp-sphinx-docfx-yaml/tox.ini | 2 +- 4 files changed, 39 insertions(+), 4 deletions(-) create mode 100644 packages/gcp-sphinx-docfx-yaml/.github/workflows/ci.yaml diff --git a/packages/gcp-sphinx-docfx-yaml/.github/workflows/ci.yaml b/packages/gcp-sphinx-docfx-yaml/.github/workflows/ci.yaml new file mode 100644 index 000000000000..509ece6e85fb --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/.github/workflows/ci.yaml @@ -0,0 +1,25 @@ +name: ci + +on: [push] + +jobs: + test: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: [3.6, 3.7, 3.8, 3.9] + + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install tox + - name: Run tests + run: | + tox -e docs + diff --git a/packages/gcp-sphinx-docfx-yaml/.gitignore b/packages/gcp-sphinx-docfx-yaml/.gitignore index b4243ced74e4..53aa75199a50 100644 --- a/packages/gcp-sphinx-docfx-yaml/.gitignore +++ b/packages/gcp-sphinx-docfx-yaml/.gitignore @@ -29,6 +29,7 @@ pip-log.txt .nox .cache .pytest_cache +.tox # Mac diff --git a/packages/gcp-sphinx-docfx-yaml/README.rst b/packages/gcp-sphinx-docfx-yaml/README.rst index 38291eeaf1d9..736966df9c61 100644 --- a/packages/gcp-sphinx-docfx-yaml/README.rst +++ b/packages/gcp-sphinx-docfx-yaml/README.rst @@ -7,9 +7,6 @@ Feel free to use this forked repository for personal or experimental use, use th Sphinx DocFX YAML ================= -.. image:: https://travis-ci.org/docascode/sphinx-docfx-yaml.svg?branch=master - :target: https://travis-ci.org/docascode/sphinx-docfx-yaml - Sphinx DocFX YAML is an exporter for the Sphinx Autodoc module into `DocFX YAML `_. You can read the full documentation online at http://sphinx-docfx-yaml.readthedocs.io @@ -61,6 +58,18 @@ Then build your documentation:: Inside your build directory (``_build/html`` usually), the ``docfx_yaml`` will contain the YAML files that are output. +Testing +------- + +To run the tests in this repository, run: + +.. code:: bash + + pip install tox + tox -e docs + +from the top directory of this repository. + .. Modes ----- diff --git a/packages/gcp-sphinx-docfx-yaml/tox.ini b/packages/gcp-sphinx-docfx-yaml/tox.ini index a547cf269cee..74f5405215c2 100644 --- a/packages/gcp-sphinx-docfx-yaml/tox.ini +++ b/packages/gcp-sphinx-docfx-yaml/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py35,py36,lint,docs +envlist = py36,py37,py38,py39,lint,docs [testenv] setenv = From e7a9434d922f97f7614e4e2f761ae84f91896bd3 Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Wed, 19 May 2021 08:41:37 -0400 Subject: [PATCH 016/279] feat: shorten function names shown on pages (#22) --- packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index 8a17f452b28b..ae1388c2c977 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -124,6 +124,7 @@ def _get_cls_module(_type, name): Foo """ + cls = None if _type in [FUNCTION, EXCEPTION]: module = '.'.join(name.split('.')[:-1]) @@ -145,7 +146,7 @@ def _create_reference(datam, parent, is_external=False): 'uid': datam['uid'], 'parent': parent, 'isExternal': is_external, - 'name': datam['name'], + 'name': datam['source']['id'], 'fullName': datam['fullName'], } @@ -304,6 +305,7 @@ def _update_friendly_package_name(path): # Match the defaults with the count if 'object at 0x' not in str(default): args[len(args) - cut_count + count]['defaultValue'] = str(default) + except Exception as e: print("Can't get argspec for {}: {}. Exception: {}".format(type(obj), name, e)) @@ -733,7 +735,8 @@ def convert_module_to_package_if_needed(obj): convert_module_to_package_if_needed(obj) if obj['type'] == 'method': - obj['namewithoutparameters'] = obj['source']['id'] + # Update the name to use shorter name to show + obj['name'] = obj['source']['id'] # To distinguish distribution package and import package if obj.get('type', '') == 'package' and obj.get('kind', '') != 'distribution': From adf3024b7dee9779921262e41f45656942b65ae6 Mon Sep 17 00:00:00 2001 From: Yoshi Automation Bot Date: Wed, 19 May 2021 13:50:51 -0700 Subject: [PATCH 017/279] changes without context (#17) autosynth cannot find the source of changes triggered by earlier changes in this repository, or by version upgrades to tools such as linters. Co-authored-by: Dan Lee <71398022+dandhlee@users.noreply.github.com> --- packages/gcp-sphinx-docfx-yaml/.pre-commit-config.yaml | 2 +- packages/gcp-sphinx-docfx-yaml/synth.metadata | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/.pre-commit-config.yaml b/packages/gcp-sphinx-docfx-yaml/.pre-commit-config.yaml index 1bbd787833ec..4f00c7cffcfd 100644 --- a/packages/gcp-sphinx-docfx-yaml/.pre-commit-config.yaml +++ b/packages/gcp-sphinx-docfx-yaml/.pre-commit-config.yaml @@ -26,6 +26,6 @@ repos: hooks: - id: black - repo: https://gitlab.com/pycqa/flake8 - rev: 3.9.1 + rev: 3.9.2 hooks: - id: flake8 diff --git a/packages/gcp-sphinx-docfx-yaml/synth.metadata b/packages/gcp-sphinx-docfx-yaml/synth.metadata index f3c44afcb479..9f6cb70640a3 100644 --- a/packages/gcp-sphinx-docfx-yaml/synth.metadata +++ b/packages/gcp-sphinx-docfx-yaml/synth.metadata @@ -4,7 +4,7 @@ "git": { "name": ".", "remote": "https://github.com/googleapis/sphinx-docfx-yaml.git", - "sha": "72eed3a8fdff8dffc6e5948a91376435befb9632" + "sha": "e013fa576c4bb4d0467ca530061107a1bfc9863b" } } ], From d17955eea6541bfd0767d6ad45e6d27613564bc5 Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Thu, 20 May 2021 23:56:57 -0400 Subject: [PATCH 018/279] chore(deps): use RenovateBot for Sphinx versioning (#26) --- packages/gcp-sphinx-docfx-yaml/requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/gcp-sphinx-docfx-yaml/requirements.txt b/packages/gcp-sphinx-docfx-yaml/requirements.txt index ee0595be3838..ec352d26d98a 100644 --- a/packages/gcp-sphinx-docfx-yaml/requirements.txt +++ b/packages/gcp-sphinx-docfx-yaml/requirements.txt @@ -1,2 +1,3 @@ +sphinx==4.0.0 -e . tox From d31529365b375214d2d38faa0d96adeb29333b5b Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Fri, 21 May 2021 06:26:10 +0200 Subject: [PATCH 019/279] chore(deps): update dependency sphinx to v4.0.2 (#29) --- packages/gcp-sphinx-docfx-yaml/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/requirements.txt b/packages/gcp-sphinx-docfx-yaml/requirements.txt index ec352d26d98a..c31742fd14a0 100644 --- a/packages/gcp-sphinx-docfx-yaml/requirements.txt +++ b/packages/gcp-sphinx-docfx-yaml/requirements.txt @@ -1,3 +1,3 @@ -sphinx==4.0.0 +sphinx==4.0.2 -e . tox From 2ac46500c02251e1583e6963127838af7df94720 Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Thu, 27 May 2021 15:04:34 -0400 Subject: [PATCH 020/279] chore: exclude .gitignore from template updates (#33) --- packages/gcp-sphinx-docfx-yaml/synth.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/synth.py b/packages/gcp-sphinx-docfx-yaml/synth.py index e44e73bd48d0..53a71a2c89ae 100644 --- a/packages/gcp-sphinx-docfx-yaml/synth.py +++ b/packages/gcp-sphinx-docfx-yaml/synth.py @@ -41,6 +41,7 @@ ".kokoro/test-sample*", "CONTRIBUTING.rst", # repo has a CONTRIBUTING.md ".github/CONTRIBUTING.md", - ".github/PULL_REQUEST_TEMPLATE.md" + ".github/PULL_REQUEST_TEMPLATE.md", + ".gitignore" ], ) From b1a38041e85887e6c971b6974282d07dead56fa0 Mon Sep 17 00:00:00 2001 From: Anthonios Partheniou Date: Sun, 30 May 2021 02:12:41 -0400 Subject: [PATCH 021/279] chore: migrate to owl bot (#35) --- .../.github/.OwlBot.lock.yaml | 17 +++++++ .../.github/.OwlBot.yaml | 18 ++++++++ .../{synth.py => owlbot.py} | 0 packages/gcp-sphinx-docfx-yaml/synth.metadata | 46 ------------------- 4 files changed, 35 insertions(+), 46 deletions(-) create mode 100644 packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml create mode 100644 packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.yaml rename packages/gcp-sphinx-docfx-yaml/{synth.py => owlbot.py} (100%) delete mode 100644 packages/gcp-sphinx-docfx-yaml/synth.metadata diff --git a/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml new file mode 100644 index 000000000000..eaee10479eed --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml @@ -0,0 +1,17 @@ +# Copyright 2021 Google LLC +# +# 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. + +docker: + image: gcr.io/repo-automation-bots/owlbot-python:latest + digest: sha256:c66ba3c8d7bc8566f47df841f98cd0097b28fff0b1864c86f5817f4c8c3e8600 diff --git a/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.yaml b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.yaml new file mode 100644 index 000000000000..892fbc2910bf --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.yaml @@ -0,0 +1,18 @@ +# Copyright 2021 Google LLC +# +# 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. + +docker: + image: gcr.io/repo-automation-bots/owlbot-python:latest + +begin-after-commit-hash: ee56c3493ec6aeb237ff515ecea949710944a20f diff --git a/packages/gcp-sphinx-docfx-yaml/synth.py b/packages/gcp-sphinx-docfx-yaml/owlbot.py similarity index 100% rename from packages/gcp-sphinx-docfx-yaml/synth.py rename to packages/gcp-sphinx-docfx-yaml/owlbot.py diff --git a/packages/gcp-sphinx-docfx-yaml/synth.metadata b/packages/gcp-sphinx-docfx-yaml/synth.metadata deleted file mode 100644 index 9f6cb70640a3..000000000000 --- a/packages/gcp-sphinx-docfx-yaml/synth.metadata +++ /dev/null @@ -1,46 +0,0 @@ -{ - "sources": [ - { - "git": { - "name": ".", - "remote": "https://github.com/googleapis/sphinx-docfx-yaml.git", - "sha": "e013fa576c4bb4d0467ca530061107a1bfc9863b" - } - } - ], - "generatedFiles": [ - ".github/ISSUE_TEMPLATE/bug_report.md", - ".github/ISSUE_TEMPLATE/feature_request.md", - ".github/ISSUE_TEMPLATE/support_request.md", - ".github/header-checker-lint.yml", - ".github/release-please.yml", - ".github/snippet-bot.yml", - ".gitignore", - ".kokoro/build.sh", - ".kokoro/continuous/common.cfg", - ".kokoro/continuous/continuous.cfg", - ".kokoro/docker/docs/Dockerfile", - ".kokoro/docker/docs/fetch_gpg_keys.sh", - ".kokoro/populate-secrets.sh", - ".kokoro/presubmit/common.cfg", - ".kokoro/presubmit/presubmit.cfg", - ".kokoro/release.sh", - ".kokoro/release/common.cfg", - ".kokoro/release/release.cfg", - ".kokoro/trampoline.sh", - ".kokoro/trampoline_v2.sh", - ".pre-commit-config.yaml", - ".trampolinerc", - "CODE_OF_CONDUCT.md", - "LICENSE", - "renovate.json", - "scripts/decrypt-secrets.sh", - "scripts/readme-gen/readme_gen.py", - "scripts/readme-gen/templates/README.tmpl.rst", - "scripts/readme-gen/templates/auth.tmpl.rst", - "scripts/readme-gen/templates/auth_api_key.tmpl.rst", - "scripts/readme-gen/templates/install_deps.tmpl.rst", - "scripts/readme-gen/templates/install_portaudio.tmpl.rst", - "testing/.gitignore" - ] -} \ No newline at end of file From 4fd986a7b24ab619e1ad0c904e74935423d5cc6e Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Tue, 1 Jun 2021 15:04:15 -0400 Subject: [PATCH 022/279] ci: add YAML generation Kokoro job (#32) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ci: add YAML generation Kokoro job * ci: update to use FORCE_GENERATE_ALL_TAGS * 🦉 Updates from OwlBot * chore: disable uploading googleapis.dev documents * chore: Update .kokoro/generate-docs.sh Co-authored-by: Tyler Bui-Palsulich <26876514+tbpg@users.noreply.github.com> * feat: Update shell script Co-authored-by: Owl Bot Co-authored-by: Tyler Bui-Palsulich <26876514+tbpg@users.noreply.github.com> --- .../.kokoro/docs/common.cfg | 65 ++++++++++++ .../.kokoro/docs/generate-docs.cfg | 1 + .../.kokoro/generate-docs.sh | 98 +++++++++++++++++++ 3 files changed, 164 insertions(+) create mode 100644 packages/gcp-sphinx-docfx-yaml/.kokoro/docs/common.cfg create mode 100644 packages/gcp-sphinx-docfx-yaml/.kokoro/docs/generate-docs.cfg create mode 100755 packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/docs/common.cfg b/packages/gcp-sphinx-docfx-yaml/.kokoro/docs/common.cfg new file mode 100644 index 000000000000..6659769f37d0 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/docs/common.cfg @@ -0,0 +1,65 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +# Build logs will be here +action { + define_artifacts { + regex: "**/*sponge_log.xml" + } +} + +# Download trampoline resources. +gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline" + +# Use the trampoline script to run in docker. +build_file: "sphinx-docfx-yaml/.kokoro/trampoline_v2.sh" + +# Configure the docker image for kokoro-trampoline. +env_vars: { + key: "TRAMPOLINE_IMAGE" + value: "gcr.io/cloud-devrel-kokoro-resources/python-lib-docs" +} +env_vars: { + key: "TRAMPOLINE_BUILD_FILE" + value: "github/sphinx-docfx-yaml/.kokoro/generate-docs.sh" +} + +env_vars: { + key: "STAGING_BUCKET" + value: "docs-staging" +} + +env_vars: { + key: "V2_STAGING_BUCKET" + value: "docs-staging-v2" +} + +# It will upload the docker image after successful builds. +env_vars: { + key: "TRAMPOLINE_IMAGE_UPLOAD" + value: "true" +} + +# It will always build the docker image. +env_vars: { + key: "TRAMPOLINE_DOCKERFILE" + value: ".kokoro/docker/docs/Dockerfile" +} + +# Fetch the token needed for reporting release status to GitHub +before_action { + fetch_keystore { + keystore_resource { + keystore_config_id: 73713 + keyname: "yoshi-automation-github-key" + } + } +} + +before_action { + fetch_keystore { + keystore_resource { + keystore_config_id: 73713 + keyname: "docuploader_service_account" + } + } +} diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/docs/generate-docs.cfg b/packages/gcp-sphinx-docfx-yaml/.kokoro/docs/generate-docs.cfg new file mode 100644 index 000000000000..8f43917d92fe --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/docs/generate-docs.cfg @@ -0,0 +1 @@ +# Format: //devtools/kokoro/config/proto/build.proto \ No newline at end of file diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh b/packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh new file mode 100755 index 000000000000..a4e2c65e6e4a --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh @@ -0,0 +1,98 @@ +#!/bin/bash +# Copyright 2021 Google LLC +# +# 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 +# +# https://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. + +set -eo pipefail + +# Disable buffering, so that the logs stream through. +export PYTHONUNBUFFERED=1 + +export PATH="${HOME}/.local/bin:${PATH}" + +# Install dependencies. +python3 -m pip install --user --quiet --upgrade nox +python3 -m pip install --user gcp-docuploader + +# Retrieve unique repositories to regenerate the YAML with. +for bucket_item in $(gsutil ls 'gs://docs-staging-v2/docfx-python*' | sort -u -t- -k5,5); do + + # Retrieve the GitHub Repository info. + gsutil cp ${bucket_item} . + tarball=$(echo ${bucket_item} | cut -d "/" -f 4) + tar -xf ${tarball} docs.metadata + repo=$(cat docs.metadata | grep "github_repository:" | cut -d "\"" -f 2 | cut -d "/" -f 2) + + echo "cloning ${repo}..." + git clone https://github.com/googleapis/${repo}.git + + # Clean up resources we don't need anymore. + rm ${tarball} + rm docs.metadata + + # For each repo, process docs and docfx jobs to regenerate the YAML. + cd ${repo} + + if [ ${FORCE_GENERATE_ALL_TAGS} = "true" ]; then + # Grabs all tags from the repository + GITHUB_TAGS=$(git tag --sort=-v:refname) + else + # Grab the latest released tag + GITHUB_TAGS=$(git describe --tags `git rev-list --tags --max-count=1`) + fi + + # TODO: allow skipping failing docs builds and continue with the rest of the generation. + for tag in ${GITHUB_TAGS}; do + git checkout ${tag} + + # TODO: support building all googleapis.dev docs through an environmental variable option passed. + ## Build HTML docs for googleapis.dev. + # nox -s docs + + # python3 -m docuploader create-metadata \ + # --name=$(jq --raw-output '.name // empty' .repo-metadata.json) \ + # --version=$(python3 setup.py --version) \ + # --language=$(jq --raw-output '.language // empty' .repo-metadata.json) \ + # --distribution-name=$(python3 setup.py --name) \ + # --product-page=$(jq --raw-output '.product_documentation // empty' .repo-metadata.json) \ + # --github-repository=$(jq --raw-output '.repo // empty' .repo-metadata.json) \ + # --issue-tracker=$(jq --raw-output '.issue_tracker // empty' .repo-metadata.json) + + # cat docs.metadata + + ## upload docs + # python3 -m docuploader upload docs/_build/html --metadata-file docs.metadata --staging-bucket "${STAGING_BUCKET}" + + + # Build YAML tarballs for Cloud-RAD. + nox -s docfx + + python3 -m docuploader create-metadata \ + --name=$(jq --raw-output '.name // empty' .repo-metadata.json) \ + --version=$(python3 setup.py --version) \ + --language=$(jq --raw-output '.language // empty' .repo-metadata.json) \ + --distribution-name=$(python3 setup.py --name) \ + --product-page=$(jq --raw-output '.product_documentation // empty' .repo-metadata.json) \ + --github-repository=$(jq --raw-output '.repo // empty' .repo-metadata.json) \ + --issue-tracker=$(jq --raw-output '.issue_tracker // empty' .repo-metadata.json) + + cat docs.metadata + + # upload docs + python3 -m docuploader upload docs/_build/html/docfx_yaml --metadata-file docs.metadata --destination-prefix docfx --staging-bucket "${V2_STAGING_BUCKET}" + done + + # Clean up the repository to make room. + cd ../ + rm -rf ${repo} +done From b43792f97f491d19c62051bcc5e11c5a387c5cc1 Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Thu, 3 Jun 2021 23:15:24 -0400 Subject: [PATCH 023/279] chore: exclude necessary file paths from OwlBot (#37) * chore: exclude necessary file paths from OwlBot * chore: rearrange for lexicographic ordering --- packages/gcp-sphinx-docfx-yaml/owlbot.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/gcp-sphinx-docfx-yaml/owlbot.py b/packages/gcp-sphinx-docfx-yaml/owlbot.py index 53a71a2c89ae..d05f2553d3cd 100644 --- a/packages/gcp-sphinx-docfx-yaml/owlbot.py +++ b/packages/gcp-sphinx-docfx-yaml/owlbot.py @@ -30,12 +30,14 @@ templated_files, excludes=[ ".flake8", + ".trampolinerc", "MANIFEST.in", "setup.cfg", ".coveragerc", "noxfile.py", # repo uses nox "docs/**/*", # no docs to publish ".kokoro/docs/", + ".kokoro/docker/", ".kokoro/publish-docs.sh", ".kokoro/samples/**", # no samples ".kokoro/test-sample*", From a48342a385b1c4a474ce70794bba7c7b2544060e Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Sun, 6 Jun 2021 19:42:57 -0400 Subject: [PATCH 024/279] chore: update OwlBot config (#38) --- packages/gcp-sphinx-docfx-yaml/owlbot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/owlbot.py b/packages/gcp-sphinx-docfx-yaml/owlbot.py index d05f2553d3cd..79300a22bdd2 100644 --- a/packages/gcp-sphinx-docfx-yaml/owlbot.py +++ b/packages/gcp-sphinx-docfx-yaml/owlbot.py @@ -37,7 +37,7 @@ "noxfile.py", # repo uses nox "docs/**/*", # no docs to publish ".kokoro/docs/", - ".kokoro/docker/", + ".kokoro/docker/**", ".kokoro/publish-docs.sh", ".kokoro/samples/**", # no samples ".kokoro/test-sample*", From 7adf6197f33b72cbc04a1a8455a4d793294900fc Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Mon, 7 Jun 2021 12:31:04 -0400 Subject: [PATCH 025/279] ci: Update Kokoro config files to fix pipeline build (#36) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ci: fix Kokoro job and continue on failures * chore: fix typo on script * ci: fix unary comparison error message * 🦉 Updates from OwlBot * ci: pass down FORCE_GENERATE_ALL_TAGS var * ci: exclude Dockerfile from Owlbot sync * 🦉 Updates from OwlBot * ci: update trampoline and Dockerfile * 🦉 Updates from OwlBot * ci: remove extra docker path from OwlBot config * ci: update Dockerfile with updated OwlBot Co-authored-by: Owl Bot --- .../.kokoro/docker/docs/Dockerfile | 3 ++ .../.kokoro/docs/common.cfg | 7 +-- .../.kokoro/generate-docs.sh | 43 ++++++++++++++----- packages/gcp-sphinx-docfx-yaml/.trampolinerc | 1 + 4 files changed, 40 insertions(+), 14 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/docker/docs/Dockerfile b/packages/gcp-sphinx-docfx-yaml/.kokoro/docker/docs/Dockerfile index 412b0b56a921..003da81e05b0 100644 --- a/packages/gcp-sphinx-docfx-yaml/.kokoro/docker/docs/Dockerfile +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/docker/docs/Dockerfile @@ -95,4 +95,7 @@ RUN wget -O /tmp/get-pip.py 'https://bootstrap.pypa.io/get-pip.py' \ && python3.8 /tmp/get-pip.py \ && rm /tmp/get-pip.py +# Install Google Cloud SDK +RUN echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] http://packages.cloud.google.com/apt cloud-sdk main" | tee -a /etc/apt/sources.list.d/google-cloud-sdk.list && curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key --keyring /usr/share/keyrings/cloud.google.gpg add - && apt-get update -y && apt-get install google-cloud-sdk -y + CMD ["python3.7"] diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/docs/common.cfg b/packages/gcp-sphinx-docfx-yaml/.kokoro/docs/common.cfg index 6659769f37d0..10ea6841569e 100644 --- a/packages/gcp-sphinx-docfx-yaml/.kokoro/docs/common.cfg +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/docs/common.cfg @@ -16,8 +16,9 @@ build_file: "sphinx-docfx-yaml/.kokoro/trampoline_v2.sh" # Configure the docker image for kokoro-trampoline. env_vars: { key: "TRAMPOLINE_IMAGE" - value: "gcr.io/cloud-devrel-kokoro-resources/python-lib-docs" + value: "gcr.io/cloud-devrel-kokoro-resources/python-multi" } + env_vars: { key: "TRAMPOLINE_BUILD_FILE" value: "github/sphinx-docfx-yaml/.kokoro/generate-docs.sh" @@ -33,10 +34,10 @@ env_vars: { value: "docs-staging-v2" } -# It will upload the docker image after successful builds. +# Do not upload the docker image after successful builds. env_vars: { key: "TRAMPOLINE_IMAGE_UPLOAD" - value: "true" + value: "false" } # It will always build the docker image. diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh b/packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh index a4e2c65e6e4a..33ed001b58f8 100755 --- a/packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh @@ -20,6 +20,13 @@ export PYTHONUNBUFFERED=1 export PATH="${HOME}/.local/bin:${PATH}" +# If running locally, copy a service account file to +# /dev/shm/73713_docuploader_service_account before calling ci/trampoline_v2.sh. +export GOOGLE_APPLICATION_CREDENTIALS=$KOKORO_KEYSTORE_DIR/73713_docuploader_service_account + +# Configure Google Cloud SDK to use service account details for gsutil commands. +gcloud auth activate-service-account --key-file ${GOOGLE_APPLICATION_CREDENTIALS} + # Install dependencies. python3 -m pip install --user --quiet --upgrade nox python3 -m pip install --user gcp-docuploader @@ -28,33 +35,46 @@ python3 -m pip install --user gcp-docuploader for bucket_item in $(gsutil ls 'gs://docs-staging-v2/docfx-python*' | sort -u -t- -k5,5); do # Retrieve the GitHub Repository info. - gsutil cp ${bucket_item} . tarball=$(echo ${bucket_item} | cut -d "/" -f 4) - tar -xf ${tarball} docs.metadata + + # Make temporary directory to extract tarball content. + mkdir ${tarball} + cd ${tarball} + + gsutil cp ${bucket_item} . + tar -zxvf ${tarball} repo=$(cat docs.metadata | grep "github_repository:" | cut -d "\"" -f 2 | cut -d "/" -f 2) - echo "cloning ${repo}..." - git clone https://github.com/googleapis/${repo}.git + # Clean up the tarball content. + cd .. + rm -rf ${tarball} - # Clean up resources we don't need anymore. - rm ${tarball} - rm docs.metadata + # Clone the repository. + git clone "https://github.com/googleapis/${repo}.git" # For each repo, process docs and docfx jobs to regenerate the YAML. cd ${repo} - if [ ${FORCE_GENERATE_ALL_TAGS} = "true" ]; then - # Grabs all tags from the repository + # Save the noxfile for usage throughout different releases. + cp "noxfile.py" ../ + + if [[ ${FORCE_GENERATE_ALL_TAGS} == "true" ]]; then + # Grabs all tags from the repository. GITHUB_TAGS=$(git tag --sort=-v:refname) + + # Turn off exit on failures, continue execution. + set +eo pipefail else - # Grab the latest released tag + # Grab the latest released tag. GITHUB_TAGS=$(git describe --tags `git rev-list --tags --max-count=1`) fi - # TODO: allow skipping failing docs builds and continue with the rest of the generation. for tag in ${GITHUB_TAGS}; do git checkout ${tag} + # Use the latest noxfile for all tags. + cp ../"noxfile.py" . + # TODO: support building all googleapis.dev docs through an environmental variable option passed. ## Build HTML docs for googleapis.dev. # nox -s docs @@ -95,4 +115,5 @@ for bucket_item in $(gsutil ls 'gs://docs-staging-v2/docfx-python*' | sort -u -t # Clean up the repository to make room. cd ../ rm -rf ${repo} + rm "noxfile.py" done diff --git a/packages/gcp-sphinx-docfx-yaml/.trampolinerc b/packages/gcp-sphinx-docfx-yaml/.trampolinerc index 383b6ec89fbc..521eae5d06df 100644 --- a/packages/gcp-sphinx-docfx-yaml/.trampolinerc +++ b/packages/gcp-sphinx-docfx-yaml/.trampolinerc @@ -25,6 +25,7 @@ pass_down_envvars+=( "STAGING_BUCKET" "V2_STAGING_BUCKET" "NOX_SESSION" + "FORCE_GENERATE_ALL_TAGS" # Regenerates YAML for all versions if set to true. ) # Prevent unintentional override on the default image. From 939fc0418716c244a2b9a0b4848c0bd9a51f6426 Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Tue, 15 Jun 2021 12:08:40 -0400 Subject: [PATCH 026/279] chore: Add note for repos that need manual update (#39) --- packages/gcp-sphinx-docfx-yaml/requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/gcp-sphinx-docfx-yaml/requirements.txt b/packages/gcp-sphinx-docfx-yaml/requirements.txt index c31742fd14a0..3cbc92cc8b0f 100644 --- a/packages/gcp-sphinx-docfx-yaml/requirements.txt +++ b/packages/gcp-sphinx-docfx-yaml/requirements.txt @@ -1,3 +1,4 @@ +# google-resumable-media-python requires manual update as this repo isn't templated. sphinx==4.0.2 -e . tox From 27ba3bc3bcd86d3ed6f5b3f1dbb1cbd87082ba42 Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Wed, 16 Jun 2021 14:48:45 -0400 Subject: [PATCH 027/279] fix: remove function and method name override (#42) --- packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index ae1388c2c977..07830bac24aa 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -384,9 +384,6 @@ def _update_friendly_package_name(path): datam['children'] = [] datam['references'] = [] - if _type in [FUNCTION, METHOD]: - datam['name'] = app.env.docfx_signature_funcs_methods.get(name, datam['name']) - return datam From 91478e567982af0414b00907352b5f14b61f5214 Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Thu, 17 Jun 2021 11:42:25 -0400 Subject: [PATCH 028/279] chore(.github): switch owner from onramp to cx-eng (#43) --- packages/gcp-sphinx-docfx-yaml/.github/CODEOWNERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/.github/CODEOWNERS b/packages/gcp-sphinx-docfx-yaml/.github/CODEOWNERS index c51369c19ced..fae1a7ad9db6 100644 --- a/packages/gcp-sphinx-docfx-yaml/.github/CODEOWNERS +++ b/packages/gcp-sphinx-docfx-yaml/.github/CODEOWNERS @@ -5,5 +5,5 @@ # https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners#codeowners-syntax -# The onramp team is responsible for all doc generation pipelines -* @googleapis/onramp +# The cx-eng team is responsible for all doc generation pipelines. +* @googleapis/cx-eng From e28b1a00bd0801fe24361ca6885c4f09c601edb2 Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Thu, 17 Jun 2021 15:02:21 -0400 Subject: [PATCH 029/279] feat: Add support for Property and missing content (#41) * feat: Add support for Property and missing content * chore: Apply suggestions from code review Co-authored-by: Tyler Bui-Palsulich <26876514+tbpg@users.noreply.github.com> * fix: refactor using GoogleDocstring * tests: adding test cases for further coverage * chore: add napoelon specification in requirements Co-authored-by: Tyler Bui-Palsulich <26876514+tbpg@users.noreply.github.com> --- .../docfx_yaml/extension.py | 186 ++++++++++++++++-- .../gcp-sphinx-docfx-yaml/requirements.txt | 1 + .../tests/example/conflict/foo.py | 19 ++ .../tests/example/format/google/foo.py | 2 + packages/gcp-sphinx-docfx-yaml/tox.ini | 2 +- 5 files changed, 191 insertions(+), 19 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index 07830bac24aa..f478b1c67d43 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -36,6 +36,8 @@ from sphinx.util import ensuredir from sphinx.errors import ExtensionError from sphinx.util.nodes import make_refnode +from sphinxcontrib.napoleon.docstring import GoogleDocstring +from sphinxcontrib.napoleon import Config from .utils import transform_node, transform_string from .settings import API_ROOT @@ -70,7 +72,9 @@ class Bcolors: REFMETHOD = 'meth' REFFUNCTION = 'func' INITPY = '__init__.py' -REF_PATTERN = ':(py:)?(func|class|meth|mod|ref):`~?[a-zA-Z_\.<> ]*?`' +REF_PATTERN = ':(py:)?(func|class|meth|mod|ref|attr|exc):`~?[a-zA-Z0-9_\.<> ]*?`' + +PROPERTY = 'property' def build_init(app): @@ -128,7 +132,7 @@ def _get_cls_module(_type, name): cls = None if _type in [FUNCTION, EXCEPTION]: module = '.'.join(name.split('.')[:-1]) - elif _type in [METHOD, ATTRIBUTE]: + elif _type in [METHOD, ATTRIBUTE, PROPERTY]: cls = '.'.join(name.split('.')[:-1]) module = '.'.join(name.split('.')[:-2]) elif _type in [CLASS]: @@ -287,6 +291,107 @@ def _update_friendly_package_name(path): return path + def _extract_docstring_info(summary_info, summary): + top_summary = "" + + # Initialize known types needing further processing. + var_types = { + ':rtype:': 'returns', + ':returns:': 'returns', + ':type': 'variables', + ':param': 'variables', + ':raises': 'exceptions', + ':raises:': 'exceptions' + } + + # Clean the string by cleaning newlines and backlashes, then split by white space. + config = Config(napoleon_use_param=True, napoleon_use_rtype=True) + # Convert Google style to reStructuredText + parsed_text = str(GoogleDocstring(summary, config)) + + # Trim the top summary but maintain its formatting. + indexes = [] + for types in var_types: + index = parsed_text.find(types) + if index > -1: + # For now, skip on parsing custom fields like attribute + if types == ':type' and 'attribute::' in parsed_text: + continue + indexes.append(index) + + # If we found types needing further processing, locate its index, + # if we found empty array for indexes, stop processing further. + index = min(indexes) if indexes else 0 + + # Store the top summary separately. + if index == 0: + top_summary = summary + else: + top_summary = parsed_text[:index] + parsed_text = parsed_text[index:] + + # Clean up whitespace and other characters + parsed_text = " ".join(filter(None, re.split(r'\n| |\|\s', parsed_text))).split(" ") + + cur_type = '' + words = [] + arg_name = '' + index = 0 + + # Using counter iteration to easily extract names rather than + # coming up with more complicated stopping logic for each tags. + while index <= len(parsed_text): + word = parsed_text[index] if index < len(parsed_text) else "" + # Check if we encountered specific words. + if word in var_types or index == len(parsed_text): + # Finish processing previous section. + if cur_type: + if cur_type == ':type': + summary_info[var_types[cur_type]][arg_name]['var_type'] = " ".join(words) + elif cur_type == ':param': + summary_info[var_types[cur_type]][arg_name]['description'] = " ".join(words) + elif ":raises" in cur_type: + summary_info[var_types[cur_type]].append({ + 'var_type': arg_name, + 'description': " ".join(words) + }) + elif cur_type == ':rtype:': + arg_name = " ".join(words) + else: + summary_info[var_types[cur_type]].append({ + 'var_type': arg_name, + 'description': " ".join(words) + }) + else: + # If after we processed the top summary and get in this state, + # likely we encountered a type that's not covered above or the docstring + # was formatted badly. This will likely break docfx job later on, should not + # process further. + if word not in var_types: + raise ValueError("Encountered wrong formatting, please check docstrings") + + # Reached end of string, break after finishing processing + if index == len(parsed_text): + break + + # Start processing for new section + cur_type = word + if cur_type in [':type', ':param', ':raises', ':raises:']: + index += 1 + arg_name = parsed_text[index][:-1] + # Initialize empty dictionary if it doesn't exist already + if arg_name not in summary_info[var_types[cur_type]] and ':raises' not in cur_type: + summary_info[var_types[cur_type]][arg_name] = {} + + # Empty target string + words = [] + else: + words.append(word) + + index += 1 + + return top_summary + if lines is None: lines = [] @@ -296,7 +401,13 @@ def _update_friendly_package_name(path): if _type in [METHOD, FUNCTION]: argspec = inspect.getfullargspec(obj) # noqa for arg in argspec.args: - args.append({'id': arg}) + # Ignore adding in entry for "self" + if arg != 'cls': + args.append({'id': arg}) + if argspec.varargs: + args.append({'id': argspec.varargs}) + if argspec.varkw: + args.append({'id': argspec.varkw}) if argspec.defaults: for count, default in enumerate(argspec.defaults): cut_count = len(argspec.defaults) @@ -305,9 +416,18 @@ def _update_friendly_package_name(path): # Match the defaults with the count if 'object at 0x' not in str(default): args[len(args) - cut_count + count]['defaultValue'] = str(default) + try: + lines = inspect.getdoc(obj) + lines = lines.split("\n") if lines else [] + except TypeError as e: + print("couldn't getdoc from method, function: {}".format(e)) - except Exception as e: - print("Can't get argspec for {}: {}. Exception: {}".format(type(obj), name, e)) + + elif _type in [PROPERTY]: + lines = inspect.getdoc(obj) + lines = lines.split("\n") if lines else [] + except TypeError as e: + print("Can't get argspec for {}: {}. {}".format(type(obj), name, e)) if name in app.env.docfx_signature_funcs_methods: sig = app.env.docfx_signature_funcs_methods[name] @@ -316,6 +436,7 @@ def _update_friendly_package_name(path): try: full_path = inspect.getsourcefile(obj) + if full_path is None: # Meet a .pyd file raise TypeError() # Sub git repo path @@ -342,7 +463,11 @@ def _update_friendly_package_name(path): pass except (TypeError, OSError): - print("Can't inspect type {}: {}".format(type(obj), name)) + # TODO: remove this once there is full handler for property + if _type in [PROPERTY]: + print("Skip inspecting for property: {}".format(name)) + else: + print("Can't inspect type {}: {}".format(type(obj), name)) path = None start_line = None @@ -365,19 +490,44 @@ def _update_friendly_package_name(path): 'langs': ['python'], } - # Only add summary to parts of the code that we don't get it from the monkeypatch - if _type == MODULE: + summary_info = { + 'variables': {}, # Stores mapping of variables and its description & types + 'returns': [], # Stores the return info + 'exceptions': [] # Stores the exception info + } + + # Add extracted summary + if lines != []: lines = _resolve_reference_in_module_summary(lines) summary = app.docfx_transform_string('\n'.join(_refact_example_in_module_summary(lines))) + + # Extract summary info into respective sections. if summary: - datam['summary'] = summary.strip(" \n\r\r") + top_summary = _extract_docstring_info(summary_info, summary) + datam['summary'] = top_summary - if args or sig: + if args or sig or summary_info: datam['syntax'] = {} - if args: - datam['syntax']['parameters'] = args - if sig: - datam['syntax']['content'] = sig + + if args: + variables = summary_info['variables'] + for arg in args: + if arg['id'] in variables: + # Retrieve argument info from extracted map of variable info + arg_var = variables[arg['id']] + arg['var_type'] = arg_var.get('var_type') if arg_var.get('var_type') else '' + arg['description'] = arg_var.get('description') if arg_var.get('description') else '' + datam['syntax']['parameters'] = args + + if sig: + datam['syntax']['content'] = sig + + if summary_info['returns']: + datam['syntax']['returns'] = summary_info['returns'] + + if summary_info['exceptions']: + datam['syntax']['exceptions'] = summary_info['exceptions'] + if cls: datam[CLASS] = cls if _type in [CLASS, MODULE]: @@ -404,7 +554,7 @@ def process_docstring(app, _type, name, obj, options, lines): _type = CLASS cls, module = _get_cls_module(_type, name) - if not module: + if not module and _type != PROPERTY: print('Unknown Type: %s' % _type) return None @@ -416,7 +566,7 @@ def process_docstring(app, _type, name, obj, options, lines): else: app.env.docfx_yaml_modules[module].append(datam) - if _type == CLASS: + if _type == CLASS or _type == PROPERTY: if cls not in app.env.docfx_yaml_classes: app.env.docfx_yaml_classes[cls] = [datam] else: @@ -539,8 +689,8 @@ def insert_children_on_class(app, _type, datam): for obj in insert_class: if obj['type'] != CLASS: continue - # Add methods & attributes to class - if _type in [METHOD, ATTRIBUTE] and \ + # Add methods & attributes & properties to class + if _type in [METHOD, ATTRIBUTE, PROPERTY] and \ obj[CLASS] == datam[CLASS]: obj['children'].append(datam['uid']) obj['references'].append(_create_reference(datam, parent=obj['uid'])) diff --git a/packages/gcp-sphinx-docfx-yaml/requirements.txt b/packages/gcp-sphinx-docfx-yaml/requirements.txt index 3cbc92cc8b0f..1b6ba53eb71f 100644 --- a/packages/gcp-sphinx-docfx-yaml/requirements.txt +++ b/packages/gcp-sphinx-docfx-yaml/requirements.txt @@ -1,4 +1,5 @@ # google-resumable-media-python requires manual update as this repo isn't templated. +sphinxcontrib.napoleon sphinx==4.0.2 -e . tox diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/conflict/foo.py b/packages/gcp-sphinx-docfx-yaml/tests/example/conflict/foo.py index 3f8b49c3e1aa..46a7ebb6d971 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/example/conflict/foo.py +++ b/packages/gcp-sphinx-docfx-yaml/tests/example/conflict/foo.py @@ -182,3 +182,22 @@ def method_default_value_comma(self, arg1=(1,2,3)): :param tuple arg1: Parameter arg1 of :meth:`conflict.foo.Foo.method_default_value_comma`, default value is (1,2,3). """ pass + + def snapshot(self, **kw): + """Create a snapshot to perform a set of reads with shared staleness. + + See + https://cloud.google.com/spanner/reference/rpc/google.spanner.v1#google.spanner.v1.TransactionOptions.ReadOnly + + :type kw: dict + :param kw: Passed through to + :class:`~google.cloud.spanner_v1.snapshot.Snapshot` ctor. + + :rtype: :class:`~google.cloud.spanner_v1.snapshot.Snapshot` + :returns: a snapshot bound to this session + :raises ValueError: if the session has not yet been created. + """ + if self._session_id is None: + raise ValueError("Session has not been created.") + + return Snapshot(self, **kw) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/format/google/foo.py b/packages/gcp-sphinx-docfx-yaml/tests/example/format/google/foo.py index e2efbf55700b..cd87600c86d8 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/example/format/google/foo.py +++ b/packages/gcp-sphinx-docfx-yaml/tests/example/format/google/foo.py @@ -35,6 +35,8 @@ def function(arg1, arg2, arg3, arg4): class Foo(object): """ Docstring of :class:`format.google.foo.Foo` class in google format. + + Testing for xref with new regex: :class:`google.spanner.v1.types.ExecuteSqlRequest.QueryMode` class. Attributes: attr (:class:`~format.rst.enum.EnumFoo`): Docstring of :any:`format.google.foo.Foo.attr` from class docstring. diff --git a/packages/gcp-sphinx-docfx-yaml/tox.ini b/packages/gcp-sphinx-docfx-yaml/tox.ini index 74f5405215c2..340066e55d71 100644 --- a/packages/gcp-sphinx-docfx-yaml/tox.ini +++ b/packages/gcp-sphinx-docfx-yaml/tox.ini @@ -16,7 +16,7 @@ deps = {[testenv]deps} changedir = {toxinidir}/docs commands = - sphinx-build -b html -d {envtmpdir}/doctrees . {envtmpdir}/html + sphinx-build -D extensions=sphinx.ext.autodoc,sphinx.ext.autosummary,docfx_yaml.extension,sphinx.ext.intersphinx,sphinx.ext.coverage,sphinx.ext.napoleon,sphinx.ext.todo,sphinx.ext.viewcode -b html -d {envtmpdir}/doctrees . {envtmpdir}/html [testenv:lint] deps = From f8b508eb9ba76b8d28dbdfb6381205b4eb10564e Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Mon, 21 Jun 2021 12:01:47 -0400 Subject: [PATCH 030/279] chore: update precommit hook pre-commit/pre-commit-hooks to v4 (#1083) (#46) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [![WhiteSource Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com) This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [pre-commit/pre-commit-hooks](https://togithub.com/pre-commit/pre-commit-hooks) | repository | major | `v3.4.0` -> `v4.0.1` | --- ### Release Notes
pre-commit/pre-commit-hooks ### [`v4.0.1`](https://togithub.com/pre-commit/pre-commit-hooks/releases/v4.0.1) [Compare Source](https://togithub.com/pre-commit/pre-commit-hooks/compare/v4.0.0...v4.0.1) ##### Fixes - `check-shebang-scripts-are-executable` fix entry point. - [#​602](https://togithub.com/pre-commit/pre-commit-hooks/issues/602) issue by [@​Person-93](https://togithub.com/Person-93). - [#​603](https://togithub.com/pre-commit/pre-commit-hooks/issues/603) PR by [@​scop](https://togithub.com/scop). ### [`v4.0.0`](https://togithub.com/pre-commit/pre-commit-hooks/releases/v4.0.0) [Compare Source](https://togithub.com/pre-commit/pre-commit-hooks/compare/v3.4.0...v4.0.0) ##### Features - `check-json`: report duplicate keys. - [#​558](https://togithub.com/pre-commit/pre-commit-hooks/issues/558) PR by [@​AdityaKhursale](https://togithub.com/AdityaKhursale). - [#​554](https://togithub.com/pre-commit/pre-commit-hooks/issues/554) issue by [@​adamchainz](https://togithub.com/adamchainz). - `no-commit-to-branch`: add `main` to default blocked branches. - [#​565](https://togithub.com/pre-commit/pre-commit-hooks/issues/565) PR by [@​ndevenish](https://togithub.com/ndevenish). - `check-case-conflict`: check conflicts in directory names as well. - [#​575](https://togithub.com/pre-commit/pre-commit-hooks/issues/575) PR by [@​slsyy](https://togithub.com/slsyy). - [#​70](https://togithub.com/pre-commit/pre-commit-hooks/issues/70) issue by [@​andyjack](https://togithub.com/andyjack). - `check-vcs-permalinks`: forbid other branch names. - [#​582](https://togithub.com/pre-commit/pre-commit-hooks/issues/582) PR by [@​jack1142](https://togithub.com/jack1142). - [#​581](https://togithub.com/pre-commit/pre-commit-hooks/issues/581) issue by [@​jack1142](https://togithub.com/jack1142). - `check-shebang-scripts-are-executable`: new hook which ensures shebang'd scripts are executable. - [#​545](https://togithub.com/pre-commit/pre-commit-hooks/issues/545) PR by [@​scop](https://togithub.com/scop). ##### Fixes - `check-executables-have-shebangs`: Short circuit shebang lookup on windows. - [#​544](https://togithub.com/pre-commit/pre-commit-hooks/issues/544) PR by [@​scop](https://togithub.com/scop). - `requirements-txt-fixer`: Fix comments which have indentation - [#​549](https://togithub.com/pre-commit/pre-commit-hooks/issues/549) PR by [@​greshilov](https://togithub.com/greshilov). - [#​548](https://togithub.com/pre-commit/pre-commit-hooks/issues/548) issue by [@​greshilov](https://togithub.com/greshilov). - `pretty-format-json`: write to stdout using UTF-8 encoding. - [#​571](https://togithub.com/pre-commit/pre-commit-hooks/issues/571) PR by [@​jack1142](https://togithub.com/jack1142). - [#​570](https://togithub.com/pre-commit/pre-commit-hooks/issues/570) issue by [@​jack1142](https://togithub.com/jack1142). - Use more inclusive language. - [#​599](https://togithub.com/pre-commit/pre-commit-hooks/issues/599) PR by [@​asottile](https://togithub.com/asottile). ##### Breaking changes - Remove deprecated hooks: `flake8`, `pyflakes`, `autopep8-wrapper`. - [#​597](https://togithub.com/pre-commit/pre-commit-hooks/issues/597) PR by [@​asottile](https://togithub.com/asottile).
--- ### Configuration 📅 **Schedule**: At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻️ **Rebasing**: Renovate will not automatically rebase this PR, because other commits have been found. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box. --- This PR has been generated by [WhiteSource Renovate](https://renovate.whitesourcesoftware.com). View repository job log [here](https://app.renovatebot.com/dashboard#github/googleapis/synthtool). Source-Link: https://github.com/googleapis/synthtool/commit/333fd90856f1454380514bc59fc0936cdaf1c202 Post-Processor: gcr.io/repo-automation-bots/owlbot-python:latest@sha256:b8c131c558606d3cea6e18f8e87befbd448c1482319b0db3c5d5388fa6ea72e3 Co-authored-by: Owl Bot --- .../.github/.OwlBot.lock.yaml | 16 +--------------- .../.pre-commit-config.yaml | 2 +- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml index eaee10479eed..9602d540595e 100644 --- a/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml +++ b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml @@ -1,17 +1,3 @@ -# Copyright 2021 Google LLC -# -# 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. - docker: image: gcr.io/repo-automation-bots/owlbot-python:latest - digest: sha256:c66ba3c8d7bc8566f47df841f98cd0097b28fff0b1864c86f5817f4c8c3e8600 + digest: sha256:b8c131c558606d3cea6e18f8e87befbd448c1482319b0db3c5d5388fa6ea72e3 diff --git a/packages/gcp-sphinx-docfx-yaml/.pre-commit-config.yaml b/packages/gcp-sphinx-docfx-yaml/.pre-commit-config.yaml index 4f00c7cffcfd..62eb5a77d9a3 100644 --- a/packages/gcp-sphinx-docfx-yaml/.pre-commit-config.yaml +++ b/packages/gcp-sphinx-docfx-yaml/.pre-commit-config.yaml @@ -16,7 +16,7 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v3.4.0 + rev: v4.0.1 hooks: - id: trailing-whitespace - id: end-of-file-fixer From b2a424dcdee1a01e4d6ffb0da83c4fa1441b75e5 Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Mon, 21 Jun 2021 14:24:47 -0400 Subject: [PATCH 031/279] fix: complete toc disambiguation (#45) * fix: complete toc disambiguation * fix: update to increment values * chore: update names map to name_entries * test: update to use unittest * test: fix typo in ci.yaml * test: update name and test file lengths --- .../.github/workflows/ci.yaml | 3 + .../docfx_yaml/extension.py | 57 +++++++++++++------ .../gcp-sphinx-docfx-yaml/tests/test_unit.py | 48 ++++++++++++++++ .../tests/yaml_post.yaml | 50 ++++++++++++++++ .../gcp-sphinx-docfx-yaml/tests/yaml_pre.yaml | 50 ++++++++++++++++ packages/gcp-sphinx-docfx-yaml/tox.ini | 6 ++ 6 files changed, 196 insertions(+), 18 deletions(-) create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/test_unit.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/yaml_post.yaml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/yaml_pre.yaml diff --git a/packages/gcp-sphinx-docfx-yaml/.github/workflows/ci.yaml b/packages/gcp-sphinx-docfx-yaml/.github/workflows/ci.yaml index 509ece6e85fb..1a4c02d9c1a5 100644 --- a/packages/gcp-sphinx-docfx-yaml/.github/workflows/ci.yaml +++ b/packages/gcp-sphinx-docfx-yaml/.github/workflows/ci.yaml @@ -22,4 +22,7 @@ jobs: - name: Run tests run: | tox -e docs + - name: Run unittest + run: | + tox -e unittest diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index f478b1c67d43..9e373432408d 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -707,6 +707,45 @@ def insert_children_on_function(app, _type, datam): insert_functions = app.env.docfx_yaml_functions[datam[FUNCTION]] insert_functions.append(datam) +# Parses the package name and returns unique identifer and name. +def find_unique_name(package_name, entries): + for name in package_name: + # Only find unique identifiers beside "google" and "cloud" + # For example, if given + # "google.cloud.spanner.v1.params_v1.types" + # "google.cloud.spanner.v1.instance_v1.types" + # it will return "instace_v1" or "params_v1" and "types". + if name != "google" and name != "cloud" and entries[name] == 1: + return [name, package_name[-1]] + +# Used to disambiguate names that have same entries. +def disambiguate_toc_name(toc_yaml): + name_entries = {} + for module in toc_yaml: + module_name = module['name'] + if module_name not in name_entries: + name_entries[module_name] = {} + + # Split the name and mark all duplicates. + # There will be at least 1 unique identifer for each name. + for part in module['uidname'].split("."): + if part not in name_entries[module_name]: + name_entries[module_name][part] = 1 + else: + name_entries[module_name][part] += 1 + + # Some entries don't contain `name` in `uidname`, add these into the map as well. + if module_name not in name_entries[module_name]: + name_entries[module_name][module_name] = 1 + + if 'items' in module: + disambiguate_toc_name(module['items']) + + for module in toc_yaml: + module_name = module['name'] + # Check if there are multiple entires of module['name'], disambiguate if needed. + if name_entries[module_name][module_name] > 1: + module['name'] = ".".join(find_unique_name(module['uidname'].split("."), name_entries[module_name])) def build_finished(app, exception): """ @@ -720,24 +759,6 @@ def sanitize_uidname_field(toc_yaml): sanitize_uidname_field(module['items']) module.pop('uidname') - # Parses the package name and returns package name and module name. - def find_package_name(package_name): - for name in package_name: - if name != "google" and name != "cloud": - return [name, package_name[-1]] - - # Used to disambiguate names that have same entries. - def disambiguate_toc_name(toc_yaml): - names = {} - for module in toc_yaml: - names[module['name']] = 1 if module['name'] not in names else 2 - if 'items' in module: - disambiguate_toc_name(module['items']) - - for module in toc_yaml: - if names[module['name']] > 1: - module['name'] = ".".join(find_package_name(module['uidname'].split("."))) - def find_node_in_toc_tree(toc_yaml, to_add_node): for module in toc_yaml: if module['uidname'] == to_add_node: diff --git a/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py b/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py new file mode 100644 index 000000000000..5a6056075f32 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py @@ -0,0 +1,48 @@ +from docfx_yaml.extension import find_unique_name +from docfx_yaml.extension import disambiguate_toc_name + +import unittest + +from yaml import load, Loader + +class TestGenerate(unittest.TestCase): + def test_find_unique_name(self): + + entries = {} + + # Disambiguate with unique entries. + entry1 = "google.cloud.aiplatform.v1.schema.predict.instance_v1.types" + entry2 = "google.cloud.aiplatform.v1beta2.schema.predict.instance_v1.types" + want1 = "v1.types" + want2 = "v1beta2.types" + + for entry in [entry1, entry2]: + for word in entry.split("."): + if word not in entries: + entries[word] = 1 + else: + entries[word] += 1 + + got1 = find_unique_name(entry1.split("."), entries) + got2 = find_unique_name(entry2.split("."), entries) + + self.assertEqual(want1, ".".join(got1)) + self.assertEqual(want2, ".".join(got2)) + + + def test_disambiguate_toc_name(self): + + want_file = open('tests/yaml_post.yaml', 'r') + yaml_want = load(want_file, Loader=Loader) + + test_file = open('tests/yaml_pre.yaml', 'r') + yaml_got = load(test_file, Loader=Loader) + disambiguate_toc_name(yaml_got) + + want_file.close() + test_file.close() + + self.assertEqual(yaml_want, yaml_got) + +if __name__ == '__main__': + unittest.main() diff --git a/packages/gcp-sphinx-docfx-yaml/tests/yaml_post.yaml b/packages/gcp-sphinx-docfx-yaml/tests/yaml_post.yaml new file mode 100644 index 000000000000..c422b2bb9850 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/yaml_post.yaml @@ -0,0 +1,50 @@ +[ + { + "name":"database_admin", + "uidname":"google.cloud.spanner_admin_database_v1.services.database_admin", + "items":[ + { + "name":"DatabaseAdminAsyncClient", + "uidname":"google.cloud.spanner_admin_database_v1.services.database_admin.DatabaseAdminAsyncClient", + "uid":"google.cloud.spanner_admin_database_v1.services.database_admin.DatabaseAdminAsyncClient" + }, + { + "name":"DatabaseAdminClient", + "uidname":"google.cloud.spanner_admin_database_v1.services.database_admin.DatabaseAdminClient", + "uid":"google.cloud.spanner_admin_database_v1.services.database_admin.DatabaseAdminClient" + } + ] + }, + { + "name":"spanner_admin_database_v1.types", + "uidname":"google.cloud.spanner_admin_database_v1.types", + }, + { + "name":"instance_admin", + "uidname":"google.cloud.spanner_admin_instance_v1.services.instance_admin", + }, + { + "name":"spanner_admin_instance_v1.types", + "uidname":"google.cloud.spanner_admin_instance_v1.types", + }, + { + "name":"batch", + "uidname":"google.cloud.spanner_v1.batch", + "items":[ + { + "name":"Overview", + "uidname":"google.cloud.spanner_v1.batch", + "uid":"google.cloud.spanner_v1.batch" + }, + { + "name":"Batch", + "uidname":"google.cloud.spanner_v1.batch.Batch", + "uid":"google.cloud.spanner_v1.batch.Batch" + } + ] + }, + { + "name":"spanner_v1.types", + "uidname":"google.cloud.spanner_v1.types", + } +] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/yaml_pre.yaml b/packages/gcp-sphinx-docfx-yaml/tests/yaml_pre.yaml new file mode 100644 index 000000000000..45e89ac35deb --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/yaml_pre.yaml @@ -0,0 +1,50 @@ +[ + { + "name":"database_admin", + "uidname":"google.cloud.spanner_admin_database_v1.services.database_admin", + "items":[ + { + "name":"DatabaseAdminAsyncClient", + "uidname":"google.cloud.spanner_admin_database_v1.services.database_admin.DatabaseAdminAsyncClient", + "uid":"google.cloud.spanner_admin_database_v1.services.database_admin.DatabaseAdminAsyncClient" + }, + { + "name":"DatabaseAdminClient", + "uidname":"google.cloud.spanner_admin_database_v1.services.database_admin.DatabaseAdminClient", + "uid":"google.cloud.spanner_admin_database_v1.services.database_admin.DatabaseAdminClient" + } + ] + }, + { + "name":"types", + "uidname":"google.cloud.spanner_admin_database_v1.types", + }, + { + "name":"instance_admin", + "uidname":"google.cloud.spanner_admin_instance_v1.services.instance_admin", + }, + { + "name":"types", + "uidname":"google.cloud.spanner_admin_instance_v1.types", + }, + { + "name":"batch", + "uidname":"google.cloud.spanner_v1.batch", + "items":[ + { + "name":"Overview", + "uidname":"google.cloud.spanner_v1.batch", + "uid":"google.cloud.spanner_v1.batch" + }, + { + "name":"Batch", + "uidname":"google.cloud.spanner_v1.batch.Batch", + "uid":"google.cloud.spanner_v1.batch.Batch" + } + ] + }, + { + "name":"types", + "uidname":"google.cloud.spanner_v1.types", + } +] diff --git a/packages/gcp-sphinx-docfx-yaml/tox.ini b/packages/gcp-sphinx-docfx-yaml/tox.ini index 340066e55d71..422b3123d7a8 100644 --- a/packages/gcp-sphinx-docfx-yaml/tox.ini +++ b/packages/gcp-sphinx-docfx-yaml/tox.ini @@ -18,6 +18,12 @@ changedir = {toxinidir}/docs commands = sphinx-build -D extensions=sphinx.ext.autodoc,sphinx.ext.autosummary,docfx_yaml.extension,sphinx.ext.intersphinx,sphinx.ext.coverage,sphinx.ext.napoleon,sphinx.ext.todo,sphinx.ext.viewcode -b html -d {envtmpdir}/doctrees . {envtmpdir}/html +[testenv:unittest] +deps = + {[testenv]deps} +commands = + python3 -m unittest tests/test_unit.py + [testenv:lint] deps = {[testenv]deps} From 12b8a5541c51a10df4b5ef0ed368882e5525425f Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Mon, 21 Jun 2021 14:26:00 -0400 Subject: [PATCH 032/279] chore: release 0.3.0 (#23) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/gcp-sphinx-docfx-yaml/CHANGELOG.md | 14 ++++++++++++++ packages/gcp-sphinx-docfx-yaml/setup.py | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md index 90807a75edc0..c5f4bcb25845 100644 --- a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md +++ b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## [0.3.0](https://www.github.com/googleapis/sphinx-docfx-yaml/compare/v0.2.0...v0.3.0) (2021-06-21) + + +### Features + +* Add support for Property and missing content ([#41](https://www.github.com/googleapis/sphinx-docfx-yaml/issues/41)) ([5ac499f](https://www.github.com/googleapis/sphinx-docfx-yaml/commit/5ac499fae23983cf929459ccc9a2ea9dcebae790)) +* shorten function names shown on pages ([#22](https://www.github.com/googleapis/sphinx-docfx-yaml/issues/22)) ([13edc85](https://www.github.com/googleapis/sphinx-docfx-yaml/commit/13edc859bea7c6150d6b688ddd3d65cef1ad33d7)) + + +### Bug Fixes + +* complete toc disambiguation ([#45](https://www.github.com/googleapis/sphinx-docfx-yaml/issues/45)) ([8928614](https://www.github.com/googleapis/sphinx-docfx-yaml/commit/892861441853735b4ab608aab94edd824ae77137)) +* remove function and method name override ([#42](https://www.github.com/googleapis/sphinx-docfx-yaml/issues/42)) ([ab8f265](https://www.github.com/googleapis/sphinx-docfx-yaml/commit/ab8f2656682ea4727c68f3bb5205260e16fb8f5c)) + ## [0.2.0](https://www.github.com/googleapis/sphinx-docfx-yaml/compare/v0.1.0...v0.2.0) (2021-05-13) diff --git a/packages/gcp-sphinx-docfx-yaml/setup.py b/packages/gcp-sphinx-docfx-yaml/setup.py index 9e8f1a92a4c6..c51a96d6240e 100644 --- a/packages/gcp-sphinx-docfx-yaml/setup.py +++ b/packages/gcp-sphinx-docfx-yaml/setup.py @@ -17,7 +17,7 @@ name = 'gcp-sphinx-docfx-yaml' description = 'Sphinx Python Domain to DocFX YAML Generator' -version = '0.2.0' +version = '0.3.0' dependencies = [ 'PyYAML', 'wheel>=0.24.0', From 170a52326e96d406dbb168f6763d49d23580e2bc Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Mon, 21 Jun 2021 17:48:41 -0400 Subject: [PATCH 033/279] fix: update dependency requirements (#48) * fix: update dependency requirements * test: add test for using without requirements.txt * test: replace original set up for this PR --- packages/gcp-sphinx-docfx-yaml/.github/workflows/ci.yaml | 3 +++ packages/gcp-sphinx-docfx-yaml/requirements.txt | 1 - packages/gcp-sphinx-docfx-yaml/setup.py | 5 +++-- packages/gcp-sphinx-docfx-yaml/tox.ini | 7 +++++++ 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/.github/workflows/ci.yaml b/packages/gcp-sphinx-docfx-yaml/.github/workflows/ci.yaml index 1a4c02d9c1a5..b5907a26587a 100644 --- a/packages/gcp-sphinx-docfx-yaml/.github/workflows/ci.yaml +++ b/packages/gcp-sphinx-docfx-yaml/.github/workflows/ci.yaml @@ -25,4 +25,7 @@ jobs: - name: Run unittest run: | tox -e unittest + - name: Run librarytest + run: | + tox -e librarytest diff --git a/packages/gcp-sphinx-docfx-yaml/requirements.txt b/packages/gcp-sphinx-docfx-yaml/requirements.txt index 1b6ba53eb71f..3cbc92cc8b0f 100644 --- a/packages/gcp-sphinx-docfx-yaml/requirements.txt +++ b/packages/gcp-sphinx-docfx-yaml/requirements.txt @@ -1,5 +1,4 @@ # google-resumable-media-python requires manual update as this repo isn't templated. -sphinxcontrib.napoleon sphinx==4.0.2 -e . tox diff --git a/packages/gcp-sphinx-docfx-yaml/setup.py b/packages/gcp-sphinx-docfx-yaml/setup.py index c51a96d6240e..18ea5ad0e3b9 100644 --- a/packages/gcp-sphinx-docfx-yaml/setup.py +++ b/packages/gcp-sphinx-docfx-yaml/setup.py @@ -20,9 +20,10 @@ version = '0.3.0' dependencies = [ 'PyYAML', - 'wheel>=0.24.0', 'sphinx', - 'unidecode' + 'sphinxcontrib.napoleon', + 'unidecode', + 'wheel>=0.24.0' ] packages = setuptools.find_packages('.', exclude=['tests']) diff --git a/packages/gcp-sphinx-docfx-yaml/tox.ini b/packages/gcp-sphinx-docfx-yaml/tox.ini index 422b3123d7a8..1aefc3b435a6 100644 --- a/packages/gcp-sphinx-docfx-yaml/tox.ini +++ b/packages/gcp-sphinx-docfx-yaml/tox.ini @@ -24,6 +24,13 @@ deps = commands = python3 -m unittest tests/test_unit.py +[testenv:librarytest] +deps = + sphinx_rtd_theme +changedir = {toxinidir}/docs +commands = + sphinx-build -D extensions=sphinx.ext.autodoc,sphinx.ext.autosummary,docfx_yaml.extension,sphinx.ext.intersphinx,sphinx.ext.coverage,sphinx.ext.napoleon,sphinx.ext.todo,sphinx.ext.viewcode -b html -d {envtmpdir}/doctrees . {envtmpdir}/html + [testenv:lint] deps = {[testenv]deps} From 5c7bd5fb507e7b99863c9b9e2ba40cc9c7897042 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Mon, 21 Jun 2021 17:50:22 -0400 Subject: [PATCH 034/279] chore: release 0.3.1 (#49) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/gcp-sphinx-docfx-yaml/CHANGELOG.md | 7 +++++++ packages/gcp-sphinx-docfx-yaml/setup.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md index c5f4bcb25845..aca1292661a1 100644 --- a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md +++ b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +### [0.3.1](https://www.github.com/googleapis/sphinx-docfx-yaml/compare/v0.3.0...v0.3.1) (2021-06-21) + + +### Bug Fixes + +* update dependency requirements ([#48](https://www.github.com/googleapis/sphinx-docfx-yaml/issues/48)) ([c1c036f](https://www.github.com/googleapis/sphinx-docfx-yaml/commit/c1c036fd00be08f219ffa4ebdfb5d13e2ee5768a)) + ## [0.3.0](https://www.github.com/googleapis/sphinx-docfx-yaml/compare/v0.2.0...v0.3.0) (2021-06-21) diff --git a/packages/gcp-sphinx-docfx-yaml/setup.py b/packages/gcp-sphinx-docfx-yaml/setup.py index 18ea5ad0e3b9..de63a8efcd7f 100644 --- a/packages/gcp-sphinx-docfx-yaml/setup.py +++ b/packages/gcp-sphinx-docfx-yaml/setup.py @@ -17,7 +17,7 @@ name = 'gcp-sphinx-docfx-yaml' description = 'Sphinx Python Domain to DocFX YAML Generator' -version = '0.3.0' +version = '0.3.1' dependencies = [ 'PyYAML', 'sphinx', From 8024f488a235ca3fa676522e9fe23130b03327a4 Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Wed, 23 Jun 2021 13:42:19 -0400 Subject: [PATCH 035/279] ci: update Dockerfile to install generic Python version (#54) * test: update Dockerfile * ci: update Dockerfile * chore: update formatting --- .../.kokoro/docker/docs/Dockerfile | 40 ++----------------- 1 file changed, 3 insertions(+), 37 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/docker/docs/Dockerfile b/packages/gcp-sphinx-docfx-yaml/.kokoro/docker/docs/Dockerfile index 003da81e05b0..0e91cd3cf9fa 100644 --- a/packages/gcp-sphinx-docfx-yaml/.kokoro/docker/docs/Dockerfile +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/docker/docs/Dockerfile @@ -40,6 +40,8 @@ RUN apt-get update \ libssl-dev \ libsqlite3-dev \ portaudio19-dev \ + python3 \ + python3-pip \ redis-server \ software-properties-common \ ssh \ @@ -59,43 +61,7 @@ RUN apt-get update \ && rm -rf /var/lib/apt/lists/* \ && rm -f /var/cache/apt/archives/*.deb - -COPY fetch_gpg_keys.sh /tmp -# Install the desired versions of Python. -RUN set -ex \ - && export GNUPGHOME="$(mktemp -d)" \ - && echo "disable-ipv6" >> "${GNUPGHOME}/dirmngr.conf" \ - && /tmp/fetch_gpg_keys.sh \ - && for PYTHON_VERSION in 3.7.8 3.8.5; do \ - wget --no-check-certificate -O python-${PYTHON_VERSION}.tar.xz "https://www.python.org/ftp/python/${PYTHON_VERSION%%[a-z]*}/Python-$PYTHON_VERSION.tar.xz" \ - && wget --no-check-certificate -O python-${PYTHON_VERSION}.tar.xz.asc "https://www.python.org/ftp/python/${PYTHON_VERSION%%[a-z]*}/Python-$PYTHON_VERSION.tar.xz.asc" \ - && gpg --batch --verify python-${PYTHON_VERSION}.tar.xz.asc python-${PYTHON_VERSION}.tar.xz \ - && rm -r python-${PYTHON_VERSION}.tar.xz.asc \ - && mkdir -p /usr/src/python-${PYTHON_VERSION} \ - && tar -xJC /usr/src/python-${PYTHON_VERSION} --strip-components=1 -f python-${PYTHON_VERSION}.tar.xz \ - && rm python-${PYTHON_VERSION}.tar.xz \ - && cd /usr/src/python-${PYTHON_VERSION} \ - && ./configure \ - --enable-shared \ - # This works only on Python 2.7 and throws a warning on every other - # version, but seems otherwise harmless. - --enable-unicode=ucs4 \ - --with-system-ffi \ - --without-ensurepip \ - && make -j$(nproc) \ - && make install \ - && ldconfig \ - ; done \ - && rm -rf "${GNUPGHOME}" \ - && rm -rf /usr/src/python* \ - && rm -rf ~/.cache/ - -RUN wget -O /tmp/get-pip.py 'https://bootstrap.pypa.io/get-pip.py' \ - && python3.7 /tmp/get-pip.py \ - && python3.8 /tmp/get-pip.py \ - && rm /tmp/get-pip.py - # Install Google Cloud SDK RUN echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] http://packages.cloud.google.com/apt cloud-sdk main" | tee -a /etc/apt/sources.list.d/google-cloud-sdk.list && curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key --keyring /usr/share/keyrings/cloud.google.gpg add - && apt-get update -y && apt-get install google-cloud-sdk -y -CMD ["python3.7"] +CMD ["python3"] From 78e0e7f04156ac2a72e4b01eb84b9c8c5d4c0ffc Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Thu, 24 Jun 2021 14:10:52 -0400 Subject: [PATCH 036/279] fix: update parser to correctly parse desired tokens (#55) * fix: correct parser to scan specific tokens only * fix: update parser for varying input types * test: add unittest for extract_docstring_info * fix: update parser and test * fix: update to return summary directly --- .../docfx_yaml/extension.py | 223 ++++++++++-------- .../gcp-sphinx-docfx-yaml/tests/test_unit.py | 128 ++++++++++ 2 files changed, 247 insertions(+), 104 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index 9e373432408d..b7ad6743c05a 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -270,6 +270,124 @@ def _extract_signature(obj_sig): return signature, parameters +# Given documentation docstring, parse them into summary_info. +def _extract_docstring_info(summary_info, summary, name): + top_summary = "" + + # Initialize known types needing further processing. + var_types = { + ':rtype:': 'returns', + ':returns:': 'returns', + ':type': 'variables', + ':param': 'variables', + ':raises': 'exceptions', + ':raises:': 'exceptions' + } + + # Clean the string by cleaning newlines and backlashes, then split by white space. + config = Config(napoleon_use_param=True, napoleon_use_rtype=True) + # Convert Google style to reStructuredText + parsed_text = str(GoogleDocstring(summary, config)) + + # Trim the top summary but maintain its formatting. + indexes = [] + for types in var_types: + # Ensure that we look for exactly the string we want. + # Adding the extra space for non-colon ending types + # helps determine if we simply ran into desired occurrence + # or if we ran into a similar looking syntax but shouldn't + # parse upon it. + types += ' ' if types[-1] != ':' else '' + if types in parsed_text: + index = parsed_text.find(types) + if index > -1: + # For now, skip on parsing custom fields like attribute + if types == ':type ' and 'attribute::' in parsed_text: + continue + indexes.append(index) + + # If we found types needing further processing, locate its index, + # if we found empty array for indexes, stop processing further. + index = min(indexes) if indexes else 0 + + # Store the top summary separately. + if index == 0: + return summary + + top_summary = parsed_text[:index] + parsed_text = parsed_text[index:] + + # Clean up whitespace and other characters + parsed_text = " ".join(filter(None, re.split(r'\|\s', parsed_text))).split() + + cur_type = '' + words = [] + arg_name = '' + index = 0 + # Used to track return type and description + r_type, r_descr = '', '' + + # Using counter iteration to easily extract names rather than + # coming up with more complicated stopping logic for each tags. + while index <= len(parsed_text): + word = parsed_text[index] if index < len(parsed_text) else "" + # Check if we encountered specific words. + if word in var_types or index == len(parsed_text): + # Finish processing previous section. + if cur_type: + if cur_type == ':type': + summary_info[var_types[cur_type]][arg_name]['var_type'] = " ".join(words) + elif cur_type == ':param': + summary_info[var_types[cur_type]][arg_name]['description'] = " ".join(words) + elif ":raises" in cur_type: + summary_info[var_types[cur_type]].append({ + 'var_type': arg_name, + 'description': " ".join(words) + }) + else: + if cur_type == ':rtype:': + r_type = " ".join(words) + else: + r_descr = " ".join(words) + if r_type and r_descr: + summary_info[var_types[cur_type]].append({ + 'var_type': r_type, + 'description': r_descr + }) + r_type, r_descr = '', '' + + else: + + # If after we processed the top summary and get in this state, + # likely we encountered a type that's not covered above or the docstring + # was formatted badly. This will likely break docfx job later on, should not + # process further. + if word not in var_types: + raise ValueError(f"Encountered wrong formatting, please check docstring for {name}") + + # Reached end of string, break after finishing processing + if index == len(parsed_text): + break + + # Start processing for new section + cur_type = word + if cur_type in [':type', ':param', ':raises', ':raises:']: + index += 1 + arg_name = parsed_text[index][:-1] + # Initialize empty dictionary if it doesn't exist already + if arg_name not in summary_info[var_types[cur_type]] and ':raises' not in cur_type: + summary_info[var_types[cur_type]][arg_name] = {} + + # Empty target string + words = [] + else: + words.append(word) + + index += 1 + + return top_summary + + def _create_datam(app, cls, module, name, _type, obj, lines=None): """ Build the data structure for an autodoc class @@ -291,108 +409,6 @@ def _update_friendly_package_name(path): return path - def _extract_docstring_info(summary_info, summary): - top_summary = "" - - # Initialize known types needing further processing. - var_types = { - ':rtype:': 'returns', - ':returns:': 'returns', - ':type': 'variables', - ':param': 'variables', - ':raises': 'exceptions', - ':raises:': 'exceptions' - } - - # Clean the string by cleaning newlines and backlashes, then split by white space. - config = Config(napoleon_use_param=True, napoleon_use_rtype=True) - # Convert Google style to reStructuredText - parsed_text = str(GoogleDocstring(summary, config)) - - # Trim the top summary but maintain its formatting. - indexes = [] - for types in var_types: - index = parsed_text.find(types) - if index > -1: - # For now, skip on parsing custom fields like attribute - if types == ':type' and 'attribute::' in parsed_text: - continue - indexes.append(index) - - # If we found types needing further processing, locate its index, - # if we found empty array for indexes, stop processing further. - index = min(indexes) if indexes else 0 - - # Store the top summary separately. - if index == 0: - top_summary = summary - else: - top_summary = parsed_text[:index] - parsed_text = parsed_text[index:] - - # Clean up whitespace and other characters - parsed_text = " ".join(filter(None, re.split(r'\n| |\|\s', parsed_text))).split(" ") - - cur_type = '' - words = [] - arg_name = '' - index = 0 - - # Using counter iteration to easily extract names rather than - # coming up with more complicated stopping logic for each tags. - while index <= len(parsed_text): - word = parsed_text[index] if index < len(parsed_text) else "" - # Check if we encountered specific words. - if word in var_types or index == len(parsed_text): - # Finish processing previous section. - if cur_type: - if cur_type == ':type': - summary_info[var_types[cur_type]][arg_name]['var_type'] = " ".join(words) - elif cur_type == ':param': - summary_info[var_types[cur_type]][arg_name]['description'] = " ".join(words) - elif ":raises" in cur_type: - summary_info[var_types[cur_type]].append({ - 'var_type': arg_name, - 'description': " ".join(words) - }) - elif cur_type == ':rtype:': - arg_name = " ".join(words) - else: - summary_info[var_types[cur_type]].append({ - 'var_type': arg_name, - 'description': " ".join(words) - }) - else: - # If after we processed the top summary and get in this state, - # likely we encountered a type that's not covered above or the docstring - # was formatted badly. This will likely break docfx job later on, should not - # process further. - if word not in var_types: - raise ValueError("Encountered wrong formatting, please check docstrings") - - # Reached end of string, break after finishing processing - if index == len(parsed_text): - break - - # Start processing for new section - cur_type = word - if cur_type in [':type', ':param', ':raises', ':raises:']: - index += 1 - arg_name = parsed_text[index][:-1] - # Initialize empty dictionary if it doesn't exist already - if arg_name not in summary_info[var_types[cur_type]] and ':raises' not in cur_type: - summary_info[var_types[cur_type]][arg_name] = {} - - # Empty target string - words = [] - else: - words.append(word) - - index += 1 - - return top_summary - - if lines is None: lines = [] short_name = name.split('.')[-1] @@ -421,7 +437,6 @@ def _extract_docstring_info(summary_info, summary): lines = lines.split("\n") if lines else [] except TypeError as e: print("couldn't getdoc from method, function: {}".format(e)) - elif _type in [PROPERTY]: lines = inspect.getdoc(obj) @@ -503,7 +518,7 @@ def _extract_docstring_info(summary_info, summary): # Extract summary info into respective sections. if summary: - top_summary = _extract_docstring_info(summary_info, summary) + top_summary = _extract_docstring_info(summary_info, summary, name) datam['summary'] = top_summary if args or sig or summary_info: diff --git a/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py b/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py index 5a6056075f32..984257a24ff2 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py +++ b/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py @@ -1,5 +1,6 @@ from docfx_yaml.extension import find_unique_name from docfx_yaml.extension import disambiguate_toc_name +from docfx_yaml.extension import _extract_docstring_info import unittest @@ -44,5 +45,132 @@ def test_disambiguate_toc_name(self): self.assertEqual(yaml_want, yaml_got) + # Variables used for testing _extract_docstring_info + top_summary1_want = "\nSimple test for docstring.\n\n" + summary_info1_want = { + 'variables': { + 'arg1': { + 'var_type': 'int', + 'description': 'simple description.' + }, + 'arg2': { + 'var_type': 'str', + 'description': 'simple description for `arg2`.' + } + }, + 'returns': [ + { + 'var_type': 'str', + 'description': 'simple description for return value.' + } + ], + 'exceptions': [ + { + 'var_type': 'AttributeError', + 'description': 'if `condition x`.' + } + ] + } + + + def test_extract_docstring_info_normal_input(self): + + ## Test for normal input + summary_info1_got = { + 'variables': {}, + 'returns': [], + 'exceptions': [] + } + + summary1 = """ +Simple test for docstring. + +Args: + arg1(int): simple description. + arg2(str): simple description for `arg2`. + +Returns: + str: simple description for return value. + +Raises: + AttributeError: if `condition x`. +""" + + top_summary1_got = _extract_docstring_info(summary_info1_got, summary1, "") + + self.assertEqual(top_summary1_got, self.top_summary1_want) + self.assertEqual(summary_info1_got, self.summary_info1_want) + + + def test_extract_docstring_info_mixed_format(self): + ## Test for input coming in mixed format. + summary2 = """ +Simple test for docstring. + +:type arg1: int +:param arg1: simple description. +:param arg2: simple description for `arg2`. +:type arg2: str + +:rtype: str +:returns: simple description for return value. + +:raises AttributeError: if `condition x`. +""" + + summary_info2_got = { + 'variables': {}, + 'returns': [], + 'exceptions': [] + } + + top_summary2_got = _extract_docstring_info(summary_info2_got, summary2, "") + + # Output should be same as test 1 with normal input. + self.assertEqual(top_summary2_got, self.top_summary1_want) + self.assertEqual(summary_info2_got, self.summary_info1_want) + + + def test_extract_docstring_info_check_parser(self): + ## Test for parser to correctly scan docstring tokens and not custom fields + summary_info3_want = { + 'variables': {}, + 'returns': [], + 'exceptions': [] + } + + summary3 = """ +Union[int, None]: Expiration time in milliseconds for a partition. + +If :attr:`partition_expiration` is set and is +not set, :attr:`type_` will default to +:attr:`~google.cloud.bigquery.table.TimePartitioningType.DAY`. +It could return :param: with :returns as well. +""" + + summary_info3_got = { + 'variables': {}, + 'returns': [], + 'exceptions': [] + } + + # Nothing should change + top_summary3_want = summary3 + + top_summary3_got = _extract_docstring_info(summary_info3_got, summary3, "") + + self.assertEqual(top_summary3_got, top_summary3_want) + self.assertEqual(summary_info3_got, summary_info3_want) + + def test_extract_docstring_info_check_error(self): + ## Test for incorrectly formmatted docstring raising error + summary4 = """ +Description of docstring which should fail. + +:returns:param: +""" + with self.assertRaises(ValueError): + _extract_docstring_info({}, summary4, "error string") + if __name__ == '__main__': unittest.main() From 385a44ef1751ca4d3bd0dc80824b7c705667843c Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Thu, 24 Jun 2021 15:01:36 -0400 Subject: [PATCH 037/279] fix: properly handle Raises section for GoogleDocstring (#56) * fix: add addtional handler for GoogleDocstring * test: add unittest * fix: simplify function call and references in test * fix: update test to include xref version * fix: update variable name to lowercase --- .../docfx_yaml/extension.py | 83 ++++++++++-- .../gcp-sphinx-docfx-yaml/tests/test_unit.py | 121 ++++++++++++++++++ 2 files changed, 194 insertions(+), 10 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index b7ad6743c05a..3a8fde92b9a3 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -72,7 +72,10 @@ class Bcolors: REFMETHOD = 'meth' REFFUNCTION = 'func' INITPY = '__init__.py' +# Regex expression for checking references of pattern like ":class:`~package_v1.module`" REF_PATTERN = ':(py:)?(func|class|meth|mod|ref|attr|exc):`~?[a-zA-Z0-9_\.<> ]*?`' +# Regex expression for checking references of pattern like "~package_v1.subpackage.module" +REF_PATTERN_LAST = '~(([a-zA-Z0-9_<>]*\.)*[a-zA-Z0-9_<>]*)' PROPERTY = 'property' @@ -184,23 +187,31 @@ def _refact_example_in_module_summary(lines): return new_lines -def _resolve_reference_in_module_summary(lines): +def _resolve_reference_in_module_summary(pattern, lines): new_lines = [] for line in lines: - matched_objs = list(re.finditer(REF_PATTERN, line)) + matched_objs = list(re.finditer(pattern, line)) new_line = line for matched_obj in matched_objs: start = matched_obj.start() end = matched_obj.end() matched_str = line[start:end] - if '<' in matched_str and '>' in matched_str: - # match string like ':func:`***<***>`' - index = matched_str.index('<') - ref_name = matched_str[index+1:-2] + if pattern == REF_PATTERN: + if '<' in matched_str and '>' in matched_str: + # match string like ':func:`***<***>`' + index = matched_str.index('<') + ref_name = matched_str[index+1:-2] + else: + # match string like ':func:`~***`' or ':func:`***`' + index = matched_str.index('~') if '~' in matched_str else matched_str.index('`') + ref_name = matched_str[index+1:-1] else: - # match string like ':func:`~***`' or ':func:`***`' - index = matched_str.index('~') if '~' in matched_str else matched_str.index('`') - ref_name = matched_str[index+1:-1] + index = matched_str.rfind('.') + 1 + if index == 0: + # If there is no dot, push index to not include tilde + index = 1 + # Find the last component of the target. "~Queue.get" only returns + ref_name = matched_str[index:] new_line = new_line.replace(matched_str, ''.format(ref_name)) new_lines.append(new_line) return new_lines @@ -283,11 +294,59 @@ def _extract_docstring_info(summary_info, summary, name): ':raises': 'exceptions', ':raises:': 'exceptions' } + + initial_index = -1 + + # Prevent GoogleDocstring crashing on custom types and parse all xrefs to normal + if '~' in summary or '" + while '~' in summary_part or ":" + elif "'))+1] + initial_index += len(original_type) + original_type = " ".join(filter(None, re.split(r'\n| |\|\s|\t', original_type))) + safe_type = original_type[6:-1] + else: + raise ValueError("Encountered unexpected type in Exception docstring.") + + type_pairs.append([original_type, safe_type]) + summary_part = summary[initial_index:] + + # Replace all the found occurrences + for pairs in type_pairs: + original_type, safe_type = pairs[0], pairs[1] + summary = summary.replace(original_type, safe_type) # Clean the string by cleaning newlines and backlashes, then split by white space. config = Config(napoleon_use_param=True, napoleon_use_rtype=True) # Convert Google style to reStructuredText parsed_text = str(GoogleDocstring(summary, config)) + + # Revert back to original type + if initial_index > -1: + for pairs in type_pairs: + original_type, safe_type = pairs[0], pairs[1] + parsed_text = parsed_text.replace(safe_type, original_type) # Trim the top summary but maintain its formatting. indexes = [] @@ -513,7 +572,11 @@ def _update_friendly_package_name(path): # Add extracted summary if lines != []: - lines = _resolve_reference_in_module_summary(lines) + # Resolve references for xrefs in two different formats. + # REF_PATTERN checks for patterns like ":class:`~google.package.module`" + lines = _resolve_reference_in_module_summary(REF_PATTERN, lines) + # REF_PATTERN_LAST checks for patterns like "~package.module" + lines = _resolve_reference_in_module_summary(REF_PATTERN_LAST, lines) summary = app.docfx_transform_string('\n'.join(_refact_example_in_module_summary(lines))) # Extract summary info into respective sections. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py b/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py index 984257a24ff2..3bc522f8920b 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py +++ b/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py @@ -1,5 +1,8 @@ from docfx_yaml.extension import find_unique_name from docfx_yaml.extension import disambiguate_toc_name +from docfx_yaml.extension import _resolve_reference_in_module_summary +from docfx_yaml.extension import REF_PATTERN +from docfx_yaml.extension import REF_PATTERN_LAST from docfx_yaml.extension import _extract_docstring_info import unittest @@ -45,6 +48,69 @@ def test_disambiguate_toc_name(self): self.assertEqual(yaml_want, yaml_got) + + def test_reference_in_summary(self): + lines_got = """ +If a ``stream`` is attached to this download, then the downloaded +resource will be written to the stream. + +Args: + transport (~requests.Session): A ``requests`` object which can + make authenticated requests. + + timeout (Optional[Union[float, Tuple[float, float]]]): + The number of seconds to wait for the server response. + Depending on the retry strategy, a request may be repeated + several times using the same timeout each time. + + Can also be passed as a tuple (connect_timeout, read_timeout). + See :meth:`requests.Session.request` documentation for details. + +Returns: + ~requests.Response: The HTTP response returned by ``transport``. + +Raises: + ~google.resumable_media.common.DataCorruption: If the download's + checksum doesn't agree with server-computed checksum. + ValueError: If the current :class:`Download` has already + finished. +""" + lines_got = lines_got.split("\n") + + # Resolve over different regular expressions for different types of reference patterns. + lines_got = _resolve_reference_in_module_summary(REF_PATTERN, lines_got) + lines_got = _resolve_reference_in_module_summary(REF_PATTERN_LAST, lines_got) + + lines_want = """ +If a ``stream`` is attached to this download, then the downloaded +resource will be written to the stream. + +Args: + transport (): A ``requests`` object which can + make authenticated requests. + + timeout (Optional[Union[float, Tuple[float, float]]]): + The number of seconds to wait for the server response. + Depending on the retry strategy, a request may be repeated + several times using the same timeout each time. + + Can also be passed as a tuple (connect_timeout, read_timeout). + See documentation for details. + +Returns: + : The HTTP response returned by ``transport``. + +Raises: + : If the download's + checksum doesn't agree with server-computed checksum. + ValueError: If the current has already + finished. +""" + lines_want = lines_want.split("\n") + + self.assertEqual(lines_got, lines_want) + + # Variables used for testing _extract_docstring_info top_summary1_want = "\nSimple test for docstring.\n\n" summary_info1_want = { @@ -162,6 +228,7 @@ def test_extract_docstring_info_check_parser(self): self.assertEqual(top_summary3_got, top_summary3_want) self.assertEqual(summary_info3_got, summary_info3_want) + def test_extract_docstring_info_check_error(self): ## Test for incorrectly formmatted docstring raising error summary4 = """ @@ -172,5 +239,59 @@ def test_extract_docstring_info_check_error(self): with self.assertRaises(ValueError): _extract_docstring_info({}, summary4, "error string") + + def test_extract_docstring_info_with_xref(self): + ## Test with xref included in the summary, ensure they're processed as-is + summary_info_want = { + 'variables': { + 'arg1': { + 'var_type': '', + 'description': 'simple description.' + }, + 'arg2': { + 'var_type': '~google.spanner_v1.type.dict', + 'description': 'simple description for `arg2`.' + } + }, + 'returns': [ + { + 'var_type': '', + 'description': 'simple description for return value.' + } + ], + 'exceptions': [ + { + 'var_type': '', + 'description': 'if `condition x`.' + } + ] + } + + summary = """ +Simple test for docstring. + +:type arg1: +:param arg1: simple description. +:param arg2: simple description for `arg2`. +:type arg2: ~google.spanner_v1.type.dict + +:rtype: +:returns: simple description for return value. + +:raises : if `condition x`. +""" + + summary_info_got = { + 'variables': {}, + 'returns': [], + 'exceptions': [] + } + + top_summary_got = _extract_docstring_info(summary_info_got, summary, "") + + # Same as the top summary from previous example, compare with that + self.assertEqual(top_summary_got, self.top_summary1_want) + self.assertEqual(summary_info_got, summary_info_want) + if __name__ == '__main__': unittest.main() From d157bf42990ae0694965869bb0f642ce93fd961a Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Thu, 24 Jun 2021 15:04:06 -0400 Subject: [PATCH 038/279] chore: release 0.3.2 (#57) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/gcp-sphinx-docfx-yaml/CHANGELOG.md | 8 ++++++++ packages/gcp-sphinx-docfx-yaml/setup.py | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md index aca1292661a1..953d91e8f9c4 100644 --- a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md +++ b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +### [0.3.2](https://www.github.com/googleapis/sphinx-docfx-yaml/compare/v0.3.1...v0.3.2) (2021-06-24) + + +### Bug Fixes + +* properly handle Raises section for GoogleDocstring ([#56](https://www.github.com/googleapis/sphinx-docfx-yaml/issues/56)) ([793dd48](https://www.github.com/googleapis/sphinx-docfx-yaml/commit/793dd4847cfbc6bc060d7a8840bd102f4bf37058)) +* update parser to correctly parse desired tokens ([#55](https://www.github.com/googleapis/sphinx-docfx-yaml/issues/55)) ([d1e18c7](https://www.github.com/googleapis/sphinx-docfx-yaml/commit/d1e18c7cb64aac9710ff18863e7c78306e93d568)) + ### [0.3.1](https://www.github.com/googleapis/sphinx-docfx-yaml/compare/v0.3.0...v0.3.1) (2021-06-21) diff --git a/packages/gcp-sphinx-docfx-yaml/setup.py b/packages/gcp-sphinx-docfx-yaml/setup.py index de63a8efcd7f..308dcc7377b8 100644 --- a/packages/gcp-sphinx-docfx-yaml/setup.py +++ b/packages/gcp-sphinx-docfx-yaml/setup.py @@ -17,7 +17,7 @@ name = 'gcp-sphinx-docfx-yaml' description = 'Sphinx Python Domain to DocFX YAML Generator' -version = '0.3.1' +version = '0.3.2' dependencies = [ 'PyYAML', 'sphinx', From c9de6cf0352cc13ba2ca959110dec799e2b91001 Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Fri, 25 Jun 2021 17:53:35 -0400 Subject: [PATCH 039/279] fix: handle entries that cannot be disambiguated (#59) --- .../docfx_yaml/extension.py | 3 ++ .../gcp-sphinx-docfx-yaml/tests/test_unit.py | 15 ++++++++ .../tests/yaml_post_duplicate.yaml | 34 +++++++++++++++++++ .../tests/yaml_pre_duplicate.yaml | 34 +++++++++++++++++++ 4 files changed, 86 insertions(+) create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/yaml_post_duplicate.yaml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/yaml_pre_duplicate.yaml diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index 3a8fde92b9a3..2ea09bbb7809 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -796,6 +796,9 @@ def find_unique_name(package_name, entries): if name != "google" and name != "cloud" and entries[name] == 1: return [name, package_name[-1]] + # If there is no way to disambiguate, return the identifier name + return [package_name[-1]] + # Used to disambiguate names that have same entries. def disambiguate_toc_name(toc_yaml): name_entries = {} diff --git a/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py b/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py index 3bc522f8920b..a5ea20c446e3 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py +++ b/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py @@ -49,6 +49,21 @@ def test_disambiguate_toc_name(self): self.assertEqual(yaml_want, yaml_got) + def test_disambiguate_toc_name_duplicate(self): + + want_file = open('tests/yaml_post_duplicate.yaml', 'r') + yaml_want = load(want_file, Loader=Loader) + + test_file = open('tests/yaml_pre_duplicate.yaml', 'r') + yaml_got = load(test_file, Loader=Loader) + disambiguate_toc_name(yaml_got) + + want_file.close() + test_file.close() + + self.assertEqual(yaml_want, yaml_got) + + def test_reference_in_summary(self): lines_got = """ If a ``stream`` is attached to this download, then the downloaded diff --git a/packages/gcp-sphinx-docfx-yaml/tests/yaml_post_duplicate.yaml b/packages/gcp-sphinx-docfx-yaml/tests/yaml_post_duplicate.yaml new file mode 100644 index 000000000000..520d45e40dbe --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/yaml_post_duplicate.yaml @@ -0,0 +1,34 @@ +[ + { + "name":"client_info", + "uidname":"google.api_core.client_info", + "items":[ + { + "name":"Overview", + "uidname":"google.api_core.client_info", + "uid":"google.api_core.client_info" + }, + { + "name":"ClientInfo", + "uidname":"google.api_core.client_info.ClientInfo", + "uid":"google.api_core.client_info.ClientInfo" + } + ] + }, + { + "name":"gapic_v1.client_info", + "uidname":"google.api_core.gapic_v1.client_info", + "items":[ + { + "name":"Overview", + "uidname":"google.api_core.gapic_v1.client_info", + "uid":"google.api_core.gapic_v1.client_info" + }, + { + "name":"ClientInfo", + "uidname":"google.api_core.gapic_v1.client_info.ClientInfo", + "uid":"google.api_core.gapic_v1.client_info.ClientInfo" + } + ] + }, +] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/yaml_pre_duplicate.yaml b/packages/gcp-sphinx-docfx-yaml/tests/yaml_pre_duplicate.yaml new file mode 100644 index 000000000000..dfae6974da3a --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/yaml_pre_duplicate.yaml @@ -0,0 +1,34 @@ +[ + { + "name":"client_info", + "uidname":"google.api_core.client_info", + "items":[ + { + "name":"Overview", + "uidname":"google.api_core.client_info", + "uid":"google.api_core.client_info" + }, + { + "name":"ClientInfo", + "uidname":"google.api_core.client_info.ClientInfo", + "uid":"google.api_core.client_info.ClientInfo" + } + ] + }, + { + "name":"client_info", + "uidname":"google.api_core.gapic_v1.client_info", + "items":[ + { + "name":"Overview", + "uidname":"google.api_core.gapic_v1.client_info", + "uid":"google.api_core.gapic_v1.client_info" + }, + { + "name":"ClientInfo", + "uidname":"google.api_core.gapic_v1.client_info.ClientInfo", + "uid":"google.api_core.gapic_v1.client_info.ClientInfo" + } + ] + }, +] From 599b81d4902a095e694dc9031d5fe8a4621579c5 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Fri, 25 Jun 2021 17:58:06 -0400 Subject: [PATCH 040/279] chore: release 0.3.3 (#62) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/gcp-sphinx-docfx-yaml/CHANGELOG.md | 7 +++++++ packages/gcp-sphinx-docfx-yaml/setup.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md index 953d91e8f9c4..fce69d7d4a60 100644 --- a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md +++ b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +### [0.3.3](https://www.github.com/googleapis/sphinx-docfx-yaml/compare/v0.3.2...v0.3.3) (2021-06-25) + + +### Bug Fixes + +* handle entries that cannot be disambiguated ([#59](https://www.github.com/googleapis/sphinx-docfx-yaml/issues/59)) ([7678b24](https://www.github.com/googleapis/sphinx-docfx-yaml/commit/7678b246636bf8387e7049af11bce1a33a9a5826)) + ### [0.3.2](https://www.github.com/googleapis/sphinx-docfx-yaml/compare/v0.3.1...v0.3.2) (2021-06-24) diff --git a/packages/gcp-sphinx-docfx-yaml/setup.py b/packages/gcp-sphinx-docfx-yaml/setup.py index 308dcc7377b8..a0bd54f4a158 100644 --- a/packages/gcp-sphinx-docfx-yaml/setup.py +++ b/packages/gcp-sphinx-docfx-yaml/setup.py @@ -17,7 +17,7 @@ name = 'gcp-sphinx-docfx-yaml' description = 'Sphinx Python Domain to DocFX YAML Generator' -version = '0.3.2' +version = '0.3.3' dependencies = [ 'PyYAML', 'sphinx', From 2d12eccbe15a9dd41f0da5dd0512a2d0e5c52027 Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Mon, 28 Jun 2021 13:16:57 -0400 Subject: [PATCH 041/279] fix: deduplicate entries in children and references (#61) --- .../gcp-sphinx-docfx-yaml/docfx_yaml/extension.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index 2ea09bbb7809..5557f1142d40 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -99,6 +99,8 @@ def build_init(app): app.env.docfx_signature_funcs_methods = {} # This store the uid-type mapping info app.env.docfx_info_uid_types = {} + # This stores uidnames of docstrings already parsed + app.env.docfx_uid_names = {} remote = getoutput('git remote -v') @@ -626,8 +628,15 @@ def process_docstring(app, _type, name, obj, options, lines): """ This function takes the docstring and indexes it into memory. """ - # Use exception as class + # Check if we already processed this docstring. + if name in app.env.docfx_uid_names: + return + + # Register current docstring to a set. + app.env.docfx_uid_names[name] = '' + + # Use exception as class if _type == EXCEPTION: _type = CLASS @@ -703,6 +712,7 @@ def insert_children_on_module(app, _type, datam): if MODULE not in datam or datam[MODULE] not in app.env.docfx_yaml_modules: return + insert_module = app.env.docfx_yaml_modules[datam[MODULE]] # Find the module which the datam belongs to for obj in insert_module: @@ -715,7 +725,6 @@ def insert_children_on_module(app, _type, datam): # If it is a function, add this to its module. No need for class and module since this is # done before calling this function. insert_module.append(datam) - obj['references'].append(_create_reference(datam, parent=obj['uid'])) break # Add classes & exceptions to module From cefd7d8ab5b0605ec59314cd175f4e3789a6868b Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Mon, 5 Jul 2021 18:32:37 +0200 Subject: [PATCH 042/279] chore(deps): update dependency sphinx to v4.0.3 (#64) --- packages/gcp-sphinx-docfx-yaml/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/requirements.txt b/packages/gcp-sphinx-docfx-yaml/requirements.txt index 3cbc92cc8b0f..80e18620aff5 100644 --- a/packages/gcp-sphinx-docfx-yaml/requirements.txt +++ b/packages/gcp-sphinx-docfx-yaml/requirements.txt @@ -1,4 +1,4 @@ # google-resumable-media-python requires manual update as this repo isn't templated. -sphinx==4.0.2 +sphinx==4.0.3 -e . tox From 89889add22121274f33630a914b47a1e42b85344 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Wed, 7 Jul 2021 15:11:53 -0400 Subject: [PATCH 043/279] chore: release 0.3.4 (#63) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/gcp-sphinx-docfx-yaml/CHANGELOG.md | 7 +++++++ packages/gcp-sphinx-docfx-yaml/setup.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md index fce69d7d4a60..c29fdeefb36a 100644 --- a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md +++ b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +### [0.3.4](https://www.github.com/googleapis/sphinx-docfx-yaml/compare/v0.3.3...v0.3.4) (2021-07-05) + + +### Bug Fixes + +* deduplicate entries in children and references ([#61](https://www.github.com/googleapis/sphinx-docfx-yaml/issues/61)) ([6d5407b](https://www.github.com/googleapis/sphinx-docfx-yaml/commit/6d5407b6c004587071d2523f1bad4717678774da)) + ### [0.3.3](https://www.github.com/googleapis/sphinx-docfx-yaml/compare/v0.3.2...v0.3.3) (2021-06-25) diff --git a/packages/gcp-sphinx-docfx-yaml/setup.py b/packages/gcp-sphinx-docfx-yaml/setup.py index a0bd54f4a158..378888209998 100644 --- a/packages/gcp-sphinx-docfx-yaml/setup.py +++ b/packages/gcp-sphinx-docfx-yaml/setup.py @@ -17,7 +17,7 @@ name = 'gcp-sphinx-docfx-yaml' description = 'Sphinx Python Domain to DocFX YAML Generator' -version = '0.3.3' +version = '0.3.4' dependencies = [ 'PyYAML', 'sphinx', From 42b6ab3cdfaf498c875ddf69bc8c304a8da654bc Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Thu, 8 Jul 2021 08:12:22 -0400 Subject: [PATCH 044/279] chore: update reminder for sphinx version update on other repositories (#65) Before you open a pull request, note that this repository is forked from [here](https://github.com/docascode/sphinx-docfx-yaml/). Unless the issue you're trying to solve is unique to this specific repository, please file an issue and/or send changes upstream to the original as well. __________________________________________________________________ Python-api-core is another repo that is not using templated Noxfile.py for various reasons (see discussion on https://github.com/googleapis/python-api-core/issues/219), and we'll need to update it manually when we need Sphinx version updates. > It's a good idea to open an issue first for discussion. - [x] Tests pass - [ ] Appropriate changes to README are included in PR --- packages/gcp-sphinx-docfx-yaml/requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/gcp-sphinx-docfx-yaml/requirements.txt b/packages/gcp-sphinx-docfx-yaml/requirements.txt index 80e18620aff5..a8bc2f792b82 100644 --- a/packages/gcp-sphinx-docfx-yaml/requirements.txt +++ b/packages/gcp-sphinx-docfx-yaml/requirements.txt @@ -1,4 +1,5 @@ # google-resumable-media-python requires manual update as this repo isn't templated. +# python-api-core also requires manual update as it is not templated. sphinx==4.0.3 -e . tox From 9f1fc8a22434ab431b61c8c3ebec5171f2c56bd0 Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Tue, 13 Jul 2021 14:21:54 -0400 Subject: [PATCH 045/279] chore: allow testing plugin without running nox (#69) * chore: allow testing plugin without running nox * chore: update comment * chore: Update .kokoro/generate-docs.sh Co-authored-by: Tyler Bui-Palsulich <26876514+tbpg@users.noreply.github.com> Co-authored-by: Tyler Bui-Palsulich <26876514+tbpg@users.noreply.github.com> --- packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh | 8 ++++++++ packages/gcp-sphinx-docfx-yaml/.trampolinerc | 1 + 2 files changed, 9 insertions(+) diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh b/packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh index 33ed001b58f8..5605f7780973 100755 --- a/packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh @@ -30,6 +30,8 @@ gcloud auth activate-service-account --key-file ${GOOGLE_APPLICATION_CREDENTIALS # Install dependencies. python3 -m pip install --user --quiet --upgrade nox python3 -m pip install --user gcp-docuploader +python3 -m pip install -e . +python3 -m pip install recommonmark # Retrieve unique repositories to regenerate the YAML with. for bucket_item in $(gsutil ls 'gs://docs-staging-v2/docfx-python*' | sort -u -t- -k5,5); do @@ -93,6 +95,12 @@ for bucket_item in $(gsutil ls 'gs://docs-staging-v2/docfx-python*' | sort -u -t ## upload docs # python3 -m docuploader upload docs/_build/html --metadata-file docs.metadata --staging-bucket "${STAGING_BUCKET}" + # Test running with the plugin version locally. + if [[ "${TEST_PLUGIN}" == "true" ]]; then + python3 -m pip install -e . + sphinx-build -T -N -D extensions=sphinx.ext.autodoc,sphinx.ext.autosummary,docfx_yaml.extension,sphinx.ext.intersphinx,sphinx.ext.coverage,sphinx.ext.napoleon,sphinx.ext.todo,sphinx.ext.viewcode,recommonmark -b html -d docs/_build/doctrees/ docs/ docs/_build/html/ + continue + fi # Build YAML tarballs for Cloud-RAD. nox -s docfx diff --git a/packages/gcp-sphinx-docfx-yaml/.trampolinerc b/packages/gcp-sphinx-docfx-yaml/.trampolinerc index 521eae5d06df..f1c34bb43ca6 100644 --- a/packages/gcp-sphinx-docfx-yaml/.trampolinerc +++ b/packages/gcp-sphinx-docfx-yaml/.trampolinerc @@ -26,6 +26,7 @@ pass_down_envvars+=( "V2_STAGING_BUCKET" "NOX_SESSION" "FORCE_GENERATE_ALL_TAGS" # Regenerates YAML for all versions if set to true. + "TEST_PLUGIN" # Test current plugin version without updating the docs. ) # Prevent unintentional override on the default image. From 8628628fe7dd1d2987992961d58d941b3a865324 Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Wed, 21 Jul 2021 15:35:37 -0400 Subject: [PATCH 046/279] feat: add short snippet for missing summary (#73) * feat: add short snippet for missing summary * feat: add summary for index pages --- packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index 5557f1142d40..9f69c67d10f7 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -586,6 +586,10 @@ def _update_friendly_package_name(path): top_summary = _extract_docstring_info(summary_info, summary, name) datam['summary'] = top_summary + # If there is no summary, add a short snippet. + else: + datam['summary'] = "API documentation for {} {}.".format(name, _type) + if args or sig or summary_info: datam['syntax'] = {} @@ -1126,7 +1130,7 @@ def convert_module_to_package_if_needed(obj): 'langs': ['python'], 'type': 'package', 'kind': 'distribution', - 'summary': '', + 'summary': 'Reference API documentation for `{}`.'.format(app.config.project), 'children': index_children }], 'references': index_references From 9381b45c81c443dfa06591d93f9b0271a341befd Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Wed, 21 Jul 2021 15:44:34 -0400 Subject: [PATCH 047/279] fix: disambiguate all entry names to clarify duplicate names (#72) * feat: deduplicate all entry names in yaml_data * test: update unittest for disambiguate_toc_name --- .../docfx_yaml/extension.py | 82 ++++++++++++------- .../gcp-sphinx-docfx-yaml/tests/test_unit.py | 17 +++- 2 files changed, 67 insertions(+), 32 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index 9f69c67d10f7..78f7e4c55570 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -813,8 +813,12 @@ def find_unique_name(package_name, entries): return [package_name[-1]] # Used to disambiguate names that have same entries. +# Returns a dictionary of names that are disambiguated in the form of: +# {uidname: disambiguated_name} def disambiguate_toc_name(toc_yaml): name_entries = {} + disambiguated_names = {} + for module in toc_yaml: module_name = module['name'] if module_name not in name_entries: @@ -833,13 +837,17 @@ def disambiguate_toc_name(toc_yaml): name_entries[module_name][module_name] = 1 if 'items' in module: - disambiguate_toc_name(module['items']) + # Update the dictionary of dismabiguated names + disambiguated_names.update(disambiguate_toc_name(module['items'])) for module in toc_yaml: module_name = module['name'] # Check if there are multiple entires of module['name'], disambiguate if needed. if name_entries[module_name][module_name] > 1: module['name'] = ".".join(find_unique_name(module['uidname'].split("."), name_entries[module_name])) + disambiguated_names[module['uidname']] = module['name'] + + return disambiguated_names def build_finished(app, exception): """ @@ -891,6 +899,9 @@ def convert_module_to_package_if_needed(obj): # caused by Windows case insensitive file system file_name_set = set() + # Used to disambiguate entry names + yaml_map = {} + # Order matters here, we need modules before lower level classes, # so that we can make sure to inject the TOC properly for data_set in (app.env.docfx_yaml_modules, @@ -1020,33 +1031,7 @@ def convert_module_to_package_if_needed(obj): obj['source']['remote']['repo'] == 'https://apidrop.visualstudio.com/Content%20CI/_git/ReferenceAutomation'): del(obj['source']) - # Output file - if uid.lower() in file_name_set: - filename = uid + "(%s)" % app.env.docfx_info_uid_types[uid] - else: - filename = uid - - out_file = os.path.join(normalized_outdir, '%s.yml' % filename) - ensuredir(os.path.dirname(out_file)) - if app.verbosity >= 1: - app.info(bold('[docfx_yaml] ') + darkgreen('Outputting %s' % filename)) - - with open(out_file, 'w') as out_file_obj: - out_file_obj.write('### YamlMime:UniversalReference\n') - try: - dump( - { - 'items': yaml_data, - 'references': references, - 'api_name': [], # Hack around docfx YAML - }, - out_file_obj, - default_flow_style=False - ) - except Exception as e: - raise ValueError("Unable to dump object\n{0}".format(yaml_data)) from e - - file_name_set.add(filename) + yaml_map[uid] = [yaml_data, references] # Parse the name of the object. # Some types will need additional parsing to de-duplicate their names and contain @@ -1088,7 +1073,7 @@ def convert_module_to_package_if_needed(obj): raise RuntimeError("No documentation for this module.") # Perform additional disambiguation of the name - disambiguate_toc_name(toc_yaml) + disambiguated_names = disambiguate_toc_name(toc_yaml) # Keeping uidname field carrys over onto the toc.yaml files, we need to # be keep using them but don't need them in the actual file @@ -1139,6 +1124,45 @@ def convert_module_to_package_if_needed(obj): default_flow_style=False ) + # Output files + for uid, data in iter(yaml_map.items()): + + for yaml_item in data: + for obj in yaml_item: + # If the entry was disambiguated, update here: + obj_full_name = obj['fullName'] + if disambiguated_names.get(obj_full_name): + obj['name'] = disambiguated_names[obj_full_name] + + # data is formatted as [yaml_data, references] + yaml_data, references = data + + if uid.lower() in file_name_set: + filename = uid + "(%s)" % app.env.docfx_info_uid_types[uid] + else: + filename = uid + + out_file = os.path.join(normalized_outdir, '%s.yml' % filename) + ensuredir(os.path.dirname(out_file)) + if app.verbosity >= 1: + app.info(bold('[docfx_yaml] ') + darkgreen('Outputting %s' % filename)) + + with open(out_file, 'w') as out_file_obj: + out_file_obj.write('### YamlMime:UniversalReference\n') + try: + dump( + { + 'items': yaml_data, + 'references': references, + 'api_name': [], # Hack around docfx YAML + }, + out_file_obj, + default_flow_style=False + ) + except Exception as e: + raise ValueError("Unable to dump object\n{0}".format(yaml_data)) from e + + file_name_set.add(filename) def missing_reference(app, env, node, contnode): reftarget = '' diff --git a/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py b/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py index a5ea20c446e3..8ff10c94368f 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py +++ b/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py @@ -38,30 +38,41 @@ def test_disambiguate_toc_name(self): want_file = open('tests/yaml_post.yaml', 'r') yaml_want = load(want_file, Loader=Loader) + disambiguated_names_want = { + 'google.cloud.spanner_admin_database_v1.types': 'spanner_admin_database_v1.types', + 'google.cloud.spanner_admin_instance_v1.types': 'spanner_admin_instance_v1.types', + 'google.cloud.spanner_v1.types': 'spanner_v1.types' + } test_file = open('tests/yaml_pre.yaml', 'r') yaml_got = load(test_file, Loader=Loader) - disambiguate_toc_name(yaml_got) + disambiguated_names_got = disambiguate_toc_name(yaml_got) want_file.close() test_file.close() self.assertEqual(yaml_want, yaml_got) + self.assertEqual(disambiguated_names_want, disambiguated_names_got) def test_disambiguate_toc_name_duplicate(self): want_file = open('tests/yaml_post_duplicate.yaml', 'r') yaml_want = load(want_file, Loader=Loader) - + disambiguated_names_want = { + 'google.api_core.client_info': 'client_info', + 'google.api_core.gapic_v1.client_info': 'gapic_v1.client_info' + } + test_file = open('tests/yaml_pre_duplicate.yaml', 'r') yaml_got = load(test_file, Loader=Loader) - disambiguate_toc_name(yaml_got) + disambiguated_names_got = disambiguate_toc_name(yaml_got) want_file.close() test_file.close() self.assertEqual(yaml_want, yaml_got) + self.assertEqual(disambiguated_names_want, disambiguated_names_got) def test_reference_in_summary(self): From d47f78d54a5d98a32b6e2f06a9685427a7970220 Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Wed, 21 Jul 2021 15:47:34 -0400 Subject: [PATCH 048/279] chore: fix test-plugin for generate-docs job (#70) --- packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh b/packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh index 5605f7780973..49bad68f8418 100755 --- a/packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh @@ -32,6 +32,8 @@ python3 -m pip install --user --quiet --upgrade nox python3 -m pip install --user gcp-docuploader python3 -m pip install -e . python3 -m pip install recommonmark +# Required for some client libraries: +python3 -m pip install --user django==2.2 # Retrieve unique repositories to regenerate the YAML with. for bucket_item in $(gsutil ls 'gs://docs-staging-v2/docfx-python*' | sort -u -t- -k5,5); do @@ -97,7 +99,8 @@ for bucket_item in $(gsutil ls 'gs://docs-staging-v2/docfx-python*' | sort -u -t # Test running with the plugin version locally. if [[ "${TEST_PLUGIN}" == "true" ]]; then - python3 -m pip install -e . + # --no-use-pep517 is required for django-spanner install issue: see https://github.com/pypa/pip/issues/7953 + python3 -m pip install --user --no-use-pep517 -e . sphinx-build -T -N -D extensions=sphinx.ext.autodoc,sphinx.ext.autosummary,docfx_yaml.extension,sphinx.ext.intersphinx,sphinx.ext.coverage,sphinx.ext.napoleon,sphinx.ext.todo,sphinx.ext.viewcode,recommonmark -b html -d docs/_build/doctrees/ docs/ docs/_build/html/ continue fi From 84514c6773261e88aed675af2e0d1197d16cf5dc Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Wed, 21 Jul 2021 23:41:21 +0200 Subject: [PATCH 049/279] chore(deps): update dependency sphinx to v4.1.1 (#67) Co-authored-by: Dan Lee <71398022+dandhlee@users.noreply.github.com> --- packages/gcp-sphinx-docfx-yaml/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/requirements.txt b/packages/gcp-sphinx-docfx-yaml/requirements.txt index a8bc2f792b82..03f3696511d9 100644 --- a/packages/gcp-sphinx-docfx-yaml/requirements.txt +++ b/packages/gcp-sphinx-docfx-yaml/requirements.txt @@ -1,5 +1,5 @@ # google-resumable-media-python requires manual update as this repo isn't templated. # python-api-core also requires manual update as it is not templated. -sphinx==4.0.3 +sphinx==4.1.1 -e . tox From c93e57555ba69a662fa3392a842b715d4a8d81f3 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Wed, 21 Jul 2021 20:47:54 -0400 Subject: [PATCH 050/279] chore: release 0.4.0 (#74) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> Co-authored-by: Dan Lee <71398022+dandhlee@users.noreply.github.com> --- packages/gcp-sphinx-docfx-yaml/CHANGELOG.md | 12 ++++++++++++ packages/gcp-sphinx-docfx-yaml/setup.py | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md index c29fdeefb36a..ac6356ebf04a 100644 --- a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md +++ b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog +## [0.4.0](https://www.github.com/googleapis/sphinx-docfx-yaml/compare/v0.3.4...v0.4.0) (2021-07-21) + + +### Features + +* add short snippet for missing summary ([#73](https://www.github.com/googleapis/sphinx-docfx-yaml/issues/73)) ([bb432e7](https://www.github.com/googleapis/sphinx-docfx-yaml/commit/bb432e7ef0e1df6b4315306ddb3b8a82eebb375f)) + + +### Bug Fixes + +* disambiguate all entry names to clarify duplicate names ([#72](https://www.github.com/googleapis/sphinx-docfx-yaml/issues/72)) ([b632eb7](https://www.github.com/googleapis/sphinx-docfx-yaml/commit/b632eb74fd3ce1dd16bc626b9a23ff79c2b6559f)) + ### [0.3.4](https://www.github.com/googleapis/sphinx-docfx-yaml/compare/v0.3.3...v0.3.4) (2021-07-05) diff --git a/packages/gcp-sphinx-docfx-yaml/setup.py b/packages/gcp-sphinx-docfx-yaml/setup.py index 378888209998..f3510da10149 100644 --- a/packages/gcp-sphinx-docfx-yaml/setup.py +++ b/packages/gcp-sphinx-docfx-yaml/setup.py @@ -17,7 +17,7 @@ name = 'gcp-sphinx-docfx-yaml' description = 'Sphinx Python Domain to DocFX YAML Generator' -version = '0.3.4' +version = '0.4.0' dependencies = [ 'PyYAML', 'sphinx', From 29c29c5442b7a11571eadd1a4dcee38acc778595 Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Mon, 26 Jul 2021 13:49:54 -0400 Subject: [PATCH 051/279] feat: add subPackage types for better classification (#76) * feat: add subPackage types * fix: update type in summary and use markdown to highlight names * fix: use short and disambiguated names * nit: update to f string for single-line string --- packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index 78f7e4c55570..894ea36daccf 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -588,7 +588,7 @@ def _update_friendly_package_name(path): # If there is no summary, add a short snippet. else: - datam['summary'] = "API documentation for {} {}.".format(name, _type) + datam['summary'] = f"API documentation for `{short_name}` {_type}." if args or sig or summary_info: datam['syntax'] = {} @@ -876,7 +876,7 @@ def find_node_in_toc_tree(toc_yaml, to_add_node): def convert_module_to_package_if_needed(obj): if 'source' in obj and 'path' in obj['source'] and obj['source']['path']: if obj['source']['path'].endswith(INITPY): - obj['type'] = 'package' + obj['type'] = 'subPackage' return for child_uid in obj['children']: @@ -1133,6 +1133,8 @@ def convert_module_to_package_if_needed(obj): obj_full_name = obj['fullName'] if disambiguated_names.get(obj_full_name): obj['name'] = disambiguated_names[obj_full_name] + if obj['type'] == 'subPackage': + obj['summary'] = "API documentation for `{}` package.".format(obj['name']) # data is formatted as [yaml_data, references] yaml_data, references = data From cf1a97dfc6f4f103c5ec3433507fe7b074fd429d Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Mon, 26 Jul 2021 14:25:28 -0400 Subject: [PATCH 052/279] feat: add subclasses to children and reference (#77) * feat: add subclasses to children and reference * chore: lint * nit: update comment to clarify confusion --- .../gcp-sphinx-docfx-yaml/docfx_yaml/extension.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index 894ea36daccf..11a780605978 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -776,13 +776,22 @@ def insert_children_on_class(app, _type, datam): return insert_class = app.env.docfx_yaml_classes[datam[CLASS]] + # Find the parent class using the module for subclasses of a class. + parent_class = app.env.docfx_yaml_classes.get(datam[MODULE]) + if parent_class: + insert_class += parent_class # Find the class which the datam belongs to for obj in insert_class: if obj['type'] != CLASS: continue - # Add methods & attributes & properties to class - if _type in [METHOD, ATTRIBUTE, PROPERTY] and \ - obj[CLASS] == datam[CLASS]: + # Add subclass & methods & attributes & properties to class + if _type in [METHOD, ATTRIBUTE, PROPERTY, CLASS] and \ + ( + # If obj is either method, attr or prop of a class and not self, or + (obj[CLASS] == datam[CLASS] and obj != datam) or \ + # If datam is a subclass of another class. + (_type == CLASS and obj['class'] == datam['module']) + ): obj['children'].append(datam['uid']) obj['references'].append(_create_reference(datam, parent=obj['uid'])) insert_class.append(datam) From 0cba98b630cb6554accefe28bc124b0e6de9c6b0 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Wed, 28 Jul 2021 06:12:46 +0200 Subject: [PATCH 053/279] chore(deps): update dependency sphinx to v4.1.2 (#79) Co-authored-by: Dan Lee <71398022+dandhlee@users.noreply.github.com> --- packages/gcp-sphinx-docfx-yaml/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/requirements.txt b/packages/gcp-sphinx-docfx-yaml/requirements.txt index 03f3696511d9..25607b8a37a7 100644 --- a/packages/gcp-sphinx-docfx-yaml/requirements.txt +++ b/packages/gcp-sphinx-docfx-yaml/requirements.txt @@ -1,5 +1,5 @@ # google-resumable-media-python requires manual update as this repo isn't templated. # python-api-core also requires manual update as it is not templated. -sphinx==4.1.1 +sphinx==4.1.2 -e . tox From 1121b2e4385099bf894bc1e98330d389e4f0fe53 Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Wed, 28 Jul 2021 16:05:11 -0400 Subject: [PATCH 054/279] feat: process xrefs properly (#78) * accept change from upstream * feat: add full support for xrefs * test: update test case * fix: expand xref format for proper processing * test: update unit test * fix: handle xrefs for other products in the future --- .../docfx_yaml/extension.py | 97 ++++++++++++------- .../gcp-sphinx-docfx-yaml/tests/test_unit.py | 23 +++-- 2 files changed, 73 insertions(+), 47 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index 11a780605978..571daf388d43 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -102,6 +102,8 @@ def build_init(app): # This stores uidnames of docstrings already parsed app.env.docfx_uid_names = {} + app.env.docfx_xrefs = {} + remote = getoutput('git remote -v') try: @@ -190,7 +192,7 @@ def _refact_example_in_module_summary(lines): def _resolve_reference_in_module_summary(pattern, lines): - new_lines = [] + new_lines, xrefs = [], [] for line in lines: matched_objs = list(re.finditer(pattern, line)) new_line = line @@ -207,16 +209,35 @@ def _resolve_reference_in_module_summary(pattern, lines): # match string like ':func:`~***`' or ':func:`***`' index = matched_str.index('~') if '~' in matched_str else matched_str.index('`') ref_name = matched_str[index+1:-1] + + index = ref_name.rfind('.') + 1 + # Find the last component of the target. "~Queue.get" only returns + ref_name = ref_name[index:] + else: index = matched_str.rfind('.') + 1 if index == 0: # If there is no dot, push index to not include tilde index = 1 - # Find the last component of the target. "~Queue.get" only returns ref_name = matched_str[index:] - new_line = new_line.replace(matched_str, ''.format(ref_name)) + + # Find the uid to add for xref + index = matched_str.find("google.cloud") + if index > -1: + xref = matched_str[index:] + while not xref[-1].isalnum(): + xref = xref[:-1] + xrefs.append(xref) + + # Check to see if we should create an xref for it. + if 'google.cloud' in matched_str: + new_line = new_line.replace(matched_str, '{}'.format(xref, ref_name)) + # If it not a Cloud library, don't create xref for it. + else: + new_line = new_line.replace(matched_str, '`{}`'.format(ref_name)) + new_lines.append(new_line) - return new_lines + return new_lines, xrefs def enumerate_extract_signature(doc, max_args=20): @@ -286,6 +307,8 @@ def _extract_signature(obj_sig): # Given documentation docstring, parse them into summary_info. def _extract_docstring_info(summary_info, summary, name): top_summary = "" + # Return clean summary if returning early. + parsed_text = summary # Initialize known types needing further processing. var_types = { @@ -300,56 +323,38 @@ def _extract_docstring_info(summary_info, summary, name): initial_index = -1 # Prevent GoogleDocstring crashing on custom types and parse all xrefs to normal - if '~' in summary or '" - while '~' in summary_part or "" + while ":" - elif "'))+1] + original_type = parsed_text[initial_index:initial_index+(parsed_text[initial_index:].find('>'))+1] initial_index += len(original_type) original_type = " ".join(filter(None, re.split(r'\n| |\|\s|\t', original_type))) - safe_type = original_type[6:-1] + safe_type = 'xref_' + original_type[6:-1] else: raise ValueError("Encountered unexpected type in Exception docstring.") type_pairs.append([original_type, safe_type]) - summary_part = summary[initial_index:] + summary_part = parsed_text[initial_index:] # Replace all the found occurrences for pairs in type_pairs: original_type, safe_type = pairs[0], pairs[1] - summary = summary.replace(original_type, safe_type) + parsed_text = parsed_text.replace(original_type, safe_type) # Clean the string by cleaning newlines and backlashes, then split by white space. config = Config(napoleon_use_param=True, napoleon_use_rtype=True) # Convert Google style to reStructuredText - parsed_text = str(GoogleDocstring(summary, config)) + parsed_text = str(GoogleDocstring(parsed_text, config)) - # Revert back to original type - if initial_index > -1: - for pairs in type_pairs: - original_type, safe_type = pairs[0], pairs[1] - parsed_text = parsed_text.replace(safe_type, original_type) - # Trim the top summary but maintain its formatting. indexes = [] for types in var_types: @@ -378,6 +383,12 @@ def _extract_docstring_info(summary_info, summary, name): top_summary = parsed_text[:index] parsed_text = parsed_text[index:] + # Revert back to original type + if initial_index > -1: + for pairs in type_pairs: + original_type, safe_type = pairs[0], pairs[1] + parsed_text = parsed_text.replace(safe_type, original_type) + # Clean up whitespace and other characters parsed_text = " ".join(filter(None, re.split(r'\|\s', parsed_text))).split() @@ -576,9 +587,17 @@ def _update_friendly_package_name(path): if lines != []: # Resolve references for xrefs in two different formats. # REF_PATTERN checks for patterns like ":class:`~google.package.module`" - lines = _resolve_reference_in_module_summary(REF_PATTERN, lines) + lines, xrefs = _resolve_reference_in_module_summary(REF_PATTERN, lines) + for xref in xrefs: + if xref not in app.env.docfx_xrefs: + app.env.docfx_xrefs[xref] = '' + # REF_PATTERN_LAST checks for patterns like "~package.module" - lines = _resolve_reference_in_module_summary(REF_PATTERN_LAST, lines) + lines, xrefs = _resolve_reference_in_module_summary(REF_PATTERN_LAST, lines) + for xref in xrefs: + if xref not in app.env.docfx_xrefs: + app.env.docfx_xrefs[xref] = '' + summary = app.docfx_transform_string('\n'.join(_refact_example_in_module_summary(lines))) # Extract summary info into respective sections. @@ -1175,6 +1194,14 @@ def convert_module_to_package_if_needed(obj): file_name_set.add(filename) + ''' + # TODO: handle xref for other products. + xref_file = os.path.join(normalized_outdir, 'xrefs.yml') + with open(xref_file, 'w') as xref_file_obj: + for xref in app.env.docfx_xrefs: + xref_file_obj.write(f'{xref}\n') + ''' + def missing_reference(app, env, node, contnode): reftarget = '' refdoc = '' diff --git a/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py b/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py index 8ff10c94368f..42355d0d528b 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py +++ b/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py @@ -81,7 +81,7 @@ def test_reference_in_summary(self): resource will be written to the stream. Args: - transport (~requests.Session): A ``requests`` object which can + transport (~google.cloud.requests.Session): A ``requests`` object which can make authenticated requests. timeout (Optional[Union[float, Tuple[float, float]]]): @@ -90,29 +90,28 @@ def test_reference_in_summary(self): several times using the same timeout each time. Can also be passed as a tuple (connect_timeout, read_timeout). - See :meth:`requests.Session.request` documentation for details. + See :meth:`google.cloud.requests.Session.request` documentation for details. Returns: - ~requests.Response: The HTTP response returned by ``transport``. + ~google.cloud.requests.Response: The HTTP response returned by ``transport``. Raises: - ~google.resumable_media.common.DataCorruption: If the download's + ~google.cloud.resumable_media.common.DataCorruption: If the download's checksum doesn't agree with server-computed checksum. ValueError: If the current :class:`Download` has already finished. """ lines_got = lines_got.split("\n") - # Resolve over different regular expressions for different types of reference patterns. - lines_got = _resolve_reference_in_module_summary(REF_PATTERN, lines_got) - lines_got = _resolve_reference_in_module_summary(REF_PATTERN_LAST, lines_got) + lines_got, xrefs = _resolve_reference_in_module_summary(REF_PATTERN, lines_got) + lines_got, xrefs = _resolve_reference_in_module_summary(REF_PATTERN_LAST, lines_got) lines_want = """ If a ``stream`` is attached to this download, then the downloaded resource will be written to the stream. Args: - transport (): A ``requests`` object which can + transport (Session): A ``requests`` object which can make authenticated requests. timeout (Optional[Union[float, Tuple[float, float]]]): @@ -121,15 +120,15 @@ def test_reference_in_summary(self): several times using the same timeout each time. Can also be passed as a tuple (connect_timeout, read_timeout). - See documentation for details. + See request documentation for details. Returns: - : The HTTP response returned by ``transport``. + Response: The HTTP response returned by ``transport``. Raises: - : If the download's + DataCorruption: If the download's checksum doesn't agree with server-computed checksum. - ValueError: If the current has already + ValueError: If the current `Download` has already finished. """ lines_want = lines_want.split("\n") From 29da5cf421c0ca276dfc33f54459ce4361c0ec36 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Wed, 28 Jul 2021 16:06:47 -0400 Subject: [PATCH 055/279] chore: release 0.5.0 (#81) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/gcp-sphinx-docfx-yaml/CHANGELOG.md | 9 +++++++++ packages/gcp-sphinx-docfx-yaml/setup.py | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md index ac6356ebf04a..308f3b3d5872 100644 --- a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md +++ b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## [0.5.0](https://www.github.com/googleapis/sphinx-docfx-yaml/compare/v0.4.0...v0.5.0) (2021-07-28) + + +### Features + +* add subclasses to children and reference ([#77](https://www.github.com/googleapis/sphinx-docfx-yaml/issues/77)) ([0cab5f6](https://www.github.com/googleapis/sphinx-docfx-yaml/commit/0cab5f6cd6cd9b1da2f5f63cbcabeea69e0d7c81)) +* add subPackage types for better classification ([#76](https://www.github.com/googleapis/sphinx-docfx-yaml/issues/76)) ([3c84f3e](https://www.github.com/googleapis/sphinx-docfx-yaml/commit/3c84f3ea05677e2e8a5a6659a14f281f537ae37a)) +* process xrefs properly ([#78](https://www.github.com/googleapis/sphinx-docfx-yaml/issues/78)) ([fcc1989](https://www.github.com/googleapis/sphinx-docfx-yaml/commit/fcc1989a114640fd21955d35ef3eabce2d043fc9)) + ## [0.4.0](https://www.github.com/googleapis/sphinx-docfx-yaml/compare/v0.3.4...v0.4.0) (2021-07-21) diff --git a/packages/gcp-sphinx-docfx-yaml/setup.py b/packages/gcp-sphinx-docfx-yaml/setup.py index f3510da10149..050aeef7d9ad 100644 --- a/packages/gcp-sphinx-docfx-yaml/setup.py +++ b/packages/gcp-sphinx-docfx-yaml/setup.py @@ -17,7 +17,7 @@ name = 'gcp-sphinx-docfx-yaml' description = 'Sphinx Python Domain to DocFX YAML Generator' -version = '0.4.0' +version = '0.5.0' dependencies = [ 'PyYAML', 'sphinx', From fc09f80315f027498b7861132f1b326edc708384 Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Thu, 29 Jul 2021 10:07:19 -0400 Subject: [PATCH 056/279] fix: remove redundant class info for subclasses (#87) --- .../docfx_yaml/extension.py | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index 571daf388d43..88eb939d3b41 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -797,24 +797,29 @@ def insert_children_on_class(app, _type, datam): insert_class = app.env.docfx_yaml_classes[datam[CLASS]] # Find the parent class using the module for subclasses of a class. parent_class = app.env.docfx_yaml_classes.get(datam[MODULE]) - if parent_class: - insert_class += parent_class + # Find the class which the datam belongs to for obj in insert_class: if obj['type'] != CLASS: continue # Add subclass & methods & attributes & properties to class if _type in [METHOD, ATTRIBUTE, PROPERTY, CLASS] and \ - ( - # If obj is either method, attr or prop of a class and not self, or - (obj[CLASS] == datam[CLASS] and obj != datam) or \ - # If datam is a subclass of another class. - (_type == CLASS and obj['class'] == datam['module']) - ): + (obj[CLASS] == datam[CLASS] and obj != datam): obj['children'].append(datam['uid']) obj['references'].append(_create_reference(datam, parent=obj['uid'])) insert_class.append(datam) + # If there is a parent class, determine if current class is a subclass. + if not parent_class: + return + for obj in parent_class: + if obj['type'] != CLASS: + continue + if _type == CLASS and obj['class'] == datam['module']: + # No need to add datam to the parent class. + obj['children'].append(datam['uid']) + obj['references'].append(_create_reference(datam, parent=obj['uid'])) + def insert_children_on_function(app, _type, datam): """ From 93e7524ea2831980272aca06f435b694b419ab83 Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Thu, 29 Jul 2021 10:17:25 -0400 Subject: [PATCH 057/279] fix: handle more xrefs and keep long uid (#85) * fix: allow bracketed xref to work * test: update unit test * test: update to include xref checking in unit test --- .../docfx_yaml/extension.py | 10 ++- .../gcp-sphinx-docfx-yaml/tests/test_unit.py | 71 +++++++++++++++++++ 2 files changed, 79 insertions(+), 2 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index 88eb939d3b41..d0e8316ced09 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -73,9 +73,9 @@ class Bcolors: REFFUNCTION = 'func' INITPY = '__init__.py' # Regex expression for checking references of pattern like ":class:`~package_v1.module`" -REF_PATTERN = ':(py:)?(func|class|meth|mod|ref|attr|exc):`~?[a-zA-Z0-9_\.<> ]*?`' +REF_PATTERN = ':(py:)?(func|class|meth|mod|ref|attr|exc):`~?[a-zA-Z0-9_\.<> ]*(\(\))?`' # Regex expression for checking references of pattern like "~package_v1.subpackage.module" -REF_PATTERN_LAST = '~(([a-zA-Z0-9_<>]*\.)*[a-zA-Z0-9_<>]*)' +REF_PATTERN_LAST = '~([a-zA-Z0-9_<>]*\.)*[a-zA-Z0-9_<>]*(\(\))?' PROPERTY = 'property' @@ -234,6 +234,12 @@ def _resolve_reference_in_module_summary(pattern, lines): new_line = new_line.replace(matched_str, '{}'.format(xref, ref_name)) # If it not a Cloud library, don't create xref for it. else: + # Carefully extract the original uid + if pattern == REF_PATTERN: + index = matched_str.index('~') if '~' in matched_str else matched_str.index('`') + ref_name = matched_str[index+1:-1] + else: + ref_name = matched_str[1:] new_line = new_line.replace(matched_str, '`{}`'.format(ref_name)) new_lines.append(new_line) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py b/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py index 42355d0d528b..1353f56fff68 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py +++ b/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py @@ -102,9 +102,14 @@ def test_reference_in_summary(self): finished. """ lines_got = lines_got.split("\n") + xrefs_got = [] # Resolve over different regular expressions for different types of reference patterns. lines_got, xrefs = _resolve_reference_in_module_summary(REF_PATTERN, lines_got) + for xref in xrefs: + xrefs_got.append(xref) lines_got, xrefs = _resolve_reference_in_module_summary(REF_PATTERN_LAST, lines_got) + for xref in xrefs: + xrefs_got.append(xref) lines_want = """ If a ``stream`` is attached to this download, then the downloaded @@ -132,8 +137,74 @@ def test_reference_in_summary(self): finished. """ lines_want = lines_want.split("\n") + xrefs_want = [ + "google.cloud.requests.Session", + "google.cloud.requests.Session.request", + "google.cloud.requests.Response", + "google.cloud.resumable_media.common.DataCorruption" + ] + + self.assertEqual(lines_got, lines_want) + self.assertCountEqual(xrefs_got, xrefs_want) + # assertCountEqual is a misleading name but checks that two lists contain + # same items regardless of order, as long as items in list are sortable. + + + # Test for added xref coverage and third party xrefs staying as-is + def test_reference_in_summary_more_xrefs(self): + lines_got = """ +If a ~dateutil.time.stream() is attached to this download, then the downloaded +resource will be written to the stream. + +Args: + transport (~google.cloud.requests.Session()): A ``requests`` object which can + make authenticated requests. + + timeout (Optional[Union[float, Tuple[float, float]]]): + The number of seconds to wait for the server response. + Depending on the retry strategy, a request may be repeated + several times using the same timeout each time. + + Can also be passed as a :func:`~google.cloud.requests.tuple()` (connect_timeout, read_timeout). + See :meth:`google.cloud.requests.Session.request()` documentation for details. +""" + lines_got = lines_got.split("\n") + xrefs_got = [] + # Resolve over different regular expressions for different types of reference patterns. + lines_got, xrefs = _resolve_reference_in_module_summary(REF_PATTERN, lines_got) + for xref in xrefs: + xrefs_got.append(xref) + lines_got, xrefs = _resolve_reference_in_module_summary(REF_PATTERN_LAST, lines_got) + for xref in xrefs: + xrefs_got.append(xref) + + lines_want = """ +If a `dateutil.time.stream()` is attached to this download, then the downloaded +resource will be written to the stream. + +Args: + transport (Session()): A ``requests`` object which can + make authenticated requests. + + timeout (Optional[Union[float, Tuple[float, float]]]): + The number of seconds to wait for the server response. + Depending on the retry strategy, a request may be repeated + several times using the same timeout each time. + + Can also be passed as a tuple() (connect_timeout, read_timeout). + See request() documentation for details. +""" + lines_want = lines_want.split("\n") + xrefs_want = [ + "google.cloud.requests.Session", + "google.cloud.requests.tuple", + "google.cloud.requests.Session.request" + ] self.assertEqual(lines_got, lines_want) + self.assertCountEqual(xrefs_got, xrefs_want) + # assertCountEqual is a misleading name but checks that two lists contain + # same items regardless of order, as long as items in list are sortable. # Variables used for testing _extract_docstring_info From 1c3354746a2b9b6cf2d35c21161d4798dfbdc2d6 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Thu, 29 Jul 2021 10:20:50 -0400 Subject: [PATCH 058/279] chore: release 0.5.1 (#88) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/gcp-sphinx-docfx-yaml/CHANGELOG.md | 8 ++++++++ packages/gcp-sphinx-docfx-yaml/setup.py | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md index 308f3b3d5872..35eac7e4f157 100644 --- a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md +++ b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +### [0.5.1](https://www.github.com/googleapis/sphinx-docfx-yaml/compare/v0.5.0...v0.5.1) (2021-07-29) + + +### Bug Fixes + +* handle more xrefs and keep long uid ([#85](https://www.github.com/googleapis/sphinx-docfx-yaml/issues/85)) ([fd4f9f3](https://www.github.com/googleapis/sphinx-docfx-yaml/commit/fd4f9f373fcf6429d0faa76846d2d50673809a59)) +* remove redundant class info for subclasses ([#87](https://www.github.com/googleapis/sphinx-docfx-yaml/issues/87)) ([06bb556](https://www.github.com/googleapis/sphinx-docfx-yaml/commit/06bb556a4c2371ef05e9749c6f68b9eeb18315a6)) + ## [0.5.0](https://www.github.com/googleapis/sphinx-docfx-yaml/compare/v0.4.0...v0.5.0) (2021-07-28) diff --git a/packages/gcp-sphinx-docfx-yaml/setup.py b/packages/gcp-sphinx-docfx-yaml/setup.py index 050aeef7d9ad..fbe0340df9fd 100644 --- a/packages/gcp-sphinx-docfx-yaml/setup.py +++ b/packages/gcp-sphinx-docfx-yaml/setup.py @@ -17,7 +17,7 @@ name = 'gcp-sphinx-docfx-yaml' description = 'Sphinx Python Domain to DocFX YAML Generator' -version = '0.5.0' +version = '0.5.1' dependencies = [ 'PyYAML', 'sphinx', From eabdc1b8fab313eb2fa50a8f98fa6d065cca10a3 Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Fri, 30 Jul 2021 11:41:40 -0400 Subject: [PATCH 059/279] fix: parse xrefs differently with new xref format (#90) * fix: parse xrefs differently with new xref format * fix: update Docstring parser * test: update unit test * fix: move error catching to another block * test: update unittest to include error scenarios * fix: clean up messy formatting --- .../docfx_yaml/extension.py | 49 ++++++++++++++----- .../gcp-sphinx-docfx-yaml/tests/test_unit.py | 25 +++++++--- 2 files changed, 53 insertions(+), 21 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index d0e8316ced09..6b9b64965e01 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -327,24 +327,37 @@ def _extract_docstring_info(summary_info, summary, name): } initial_index = -1 + front_tag = '" - while "text" + while front_tag in summary_part: - # Expecting format of ":" - if "'))+1] + # Expecting format of "text" + if front_tag in summary_part: + # Retrieve the index for starting position of xref tag + initial_index += summary_part.find(front_tag) + + # Find the index of the end of xref tag, relative to the start of xref tag + end_tag_index = initial_index + parsed_text[initial_index:].find(end_tag) + end_len + + # Retrieve the entire xref tag + original_type = parsed_text[initial_index:end_tag_index] initial_index += len(original_type) original_type = " ".join(filter(None, re.split(r'\n| |\|\s|\t', original_type))) - safe_type = 'xref_' + original_type[6:-1] + + # Extract text from "text" + index = original_type.find(">") + safe_type = 'xref_' + original_type[index+1:index+(original_type[index:].find("<"))] else: raise ValueError("Encountered unexpected type in Exception docstring.") @@ -451,10 +464,20 @@ def _extract_docstring_info(summary_info, summary, name): cur_type = word if cur_type in [':type', ':param', ':raises', ':raises:']: index += 1 - arg_name = parsed_text[index][:-1] - # Initialize empty dictionary if it doesn't exist already - if arg_name not in summary_info[var_types[cur_type]] and ':raises' not in cur_type: - summary_info[var_types[cur_type]][arg_name] = {} + # Exception that's not xref should be treated same as other names + if ':raises' not in cur_type or 'xref' not in parsed_text[index]: + arg_name = parsed_text[index][:-1] + # xrefs are treated by taking its second half and combining the two + elif ':raises' in cur_type and 'xref' in parsed_text[index]: + arg_name = f'{parsed_text[index]} {parsed_text[index+1][:-1]}' + index += 1 + + try: + # Initialize empty dictionary if it doesn't exist already + if arg_name not in summary_info[var_types[cur_type]] and ':raises' not in cur_type: + summary_info[var_types[cur_type]][arg_name] = {} + except KeyError: + raise KeyError(f"Encountered wrong formatting, please check docstring for {name}") # Empty target string words = [] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py b/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py index 1353f56fff68..7d11bdde1f2f 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py +++ b/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py @@ -335,13 +335,22 @@ def test_extract_docstring_info_check_error(self): with self.assertRaises(ValueError): _extract_docstring_info({}, summary4, "error string") + summary5 = """ +Description of malformed docstring. + +Raises: + Error that should fail: if condition `x`. +""" + with self.assertRaises(KeyError): + _extract_docstring_info({}, summary5, "malformed docstring") + def test_extract_docstring_info_with_xref(self): ## Test with xref included in the summary, ensure they're processed as-is summary_info_want = { 'variables': { 'arg1': { - 'var_type': '', + 'var_type': 'Type', 'description': 'simple description.' }, 'arg2': { @@ -351,13 +360,13 @@ def test_extract_docstring_info_with_xref(self): }, 'returns': [ { - 'var_type': '', + 'var_type': 'Pair', 'description': 'simple description for return value.' } ], 'exceptions': [ { - 'var_type': '', + 'var_type': 'SpannerException', 'description': 'if `condition x`.' } ] @@ -366,15 +375,15 @@ def test_extract_docstring_info_with_xref(self): summary = """ Simple test for docstring. -:type arg1: +:type arg1: Type :param arg1: simple description. :param arg2: simple description for `arg2`. :type arg2: ~google.spanner_v1.type.dict -:rtype: +:rtype: Pair :returns: simple description for return value. -:raises : if `condition x`. +:raises SpannerException: if `condition x`. """ summary_info_got = { @@ -384,10 +393,10 @@ def test_extract_docstring_info_with_xref(self): } top_summary_got = _extract_docstring_info(summary_info_got, summary, "") - + self.maxDiff = None # Same as the top summary from previous example, compare with that self.assertEqual(top_summary_got, self.top_summary1_want) - self.assertEqual(summary_info_got, summary_info_want) + self.assertDictEqual(summary_info_got, summary_info_want) if __name__ == '__main__': unittest.main() From 57db01074e3afbd53be07a7fc426e1454be10897 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Fri, 30 Jul 2021 11:43:28 -0400 Subject: [PATCH 060/279] chore: release 0.5.2 (#91) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/gcp-sphinx-docfx-yaml/CHANGELOG.md | 7 +++++++ packages/gcp-sphinx-docfx-yaml/setup.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md index 35eac7e4f157..590147e01654 100644 --- a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md +++ b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +### [0.5.2](https://www.github.com/googleapis/sphinx-docfx-yaml/compare/v0.5.1...v0.5.2) (2021-07-30) + + +### Bug Fixes + +* parse xrefs differently with new xref format ([#90](https://www.github.com/googleapis/sphinx-docfx-yaml/issues/90)) ([22485e8](https://www.github.com/googleapis/sphinx-docfx-yaml/commit/22485e82b1e4c3be2f7589434d53c75b28921266)) + ### [0.5.1](https://www.github.com/googleapis/sphinx-docfx-yaml/compare/v0.5.0...v0.5.1) (2021-07-29) diff --git a/packages/gcp-sphinx-docfx-yaml/setup.py b/packages/gcp-sphinx-docfx-yaml/setup.py index fbe0340df9fd..fca8369f41fd 100644 --- a/packages/gcp-sphinx-docfx-yaml/setup.py +++ b/packages/gcp-sphinx-docfx-yaml/setup.py @@ -17,7 +17,7 @@ name = 'gcp-sphinx-docfx-yaml' description = 'Sphinx Python Domain to DocFX YAML Generator' -version = '0.5.1' +version = '0.5.2' dependencies = [ 'PyYAML', 'sphinx', From 38edef765807c5d924c83ce2e2849bb64381f855 Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Fri, 13 Aug 2021 11:18:40 -0400 Subject: [PATCH 061/279] chore: drop mention of Python 2.7 from templates (#94) Source-Link: https://github.com/googleapis/synthtool/commit/facee4cc1ea096cd8bcc008bb85929daa7c414c0 Post-Processor: gcr.io/repo-automation-bots/owlbot-python:latest@sha256:9743664022bd63a8084be67f144898314c7ca12f0a03e422ac17c733c129d803 Co-authored-by: Owl Bot --- packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml | 2 +- .../scripts/readme-gen/templates/install_deps.tmpl.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml index 9602d540595e..a9fcd07cc43b 100644 --- a/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml +++ b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml @@ -1,3 +1,3 @@ docker: image: gcr.io/repo-automation-bots/owlbot-python:latest - digest: sha256:b8c131c558606d3cea6e18f8e87befbd448c1482319b0db3c5d5388fa6ea72e3 + digest: sha256:9743664022bd63a8084be67f144898314c7ca12f0a03e422ac17c733c129d803 diff --git a/packages/gcp-sphinx-docfx-yaml/scripts/readme-gen/templates/install_deps.tmpl.rst b/packages/gcp-sphinx-docfx-yaml/scripts/readme-gen/templates/install_deps.tmpl.rst index a0406dba8c84..275d649890d7 100644 --- a/packages/gcp-sphinx-docfx-yaml/scripts/readme-gen/templates/install_deps.tmpl.rst +++ b/packages/gcp-sphinx-docfx-yaml/scripts/readme-gen/templates/install_deps.tmpl.rst @@ -12,7 +12,7 @@ Install Dependencies .. _Python Development Environment Setup Guide: https://cloud.google.com/python/setup -#. Create a virtualenv. Samples are compatible with Python 2.7 and 3.4+. +#. Create a virtualenv. Samples are compatible with Python 3.6+. .. code-block:: bash From e9b685462ff1cc4403f284d0661c359dea7cc8cb Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Fri, 13 Aug 2021 12:34:28 -0400 Subject: [PATCH 062/279] fix: recover lost function arguments and argument types (#93) * fix: recover lost arguments to functions * fix: add default argument types * fix: work for None type arguments * fix: omit variables without types * chore: update comment about default arguments * chore: fix to make comment more readable --- .../docfx_yaml/extension.py | 63 ++++++++++++++++--- 1 file changed, 55 insertions(+), 8 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index 6b9b64965e01..ec9aaa1ed398 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -517,22 +517,55 @@ def _update_friendly_package_name(path): try: if _type in [METHOD, FUNCTION]: argspec = inspect.getfullargspec(obj) # noqa + type_map = {} + if argspec.annotations: + for annotation in argspec.annotations: + if annotation == "return": + continue + # Extract names for simple types. + try: + type_map[annotation] = (argspec.annotations[annotation]).__name__ + # Try to extract names for more complicated types. + except AttributeError: + vartype = argspec.annotations[annotation] + try: + type_map[annotation] = str(vartype._name) + if vartype.__args__: + type_map[annotation] += str(vartype.__args__)[:-2] + ")" + except AttributeError: + print(f"Could not parse argument information for {annotation}.") + continue + for arg in argspec.args: + arg_map = {} # Ignore adding in entry for "self" if arg != 'cls': - args.append({'id': arg}) + arg_map['id'] = arg + if arg in type_map: + arg_map['var_type'] = type_map[arg] + args.append(arg_map) if argspec.varargs: args.append({'id': argspec.varargs}) if argspec.varkw: args.append({'id': argspec.varkw}) + # Try to add default values. Currently does not work if there is * argument present. if argspec.defaults: - for count, default in enumerate(argspec.defaults): - cut_count = len(argspec.defaults) - # Only add defaultValue when str(default) doesn't contain object address string(object at 0x) - # inspect.getargspec method will return wrong defaults which contain object address for some default values, like sys.stdout - # Match the defaults with the count - if 'object at 0x' not in str(default): - args[len(args) - cut_count + count]['defaultValue'] = str(default) + # Attempt to add default values to arguments. + try: + for count, default in enumerate(argspec.defaults): + # Find the first index which default arguments start at. + # Every argument after this offset_count all have default values. + offset_count = len(argspec.defaults) + # Find the index of the current default value argument + index = len(args) + count - offset_count + + # Only add defaultValue when str(default) doesn't contain object address string(object at 0x) + # inspect.getargspec method will return wrong defaults which contain object address for some default values, like sys.stdout + if 'object at 0x' not in str(default): + args[index]['defaultValue'] = str(default) + # If we cannot find the argument, it is missing a type and was taken out intentionally. + except IndexError: + pass try: lines = inspect.getdoc(obj) lines = lines.split("\n") if lines else [] @@ -643,12 +676,26 @@ def _update_friendly_package_name(path): if args: variables = summary_info['variables'] + arg_id = [] for arg in args: + arg_id.append(arg['id']) + if arg['id'] in variables: # Retrieve argument info from extracted map of variable info arg_var = variables[arg['id']] arg['var_type'] = arg_var.get('var_type') if arg_var.get('var_type') else '' arg['description'] = arg_var.get('description') if arg_var.get('description') else '' + + # Add any variables we might have missed from extraction. + for variable in variables: + if variable not in arg_id: + new_arg = { + "id": variable, + "var_type": variables[variable].get('var_type'), + "description": variables[variable].get('description') + } + args.append(new_arg) + datam['syntax']['parameters'] = args if sig: From 320b28108f1adbb3a637463e8adc5def460e154d Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Tue, 17 Aug 2021 13:58:56 -0400 Subject: [PATCH 063/279] feat: group left-nav entries into versions and groups (#96) * feat: group left-nav entries by versions * fix: remove uid from package groups, fix index * fix: disambiguate only on index and not on toc * chore: add unit test --- .../docfx_yaml/extension.py | 106 +++++++++---- .../gcp-sphinx-docfx-yaml/tests/test_unit.py | 140 ++++++++++++++++++ 2 files changed, 214 insertions(+), 32 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index ec9aaa1ed398..e740b205defa 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -958,6 +958,44 @@ def disambiguate_toc_name(toc_yaml): return disambiguated_names + +# Combines toc_yaml entries with similar version headers. +def group_by_package(toc_yaml): + new_toc_yaml = [] + package_groups = {} + for module in toc_yaml: + package_group = find_package_group(module['uidname']) + if package_group not in package_groups: + package_name = pretty_package_name(package_group) + package_groups[package_group] = { + "name": package_name, + "uidname": package_group, + "items": [] + } + package_groups[package_group]['items'].append(module) + + for package_group in package_groups: + new_toc_yaml.append(package_groups[package_group]) + + return new_toc_yaml + + +# Given the full uid, return the package group including its prefix. +def find_package_group(uid): + return ".".join(uid.split(".")[:3]) + + +# Given the package group, make its name presentable. +def pretty_package_name(package_group): + name = "" + + # Retrieve only the package name + split_name = package_group.split(".")[-1] + # Capitalize the first letter of each package name part + capitalized_name = [part.capitalize() for part in split_name.split("_")] + return " ".join(capitalized_name) + + def build_finished(app, exception): """ Output YAML on the file system. @@ -986,6 +1024,7 @@ def convert_module_to_package_if_needed(obj): if 'source' in obj and 'path' in obj['source'] and obj['source']['path']: if obj['source']['path'].endswith(INITPY): obj['type'] = 'subPackage' + obj['summary'] = "API documentation for `{}` package.".format(obj['name']) return for child_uid in obj['children']: @@ -1184,6 +1223,8 @@ def convert_module_to_package_if_needed(obj): # Perform additional disambiguation of the name disambiguated_names = disambiguate_toc_name(toc_yaml) + toc_yaml = group_by_package(toc_yaml) + # Keeping uidname field carrys over onto the toc.yaml files, we need to # be keep using them but don't need them in the actual file toc_yaml_with_uid = copy.deepcopy(toc_yaml) @@ -1202,37 +1243,6 @@ def convert_module_to_package_if_needed(obj): ) ) - index_file = os.path.join(normalized_outdir, 'index.yml') - index_children = [] - index_references = [] - for item in toc_yaml_with_uid: - index_children.append(item.get('uidname', '')) - index_references.append({ - 'uid': item.get('uidname', ''), - 'name': item.get('name', ''), - 'fullname': item.get('uidname', ''), - 'isExternal': False - }) - with open(index_file, 'w') as index_file_obj: - index_file_obj.write('### YamlMime:UniversalReference\n') - dump( - { - 'items': [{ - 'uid': 'project-' + app.config.project, - 'name': app.config.project, - 'fullName': app.config.project, - 'langs': ['python'], - 'type': 'package', - 'kind': 'distribution', - 'summary': 'Reference API documentation for `{}`.'.format(app.config.project), - 'children': index_children - }], - 'references': index_references - }, - index_file_obj, - default_flow_style=False - ) - # Output files for uid, data in iter(yaml_map.items()): @@ -1244,7 +1254,7 @@ def convert_module_to_package_if_needed(obj): obj['name'] = disambiguated_names[obj_full_name] if obj['type'] == 'subPackage': obj['summary'] = "API documentation for `{}` package.".format(obj['name']) - + # data is formatted as [yaml_data, references] yaml_data, references = data @@ -1275,6 +1285,38 @@ def convert_module_to_package_if_needed(obj): file_name_set.add(filename) + index_file = os.path.join(normalized_outdir, 'index.yml') + index_children = [] + index_references = [] + for package in toc_yaml_with_uid: + for item in package.get("items"): + index_children.append(item.get('uidname', '')) + index_references.append({ + 'uid': item.get('uidname', ''), + 'name': item.get('name', ''), + 'fullname': item.get('uidname', ''), + 'isExternal': False + }) + with open(index_file, 'w') as index_file_obj: + index_file_obj.write('### YamlMime:UniversalReference\n') + dump( + { + 'items': [{ + 'uid': 'project-' + app.config.project, + 'name': app.config.project, + 'fullName': app.config.project, + 'langs': ['python'], + 'type': 'package', + 'kind': 'distribution', + 'summary': 'Reference API documentation for `{}`.'.format(app.config.project), + 'children': index_children + }], + 'references': index_references + }, + index_file_obj, + default_flow_style=False + ) + ''' # TODO: handle xref for other products. xref_file = os.path.join(normalized_outdir, 'xrefs.yml') diff --git a/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py b/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py index 7d11bdde1f2f..ca4c6c12407a 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py +++ b/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py @@ -4,6 +4,9 @@ from docfx_yaml.extension import REF_PATTERN from docfx_yaml.extension import REF_PATTERN_LAST from docfx_yaml.extension import _extract_docstring_info +from docfx_yaml.extension import find_package_group +from docfx_yaml.extension import pretty_package_name +from docfx_yaml.extension import group_by_package import unittest @@ -398,5 +401,142 @@ def test_extract_docstring_info_with_xref(self): self.assertEqual(top_summary_got, self.top_summary1_want) self.assertDictEqual(summary_info_got, summary_info_want) + + def test_find_package_group(self): + package_group_want = "google.cloud.spanner_v1beta2" + uid = "google.cloud.spanner_v1beta2.services.admin_database_v1.types" + + package_group_got = find_package_group(uid) + self.assertEqual(package_group_got, package_group_want) + + + def test_pretty_package_name(self): + package_name_want = "Spanner V1beta2" + package_group = "google.cloud.spanner_v1beta2" + + package_name_got = pretty_package_name(package_group) + self.assertEqual(package_name_got, package_name_want) + + + def test_group_by_package(self): + toc_yaml_want = [ + { + "name": "Spanner Admin Database V1", + "uidname":"google.cloud.spanner_admin_database_v1", + "items": [ + { + "name":"database_admin", + "uidname":"google.cloud.spanner_admin_database_v1.services.database_admin", + "items":[ + { + "name":"Overview", + "uidname":"google.cloud.spanner_admin_database_v1.services.database_admin", + "uid":"google.cloud.spanner_admin_database_v1.services.database_admin" + }, + { + "name":"ListBackupOperationsAsyncPager", + "uidname":"google.cloud.spanner_admin_database_v1.services.database_admin.pagers.ListBackupOperationsAsyncPager", + "uid":"google.cloud.spanner_admin_database_v1.services.database_admin.pagers.ListBackupOperationsAsyncPager" + } + ] + }, + { + "name":"spanner_admin_database_v1.types", + "uidname":"google.cloud.spanner_admin_database_v1.types", + "items":[ + { + "name":"Overview", + "uidname":"google.cloud.spanner_admin_database_v1.types", + "uid":"google.cloud.spanner_admin_database_v1.types" + }, + { + "name":"BackupInfo", + "uidname":"google.cloud.spanner_admin_database_v1.types.BackupInfo", + "uid":"google.cloud.spanner_admin_database_v1.types.BackupInfo" + } + ] + }, + ] + }, + { + "name": "Spanner V1", + "uidname":"google.cloud.spanner_v1", + "items": [ + { + "name":"pool", + "uidname":"google.cloud.spanner_v1.pool", + "items":[ + { + "name":"Overview", + "uidname":"google.cloud.spanner_v1.pool", + "uid":"google.cloud.spanner_v1.pool" + }, + { + "name":"AbstractSessionPool", + "uidname":"google.cloud.spanner_v1.pool.AbstractSessionPool", + "uid":"google.cloud.spanner_v1.pool.AbstractSessionPool" + } + ] + } + ] + } + ] + + toc_yaml = [ + { + "name":"database_admin", + "uidname":"google.cloud.spanner_admin_database_v1.services.database_admin", + "items":[ + { + "name":"Overview", + "uidname":"google.cloud.spanner_admin_database_v1.services.database_admin", + "uid":"google.cloud.spanner_admin_database_v1.services.database_admin" + }, + { + "name":"ListBackupOperationsAsyncPager", + "uidname":"google.cloud.spanner_admin_database_v1.services.database_admin.pagers.ListBackupOperationsAsyncPager", + "uid":"google.cloud.spanner_admin_database_v1.services.database_admin.pagers.ListBackupOperationsAsyncPager" + } + ] + }, + { + "name":"spanner_admin_database_v1.types", + "uidname":"google.cloud.spanner_admin_database_v1.types", + "items":[ + { + "name":"Overview", + "uidname":"google.cloud.spanner_admin_database_v1.types", + "uid":"google.cloud.spanner_admin_database_v1.types" + }, + { + "name":"BackupInfo", + "uidname":"google.cloud.spanner_admin_database_v1.types.BackupInfo", + "uid":"google.cloud.spanner_admin_database_v1.types.BackupInfo" + } + ] + }, + { + "name":"pool", + "uidname":"google.cloud.spanner_v1.pool", + "items":[ + { + "name":"Overview", + "uidname":"google.cloud.spanner_v1.pool", + "uid":"google.cloud.spanner_v1.pool" + }, + { + "name":"AbstractSessionPool", + "uidname":"google.cloud.spanner_v1.pool.AbstractSessionPool", + "uid":"google.cloud.spanner_v1.pool.AbstractSessionPool" + } + ] + } + ] + + toc_yaml_got = group_by_package(toc_yaml) + + self.assertCountEqual(toc_yaml_got, toc_yaml_want) + + if __name__ == '__main__': unittest.main() From 48248e71f9234e59858e1c4772b60b63eb5f28b4 Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Tue, 17 Aug 2021 14:16:13 -0400 Subject: [PATCH 064/279] fix: use file name instead of object name for TOC (#97) --- packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index e740b205defa..bff5e96d84d2 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -1204,8 +1204,11 @@ def convert_module_to_package_if_needed(obj): 'uid': uid }) else: + # Extract the file name to use for new entries into the TOC + # to make TOC entries consistent with filenames. + file_name = obj['source']['path'].split("/")[-1][:-3] toc_yaml.append({ - 'name': node_name, + 'name': file_name, 'uidname': uid, 'uid': uid }) From 3bd53d9c7b64e569060a928e3b4881ef8722ffe0 Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Wed, 18 Aug 2021 20:52:23 -0400 Subject: [PATCH 065/279] fix: retrieve file name as much as possible (#100) * fix: retrieve file name as much as possible * fix: use default return when there are duplicates --- .../docfx_yaml/extension.py | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index bff5e96d84d2..08b387095e16 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -101,6 +101,8 @@ def build_init(app): app.env.docfx_info_uid_types = {} # This stores uidnames of docstrings already parsed app.env.docfx_uid_names = {} + # This stores file path for class when inspect cannot retrieve file path + app.env.docfx_class_paths = {} app.env.docfx_xrefs = {} @@ -603,11 +605,13 @@ def _update_friendly_package_name(path): # Get folder name from conf.py path = os.path.join(app.config.folder, path) + app.env.docfx_class_paths[cls] = path # append relative path defined in conf.py (in case of "binding python" project) try: source_prefix # does source_prefix exist in the current namespace path = source_prefix + path + app.env.docfx_class_paths[cls] = path except NameError: pass @@ -915,10 +919,12 @@ def find_unique_name(package_name, entries): # "google.cloud.spanner.v1.params_v1.types" # "google.cloud.spanner.v1.instance_v1.types" # it will return "instace_v1" or "params_v1" and "types". - if name != "google" and name != "cloud" and entries[name] == 1: + # Also ensure that if name == package_name[-1], we only return one of + # the duplicate and not both. + if name != "google" and name != "cloud" and entries[name] == 1 and name != package_name[-1]: return [name, package_name[-1]] - # If there is no way to disambiguate, return the identifier name + # If there is no way to disambiguate or we found duplicates, return the identifier name. return [package_name[-1]] # Used to disambiguate names that have same entries. @@ -1206,7 +1212,16 @@ def convert_module_to_package_if_needed(obj): else: # Extract the file name to use for new entries into the TOC # to make TOC entries consistent with filenames. - file_name = obj['source']['path'].split("/")[-1][:-3] + file_name = obj['source']['path'] + # `inspect.getfile() cannot retrieve file path for some + # types. Try to retrieve the file path from its class + # parent, otherwise simply use node_name. + if not file_name: + file_name = app.env.docfx_class_paths.get(obj.get("class")) + try: + file_name = obj['source']['path'].split("/")[-1][:-3] + except AttributeError: + file_name = node_name toc_yaml.append({ 'name': file_name, 'uidname': uid, From 86fb80431dd067b8293fe6185818cc46b2b8d77f Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Thu, 19 Aug 2021 14:18:00 -0400 Subject: [PATCH 066/279] chore: add yoshi-python as addititional owner (#101) --- packages/gcp-sphinx-docfx-yaml/.github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/.github/CODEOWNERS b/packages/gcp-sphinx-docfx-yaml/.github/CODEOWNERS index fae1a7ad9db6..e3ce470e3f43 100644 --- a/packages/gcp-sphinx-docfx-yaml/.github/CODEOWNERS +++ b/packages/gcp-sphinx-docfx-yaml/.github/CODEOWNERS @@ -6,4 +6,4 @@ # The cx-eng team is responsible for all doc generation pipelines. -* @googleapis/cx-eng +* @googleapis/cx-eng @googleapis/yoshi-python From ac49e2098e28f271d332cc2745a61d07fda7b146 Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Mon, 23 Aug 2021 15:51:48 -0400 Subject: [PATCH 067/279] feat!: add markdown page support (#102) * feat: add markdown page support * feat: add sphinx-markdown-builder in the plugin * chore: add docuploader to setup.py * test: skip running markdown builder for unittest * chore: fix Kokoro * test: run Kokoro test against head of the branch only * chore: update comments * fix: address comments from PR * fix: lint updates * test: add unit test coverage for new function added * revert(test): revert testing only against HEAD * chore: update comment with issues referenced inline * test: add test case with space after the hashtag --- .../.kokoro/generate-docs.sh | 4 +- .../docfx_yaml/extension.py | 135 ++++++++++++++---- packages/gcp-sphinx-docfx-yaml/setup.py | 2 + .../tests/markdown_example.md | 4 + .../tests/markdown_example_bad.md | 4 + .../tests/markdown_example_header.md | 18 +++ .../tests/markdown_example_noheader.md | 5 + .../gcp-sphinx-docfx-yaml/tests/test_unit.py | 39 ++++- 8 files changed, 184 insertions(+), 27 deletions(-) create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/markdown_example.md create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/markdown_example_bad.md create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/markdown_example_header.md create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/markdown_example_noheader.md diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh b/packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh index 49bad68f8418..261a6468b14d 100755 --- a/packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh @@ -33,7 +33,7 @@ python3 -m pip install --user gcp-docuploader python3 -m pip install -e . python3 -m pip install recommonmark # Required for some client libraries: -python3 -m pip install --user django==2.2 +python3 -m pip install --user django==2.2 ipython # Retrieve unique repositories to regenerate the YAML with. for bucket_item in $(gsutil ls 'gs://docs-staging-v2/docfx-python*' | sort -u -t- -k5,5); do @@ -100,7 +100,7 @@ for bucket_item in $(gsutil ls 'gs://docs-staging-v2/docfx-python*' | sort -u -t # Test running with the plugin version locally. if [[ "${TEST_PLUGIN}" == "true" ]]; then # --no-use-pep517 is required for django-spanner install issue: see https://github.com/pypa/pip/issues/7953 - python3 -m pip install --user --no-use-pep517 -e . + python3 -m pip install --user --no-use-pep517 -e .[all] sphinx-build -T -N -D extensions=sphinx.ext.autodoc,sphinx.ext.autosummary,docfx_yaml.extension,sphinx.ext.intersphinx,sphinx.ext.coverage,sphinx.ext.napoleon,sphinx.ext.todo,sphinx.ext.viewcode,recommonmark -b html -d docs/_build/doctrees/ docs/ docs/_build/html/ continue fi diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index 08b387095e16..97af8ca80c1f 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -22,6 +22,8 @@ import inspect import re import copy +import shutil +from pathlib import Path from functools import partial from itertools import zip_longest @@ -45,6 +47,8 @@ from .directives import RemarksDirective, TodoDirective from .nodes import remarks +import subprocess +from docuploader import shell class Bcolors: HEADER = '\033[95m' @@ -80,7 +84,31 @@ class Bcolors: PROPERTY = 'property' +# Run sphinx-build with Markdown builder in the plugin. +def run_sphinx_markdown(): + cwd = os.getcwd() + # Skip running sphinx-build for Markdown for some unit tests. + # Not required other than to output DocFX YAML. + if "docs" in cwd: + return + + return shell.run( + [ + "sphinx-build", + "-M", + "markdown", + "docs/", + "docs/_build", + ], + hide_output=False + ) + + def build_init(app): + print("Running sphinx-build with Markdown first...") + run_sphinx_markdown() + print("Completed running sphinx-build with Markdown files.") + """ Set up environment data """ @@ -103,6 +131,8 @@ def build_init(app): app.env.docfx_uid_names = {} # This stores file path for class when inspect cannot retrieve file path app.env.docfx_class_paths = {} + # This stores the name and href of the markdown pages. + app.env.markdown_pages = [] app.env.docfx_xrefs = {} @@ -930,11 +960,11 @@ def find_unique_name(package_name, entries): # Used to disambiguate names that have same entries. # Returns a dictionary of names that are disambiguated in the form of: # {uidname: disambiguated_name} -def disambiguate_toc_name(toc_yaml): +def disambiguate_toc_name(pkg_toc_yaml): name_entries = {} disambiguated_names = {} - for module in toc_yaml: + for module in pkg_toc_yaml: module_name = module['name'] if module_name not in name_entries: name_entries[module_name] = {} @@ -955,7 +985,7 @@ def disambiguate_toc_name(toc_yaml): # Update the dictionary of dismabiguated names disambiguated_names.update(disambiguate_toc_name(module['items'])) - for module in toc_yaml: + for module in pkg_toc_yaml: module_name = module['name'] # Check if there are multiple entires of module['name'], disambiguate if needed. if name_entries[module_name][module_name] > 1: @@ -965,11 +995,11 @@ def disambiguate_toc_name(toc_yaml): return disambiguated_names -# Combines toc_yaml entries with similar version headers. -def group_by_package(toc_yaml): - new_toc_yaml = [] +# Combines pkg_toc_yaml entries with similar version headers. +def group_by_package(pkg_toc_yaml): + new_pkg_toc_yaml = [] package_groups = {} - for module in toc_yaml: + for module in pkg_toc_yaml: package_group = find_package_group(module['uidname']) if package_group not in package_groups: package_name = pretty_package_name(package_group) @@ -981,9 +1011,9 @@ def group_by_package(toc_yaml): package_groups[package_group]['items'].append(module) for package_group in package_groups: - new_toc_yaml.append(package_groups[package_group]) + new_pkg_toc_yaml.append(package_groups[package_group]) - return new_toc_yaml + return new_pkg_toc_yaml # Given the full uid, return the package group including its prefix. @@ -1002,20 +1032,73 @@ def pretty_package_name(package_group): return " ".join(capitalized_name) +# For a given markdown file, extract its header line. +def extract_header_from_markdown(mdfile_iterator): + for header_line in mdfile_iterator: + # Ignore licenses and other non-headers prior to the header. + if "#" in header_line: + break + + if header_line.count("#") != 1: + raise ValueError(f"The first header of {mdfile_iterator.name} is not a h1 header: {header_line}") + + # Extract the header name. + return header_line.strip("#").strip() + + +# Given generated markdown files, incorporate them into the docfx_yaml output. +# The markdown file metadata will be added to top level of the TOC. +def find_markdown_pages(app, outdir): + # Use this to ignore markdown files that are unnecessary. + files_to_ignore = [ + "index.md", # merge index.md and README.md and index.yaml later. + # See https://github.com/googleapis/sphinx-docfx-yaml/issues/105. + + "reference.md", # Reference docs overlap with Overview. Will try and incorporate this in later. + # See https://github.com/googleapis/sphinx-docfx-yaml/issues/106. + + "readme.md", # README does not seem to work in cloud site + # See https://github.com/googleapis/sphinx-docfx-yaml/issues/107. + + "upgrading.md", # Currently the formatting breaks, will need to come back to it. + # See https://github.com/googleapis/sphinx-docfx-yaml/issues/108. + ] + + markdown_dir = Path(app.builder.outdir).parent / "markdown" + if not markdown_dir.exists(): + print("There's no markdown file to move.") + return + + # For each file, if it is a markdown file move to the top level pages. + for mdfile in markdown_dir.iterdir(): + if mdfile.is_file() and mdfile.name.lower() not in files_to_ignore: + shutil.copy(mdfile, f"{outdir}/{mdfile.name.lower()}") + + # Extract the header name for TOC. + with open(mdfile) as mdfile_iterator: + name = extract_header_from_markdown(mdfile_iterator) + + # Add the file to the TOC later. + app.env.markdown_pages.append({ + 'name': name, + 'href': mdfile.name.lower(), + }) + + def build_finished(app, exception): """ Output YAML on the file system. """ # Used to get rid of the uidname field for cleaner toc file. - def sanitize_uidname_field(toc_yaml): - for module in toc_yaml: + def sanitize_uidname_field(pkg_toc_yaml): + for module in pkg_toc_yaml: if 'items' in module: sanitize_uidname_field(module['items']) module.pop('uidname') - def find_node_in_toc_tree(toc_yaml, to_add_node): - for module in toc_yaml: + def find_node_in_toc_tree(pkg_toc_yaml, to_add_node): + for module in pkg_toc_yaml: if module['uidname'] == to_add_node: return module @@ -1048,7 +1131,10 @@ def convert_module_to_package_if_needed(obj): )) ensuredir(normalized_outdir) - toc_yaml = [] + # Add markdown pages to the configured output directory. + find_markdown_pages(app, normalized_outdir) + + pkg_toc_yaml = [] # Used to record filenames dumped to avoid confliction # caused by Windows case insensitive file system file_name_set = set() @@ -1197,7 +1283,7 @@ def convert_module_to_package_if_needed(obj): # Build nested TOC if uid.count('.') >= 1: parent_level = '.'.join(uid.split('.')[:-1]) - found_node = find_node_in_toc_tree(toc_yaml, parent_level) + found_node = find_node_in_toc_tree(pkg_toc_yaml, parent_level) if found_node: found_node.pop('uid', 'No uid found') @@ -1222,32 +1308,33 @@ def convert_module_to_package_if_needed(obj): file_name = obj['source']['path'].split("/")[-1][:-3] except AttributeError: file_name = node_name - toc_yaml.append({ + pkg_toc_yaml.append({ 'name': file_name, 'uidname': uid, 'uid': uid }) else: - toc_yaml.append({ + pkg_toc_yaml.append({ 'name': node_name, 'uidname': uid, 'uid': uid }) - if len(toc_yaml) == 0: + # Exit if there are no generated YAML pages or Markdown pages. + if len(pkg_toc_yaml) == 0 and len(app.env.markdown_pages) == 0: raise RuntimeError("No documentation for this module.") # Perform additional disambiguation of the name - disambiguated_names = disambiguate_toc_name(toc_yaml) + disambiguated_names = disambiguate_toc_name(pkg_toc_yaml) - toc_yaml = group_by_package(toc_yaml) + pkg_toc_yaml = group_by_package(pkg_toc_yaml) # Keeping uidname field carrys over onto the toc.yaml files, we need to # be keep using them but don't need them in the actual file - toc_yaml_with_uid = copy.deepcopy(toc_yaml) + pkg_toc_yaml_with_uid = copy.deepcopy(pkg_toc_yaml) - sanitize_uidname_field(toc_yaml) + sanitize_uidname_field(pkg_toc_yaml) toc_file = os.path.join(normalized_outdir, 'toc.yml') with open(toc_file, 'w') as writable: @@ -1255,7 +1342,7 @@ def convert_module_to_package_if_needed(obj): dump( [{ 'name': app.config.project, - 'items': [{'name': 'Overview', 'uid': 'project-' + app.config.project}] + toc_yaml + 'items': [{'name': 'Overview', 'uid': 'project-' + app.config.project}] + app.env.markdown_pages + pkg_toc_yaml }], default_flow_style=False, ) @@ -1306,7 +1393,7 @@ def convert_module_to_package_if_needed(obj): index_file = os.path.join(normalized_outdir, 'index.yml') index_children = [] index_references = [] - for package in toc_yaml_with_uid: + for package in pkg_toc_yaml_with_uid: for item in package.get("items"): index_children.append(item.get('uidname', '')) index_references.append({ diff --git a/packages/gcp-sphinx-docfx-yaml/setup.py b/packages/gcp-sphinx-docfx-yaml/setup.py index fca8369f41fd..d18dc8b087a2 100644 --- a/packages/gcp-sphinx-docfx-yaml/setup.py +++ b/packages/gcp-sphinx-docfx-yaml/setup.py @@ -19,8 +19,10 @@ description = 'Sphinx Python Domain to DocFX YAML Generator' version = '0.5.2' dependencies = [ + 'gcp-docuploader', 'PyYAML', 'sphinx', + 'sphinx-markdown-builder', 'sphinxcontrib.napoleon', 'unidecode', 'wheel>=0.24.0' diff --git a/packages/gcp-sphinx-docfx-yaml/tests/markdown_example.md b/packages/gcp-sphinx-docfx-yaml/tests/markdown_example.md new file mode 100644 index 000000000000..04f9b339b444 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/markdown_example.md @@ -0,0 +1,4 @@ +#Test header for a simple markdown file. + +##Content header +This is a simple line followed by an h2 header. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_bad.md b/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_bad.md new file mode 100644 index 000000000000..8697361ad573 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_bad.md @@ -0,0 +1,4 @@ +##Test header for a simple markdown file. + +##Content header +This is a simple line followed by an h2 header. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_header.md b/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_header.md new file mode 100644 index 000000000000..fb392b549c62 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_header.md @@ -0,0 +1,18 @@ + + + +# Test header for a simple markdown file. + +##Content header +This is a simple line followed by an h2 header. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_noheader.md b/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_noheader.md new file mode 100644 index 000000000000..1c27dd02fbde --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_noheader.md @@ -0,0 +1,5 @@ +This is a simple markdown file with no header. + +When running the test on this file to extract its header, + +it should throw an exception. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py b/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py index ca4c6c12407a..e7279de6957f 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py +++ b/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py @@ -7,6 +7,7 @@ from docfx_yaml.extension import find_package_group from docfx_yaml.extension import pretty_package_name from docfx_yaml.extension import group_by_package +from docfx_yaml.extension import extract_header_from_markdown import unittest @@ -396,7 +397,6 @@ def test_extract_docstring_info_with_xref(self): } top_summary_got = _extract_docstring_info(summary_info_got, summary, "") - self.maxDiff = None # Same as the top summary from previous example, compare with that self.assertEqual(top_summary_got, self.top_summary1_want) self.assertDictEqual(summary_info_got, summary_info_want) @@ -538,5 +538,42 @@ def test_group_by_package(self): self.assertCountEqual(toc_yaml_got, toc_yaml_want) + def test_extract_header_from_markdown(self): + # Check the header for a normal markdown file. + header_line_want = "Test header for a simple markdown file." + + mdfile = open('tests/markdown_example.md', 'r') + header_line_got = extract_header_from_markdown(mdfile) + + self.assertEqual(header_line_got, header_line_want) + mdfile.close() + + # The header should be the same even with the license header. + header_line_with_license_want = header_line_want + + mdfile = open('tests/markdown_example_header.md', 'r') + header_line_with_license_got = extract_header_from_markdown(mdfile) + + self.assertEqual(header_line_with_license_got, header_line_with_license_want) + mdfile.close() + + + def test_extract_header_from_markdown_check_error(self): + # Check an exception is thrown for markdown files that's not well + # formatted. + mdfile = open('tests/markdown_example_bad.md', 'r') + with self.assertRaises(ValueError): + header_line = extract_header_from_markdown(mdfile) + + mdfile.close() + + mdfile = open('tests/markdown_example_noheader.md', 'r') + with self.assertRaises(ValueError): + header_line = extract_header_from_markdown(mdfile) + + mdfile.close() + + + if __name__ == '__main__': unittest.main() From 78e34db44c609d07e6e4a630248bea54e437256d Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Tue, 24 Aug 2021 09:54:15 -0400 Subject: [PATCH 068/279] fix: use the uid for toc entries (#104) * fix: use the uid when applicalbe for toc entries * test: use latest build for Kokoro * test: revert kokoro setting * test: update test case * fix: remove check_name_with_uid function * chore: lint update --- .../docfx_yaml/extension.py | 33 ++++++------------- .../gcp-sphinx-docfx-yaml/tests/test_unit.py | 2 +- 2 files changed, 11 insertions(+), 24 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index 97af8ca80c1f..d55219bc5462 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -1272,13 +1272,13 @@ def convert_module_to_package_if_needed(obj): del(obj['source']) yaml_map[uid] = [yaml_data, references] - + # Parse the name of the object. # Some types will need additional parsing to de-duplicate their names and contain - # a portion of their parent name for better disambiguation. This is done in + # a portion of their parent name for better disambiguation. This is done in # disambiguate_toc_name - - node_name = obj.get('class').split(".")[-1] if obj.get('class') else obj['name'] + + node_name = uid.split(".")[-1] # Build nested TOC if uid.count('.') >= 1: @@ -1286,38 +1286,25 @@ def convert_module_to_package_if_needed(obj): found_node = find_node_in_toc_tree(pkg_toc_yaml, parent_level) if found_node: - found_node.pop('uid', 'No uid found') found_node.setdefault( - 'items', + 'items', [{'name': 'Overview', 'uidname': parent_level, 'uid': parent_level}] ).append({ 'name': node_name, - 'uidname': uid, + 'uidname': uid, 'uid': uid }) else: - # Extract the file name to use for new entries into the TOC - # to make TOC entries consistent with filenames. - file_name = obj['source']['path'] - # `inspect.getfile() cannot retrieve file path for some - # types. Try to retrieve the file path from its class - # parent, otherwise simply use node_name. - if not file_name: - file_name = app.env.docfx_class_paths.get(obj.get("class")) - try: - file_name = obj['source']['path'].split("/")[-1][:-3] - except AttributeError: - file_name = node_name pkg_toc_yaml.append({ - 'name': file_name, - 'uidname': uid, + 'name': node_name, + 'uidname': uid, 'uid': uid }) else: pkg_toc_yaml.append({ - 'name': node_name, - 'uidname': uid, + 'name': node_name, + 'uidname': uid, 'uid': uid }) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py b/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py index e7279de6957f..39443bb15616 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py +++ b/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py @@ -17,7 +17,7 @@ class TestGenerate(unittest.TestCase): def test_find_unique_name(self): entries = {} - + # Disambiguate with unique entries. entry1 = "google.cloud.aiplatform.v1.schema.predict.instance_v1.types" entry2 = "google.cloud.aiplatform.v1beta2.schema.predict.instance_v1.types" From 799e238f8c56c60b54ef52668da59644019a5667 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Tue, 24 Aug 2021 09:57:48 -0400 Subject: [PATCH 069/279] chore: release 1.0.0 (#109) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/gcp-sphinx-docfx-yaml/CHANGELOG.md | 20 ++++++++++++++++++++ packages/gcp-sphinx-docfx-yaml/setup.py | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md index 590147e01654..a7db6ec35ccd 100644 --- a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md +++ b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md @@ -1,5 +1,25 @@ # Changelog +## [1.0.0](https://www.github.com/googleapis/sphinx-docfx-yaml/compare/v0.5.2...v1.0.0) (2021-08-24) + + +### ⚠ BREAKING CHANGES + +* add markdown page support (#102) + +### Features + +* add markdown page support ([#102](https://www.github.com/googleapis/sphinx-docfx-yaml/issues/102)) ([878f1c3](https://www.github.com/googleapis/sphinx-docfx-yaml/commit/878f1c33f3d1ff59df3417ddffd1ac3cecd3f8c1)) +* group left-nav entries into versions and groups ([#96](https://www.github.com/googleapis/sphinx-docfx-yaml/issues/96)) ([ee89394](https://www.github.com/googleapis/sphinx-docfx-yaml/commit/ee8939425682bb81294214dd23b6aaeff74c36da)) + + +### Bug Fixes + +* recover lost function arguments and argument types ([#93](https://www.github.com/googleapis/sphinx-docfx-yaml/issues/93)) ([b90dd0f](https://www.github.com/googleapis/sphinx-docfx-yaml/commit/b90dd0f7a1e8e00630f24945b5425e20511be7c5)) +* retrieve file name as much as possible ([#100](https://www.github.com/googleapis/sphinx-docfx-yaml/issues/100)) ([34cad2b](https://www.github.com/googleapis/sphinx-docfx-yaml/commit/34cad2b2159ee73a5d1d1c16a504a1f82527deda)) +* use file name instead of object name for TOC ([#97](https://www.github.com/googleapis/sphinx-docfx-yaml/issues/97)) ([48279ef](https://www.github.com/googleapis/sphinx-docfx-yaml/commit/48279ef23e4962cab7a5b05cf2e1dc6d0b8907f3)) +* use the uid for toc entries ([#104](https://www.github.com/googleapis/sphinx-docfx-yaml/issues/104)) ([1364dfc](https://www.github.com/googleapis/sphinx-docfx-yaml/commit/1364dfce95044bd4e3763f40af5d281fa2ddb96a)) + ### [0.5.2](https://www.github.com/googleapis/sphinx-docfx-yaml/compare/v0.5.1...v0.5.2) (2021-07-30) diff --git a/packages/gcp-sphinx-docfx-yaml/setup.py b/packages/gcp-sphinx-docfx-yaml/setup.py index d18dc8b087a2..9132e8a06aca 100644 --- a/packages/gcp-sphinx-docfx-yaml/setup.py +++ b/packages/gcp-sphinx-docfx-yaml/setup.py @@ -17,7 +17,7 @@ name = 'gcp-sphinx-docfx-yaml' description = 'Sphinx Python Domain to DocFX YAML Generator' -version = '0.5.2' +version = '1.0.0' dependencies = [ 'gcp-docuploader', 'PyYAML', From ac8fa85e8078a0e21549a6585849552b03f76118 Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Wed, 25 Aug 2021 12:01:08 -0400 Subject: [PATCH 070/279] fix: do not omit arguments retrieved from docstring (#114) * fix: do not omit arguments retrieved from docstring * chore: update comments --- packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index d55219bc5462..dac1bfe42cc7 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -546,6 +546,8 @@ def _update_friendly_package_name(path): lines = [] short_name = name.split('.')[-1] args = [] + # Check how many arguments are present in the function. + arg_count = 0 try: if _type in [METHOD, FUNCTION]: argspec = inspect.getfullargspec(obj) # noqa @@ -568,6 +570,9 @@ def _update_friendly_package_name(path): print(f"Could not parse argument information for {annotation}.") continue + # Add up the number of arguments. `argspec.args` contains a list of + # all the arguments from the function. + arg_count += len(argspec.args) for arg in argspec.args: arg_map = {} # Ignore adding in entry for "self" @@ -708,7 +713,9 @@ def _update_friendly_package_name(path): if args or sig or summary_info: datam['syntax'] = {} - if args: + # If there are well-formatted arguments or a lot of arguments we should look + # into, loop through what we got from the docstring. + if args or arg_count > 0: variables = summary_info['variables'] arg_id = [] for arg in args: From 5a0418d4aa535d6e62096fcebd23f472a6d8adff Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Wed, 25 Aug 2021 12:19:52 -0400 Subject: [PATCH 071/279] fix: parse markdown header more carefully (#111) * fix: check for markdown header more carefully * test: update unit test * fix: update parser and unit test * fix: removing redundant code and adding comment * test: update lint and open file formats * fix: update to parse_markdown_header --- .../docfx_yaml/extension.py | 42 ++++- .../tests/markdown_example.md | 2 +- .../tests/markdown_example_alternate.md | 7 + .../tests/markdown_example_alternate_bad.md | 6 + .../markdown_example_alternate_header.md | 20 +++ .../tests/markdown_example_alternate_less.md | 7 + .../tests/markdown_example_bad_header.md | 4 + ..._example_bad.md => markdown_example_h2.md} | 2 +- .../tests/markdown_example_header.md | 2 +- .../tests/markdown_example_noheader.md | 2 +- .../gcp-sphinx-docfx-yaml/tests/test_unit.py | 170 ++++++++++++++---- 11 files changed, 221 insertions(+), 43 deletions(-) create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/markdown_example_alternate.md create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/markdown_example_alternate_bad.md create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/markdown_example_alternate_header.md create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/markdown_example_alternate_less.md create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/markdown_example_bad_header.md rename packages/gcp-sphinx-docfx-yaml/tests/{markdown_example_bad.md => markdown_example_h2.md} (59%) diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index dac1bfe42cc7..9d28bb8bd98f 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -1039,18 +1039,48 @@ def pretty_package_name(package_group): return " ".join(capitalized_name) +# Check is the current lines conform to markdown header format. +def parse_markdown_header(header_line, prev_line): + # Markdown h1 prefix should have only 1 of '#' character followed by exactly one space. + h1_header_prefix = "# " + if h1_header_prefix in header_line and header_line.count("#") == 1: + # Check for proper h1 header formatting, ensure there's more than just + # the hashtag character, and exactly only one space after the hashtag. + if not header_line[header_line.index(h1_header_prefix)+2].isspace() and \ + len(header_line) > 2: + + return header_line.strip("#").strip() + + elif "=" in header_line: + # Check if we're inspecting an empty or undefined lines. + if not prev_line: + return "" + + # Check if the current line only has equal sign divider. + if header_line.count("=") == len(header_line.strip()): + # Update header to the previous line. + return prev_line.strip() + + return "" + + # For a given markdown file, extract its header line. def extract_header_from_markdown(mdfile_iterator): + mdfile_name = mdfile_iterator.name.split("/")[-1].split(".")[0].capitalize() + prev_line = "" + for header_line in mdfile_iterator: + # Ignore licenses and other non-headers prior to the header. - if "#" in header_line: - break + header = parse_markdown_header(header_line, prev_line) + # If we've found the header, return the header. + if header != "": + return header - if header_line.count("#") != 1: - raise ValueError(f"The first header of {mdfile_iterator.name} is not a h1 header: {header_line}") + prev_line = header_line - # Extract the header name. - return header_line.strip("#").strip() + print(f"Could not find a title for {mdfile_iterator.name}. Using {mdfile_name} as the title instead.") + return mdfile_name # Given generated markdown files, incorporate them into the docfx_yaml output. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/markdown_example.md b/packages/gcp-sphinx-docfx-yaml/tests/markdown_example.md index 04f9b339b444..a2208b1d295f 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/markdown_example.md +++ b/packages/gcp-sphinx-docfx-yaml/tests/markdown_example.md @@ -1,4 +1,4 @@ -#Test header for a simple markdown file. +# Test header for a simple markdown file. ##Content header This is a simple line followed by an h2 header. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_alternate.md b/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_alternate.md new file mode 100644 index 000000000000..9945014edf88 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_alternate.md @@ -0,0 +1,7 @@ +This is a simple alternate header +================================= + +With a different style +---------------------- + +This is a simple markdown file testing for different header style. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_alternate_bad.md b/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_alternate_bad.md new file mode 100644 index 000000000000..e500ba9a8718 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_alternate_bad.md @@ -0,0 +1,6 @@ +============== + +There should be a header line before the divider. + +##Content header +This is a simple line followed by an h2 header. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_alternate_header.md b/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_alternate_header.md new file mode 100644 index 000000000000..ec83c70305be --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_alternate_header.md @@ -0,0 +1,20 @@ + + +This is a simple alternate header +================================= + +With a different style +---------------------- + +This is a simple markdown file testing for different header style. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_alternate_less.md b/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_alternate_less.md new file mode 100644 index 000000000000..38194ce908d6 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_alternate_less.md @@ -0,0 +1,7 @@ +This is a simple alternate header +========= + +With less divider length but it's still a header. +-------- + +This is a markdown file to test for alternate header style with shorter divider. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_bad_header.md b/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_bad_header.md new file mode 100644 index 000000000000..6a3a1893ba25 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_bad_header.md @@ -0,0 +1,4 @@ + #Test header for a bad formatted markdown file. + +##Content header +This is a simple line followed by an h2 header. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_bad.md b/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_h2.md similarity index 59% rename from packages/gcp-sphinx-docfx-yaml/tests/markdown_example_bad.md rename to packages/gcp-sphinx-docfx-yaml/tests/markdown_example_h2.md index 8697361ad573..bc90dbe2c64d 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_bad.md +++ b/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_h2.md @@ -1,4 +1,4 @@ -##Test header for a simple markdown file. +## Test header for a simple markdown file. ##Content header This is a simple line followed by an h2 header. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_header.md b/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_header.md index fb392b549c62..9a534ce3d700 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_header.md +++ b/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_header.md @@ -12,7 +12,7 @@ limitations under the License. --> -# Test header for a simple markdown file. +# Test header for a simple markdown file. ##Content header This is a simple line followed by an h2 header. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_noheader.md b/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_noheader.md index 1c27dd02fbde..6a69ee4571a0 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_noheader.md +++ b/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_noheader.md @@ -2,4 +2,4 @@ This is a simple markdown file with no header. When running the test on this file to extract its header, -it should throw an exception. +it should use the filename as the title. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py b/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py index 39443bb15616..91fd57ed637b 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py +++ b/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py @@ -8,6 +8,7 @@ from docfx_yaml.extension import pretty_package_name from docfx_yaml.extension import group_by_package from docfx_yaml.extension import extract_header_from_markdown +from docfx_yaml.extension import parse_markdown_header import unittest @@ -40,40 +41,35 @@ def test_find_unique_name(self): def test_disambiguate_toc_name(self): - want_file = open('tests/yaml_post.yaml', 'r') - yaml_want = load(want_file, Loader=Loader) + with open('tests/yaml_post.yaml', 'r') as want_file: + yaml_want = load(want_file, Loader=Loader) disambiguated_names_want = { 'google.cloud.spanner_admin_database_v1.types': 'spanner_admin_database_v1.types', - 'google.cloud.spanner_admin_instance_v1.types': 'spanner_admin_instance_v1.types', + 'google.cloud.spanner_admin_instance_v1.types': 'spanner_admin_instance_v1.types', 'google.cloud.spanner_v1.types': 'spanner_v1.types' } - test_file = open('tests/yaml_pre.yaml', 'r') - yaml_got = load(test_file, Loader=Loader) + with open('tests/yaml_pre.yaml', 'r') as test_file: + yaml_got = load(test_file, Loader=Loader) disambiguated_names_got = disambiguate_toc_name(yaml_got) - want_file.close() - test_file.close() - self.assertEqual(yaml_want, yaml_got) self.assertEqual(disambiguated_names_want, disambiguated_names_got) def test_disambiguate_toc_name_duplicate(self): - want_file = open('tests/yaml_post_duplicate.yaml', 'r') - yaml_want = load(want_file, Loader=Loader) + with open('tests/yaml_post_duplicate.yaml', 'r') as want_file: + yaml_want = load(want_file, Loader=Loader) disambiguated_names_want = { - 'google.api_core.client_info': 'client_info', + 'google.api_core.client_info': 'client_info', 'google.api_core.gapic_v1.client_info': 'gapic_v1.client_info' } - - test_file = open('tests/yaml_pre_duplicate.yaml', 'r') - yaml_got = load(test_file, Loader=Loader) + + with open('tests/yaml_pre_duplicate.yaml', 'r') as test_file: + yaml_got = load(test_file, Loader=Loader) disambiguated_names_got = disambiguate_toc_name(yaml_got) - want_file.close() - test_file.close() self.assertEqual(yaml_want, yaml_got) self.assertEqual(disambiguated_names_want, disambiguated_names_got) @@ -538,41 +534,149 @@ def test_group_by_package(self): self.assertCountEqual(toc_yaml_got, toc_yaml_want) + def test_parse_markdown_header(self): + # Test for simple header_line. + header_line_want = "Test header" + + header_line = "# Test header" + prev_line = "" + + header_line_got = parse_markdown_header(header_line, prev_line) + + self.assertEqual(header_line_got, header_line_want) + + # Test for invalid input. + header_line_want = "" + + header_line = "#Test header" + prev_line = "" + + header_line_got = parse_markdown_header(header_line, prev_line) + + self.assertEqual(header_line_got, header_line_want) + + # Test for invalid input. + header_line_want = "" + + header_line = "# Test header" + prev_line = "" + + header_line_got = parse_markdown_header(header_line, prev_line) + + self.assertEqual(header_line_got, header_line_want) + + # Test for no header. + header_line_want = "" + + header_line = "-->" + prev_line = "limitations under the License.\n" + + header_line_got = parse_markdown_header(header_line, prev_line) + + self.assertEqual(header_line_got, header_line_want) + + + def test_parse_markdown_header_alternate(self): + # Test for simple alternate header. + header_line_want = "Test header" + + header_line = "============\n" + prev_line = "Test header" + + header_line_got = parse_markdown_header(header_line, prev_line) + + self.assertEqual(header_line_got, header_line_want) + + # Test for no header. + header_line_want = "" + + header_line = "============\n" + prev_line = "" + + header_line_got = parse_markdown_header(header_line, prev_line) + + self.assertEqual(header_line_got, header_line_want) + + + # Test for shorter divider. + header_line_want = "Test header" + + header_line = "======\n" + prev_line = "Test header" + + header_line_got = parse_markdown_header(header_line, prev_line) + + self.assertEqual(header_line_got, header_line_want) + + def test_extract_header_from_markdown(self): # Check the header for a normal markdown file. header_line_want = "Test header for a simple markdown file." - mdfile = open('tests/markdown_example.md', 'r') - header_line_got = extract_header_from_markdown(mdfile) + with open('tests/markdown_example.md', 'r') as mdfile: + header_line_got = extract_header_from_markdown(mdfile) self.assertEqual(header_line_got, header_line_want) - mdfile.close() # The header should be the same even with the license header. header_line_with_license_want = header_line_want - mdfile = open('tests/markdown_example_header.md', 'r') - header_line_with_license_got = extract_header_from_markdown(mdfile) + with open('tests/markdown_example_header.md', 'r') as mdfile_license: + header_line_with_license_got = extract_header_from_markdown(mdfile_license) self.assertEqual(header_line_with_license_got, header_line_with_license_want) - mdfile.close() - def test_extract_header_from_markdown_check_error(self): - # Check an exception is thrown for markdown files that's not well - # formatted. - mdfile = open('tests/markdown_example_bad.md', 'r') - with self.assertRaises(ValueError): - header_line = extract_header_from_markdown(mdfile) + def test_extract_header_from_markdown_alternate_header(self): + # Check the header for an alternate header style. + header_line_want = "This is a simple alternate header" - mdfile.close() + with open('tests/markdown_example_alternate.md', 'r') as mdfile: + header_line_got = extract_header_from_markdown(mdfile) - mdfile = open('tests/markdown_example_noheader.md', 'r') - with self.assertRaises(ValueError): - header_line = extract_header_from_markdown(mdfile) + self.assertEqual(header_line_got, header_line_want) + + # The header should be the same even with the license header. + header_line_with_license_want = header_line_want + + with open('tests/markdown_example_alternate_header.md', 'r') as mdfile: + header_line_with_license_got = extract_header_from_markdown(mdfile) + + self.assertEqual(header_line_with_license_got, header_line_with_license_want) + + # Check the header for an alternate header style. + header_line_want = "This is a simple alternate header" + + with open('tests/markdown_example_alternate_less.md', 'r') as mdfile: + header_line_got = extract_header_from_markdown(mdfile) + + self.assertEqual(header_line_got, header_line_want) + + + def test_extract_header_from_markdown_bad_headers(self): + # Check that the filename is used as header if no valid header is found. + header_line_want = "Markdown_example_bad_header" + + with open('tests/markdown_example_bad_header.md', 'r') as mdfile: + header_line_got = extract_header_from_markdown(mdfile) + + self.assertEqual(header_line_want, header_line_got) + + # Check that only h1 headers are parsed. + header_line_want = "Markdown_example_h2" + + with open('tests/markdown_example_h2.md', 'r') as mdfile: + header_line_got = extract_header_from_markdown(mdfile) + + self.assertEqual(header_line_want, header_line_got) + + # Check that there must be a line before the h1 header breaker. + header_line_want = "Markdown_example_alternate_bad" - mdfile.close() + with open('tests/markdown_example_alternate_bad.md', 'r') as mdfile: + header_line_got = extract_header_from_markdown(mdfile) + self.assertEqual(header_line_want, header_line_got) if __name__ == '__main__': From 4e4befcd32ff7589915c1e970f8e0616e3efcbef Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Wed, 25 Aug 2021 12:21:54 -0400 Subject: [PATCH 072/279] chore: release 1.0.1 (#117) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/gcp-sphinx-docfx-yaml/CHANGELOG.md | 8 ++++++++ packages/gcp-sphinx-docfx-yaml/setup.py | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md index a7db6ec35ccd..a94f0fa6b60e 100644 --- a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md +++ b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +### [1.0.1](https://www.github.com/googleapis/sphinx-docfx-yaml/compare/v1.0.0...v1.0.1) (2021-08-25) + + +### Bug Fixes + +* do not omit arguments retrieved from docstring ([#114](https://www.github.com/googleapis/sphinx-docfx-yaml/issues/114)) ([18bf0de](https://www.github.com/googleapis/sphinx-docfx-yaml/commit/18bf0de2b761feabdcba071690d04b4dac0a6001)) +* parse markdown header more carefully ([#111](https://www.github.com/googleapis/sphinx-docfx-yaml/issues/111)) ([485b248](https://www.github.com/googleapis/sphinx-docfx-yaml/commit/485b248091a6dffd8f4c0cd77a8fcb4fde8eca09)) + ## [1.0.0](https://www.github.com/googleapis/sphinx-docfx-yaml/compare/v0.5.2...v1.0.0) (2021-08-24) diff --git a/packages/gcp-sphinx-docfx-yaml/setup.py b/packages/gcp-sphinx-docfx-yaml/setup.py index 9132e8a06aca..74727e162c3a 100644 --- a/packages/gcp-sphinx-docfx-yaml/setup.py +++ b/packages/gcp-sphinx-docfx-yaml/setup.py @@ -17,7 +17,7 @@ name = 'gcp-sphinx-docfx-yaml' description = 'Sphinx Python Domain to DocFX YAML Generator' -version = '1.0.0' +version = '1.0.1' dependencies = [ 'gcp-docuploader', 'PyYAML', From 52746746ec1f72e78be175ad8b397e431c1b181e Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Thu, 26 Aug 2021 15:22:11 -0400 Subject: [PATCH 073/279] feat: handle additional docstring items (#116) Adding support for handling docstring items in `top_summary`. Notably, `.. code-block::` and `.. attributes::` will be supported, and any other items as they appear. Similar to how return/exception/params were extracted, iterating through the summary to look for keywords like `code-block`, `attribute` and more in patterns that show up in `.. keyword::` format. If the docstring is malformed from the source, we do not handle it in the plugin. Hand-written docstrings may not work well against the autogenerated reStructuredText, however we should fix those from the client library side than to make special adjustments in the plugin like the bad formatted keywords. For each keyword: - For `code-block`, convert the code snippet in code block using multi-line commenting blocks. - code should be indented, extract lines until there is no indentation/leading whitespace found and/or found other keywords. - Adjust spacing and line breaks as necessary to better display them on cloud site. - For `attributes`, there are 3 main parts: name, description and type. - Extract the name first, followed by the description, then type. Once all 3 are extracted, add it to the list of attributes. - Attributes will be added to the YAML file directly, to be processed in doc-templates. - If attributes are not well formatted, do not add them to the list to be outputted to YAML. Afterwards, incorporate them back into `top_summary` and to be added into the YAMLs. Fixes internally filed issue. - [x] Tests pass --- .../docfx_yaml/extension.py | 136 +++++++++++- .../tests/test_helpers.py | 61 ++++++ .../gcp-sphinx-docfx-yaml/tests/test_unit.py | 193 ++++++++++++++++++ packages/gcp-sphinx-docfx-yaml/tox.ini | 2 +- 4 files changed, 388 insertions(+), 4 deletions(-) create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/test_helpers.py diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index 9d28bb8bd98f..98e02db6caa8 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -39,7 +39,7 @@ from sphinx.errors import ExtensionError from sphinx.util.nodes import make_refnode from sphinxcontrib.napoleon.docstring import GoogleDocstring -from sphinxcontrib.napoleon import Config +from sphinxcontrib.napoleon import Config, _process_docstring from .utils import transform_node, transform_string from .settings import API_ROOT @@ -48,6 +48,7 @@ from .nodes import remarks import subprocess +import ast from docuploader import shell class Bcolors: @@ -82,6 +83,8 @@ class Bcolors: REF_PATTERN_LAST = '~([a-zA-Z0-9_<>]*\.)*[a-zA-Z0-9_<>]*(\(\))?' PROPERTY = 'property' +CODEBLOCK = "code-block" +CODE = "code" # Run sphinx-build with Markdown builder in the plugin. @@ -342,6 +345,129 @@ def _extract_signature(obj_sig): return signature, parameters +# Given a line containing restructured keyword, returns which keyword it is. +def extract_keyword(line): + # Must be in the form of: + # .. keyword:: + # where it begind with 2 dot prefix, followed by a space, then the keyword + # followed by 2 collon suffix. + try: + return line[ 3 : line.index("::") ] + except ValueError: + # TODO: handle reST template. + if line[3] != "_": + raise ValueError(f"Wrong formatting enoucntered for \n{line}\n Please check the docstring.") + return line + + +# Given lines of code, indent to left by 1 block, based on +# amount of trailing white space of first line as 1 block. +def indent_code_left(lines): + parts = lines.split("\n") + # Count how much leading whitespaces there are based on first line. + # lstrip(" ") removes all trailing whitespace from the string. + tab_space = len(parts[0]) - len(parts[0].lstrip(" ")) + parts = [part[tab_space:] for part in parts] + return "\n".join(parts) + + +def _parse_docstring_summary(summary): + summary_parts = [] + attributes = [] + attribute_type_token = ":type:" + keyword = name = description = var_type = "" + + # We need to separate in chunks, which is defined by 3 newline breaks. + # Otherwise when parsing for code and blocks of stuff, we will not be able + # to have the entire context when just splitting by single newlines. + # We should fix this from the library side for consistent docstring style, + # rather than monkey-patching it in the plugin. + for part in summary.split("\n\n\n"): + # Don't process empty string + if part == "": + continue + + # Continue adding parts for code-block. + if keyword and keyword in [CODE, CODEBLOCK]: + # If we reach the end of keyword, close up the code block. + if not part.startswith(" "*tab_space) or part.startswith(".."): + summary_parts.append("```\n") + keyword = "" + + else: + if tab_space == -1: + parts = [split_part for split_part in part.split("\n") if split_part] + tab_space = len(parts[0]) - len(parts[0].lstrip(" ")) + if tab_space == 0: + raise ValueError("Code in the code block should be indented. Please check the docstring.") + if not part.startswith(" "*tab_space): + # No longer looking at code-block, reset keyword. + keyword = "" + summary_parts.append("```\n") + summary_parts.append(indent_code_left(part)) + continue + + # Attributes come in 3 parts, parse the latter two here. + elif keyword and keyword == ATTRIBUTE: + # Second part, extract the description. + if not found_name: + description = part.strip() + found_name = True + continue + # Third part, extract the attribute type then add the completed one + # set to a list to be returned. Close up as needed. + else: + if attribute_type_token in part: + var_type = part.split(":type:")[1].strip() + keyword = "" + if name and description and var_type: + attributes.append({ + "name": name, + "description": description, + "var_type": var_type + }) + + else: + print("Could not process the attribute. Please check the docstring in {summary}.") + + continue + + # Parse keywords if found. + if part.startswith(".."): + keyword = extract_keyword(part) + # Works for both code-block and code + if keyword and keyword in [CODE, CODEBLOCK]: + # Retrieve the language found in the format of + # .. code-block:: lang + # {lang} is optional however. + language = part.split("::")[1].strip() + summary_parts.append(f"```{language}") + + tab_space = -1 + + # Extract the name for attribute first. + elif keyword and keyword == ATTRIBUTE: + found_name = False + name = part.split("::")[1].strip() + + # Reserve for additional parts + # elif keyword == keyword: + else: + summary_parts.append(part + "\n") + + else: + summary_parts.append(part + "\n") + + # Close up from the keyword if needed. + if keyword and keyword in [CODE, CODEBLOCK]: + # Check if it's already closed. + if summary_parts[-1] != "```\n": + summary_parts.append("```\n") + + # Requires 2 newline chars to properly show on cloud site. + return "\n".join(summary_parts), attributes + + # Given documentation docstring, parse them into summary_info. def _extract_docstring_info(summary_info, summary, name): top_summary = "" @@ -700,11 +826,12 @@ def _update_friendly_package_name(path): app.env.docfx_xrefs[xref] = '' summary = app.docfx_transform_string('\n'.join(_refact_example_in_module_summary(lines))) - + # Extract summary info into respective sections. if summary: top_summary = _extract_docstring_info(summary_info, summary, name) - datam['summary'] = top_summary + datam['summary'], datam['attributes'] = _parse_docstring_summary(top_summary) + # If there is no summary, add a short snippet. else: @@ -1487,6 +1614,9 @@ def setup(app): """ + app.setup_extension('sphinx.ext.autodoc') + app.connect('autodoc-process-docstring', _process_docstring) + app.add_node(remarks, html = (remarks.visit_remarks, remarks.depart_remarks)) app.add_directive('remarks', RemarksDirective) app.add_directive('todo', TodoDirective) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/test_helpers.py b/packages/gcp-sphinx-docfx-yaml/tests/test_helpers.py new file mode 100644 index 000000000000..cca7ccb36a43 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/test_helpers.py @@ -0,0 +1,61 @@ +from docfx_yaml.extension import extract_keyword +from docfx_yaml.extension import indent_code_left + + +import unittest + +from yaml import load, Loader + +class TestGenerate(unittest.TestCase): + def test_indent_code_left(self): + # Check that the code indents to left based on first line. + code_want = \ +"""def foo(): + print('test function for indent') + return ('left-indented-code') +""" + + code = \ +""" def foo(): + print('test function for indent') + return ('left-indented-code') +""" + code = indent_code_left(code) + self.assertEqual(code, code_want) + + # Check that if there's no whitespace, it does not indent + code_want = \ +""" +print('test function for no impact indent') +for i in range(10): + print(i) + if i%5 == 0: + i += 1 + else: + continue +""" + + code_got = indent_code_left(code_want) + # Confirm that nothing changes. + self.assertEqual(code_got, code_want) + + + def test_extract_keyword(self): + # Check that keyword properly gets processed. + keyword_want = "attribute" + + keyword_line = ".. attribute:: " + keyword_got = extract_keyword(keyword_line) + + self.assertEqual(keyword_got, keyword_want) + + # Check that keyword is not retrieved for bad formats. + keyword_line = ".. attribute:" + + # Should raise an exception.. + with self.assertRaises(ValueError): + keyword_got = extract_keyword(keyword_line) + + +if __name__ == '__main__': + unittest.main() diff --git a/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py b/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py index 91fd57ed637b..53168a0954c2 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py +++ b/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py @@ -8,6 +8,7 @@ from docfx_yaml.extension import pretty_package_name from docfx_yaml.extension import group_by_package from docfx_yaml.extension import extract_header_from_markdown +from docfx_yaml.extension import _parse_docstring_summary from docfx_yaml.extension import parse_markdown_header import unittest @@ -678,6 +679,198 @@ def test_extract_header_from_markdown_bad_headers(self): self.assertEqual(header_line_want, header_line_got) + def test_parse_docstring_summary(self): + # Check that the summary gets parsed correctly. + attributes_want = [] + summary_want = \ +"""```python +from google.api_core.client_options import ClientOptions + +from google.cloud.vision_v1 import ImageAnnotatorClient + +def get_client_cert(): + + # code to load client certificate and private key. + + return client_cert_bytes, client_private_key_bytes + +options = ClientOptions(api_endpoint=\"foo.googleapis.com\", + + client_cert_source=get_client_cert) + +client = ImageAnnotatorClient(client_options=options) +``` + +You can also pass a mapping object. + +```ruby +from google.cloud.vision_v1 import ImageAnnotatorClient + +client = ImageAnnotatorClient( + + client_options={ + + \"api_endpoint\": \"foo.googleapis.com\", + + \"client_cert_source\" : get_client_cert + + }) + +``` +""" + summary = \ +""" + + +.. code-block:: python + +\n from google.api_core.client_options import ClientOptions +\n from google.cloud.vision_v1 import ImageAnnotatorClient +\n def get_client_cert(): +\n # code to load client certificate and private key. +\n return client_cert_bytes, client_private_key_bytes +\n options = ClientOptions(api_endpoint=\"foo.googleapis.com\", +\n client_cert_source=get_client_cert) +\n client = ImageAnnotatorClient(client_options=options) + + +You can also pass a mapping object. + + +.. code-block:: ruby + +\n from google.cloud.vision_v1 import ImageAnnotatorClient +\n client = ImageAnnotatorClient( +\n client_options={ +\n \"api_endpoint\": \"foo.googleapis.com\", +\n \"client_cert_source\" : get_client_cert +\n }) +""" + summary_got, attributes_got = _parse_docstring_summary(summary) + self.assertEqual(summary_got, summary_want) + self.assertEqual(attributes_got, attributes_want) + + # Check that nothing much changes otherwise. + summary = \ +""" +.. note:: + note that these are not supported yet, so they will be ignored for now. + +And any other documentation that the source code would have could go here. +""" + summary_want = summary + "\n" + + summary_got, attributes_got = _parse_docstring_summary(summary) + self.assertEqual(summary_got, summary_want) + self.assertEqual(attributes_got, attributes_want) + + # Check that exception is raised if code block is not indented. + summary = \ +""" + + +.. code:: python + +\nprint("This should throw an exception.") +\nfor i in range(10): +\n print(i) +""" + with self.assertRaises(ValueError): + _parse_docstring_summary(summary) + + + def test_parse_docstring_summary_attributes(self): + # Test parsing docstring with attributes. + attributes_want = [ + { + "name": "simple name", + "description": "simple description", + "var_type": 'str' + } + ] + summary = \ +""" + + +.. attribute:: simple name + +\nsimple description + +\n:type: str +""" + + summary_got, attributes_got = _parse_docstring_summary(summary) + self.assertCountEqual(attributes_got, attributes_want) + + # Check multiple attributes are parsed. + attributes_want = [ + { + "name": "simple name", + "description": "simple description", + "var_type": "str" + }, + { + "name": "table_insert_request", + "description": "Table insert request.", + "var_type": "google.cloud.bigquery_logging_v1.types.TableInsertRequest" + } + ] + + summary = \ +""" + + +.. attribute:: simple name + +\nsimple description + +\n:type: str + + +.. attribute:: table_insert_request + +\nTable insert request. + +\n:type: google.cloud.bigquery_logging_v1.types.TableInsertRequest +""" + summary_got, attributes_got = _parse_docstring_summary(summary) + + self.assertCountEqual(attributes_got, attributes_want) + for attribute_got, attribute_want in zip(attributes_got, attributes_want): + self.assertDictEqual(attribute_got, attribute_want) + + # Check only attributes in valid format gets parsed. + attributes_want = [ + { + "name": "proper name", + "description": "proper description.", + "var_type": "str" + } + ] + summary = \ +""" + + +.. attribute:: table_insert_request + +\nTable insert request. + +\ntype: google.cloud.bigquery_logging_v1.types.TableInsertRequest + + +.. attribute:: proper name + +\nproper description. + +\n:type: str +""" + summary_got, attributes_got = _parse_docstring_summary(summary) + + # Check that we are returned only one item. + self.assertCountEqual(attributes_got, attributes_want) + for attribute_got, attribute_want in zip(attributes_got, attributes_want): + self.assertDictEqual(attribute_got, attribute_want) + if __name__ == '__main__': unittest.main() diff --git a/packages/gcp-sphinx-docfx-yaml/tox.ini b/packages/gcp-sphinx-docfx-yaml/tox.ini index 1aefc3b435a6..4ebd9e354269 100644 --- a/packages/gcp-sphinx-docfx-yaml/tox.ini +++ b/packages/gcp-sphinx-docfx-yaml/tox.ini @@ -22,7 +22,7 @@ commands = deps = {[testenv]deps} commands = - python3 -m unittest tests/test_unit.py + python3 -m unittest tests/test_unit.py tests/test_helpers.py [testenv:librarytest] deps = From fc6f532507f67702207223510838ac9ff329f9e3 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Thu, 26 Aug 2021 15:29:58 -0400 Subject: [PATCH 074/279] chore: release 1.1.0 (#119) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/gcp-sphinx-docfx-yaml/CHANGELOG.md | 7 +++++++ packages/gcp-sphinx-docfx-yaml/setup.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md index a94f0fa6b60e..39924769662f 100644 --- a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md +++ b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.1.0](https://www.github.com/googleapis/sphinx-docfx-yaml/compare/v1.0.1...v1.1.0) (2021-08-26) + + +### Features + +* handle additional docstring items ([#116](https://www.github.com/googleapis/sphinx-docfx-yaml/issues/116)) ([8c31924](https://www.github.com/googleapis/sphinx-docfx-yaml/commit/8c319244d726c3425fcb9d10ee0a3f4157193e75)) + ### [1.0.1](https://www.github.com/googleapis/sphinx-docfx-yaml/compare/v1.0.0...v1.0.1) (2021-08-25) diff --git a/packages/gcp-sphinx-docfx-yaml/setup.py b/packages/gcp-sphinx-docfx-yaml/setup.py index 74727e162c3a..ad28a4078608 100644 --- a/packages/gcp-sphinx-docfx-yaml/setup.py +++ b/packages/gcp-sphinx-docfx-yaml/setup.py @@ -17,7 +17,7 @@ name = 'gcp-sphinx-docfx-yaml' description = 'Sphinx Python Domain to DocFX YAML Generator' -version = '1.0.1' +version = '1.1.0' dependencies = [ 'gcp-docuploader', 'PyYAML', From 0b7ee0d5ca5df1d58df96ee244d9319a4ad3ed8b Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Thu, 26 Aug 2021 18:30:50 -0400 Subject: [PATCH 075/279] test: update kokoro job to continue on failure (#120) * test: update kokoro job to continue on failure * fix: update comments --- .../gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh b/packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh index 261a6468b14d..125bf5aa0fbb 100755 --- a/packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh @@ -13,7 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -set -eo pipefail +# Should run regardless of failure status for the generator. +set +eo pipefail # Disable buffering, so that the logs stream through. export PYTHONUNBUFFERED=1 @@ -59,15 +60,12 @@ for bucket_item in $(gsutil ls 'gs://docs-staging-v2/docfx-python*' | sort -u -t # For each repo, process docs and docfx jobs to regenerate the YAML. cd ${repo} - # Save the noxfile for usage throughout different releases. + # Save the noxfile for usage throughout different releases. cp "noxfile.py" ../ if [[ ${FORCE_GENERATE_ALL_TAGS} == "true" ]]; then # Grabs all tags from the repository. GITHUB_TAGS=$(git tag --sort=-v:refname) - - # Turn off exit on failures, continue execution. - set +eo pipefail else # Grab the latest released tag. GITHUB_TAGS=$(git describe --tags `git rev-list --tags --max-count=1`) @@ -122,9 +120,9 @@ for bucket_item in $(gsutil ls 'gs://docs-staging-v2/docfx-python*' | sort -u -t # upload docs python3 -m docuploader upload docs/_build/html/docfx_yaml --metadata-file docs.metadata --destination-prefix docfx --staging-bucket "${V2_STAGING_BUCKET}" done - + # Clean up the repository to make room. cd ../ - rm -rf ${repo} + rm -rf ${repo} rm "noxfile.py" done From 4e69471b6d364ef6a92384cce3c9cfd946099817 Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Fri, 27 Aug 2021 14:38:00 -0400 Subject: [PATCH 076/279] chore: move Renovate config to .github, turn off dashboard (#121) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: move Renovate config to .github, turn off dashboard * 🦉 Updates from OwlBot See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md Co-authored-by: Owl Bot --- packages/gcp-sphinx-docfx-yaml/.github/renovate.json | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 packages/gcp-sphinx-docfx-yaml/.github/renovate.json diff --git a/packages/gcp-sphinx-docfx-yaml/.github/renovate.json b/packages/gcp-sphinx-docfx-yaml/.github/renovate.json new file mode 100644 index 000000000000..9fa8816fe873 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/.github/renovate.json @@ -0,0 +1,11 @@ +{ + "extends": [ + "config:base", + ":preserveSemverRanges", + ":disableDependencyDashboard" + ], + "ignorePaths": [".pre-commit-config.yaml"], + "pip_requirements": { + "fileMatch": ["requirements-test.txt", "samples/[\\S/]*constraints.txt", "samples/[\\S/]*constraints-test.txt"] + } +} From 83ec9ba48e5c31b7bca7eaa7e01e617cae78fbcd Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Mon, 30 Aug 2021 11:07:46 -0400 Subject: [PATCH 077/279] fix: make plugin more verbose (#123) * fix: make the plugin be more verbose * fix: include file path when necessary * fix: consolidate error message * fix: update to use string join --- .../docfx_yaml/extension.py | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index 98e02db6caa8..c179c1a27915 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -356,7 +356,7 @@ def extract_keyword(line): except ValueError: # TODO: handle reST template. if line[3] != "_": - raise ValueError(f"Wrong formatting enoucntered for \n{line}\n Please check the docstring.") + raise ValueError(f"Wrong formatting enoucntered for \n{line}") return line @@ -399,7 +399,7 @@ def _parse_docstring_summary(summary): parts = [split_part for split_part in part.split("\n") if split_part] tab_space = len(parts[0]) - len(parts[0].lstrip(" ")) if tab_space == 0: - raise ValueError("Code in the code block should be indented. Please check the docstring.") + raise ValueError(f"Code in the code block should be indented. Please check the docstring: \n{summary}") if not part.startswith(" "*tab_space): # No longer looking at code-block, reset keyword. keyword = "" @@ -428,13 +428,16 @@ def _parse_docstring_summary(summary): }) else: - print("Could not process the attribute. Please check the docstring in {summary}.") + print(f"Could not process the attribute. Please check the docstring: \n{summary}") continue # Parse keywords if found. if part.startswith(".."): - keyword = extract_keyword(part) + try: + keyword = extract_keyword(part) + except ValueError: + raise ValueError(f"Please check the docstring: \n{summary}") # Works for both code-block and code if keyword and keyword in [CODE, CODEBLOCK]: # Retrieve the language found in the format of @@ -830,7 +833,15 @@ def _update_friendly_package_name(path): # Extract summary info into respective sections. if summary: top_summary = _extract_docstring_info(summary_info, summary, name) - datam['summary'], datam['attributes'] = _parse_docstring_summary(top_summary) + try: + datam['summary'], datam['attributes'] = _parse_docstring_summary(top_summary) + except ValueError: + debug_line = [] + if path: + debug_line.append(f"In file {path}\n") + debug_line.append(f"For module {module}, type {_type}:\n") + debug_line.append(f"Failed to parse docstring on {name}.") + raise ValueError("".join(debug_line)) # If there is no summary, add a short snippet. From 4aa31504c4c1c483749a0e3fe924fa393febeb93 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Mon, 30 Aug 2021 11:10:40 -0400 Subject: [PATCH 078/279] chore: release 1.1.1 (#124) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/gcp-sphinx-docfx-yaml/CHANGELOG.md | 7 +++++++ packages/gcp-sphinx-docfx-yaml/setup.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md index 39924769662f..0b7d05555d9a 100644 --- a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md +++ b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +### [1.1.1](https://www.github.com/googleapis/sphinx-docfx-yaml/compare/v1.1.0...v1.1.1) (2021-08-30) + + +### Bug Fixes + +* make plugin more verbose ([#123](https://www.github.com/googleapis/sphinx-docfx-yaml/issues/123)) ([1f25757](https://www.github.com/googleapis/sphinx-docfx-yaml/commit/1f2575730935f0be2795c37262aa1e465221daa7)) + ## [1.1.0](https://www.github.com/googleapis/sphinx-docfx-yaml/compare/v1.0.1...v1.1.0) (2021-08-26) diff --git a/packages/gcp-sphinx-docfx-yaml/setup.py b/packages/gcp-sphinx-docfx-yaml/setup.py index ad28a4078608..7792d057101c 100644 --- a/packages/gcp-sphinx-docfx-yaml/setup.py +++ b/packages/gcp-sphinx-docfx-yaml/setup.py @@ -17,7 +17,7 @@ name = 'gcp-sphinx-docfx-yaml' description = 'Sphinx Python Domain to DocFX YAML Generator' -version = '1.1.0' +version = '1.1.1' dependencies = [ 'gcp-docuploader', 'PyYAML', From aac1a3b90196ed51d343b7ffb8699b72e34fef19 Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Mon, 30 Aug 2021 17:29:16 -0400 Subject: [PATCH 079/279] chore: exclude and remove renovate on OwlBot (#126) --- packages/gcp-sphinx-docfx-yaml/owlbot.py | 3 ++- packages/gcp-sphinx-docfx-yaml/renovate.json | 9 --------- 2 files changed, 2 insertions(+), 10 deletions(-) delete mode 100644 packages/gcp-sphinx-docfx-yaml/renovate.json diff --git a/packages/gcp-sphinx-docfx-yaml/owlbot.py b/packages/gcp-sphinx-docfx-yaml/owlbot.py index 79300a22bdd2..d3cee1cdad76 100644 --- a/packages/gcp-sphinx-docfx-yaml/owlbot.py +++ b/packages/gcp-sphinx-docfx-yaml/owlbot.py @@ -44,6 +44,7 @@ "CONTRIBUTING.rst", # repo has a CONTRIBUTING.md ".github/CONTRIBUTING.md", ".github/PULL_REQUEST_TEMPLATE.md", - ".gitignore" + ".gitignore", + "renovate.json" ], ) diff --git a/packages/gcp-sphinx-docfx-yaml/renovate.json b/packages/gcp-sphinx-docfx-yaml/renovate.json deleted file mode 100644 index c04895563e69..000000000000 --- a/packages/gcp-sphinx-docfx-yaml/renovate.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": [ - "config:base", ":preserveSemverRanges" - ], - "ignorePaths": [".pre-commit-config.yaml"], - "pip_requirements": { - "fileMatch": ["requirements-test.txt", "samples/[\\S/]*constraints.txt", "samples/[\\S/]*constraints-test.txt"] - } -} From f87f90df5c8c8c9984c0d3a0b4868c5a5f0c51e7 Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Thu, 2 Sep 2021 16:50:05 -0600 Subject: [PATCH 080/279] chore(python): rename default branch to main (#128) Source-Link: https://github.com/googleapis/synthtool/commit/5c0fa62eea9c33ebe61e582424b659eb264e1ba4 Post-Processor: gcr.io/repo-automation-bots/owlbot-python:latest@sha256:0ffe3bdd6c7159692df5f7744da74e5ef19966288a6bf76023e8e04e0c424d7d Co-authored-by: Owl Bot --- packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml | 2 +- packages/gcp-sphinx-docfx-yaml/.kokoro/build.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml index a9fcd07cc43b..c07f148f0b0b 100644 --- a/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml +++ b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml @@ -1,3 +1,3 @@ docker: image: gcr.io/repo-automation-bots/owlbot-python:latest - digest: sha256:9743664022bd63a8084be67f144898314c7ca12f0a03e422ac17c733c129d803 + digest: sha256:0ffe3bdd6c7159692df5f7744da74e5ef19966288a6bf76023e8e04e0c424d7d diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/build.sh b/packages/gcp-sphinx-docfx-yaml/.kokoro/build.sh index b3bb5c2b7a1a..a98bd5fe9c1f 100755 --- a/packages/gcp-sphinx-docfx-yaml/.kokoro/build.sh +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/build.sh @@ -41,7 +41,7 @@ python3 -m pip install --upgrade --quiet nox python3 -m nox --version # If this is a continuous build, send the test log to the FlakyBot. -# See https://github.com/googleapis/repo-automation-bots/tree/master/packages/flakybot. +# See https://github.com/googleapis/repo-automation-bots/tree/main/packages/flakybot. if [[ $KOKORO_BUILD_ARTIFACTS_SUBDIR = *"continuous"* ]]; then cleanup() { chmod +x $KOKORO_GFILE_DIR/linux_amd64/flakybot From f59cb7c01f37f0ef5c5c442fcf3eae0af50335a1 Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Tue, 14 Sep 2021 11:00:32 -0400 Subject: [PATCH 081/279] fix: disambiguate after grouping by packages and versions (#132) --- packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index c179c1a27915..f4a22ad93384 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -1487,11 +1487,11 @@ def convert_module_to_package_if_needed(obj): if len(pkg_toc_yaml) == 0 and len(app.env.markdown_pages) == 0: raise RuntimeError("No documentation for this module.") + pkg_toc_yaml = group_by_package(pkg_toc_yaml) + # Perform additional disambiguation of the name disambiguated_names = disambiguate_toc_name(pkg_toc_yaml) - pkg_toc_yaml = group_by_package(pkg_toc_yaml) - # Keeping uidname field carrys over onto the toc.yaml files, we need to # be keep using them but don't need them in the actual file pkg_toc_yaml_with_uid = copy.deepcopy(pkg_toc_yaml) From d25c262c42a91e279b015c33fc9a15da509dc484 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Wed, 15 Sep 2021 16:29:56 -0400 Subject: [PATCH 082/279] chore: release 1.1.2 (#133) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/gcp-sphinx-docfx-yaml/CHANGELOG.md | 7 +++++++ packages/gcp-sphinx-docfx-yaml/setup.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md index 0b7d05555d9a..27ebd3ae7d45 100644 --- a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md +++ b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +### [1.1.2](https://www.github.com/googleapis/sphinx-docfx-yaml/compare/v1.1.1...v1.1.2) (2021-09-14) + + +### Bug Fixes + +* disambiguate after grouping by packages and versions ([#132](https://www.github.com/googleapis/sphinx-docfx-yaml/issues/132)) ([53d68fe](https://www.github.com/googleapis/sphinx-docfx-yaml/commit/53d68fe2a05302e4dc955157d9e08b9de33ec947)) + ### [1.1.1](https://www.github.com/googleapis/sphinx-docfx-yaml/compare/v1.1.0...v1.1.1) (2021-08-30) diff --git a/packages/gcp-sphinx-docfx-yaml/setup.py b/packages/gcp-sphinx-docfx-yaml/setup.py index 7792d057101c..cea554c56231 100644 --- a/packages/gcp-sphinx-docfx-yaml/setup.py +++ b/packages/gcp-sphinx-docfx-yaml/setup.py @@ -17,7 +17,7 @@ name = 'gcp-sphinx-docfx-yaml' description = 'Sphinx Python Domain to DocFX YAML Generator' -version = '1.1.1' +version = '1.1.2' dependencies = [ 'gcp-docuploader', 'PyYAML', From 9874bb5cf820d972b18065996c8e5fed12f70d6d Mon Sep 17 00:00:00 2001 From: Jeffrey Rennie Date: Tue, 21 Sep 2021 12:40:27 -0700 Subject: [PATCH 083/279] chore: relocate owl bot post processor (#136) chore: relocate owl bot post processor --- packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml | 4 ++-- packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml index c07f148f0b0b..2567653c000d 100644 --- a/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml +++ b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml @@ -1,3 +1,3 @@ docker: - image: gcr.io/repo-automation-bots/owlbot-python:latest - digest: sha256:0ffe3bdd6c7159692df5f7744da74e5ef19966288a6bf76023e8e04e0c424d7d + image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest + digest: sha256:87eee22d276554e4e52863ec9b1cb6a7245815dfae20439712bf644348215a5a diff --git a/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.yaml b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.yaml index 892fbc2910bf..ed6155aab50f 100644 --- a/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.yaml +++ b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.yaml @@ -13,6 +13,6 @@ # limitations under the License. docker: - image: gcr.io/repo-automation-bots/owlbot-python:latest + image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest begin-after-commit-hash: ee56c3493ec6aeb237ff515ecea949710944a20f From 98aa6db3d411a34bc057a4c50eb7dd410340ae9a Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Mon, 4 Oct 2021 16:14:43 -0400 Subject: [PATCH 084/279] feat: find more items to cross reference (#138) * feat: find more items to cross reference * fix: address review comments * fix: address review comments * fix: address review comment * test: update unit test * test: include unit test for searching xref * fix: update variable name for accurate representation and test update * fix: update param name, add type hints * fix: update Typing error --- .../docfx_yaml/extension.py | 133 +++++++++++++++++- .../gcp-sphinx-docfx-yaml/requirements.txt | 1 + .../tests/cross_references_post.yaml | 52 +++++++ .../tests/cross_references_pre.yaml | 52 +++++++ .../tests/test_helpers.py | 103 +++++++++++++- 5 files changed, 339 insertions(+), 2 deletions(-) create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/cross_references_post.yaml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/cross_references_pre.yaml diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index f4a22ad93384..03b9cd57a25e 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -26,6 +26,7 @@ from pathlib import Path from functools import partial from itertools import zip_longest +from typing import List try: from subprocess import getoutput @@ -85,6 +86,7 @@ class Bcolors: PROPERTY = 'property' CODEBLOCK = "code-block" CODE = "code" +PACKAGE = "package" # Run sphinx-build with Markdown builder in the plugin. @@ -673,7 +675,7 @@ def _update_friendly_package_name(path): if lines is None: lines = [] - short_name = name.split('.')[-1] + short_name = name.split(".")[-1] args = [] # Check how many arguments are present in the function. arg_count = 0 @@ -1260,6 +1262,117 @@ def find_markdown_pages(app, outdir): }) +# Finds and replaces occurrences which should be a cross reference in the given +# content, except for the current name. +def convert_cross_references(content: str, current_name: str, entry_names: List[str]): + words = content.split(" ") + new_words = [] + # Using counter to check if the entry is already a cross reference. + for index, word in enumerate(words): + cross_reference = "" + for keyword in entry_names: + if keyword != current_name and keyword not in current_name and keyword in word: + # If it is already processed as cross reference, skip over it. + if "{keyword}" + new_words.append(word.replace(keyword, cross_reference)) + print(f"Converted {keyword} into cross reference in: \n{content}") + + # If cross reference has not been found, add current unchanged content. + if not cross_reference: + new_words.append(word) + + return " ".join(new_words) + + +# Used to look for cross references in the obj's data where applicable. +# For now, we inspect summary, syntax and attributes. +def search_cross_references(obj, current_name: str, entry_names: List[str]): + if obj.get("summary"): + obj["summary"] = convert_cross_references(obj["summary"], current_name, entry_names) + + if obj.get("syntax"): + if obj["syntax"].get("parameters"): + for param in obj["syntax"]["parameters"]: + if param.get("description"): + param["description"] = convert_cross_references( + param["description"], + current_name, + entry_names + ) + + if param.get("id"): + param["id"] = convert_cross_references( + param["id"], + current_name, + entry_names + ) + + if param.get("var_type"): + param["var_type"] = convert_cross_references( + param["var_type"], + current_name, + entry_names + ) + + if obj["syntax"].get("exceptions"): + for exception in obj["syntax"]["exceptions"]: + if exception.get("description"): + exception["description"] = convert_cross_references( + exception["description"], + current_name, + entry_names + ) + + if exception.get("var_type"): + exception["var_type"] = convert_cross_references( + exception["var_type"], + current_name, + entry_names + ) + + if obj["syntax"].get("returns"): + for ret in obj["syntax"]["returns"]: + if ret.get("description"): + ret["description"] = convert_cross_references( + ret["description"], + current_name, + entry_names + ) + + if ret.get("var_type"): + ret["var_type"] = convert_cross_references( + ret["var_type"], + current_name, + entry_names + ) + + + if obj.get("attributes"): + for attribute in obj["attributes"]: + if attribute.get("description"): + attribute["description"] = convert_cross_references( + attribute["description"], + current_name, + entry_names + ) + + if attribute.get("name"): + attribute["name"] = convert_cross_references( + attribute["name"], + current_name, + entry_names + ) + + if attribute.get("var_type"): + attribute["var_type"] = convert_cross_references( + attribute["var_type"], + current_name, + entry_names + ) + + def build_finished(app, exception): """ Output YAML on the file system. @@ -1446,6 +1559,24 @@ def convert_module_to_package_if_needed(obj): obj['source']['remote']['repo'] == 'https://apidrop.visualstudio.com/Content%20CI/_git/ReferenceAutomation'): del(obj['source']) + + # Extract any missing cross references where applicable. + # Potential targets are instances of full uid shown, or + # if we find a short form of the uid of one of current + # package's items. For example: + # cross reference candidates: + # google.cloud.bigquery_storage_v1.types.storage.SplitReadStreamResponse + # SplitReadStreamResponse + # non-candidates: + # (not from the same library) + # google.cloud.aiplatform.AutoMLForecastingTrainingJob + + current_name = obj["fullName"] + entry_names = sorted(app.env.docfx_uid_names.keys(), reverse=True) + # Currently we only need to look in summary, syntax and + # attributes for cross references. + search_cross_references(obj, current_name, entry_names) + yaml_map[uid] = [yaml_data, references] # Parse the name of the object. diff --git a/packages/gcp-sphinx-docfx-yaml/requirements.txt b/packages/gcp-sphinx-docfx-yaml/requirements.txt index 25607b8a37a7..1191f7db1b43 100644 --- a/packages/gcp-sphinx-docfx-yaml/requirements.txt +++ b/packages/gcp-sphinx-docfx-yaml/requirements.txt @@ -1,3 +1,4 @@ +parameterized==0.8.1 # google-resumable-media-python requires manual update as this repo isn't templated. # python-api-core also requires manual update as it is not templated. sphinx==4.1.2 diff --git a/packages/gcp-sphinx-docfx-yaml/tests/cross_references_post.yaml b/packages/gcp-sphinx-docfx-yaml/tests/cross_references_post.yaml new file mode 100644 index 000000000000..366c79c8fc70 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/cross_references_post.yaml @@ -0,0 +1,52 @@ +## YamlMime:UniversalReference +api_name: [] +items: +- attributes: + - description: "SQL text filtering statement, similar to a WHERE clause in a\n \ + \ query. Aggregates are not supported.\n \n Examples: \"int_field > 5\"\ + \ \"date_field = CAST('2014-9-27' as\n DATE)\" \"nullable_field is not NULL\"\ + \ \"st_equals(geo_field,\n st_geofromtext(\"POINT(2, 2)\"))\" \"numeric_field\ + \ BETWEEN 1.0\n AND 5.0\"\n \n Restricted to a maximum length for 1 MB." + name: google.cloud.bigquery_storage_v1.types.StreamStats + var_type: str + - description: "Optional. Options specific to the Apache\n Arrow output format." + name: arrow_serialization_options + var_type: google.cloud.bigquery_storage_v1.types.ArrowSerializationOptions + children: [] + class: google.cloud.bigquery_storage_v1.types.ReadSession.TableReadOptions + fullName: google.cloud.bigquery_storage_v1.types.ReadSession.TableReadOptions + inheritance: + - inheritance: + - type: builtins.object + type: proto.message.Message + langs: + - python + module: google.cloud.bigquery_storage_v1.types.ReadSession + name: TableReadOptions + source: + id: TableReadOptions + path: google/cloud/bigquery_storage_v1/types/stream.py + remote: + branch: main + path: google/cloud/bigquery_storage_v1/types/stream.py + repo: git@github.com:googleapis/python-bigquery-storage.git + startLine: 85 + summary: "Options dictating how we read a table.\n\ + \nNames of the fields in the table that should be read in google.cloud.bigquery_storage_v1.types.ReadSession.TableReadOptions." + syntax: + content: TableReadOptions(mapping=None, *, ignore_unknown_fields=False, **kwargs) + exceptions: + - description: If the request failed for any reason. + var_type: google.api_core.exceptions.GoogleAPICallError + parameters: + - description: Required. Name of the stream to start reading from, of the form + `projects/{project_id}/locations/{location}/sessions/{session_id}/streams/{stream_id}` + with google.cloud.bigquery_storage_v1.types.SplitReadStreamResponse + id: row + var_type: google.cloud.bigquery_storage_v1.types.AvroRows + returns: + - description: An iterable of ReadRowsResponse. + var_type: ReadRowsStream + type: class + uid: google.cloud.bigquery_storage_v1.types.ReadSession.TableReadOptions +references: [] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/cross_references_pre.yaml b/packages/gcp-sphinx-docfx-yaml/tests/cross_references_pre.yaml new file mode 100644 index 000000000000..4529cc4d94ee --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/cross_references_pre.yaml @@ -0,0 +1,52 @@ +## YamlMime:UniversalReference +api_name: [] +items: +- attributes: + - description: "SQL text filtering statement, similar to a WHERE clause in a\n \ + \ query. Aggregates are not supported.\n \n Examples: \"int_field > 5\"\ + \ \"date_field = CAST('2014-9-27' as\n DATE)\" \"nullable_field is not NULL\"\ + \ \"st_equals(geo_field,\n st_geofromtext(\"POINT(2, 2)\"))\" \"numeric_field\ + \ BETWEEN 1.0\n AND 5.0\"\n \n Restricted to a maximum length for 1 MB." + name: google.cloud.bigquery_storage_v1.types.StreamStats + var_type: str + - description: "Optional. Options specific to the Apache\n Arrow output format." + name: arrow_serialization_options + var_type: google.cloud.bigquery_storage_v1.types.ArrowSerializationOptions + children: [] + class: google.cloud.bigquery_storage_v1.types.ReadSession.TableReadOptions + fullName: google.cloud.bigquery_storage_v1.types.ReadSession.TableReadOptions + inheritance: + - inheritance: + - type: builtins.object + type: proto.message.Message + langs: + - python + module: google.cloud.bigquery_storage_v1.types.ReadSession + name: TableReadOptions + source: + id: TableReadOptions + path: google/cloud/bigquery_storage_v1/types/stream.py + remote: + branch: main + path: google/cloud/bigquery_storage_v1/types/stream.py + repo: git@github.com:googleapis/python-bigquery-storage.git + startLine: 85 + summary: "Options dictating how we read a table.\n\ + \nNames of the fields in the table that should be read in google.cloud.bigquery_storage_v1.types.ReadSession.TableReadOptions." + syntax: + content: TableReadOptions(mapping=None, *, ignore_unknown_fields=False, **kwargs) + exceptions: + - description: If the request failed for any reason. + var_type: google.api_core.exceptions.GoogleAPICallError + parameters: + - description: Required. Name of the stream to start reading from, of the form + `projects/{project_id}/locations/{location}/sessions/{session_id}/streams/{stream_id}` + with google.cloud.bigquery_storage_v1.types.SplitReadStreamResponse + id: row + var_type: google.cloud.bigquery_storage_v1.types.AvroRows + returns: + - description: An iterable of ReadRowsResponse. + var_type: ReadRowsStream + type: class + uid: google.cloud.bigquery_storage_v1.types.ReadSession.TableReadOptions +references: [] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/test_helpers.py b/packages/gcp-sphinx-docfx-yaml/tests/test_helpers.py index cca7ccb36a43..3393b74d2917 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/test_helpers.py +++ b/packages/gcp-sphinx-docfx-yaml/tests/test_helpers.py @@ -1,8 +1,10 @@ from docfx_yaml.extension import extract_keyword from docfx_yaml.extension import indent_code_left - +from docfx_yaml.extension import convert_cross_references +from docfx_yaml.extension import search_cross_references import unittest +from parameterized import parameterized from yaml import load, Loader @@ -57,5 +59,104 @@ def test_extract_keyword(self): keyword_got = extract_keyword(keyword_line) + cross_references_testdata = [ + # Testing for normal input. + [ + "google.cloud.bigquery_storage_v1.types.SplitReadStreamResponse", + "google.cloud.bigquery_storage_v1.types.SplitReadStreamResponse" + ], + # Testing for no cross references to convert. + [ + "Response message for SplitReadStreamResponse.", + "Response message for SplitReadStreamResponse." + ], + # Testing for cross references to convert within longer content. + [ + "Response message for google.cloud.bigquery_storage_v1.types.SplitReadStreamResponse.", + "Response message for google.cloud.bigquery_storage_v1.types.SplitReadStreamResponse." + ], + ] + @parameterized.expand(cross_references_testdata) + def test_convert_cross_references(self, content, content_want): + # Check that entries correctly turns into cross references. + keyword_map = [ + "google.cloud.bigquery_storage_v1.types.SplitReadStreamResponse" + ] + current_name = "SplitRepsonse" + + content_got = convert_cross_references(content, current_name, keyword_map) + self.assertEqual(content_got, content_want) + + + # Test data used to test for processing already-processed cross references. + cross_references_short_testdata = [ + [ + "Response message for google.cloud.bigquery_storage_v1.types.SplitReadStreamResponse.", + "Response message for google.cloud.bigquery_storage_v1.types.SplitReadStreamResponse." + ], + ] + @parameterized.expand(cross_references_short_testdata) + def test_convert_cross_references_twice(self, content, content_want): + keyword_map = [ + "google.cloud.bigquery_storage_v1.types.SplitReadStreamResponse" + ] + current_name = "SplitRepsonse" + + content_got = convert_cross_references(content, current_name, keyword_map) + + # Make sure that same entries are not processed twice. + # The output should not be different. + current = content_got + current_got = convert_cross_references(current, content, keyword_map) + self.assertEqual(content_want, current_got) + + # If shorter version of the current name exists, it should not interfere + # unless strictly necessary. + keyword_map.append("google.cloud.bigquery_storage_v1.types") + long_name_got = convert_cross_references(content, current_name, keyword_map) + self.assertEqual(long_name_got, content_want) + + shorter_name_want = "google.cloud.bigquery_storage_v1.types" + shorter_name = "google.cloud.bigquery_storage_v1.types" + shorter_name_got = convert_cross_references(shorter_name, current_name, keyword_map) + self.assertEqual(shorter_name_got, shorter_name_want) + + + def test_search_cross_references(self): + # Test for a given YAML file. + keyword_map = [ + "google.cloud.bigquery_storage_v1.types.ThrottleState", + "google.cloud.bigquery_storage_v1.types.StreamStats.Progress", + "google.cloud.bigquery_storage_v1.types.StreamStats", + "google.cloud.bigquery_storage_v1.types.SplitReadStreamResponse", + "google.cloud.bigquery_storage_v1.types.SplitReadStreamRequest", + "google.cloud.bigquery_storage_v1.types.ReadStream", + "google.cloud.bigquery_storage_v1.types.ReadSession.TableReadOptions", + "google.cloud.bigquery_storage_v1.types.ReadSession.TableModifiers", + "google.cloud.bigquery_storage_v1.types.ReadSession", + "google.cloud.bigquery_storage_v1.types.ReadRowsResponse", + "google.cloud.bigquery_storage_v1.types.ReadRowsRequest", + "google.cloud.bigquery_storage_v1.types.DataFormat", + "google.cloud.bigquery_storage_v1.types.CreateReadSessionRequest", + "google.cloud.bigquery_storage_v1.types.AvroSchema", + "google.cloud.bigquery_storage_v1.types.AvroRows", + "google.cloud.bigquery_storage_v1.types.ArrowSerializationOptions.CompressionCodec", + "google.cloud.bigquery_storage_v1.types.ArrowSerializationOptions", + "google.cloud.bigquery_storage_v1.types.ArrowSchema", + "google.cloud.bigquery_storage_v1.types.ArrowRecordBatch", + "google.cloud.bigquery_storage_v1.types", + ] + current_name = "google.cloud.bigquery_storage_v1.types.ReadSession.TableReadOptions" + with open('tests/cross_references_pre.yaml', 'r') as test_file: + yaml_pre = load(test_file, Loader=Loader) + + for obj in yaml_pre['items']: + search_cross_references(obj, current_name, keyword_map) + + with open('tests/cross_references_post.yaml', 'r') as want_file: + yaml_post = load(want_file, Loader=Loader) + + self.assertEqual(yaml_pre, yaml_post) + if __name__ == '__main__': unittest.main() From 39d323c8cf3eee8a34abf7802d6a6500c33682fe Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Tue, 5 Oct 2021 08:24:38 +0200 Subject: [PATCH 085/279] chore(deps): update dependency sphinx to v4.2.0 (#130) Co-authored-by: Dan Lee <71398022+dandhlee@users.noreply.github.com> --- packages/gcp-sphinx-docfx-yaml/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/requirements.txt b/packages/gcp-sphinx-docfx-yaml/requirements.txt index 1191f7db1b43..6cb387fdb30a 100644 --- a/packages/gcp-sphinx-docfx-yaml/requirements.txt +++ b/packages/gcp-sphinx-docfx-yaml/requirements.txt @@ -1,6 +1,6 @@ parameterized==0.8.1 # google-resumable-media-python requires manual update as this repo isn't templated. # python-api-core also requires manual update as it is not templated. -sphinx==4.1.2 +sphinx==4.2.0 -e . tox From f48c6b2d73ac5d83e469293a51f3caabee86aebc Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Tue, 5 Oct 2021 02:33:08 -0400 Subject: [PATCH 086/279] chore: release 1.2.0 (#139) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/gcp-sphinx-docfx-yaml/CHANGELOG.md | 7 +++++++ packages/gcp-sphinx-docfx-yaml/setup.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md index 27ebd3ae7d45..f9acfe384e68 100644 --- a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md +++ b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.2.0](https://www.github.com/googleapis/sphinx-docfx-yaml/compare/v1.1.2...v1.2.0) (2021-10-05) + + +### Features + +* find more items to cross reference ([#138](https://www.github.com/googleapis/sphinx-docfx-yaml/issues/138)) ([a0f82dd](https://www.github.com/googleapis/sphinx-docfx-yaml/commit/a0f82ddc45d8c09ecae6ab55d6366ab6e666397b)) + ### [1.1.2](https://www.github.com/googleapis/sphinx-docfx-yaml/compare/v1.1.1...v1.1.2) (2021-09-14) diff --git a/packages/gcp-sphinx-docfx-yaml/setup.py b/packages/gcp-sphinx-docfx-yaml/setup.py index cea554c56231..d38ba3c32233 100644 --- a/packages/gcp-sphinx-docfx-yaml/setup.py +++ b/packages/gcp-sphinx-docfx-yaml/setup.py @@ -17,7 +17,7 @@ name = 'gcp-sphinx-docfx-yaml' description = 'Sphinx Python Domain to DocFX YAML Generator' -version = '1.1.2' +version = '1.2.0' dependencies = [ 'gcp-docuploader', 'PyYAML', From 535b8d760de9243c67babc03018e94878444608c Mon Sep 17 00:00:00 2001 From: Anthonios Partheniou Date: Thu, 11 Nov 2021 11:57:23 -0500 Subject: [PATCH 087/279] chore: add codeowner_team to .repo-metadata.json (#143) --- packages/gcp-sphinx-docfx-yaml/.repo-metadata.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/.repo-metadata.json b/packages/gcp-sphinx-docfx-yaml/.repo-metadata.json index f6de43400193..af03c51959ff 100644 --- a/packages/gcp-sphinx-docfx-yaml/.repo-metadata.json +++ b/packages/gcp-sphinx-docfx-yaml/.repo-metadata.json @@ -6,5 +6,6 @@ "release_level": "ga", "language": "python", "repo": "googleapis/sphinx-docfx-yaml", - "distribution_name": "gcp-sphinx-docfx-yaml" + "distribution_name": "gcp-sphinx-docfx-yaml", + "codeowner_team": "@googleapis/cx-eng" } From 02c064dedc0e94cc87504fa6b95e2836aeb2ac16 Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Thu, 11 Nov 2021 13:19:14 -0500 Subject: [PATCH 088/279] chore(python): add .github/CODEOWNERS as a templated file (#142) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore(python): add .github/CODEOWNERS as a templated file Source-Link: https://github.com/googleapis/synthtool/commit/c5026b3217973a8db55db8ee85feee0e9a65e295 Post-Processor: gcr.io/cloud-devrel-public-resources/owlbot-python:latest@sha256:0e18b9475fbeb12d9ad4302283171edebb6baf2dfca1bd215ee3b34ed79d95d7 * 🦉 Updates from OwlBot See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md Co-authored-by: Owl Bot Co-authored-by: Anthonios Partheniou --- packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml | 2 +- packages/gcp-sphinx-docfx-yaml/.github/CODEOWNERS | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml index 2567653c000d..7519fa3a2289 100644 --- a/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml +++ b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml @@ -1,3 +1,3 @@ docker: image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest - digest: sha256:87eee22d276554e4e52863ec9b1cb6a7245815dfae20439712bf644348215a5a + digest: sha256:0e18b9475fbeb12d9ad4302283171edebb6baf2dfca1bd215ee3b34ed79d95d7 diff --git a/packages/gcp-sphinx-docfx-yaml/.github/CODEOWNERS b/packages/gcp-sphinx-docfx-yaml/.github/CODEOWNERS index e3ce470e3f43..432949a329da 100644 --- a/packages/gcp-sphinx-docfx-yaml/.github/CODEOWNERS +++ b/packages/gcp-sphinx-docfx-yaml/.github/CODEOWNERS @@ -3,7 +3,10 @@ # # For syntax help see: # https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners#codeowners-syntax +# Note: This file is autogenerated. To make changes to the codeowner team, please update .repo-metadata.json. +# @googleapis/yoshi-python @googleapis/cx-eng are the default owners for changes in this repo +* @googleapis/yoshi-python @googleapis/cx-eng -# The cx-eng team is responsible for all doc generation pipelines. -* @googleapis/cx-eng @googleapis/yoshi-python +# @googleapis/python-samples-owners @googleapis/cx-eng are the default owners for samples changes +/samples/ @googleapis/python-samples-owners @googleapis/cx-eng From 5cf953c9c21800231d26787066be4200b4944f8e Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Mon, 15 Nov 2021 09:25:11 -0500 Subject: [PATCH 089/279] feat: format signature using black (#144) --- .../gcp-sphinx-docfx-yaml/docfx_yaml/extension.py | 15 +++++++++++++-- packages/gcp-sphinx-docfx-yaml/requirements.txt | 1 + packages/gcp-sphinx-docfx-yaml/setup.py | 1 + .../gcp-sphinx-docfx-yaml/tests/test_helpers.py | 11 +++++++++++ 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index 03b9cd57a25e..53a73bbae0ea 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -23,6 +23,7 @@ import re import copy import shutil +import black from pathlib import Path from functools import partial from itertools import zip_longest @@ -712,11 +713,12 @@ def _update_friendly_package_name(path): if arg in type_map: arg_map['var_type'] = type_map[arg] args.append(arg_map) + if argspec.varargs: args.append({'id': argspec.varargs}) if argspec.varkw: args.append({'id': argspec.varkw}) - # Try to add default values. Currently does not work if there is * argument present. + if argspec.defaults: # Attempt to add default values to arguments. try: @@ -959,10 +961,19 @@ def process_docstring(app, _type, name, obj, options, lines): app.env.docfx_info_uid_types[datam['uid']] = _type +# Uses black.format_str() to reformat code as if running black/linter +# for better presnetation. +def format_code(code): + # Signature code comes in raw text without formatting, to run black it + # requires the code to look like actual function declaration in code. + # Returns the original formatted code without the added bits. + return black.format_str("def " + code + ": pass", mode=black.FileMode())[4:-11] + + def process_signature(app, _type, name, obj, options, signature, return_annotation): if signature: short_name = name.split('.')[-1] - signature = short_name + signature + signature = format_code(short_name + signature) app.env.docfx_signature_funcs_methods[name] = signature diff --git a/packages/gcp-sphinx-docfx-yaml/requirements.txt b/packages/gcp-sphinx-docfx-yaml/requirements.txt index 6cb387fdb30a..767aa5c71ca4 100644 --- a/packages/gcp-sphinx-docfx-yaml/requirements.txt +++ b/packages/gcp-sphinx-docfx-yaml/requirements.txt @@ -1,3 +1,4 @@ +black==21.10.b0 parameterized==0.8.1 # google-resumable-media-python requires manual update as this repo isn't templated. # python-api-core also requires manual update as it is not templated. diff --git a/packages/gcp-sphinx-docfx-yaml/setup.py b/packages/gcp-sphinx-docfx-yaml/setup.py index d38ba3c32233..dc7205feaa93 100644 --- a/packages/gcp-sphinx-docfx-yaml/setup.py +++ b/packages/gcp-sphinx-docfx-yaml/setup.py @@ -19,6 +19,7 @@ description = 'Sphinx Python Domain to DocFX YAML Generator' version = '1.2.0' dependencies = [ + 'black', 'gcp-docuploader', 'PyYAML', 'sphinx', diff --git a/packages/gcp-sphinx-docfx-yaml/tests/test_helpers.py b/packages/gcp-sphinx-docfx-yaml/tests/test_helpers.py index 3393b74d2917..aeefde2c7a0f 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/test_helpers.py +++ b/packages/gcp-sphinx-docfx-yaml/tests/test_helpers.py @@ -2,6 +2,7 @@ from docfx_yaml.extension import indent_code_left from docfx_yaml.extension import convert_cross_references from docfx_yaml.extension import search_cross_references +from docfx_yaml.extension import format_code import unittest from parameterized import parameterized @@ -158,5 +159,15 @@ def test_search_cross_references(self): self.assertEqual(yaml_pre, yaml_post) + + def test_format_code(self): + # Test to ensure black formats strings properly. + code_want = 'batch_predict(\n *,\n gcs_source: Optional[Union[str, Sequence[str]]] = None,\n instances_format: str = "jsonl",\n gcs_destination_prefix: Optional[str] = None,\n predictions_format: str = "jsonl",\n model_parameters: Optional[Dict] = None,\n machine_type: Optional[str] = None,\n accelerator_type: Optional[str] = None,\n explanation_parameters: Optional[\n google.cloud.aiplatform_v1.types.explanation.ExplanationParameters\n ] = None,\n labels: Optional[Dict[str, str]] = None,\n sync: bool = True,\n)' + + code = 'batch_predict(*, gcs_source: Optional[Union[str, Sequence[str]]] = None, instances_format: str = "jsonl", gcs_destination_prefix: Optional[str] = None, predictions_format: str = "jsonl", model_parameters: Optional[Dict] = None, machine_type: Optional[str] = None, accelerator_type: Optional[str] = None, explanation_parameters: Optional[google.cloud.aiplatform_v1.types.explanation.ExplanationParameters] = None, labels: Optional[Dict[str, str]] = None, sync: bool = True,)' + + code_got = format_code(code) + self.assertEqual(code_want, code_got) + if __name__ == '__main__': unittest.main() From b8807891c51b156da28c8d7782869589e75b1791 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Mon, 15 Nov 2021 09:48:31 -0500 Subject: [PATCH 090/279] chore: release 1.3.0 (#147) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/gcp-sphinx-docfx-yaml/CHANGELOG.md | 7 +++++++ packages/gcp-sphinx-docfx-yaml/setup.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md index f9acfe384e68..fed8004dcc0b 100644 --- a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md +++ b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.3.0](https://www.github.com/googleapis/sphinx-docfx-yaml/compare/v1.2.0...v1.3.0) (2021-11-15) + + +### Features + +* format signature using black ([#144](https://www.github.com/googleapis/sphinx-docfx-yaml/issues/144)) ([4462b93](https://www.github.com/googleapis/sphinx-docfx-yaml/commit/4462b93a732c9aedf35ad3321269bd4cea9f26dc)) + ## [1.2.0](https://www.github.com/googleapis/sphinx-docfx-yaml/compare/v1.1.2...v1.2.0) (2021-10-05) diff --git a/packages/gcp-sphinx-docfx-yaml/setup.py b/packages/gcp-sphinx-docfx-yaml/setup.py index dc7205feaa93..c0b202046648 100644 --- a/packages/gcp-sphinx-docfx-yaml/setup.py +++ b/packages/gcp-sphinx-docfx-yaml/setup.py @@ -17,7 +17,7 @@ name = 'gcp-sphinx-docfx-yaml' description = 'Sphinx Python Domain to DocFX YAML Generator' -version = '1.2.0' +version = '1.3.0' dependencies = [ 'black', 'gcp-docuploader', From 8c036c1e72026aa07eb584d5979412de8be3b22a Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Mon, 15 Nov 2021 15:49:26 +0100 Subject: [PATCH 091/279] chore(deps): update dependency sphinx to v4.3.0 (#141) Co-authored-by: Anthonios Partheniou Co-authored-by: Dan Lee <71398022+dandhlee@users.noreply.github.com> --- packages/gcp-sphinx-docfx-yaml/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/requirements.txt b/packages/gcp-sphinx-docfx-yaml/requirements.txt index 767aa5c71ca4..686416b508c8 100644 --- a/packages/gcp-sphinx-docfx-yaml/requirements.txt +++ b/packages/gcp-sphinx-docfx-yaml/requirements.txt @@ -2,6 +2,6 @@ black==21.10.b0 parameterized==0.8.1 # google-resumable-media-python requires manual update as this repo isn't templated. # python-api-core also requires manual update as it is not templated. -sphinx==4.2.0 +sphinx==4.3.0 -e . tox From 59c413e2d5b05bfc4f4d7e464f015f12a5b9b41f Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Mon, 15 Nov 2021 17:15:00 -0500 Subject: [PATCH 092/279] fix: resolve square bracketed references (#146) * fix: resolve square bracketed references * fix: update with reviewer comments * fix: update exception message and constant declaration --- .../docfx_yaml/extension.py | 37 ++++++++++++------- .../gcp-sphinx-docfx-yaml/tests/test_unit.py | 34 ++++++++++++++++- 2 files changed, 57 insertions(+), 14 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index 53a73bbae0ea..38ff86b13fee 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -83,6 +83,15 @@ class Bcolors: REF_PATTERN = ':(py:)?(func|class|meth|mod|ref|attr|exc):`~?[a-zA-Z0-9_\.<> ]*(\(\))?`' # Regex expression for checking references of pattern like "~package_v1.subpackage.module" REF_PATTERN_LAST = '~([a-zA-Z0-9_<>]*\.)*[a-zA-Z0-9_<>]*(\(\))?' +# Regex expression for checking references of pattern like +# "[module][google.cloud.cloudkms_v1.module]" +REF_PATTERN_BRACKETS = '\[[a-zA-Z0-9\_\<\>\-\. ]+\]\[[a-zA-Z0-9\_\<\>\-\. ]+\]' + +REF_PATTERNS = [ + REF_PATTERN, + REF_PATTERN_LAST, + REF_PATTERN_BRACKETS, +] PROPERTY = 'property' CODEBLOCK = "code-block" @@ -238,6 +247,7 @@ def _resolve_reference_in_module_summary(pattern, lines): start = matched_obj.start() end = matched_obj.end() matched_str = line[start:end] + # TODO: separate this portion into a function per pattern. if pattern == REF_PATTERN: if '<' in matched_str and '>' in matched_str: # match string like ':func:`***<***>`' @@ -252,13 +262,21 @@ def _resolve_reference_in_module_summary(pattern, lines): # Find the last component of the target. "~Queue.get" only returns ref_name = ref_name[index:] - else: + elif pattern == REF_PATTERN_LAST: index = matched_str.rfind('.') + 1 if index == 0: # If there is no dot, push index to not include tilde index = 1 ref_name = matched_str[index:] + elif pattern == REF_PATTERN_BRACKETS: + lbracket = matched_str.find('[')+1 + rbracket = matched_str.find(']') + ref_name = matched_str[lbracket:rbracket] + + else: + raise ValueError(f'Encountered wrong ref pattern: \n{pattern}') + # Find the uid to add for xref index = matched_str.find("google.cloud") if index > -1: @@ -819,18 +837,11 @@ def _update_friendly_package_name(path): # Add extracted summary if lines != []: - # Resolve references for xrefs in two different formats. - # REF_PATTERN checks for patterns like ":class:`~google.package.module`" - lines, xrefs = _resolve_reference_in_module_summary(REF_PATTERN, lines) - for xref in xrefs: - if xref not in app.env.docfx_xrefs: - app.env.docfx_xrefs[xref] = '' - - # REF_PATTERN_LAST checks for patterns like "~package.module" - lines, xrefs = _resolve_reference_in_module_summary(REF_PATTERN_LAST, lines) - for xref in xrefs: - if xref not in app.env.docfx_xrefs: - app.env.docfx_xrefs[xref] = '' + for ref_pattern in REF_PATTERNS: + lines, xrefs = _resolve_reference_in_module_summary(ref_pattern, lines) + for xref in xrefs: + if xref not in app.env.docfx_xrefs: + app.env.docfx_xrefs[xref] = '' summary = app.docfx_transform_string('\n'.join(_refact_example_in_module_summary(lines))) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py b/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py index 53168a0954c2..8ee6000e4955 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py +++ b/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py @@ -3,6 +3,7 @@ from docfx_yaml.extension import _resolve_reference_in_module_summary from docfx_yaml.extension import REF_PATTERN from docfx_yaml.extension import REF_PATTERN_LAST +from docfx_yaml.extension import REF_PATTERN_BRACKETS from docfx_yaml.extension import _extract_docstring_info from docfx_yaml.extension import find_package_group from docfx_yaml.extension import pretty_package_name @@ -234,7 +235,38 @@ def test_reference_in_summary_more_xrefs(self): } ] } - + + + # Test for resolving square bracketed references. + def test_reference_square_brackets(self): + xrefs_want = [ + 'google.cloud.kms.v1.KeyRing.name', + 'google.cloud.kms.v1.KeyRing', + 'google.cloud.kms.v1.ImportJob', + ] + summary_want = """Required. + +The name of the KeyRing associated with the ImportJobs. +""" + summary_want = summary_want.split("\n") + + summary = """Required. + +The [name][google.cloud.kms.v1.KeyRing.name] of the [KeyRing][google.cloud.kms.v1.KeyRing] associated with the [ImportJobs][google.cloud.kms.v1.ImportJob]. +""" + summary = summary.split("\n") + + summary_got, xrefs_got = _resolve_reference_in_module_summary(REF_PATTERN_BRACKETS, summary) + + self.assertEqual(summary_got, summary_want) + self.assertCountEqual(xrefs_got, xrefs_want) + + + # Check that other patterns throws an exception. + def test_reference_check_error(self): + with self.assertRaises(ValueError): + _resolve_reference_in_module_summary('.*', 'not a valid ref line'.split('\n')) + def test_extract_docstring_info_normal_input(self): From bb98200e36e2cce4ef3d10bad7cd77251bfaeca0 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Mon, 15 Nov 2021 17:20:24 -0500 Subject: [PATCH 093/279] chore: release 1.3.1 (#148) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/gcp-sphinx-docfx-yaml/CHANGELOG.md | 7 +++++++ packages/gcp-sphinx-docfx-yaml/setup.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md index fed8004dcc0b..f8200b33a1b1 100644 --- a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md +++ b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +### [1.3.1](https://www.github.com/googleapis/sphinx-docfx-yaml/compare/v1.3.0...v1.3.1) (2021-11-15) + + +### Bug Fixes + +* resolve square bracketed references ([#146](https://www.github.com/googleapis/sphinx-docfx-yaml/issues/146)) ([fa049ac](https://www.github.com/googleapis/sphinx-docfx-yaml/commit/fa049ace9d14e1f9993313983ad3426ff041672d)) + ## [1.3.0](https://www.github.com/googleapis/sphinx-docfx-yaml/compare/v1.2.0...v1.3.0) (2021-11-15) diff --git a/packages/gcp-sphinx-docfx-yaml/setup.py b/packages/gcp-sphinx-docfx-yaml/setup.py index c0b202046648..f14ef2d755a0 100644 --- a/packages/gcp-sphinx-docfx-yaml/setup.py +++ b/packages/gcp-sphinx-docfx-yaml/setup.py @@ -17,7 +17,7 @@ name = 'gcp-sphinx-docfx-yaml' description = 'Sphinx Python Domain to DocFX YAML Generator' -version = '1.3.0' +version = '1.3.1' dependencies = [ 'black', 'gcp-docuploader', From 23fd788fb29ba1b10f8e2647d97f1ad374a1a21f Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Tue, 16 Nov 2021 06:12:31 -0500 Subject: [PATCH 094/279] fix: gracefully handle format_code exceptions (#152) --- packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index 38ff86b13fee..18eb80fc75cf 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -28,6 +28,7 @@ from functools import partial from itertools import zip_longest from typing import List +from black import InvalidInput try: from subprocess import getoutput @@ -984,7 +985,11 @@ def format_code(code): def process_signature(app, _type, name, obj, options, signature, return_annotation): if signature: short_name = name.split('.')[-1] - signature = format_code(short_name + signature) + signature = short_name + signature + try: + signature = format_code(signature) + except InvalidInput as e: + print(f"Could not format the given code: \n{e})") app.env.docfx_signature_funcs_methods[name] = signature From 93f1503a3ddb74f5657c0b90054837da7c7d9a5e Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Tue, 16 Nov 2021 10:49:25 -0500 Subject: [PATCH 095/279] chore: suppress blib2to3.pgen2.driver output to log (#153) * chore: suppress blib2to3.pgen2.driver output to log * chore: fix placement --- packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index 18eb80fc75cf..1b810d6ee6f0 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -24,6 +24,8 @@ import copy import shutil import black +import logging + from pathlib import Path from functools import partial from itertools import zip_longest @@ -99,6 +101,8 @@ class Bcolors: CODE = "code" PACKAGE = "package" +# Disable blib2to3 output that clutters debugging log. +logging.getLogger("blib2to3").setLevel(logging.ERROR) # Run sphinx-build with Markdown builder in the plugin. def run_sphinx_markdown(): From 98845195c065b7f6cff3f40654f62fe16fa35eec Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Tue, 16 Nov 2021 15:52:18 +0000 Subject: [PATCH 096/279] chore: release 1.3.2 (#154) :robot: I have created a release \*beep\* \*boop\* --- ### [1.3.2](https://www.github.com/googleapis/sphinx-docfx-yaml/compare/v1.3.1...v1.3.2) (2021-11-16) ### Bug Fixes * gracefully handle format_code exceptions ([#152](https://www.github.com/googleapis/sphinx-docfx-yaml/issues/152)) ([a679ace](https://www.github.com/googleapis/sphinx-docfx-yaml/commit/a679ace42c88ac40d7336f6d8b6266191932a3ea)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --- packages/gcp-sphinx-docfx-yaml/CHANGELOG.md | 7 +++++++ packages/gcp-sphinx-docfx-yaml/setup.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md index f8200b33a1b1..fdf3a96bfade 100644 --- a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md +++ b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +### [1.3.2](https://www.github.com/googleapis/sphinx-docfx-yaml/compare/v1.3.1...v1.3.2) (2021-11-16) + + +### Bug Fixes + +* gracefully handle format_code exceptions ([#152](https://www.github.com/googleapis/sphinx-docfx-yaml/issues/152)) ([a679ace](https://www.github.com/googleapis/sphinx-docfx-yaml/commit/a679ace42c88ac40d7336f6d8b6266191932a3ea)) + ### [1.3.1](https://www.github.com/googleapis/sphinx-docfx-yaml/compare/v1.3.0...v1.3.1) (2021-11-15) diff --git a/packages/gcp-sphinx-docfx-yaml/setup.py b/packages/gcp-sphinx-docfx-yaml/setup.py index f14ef2d755a0..fd01c4f9b518 100644 --- a/packages/gcp-sphinx-docfx-yaml/setup.py +++ b/packages/gcp-sphinx-docfx-yaml/setup.py @@ -17,7 +17,7 @@ name = 'gcp-sphinx-docfx-yaml' description = 'Sphinx Python Domain to DocFX YAML Generator' -version = '1.3.1' +version = '1.3.2' dependencies = [ 'black', 'gcp-docuploader', From 80e41423e4b3b6ccb1a3fa3ffcf6bb77db73a0c7 Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Mon, 29 Nov 2021 10:51:24 -0500 Subject: [PATCH 097/279] fix: expand entry names in Overview page to be more descriptive (#159) * fix: expand entry names to be more descriptive * test: add unit test --- .../docfx_yaml/extension.py | 19 +++++++++++++++-- .../tests/test_helpers.py | 21 +++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index 1b810d6ee6f0..800db0ddb695 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -676,6 +676,19 @@ def _extract_docstring_info(summary_info, summary, name): return top_summary +# Returns appropriate product name to display for given full name of entry. +def extract_product_name(name): + if 'google.cloud' in name: + product_name = '.'.join(name.split('.')[2:]) + elif 'google' in name: + product_name = '.'.join(name.split('.')[1:]) + else: + # Use the short name for other formats. + product_name = name.split('.')[-1] + + return product_name + + def _create_datam(app, cls, module, name, _type, obj, lines=None): """ Build the data structure for an autodoc class @@ -866,7 +879,8 @@ def _update_friendly_package_name(path): # If there is no summary, add a short snippet. else: - datam['summary'] = f"API documentation for `{short_name}` {_type}." + product_name = extract_product_name(name) + datam['summary'] = f"API documentation for `{product_name}` {_type}." if args or sig or summary_info: datam['syntax'] = {} @@ -1432,7 +1446,8 @@ def convert_module_to_package_if_needed(obj): if 'source' in obj and 'path' in obj['source'] and obj['source']['path']: if obj['source']['path'].endswith(INITPY): obj['type'] = 'subPackage' - obj['summary'] = "API documentation for `{}` package.".format(obj['name']) + product_name = extract_product_name(obj['fullName']) + obj['summary'] = f"API documentation for `{product_name}` package." return for child_uid in obj['children']: diff --git a/packages/gcp-sphinx-docfx-yaml/tests/test_helpers.py b/packages/gcp-sphinx-docfx-yaml/tests/test_helpers.py index aeefde2c7a0f..b2b4f51e2947 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/test_helpers.py +++ b/packages/gcp-sphinx-docfx-yaml/tests/test_helpers.py @@ -3,6 +3,7 @@ from docfx_yaml.extension import convert_cross_references from docfx_yaml.extension import search_cross_references from docfx_yaml.extension import format_code +from docfx_yaml.extension import extract_product_name import unittest from parameterized import parameterized @@ -169,5 +170,25 @@ def test_format_code(self): code_got = format_code(code) self.assertEqual(code_want, code_got) + + def test_extract_product_name(self): + # Test to ensure different name formats extract product name properly. + name_want = "scheduler_v1.types.Digest" + name = "google.cloud.scheduler_v1.types.Digest" + product_name = extract_product_name(name) + + self.assertEqual(name_want, product_name) + + non_cloud_name = "google.scheduler_v1.types.Digest" + non_cloud_product_name = extract_product_name(non_cloud_name) + + self.assertEqual(name_want, non_cloud_product_name) + + short_name_want = "Digest" + short_name = "scheduler_v1.types.Digest" + short_product_name = extract_product_name(short_name) + + self.assertEqual(short_name_want, short_product_name) + if __name__ == '__main__': unittest.main() From a656da49c24024a7c8aaa82241a3901385ba79ad Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Mon, 29 Nov 2021 11:05:11 -0500 Subject: [PATCH 098/279] chore: release 1.3.3 (#161) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/gcp-sphinx-docfx-yaml/CHANGELOG.md | 7 +++++++ packages/gcp-sphinx-docfx-yaml/setup.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md index fdf3a96bfade..dc976c756024 100644 --- a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md +++ b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +### [1.3.3](https://www.github.com/googleapis/sphinx-docfx-yaml/compare/v1.3.2...v1.3.3) (2021-11-29) + + +### Bug Fixes + +* expand entry names in Overview page to be more descriptive ([#159](https://www.github.com/googleapis/sphinx-docfx-yaml/issues/159)) ([7bd6416](https://www.github.com/googleapis/sphinx-docfx-yaml/commit/7bd64160cda8a84cdbd14f61bd39d5594b048bd2)) + ### [1.3.2](https://www.github.com/googleapis/sphinx-docfx-yaml/compare/v1.3.1...v1.3.2) (2021-11-16) diff --git a/packages/gcp-sphinx-docfx-yaml/setup.py b/packages/gcp-sphinx-docfx-yaml/setup.py index fd01c4f9b518..9bf1129f86c0 100644 --- a/packages/gcp-sphinx-docfx-yaml/setup.py +++ b/packages/gcp-sphinx-docfx-yaml/setup.py @@ -17,7 +17,7 @@ name = 'gcp-sphinx-docfx-yaml' description = 'Sphinx Python Domain to DocFX YAML Generator' -version = '1.3.2' +version = '1.3.3' dependencies = [ 'black', 'gcp-docuploader', From 111e76574a241a52fb5e1462dcb1121354a78c3c Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Thu, 6 Jan 2022 16:08:23 +0000 Subject: [PATCH 099/279] chore: use python-samples-reviewers (#162) --- packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml | 2 +- packages/gcp-sphinx-docfx-yaml/.github/CODEOWNERS | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml index 7519fa3a2289..f33299ddbbab 100644 --- a/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml +++ b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml @@ -1,3 +1,3 @@ docker: image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest - digest: sha256:0e18b9475fbeb12d9ad4302283171edebb6baf2dfca1bd215ee3b34ed79d95d7 + digest: sha256:899d5d7cc340fa8ef9d8ae1a8cfba362c6898584f779e156f25ee828ba824610 diff --git a/packages/gcp-sphinx-docfx-yaml/.github/CODEOWNERS b/packages/gcp-sphinx-docfx-yaml/.github/CODEOWNERS index 432949a329da..828d46300d45 100644 --- a/packages/gcp-sphinx-docfx-yaml/.github/CODEOWNERS +++ b/packages/gcp-sphinx-docfx-yaml/.github/CODEOWNERS @@ -8,5 +8,5 @@ # @googleapis/yoshi-python @googleapis/cx-eng are the default owners for changes in this repo * @googleapis/yoshi-python @googleapis/cx-eng -# @googleapis/python-samples-owners @googleapis/cx-eng are the default owners for samples changes -/samples/ @googleapis/python-samples-owners @googleapis/cx-eng +# @googleapis/python-samples-reviewers @googleapis/cx-eng are the default owners for samples changes +/samples/ @googleapis/python-samples-reviewers @googleapis/cx-eng From 54342c2c1e7485c0d778dc69c028f000eae97b8f Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Sat, 8 Jan 2022 00:09:19 +0100 Subject: [PATCH 100/279] chore(deps): update dependency sphinx to v4.3.1 (#160) Co-authored-by: Dan Lee <71398022+dandhlee@users.noreply.github.com> --- packages/gcp-sphinx-docfx-yaml/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/requirements.txt b/packages/gcp-sphinx-docfx-yaml/requirements.txt index 686416b508c8..25d027047266 100644 --- a/packages/gcp-sphinx-docfx-yaml/requirements.txt +++ b/packages/gcp-sphinx-docfx-yaml/requirements.txt @@ -2,6 +2,6 @@ black==21.10.b0 parameterized==0.8.1 # google-resumable-media-python requires manual update as this repo isn't templated. # python-api-core also requires manual update as it is not templated. -sphinx==4.3.0 +sphinx==4.3.1 -e . tox From ad8cfb915ea09bef647e7f976918b352f9196169 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Sat, 8 Jan 2022 00:11:44 +0100 Subject: [PATCH 101/279] chore(deps): update dependency sphinx to v4.3.2 (#163) --- packages/gcp-sphinx-docfx-yaml/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/requirements.txt b/packages/gcp-sphinx-docfx-yaml/requirements.txt index 25d027047266..e3aa0c3dabd1 100644 --- a/packages/gcp-sphinx-docfx-yaml/requirements.txt +++ b/packages/gcp-sphinx-docfx-yaml/requirements.txt @@ -2,6 +2,6 @@ black==21.10.b0 parameterized==0.8.1 # google-resumable-media-python requires manual update as this repo isn't templated. # python-api-core also requires manual update as it is not templated. -sphinx==4.3.1 +sphinx==4.3.2 -e . tox From 6e1420c4a0f4417d48ff3fef4cdabe98d8544303 Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Wed, 12 Jan 2022 17:37:17 -0500 Subject: [PATCH 102/279] build: switch to release-please for tagging (#165) Source-Link: https://github.com/googleapis/synthtool/commit/f8077d237e0df2cb0066dfc6e09fc41e1c59646a Post-Processor: gcr.io/cloud-devrel-public-resources/owlbot-python:latest@sha256:dfa9b663b32de8b5b327e32c1da665a80de48876558dd58091d8160c60ad7355 Co-authored-by: Owl Bot --- packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml | 2 +- packages/gcp-sphinx-docfx-yaml/.github/release-please.yml | 1 + packages/gcp-sphinx-docfx-yaml/.github/release-trigger.yml | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 packages/gcp-sphinx-docfx-yaml/.github/release-trigger.yml diff --git a/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml index f33299ddbbab..ff5126c188d0 100644 --- a/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml +++ b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml @@ -1,3 +1,3 @@ docker: image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest - digest: sha256:899d5d7cc340fa8ef9d8ae1a8cfba362c6898584f779e156f25ee828ba824610 + digest: sha256:dfa9b663b32de8b5b327e32c1da665a80de48876558dd58091d8160c60ad7355 diff --git a/packages/gcp-sphinx-docfx-yaml/.github/release-please.yml b/packages/gcp-sphinx-docfx-yaml/.github/release-please.yml index 4507ad0598a5..466597e5b196 100644 --- a/packages/gcp-sphinx-docfx-yaml/.github/release-please.yml +++ b/packages/gcp-sphinx-docfx-yaml/.github/release-please.yml @@ -1 +1,2 @@ releaseType: python +handleGHRelease: true diff --git a/packages/gcp-sphinx-docfx-yaml/.github/release-trigger.yml b/packages/gcp-sphinx-docfx-yaml/.github/release-trigger.yml new file mode 100644 index 000000000000..d4ca94189e16 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/.github/release-trigger.yml @@ -0,0 +1 @@ +enabled: true From deab6884ce9200d8e36c8f640b75da99151781ef Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Thu, 13 Jan 2022 20:08:16 -0500 Subject: [PATCH 103/279] chore(python): update release.sh to use keystore (#166) Source-Link: https://github.com/googleapis/synthtool/commit/69fda12e2994f0b595a397e8bb6e3e9f380524eb Post-Processor: gcr.io/cloud-devrel-public-resources/owlbot-python:latest@sha256:ae600f36b6bc972b368367b6f83a1d91ec2c82a4a116b383d67d547c56fe6de3 Co-authored-by: Owl Bot --- .../gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml | 2 +- packages/gcp-sphinx-docfx-yaml/.kokoro/release.sh | 2 +- .../gcp-sphinx-docfx-yaml/.kokoro/release/common.cfg | 12 +++++++++++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml index ff5126c188d0..eecb84c21b27 100644 --- a/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml +++ b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml @@ -1,3 +1,3 @@ docker: image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest - digest: sha256:dfa9b663b32de8b5b327e32c1da665a80de48876558dd58091d8160c60ad7355 + digest: sha256:ae600f36b6bc972b368367b6f83a1d91ec2c82a4a116b383d67d547c56fe6de3 diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/release.sh b/packages/gcp-sphinx-docfx-yaml/.kokoro/release.sh index 8fdf97fc49b5..3c20981b38c8 100755 --- a/packages/gcp-sphinx-docfx-yaml/.kokoro/release.sh +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/release.sh @@ -26,7 +26,7 @@ python3 -m pip install --upgrade twine wheel setuptools export PYTHONUNBUFFERED=1 # Move into the package, build the distribution and upload. -TWINE_PASSWORD=$(cat "${KOKORO_GFILE_DIR}/secret_manager/google-cloud-pypi-token") +TWINE_PASSWORD=$(cat "${KOKORO_KEYSTORE_DIR}/73713_google-cloud-pypi-token-keystore-1") cd github/sphinx-docfx-yaml python3 setup.py sdist bdist_wheel twine upload --username __token__ --password "${TWINE_PASSWORD}" dist/* diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/release/common.cfg b/packages/gcp-sphinx-docfx-yaml/.kokoro/release/common.cfg index 01d29a195724..d37c59b9eb57 100644 --- a/packages/gcp-sphinx-docfx-yaml/.kokoro/release/common.cfg +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/release/common.cfg @@ -23,8 +23,18 @@ env_vars: { value: "github/sphinx-docfx-yaml/.kokoro/release.sh" } +# Fetch PyPI password +before_action { + fetch_keystore { + keystore_resource { + keystore_config_id: 73713 + keyname: "google-cloud-pypi-token-keystore-1" + } + } +} + # Tokens needed to report release status back to GitHub env_vars: { key: "SECRET_MANAGER_KEYS" - value: "releasetool-publish-reporter-app,releasetool-publish-reporter-googleapis-installation,releasetool-publish-reporter-pem,google-cloud-pypi-token" + value: "releasetool-publish-reporter-app,releasetool-publish-reporter-googleapis-installation,releasetool-publish-reporter-pem" } From 6d22ec3a27450ca0c362cd544784d43104658616 Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Thu, 20 Jan 2022 10:42:08 -0500 Subject: [PATCH 104/279] chore(python): exclude templated GH action workflows (#168) * ci(python): run lint / unit tests / docs as GH actions Source-Link: https://github.com/googleapis/synthtool/commit/57be0cdb0b94e1669cee0ca38d790de1dfdbcd44 Post-Processor: gcr.io/cloud-devrel-public-resources/owlbot-python:latest@sha256:ed1f9983d5a935a89fe8085e8bb97d94e41015252c5b6c9771257cf8624367e6 * exclude templated gh actions Co-authored-by: Owl Bot Co-authored-by: Anthonios Partheniou --- .../.github/.OwlBot.lock.yaml | 15 ++++++++++++++- packages/gcp-sphinx-docfx-yaml/owlbot.py | 3 ++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml index eecb84c21b27..8cb43804d999 100644 --- a/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml +++ b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml @@ -1,3 +1,16 @@ +# Copyright 2022 Google LLC +# +# 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. docker: image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest - digest: sha256:ae600f36b6bc972b368367b6f83a1d91ec2c82a4a116b383d67d547c56fe6de3 + digest: sha256:ed1f9983d5a935a89fe8085e8bb97d94e41015252c5b6c9771257cf8624367e6 diff --git a/packages/gcp-sphinx-docfx-yaml/owlbot.py b/packages/gcp-sphinx-docfx-yaml/owlbot.py index d3cee1cdad76..5d9cdae39b24 100644 --- a/packages/gcp-sphinx-docfx-yaml/owlbot.py +++ b/packages/gcp-sphinx-docfx-yaml/owlbot.py @@ -45,6 +45,7 @@ ".github/CONTRIBUTING.md", ".github/PULL_REQUEST_TEMPLATE.md", ".gitignore", - "renovate.json" + "renovate.json", + ".github/workflows", # exclude templated gh actions ], ) From 41bacebc81a282f318169b0f56b9a58c7653da1b Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Thu, 20 Jan 2022 12:57:49 -0500 Subject: [PATCH 105/279] chore: fix repo-metadata as required (#169) --- packages/gcp-sphinx-docfx-yaml/.repo-metadata.json | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/.repo-metadata.json b/packages/gcp-sphinx-docfx-yaml/.repo-metadata.json index af03c51959ff..0528f83fd251 100644 --- a/packages/gcp-sphinx-docfx-yaml/.repo-metadata.json +++ b/packages/gcp-sphinx-docfx-yaml/.repo-metadata.json @@ -1,11 +1,13 @@ { "name": "gcp-sphinx-docfx-yaml", "name_pretty": "Sphinx DocFX YAML Generator", - "client_documentation": "", + "product_documentation": "https://github.com/googleapis/sphinx-docfx-yaml", + "client_documentation": "https://github.com/googleapis/sphinx-docfx-yaml", "issue_tracker": "https://github.com/googleapis/sphinx-docfx-yaml/issues", - "release_level": "ga", + "release_level": "preview", "language": "python", "repo": "googleapis/sphinx-docfx-yaml", "distribution_name": "gcp-sphinx-docfx-yaml", - "codeowner_team": "@googleapis/cx-eng" + "codeowner_team": "@googleapis/cx-eng", + "library_type": "OTHER" } From 74c7b9d52ffe30221aceff1ebab05219b1bf9294 Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Fri, 28 Jan 2022 11:55:27 -0500 Subject: [PATCH 106/279] feat: add syntax highlighting support for Markdown pages (#170) * feat: add syntax highlight support for markdown pages * test: add unit test for syntax highlighting * test: remove unneeded files * fix: apply commit suggestion * feat: handle code blocks with langauge indicators * test: update unittest with language indicator support * test: apply review suggestions * test: update to use temporary file. * feat: update with review suggestions. * chore: code cleanup * test: update to use context manager for temporary file --- .../docfx_yaml/extension.py | 47 +++++++++++++++++++ .../tests/markdown_mixed_highlight.md | 15 ++++++ .../tests/markdown_mixed_highlight_want.md | 15 ++++++ .../tests/markdown_no_highlight.md | 7 +++ .../tests/markdown_no_highlight_want.md | 7 +++ .../tests/markdown_syntax_highlight.md | 9 ++++ .../tests/markdown_syntax_highlight_want.md | 9 ++++ .../tests/test_helpers.py | 36 ++++++++++++++ 8 files changed, 145 insertions(+) create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/markdown_mixed_highlight.md create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/markdown_mixed_highlight_want.md create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/markdown_no_highlight.md create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/markdown_no_highlight_want.md create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/markdown_syntax_highlight.md create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/markdown_syntax_highlight_want.md diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index 800db0ddb695..4e2e9f4710b1 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -1268,6 +1268,52 @@ def extract_header_from_markdown(mdfile_iterator): return mdfile_name +# For a given markdown file, adds syntax highlighting to code blocks. +def highlight_md_codeblocks(mdfile): + fence = '```' + fence_with_python = '```python' + new_lines = [] + + with open(mdfile) as mdfile_iterator: + file_content = mdfile_iterator.read() + # If there is an odd number of code block annotations, do not syntax + # highlight. + if file_content.count(fence) % 2 != 0: + print(f'{mdfile_iterator.name} contains wrong format of code blocks. Skipping syntax highlighting.') + return + # Retrieve code block positions to replace + codeblocks = [[m.start(), m.end()] for m in re.finditer( + fence, + file_content)] + + # This is equivalent to grabbing every odd index item. + codeblocks = codeblocks[::2] + # Used to store code blocks that come without language indicators. + blocks_without_indicators = [] + + # Check if the fence comes without a language indicator. If so, include + # this to a list to render. + for start, end in codeblocks: + if file_content[end] == '\n': + blocks_without_indicators.append([start, end]) + + # Stitch content that does not need to be parsed, and replace with + # `fence_with_python` for parsed portions. + prev_start = prev_end = 0 + for start, end in blocks_without_indicators: + new_lines.append(file_content[prev_end:start]) + new_lines.append(fence_with_python) + prev_start, prev_end = start, end + + # Include rest of the content. + new_lines.append(file_content[prev_end:]) + + # Overwrite with newly parsed content. + with open(mdfile, 'w') as mdfile_iterator: + new_content = ''.join(new_lines) + mdfile_iterator.write(new_content) + + # Given generated markdown files, incorporate them into the docfx_yaml output. # The markdown file metadata will be added to top level of the TOC. def find_markdown_pages(app, outdir): @@ -1294,6 +1340,7 @@ def find_markdown_pages(app, outdir): # For each file, if it is a markdown file move to the top level pages. for mdfile in markdown_dir.iterdir(): if mdfile.is_file() and mdfile.name.lower() not in files_to_ignore: + highlight_md_codeblocks(markdown_dir / mdfile.name) shutil.copy(mdfile, f"{outdir}/{mdfile.name.lower()}") # Extract the header name for TOC. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/markdown_mixed_highlight.md b/packages/gcp-sphinx-docfx-yaml/tests/markdown_mixed_highlight.md new file mode 100644 index 000000000000..1b9c6cd77306 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/markdown_mixed_highlight.md @@ -0,0 +1,15 @@ +```python +These code blocks should not be highlighted. +``` + +```py +As these come with a language indicator. +``` + +```java +Shouldn't matter which langauge indicator is used. +``` + +``` +But this block should get highlighted. +``` diff --git a/packages/gcp-sphinx-docfx-yaml/tests/markdown_mixed_highlight_want.md b/packages/gcp-sphinx-docfx-yaml/tests/markdown_mixed_highlight_want.md new file mode 100644 index 000000000000..6e19859e1404 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/markdown_mixed_highlight_want.md @@ -0,0 +1,15 @@ +```python +These code blocks should not be highlighted. +``` + +```py +As these come with a language indicator. +``` + +```java +Shouldn't matter which langauge indicator is used. +``` + +```python +But this block should get highlighted. +``` diff --git a/packages/gcp-sphinx-docfx-yaml/tests/markdown_no_highlight.md b/packages/gcp-sphinx-docfx-yaml/tests/markdown_no_highlight.md new file mode 100644 index 000000000000..fc4a03fe3792 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/markdown_no_highlight.md @@ -0,0 +1,7 @@ +``` +File with missing codeblock +``` + +``` +with no closing bracket + diff --git a/packages/gcp-sphinx-docfx-yaml/tests/markdown_no_highlight_want.md b/packages/gcp-sphinx-docfx-yaml/tests/markdown_no_highlight_want.md new file mode 100644 index 000000000000..fc4a03fe3792 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/markdown_no_highlight_want.md @@ -0,0 +1,7 @@ +``` +File with missing codeblock +``` + +``` +with no closing bracket + diff --git a/packages/gcp-sphinx-docfx-yaml/tests/markdown_syntax_highlight.md b/packages/gcp-sphinx-docfx-yaml/tests/markdown_syntax_highlight.md new file mode 100644 index 000000000000..d3daf654c4d7 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/markdown_syntax_highlight.md @@ -0,0 +1,9 @@ +``` +test markdown file for +highlighing markdown codeblocks +``` + +``` +all code blocks +should be highlighted +``` diff --git a/packages/gcp-sphinx-docfx-yaml/tests/markdown_syntax_highlight_want.md b/packages/gcp-sphinx-docfx-yaml/tests/markdown_syntax_highlight_want.md new file mode 100644 index 000000000000..5fa792e4c469 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/markdown_syntax_highlight_want.md @@ -0,0 +1,9 @@ +```python +test markdown file for +highlighing markdown codeblocks +``` + +```python +all code blocks +should be highlighted +``` diff --git a/packages/gcp-sphinx-docfx-yaml/tests/test_helpers.py b/packages/gcp-sphinx-docfx-yaml/tests/test_helpers.py index b2b4f51e2947..77e4317cb41a 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/test_helpers.py +++ b/packages/gcp-sphinx-docfx-yaml/tests/test_helpers.py @@ -4,12 +4,15 @@ from docfx_yaml.extension import search_cross_references from docfx_yaml.extension import format_code from docfx_yaml.extension import extract_product_name +from docfx_yaml.extension import highlight_md_codeblocks import unittest from parameterized import parameterized from yaml import load, Loader +import tempfile + class TestGenerate(unittest.TestCase): def test_indent_code_left(self): # Check that the code indents to left based on first line. @@ -190,5 +193,38 @@ def test_extract_product_name(self): self.assertEqual(short_name_want, short_product_name) + + # Filenames to test markdown syntax highlight with. + test_markdown_filenames = [ + [ + "tests/markdown_syntax_highlight.md", + "tests/markdown_syntax_highlight_want.md" + ], + [ + "tests/markdown_no_highlight.md", + "tests/markdown_no_highlight_want.md" + ], + [ + "tests/markdown_mixed_highlight.md", + "tests/markdown_mixed_highlight_want.md" + ], + ] + @parameterized.expand(test_markdown_filenames) + def test_highlight_md_codeblocks(self, base_filename, want_filename): + # Test to ensure codeblocks in markdown files are correctly highlighted. + + # Copy the base file we'll need to test. + with tempfile.NamedTemporaryFile(mode='r+', delete=False) as test_file: + with open(base_filename) as base_file: + test_file.write(base_file.read()) + test_file.flush() + + highlight_md_codeblocks(test_file.name) + test_file.seek(0) + + with open(want_filename) as mdfile_want: + self.assertEqual(test_file.read(), mdfile_want.read()) + + if __name__ == '__main__': unittest.main() From 1d13e91a9971b870597a0194bd569c7a2862fd30 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Fri, 28 Jan 2022 17:56:20 +0100 Subject: [PATCH 107/279] chore(deps): update dependency sphinx to v4.4.0 (#167) Co-authored-by: Dan Lee <71398022+dandhlee@users.noreply.github.com> --- packages/gcp-sphinx-docfx-yaml/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/requirements.txt b/packages/gcp-sphinx-docfx-yaml/requirements.txt index e3aa0c3dabd1..2f2f3f17a2e6 100644 --- a/packages/gcp-sphinx-docfx-yaml/requirements.txt +++ b/packages/gcp-sphinx-docfx-yaml/requirements.txt @@ -2,6 +2,6 @@ black==21.10.b0 parameterized==0.8.1 # google-resumable-media-python requires manual update as this repo isn't templated. # python-api-core also requires manual update as it is not templated. -sphinx==4.3.2 +sphinx==4.4.0 -e . tox From e70c8697fa2073dd6a509f6c484269c7248083f4 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Fri, 28 Jan 2022 17:00:17 +0000 Subject: [PATCH 108/279] chore(main): release 1.4.0 (#171) :robot: I have created a release *beep* *boop* --- ## [1.4.0](https://github.com/googleapis/sphinx-docfx-yaml/compare/v1.3.3...v1.4.0) (2022-01-28) ### Features * add syntax highlighting support for Markdown pages ([#170](https://github.com/googleapis/sphinx-docfx-yaml/issues/170)) ([9898807](https://github.com/googleapis/sphinx-docfx-yaml/commit/98988072c3a32ff1d1be44cb835eea0ad787e8e9)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --- packages/gcp-sphinx-docfx-yaml/CHANGELOG.md | 7 +++++++ packages/gcp-sphinx-docfx-yaml/setup.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md index dc976c756024..9d9f96185913 100644 --- a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md +++ b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.4.0](https://github.com/googleapis/sphinx-docfx-yaml/compare/v1.3.3...v1.4.0) (2022-01-28) + + +### Features + +* add syntax highlighting support for Markdown pages ([#170](https://github.com/googleapis/sphinx-docfx-yaml/issues/170)) ([9898807](https://github.com/googleapis/sphinx-docfx-yaml/commit/98988072c3a32ff1d1be44cb835eea0ad787e8e9)) + ### [1.3.3](https://www.github.com/googleapis/sphinx-docfx-yaml/compare/v1.3.2...v1.3.3) (2021-11-29) diff --git a/packages/gcp-sphinx-docfx-yaml/setup.py b/packages/gcp-sphinx-docfx-yaml/setup.py index 9bf1129f86c0..6278a7539d28 100644 --- a/packages/gcp-sphinx-docfx-yaml/setup.py +++ b/packages/gcp-sphinx-docfx-yaml/setup.py @@ -17,7 +17,7 @@ name = 'gcp-sphinx-docfx-yaml' description = 'Sphinx Python Domain to DocFX YAML Generator' -version = '1.3.3' +version = '1.4.0' dependencies = [ 'black', 'gcp-docuploader', From 78808dc4f01d9bdc888e3a1a862a33890259f04b Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Fri, 28 Jan 2022 16:44:36 -0500 Subject: [PATCH 109/279] fix: enable upgrading docs (#172) --- packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index 4e2e9f4710b1..5bbb381e6e8b 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -1327,9 +1327,6 @@ def find_markdown_pages(app, outdir): "readme.md", # README does not seem to work in cloud site # See https://github.com/googleapis/sphinx-docfx-yaml/issues/107. - - "upgrading.md", # Currently the formatting breaks, will need to come back to it. - # See https://github.com/googleapis/sphinx-docfx-yaml/issues/108. ] markdown_dir = Path(app.builder.outdir).parent / "markdown" From 57cd3ff59fe65562f89871a98fce002239cbd054 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Fri, 28 Jan 2022 16:45:03 -0500 Subject: [PATCH 110/279] chore(main): release 1.4.1 (#173) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/gcp-sphinx-docfx-yaml/CHANGELOG.md | 7 +++++++ packages/gcp-sphinx-docfx-yaml/setup.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md index 9d9f96185913..918a64999a74 100644 --- a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md +++ b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +### [1.4.1](https://github.com/googleapis/sphinx-docfx-yaml/compare/v1.4.0...v1.4.1) (2022-01-28) + + +### Bug Fixes + +* enable upgrading docs ([#172](https://github.com/googleapis/sphinx-docfx-yaml/issues/172)) ([bb68ea9](https://github.com/googleapis/sphinx-docfx-yaml/commit/bb68ea95ded306ccb3513c9684ce2d1ad6b3e74c)) + ## [1.4.0](https://github.com/googleapis/sphinx-docfx-yaml/compare/v1.3.3...v1.4.0) (2022-01-28) diff --git a/packages/gcp-sphinx-docfx-yaml/setup.py b/packages/gcp-sphinx-docfx-yaml/setup.py index 6278a7539d28..3121587f5f04 100644 --- a/packages/gcp-sphinx-docfx-yaml/setup.py +++ b/packages/gcp-sphinx-docfx-yaml/setup.py @@ -17,7 +17,7 @@ name = 'gcp-sphinx-docfx-yaml' description = 'Sphinx Python Domain to DocFX YAML Generator' -version = '1.4.0' +version = '1.4.1' dependencies = [ 'black', 'gcp-docuploader', From 4f606bcc0b6e8801b327bc02f60d4a2804dc2471 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Sun, 30 Jan 2022 00:09:57 +0100 Subject: [PATCH 111/279] chore(deps): update dependency black to v22 (#176) --- packages/gcp-sphinx-docfx-yaml/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/requirements.txt b/packages/gcp-sphinx-docfx-yaml/requirements.txt index 2f2f3f17a2e6..8be7ce8bc18d 100644 --- a/packages/gcp-sphinx-docfx-yaml/requirements.txt +++ b/packages/gcp-sphinx-docfx-yaml/requirements.txt @@ -1,4 +1,4 @@ -black==21.10.b0 +black==22.1.0 parameterized==0.8.1 # google-resumable-media-python requires manual update as this repo isn't templated. # python-api-core also requires manual update as it is not templated. From a2ea3a92b7e9e7e730f5b6e10b77435ec0ccff49 Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Mon, 7 Feb 2022 02:45:11 -0500 Subject: [PATCH 112/279] test: disable 3.6 test (#175) * test: disable 3.6 test and add 3.10 tests * test: update 3.10 version for workflows * test: use collections.abc for py310 * test: omit python versions in tox? * test: disable 3.10 test for now * chore: revert 3.10 import * chore: add `python_requires` to setup.py --- packages/gcp-sphinx-docfx-yaml/.github/workflows/ci.yaml | 2 +- packages/gcp-sphinx-docfx-yaml/setup.py | 1 + packages/gcp-sphinx-docfx-yaml/tox.ini | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/.github/workflows/ci.yaml b/packages/gcp-sphinx-docfx-yaml/.github/workflows/ci.yaml index b5907a26587a..0ae849f1194a 100644 --- a/packages/gcp-sphinx-docfx-yaml/.github/workflows/ci.yaml +++ b/packages/gcp-sphinx-docfx-yaml/.github/workflows/ci.yaml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [3.6, 3.7, 3.8, 3.9] + python-version: [3.7, 3.8, 3.9] steps: - uses: actions/checkout@v2 diff --git a/packages/gcp-sphinx-docfx-yaml/setup.py b/packages/gcp-sphinx-docfx-yaml/setup.py index 3121587f5f04..8a4fa265f77c 100644 --- a/packages/gcp-sphinx-docfx-yaml/setup.py +++ b/packages/gcp-sphinx-docfx-yaml/setup.py @@ -47,6 +47,7 @@ package_dir={'': '.'}, packages=packages, install_requires=dependencies, + python_requires=">=3.7", include_package_data=True, zip_safe=False, **extra_setup diff --git a/packages/gcp-sphinx-docfx-yaml/tox.ini b/packages/gcp-sphinx-docfx-yaml/tox.ini index 4ebd9e354269..7bad2a653407 100644 --- a/packages/gcp-sphinx-docfx-yaml/tox.ini +++ b/packages/gcp-sphinx-docfx-yaml/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py36,py37,py38,py39,lint,docs +envlist = py37,py38,py39,lint,docs [testenv] setenv = From 0d9fdeb1018eec561933858be4936aa5096d3039 Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Mon, 7 Feb 2022 13:26:10 -0500 Subject: [PATCH 113/279] fix: update markdown header parser (#177) * fix: update markdown header parser * test: update unit test --- packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py | 2 +- .../gcp-sphinx-docfx-yaml/tests/markdown_example_header.md | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index 5bbb381e6e8b..5db16494ad3f 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -1234,7 +1234,7 @@ def parse_markdown_header(header_line, prev_line): if not header_line[header_line.index(h1_header_prefix)+2].isspace() and \ len(header_line) > 2: - return header_line.strip("#").strip() + return header_line[header_line.index(h1_header_prefix):].strip("#").strip() elif "=" in header_line: # Check if we're inspecting an empty or undefined lines. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_header.md b/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_header.md index 9a534ce3d700..58d221014824 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_header.md +++ b/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_header.md @@ -9,10 +9,7 @@ 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. ---> - - -# Test header for a simple markdown file. +--> # Test header for a simple markdown file. ##Content header This is a simple line followed by an h2 header. From edfda3485b491b0251773ddbc33c272a856409d2 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Mon, 7 Feb 2022 13:28:25 -0500 Subject: [PATCH 114/279] chore(main): release 1.4.2 (#178) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/gcp-sphinx-docfx-yaml/CHANGELOG.md | 7 +++++++ packages/gcp-sphinx-docfx-yaml/setup.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md index 918a64999a74..de74e390a092 100644 --- a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md +++ b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +### [1.4.2](https://github.com/googleapis/sphinx-docfx-yaml/compare/v1.4.1...v1.4.2) (2022-02-07) + + +### Bug Fixes + +* update markdown header parser ([#177](https://github.com/googleapis/sphinx-docfx-yaml/issues/177)) ([71d50cc](https://github.com/googleapis/sphinx-docfx-yaml/commit/71d50cce1979a8673499f731411798bfb15c7ba6)) + ### [1.4.1](https://github.com/googleapis/sphinx-docfx-yaml/compare/v1.4.0...v1.4.1) (2022-01-28) diff --git a/packages/gcp-sphinx-docfx-yaml/setup.py b/packages/gcp-sphinx-docfx-yaml/setup.py index 8a4fa265f77c..218d34abe6ba 100644 --- a/packages/gcp-sphinx-docfx-yaml/setup.py +++ b/packages/gcp-sphinx-docfx-yaml/setup.py @@ -17,7 +17,7 @@ name = 'gcp-sphinx-docfx-yaml' description = 'Sphinx Python Domain to DocFX YAML Generator' -version = '1.4.1' +version = '1.4.2' dependencies = [ 'black', 'gcp-docuploader', From 7e1d89a46ae274aedcf9ffd5198898b9161df1f1 Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Thu, 10 Feb 2022 05:34:48 -0500 Subject: [PATCH 115/279] fix: use `id` field for Attributes instead of `name` (#179) * fix: use `id` instead of `name` for Attributes * test: update unit test and testdata --- packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py | 8 ++++---- .../tests/cross_references_post.yaml | 4 ++-- .../gcp-sphinx-docfx-yaml/tests/cross_references_pre.yaml | 4 ++-- packages/gcp-sphinx-docfx-yaml/tests/test_unit.py | 8 ++++---- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index 5db16494ad3f..7942da1cc411 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -448,7 +448,7 @@ def _parse_docstring_summary(summary): keyword = "" if name and description and var_type: attributes.append({ - "name": name, + "id": name, "description": description, "var_type": var_type }) @@ -1447,9 +1447,9 @@ def search_cross_references(obj, current_name: str, entry_names: List[str]): entry_names ) - if attribute.get("name"): - attribute["name"] = convert_cross_references( - attribute["name"], + if attribute.get("id"): + attribute["id"] = convert_cross_references( + attribute["id"], current_name, entry_names ) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/cross_references_post.yaml b/packages/gcp-sphinx-docfx-yaml/tests/cross_references_post.yaml index 366c79c8fc70..a7be51817b7b 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/cross_references_post.yaml +++ b/packages/gcp-sphinx-docfx-yaml/tests/cross_references_post.yaml @@ -7,10 +7,10 @@ items: \ \"date_field = CAST('2014-9-27' as\n DATE)\" \"nullable_field is not NULL\"\ \ \"st_equals(geo_field,\n st_geofromtext(\"POINT(2, 2)\"))\" \"numeric_field\ \ BETWEEN 1.0\n AND 5.0\"\n \n Restricted to a maximum length for 1 MB." - name: google.cloud.bigquery_storage_v1.types.StreamStats + id: google.cloud.bigquery_storage_v1.types.StreamStats var_type: str - description: "Optional. Options specific to the Apache\n Arrow output format." - name: arrow_serialization_options + id: arrow_serialization_options var_type: google.cloud.bigquery_storage_v1.types.ArrowSerializationOptions children: [] class: google.cloud.bigquery_storage_v1.types.ReadSession.TableReadOptions diff --git a/packages/gcp-sphinx-docfx-yaml/tests/cross_references_pre.yaml b/packages/gcp-sphinx-docfx-yaml/tests/cross_references_pre.yaml index 4529cc4d94ee..d7d65b800f41 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/cross_references_pre.yaml +++ b/packages/gcp-sphinx-docfx-yaml/tests/cross_references_pre.yaml @@ -7,10 +7,10 @@ items: \ \"date_field = CAST('2014-9-27' as\n DATE)\" \"nullable_field is not NULL\"\ \ \"st_equals(geo_field,\n st_geofromtext(\"POINT(2, 2)\"))\" \"numeric_field\ \ BETWEEN 1.0\n AND 5.0\"\n \n Restricted to a maximum length for 1 MB." - name: google.cloud.bigquery_storage_v1.types.StreamStats + id: google.cloud.bigquery_storage_v1.types.StreamStats var_type: str - description: "Optional. Options specific to the Apache\n Arrow output format." - name: arrow_serialization_options + id: arrow_serialization_options var_type: google.cloud.bigquery_storage_v1.types.ArrowSerializationOptions children: [] class: google.cloud.bigquery_storage_v1.types.ReadSession.TableReadOptions diff --git a/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py b/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py index 8ee6000e4955..6fee6c328ba9 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py +++ b/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py @@ -815,7 +815,7 @@ def test_parse_docstring_summary_attributes(self): # Test parsing docstring with attributes. attributes_want = [ { - "name": "simple name", + "id": "simple name", "description": "simple description", "var_type": 'str' } @@ -837,12 +837,12 @@ def test_parse_docstring_summary_attributes(self): # Check multiple attributes are parsed. attributes_want = [ { - "name": "simple name", + "id": "simple name", "description": "simple description", "var_type": "str" }, { - "name": "table_insert_request", + "id": "table_insert_request", "description": "Table insert request.", "var_type": "google.cloud.bigquery_logging_v1.types.TableInsertRequest" } @@ -874,7 +874,7 @@ def test_parse_docstring_summary_attributes(self): # Check only attributes in valid format gets parsed. attributes_want = [ { - "name": "proper name", + "id": "proper name", "description": "proper description.", "var_type": "str" } From 095ce1f23ee14fee2e03289aa4076707a85ffa7a Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Tue, 15 Feb 2022 17:44:45 -0500 Subject: [PATCH 116/279] fix: retrieve constructors (#181) --- .../docfx_yaml/extension.py | 50 +++++++++++++------ 1 file changed, 36 insertions(+), 14 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index 7942da1cc411..a32a8e93f64a 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -717,7 +717,7 @@ def _update_friendly_package_name(path): # Check how many arguments are present in the function. arg_count = 0 try: - if _type in [METHOD, FUNCTION]: + if _type in [METHOD, FUNCTION, CLASS]: argspec = inspect.getfullargspec(obj) # noqa type_map = {} if argspec.annotations: @@ -773,11 +773,11 @@ def _update_friendly_package_name(path): except IndexError: pass try: - lines = inspect.getdoc(obj) - lines = lines.split("\n") if lines else [] + if len(lines) == 0: + lines = inspect.getdoc(obj) + lines = lines.split("\n") if lines else [] except TypeError as e: print("couldn't getdoc from method, function: {}".format(e)) - elif _type in [PROPERTY]: lines = inspect.getdoc(obj) lines = lines.split("\n") if lines else [] @@ -890,24 +890,35 @@ def _update_friendly_package_name(path): if args or arg_count > 0: variables = summary_info['variables'] arg_id = [] + incomplete_args = [] for arg in args: arg_id.append(arg['id']) if arg['id'] in variables: # Retrieve argument info from extracted map of variable info arg_var = variables[arg['id']] - arg['var_type'] = arg_var.get('var_type') if arg_var.get('var_type') else '' - arg['description'] = arg_var.get('description') if arg_var.get('description') else '' + arg['var_type'] = arg_var.get('var_type') + arg['description'] = arg_var.get('description') + + # Only add arguments with type and description. + if not (arg.get('var_type') and arg.get('description')): + incomplete_args.append(arg) + + # Remove any arguments with missing type or description from the YAML. + for incomplete_arg in incomplete_args: + args.remove(incomplete_arg) # Add any variables we might have missed from extraction. for variable in variables: if variable not in arg_id: - new_arg = { - "id": variable, - "var_type": variables[variable].get('var_type'), - "description": variables[variable].get('description') - } - args.append(new_arg) + # Only include arguments with type and description. + if variables[variable].get('var_type') and variables[variable].get('description'): + new_arg = { + "id": variable, + "var_type": variables[variable].get('var_type'), + "description": variables[variable].get('description') + } + args.append(new_arg) datam['syntax']['parameters'] = args @@ -941,9 +952,18 @@ def process_docstring(app, _type, name, obj, options, lines): This function takes the docstring and indexes it into memory. """ + cls = "" + module = "" + # Check if we already processed this docstring. if name in app.env.docfx_uid_names: - return + if _type != CLASS: + return + else: + # If we run into the same docstring twice for a class it's a + # constructor. Change the constructor type from CLASS to METHOD. + cls, module = _get_cls_module(_type, name) + _type = METHOD # Register current docstring to a set. app.env.docfx_uid_names[name] = '' @@ -952,7 +972,9 @@ def process_docstring(app, _type, name, obj, options, lines): if _type == EXCEPTION: _type = CLASS - cls, module = _get_cls_module(_type, name) + if not cls and not module: + cls, module = _get_cls_module(_type, name) + if not module and _type != PROPERTY: print('Unknown Type: %s' % _type) return None From fa552c7c571e6b7b99269fb814901f23e25b6d04 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Tue, 15 Feb 2022 17:46:48 -0500 Subject: [PATCH 117/279] chore(main): release 1.4.3 (#180) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/gcp-sphinx-docfx-yaml/CHANGELOG.md | 8 ++++++++ packages/gcp-sphinx-docfx-yaml/setup.py | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md index de74e390a092..7ea1b7638826 100644 --- a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md +++ b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +### [1.4.3](https://github.com/googleapis/sphinx-docfx-yaml/compare/v1.4.2...v1.4.3) (2022-02-15) + + +### Bug Fixes + +* retrieve constructors ([#181](https://github.com/googleapis/sphinx-docfx-yaml/issues/181)) ([1e6efa4](https://github.com/googleapis/sphinx-docfx-yaml/commit/1e6efa4007e3191ad07dd4e82fcb06a8fd1be746)) +* use `id` field for Attributes instead of `name` ([#179](https://github.com/googleapis/sphinx-docfx-yaml/issues/179)) ([fa38c8c](https://github.com/googleapis/sphinx-docfx-yaml/commit/fa38c8ce98b92a460755c8db548cfee9309812c7)) + ### [1.4.2](https://github.com/googleapis/sphinx-docfx-yaml/compare/v1.4.1...v1.4.2) (2022-02-07) diff --git a/packages/gcp-sphinx-docfx-yaml/setup.py b/packages/gcp-sphinx-docfx-yaml/setup.py index 218d34abe6ba..cf20199ffdae 100644 --- a/packages/gcp-sphinx-docfx-yaml/setup.py +++ b/packages/gcp-sphinx-docfx-yaml/setup.py @@ -17,7 +17,7 @@ name = 'gcp-sphinx-docfx-yaml' description = 'Sphinx Python Domain to DocFX YAML Generator' -version = '1.4.2' +version = '1.4.3' dependencies = [ 'black', 'gcp-docuploader', From 2d9c5ef78d564351a65569df881b2bdc4804aecb Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Wed, 23 Feb 2022 12:16:36 -0500 Subject: [PATCH 118/279] test: update generate-docs for multi-version (#184) * test: update generate-docs for multi-version * test: increase build timeout --- packages/gcp-sphinx-docfx-yaml/.kokoro/docs/common.cfg | 4 ++++ packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh | 2 ++ 2 files changed, 6 insertions(+) diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/docs/common.cfg b/packages/gcp-sphinx-docfx-yaml/.kokoro/docs/common.cfg index 10ea6841569e..2da648a9b9b9 100644 --- a/packages/gcp-sphinx-docfx-yaml/.kokoro/docs/common.cfg +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/docs/common.cfg @@ -1,5 +1,9 @@ # Format: //devtools/kokoro/config/proto/build.proto +# Timeout set to 120 hours to support for all tags for each library being +# generated. +timeout_mins: 7200 + # Build logs will be here action { define_artifacts { diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh b/packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh index 125bf5aa0fbb..dcf1afd818e8 100755 --- a/packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh @@ -72,6 +72,8 @@ for bucket_item in $(gsutil ls 'gs://docs-staging-v2/docfx-python*' | sort -u -t fi for tag in ${GITHUB_TAGS}; do + # Ensure noxfile.py is reverted so merge conflicts do not occur. + git restore "noxfile.py" git checkout ${tag} # Use the latest noxfile for all tags. From 4d6851f178bf267bc1c930160d828d830d732596 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Tue, 1 Mar 2022 00:15:54 +0100 Subject: [PATCH 119/279] chore(deps): update actions/setup-python action to v3 (#185) --- packages/gcp-sphinx-docfx-yaml/.github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/.github/workflows/ci.yaml b/packages/gcp-sphinx-docfx-yaml/.github/workflows/ci.yaml index 0ae849f1194a..04720700bdc6 100644 --- a/packages/gcp-sphinx-docfx-yaml/.github/workflows/ci.yaml +++ b/packages/gcp-sphinx-docfx-yaml/.github/workflows/ci.yaml @@ -12,7 +12,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v3 with: python-version: ${{ matrix.python-version }} - name: Install dependencies From 295a303a53848dace7c63c2a624fd1830092b279 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Tue, 1 Mar 2022 21:03:47 +0100 Subject: [PATCH 120/279] chore(deps): update actions/checkout action to v3 (#186) --- packages/gcp-sphinx-docfx-yaml/.github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/.github/workflows/ci.yaml b/packages/gcp-sphinx-docfx-yaml/.github/workflows/ci.yaml index 04720700bdc6..5a93820e930f 100644 --- a/packages/gcp-sphinx-docfx-yaml/.github/workflows/ci.yaml +++ b/packages/gcp-sphinx-docfx-yaml/.github/workflows/ci.yaml @@ -10,7 +10,7 @@ jobs: python-version: [3.7, 3.8, 3.9] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v3 with: From 571c2c0e08ffaa5bc73ef7c847fd7e8c53b01186 Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Thu, 3 Mar 2022 14:47:48 -0500 Subject: [PATCH 121/279] fix: parse docstring that come without summaries (#187) * fix: parse docstring with no summary given * test: update unit test for parsing docstring with no summary --- .../docfx_yaml/extension.py | 4 +-- .../gcp-sphinx-docfx-yaml/tests/test_unit.py | 25 +++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index a32a8e93f64a..c80ed137d303 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -582,8 +582,8 @@ def _extract_docstring_info(summary_info, summary, name): # if we found empty array for indexes, stop processing further. index = min(indexes) if indexes else 0 - # Store the top summary separately. - if index == 0: + # Store the top summary separately. Ensure that the docstring is not empty. + if index == 0 and not indexes: return summary top_summary = parsed_text[:index] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py b/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py index 6fee6c328ba9..6de88db39daf 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py +++ b/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py @@ -431,6 +431,31 @@ def test_extract_docstring_info_with_xref(self): self.assertDictEqual(summary_info_got, summary_info_want) + def test_extract_docstring_info_no_summary(self): + ## Test parsing docstring with no summary. + summary =( +"""Args: + arg1(int): simple description. + arg2(str): simple description for `arg2`. + +Returns: + str: simple description for return value. + +Raises: + AttributeError: if `condition x`. +""" + ) + summary_info_got = { + 'variables': {}, + 'returns': [], + 'exceptions': [] + } + + top_summary_got = _extract_docstring_info(summary_info_got, summary, "") + self.assertEqual(top_summary_got, "") + self.assertDictEqual(summary_info_got, self.summary_info1_want) + + def test_find_package_group(self): package_group_want = "google.cloud.spanner_v1beta2" uid = "google.cloud.spanner_v1beta2.services.admin_database_v1.types" From 7c5cf3a51037a00b47df013c27e963b43b13c107 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Thu, 3 Mar 2022 14:52:04 -0500 Subject: [PATCH 122/279] chore(main): release 1.4.4 (#188) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/gcp-sphinx-docfx-yaml/CHANGELOG.md | 7 +++++++ packages/gcp-sphinx-docfx-yaml/setup.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md index 7ea1b7638826..a3a8186afcc0 100644 --- a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md +++ b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +### [1.4.4](https://github.com/googleapis/sphinx-docfx-yaml/compare/v1.4.3...v1.4.4) (2022-03-03) + + +### Bug Fixes + +* parse docstring that come without summaries ([#187](https://github.com/googleapis/sphinx-docfx-yaml/issues/187)) ([8282604](https://github.com/googleapis/sphinx-docfx-yaml/commit/8282604105893a8834cbee09cd9e0080340f31de)) + ### [1.4.3](https://github.com/googleapis/sphinx-docfx-yaml/compare/v1.4.2...v1.4.3) (2022-02-15) diff --git a/packages/gcp-sphinx-docfx-yaml/setup.py b/packages/gcp-sphinx-docfx-yaml/setup.py index cf20199ffdae..c705274301b9 100644 --- a/packages/gcp-sphinx-docfx-yaml/setup.py +++ b/packages/gcp-sphinx-docfx-yaml/setup.py @@ -17,7 +17,7 @@ name = 'gcp-sphinx-docfx-yaml' description = 'Sphinx Python Domain to DocFX YAML Generator' -version = '1.4.3' +version = '1.4.4' dependencies = [ 'black', 'gcp-docuploader', From 4700ebe6095c9c7fcf388a46481092f80a9f8c7e Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Tue, 8 Mar 2022 11:17:49 -0500 Subject: [PATCH 123/279] test: retrieve unique package and latest version for YAML generation (#190) * test: fix unique tarball retrieval to latest version * test: retrieve package name by parsing the entries --- .../gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh b/packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh index dcf1afd818e8..d98896ea3fe4 100755 --- a/packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh @@ -36,16 +36,23 @@ python3 -m pip install recommonmark # Required for some client libraries: python3 -m pip install --user django==2.2 ipython +# Store the contents of bucket log in a variable to reuse. +python_bucket_items=$(gsutil ls "gs://docs-staging-v2/docfx-python*") # Retrieve unique repositories to regenerate the YAML with. -for bucket_item in $(gsutil ls 'gs://docs-staging-v2/docfx-python*' | sort -u -t- -k5,5); do +for package in $(echo "${python_bucket_items}" | cut -d "-" -f 5- | rev | cut -d "-" -f 2- | rev | uniq); do - # Retrieve the GitHub Repository info. + # Extract the latest version of the package to grab latest metadata. + version=$(echo "${python_bucket_items}" | grep "docfx-python-${package}-" | rev | cut -d "-" -f 1 | rev | sort -V -r | head -1) + + # Set the bucket and tarball values to be used for the package. + bucket_item=$(echo "gs://docs-staging-v2/docfx-python-${package}-${version}") tarball=$(echo ${bucket_item} | cut -d "/" -f 4) # Make temporary directory to extract tarball content. mkdir ${tarball} cd ${tarball} + # Retrieve the GitHub Repository info. gsutil cp ${bucket_item} . tar -zxvf ${tarball} repo=$(cat docs.metadata | grep "github_repository:" | cut -d "\"" -f 2 | cut -d "/" -f 2) From c9d0144a356acb17645865553d66b445d721c9e6 Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Fri, 18 Mar 2022 10:21:51 -0400 Subject: [PATCH 124/279] fix: format code snippets properly (#193) * fix: format code snippets properly * test: update unit test * test: add unit test for testing with blocks of code snippet * test: parameterize unit test for indent_left * docs: add docstring to indent_code_left method --- .../docfx_yaml/extension.py | 28 ++++++--- .../tests/test_helpers.py | 62 ++++++++++++++----- 2 files changed, 69 insertions(+), 21 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index c80ed137d303..43062b0080a5 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -386,13 +386,17 @@ def extract_keyword(line): return line -# Given lines of code, indent to left by 1 block, based on -# amount of trailing white space of first line as 1 block. -def indent_code_left(lines): +def indent_code_left(lines, tab_space): + """Indents code lines left by tab_space. + + Args: + lines: String lines of code. + tab_space: Number of spaces to indent to left by. + + Returns: + String lines of left-indented code. + """ parts = lines.split("\n") - # Count how much leading whitespaces there are based on first line. - # lstrip(" ") removes all trailing whitespace from the string. - tab_space = len(parts[0]) - len(parts[0].lstrip(" ")) parts = [part[tab_space:] for part in parts] return "\n".join(parts) @@ -417,6 +421,9 @@ def _parse_docstring_summary(summary): if keyword and keyword in [CODE, CODEBLOCK]: # If we reach the end of keyword, close up the code block. if not part.startswith(" "*tab_space) or part.startswith(".."): + if code_snippet: + parts = [indent_code_left(part, tab_space) for part in code_snippet] + summary_parts.append("\n\n".join(parts)) summary_parts.append("```\n") keyword = "" @@ -428,9 +435,12 @@ def _parse_docstring_summary(summary): raise ValueError(f"Code in the code block should be indented. Please check the docstring: \n{summary}") if not part.startswith(" "*tab_space): # No longer looking at code-block, reset keyword. + if code_snippet: + parts = [indent_code_left(part, tab_space) for part in code_snippet] + summary_parts.append("\n\n".join(parts)) keyword = "" summary_parts.append("```\n") - summary_parts.append(indent_code_left(part)) + code_snippet.append(part) continue # Attributes come in 3 parts, parse the latter two here. @@ -472,6 +482,7 @@ def _parse_docstring_summary(summary): language = part.split("::")[1].strip() summary_parts.append(f"```{language}") + code_snippet = [] tab_space = -1 # Extract the name for attribute first. @@ -490,6 +501,9 @@ def _parse_docstring_summary(summary): # Close up from the keyword if needed. if keyword and keyword in [CODE, CODEBLOCK]: # Check if it's already closed. + if code_snippet: + parts = [indent_code_left(part, tab_space) for part in code_snippet] + summary_parts.append("\n\n".join(parts)) if summary_parts[-1] != "```\n": summary_parts.append("```\n") diff --git a/packages/gcp-sphinx-docfx-yaml/tests/test_helpers.py b/packages/gcp-sphinx-docfx-yaml/tests/test_helpers.py index 77e4317cb41a..dc74a403f890 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/test_helpers.py +++ b/packages/gcp-sphinx-docfx-yaml/tests/test_helpers.py @@ -14,24 +14,33 @@ import tempfile class TestGenerate(unittest.TestCase): - def test_indent_code_left(self): + code_testdata = [ # Check that the code indents to left based on first line. - code_want = \ -"""def foo(): - print('test function for indent') - return ('left-indented-code') -""" - - code = \ + [ + \ """ def foo(): print('test function for indent') return ('left-indented-code') +""", + \ +"""def foo(): + print('test function for indent') + return ('left-indented-code') """ - code = indent_code_left(code) - self.assertEqual(code, code_want) - + ], # Check that if there's no whitespace, it does not indent - code_want = \ + [ + \ +""" +print('test function for no impact indent') +for i in range(10): + print(i) + if i%5 == 0: + i += 1 + else: + continue +""", + \ """ print('test function for no impact indent') for i in range(10): @@ -41,9 +50,34 @@ def test_indent_code_left(self): else: continue """ + ], + ] + @parameterized.expand(code_testdata) + def test_indent_code_left(self, code, code_want): + parts = code.split("\n") + tab_space = len(parts[0]) - len(parts[0].lstrip(" ")) + code_got = indent_code_left(code, tab_space) + self.assertEqual(code_got, code_want) + - code_got = indent_code_left(code_want) - # Confirm that nothing changes. + def test_indent_code_blocks_left(self): + # Check code blocks are indented properly. + code_want = \ +"""def foo(): + + print('test function for indent') + + return ('left-indented-blocks') +""" + + # Test with how blocks would appear in the code block + code = [ + " def foo():", + " print('test function for indent')", + " return ('left-indented-blocks')\n" + ] + tab_space = len(code[0]) - len(code[0].lstrip(" ")) + code_got = "\n\n".join([indent_code_left(part, tab_space) for part in code]) self.assertEqual(code_got, code_want) From 68c54d55fdac127b6c8a88308034b1eddf2c46f0 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Fri, 18 Mar 2022 10:34:11 -0400 Subject: [PATCH 125/279] chore(main): release 1.4.5 (#195) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/gcp-sphinx-docfx-yaml/CHANGELOG.md | 7 +++++++ packages/gcp-sphinx-docfx-yaml/setup.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md index a3a8186afcc0..ebb2dc6848e7 100644 --- a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md +++ b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +### [1.4.5](https://github.com/googleapis/sphinx-docfx-yaml/compare/v1.4.4...v1.4.5) (2022-03-18) + + +### Bug Fixes + +* format code snippets properly ([#193](https://github.com/googleapis/sphinx-docfx-yaml/issues/193)) ([ef7a337](https://github.com/googleapis/sphinx-docfx-yaml/commit/ef7a3370756ba20cc78ad8193abfaaf5cd268f0c)) + ### [1.4.4](https://github.com/googleapis/sphinx-docfx-yaml/compare/v1.4.3...v1.4.4) (2022-03-03) diff --git a/packages/gcp-sphinx-docfx-yaml/setup.py b/packages/gcp-sphinx-docfx-yaml/setup.py index c705274301b9..36eb787d8e5f 100644 --- a/packages/gcp-sphinx-docfx-yaml/setup.py +++ b/packages/gcp-sphinx-docfx-yaml/setup.py @@ -17,7 +17,7 @@ name = 'gcp-sphinx-docfx-yaml' description = 'Sphinx Python Domain to DocFX YAML Generator' -version = '1.4.4' +version = '1.4.5' dependencies = [ 'black', 'gcp-docuploader', From 810349ec54b16d0dc8df0b3f1880fc80cf6cab09 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Tue, 29 Mar 2022 18:02:52 +0200 Subject: [PATCH 126/279] chore(deps): update dependency black to v22.3.0 (#197) --- packages/gcp-sphinx-docfx-yaml/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/requirements.txt b/packages/gcp-sphinx-docfx-yaml/requirements.txt index 8be7ce8bc18d..ee29b9dc76cb 100644 --- a/packages/gcp-sphinx-docfx-yaml/requirements.txt +++ b/packages/gcp-sphinx-docfx-yaml/requirements.txt @@ -1,4 +1,4 @@ -black==22.1.0 +black==22.3.0 parameterized==0.8.1 # google-resumable-media-python requires manual update as this repo isn't templated. # python-api-core also requires manual update as it is not templated. From 68b59c4f55104f64af88f0e49063bef8940fdf58 Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Thu, 31 Mar 2022 20:43:23 -0400 Subject: [PATCH 127/279] chore(python): update .pre-commit-config.yaml to use black==22.3.0 (#198) Source-Link: https://github.com/googleapis/synthtool/commit/7804ade3daae0d66649bee8df6c55484c6580b8d Post-Processor: gcr.io/cloud-devrel-public-resources/owlbot-python:latest@sha256:eede5672562a32821444a8e803fb984a6f61f2237ea3de229d2de24453f4ae7d Co-authored-by: Owl Bot --- packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml | 3 ++- packages/gcp-sphinx-docfx-yaml/.pre-commit-config.yaml | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml index 8cb43804d999..22cc254afa2c 100644 --- a/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml +++ b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml @@ -13,4 +13,5 @@ # limitations under the License. docker: image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest - digest: sha256:ed1f9983d5a935a89fe8085e8bb97d94e41015252c5b6c9771257cf8624367e6 + digest: sha256:eede5672562a32821444a8e803fb984a6f61f2237ea3de229d2de24453f4ae7d +# created: 2022-03-30T23:44:26.560599165Z diff --git a/packages/gcp-sphinx-docfx-yaml/.pre-commit-config.yaml b/packages/gcp-sphinx-docfx-yaml/.pre-commit-config.yaml index 62eb5a77d9a3..46d237160f6d 100644 --- a/packages/gcp-sphinx-docfx-yaml/.pre-commit-config.yaml +++ b/packages/gcp-sphinx-docfx-yaml/.pre-commit-config.yaml @@ -22,7 +22,7 @@ repos: - id: end-of-file-fixer - id: check-yaml - repo: https://github.com/psf/black - rev: 19.10b0 + rev: 22.3.0 hooks: - id: black - repo: https://gitlab.com/pycqa/flake8 From 32c3d1a311cd424b52516028a493156cf0360f36 Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Thu, 31 Mar 2022 22:22:32 -0400 Subject: [PATCH 128/279] chore(python): Enable size-label bot (#199) Source-Link: https://github.com/googleapis/synthtool/commit/06e82790dd719a165ad32b8a06f8f6ec3e3cae0f Post-Processor: gcr.io/cloud-devrel-public-resources/owlbot-python:latest@sha256:b3500c053313dc34e07b1632ba9e4e589f4f77036a7cf39e1fe8906811ae0fce Co-authored-by: Owl Bot --- packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml | 4 ++-- packages/gcp-sphinx-docfx-yaml/.github/auto-label.yaml | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 packages/gcp-sphinx-docfx-yaml/.github/auto-label.yaml diff --git a/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml index 22cc254afa2c..58a0b153bf0e 100644 --- a/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml +++ b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml @@ -13,5 +13,5 @@ # limitations under the License. docker: image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest - digest: sha256:eede5672562a32821444a8e803fb984a6f61f2237ea3de229d2de24453f4ae7d -# created: 2022-03-30T23:44:26.560599165Z + digest: sha256:b3500c053313dc34e07b1632ba9e4e589f4f77036a7cf39e1fe8906811ae0fce +# created: 2022-04-01T01:42:03.609279246Z diff --git a/packages/gcp-sphinx-docfx-yaml/.github/auto-label.yaml b/packages/gcp-sphinx-docfx-yaml/.github/auto-label.yaml new file mode 100644 index 000000000000..09c8d735b456 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/.github/auto-label.yaml @@ -0,0 +1,2 @@ +requestsize: + enabled: true From d919d94c6b1640432234cd0f9c206738adb35274 Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Wed, 6 Apr 2022 07:00:04 -0400 Subject: [PATCH 129/279] chore(python): add license header to auto-label.yaml (#201) Source-Link: https://github.com/googleapis/synthtool/commit/eb78c980b52c7c6746d2edb77d9cf7aaa99a2aab Post-Processor: gcr.io/cloud-devrel-public-resources/owlbot-python:latest@sha256:8a5d3f6a2e43ed8293f34e06a2f56931d1e88a2694c3bb11b15df4eb256ad163 Co-authored-by: Owl Bot --- .../gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml | 4 ++-- .../gcp-sphinx-docfx-yaml/.github/auto-label.yaml | 13 +++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml index 58a0b153bf0e..bc893c979e20 100644 --- a/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml +++ b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml @@ -13,5 +13,5 @@ # limitations under the License. docker: image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest - digest: sha256:b3500c053313dc34e07b1632ba9e4e589f4f77036a7cf39e1fe8906811ae0fce -# created: 2022-04-01T01:42:03.609279246Z + digest: sha256:8a5d3f6a2e43ed8293f34e06a2f56931d1e88a2694c3bb11b15df4eb256ad163 +# created: 2022-04-06T10:30:21.687684602Z diff --git a/packages/gcp-sphinx-docfx-yaml/.github/auto-label.yaml b/packages/gcp-sphinx-docfx-yaml/.github/auto-label.yaml index 09c8d735b456..41bff0b5375a 100644 --- a/packages/gcp-sphinx-docfx-yaml/.github/auto-label.yaml +++ b/packages/gcp-sphinx-docfx-yaml/.github/auto-label.yaml @@ -1,2 +1,15 @@ +# Copyright 2022 Google LLC +# +# 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. requestsize: enabled: true From 323b0e4d6099df528909d6f25edbc6b622728f24 Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Wed, 6 Apr 2022 08:57:22 -0400 Subject: [PATCH 130/279] fix: support parsing summary docstring that is not well formed (#200) * fix: support parsing summary docstring even if it not well formed * test: update unit test * chore: remove unneeded TODO comment Co-authored-by: Anthonios Partheniou --- packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py | 5 +++-- packages/gcp-sphinx-docfx-yaml/tests/test_unit.py | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index 43062b0080a5..b5691efa25c4 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -469,9 +469,10 @@ def _parse_docstring_summary(summary): continue # Parse keywords if found. - if part.startswith(".."): + # lstrip is added to parse code blocks that are not formatted well. + if part.lstrip('\n').startswith('..'): try: - keyword = extract_keyword(part) + keyword = extract_keyword(part.lstrip('\n')) except ValueError: raise ValueError(f"Please check the docstring: \n{summary}") # Works for both code-block and code diff --git a/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py b/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py index 6de88db39daf..6cfd7dc61bed 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py +++ b/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py @@ -736,6 +736,7 @@ def test_extract_header_from_markdown_bad_headers(self): self.assertEqual(header_line_want, header_line_got) + def test_parse_docstring_summary(self): # Check that the summary gets parsed correctly. attributes_want = [] @@ -794,7 +795,7 @@ def get_client_cert(): You can also pass a mapping object. -.. code-block:: ruby +\n.. code-block:: ruby \n from google.cloud.vision_v1 import ImageAnnotatorClient \n client = ImageAnnotatorClient( From beca6968df04d61f8a666391d1dc800820f62881 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Wed, 6 Apr 2022 08:59:46 -0400 Subject: [PATCH 131/279] chore(main): release 1.4.6 (#202) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/gcp-sphinx-docfx-yaml/CHANGELOG.md | 7 +++++++ packages/gcp-sphinx-docfx-yaml/setup.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md index ebb2dc6848e7..ba755916fd90 100644 --- a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md +++ b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +### [1.4.6](https://github.com/googleapis/sphinx-docfx-yaml/compare/v1.4.5...v1.4.6) (2022-04-06) + + +### Bug Fixes + +* support parsing summary docstring that is not well formed ([#200](https://github.com/googleapis/sphinx-docfx-yaml/issues/200)) ([a1b362d](https://github.com/googleapis/sphinx-docfx-yaml/commit/a1b362d611be6a60d19e2b5b06806554eea111f5)) + ### [1.4.5](https://github.com/googleapis/sphinx-docfx-yaml/compare/v1.4.4...v1.4.5) (2022-03-18) diff --git a/packages/gcp-sphinx-docfx-yaml/setup.py b/packages/gcp-sphinx-docfx-yaml/setup.py index 36eb787d8e5f..e921a96001df 100644 --- a/packages/gcp-sphinx-docfx-yaml/setup.py +++ b/packages/gcp-sphinx-docfx-yaml/setup.py @@ -17,7 +17,7 @@ name = 'gcp-sphinx-docfx-yaml' description = 'Sphinx Python Domain to DocFX YAML Generator' -version = '1.4.5' +version = '1.4.6' dependencies = [ 'black', 'gcp-docuploader', From 7fa72e8fde434656c1df249fe3b30d5e4f9847fc Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Tue, 12 Apr 2022 14:35:11 -0400 Subject: [PATCH 132/279] fix: add markdown header if it is missing (#203) * fix: add a Markdown header level 1 if it is missing * test: update unit test * fix: update name from prepend_markdown_title to prepend_markdown_header * test: update unit test * fix: update comments based on code review * test: update unit test with comments and parameterized tests * test: update unit test * fix: update docstring with types * fix: update type hint for Iterables --- .../docfx_yaml/extension.py | 46 ++++++-- .../markdown_example_alternate_bad_want.md | 8 ++ .../tests/markdown_example_bad_header_want.md | 6 ++ .../tests/markdown_example_h2_want.md | 6 ++ .../tests/test_helpers.py | 36 +++++++ .../gcp-sphinx-docfx-yaml/tests/test_unit.py | 101 +++++++++--------- 6 files changed, 143 insertions(+), 60 deletions(-) create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/markdown_example_alternate_bad_want.md create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/markdown_example_bad_header_want.md create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/markdown_example_h2_want.md diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index b5691efa25c4..53c3cd9c5957 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -29,7 +29,7 @@ from pathlib import Path from functools import partial from itertools import zip_longest -from typing import List +from typing import List, Iterable from black import InvalidInput try: @@ -1286,12 +1286,18 @@ def parse_markdown_header(header_line, prev_line): return "" -# For a given markdown file, extract its header line. -def extract_header_from_markdown(mdfile_iterator): - mdfile_name = mdfile_iterator.name.split("/")[-1].split(".")[0].capitalize() +def extract_header_from_markdown(mdfile: Iterable[str]) -> str: + """For a given markdown file, extract its header line. + + Args: + mdfile: iterator to the markdown file. + + Returns: + A string for header or empty string if header is not found. + """ prev_line = "" - for header_line in mdfile_iterator: + for header_line in mdfile: # Ignore licenses and other non-headers prior to the header. header = parse_markdown_header(header_line, prev_line) @@ -1301,8 +1307,7 @@ def extract_header_from_markdown(mdfile_iterator): prev_line = header_line - print(f"Could not find a title for {mdfile_iterator.name}. Using {mdfile_name} as the title instead.") - return mdfile_name + return "" # For a given markdown file, adds syntax highlighting to code blocks. @@ -1351,6 +1356,20 @@ def highlight_md_codeblocks(mdfile): mdfile_iterator.write(new_content) +def prepend_markdown_header(filename: str, mdfile: Iterable[str]): + """Prepends the filename as a Markdown header. + + Args: + filename: the name of the markdown file to prepend. + mdfile: iterator to the markdown file that is both readable + and writable. + """ + file_content = f'# {filename}\n\n' + mdfile.read() + # Reset file position to the beginning to write + mdfile.seek(0) + mdfile.write(file_content) + + # Given generated markdown files, incorporate them into the docfx_yaml output. # The markdown file metadata will be added to top level of the TOC. def find_markdown_pages(app, outdir): @@ -1374,13 +1393,24 @@ def find_markdown_pages(app, outdir): # For each file, if it is a markdown file move to the top level pages. for mdfile in markdown_dir.iterdir(): if mdfile.is_file() and mdfile.name.lower() not in files_to_ignore: + mdfile_name = "" highlight_md_codeblocks(markdown_dir / mdfile.name) - shutil.copy(mdfile, f"{outdir}/{mdfile.name.lower()}") # Extract the header name for TOC. with open(mdfile) as mdfile_iterator: name = extract_header_from_markdown(mdfile_iterator) + if not name: + with open(mdfile, 'r+') as mdfile_iterator: + mdfile_name = mdfile_iterator.name.split("/")[-1].split(".")[0].capitalize() + + print(f"Could not find a title for {mdfile_iterator.name}. Using {mdfile_name} as the title instead.") + name = mdfile_name + + prepend_markdown_header(name, mdfile_iterator) + + shutil.copy(mdfile, f"{outdir}/{mdfile.name.lower()}") + # Add the file to the TOC later. app.env.markdown_pages.append({ 'name': name, diff --git a/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_alternate_bad_want.md b/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_alternate_bad_want.md new file mode 100644 index 000000000000..c282c5580e82 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_alternate_bad_want.md @@ -0,0 +1,8 @@ +# Markdown_example_alternate_bad + +============== + +There should be a header line before the divider. + +##Content header +This is a simple line followed by an h2 header. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_bad_header_want.md b/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_bad_header_want.md new file mode 100644 index 000000000000..01cc5f5c74f7 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_bad_header_want.md @@ -0,0 +1,6 @@ +# Markdown_example_bad_header + + #Test header for a bad formatted markdown file. + +##Content header +This is a simple line followed by an h2 header. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_h2_want.md b/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_h2_want.md new file mode 100644 index 000000000000..d952cdc68637 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_h2_want.md @@ -0,0 +1,6 @@ +# Markdown_example_h2 + +## Test header for a simple markdown file. + +##Content header +This is a simple line followed by an h2 header. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/test_helpers.py b/packages/gcp-sphinx-docfx-yaml/tests/test_helpers.py index dc74a403f890..dfb8c196e355 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/test_helpers.py +++ b/packages/gcp-sphinx-docfx-yaml/tests/test_helpers.py @@ -5,6 +5,7 @@ from docfx_yaml.extension import format_code from docfx_yaml.extension import extract_product_name from docfx_yaml.extension import highlight_md_codeblocks +from docfx_yaml.extension import prepend_markdown_header import unittest from parameterized import parameterized @@ -260,5 +261,40 @@ def test_highlight_md_codeblocks(self, base_filename, want_filename): self.assertEqual(test_file.read(), mdfile_want.read()) + # Filenames to test prepending Markdown title.. + test_markdown_filenames = [ + [ + "tests/markdown_example_bad_header.md", + "tests/markdown_example_bad_header_want.md" + ], + [ + "tests/markdown_example_h2.md", + "tests/markdown_example_h2_want.md" + ], + [ + "tests/markdown_example_alternate_bad.md", + "tests/markdown_example_alternate_bad_want.md" + ], + ] + @parameterized.expand(test_markdown_filenames) + def test_prepend_markdown_header(self, base_filename, want_filename): + # Ensure markdown titles are correctly prepended. + + # Copy the base file we'll need to test. + with tempfile.NamedTemporaryFile(mode='r+', delete=False) as test_file: + with open(base_filename) as base_file: + # Use same file name extraction as original code. + file_name = base_file.name.split("/")[-1].split(".")[0].capitalize() + test_file.write(base_file.read()) + test_file.flush() + test_file.seek(0) + + prepend_markdown_header(file_name, test_file) + test_file.seek(0) + + with open(want_filename) as mdfile_want: + self.assertEqual(test_file.read(), mdfile_want.read()) + + if __name__ == '__main__': unittest.main() diff --git a/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py b/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py index 6cfd7dc61bed..0ad10de8ba85 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py +++ b/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py @@ -13,6 +13,7 @@ from docfx_yaml.extension import parse_markdown_header import unittest +from parameterized import parameterized from yaml import load, Loader @@ -667,74 +668,70 @@ def test_parse_markdown_header_alternate(self): self.assertEqual(header_line_got, header_line_want) - def test_extract_header_from_markdown(self): - # Check the header for a normal markdown file. + test_markdown_filenames = [ + [ + # Check the header for a normal markdown file. + "tests/markdown_example.md" + ], + [ + # The header should be the same even with the license header. + "tests/markdown_example_header.md" + ], + ] + @parameterized.expand(test_markdown_filenames) + def test_extract_header_from_markdown(self, markdown_filename): + # Check the header for markdown files. header_line_want = "Test header for a simple markdown file." - with open('tests/markdown_example.md', 'r') as mdfile: + with open(markdown_filename, 'r') as mdfile: header_line_got = extract_header_from_markdown(mdfile) self.assertEqual(header_line_got, header_line_want) - # The header should be the same even with the license header. - header_line_with_license_want = header_line_want - - with open('tests/markdown_example_header.md', 'r') as mdfile_license: - header_line_with_license_got = extract_header_from_markdown(mdfile_license) - - self.assertEqual(header_line_with_license_got, header_line_with_license_want) - - def test_extract_header_from_markdown_alternate_header(self): - # Check the header for an alternate header style. - header_line_want = "This is a simple alternate header" - - with open('tests/markdown_example_alternate.md', 'r') as mdfile: - header_line_got = extract_header_from_markdown(mdfile) - - self.assertEqual(header_line_got, header_line_want) - - # The header should be the same even with the license header. - header_line_with_license_want = header_line_want - - with open('tests/markdown_example_alternate_header.md', 'r') as mdfile: - header_line_with_license_got = extract_header_from_markdown(mdfile) - - self.assertEqual(header_line_with_license_got, header_line_with_license_want) - - # Check the header for an alternate header style. + test_markdown_filenames = [ + [ + # Check the header for an alternate header style. + "tests/markdown_example_alternate.md" + ], + [ + # The header should be the same even with the license header. + "tests/markdown_example_alternate_header.md" + ], + [ + # Check the header for an alternate header style. + "tests/markdown_example_alternate_less.md" + ], + ] + @parameterized.expand(test_markdown_filenames) + def test_extract_header_from_markdown_alternate_header(self, markdown_filename): + # Check the header for different accepted styles. header_line_want = "This is a simple alternate header" - with open('tests/markdown_example_alternate_less.md', 'r') as mdfile: + with open(markdown_filename, 'r') as mdfile: header_line_got = extract_header_from_markdown(mdfile) self.assertEqual(header_line_got, header_line_want) - def test_extract_header_from_markdown_bad_headers(self): - # Check that the filename is used as header if no valid header is found. - header_line_want = "Markdown_example_bad_header" - - with open('tests/markdown_example_bad_header.md', 'r') as mdfile: - header_line_got = extract_header_from_markdown(mdfile) - - self.assertEqual(header_line_want, header_line_got) - - # Check that only h1 headers are parsed. - header_line_want = "Markdown_example_h2" - - with open('tests/markdown_example_h2.md', 'r') as mdfile: - header_line_got = extract_header_from_markdown(mdfile) - - self.assertEqual(header_line_want, header_line_got) - - # Check that there must be a line before the h1 header breaker. - header_line_want = "Markdown_example_alternate_bad" - - with open('tests/markdown_example_alternate_bad.md', 'r') as mdfile: + test_markdown_filenames = [ + [ + "tests/markdown_example_bad_header.md" + ], + [ + "tests/markdown_example_h2.md" + ], + [ + "tests/markdown_example_alternate_bad.md" + ], + ] + @parameterized.expand(test_markdown_filenames) + def test_extract_header_from_markdown_bad_headers(self, markdown_filename): + # Check that empty string is returned if no valid header is found. + with open(markdown_filename, 'r') as mdfile: header_line_got = extract_header_from_markdown(mdfile) - self.assertEqual(header_line_want, header_line_got) + self.assertFalse(header_line_got) def test_parse_docstring_summary(self): From 21ff1adc450c633cd7c0bbd960e651d8693d74f0 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Tue, 12 Apr 2022 14:38:32 -0400 Subject: [PATCH 133/279] chore(main): release 1.4.7 (#204) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/gcp-sphinx-docfx-yaml/CHANGELOG.md | 7 +++++++ packages/gcp-sphinx-docfx-yaml/setup.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md index ba755916fd90..2ed04fefed0f 100644 --- a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md +++ b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +### [1.4.7](https://github.com/googleapis/sphinx-docfx-yaml/compare/v1.4.6...v1.4.7) (2022-04-12) + + +### Bug Fixes + +* add markdown header if it is missing ([#203](https://github.com/googleapis/sphinx-docfx-yaml/issues/203)) ([ccd53bd](https://github.com/googleapis/sphinx-docfx-yaml/commit/ccd53bdba8cdfe08d900a7b05f235e635a2f0441)) + ### [1.4.6](https://github.com/googleapis/sphinx-docfx-yaml/compare/v1.4.5...v1.4.6) (2022-04-06) diff --git a/packages/gcp-sphinx-docfx-yaml/setup.py b/packages/gcp-sphinx-docfx-yaml/setup.py index e921a96001df..aa1ca7c6f008 100644 --- a/packages/gcp-sphinx-docfx-yaml/setup.py +++ b/packages/gcp-sphinx-docfx-yaml/setup.py @@ -17,7 +17,7 @@ name = 'gcp-sphinx-docfx-yaml' description = 'Sphinx Python Domain to DocFX YAML Generator' -version = '1.4.6' +version = '1.4.7' dependencies = [ 'black', 'gcp-docuploader', From 607d25312b319565fcea942efb40be202aac5440 Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Thu, 5 May 2022 11:56:12 -0400 Subject: [PATCH 134/279] chore: [autoapprove] update readme_gen.py to include autoescape True (#206) Source-Link: https://github.com/googleapis/synthtool/commit/6b4d5a6407d740beb4158b302194a62a4108a8a6 Post-Processor: gcr.io/cloud-devrel-public-resources/owlbot-python:latest@sha256:f792ee1320e03eda2d13a5281a2989f7ed8a9e50b73ef6da97fac7e1e850b149 Co-authored-by: Owl Bot --- packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml | 4 ++-- .../gcp-sphinx-docfx-yaml/scripts/readme-gen/readme_gen.py | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml index bc893c979e20..b631901e99f4 100644 --- a/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml +++ b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml @@ -13,5 +13,5 @@ # limitations under the License. docker: image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest - digest: sha256:8a5d3f6a2e43ed8293f34e06a2f56931d1e88a2694c3bb11b15df4eb256ad163 -# created: 2022-04-06T10:30:21.687684602Z + digest: sha256:f792ee1320e03eda2d13a5281a2989f7ed8a9e50b73ef6da97fac7e1e850b149 +# created: 2022-05-05T15:17:27.599381182Z diff --git a/packages/gcp-sphinx-docfx-yaml/scripts/readme-gen/readme_gen.py b/packages/gcp-sphinx-docfx-yaml/scripts/readme-gen/readme_gen.py index d309d6e97518..91b59676bfc7 100644 --- a/packages/gcp-sphinx-docfx-yaml/scripts/readme-gen/readme_gen.py +++ b/packages/gcp-sphinx-docfx-yaml/scripts/readme-gen/readme_gen.py @@ -28,7 +28,10 @@ jinja_env = jinja2.Environment( trim_blocks=True, loader=jinja2.FileSystemLoader( - os.path.abspath(os.path.join(os.path.dirname(__file__), 'templates')))) + os.path.abspath(os.path.join(os.path.dirname(__file__), "templates")) + ), + autoescape=True, +) README_TMPL = jinja_env.get_template('README.tmpl.rst') From 071653cdccd08f3059c6c65e15becf75f76f0978 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Fri, 6 May 2022 00:38:21 +0200 Subject: [PATCH 135/279] chore(deps): update dependency ubuntu to v22 (#205) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [![WhiteSource Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com) This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | ubuntu | final | major | `20.04` -> `22.04` | --- ### Configuration 📅 **Schedule**: At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, click this checkbox. --- This PR has been generated by [WhiteSource Renovate](https://renovate.whitesourcesoftware.com). View repository job log [here](https://app.renovatebot.com/dashboard#github/googleapis/sphinx-docfx-yaml). --- packages/gcp-sphinx-docfx-yaml/.kokoro/docker/docs/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/docker/docs/Dockerfile b/packages/gcp-sphinx-docfx-yaml/.kokoro/docker/docs/Dockerfile index 0e91cd3cf9fa..19d860e6ccb7 100644 --- a/packages/gcp-sphinx-docfx-yaml/.kokoro/docker/docs/Dockerfile +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/docker/docs/Dockerfile @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from ubuntu:20.04 +from ubuntu:22.04 ENV DEBIAN_FRONTEND noninteractive From d7730da4bdb650aadbb5ea7cb92617a0ab6ad517 Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Thu, 5 May 2022 19:54:54 -0400 Subject: [PATCH 136/279] chore(python): auto approve template changes (#207) Source-Link: https://github.com/googleapis/synthtool/commit/453a5d9c9a55d1969240a37d36cec626d20a9024 Post-Processor: gcr.io/cloud-devrel-public-resources/owlbot-python:latest@sha256:81ed5ecdfc7cac5b699ba4537376f3563f6f04122c4ec9e735d3b3dc1d43dd32 Co-authored-by: Owl Bot Co-authored-by: Dan Lee <71398022+dandhlee@users.noreply.github.com> --- packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml | 4 ++-- packages/gcp-sphinx-docfx-yaml/.github/auto-approve.yml | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 packages/gcp-sphinx-docfx-yaml/.github/auto-approve.yml diff --git a/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml index b631901e99f4..757c9dca75ad 100644 --- a/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml +++ b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml @@ -13,5 +13,5 @@ # limitations under the License. docker: image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest - digest: sha256:f792ee1320e03eda2d13a5281a2989f7ed8a9e50b73ef6da97fac7e1e850b149 -# created: 2022-05-05T15:17:27.599381182Z + digest: sha256:81ed5ecdfc7cac5b699ba4537376f3563f6f04122c4ec9e735d3b3dc1d43dd32 +# created: 2022-05-05T22:08:23.383410683Z diff --git a/packages/gcp-sphinx-docfx-yaml/.github/auto-approve.yml b/packages/gcp-sphinx-docfx-yaml/.github/auto-approve.yml new file mode 100644 index 000000000000..311ebbb853a9 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/.github/auto-approve.yml @@ -0,0 +1,3 @@ +# https://github.com/googleapis/repo-automation-bots/tree/main/packages/auto-approve +processes: + - "OwlBotTemplateChanges" From 2d8207defc94e4a25215743998eb805912cbdfdb Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Sat, 21 May 2022 20:00:49 -0400 Subject: [PATCH 137/279] Revert "chore(deps): update dependency ubuntu to v22 (#205)" (#210) This reverts commit f4a29d80f8840476a334ce2ef36a7f033ecee86e. --- packages/gcp-sphinx-docfx-yaml/.kokoro/docker/docs/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/docker/docs/Dockerfile b/packages/gcp-sphinx-docfx-yaml/.kokoro/docker/docs/Dockerfile index 19d860e6ccb7..0e91cd3cf9fa 100644 --- a/packages/gcp-sphinx-docfx-yaml/.kokoro/docker/docs/Dockerfile +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/docker/docs/Dockerfile @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from ubuntu:22.04 +from ubuntu:20.04 ENV DEBIAN_FRONTEND noninteractive From 5b44022f42b128008e3708c7d2ec81cbb428c69d Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Tue, 24 May 2022 14:47:03 -0400 Subject: [PATCH 138/279] fix: add hardcoded IAM references temporarily (#209) * fix: add hardcoded reference for IAM references * test: update unit test * fix: apply suggestion Co-authored-by: Tyler Bui-Palsulich <26876514+tbpg@users.noreply.github.com> * fix: separate code into helper function and add proper docstrings * fix: ensure hard_coded_references is optional and not used if not found * test: update unit test with new helper function * fix: update method name and apply review suggestions * test: update unit test * fix: address review suggestion for adding return type Co-authored-by: Tyler Bui-Palsulich <26876514+tbpg@users.noreply.github.com> * fix: address review comments * fix: update variable name from keyword to uid * fix: update method names, variable names and refactor methods * test: update unit test * fix: update comments, move hardcoded bits to the back Co-authored-by: Tyler Bui-Palsulich <26876514+tbpg@users.noreply.github.com> --- .../docfx_yaml/extension.py | 164 +++++++++++++----- .../tests/test_helpers.py | 73 +++++++- 2 files changed, 190 insertions(+), 47 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index 53c3cd9c5957..ab57bddda028 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -29,7 +29,7 @@ from pathlib import Path from functools import partial from itertools import zip_longest -from typing import List, Iterable +from typing import Dict, Iterable, List, Optional from black import InvalidInput try: @@ -1417,36 +1417,112 @@ def find_markdown_pages(app, outdir): 'href': mdfile.name.lower(), }) +def find_uid_to_convert( + current_word: str, + words: List[str], + index: int, + known_uids: List[str], + current_object_name: str, + processed_words: List[str], + hard_coded_references: Dict[str, str] = None +) -> Optional[str]: + """Given `current_word`, returns the `uid` to convert to cross reference if found. -# Finds and replaces occurrences which should be a cross reference in the given -# content, except for the current name. -def convert_cross_references(content: str, current_name: str, entry_names: List[str]): + Args: + current_word: current word being looked at + words: list of words used to check and compare content before and after `current_word` + index: index position of `current_word` within words + known_uids: list of uid references to look for + current_object_name: the name of the current Python object being processed + processed_words: list of words containing words that's been processed so far + hard_coded_references: Optional list containing a list of hard coded reference + + Returns: + None if current word does not contain any reference `uid`, or the `uid` + that should be converted. + """ + for uid in known_uids: + # Do not convert references to itself or containing partial + # references. This could result in `storage.types.ReadSession` being + # prematurely converted to + # `storage.typesReadSession` + # instead of + # `storage.types.ReadSession` + if uid in current_object_name: + continue + + if uid in current_word: + # If the cross reference has been processed already, " str: + """Finds and replaces references that should be a cross reference in given content. + + This should not convert any references that contain `current_object_name`, + i.e. if we're processing docstring for `google.cloud.spanner.v1.services`, + references to `google.cloud.spanner.v1.services` should not be convereted + to references. + + Args: + content: body of content to parse and look for references in + current_object_name: the name of the current Python object being processed + known_uids: list of uid references to look for + + Returns: + content that has been modified with proper cross references if found. + """ words = content.split(" ") - new_words = [] - # Using counter to check if the entry is already a cross reference. + + # Contains a list of words that is not a valid reference or converted + # references. + processed_words = [] + + # TODO(https://github.com/googleapis/sphinx-docfx-yaml/issues/208): + # remove this in the future. + iam_policy_link = "http://github.com/googleapis/python-grpc-google-iam-v1/blob/8e73b45993f030f521c0169b380d0fbafe66630b/google/iam/v1/iam_policy_pb2_grpc.py" + hard_coded_references = { + "google.iam.v1.iam_policy_pb2.SetIamPolicyRequest": iam_policy_link + "#L103-L109", + "google.iam.v1.iam_policy_pb2.GetIamPolicyRequest": iam_policy_link + "#L111-L118", + "google.iam.v1.iam_policy_pb2.TestIamPermissionsRequest": iam_policy_link + "#L120-L131", + "google.iam.v1.iam_policy_pb2.TestIamPermissionsResponse": iam_policy_link + "#L120-L131" + } + known_uids.extend(hard_coded_references.keys()) + for index, word in enumerate(words): - cross_reference = "" - for keyword in entry_names: - if keyword != current_name and keyword not in current_name and keyword in word: - # If it is already processed as cross reference, skip over it. - if "{keyword}" - new_words.append(word.replace(keyword, cross_reference)) - print(f"Converted {keyword} into cross reference in: \n{content}") + uid = find_uid_to_convert( + word, words, index, known_uids, current_object_name, processed_words, hard_coded_references + ) + + if uid: + cross_reference = f"{uid}" \ + if uid in hard_coded_references else \ + f"{uid}" - # If cross reference has not been found, add current unchanged content. - if not cross_reference: - new_words.append(word) + processed_words.append(word.replace(uid, cross_reference)) + print(f"Converted {uid} into cross reference in: \n{content}") + + else: + # If cross reference has not been found, add current unchanged content. + processed_words.append(word) - return " ".join(new_words) + return " ".join(processed_words) # Used to look for cross references in the obj's data where applicable. # For now, we inspect summary, syntax and attributes. -def search_cross_references(obj, current_name: str, entry_names: List[str]): +def search_cross_references(obj, current_object_name: str, known_uids: List[str]): if obj.get("summary"): - obj["summary"] = convert_cross_references(obj["summary"], current_name, entry_names) + obj["summary"] = convert_cross_references(obj["summary"], current_object_name, known_uids) if obj.get("syntax"): if obj["syntax"].get("parameters"): @@ -1454,22 +1530,22 @@ def search_cross_references(obj, current_name: str, entry_names: List[str]): if param.get("description"): param["description"] = convert_cross_references( param["description"], - current_name, - entry_names + current_object_name, + known_uids ) if param.get("id"): param["id"] = convert_cross_references( param["id"], - current_name, - entry_names + current_object_name, + known_uids ) if param.get("var_type"): param["var_type"] = convert_cross_references( param["var_type"], - current_name, - entry_names + current_object_name, + known_uids ) if obj["syntax"].get("exceptions"): @@ -1477,15 +1553,15 @@ def search_cross_references(obj, current_name: str, entry_names: List[str]): if exception.get("description"): exception["description"] = convert_cross_references( exception["description"], - current_name, - entry_names + current_object_name, + known_uids ) if exception.get("var_type"): exception["var_type"] = convert_cross_references( exception["var_type"], - current_name, - entry_names + current_object_name, + known_uids ) if obj["syntax"].get("returns"): @@ -1493,15 +1569,15 @@ def search_cross_references(obj, current_name: str, entry_names: List[str]): if ret.get("description"): ret["description"] = convert_cross_references( ret["description"], - current_name, - entry_names + current_object_name, + known_uids ) if ret.get("var_type"): ret["var_type"] = convert_cross_references( ret["var_type"], - current_name, - entry_names + current_object_name, + known_uids ) @@ -1510,22 +1586,22 @@ def search_cross_references(obj, current_name: str, entry_names: List[str]): if attribute.get("description"): attribute["description"] = convert_cross_references( attribute["description"], - current_name, - entry_names + current_object_name, + known_uids ) if attribute.get("id"): attribute["id"] = convert_cross_references( attribute["id"], - current_name, - entry_names + current_object_name, + known_uids ) if attribute.get("var_type"): attribute["var_type"] = convert_cross_references( attribute["var_type"], - current_name, - entry_names + current_object_name, + known_uids ) @@ -1728,11 +1804,11 @@ def convert_module_to_package_if_needed(obj): # (not from the same library) # google.cloud.aiplatform.AutoMLForecastingTrainingJob - current_name = obj["fullName"] - entry_names = sorted(app.env.docfx_uid_names.keys(), reverse=True) + current_object_name = obj["fullName"] + known_uids = sorted(app.env.docfx_uid_names.keys(), reverse=True) # Currently we only need to look in summary, syntax and # attributes for cross references. - search_cross_references(obj, current_name, entry_names) + search_cross_references(obj, current_object_name, known_uids) yaml_map[uid] = [yaml_data, references] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/test_helpers.py b/packages/gcp-sphinx-docfx-yaml/tests/test_helpers.py index dfb8c196e355..668b887aeb40 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/test_helpers.py +++ b/packages/gcp-sphinx-docfx-yaml/tests/test_helpers.py @@ -1,5 +1,6 @@ from docfx_yaml.extension import extract_keyword from docfx_yaml.extension import indent_code_left +from docfx_yaml.extension import find_uid_to_convert from docfx_yaml.extension import convert_cross_references from docfx_yaml.extension import search_cross_references from docfx_yaml.extension import format_code @@ -115,16 +116,29 @@ def test_extract_keyword(self): "Response message for google.cloud.bigquery_storage_v1.types.SplitReadStreamResponse.", "Response message for google.cloud.bigquery_storage_v1.types.SplitReadStreamResponse." ], + # Testing for cross reference to not be converted for its own object. + [ + "Response message for google.cloud.bigquery_storage_v1.types.SplitResponse.", + "Response message for google.cloud.bigquery_storage_v1.types.SplitResponse." + ], + # TODO(https://github.com/googleapis/sphinx-docfx-yaml/issues/208): + # remove this when it is not needed anymore. + # Testing for hardcoded reference. + [ + "google.iam.v1.iam_policy_pb2.GetIamPolicyRequest", + "google.iam.v1.iam_policy_pb2.GetIamPolicyRequest" + ] ] @parameterized.expand(cross_references_testdata) def test_convert_cross_references(self, content, content_want): # Check that entries correctly turns into cross references. keyword_map = [ - "google.cloud.bigquery_storage_v1.types.SplitReadStreamResponse" + "google.cloud.bigquery_storage_v1.types.SplitReadStreamResponse", + "google.cloud.bigquery_storage_v1.types.SplitResponse" ] - current_name = "SplitRepsonse" + current_object_name = "google.cloud.bigquery_storage_v1.types.SplitResponse" - content_got = convert_cross_references(content, current_name, keyword_map) + content_got = convert_cross_references(content, current_object_name, keyword_map) self.assertEqual(content_got, content_want) @@ -296,5 +310,58 @@ def test_prepend_markdown_header(self, base_filename, want_filename): self.assertEqual(test_file.read(), mdfile_want.read()) + test_reference_params = [ + [ + # If no reference keyword is found, check for None + "google.cloud.resourcemanager_v3.ProjectsClient", + ["google.cloud.resourcemanager_v1.ProjectsClient"], + ["The", "following", "constraints", "apply", "when", "using"], + None + ], + [ + # If keyword reference is found, validate proper cross reference + "google.cloud.resourcemanager_v3.set_iam_policy", + ["google.cloud.resourcemanager_v3.set_iam_policy"], + ["A", "Policy", "is", "a", "collection", "of", "bindings", "from"], + "google.cloud.resourcemanager_v3.set_iam_policy" + ], + [ + # If keyword reference has already been converted, do not convert + # again. + "uid=\"google.cloud.resourcemanager_v3.set_iam_policy\">documentation", + ["google.cloud.resourcemanager_v3.set_iam_policy"], + ["Take", "a", "look", "at", "documentation for more information. +""" + # Break up the paragraph into sanitized list of words as shown in Sphinx. + words = " ".join(content.split("\n")).split(" ") + + index = words.index(current_word) + + cross_reference_got = find_uid_to_convert( + current_word, words, index, uids, current_object_name, visited_words + ) + self.assertEqual(cross_reference_got, cross_reference_want) + + if __name__ == '__main__': unittest.main() From 0cd604309e041a9020c5c43e848b3504b53d6833 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Tue, 24 May 2022 20:48:13 +0200 Subject: [PATCH 139/279] chore(deps): update dependency sphinx to v4.5.0 (#196) Co-authored-by: Dan Lee <71398022+dandhlee@users.noreply.github.com> --- packages/gcp-sphinx-docfx-yaml/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/requirements.txt b/packages/gcp-sphinx-docfx-yaml/requirements.txt index ee29b9dc76cb..e16310926dfd 100644 --- a/packages/gcp-sphinx-docfx-yaml/requirements.txt +++ b/packages/gcp-sphinx-docfx-yaml/requirements.txt @@ -2,6 +2,6 @@ black==22.3.0 parameterized==0.8.1 # google-resumable-media-python requires manual update as this repo isn't templated. # python-api-core also requires manual update as it is not templated. -sphinx==4.4.0 +sphinx==4.5.0 -e . tox From 24171d6974db15fb879f4e927ed23c28e8f1137c Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Tue, 24 May 2022 14:51:37 -0400 Subject: [PATCH 140/279] chore(main): release 1.4.8 (#211) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> Co-authored-by: Dan Lee <71398022+dandhlee@users.noreply.github.com> --- packages/gcp-sphinx-docfx-yaml/CHANGELOG.md | 7 +++++++ packages/gcp-sphinx-docfx-yaml/setup.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md index 2ed04fefed0f..7d465c204dad 100644 --- a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md +++ b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +### [1.4.8](https://github.com/googleapis/sphinx-docfx-yaml/compare/v1.4.7...v1.4.8) (2022-05-24) + + +### Bug Fixes + +* add hardcoded IAM references temporarily ([#209](https://github.com/googleapis/sphinx-docfx-yaml/issues/209)) ([5dc99d2](https://github.com/googleapis/sphinx-docfx-yaml/commit/5dc99d25532e668d5bf5fc1402b93ed5f189655e)) + ### [1.4.7](https://github.com/googleapis/sphinx-docfx-yaml/compare/v1.4.6...v1.4.7) (2022-04-12) diff --git a/packages/gcp-sphinx-docfx-yaml/setup.py b/packages/gcp-sphinx-docfx-yaml/setup.py index aa1ca7c6f008..e7aacbe67d62 100644 --- a/packages/gcp-sphinx-docfx-yaml/setup.py +++ b/packages/gcp-sphinx-docfx-yaml/setup.py @@ -17,7 +17,7 @@ name = 'gcp-sphinx-docfx-yaml' description = 'Sphinx Python Domain to DocFX YAML Generator' -version = '1.4.7' +version = '1.4.8' dependencies = [ 'black', 'gcp-docuploader', From 8bf08036deab3103d5e90a0f7e2a049ea94335d7 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Wed, 8 Jun 2022 22:39:16 +0200 Subject: [PATCH 141/279] chore(deps): update actions/setup-python action to v4 (#213) --- packages/gcp-sphinx-docfx-yaml/.github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/.github/workflows/ci.yaml b/packages/gcp-sphinx-docfx-yaml/.github/workflows/ci.yaml index 5a93820e930f..a91fac013fce 100644 --- a/packages/gcp-sphinx-docfx-yaml/.github/workflows/ci.yaml +++ b/packages/gcp-sphinx-docfx-yaml/.github/workflows/ci.yaml @@ -12,7 +12,7 @@ jobs: steps: - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v3 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Install dependencies From 0df3ca28ad253eedec98937da7cab28467ecab6c Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Tue, 21 Jun 2022 11:00:25 -0400 Subject: [PATCH 142/279] chore(python): add missing import for prerelease testing (#216) Source-Link: https://github.com/googleapis/synthtool/commit/d2871d98e1e767d4ad49a557ff979236d64361a1 Post-Processor: gcr.io/cloud-devrel-public-resources/owlbot-python:latest@sha256:b2dc5f80edcf5d4486c39068c9fa11f7f851d9568eea4dcba130f994ea9b5e97 Co-authored-by: Owl Bot --- packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml | 4 ++-- .../.kokoro/continuous/prerelease-deps.cfg | 7 +++++++ .../.kokoro/presubmit/prerelease-deps.cfg | 7 +++++++ 3 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 packages/gcp-sphinx-docfx-yaml/.kokoro/continuous/prerelease-deps.cfg create mode 100644 packages/gcp-sphinx-docfx-yaml/.kokoro/presubmit/prerelease-deps.cfg diff --git a/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml index 757c9dca75ad..50b29ffd2050 100644 --- a/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml +++ b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml @@ -13,5 +13,5 @@ # limitations under the License. docker: image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest - digest: sha256:81ed5ecdfc7cac5b699ba4537376f3563f6f04122c4ec9e735d3b3dc1d43dd32 -# created: 2022-05-05T22:08:23.383410683Z + digest: sha256:b2dc5f80edcf5d4486c39068c9fa11f7f851d9568eea4dcba130f994ea9b5e97 +# created: 2022-06-12T16:09:31.61859086Z diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/continuous/prerelease-deps.cfg b/packages/gcp-sphinx-docfx-yaml/.kokoro/continuous/prerelease-deps.cfg new file mode 100644 index 000000000000..3595fb43f5c0 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/continuous/prerelease-deps.cfg @@ -0,0 +1,7 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +# Only run this nox session. +env_vars: { + key: "NOX_SESSION" + value: "prerelease_deps" +} diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/presubmit/prerelease-deps.cfg b/packages/gcp-sphinx-docfx-yaml/.kokoro/presubmit/prerelease-deps.cfg new file mode 100644 index 000000000000..3595fb43f5c0 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/presubmit/prerelease-deps.cfg @@ -0,0 +1,7 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +# Only run this nox session. +env_vars: { + key: "NOX_SESSION" + value: "prerelease_deps" +} From 56b585c30c7bfce66fc251e64d5a4a519f37d2c0 Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Mon, 27 Jun 2022 10:22:09 -0400 Subject: [PATCH 143/279] fix: include dependency for librarytest (#218) --- packages/gcp-sphinx-docfx-yaml/tox.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/gcp-sphinx-docfx-yaml/tox.ini b/packages/gcp-sphinx-docfx-yaml/tox.ini index 7bad2a653407..c11d68cef3ce 100644 --- a/packages/gcp-sphinx-docfx-yaml/tox.ini +++ b/packages/gcp-sphinx-docfx-yaml/tox.ini @@ -27,6 +27,7 @@ commands = [testenv:librarytest] deps = sphinx_rtd_theme + {[testenv]deps} changedir = {toxinidir}/docs commands = sphinx-build -D extensions=sphinx.ext.autodoc,sphinx.ext.autosummary,docfx_yaml.extension,sphinx.ext.intersphinx,sphinx.ext.coverage,sphinx.ext.napoleon,sphinx.ext.todo,sphinx.ext.viewcode -b html -d {envtmpdir}/doctrees . {envtmpdir}/html From 6b8e024ffb0aa0d643932033bf2e6c8fa41e1644 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Tue, 28 Jun 2022 06:03:41 +0200 Subject: [PATCH 144/279] chore(deps): update dependency black to v22.6.0 (#220) --- packages/gcp-sphinx-docfx-yaml/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/requirements.txt b/packages/gcp-sphinx-docfx-yaml/requirements.txt index e16310926dfd..04b221ff0edd 100644 --- a/packages/gcp-sphinx-docfx-yaml/requirements.txt +++ b/packages/gcp-sphinx-docfx-yaml/requirements.txt @@ -1,4 +1,4 @@ -black==22.3.0 +black==22.6.0 parameterized==0.8.1 # google-resumable-media-python requires manual update as this repo isn't templated. # python-api-core also requires manual update as it is not templated. From 8a7fb1042fddcc8703482a47a121a8dd5de83ccc Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Sat, 9 Jul 2022 07:14:53 -0400 Subject: [PATCH 145/279] chore: update templated files (#221) * chore(python): drop python 3.6 Source-Link: https://github.com/googleapis/synthtool/commit/4f89b13af10d086458f9b379e56a614f9d6dab7b Post-Processor: gcr.io/cloud-devrel-public-resources/owlbot-python:latest@sha256:e7bb19d47c13839fe8c147e50e02e8b6cf5da8edd1af8b82208cd6f66cc2829c * exclude templated README Co-authored-by: Owl Bot Co-authored-by: Anthonios Partheniou --- packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml | 4 ++-- packages/gcp-sphinx-docfx-yaml/owlbot.py | 1 + .../scripts/readme-gen/templates/install_deps.tmpl.rst | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml index 50b29ffd2050..1ce608523524 100644 --- a/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml +++ b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml @@ -13,5 +13,5 @@ # limitations under the License. docker: image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest - digest: sha256:b2dc5f80edcf5d4486c39068c9fa11f7f851d9568eea4dcba130f994ea9b5e97 -# created: 2022-06-12T16:09:31.61859086Z + digest: sha256:e7bb19d47c13839fe8c147e50e02e8b6cf5da8edd1af8b82208cd6f66cc2829c +# created: 2022-07-05T18:31:20.838186805Z diff --git a/packages/gcp-sphinx-docfx-yaml/owlbot.py b/packages/gcp-sphinx-docfx-yaml/owlbot.py index 5d9cdae39b24..d6c92da2be24 100644 --- a/packages/gcp-sphinx-docfx-yaml/owlbot.py +++ b/packages/gcp-sphinx-docfx-yaml/owlbot.py @@ -47,5 +47,6 @@ ".gitignore", "renovate.json", ".github/workflows", # exclude templated gh actions + "README.rst", ], ) diff --git a/packages/gcp-sphinx-docfx-yaml/scripts/readme-gen/templates/install_deps.tmpl.rst b/packages/gcp-sphinx-docfx-yaml/scripts/readme-gen/templates/install_deps.tmpl.rst index 275d649890d7..6f069c6c87a5 100644 --- a/packages/gcp-sphinx-docfx-yaml/scripts/readme-gen/templates/install_deps.tmpl.rst +++ b/packages/gcp-sphinx-docfx-yaml/scripts/readme-gen/templates/install_deps.tmpl.rst @@ -12,7 +12,7 @@ Install Dependencies .. _Python Development Environment Setup Guide: https://cloud.google.com/python/setup -#. Create a virtualenv. Samples are compatible with Python 3.6+. +#. Create a virtualenv. Samples are compatible with Python 3.7+. .. code-block:: bash From b48395cd676b39611e03cb2afbb08d382e66a537 Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Mon, 11 Jul 2022 16:31:34 -0400 Subject: [PATCH 146/279] feat: support devsite notices (#222) * feat: add support for various notices * fix: update docstrings and comments * test: update unit test --- .../docfx_yaml/extension.py | 73 +++++++++++++++++++ .../gcp-sphinx-docfx-yaml/tests/test_unit.py | 44 ++++++++++- 2 files changed, 116 insertions(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index ab57bddda028..51afbd973a9d 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -101,6 +101,33 @@ class Bcolors: CODE = "code" PACKAGE = "package" +# DevSite specific notices that can be used. +NOTE = 'note' +CAUTION = 'caution' +WARNING = 'warning' +IMPORTANT = 'special' +KEYPOINT = 'key-point' +KEYTERM = 'key-term' +OBJECTIVE = 'objective' +SUCCESS = 'success' +BETA = 'beta' +PREVIEW = 'preview' +DEPRECATED = 'deprecated' + +NOTICES = { + NOTE: 'Note', + CAUTION: 'Caution', + WARNING: 'Warning', + IMPORTANT: 'Important', + KEYPOINT: 'Key Point', + KEYTERM: 'Key Term', + OBJECTIVE: 'Objective', + SUCCESS: 'Success', + BETA: 'Beta', + PREVIEW: 'Preview', + DEPRECATED: 'deprecated', +} + # Disable blib2to3 output that clutters debugging log. logging.getLogger("blib2to3").setLevel(logging.ERROR) @@ -407,6 +434,9 @@ def _parse_docstring_summary(summary): attribute_type_token = ":type:" keyword = name = description = var_type = "" + notice_open_tag = '' + # We need to separate in chunks, which is defined by 3 newline breaks. # Otherwise when parsing for code and blocks of stuff, we will not be able # to have the entire context when just splitting by single newlines. @@ -468,6 +498,24 @@ def _parse_docstring_summary(summary): continue + elif keyword and keyword in NOTICES: + # Determine how much code block is indented to format properly. + if tab_space == -1: + parts = [split_part for split_part in part.split("\n") if split_part] + tab_space = len(parts[0]) - len(parts[0].lstrip(" ")) + if tab_space == 0: + raise ValueError("Content in the block should be indented."\ + f"Please check the docstring: \n{summary}") + if not part.startswith(" "*tab_space): + if notice_body: + parts = [indent_code_left(part, tab_space) for part in notice_body] + summary_parts.append("\n".join(parts)) + + summary_parts.append(notice_close_tag) + keyword = "" + notice_body.append(part) + continue + # Parse keywords if found. # lstrip is added to parse code blocks that are not formatted well. if part.lstrip('\n').startswith('..'): @@ -491,6 +539,24 @@ def _parse_docstring_summary(summary): found_name = False name = part.split("::")[1].strip() + # Extracts the notice content and format it. + elif keyword and keyword in NOTICES: + summary_parts.append(notice_open_tag.format( + notice_tag=keyword, notice_name=NOTICES[keyword])) + tab_space = -1 + notice_body = [] + parts = [split_part for split_part in part.split("\n") if split_part][1:] + if not parts: + continue + tab_space = len(parts[0]) - len(parts[0].lstrip(" ")) + if tab_space == 0: + raise ValueError("Content in the block should be indented."\ + f"Please check the docstring: \n{summary}") + parts = [indent_code_left(part, tab_space) for part in parts] + summary_parts.append("\n".join(parts)) + summary_parts.append(notice_close_tag) + keyword = "" + # Reserve for additional parts # elif keyword == keyword: else: @@ -508,6 +574,13 @@ def _parse_docstring_summary(summary): if summary_parts[-1] != "```\n": summary_parts.append("```\n") + if keyword and keyword in NOTICES: + if notice_body: + parts = [indent_code_left(part, tab_space) for part in notice_body] + summary_parts.append("\n\n".join(parts)) + if summary_parts[-1] != notice_close_tag: + summary_parts.append(notice_close_tag) + # Requires 2 newline chars to properly show on cloud site. return "\n".join(summary_parts), attributes diff --git a/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py b/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py index 0ad10de8ba85..f104c7411822 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py +++ b/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py @@ -808,7 +808,7 @@ def get_client_cert(): # Check that nothing much changes otherwise. summary = \ """ -.. note:: +.. literalinclude:: note that these are not supported yet, so they will be ignored for now. And any other documentation that the source code would have could go here. @@ -833,6 +833,48 @@ def get_client_cert(): with self.assertRaises(ValueError): _parse_docstring_summary(summary) + # Check that notices are processed properly. + summary_want = \ +""" + +""" + + summary = \ +""" +.. note:: +\n this is a note. + + +.. caution:: +\n another type of notice. + + +.. key-term:: +\n hyphenated term notice. +""" + + summary_got, attributes_got = _parse_docstring_summary(summary) + self.assertEqual(summary_got, summary_want) + self.assertEqual(attributes_got, attributes_want) + + # Check that exception is raised if block is not formatted properly. + + summary = \ +""" +.. warning:: +this is not a properly formatted warning. +""" + with self.assertRaises(ValueError): + _parse_docstring_summary(summary) def test_parse_docstring_summary_attributes(self): # Test parsing docstring with attributes. From 694158412bfee50845bd2fb24165a01cccfac748 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Tue, 12 Jul 2022 12:24:50 -0400 Subject: [PATCH 147/279] chore(main): release 1.5.0 (#219) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/gcp-sphinx-docfx-yaml/CHANGELOG.md | 12 ++++++++++++ packages/gcp-sphinx-docfx-yaml/setup.py | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md index 7d465c204dad..9dd57c7a43d1 100644 --- a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md +++ b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog +## [1.5.0](https://github.com/googleapis/sphinx-docfx-yaml/compare/v1.4.8...v1.5.0) (2022-07-11) + + +### Features + +* support devsite notices ([#222](https://github.com/googleapis/sphinx-docfx-yaml/issues/222)) ([0da9224](https://github.com/googleapis/sphinx-docfx-yaml/commit/0da9224712f846485bdcc13807904b7e5e094e34)) + + +### Bug Fixes + +* include dependency for librarytest ([#218](https://github.com/googleapis/sphinx-docfx-yaml/issues/218)) ([420780b](https://github.com/googleapis/sphinx-docfx-yaml/commit/420780bf873bd0fc993fbbaa98833649bf0b2762)) + ### [1.4.8](https://github.com/googleapis/sphinx-docfx-yaml/compare/v1.4.7...v1.4.8) (2022-05-24) diff --git a/packages/gcp-sphinx-docfx-yaml/setup.py b/packages/gcp-sphinx-docfx-yaml/setup.py index e7aacbe67d62..0227bb434800 100644 --- a/packages/gcp-sphinx-docfx-yaml/setup.py +++ b/packages/gcp-sphinx-docfx-yaml/setup.py @@ -17,7 +17,7 @@ name = 'gcp-sphinx-docfx-yaml' description = 'Sphinx Python Domain to DocFX YAML Generator' -version = '1.4.8' +version = '1.5.0' dependencies = [ 'black', 'gcp-docuploader', From f72a6239ef70ae75722843efef50dd3999956cee Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Wed, 13 Jul 2022 16:58:05 -0400 Subject: [PATCH 148/279] ci: handle duplicate names for renamed packages (#223) --- .../gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh b/packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh index d98896ea3fe4..cd1b0902d6bb 100755 --- a/packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh @@ -115,8 +115,20 @@ for package in $(echo "${python_bucket_items}" | cut -d "-" -f 5- | rev | cut -d # Build YAML tarballs for Cloud-RAD. nox -s docfx + # Update specific names to be up to date. + name=$(jq --raw-output '.name // empty' .repo-metadata.json) + if [[ "${name}" == "translation" ]]; then + name="translate" + fi + if [[ "${name}" == "clouderroreporting" ]]; then + name="clouderrorreporting" + fi + if [[ "${name}" == "iam" ]]; then + name="iamcredentials" + fi + python3 -m docuploader create-metadata \ - --name=$(jq --raw-output '.name // empty' .repo-metadata.json) \ + --name=${name} \ --version=$(python3 setup.py --version) \ --language=$(jq --raw-output '.language // empty' .repo-metadata.json) \ --distribution-name=$(python3 setup.py --name) \ From 95579c69a7e4a98d4f26dccf7b6bf9ee40dcb3df Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Tue, 26 Jul 2022 12:30:56 -0400 Subject: [PATCH 149/279] ci: skip empty packages (#226) * ci: skip empty packages * ci: update typo * ci: Update .kokoro/generate-docs.sh Co-authored-by: Tyler Bui-Palsulich <26876514+tbpg@users.noreply.github.com> Co-authored-by: Tyler Bui-Palsulich <26876514+tbpg@users.noreply.github.com> --- .../.kokoro/generate-docs.sh | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh b/packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh index cd1b0902d6bb..9ee83fc68ce9 100755 --- a/packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh @@ -38,6 +38,8 @@ python3 -m pip install --user django==2.2 ipython # Store the contents of bucket log in a variable to reuse. python_bucket_items=$(gsutil ls "gs://docs-staging-v2/docfx-python*") +# Store empty tarballs that did not produce any content to check later. +empty_packages="" # Retrieve unique repositories to regenerate the YAML with. for package in $(echo "${python_bucket_items}" | cut -d "-" -f 5- | rev | cut -d "-" -f 2- | rev | uniq); do @@ -115,6 +117,12 @@ for package in $(echo "${python_bucket_items}" | cut -d "-" -f 5- | rev | cut -d # Build YAML tarballs for Cloud-RAD. nox -s docfx + # Check that documentation is produced. If not, log and continue. + if [ ! "$(ls docs/_build/html/docfx_yaml/)" ]; then + empty_packages="${repo}-${tag} ${empty_packages}" + continue + fi + # Update specific names to be up to date. name=$(jq --raw-output '.name // empty' .repo-metadata.json) if [[ "${name}" == "translation" ]]; then @@ -147,3 +155,12 @@ for package in $(echo "${python_bucket_items}" | cut -d "-" -f 5- | rev | cut -d rm -rf ${repo} rm "noxfile.py" done + +if [ ! ${empty_packages} ]; then + exit +fi + +echo "The following packages did not produce any content:" +for empty_package in $(echo ${empty_packages}); do + echo ${empty_package} +done From d8acdbecaf7700803e5748f4f781e659a304acd6 Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Wed, 24 Aug 2022 14:01:50 -0400 Subject: [PATCH 150/279] chore: remove 'pip install' statements from python_library templates [autoapprove] (#228) Source-Link: https://github.com/googleapis/synthtool/commit/69fabaee9eca28af7ecaa02c86895e606fbbebd6 Post-Processor: gcr.io/cloud-devrel-public-resources/owlbot-python:latest@sha256:562802bfac02e012a6ac34eda282f81d06e77326b82a32d7bbb1369ff552b387 Co-authored-by: Owl Bot --- .../.github/.OwlBot.lock.yaml | 4 +- .../gcp-sphinx-docfx-yaml/.kokoro/release.sh | 5 +- .../.kokoro/requirements.in | 8 + .../.kokoro/requirements.txt | 464 ++++++++++++++++++ 4 files changed, 475 insertions(+), 6 deletions(-) create mode 100644 packages/gcp-sphinx-docfx-yaml/.kokoro/requirements.in create mode 100644 packages/gcp-sphinx-docfx-yaml/.kokoro/requirements.txt diff --git a/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml index 1ce608523524..c6acdf3f90c4 100644 --- a/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml +++ b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml @@ -13,5 +13,5 @@ # limitations under the License. docker: image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest - digest: sha256:e7bb19d47c13839fe8c147e50e02e8b6cf5da8edd1af8b82208cd6f66cc2829c -# created: 2022-07-05T18:31:20.838186805Z + digest: sha256:562802bfac02e012a6ac34eda282f81d06e77326b82a32d7bbb1369ff552b387 +# created: 2022-08-24T17:07:22.006876712Z diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/release.sh b/packages/gcp-sphinx-docfx-yaml/.kokoro/release.sh index 3c20981b38c8..8a9997df2d4b 100755 --- a/packages/gcp-sphinx-docfx-yaml/.kokoro/release.sh +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/release.sh @@ -16,12 +16,9 @@ set -eo pipefail # Start the releasetool reporter -python3 -m pip install gcp-releasetool +python3 -m pip install --require-hashes -r .kokoro/requirements.txt python3 -m releasetool publish-reporter-script > /tmp/publisher-script; source /tmp/publisher-script -# Ensure that we have the latest versions of Twine, Wheel, and Setuptools. -python3 -m pip install --upgrade twine wheel setuptools - # Disable buffering, so that the logs stream through. export PYTHONUNBUFFERED=1 diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/requirements.in b/packages/gcp-sphinx-docfx-yaml/.kokoro/requirements.in new file mode 100644 index 000000000000..7718391a34d7 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/requirements.in @@ -0,0 +1,8 @@ +gcp-docuploader +gcp-releasetool +importlib-metadata +typing-extensions +twine +wheel +setuptools +nox \ No newline at end of file diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/requirements.txt b/packages/gcp-sphinx-docfx-yaml/.kokoro/requirements.txt new file mode 100644 index 000000000000..c4b824f247e3 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/requirements.txt @@ -0,0 +1,464 @@ +# +# This file is autogenerated by pip-compile with python 3.10 +# To update, run: +# +# pip-compile --allow-unsafe --generate-hashes requirements.in +# +argcomplete==2.0.0 \ + --hash=sha256:6372ad78c89d662035101418ae253668445b391755cfe94ea52f1b9d22425b20 \ + --hash=sha256:cffa11ea77999bb0dd27bb25ff6dc142a6796142f68d45b1a26b11f58724561e + # via nox +attrs==22.1.0 \ + --hash=sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6 \ + --hash=sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c + # via gcp-releasetool +bleach==5.0.1 \ + --hash=sha256:085f7f33c15bd408dd9b17a4ad77c577db66d76203e5984b1bd59baeee948b2a \ + --hash=sha256:0d03255c47eb9bd2f26aa9bb7f2107732e7e8fe195ca2f64709fcf3b0a4a085c + # via readme-renderer +cachetools==5.2.0 \ + --hash=sha256:6a94c6402995a99c3970cc7e4884bb60b4a8639938157eeed436098bf9831757 \ + --hash=sha256:f9f17d2aec496a9aa6b76f53e3b614c965223c061982d434d160f930c698a9db + # via google-auth +certifi==2022.6.15 \ + --hash=sha256:84c85a9078b11105f04f3036a9482ae10e4621616db313fe045dd24743a0820d \ + --hash=sha256:fe86415d55e84719d75f8b69414f6438ac3547d2078ab91b67e779ef69378412 + # via requests +cffi==1.15.1 \ + --hash=sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5 \ + --hash=sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef \ + --hash=sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104 \ + --hash=sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426 \ + --hash=sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405 \ + --hash=sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375 \ + --hash=sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a \ + --hash=sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e \ + --hash=sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc \ + --hash=sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf \ + --hash=sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185 \ + --hash=sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497 \ + --hash=sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3 \ + --hash=sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35 \ + --hash=sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c \ + --hash=sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83 \ + --hash=sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21 \ + --hash=sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca \ + --hash=sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984 \ + --hash=sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac \ + --hash=sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd \ + --hash=sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee \ + --hash=sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a \ + --hash=sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2 \ + --hash=sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192 \ + --hash=sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7 \ + --hash=sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585 \ + --hash=sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f \ + --hash=sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e \ + --hash=sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27 \ + --hash=sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b \ + --hash=sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e \ + --hash=sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e \ + --hash=sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d \ + --hash=sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c \ + --hash=sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415 \ + --hash=sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82 \ + --hash=sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02 \ + --hash=sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314 \ + --hash=sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325 \ + --hash=sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c \ + --hash=sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3 \ + --hash=sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914 \ + --hash=sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045 \ + --hash=sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d \ + --hash=sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9 \ + --hash=sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5 \ + --hash=sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2 \ + --hash=sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c \ + --hash=sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3 \ + --hash=sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2 \ + --hash=sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8 \ + --hash=sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d \ + --hash=sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d \ + --hash=sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9 \ + --hash=sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162 \ + --hash=sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76 \ + --hash=sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4 \ + --hash=sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e \ + --hash=sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9 \ + --hash=sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6 \ + --hash=sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b \ + --hash=sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01 \ + --hash=sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0 + # via cryptography +charset-normalizer==2.1.1 \ + --hash=sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845 \ + --hash=sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f + # via requests +click==8.0.4 \ + --hash=sha256:6a7a62563bbfabfda3a38f3023a1db4a35978c0abd76f6c9605ecd6554d6d9b1 \ + --hash=sha256:8458d7b1287c5fb128c90e23381cf99dcde74beaf6c7ff6384ce84d6fe090adb + # via + # gcp-docuploader + # gcp-releasetool +colorlog==6.6.0 \ + --hash=sha256:344f73204009e4c83c5b6beb00b3c45dc70fcdae3c80db919e0a4171d006fde8 \ + --hash=sha256:351c51e866c86c3217f08e4b067a7974a678be78f07f85fc2d55b8babde6d94e + # via + # gcp-docuploader + # nox +commonmark==0.9.1 \ + --hash=sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60 \ + --hash=sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9 + # via rich +cryptography==37.0.4 \ + --hash=sha256:190f82f3e87033821828f60787cfa42bff98404483577b591429ed99bed39d59 \ + --hash=sha256:2be53f9f5505673eeda5f2736bea736c40f051a739bfae2f92d18aed1eb54596 \ + --hash=sha256:30788e070800fec9bbcf9faa71ea6d8068f5136f60029759fd8c3efec3c9dcb3 \ + --hash=sha256:3d41b965b3380f10e4611dbae366f6dc3cefc7c9ac4e8842a806b9672ae9add5 \ + --hash=sha256:4c590ec31550a724ef893c50f9a97a0c14e9c851c85621c5650d699a7b88f7ab \ + --hash=sha256:549153378611c0cca1042f20fd9c5030d37a72f634c9326e225c9f666d472884 \ + --hash=sha256:63f9c17c0e2474ccbebc9302ce2f07b55b3b3fcb211ded18a42d5764f5c10a82 \ + --hash=sha256:6bc95ed67b6741b2607298f9ea4932ff157e570ef456ef7ff0ef4884a134cc4b \ + --hash=sha256:7099a8d55cd49b737ffc99c17de504f2257e3787e02abe6d1a6d136574873441 \ + --hash=sha256:75976c217f10d48a8b5a8de3d70c454c249e4b91851f6838a4e48b8f41eb71aa \ + --hash=sha256:7bc997818309f56c0038a33b8da5c0bfbb3f1f067f315f9abd6fc07ad359398d \ + --hash=sha256:80f49023dd13ba35f7c34072fa17f604d2f19bf0989f292cedf7ab5770b87a0b \ + --hash=sha256:91ce48d35f4e3d3f1d83e29ef4a9267246e6a3be51864a5b7d2247d5086fa99a \ + --hash=sha256:a958c52505c8adf0d3822703078580d2c0456dd1d27fabfb6f76fe63d2971cd6 \ + --hash=sha256:b62439d7cd1222f3da897e9a9fe53bbf5c104fff4d60893ad1355d4c14a24157 \ + --hash=sha256:b7f8dd0d4c1f21759695c05a5ec8536c12f31611541f8904083f3dc582604280 \ + --hash=sha256:d204833f3c8a33bbe11eda63a54b1aad7aa7456ed769a982f21ec599ba5fa282 \ + --hash=sha256:e007f052ed10cc316df59bc90fbb7ff7950d7e2919c9757fd42a2b8ecf8a5f67 \ + --hash=sha256:f2dcb0b3b63afb6df7fd94ec6fbddac81b5492513f7b0436210d390c14d46ee8 \ + --hash=sha256:f721d1885ecae9078c3f6bbe8a88bc0786b6e749bf32ccec1ef2b18929a05046 \ + --hash=sha256:f7a6de3e98771e183645181b3627e2563dcde3ce94a9e42a3f427d2255190327 \ + --hash=sha256:f8c0a6e9e1dd3eb0414ba320f85da6b0dcbd543126e30fcc546e7372a7fbf3b9 + # via + # gcp-releasetool + # secretstorage +distlib==0.3.5 \ + --hash=sha256:a7f75737c70be3b25e2bee06288cec4e4c221de18455b2dd037fe2a795cab2fe \ + --hash=sha256:b710088c59f06338ca514800ad795a132da19fda270e3ce4affc74abf955a26c + # via virtualenv +docutils==0.19 \ + --hash=sha256:33995a6753c30b7f577febfc2c50411fec6aac7f7ffeb7c4cfe5991072dcf9e6 \ + --hash=sha256:5e1de4d849fee02c63b040a4a3fd567f4ab104defd8a5511fbbc24a8a017efbc + # via readme-renderer +filelock==3.8.0 \ + --hash=sha256:55447caa666f2198c5b6b13a26d2084d26fa5b115c00d065664b2124680c4edc \ + --hash=sha256:617eb4e5eedc82fc5f47b6d61e4d11cb837c56cb4544e39081099fa17ad109d4 + # via virtualenv +gcp-docuploader==0.6.3 \ + --hash=sha256:ba8c9d76b3bbac54b0311c503a373b00edc2dc02d6d54ea9507045adb8e870f7 \ + --hash=sha256:c0f5aaa82ce1854a386197e4e359b120ad6d4e57ae2c812fce42219a3288026b + # via -r requirements.in +gcp-releasetool==1.8.6 \ + --hash=sha256:42e51ab8e2e789bc8e22a03c09352962cd3452951c801a2230d564816630304a \ + --hash=sha256:a3518b79d1b243c494eac392a01c7fd65187fd6d52602dcab9b529bc934d4da1 + # via -r requirements.in +google-api-core==2.8.2 \ + --hash=sha256:06f7244c640322b508b125903bb5701bebabce8832f85aba9335ec00b3d02edc \ + --hash=sha256:93c6a91ccac79079ac6bbf8b74ee75db970cc899278b97d53bc012f35908cf50 + # via + # google-cloud-core + # google-cloud-storage +google-auth==2.11.0 \ + --hash=sha256:be62acaae38d0049c21ca90f27a23847245c9f161ff54ede13af2cb6afecbac9 \ + --hash=sha256:ed65ecf9f681832298e29328e1ef0a3676e3732b2e56f41532d45f70a22de0fb + # via + # gcp-releasetool + # google-api-core + # google-cloud-core + # google-cloud-storage +google-cloud-core==2.3.2 \ + --hash=sha256:8417acf6466be2fa85123441696c4badda48db314c607cf1e5d543fa8bdc22fe \ + --hash=sha256:b9529ee7047fd8d4bf4a2182de619154240df17fbe60ead399078c1ae152af9a + # via google-cloud-storage +google-cloud-storage==2.5.0 \ + --hash=sha256:19a26c66c317ce542cea0830b7e787e8dac2588b6bfa4d3fd3b871ba16305ab0 \ + --hash=sha256:382f34b91de2212e3c2e7b40ec079d27ee2e3dbbae99b75b1bcd8c63063ce235 + # via gcp-docuploader +google-crc32c==1.3.0 \ + --hash=sha256:04e7c220798a72fd0f08242bc8d7a05986b2a08a0573396187fd32c1dcdd58b3 \ + --hash=sha256:05340b60bf05b574159e9bd940152a47d38af3fb43803ffe71f11d704b7696a6 \ + --hash=sha256:12674a4c3b56b706153a358eaa1018c4137a5a04635b92b4652440d3d7386206 \ + --hash=sha256:127f9cc3ac41b6a859bd9dc4321097b1a4f6aa7fdf71b4f9227b9e3ebffb4422 \ + --hash=sha256:13af315c3a0eec8bb8b8d80b8b128cb3fcd17d7e4edafc39647846345a3f003a \ + --hash=sha256:1926fd8de0acb9d15ee757175ce7242e235482a783cd4ec711cc999fc103c24e \ + --hash=sha256:226f2f9b8e128a6ca6a9af9b9e8384f7b53a801907425c9a292553a3a7218ce0 \ + --hash=sha256:276de6273eb074a35bc598f8efbc00c7869c5cf2e29c90748fccc8c898c244df \ + --hash=sha256:318f73f5484b5671f0c7f5f63741ab020a599504ed81d209b5c7129ee4667407 \ + --hash=sha256:3bbce1be3687bbfebe29abdb7631b83e6b25da3f4e1856a1611eb21854b689ea \ + --hash=sha256:42ae4781333e331a1743445931b08ebdad73e188fd554259e772556fc4937c48 \ + --hash=sha256:58be56ae0529c664cc04a9c76e68bb92b091e0194d6e3c50bea7e0f266f73713 \ + --hash=sha256:5da2c81575cc3ccf05d9830f9e8d3c70954819ca9a63828210498c0774fda1a3 \ + --hash=sha256:6311853aa2bba4064d0c28ca54e7b50c4d48e3de04f6770f6c60ebda1e975267 \ + --hash=sha256:650e2917660e696041ab3dcd7abac160b4121cd9a484c08406f24c5964099829 \ + --hash=sha256:6a4db36f9721fdf391646685ecffa404eb986cbe007a3289499020daf72e88a2 \ + --hash=sha256:779cbf1ce375b96111db98fca913c1f5ec11b1d870e529b1dc7354b2681a8c3a \ + --hash=sha256:7f6fe42536d9dcd3e2ffb9d3053f5d05221ae3bbcefbe472bdf2c71c793e3183 \ + --hash=sha256:891f712ce54e0d631370e1f4997b3f182f3368179198efc30d477c75d1f44942 \ + --hash=sha256:95c68a4b9b7828ba0428f8f7e3109c5d476ca44996ed9a5f8aac6269296e2d59 \ + --hash=sha256:96a8918a78d5d64e07c8ea4ed2bc44354e3f93f46a4866a40e8db934e4c0d74b \ + --hash=sha256:9c3cf890c3c0ecfe1510a452a165431b5831e24160c5fcf2071f0f85ca5a47cd \ + --hash=sha256:9f58099ad7affc0754ae42e6d87443299f15d739b0ce03c76f515153a5cda06c \ + --hash=sha256:a0b9e622c3b2b8d0ce32f77eba617ab0d6768b82836391e4f8f9e2074582bf02 \ + --hash=sha256:a7f9cbea4245ee36190f85fe1814e2d7b1e5f2186381b082f5d59f99b7f11328 \ + --hash=sha256:bab4aebd525218bab4ee615786c4581952eadc16b1ff031813a2fd51f0cc7b08 \ + --hash=sha256:c124b8c8779bf2d35d9b721e52d4adb41c9bfbde45e6a3f25f0820caa9aba73f \ + --hash=sha256:c9da0a39b53d2fab3e5467329ed50e951eb91386e9d0d5b12daf593973c3b168 \ + --hash=sha256:ca60076c388728d3b6ac3846842474f4250c91efbfe5afa872d3ffd69dd4b318 \ + --hash=sha256:cb6994fff247987c66a8a4e550ef374671c2b82e3c0d2115e689d21e511a652d \ + --hash=sha256:d1c1d6236feab51200272d79b3d3e0f12cf2cbb12b208c835b175a21efdb0a73 \ + --hash=sha256:dd7760a88a8d3d705ff562aa93f8445ead54f58fd482e4f9e2bafb7e177375d4 \ + --hash=sha256:dda4d8a3bb0b50f540f6ff4b6033f3a74e8bf0bd5320b70fab2c03e512a62812 \ + --hash=sha256:e0f1ff55dde0ebcfbef027edc21f71c205845585fffe30d4ec4979416613e9b3 \ + --hash=sha256:e7a539b9be7b9c00f11ef16b55486141bc2cdb0c54762f84e3c6fc091917436d \ + --hash=sha256:eb0b14523758e37802f27b7f8cd973f5f3d33be7613952c0df904b68c4842f0e \ + --hash=sha256:ed447680ff21c14aaceb6a9f99a5f639f583ccfe4ce1a5e1d48eb41c3d6b3217 \ + --hash=sha256:f52a4ad2568314ee713715b1e2d79ab55fab11e8b304fd1462ff5cccf4264b3e \ + --hash=sha256:fbd60c6aaa07c31d7754edbc2334aef50601b7f1ada67a96eb1eb57c7c72378f \ + --hash=sha256:fc28e0db232c62ca0c3600884933178f0825c99be4474cdd645e378a10588125 \ + --hash=sha256:fe31de3002e7b08eb20823b3735b97c86c5926dd0581c7710a680b418a8709d4 \ + --hash=sha256:fec221a051150eeddfdfcff162e6db92c65ecf46cb0f7bb1bf812a1520ec026b \ + --hash=sha256:ff71073ebf0e42258a42a0b34f2c09ec384977e7f6808999102eedd5b49920e3 + # via google-resumable-media +google-resumable-media==2.3.3 \ + --hash=sha256:27c52620bd364d1c8116eaac4ea2afcbfb81ae9139fb3199652fcac1724bfb6c \ + --hash=sha256:5b52774ea7a829a8cdaa8bd2d4c3d4bc660c91b30857ab2668d0eb830f4ea8c5 + # via google-cloud-storage +googleapis-common-protos==1.56.4 \ + --hash=sha256:8eb2cbc91b69feaf23e32452a7ae60e791e09967d81d4fcc7fc388182d1bd394 \ + --hash=sha256:c25873c47279387cfdcbdafa36149887901d36202cb645a0e4f29686bf6e4417 + # via google-api-core +idna==3.3 \ + --hash=sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff \ + --hash=sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d + # via requests +importlib-metadata==4.12.0 \ + --hash=sha256:637245b8bab2b6502fcbc752cc4b7a6f6243bb02b31c5c26156ad103d3d45670 \ + --hash=sha256:7401a975809ea1fdc658c3aa4f78cc2195a0e019c5cbc4c06122884e9ae80c23 + # via + # -r requirements.in + # twine +jeepney==0.8.0 \ + --hash=sha256:5efe48d255973902f6badc3ce55e2aa6c5c3b3bc642059ef3a91247bcfcc5806 \ + --hash=sha256:c0a454ad016ca575060802ee4d590dd912e35c122fa04e70306de3d076cce755 + # via + # keyring + # secretstorage +jinja2==3.1.2 \ + --hash=sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852 \ + --hash=sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61 + # via gcp-releasetool +keyring==23.8.2 \ + --hash=sha256:0d9973f8891850f1ade5f26aafd06bb16865fbbae3fc56b0defb6a14a2624003 \ + --hash=sha256:10d2a8639663fe2090705a00b8c47c687cacdf97598ea9c11456679fa974473a + # via + # gcp-releasetool + # twine +markupsafe==2.1.1 \ + --hash=sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003 \ + --hash=sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88 \ + --hash=sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5 \ + --hash=sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7 \ + --hash=sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a \ + --hash=sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603 \ + --hash=sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1 \ + --hash=sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135 \ + --hash=sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247 \ + --hash=sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6 \ + --hash=sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601 \ + --hash=sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77 \ + --hash=sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02 \ + --hash=sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e \ + --hash=sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63 \ + --hash=sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f \ + --hash=sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980 \ + --hash=sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b \ + --hash=sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812 \ + --hash=sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff \ + --hash=sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96 \ + --hash=sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1 \ + --hash=sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925 \ + --hash=sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a \ + --hash=sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6 \ + --hash=sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e \ + --hash=sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f \ + --hash=sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4 \ + --hash=sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f \ + --hash=sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3 \ + --hash=sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c \ + --hash=sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a \ + --hash=sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417 \ + --hash=sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a \ + --hash=sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a \ + --hash=sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37 \ + --hash=sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452 \ + --hash=sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933 \ + --hash=sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a \ + --hash=sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7 + # via jinja2 +nox==2022.8.7 \ + --hash=sha256:1b894940551dc5c389f9271d197ca5d655d40bdc6ccf93ed6880e4042760a34b \ + --hash=sha256:96cca88779e08282a699d672258ec01eb7c792d35bbbf538c723172bce23212c + # via -r requirements.in +packaging==21.3 \ + --hash=sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb \ + --hash=sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522 + # via + # gcp-releasetool + # nox +pkginfo==1.8.3 \ + --hash=sha256:848865108ec99d4901b2f7e84058b6e7660aae8ae10164e015a6dcf5b242a594 \ + --hash=sha256:a84da4318dd86f870a9447a8c98340aa06216bfc6f2b7bdc4b8766984ae1867c + # via twine +platformdirs==2.5.2 \ + --hash=sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788 \ + --hash=sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19 + # via virtualenv +protobuf==3.20.1 \ + --hash=sha256:06059eb6953ff01e56a25cd02cca1a9649a75a7e65397b5b9b4e929ed71d10cf \ + --hash=sha256:097c5d8a9808302fb0da7e20edf0b8d4703274d140fd25c5edabddcde43e081f \ + --hash=sha256:284f86a6207c897542d7e956eb243a36bb8f9564c1742b253462386e96c6b78f \ + --hash=sha256:32ca378605b41fd180dfe4e14d3226386d8d1b002ab31c969c366549e66a2bb7 \ + --hash=sha256:3cc797c9d15d7689ed507b165cd05913acb992d78b379f6014e013f9ecb20996 \ + --hash=sha256:62f1b5c4cd6c5402b4e2d63804ba49a327e0c386c99b1675c8a0fefda23b2067 \ + --hash=sha256:69ccfdf3657ba59569c64295b7d51325f91af586f8d5793b734260dfe2e94e2c \ + --hash=sha256:6f50601512a3d23625d8a85b1638d914a0970f17920ff39cec63aaef80a93fb7 \ + --hash=sha256:7403941f6d0992d40161aa8bb23e12575637008a5a02283a930addc0508982f9 \ + --hash=sha256:755f3aee41354ae395e104d62119cb223339a8f3276a0cd009ffabfcdd46bb0c \ + --hash=sha256:77053d28427a29987ca9caf7b72ccafee011257561259faba8dd308fda9a8739 \ + --hash=sha256:7e371f10abe57cee5021797126c93479f59fccc9693dafd6bd5633ab67808a91 \ + --hash=sha256:9016d01c91e8e625141d24ec1b20fed584703e527d28512aa8c8707f105a683c \ + --hash=sha256:9be73ad47579abc26c12024239d3540e6b765182a91dbc88e23658ab71767153 \ + --hash=sha256:adc31566d027f45efe3f44eeb5b1f329da43891634d61c75a5944e9be6dd42c9 \ + --hash=sha256:adfc6cf69c7f8c50fd24c793964eef18f0ac321315439d94945820612849c388 \ + --hash=sha256:af0ebadc74e281a517141daad9d0f2c5d93ab78e9d455113719a45a49da9db4e \ + --hash=sha256:cb29edb9eab15742d791e1025dd7b6a8f6fcb53802ad2f6e3adcb102051063ab \ + --hash=sha256:cd68be2559e2a3b84f517fb029ee611546f7812b1fdd0aa2ecc9bc6ec0e4fdde \ + --hash=sha256:cdee09140e1cd184ba9324ec1df410e7147242b94b5f8b0c64fc89e38a8ba531 \ + --hash=sha256:db977c4ca738dd9ce508557d4fce0f5aebd105e158c725beec86feb1f6bc20d8 \ + --hash=sha256:dd5789b2948ca702c17027c84c2accb552fc30f4622a98ab5c51fcfe8c50d3e7 \ + --hash=sha256:e250a42f15bf9d5b09fe1b293bdba2801cd520a9f5ea2d7fb7536d4441811d20 \ + --hash=sha256:ff8d8fa42675249bb456f5db06c00de6c2f4c27a065955917b28c4f15978b9c3 + # via + # gcp-docuploader + # gcp-releasetool + # google-api-core +py==1.11.0 \ + --hash=sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719 \ + --hash=sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378 + # via nox +pyasn1==0.4.8 \ + --hash=sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d \ + --hash=sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba + # via + # pyasn1-modules + # rsa +pyasn1-modules==0.2.8 \ + --hash=sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e \ + --hash=sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74 + # via google-auth +pycparser==2.21 \ + --hash=sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9 \ + --hash=sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206 + # via cffi +pygments==2.13.0 \ + --hash=sha256:56a8508ae95f98e2b9bdf93a6be5ae3f7d8af858b43e02c5a2ff083726be40c1 \ + --hash=sha256:f643f331ab57ba3c9d89212ee4a2dabc6e94f117cf4eefde99a0574720d14c42 + # via + # readme-renderer + # rich +pyjwt==2.4.0 \ + --hash=sha256:72d1d253f32dbd4f5c88eaf1fdc62f3a19f676ccbadb9dbc5d07e951b2b26daf \ + --hash=sha256:d42908208c699b3b973cbeb01a969ba6a96c821eefb1c5bfe4c390c01d67abba + # via gcp-releasetool +pyparsing==3.0.9 \ + --hash=sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb \ + --hash=sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc + # via packaging +pyperclip==1.8.2 \ + --hash=sha256:105254a8b04934f0bc84e9c24eb360a591aaf6535c9def5f29d92af107a9bf57 + # via gcp-releasetool +python-dateutil==2.8.2 \ + --hash=sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86 \ + --hash=sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9 + # via gcp-releasetool +readme-renderer==37.0 \ + --hash=sha256:07b7ea234e03e58f77cc222e206e6abb8f4c0435becce5104794ee591f9301c5 \ + --hash=sha256:9fa416704703e509eeb900696751c908ddeb2011319d93700d8f18baff887a69 + # via twine +requests==2.28.1 \ + --hash=sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983 \ + --hash=sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349 + # via + # gcp-releasetool + # google-api-core + # google-cloud-storage + # requests-toolbelt + # twine +requests-toolbelt==0.9.1 \ + --hash=sha256:380606e1d10dc85c3bd47bf5a6095f815ec007be7a8b69c878507068df059e6f \ + --hash=sha256:968089d4584ad4ad7c171454f0a5c6dac23971e9472521ea3b6d49d610aa6fc0 + # via twine +rfc3986==2.0.0 \ + --hash=sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd \ + --hash=sha256:97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c + # via twine +rich==12.5.1 \ + --hash=sha256:2eb4e6894cde1e017976d2975ac210ef515d7548bc595ba20e195fb9628acdeb \ + --hash=sha256:63a5c5ce3673d3d5fbbf23cd87e11ab84b6b451436f1b7f19ec54b6bc36ed7ca + # via twine +rsa==4.9 \ + --hash=sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7 \ + --hash=sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21 + # via google-auth +secretstorage==3.3.3 \ + --hash=sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77 \ + --hash=sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99 + # via keyring +six==1.16.0 \ + --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ + --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 + # via + # bleach + # gcp-docuploader + # google-auth + # python-dateutil +twine==4.0.1 \ + --hash=sha256:42026c18e394eac3e06693ee52010baa5313e4811d5a11050e7d48436cf41b9e \ + --hash=sha256:96b1cf12f7ae611a4a40b6ae8e9570215daff0611828f5fe1f37a16255ab24a0 + # via -r requirements.in +typing-extensions==4.3.0 \ + --hash=sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02 \ + --hash=sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6 + # via -r requirements.in +urllib3==1.26.12 \ + --hash=sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e \ + --hash=sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997 + # via + # requests + # twine +virtualenv==20.16.3 \ + --hash=sha256:4193b7bc8a6cd23e4eb251ac64f29b4398ab2c233531e66e40b19a6b7b0d30c1 \ + --hash=sha256:d86ea0bb50e06252d79e6c241507cb904fcd66090c3271381372d6221a3970f9 + # via nox +webencodings==0.5.1 \ + --hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \ + --hash=sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923 + # via bleach +wheel==0.37.1 \ + --hash=sha256:4bdcd7d840138086126cd09254dc6195fb4fc6f01c050a1d7236f2630db1d22a \ + --hash=sha256:e9a504e793efbca1b8e0e9cb979a249cf4a0a7b5b8c9e8b65a5e39d49529c1c4 + # via -r requirements.in +zipp==3.8.1 \ + --hash=sha256:05b45f1ee8f807d0cc928485ca40a07cb491cf092ff587c0df9cb1fd154848d2 \ + --hash=sha256:47c40d7fe183a6f21403a199b3e4192cca5774656965b0a4988ad2f8feb5f009 + # via importlib-metadata + +# The following packages are considered to be unsafe in a requirements file: +setuptools==65.2.0 \ + --hash=sha256:7f4bc85450898a09f76ebf28b72fa25bc7111f6c7d665d514a60bba9c75ef2a9 \ + --hash=sha256:a3ca5857c89f82f5c9410e8508cb32f4872a3bafd4aa7ae122a24ca33bccc750 + # via -r requirements.in From 8eeb323608c874a6d71ce0d722ad2ecd68f967d3 Mon Sep 17 00:00:00 2001 From: Anthonios Partheniou Date: Sat, 27 Aug 2022 18:03:29 -0400 Subject: [PATCH 151/279] chore: use templated renovate.json (#233) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: use templated renovate.json * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md Co-authored-by: Owl Bot --- packages/gcp-sphinx-docfx-yaml/owlbot.py | 1 - packages/gcp-sphinx-docfx-yaml/renovate.json | 12 ++++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 packages/gcp-sphinx-docfx-yaml/renovate.json diff --git a/packages/gcp-sphinx-docfx-yaml/owlbot.py b/packages/gcp-sphinx-docfx-yaml/owlbot.py index d6c92da2be24..fc1abe226612 100644 --- a/packages/gcp-sphinx-docfx-yaml/owlbot.py +++ b/packages/gcp-sphinx-docfx-yaml/owlbot.py @@ -45,7 +45,6 @@ ".github/CONTRIBUTING.md", ".github/PULL_REQUEST_TEMPLATE.md", ".gitignore", - "renovate.json", ".github/workflows", # exclude templated gh actions "README.rst", ], diff --git a/packages/gcp-sphinx-docfx-yaml/renovate.json b/packages/gcp-sphinx-docfx-yaml/renovate.json new file mode 100644 index 000000000000..566a70f3cc3c --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/renovate.json @@ -0,0 +1,12 @@ +{ + "extends": [ + "config:base", + "group:all", + ":preserveSemverRanges", + ":disableDependencyDashboard" + ], + "ignorePaths": [".pre-commit-config.yaml", ".kokoro/requirements.txt"], + "pip_requirements": { + "fileMatch": ["requirements-test.txt", "samples/[\\S/]*constraints.txt", "samples/[\\S/]*constraints-test.txt"] + } +} From 88886f2655250bbcb0bdf545ef0c1b53c03b201e Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Mon, 29 Aug 2022 15:28:59 -0400 Subject: [PATCH 152/279] chore(python): update dependency distlib (#235) Source-Link: https://github.com/googleapis/synthtool/commit/c4dd5953003d13b239f872d329c3146586bb417e Post-Processor: gcr.io/cloud-devrel-public-resources/owlbot-python:latest@sha256:ce3c1686bc81145c81dd269bd12c4025c6b275b22d14641358827334fddb1d72 Co-authored-by: Owl Bot --- packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml | 4 ++-- packages/gcp-sphinx-docfx-yaml/.kokoro/requirements.txt | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml index c6acdf3f90c4..23e106b65770 100644 --- a/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml +++ b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml @@ -13,5 +13,5 @@ # limitations under the License. docker: image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest - digest: sha256:562802bfac02e012a6ac34eda282f81d06e77326b82a32d7bbb1369ff552b387 -# created: 2022-08-24T17:07:22.006876712Z + digest: sha256:ce3c1686bc81145c81dd269bd12c4025c6b275b22d14641358827334fddb1d72 +# created: 2022-08-29T17:28:30.441852797Z diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/requirements.txt b/packages/gcp-sphinx-docfx-yaml/.kokoro/requirements.txt index c4b824f247e3..4b29ef247bed 100644 --- a/packages/gcp-sphinx-docfx-yaml/.kokoro/requirements.txt +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/requirements.txt @@ -136,9 +136,9 @@ cryptography==37.0.4 \ # via # gcp-releasetool # secretstorage -distlib==0.3.5 \ - --hash=sha256:a7f75737c70be3b25e2bee06288cec4e4c221de18455b2dd037fe2a795cab2fe \ - --hash=sha256:b710088c59f06338ca514800ad795a132da19fda270e3ce4affc74abf955a26c +distlib==0.3.6 \ + --hash=sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46 \ + --hash=sha256:f35c4b692542ca110de7ef0bea44d73981caeb34ca0b9b6b2e6d7790dda8f80e # via virtualenv docutils==0.19 \ --hash=sha256:33995a6753c30b7f577febfc2c50411fec6aac7f7ffeb7c4cfe5991072dcf9e6 \ From 6c8e021677c1aa495f3f78bb4e2c7a298e9ed391 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Thu, 1 Sep 2022 16:11:09 +0200 Subject: [PATCH 153/279] chore(deps): update dependency black to v22.8.0 (#238) --- packages/gcp-sphinx-docfx-yaml/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/requirements.txt b/packages/gcp-sphinx-docfx-yaml/requirements.txt index 04b221ff0edd..28fea3c27d11 100644 --- a/packages/gcp-sphinx-docfx-yaml/requirements.txt +++ b/packages/gcp-sphinx-docfx-yaml/requirements.txt @@ -1,4 +1,4 @@ -black==22.6.0 +black==22.8.0 parameterized==0.8.1 # google-resumable-media-python requires manual update as this repo isn't templated. # python-api-core also requires manual update as it is not templated. From ec7229b3c313531004c64a5d68959873fbb0f189 Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Thu, 1 Sep 2022 13:27:28 -0500 Subject: [PATCH 154/279] ci(python): fix path to requirements.txt in release script (#240) Source-Link: https://github.com/googleapis/synthtool/commit/fdba3ed145bdb2f4f3eff434d4284b1d03b80d34 Post-Processor: gcr.io/cloud-devrel-public-resources/owlbot-python:latest@sha256:1f0dbd02745fb7cf255563dab5968345989308544e52b7f460deadd5e78e63b0 Co-authored-by: Owl Bot --- .../.github/.OwlBot.lock.yaml | 3 +-- .../gcp-sphinx-docfx-yaml/.kokoro/release.sh | 2 +- .../.kokoro/requirements.txt | 24 +++++++++---------- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml index 23e106b65770..0d9eb2af9352 100644 --- a/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml +++ b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml @@ -13,5 +13,4 @@ # limitations under the License. docker: image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest - digest: sha256:ce3c1686bc81145c81dd269bd12c4025c6b275b22d14641358827334fddb1d72 -# created: 2022-08-29T17:28:30.441852797Z + digest: sha256:1f0dbd02745fb7cf255563dab5968345989308544e52b7f460deadd5e78e63b0 diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/release.sh b/packages/gcp-sphinx-docfx-yaml/.kokoro/release.sh index 8a9997df2d4b..103d216d8b4d 100755 --- a/packages/gcp-sphinx-docfx-yaml/.kokoro/release.sh +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/release.sh @@ -16,7 +16,7 @@ set -eo pipefail # Start the releasetool reporter -python3 -m pip install --require-hashes -r .kokoro/requirements.txt +python3 -m pip install --require-hashes -r github/sphinx-docfx-yaml/.kokoro/requirements.txt python3 -m releasetool publish-reporter-script > /tmp/publisher-script; source /tmp/publisher-script # Disable buffering, so that the logs stream through. diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/requirements.txt b/packages/gcp-sphinx-docfx-yaml/.kokoro/requirements.txt index 4b29ef247bed..92b2f727e777 100644 --- a/packages/gcp-sphinx-docfx-yaml/.kokoro/requirements.txt +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/requirements.txt @@ -100,9 +100,9 @@ click==8.0.4 \ # via # gcp-docuploader # gcp-releasetool -colorlog==6.6.0 \ - --hash=sha256:344f73204009e4c83c5b6beb00b3c45dc70fcdae3c80db919e0a4171d006fde8 \ - --hash=sha256:351c51e866c86c3217f08e4b067a7974a678be78f07f85fc2d55b8babde6d94e +colorlog==6.7.0 \ + --hash=sha256:0d33ca236784a1ba3ff9c532d4964126d8a2c44f1f0cb1d2b0728196f512f662 \ + --hash=sha256:bd94bd21c1e13fac7bd3153f4bc3a7dc0eb0974b8bc2fdf1a989e474f6e582e5 # via # gcp-docuploader # nox @@ -152,9 +152,9 @@ gcp-docuploader==0.6.3 \ --hash=sha256:ba8c9d76b3bbac54b0311c503a373b00edc2dc02d6d54ea9507045adb8e870f7 \ --hash=sha256:c0f5aaa82ce1854a386197e4e359b120ad6d4e57ae2c812fce42219a3288026b # via -r requirements.in -gcp-releasetool==1.8.6 \ - --hash=sha256:42e51ab8e2e789bc8e22a03c09352962cd3452951c801a2230d564816630304a \ - --hash=sha256:a3518b79d1b243c494eac392a01c7fd65187fd6d52602dcab9b529bc934d4da1 +gcp-releasetool==1.8.7 \ + --hash=sha256:3d2a67c9db39322194afb3b427e9cb0476ce8f2a04033695f0aeb63979fc2b37 \ + --hash=sha256:5e4d28f66e90780d77f3ecf1e9155852b0c3b13cbccb08ab07e66b2357c8da8d # via -r requirements.in google-api-core==2.8.2 \ --hash=sha256:06f7244c640322b508b125903bb5701bebabce8832f85aba9335ec00b3d02edc \ @@ -251,9 +251,9 @@ jinja2==3.1.2 \ --hash=sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852 \ --hash=sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61 # via gcp-releasetool -keyring==23.8.2 \ - --hash=sha256:0d9973f8891850f1ade5f26aafd06bb16865fbbae3fc56b0defb6a14a2624003 \ - --hash=sha256:10d2a8639663fe2090705a00b8c47c687cacdf97598ea9c11456679fa974473a +keyring==23.9.0 \ + --hash=sha256:4c32a31174faaee48f43a7e2c7e9c3216ec5e95acf22a2bebfb4a1d05056ee44 \ + --hash=sha256:98f060ec95ada2ab910c195a2d4317be6ef87936a766b239c46aa3c7aac4f0db # via # gcp-releasetool # twine @@ -440,9 +440,9 @@ urllib3==1.26.12 \ # via # requests # twine -virtualenv==20.16.3 \ - --hash=sha256:4193b7bc8a6cd23e4eb251ac64f29b4398ab2c233531e66e40b19a6b7b0d30c1 \ - --hash=sha256:d86ea0bb50e06252d79e6c241507cb904fcd66090c3271381372d6221a3970f9 +virtualenv==20.16.4 \ + --hash=sha256:014f766e4134d0008dcaa1f95bafa0fb0f575795d07cae50b1bee514185d6782 \ + --hash=sha256:035ed57acce4ac35c82c9d8802202b0e71adac011a511ff650cbcf9635006a22 # via nox webencodings==0.5.1 \ --hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \ From d6ff6e5dc736857821b840066f1d0c7ba0abbe80 Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Thu, 1 Sep 2022 18:10:58 -0500 Subject: [PATCH 155/279] chore(python): update .kokoro/requirements.txt (#242) Source-Link: https://github.com/googleapis/synthtool/commit/703554a14c7479542335b62fa69279f93a9e38ec Post-Processor: gcr.io/cloud-devrel-public-resources/owlbot-python:latest@sha256:94961fdc5c9ca6d13530a6a414a49d2f607203168215d074cdb0a1df9ec31c0b Co-authored-by: Owl Bot --- packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml | 2 +- packages/gcp-sphinx-docfx-yaml/.kokoro/requirements.txt | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml index 0d9eb2af9352..2fa0f7c4fe15 100644 --- a/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml +++ b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml @@ -13,4 +13,4 @@ # limitations under the License. docker: image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest - digest: sha256:1f0dbd02745fb7cf255563dab5968345989308544e52b7f460deadd5e78e63b0 + digest: sha256:94961fdc5c9ca6d13530a6a414a49d2f607203168215d074cdb0a1df9ec31c0b diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/requirements.txt b/packages/gcp-sphinx-docfx-yaml/.kokoro/requirements.txt index 92b2f727e777..385f2d4d6106 100644 --- a/packages/gcp-sphinx-docfx-yaml/.kokoro/requirements.txt +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/requirements.txt @@ -241,6 +241,10 @@ importlib-metadata==4.12.0 \ # via # -r requirements.in # twine +jaraco-classes==3.2.2 \ + --hash=sha256:6745f113b0b588239ceb49532aa09c3ebb947433ce311ef2f8e3ad64ebb74594 \ + --hash=sha256:e6ef6fd3fcf4579a7a019d87d1e56a883f4e4c35cfe925f86731abc58804e647 + # via keyring jeepney==0.8.0 \ --hash=sha256:5efe48d255973902f6badc3ce55e2aa6c5c3b3bc642059ef3a91247bcfcc5806 \ --hash=sha256:c0a454ad016ca575060802ee4d590dd912e35c122fa04e70306de3d076cce755 @@ -299,6 +303,10 @@ markupsafe==2.1.1 \ --hash=sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a \ --hash=sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7 # via jinja2 +more-itertools==8.14.0 \ + --hash=sha256:1bc4f91ee5b1b31ac7ceacc17c09befe6a40a503907baf9c839c229b5095cfd2 \ + --hash=sha256:c09443cd3d5438b8dafccd867a6bc1cb0894389e90cb53d227456b0b0bccb750 + # via jaraco-classes nox==2022.8.7 \ --hash=sha256:1b894940551dc5c389f9271d197ca5d655d40bdc6ccf93ed6880e4042760a34b \ --hash=sha256:96cca88779e08282a699d672258ec01eb7c792d35bbbf538c723172bce23212c From 862d1e732ebe8dde9eb2beca4aefb4e2d7d76fce Mon Sep 17 00:00:00 2001 From: "gcf-owl-bot[bot]" <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Date: Fri, 2 Sep 2022 11:28:23 -0500 Subject: [PATCH 156/279] chore(python): exclude setup.py in renovate config (#244) Source-Link: https://github.com/googleapis/synthtool/commit/56da63e80c384a871356d1ea6640802017f213b4 Post-Processor: gcr.io/cloud-devrel-public-resources/owlbot-python:latest@sha256:993a058718e84a82fda04c3177e58f0a43281a996c7c395e0a56ccc4d6d210d7 Co-authored-by: Owl Bot --- packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml | 2 +- packages/gcp-sphinx-docfx-yaml/renovate.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml index 2fa0f7c4fe15..b8dcb4a4af99 100644 --- a/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml +++ b/packages/gcp-sphinx-docfx-yaml/.github/.OwlBot.lock.yaml @@ -13,4 +13,4 @@ # limitations under the License. docker: image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest - digest: sha256:94961fdc5c9ca6d13530a6a414a49d2f607203168215d074cdb0a1df9ec31c0b + digest: sha256:993a058718e84a82fda04c3177e58f0a43281a996c7c395e0a56ccc4d6d210d7 diff --git a/packages/gcp-sphinx-docfx-yaml/renovate.json b/packages/gcp-sphinx-docfx-yaml/renovate.json index 566a70f3cc3c..39b2a0ec9296 100644 --- a/packages/gcp-sphinx-docfx-yaml/renovate.json +++ b/packages/gcp-sphinx-docfx-yaml/renovate.json @@ -5,7 +5,7 @@ ":preserveSemverRanges", ":disableDependencyDashboard" ], - "ignorePaths": [".pre-commit-config.yaml", ".kokoro/requirements.txt"], + "ignorePaths": [".pre-commit-config.yaml", ".kokoro/requirements.txt", "setup.py"], "pip_requirements": { "fileMatch": ["requirements-test.txt", "samples/[\\S/]*constraints.txt", "samples/[\\S/]*constraints-test.txt"] } From 723591caf4dffff74306cc52bcc2ee97f0a29957 Mon Sep 17 00:00:00 2001 From: Anthonios Partheniou Date: Tue, 6 Sep 2022 12:06:11 -0400 Subject: [PATCH 157/279] chore: delete duplicate renovate.json (#247) Removes `.github/renovate.json` and uses the templated `renovate.json` [here](https://github.com/googleapis/sphinx-docfx-yaml/blob/main/renovate.json) --- packages/gcp-sphinx-docfx-yaml/.github/renovate.json | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 packages/gcp-sphinx-docfx-yaml/.github/renovate.json diff --git a/packages/gcp-sphinx-docfx-yaml/.github/renovate.json b/packages/gcp-sphinx-docfx-yaml/.github/renovate.json deleted file mode 100644 index 9fa8816fe873..000000000000 --- a/packages/gcp-sphinx-docfx-yaml/.github/renovate.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "extends": [ - "config:base", - ":preserveSemverRanges", - ":disableDependencyDashboard" - ], - "ignorePaths": [".pre-commit-config.yaml"], - "pip_requirements": { - "fileMatch": ["requirements-test.txt", "samples/[\\S/]*constraints.txt", "samples/[\\S/]*constraints-test.txt"] - } -} From 2e4a5836459ddb501dde46fa31e10e5f5234f194 Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Fri, 23 Sep 2022 14:47:32 -0400 Subject: [PATCH 158/279] chore: consolidate install to requirements with hash (#249) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: consolidate install to requirements with hash * chore: update owlbot * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * chore: update owlbot * chore: update dependencies and install path Co-authored-by: Owl Bot --- .../.kokoro/generate-docs.sh | 6 +- .../.kokoro/requirements.in | 9 +- .../.kokoro/requirements.txt | 232 +++++++++++++++++- packages/gcp-sphinx-docfx-yaml/owlbot.py | 9 +- 4 files changed, 237 insertions(+), 19 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh b/packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh index 9ee83fc68ce9..0ce226fafd5c 100755 --- a/packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/generate-docs.sh @@ -29,12 +29,8 @@ export GOOGLE_APPLICATION_CREDENTIALS=$KOKORO_KEYSTORE_DIR/73713_docuploader_ser gcloud auth activate-service-account --key-file ${GOOGLE_APPLICATION_CREDENTIALS} # Install dependencies. -python3 -m pip install --user --quiet --upgrade nox -python3 -m pip install --user gcp-docuploader +python3 -m pip install --require-hashes -r .kokoro/requirements.txt python3 -m pip install -e . -python3 -m pip install recommonmark -# Required for some client libraries: -python3 -m pip install --user django==2.2 ipython # Store the contents of bucket log in a variable to reuse. python_bucket_items=$(gsutil ls "gs://docs-staging-v2/docfx-python*") diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/requirements.in b/packages/gcp-sphinx-docfx-yaml/.kokoro/requirements.in index 7718391a34d7..3268861d3722 100644 --- a/packages/gcp-sphinx-docfx-yaml/.kokoro/requirements.in +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/requirements.in @@ -5,4 +5,11 @@ typing-extensions twine wheel setuptools -nox \ No newline at end of file +nox +tox +sphinx==4.5.0 +recommonmark +django==2.2 +ipython +black==22.8.0 +parameterized==0.8.1 \ No newline at end of file diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/requirements.txt b/packages/gcp-sphinx-docfx-yaml/.kokoro/requirements.txt index 385f2d4d6106..fa04dc96640c 100644 --- a/packages/gcp-sphinx-docfx-yaml/.kokoro/requirements.txt +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/requirements.txt @@ -1,17 +1,58 @@ # -# This file is autogenerated by pip-compile with python 3.10 +# This file is autogenerated by pip-compile with python 3.9 # To update, run: # # pip-compile --allow-unsafe --generate-hashes requirements.in # +alabaster==0.7.12 \ + --hash=sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359 \ + --hash=sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02 + # via sphinx argcomplete==2.0.0 \ --hash=sha256:6372ad78c89d662035101418ae253668445b391755cfe94ea52f1b9d22425b20 \ --hash=sha256:cffa11ea77999bb0dd27bb25ff6dc142a6796142f68d45b1a26b11f58724561e # via nox +asttokens==2.0.8 \ + --hash=sha256:c61e16246ecfb2cde2958406b4c8ebc043c9e6d73aaa83c941673b35e5d3a76b \ + --hash=sha256:e3305297c744ae53ffa032c45dc347286165e4ffce6875dc662b205db0623d86 + # via stack-data attrs==22.1.0 \ --hash=sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6 \ --hash=sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c # via gcp-releasetool +babel==2.10.3 \ + --hash=sha256:7614553711ee97490f732126dc077f8d0ae084ebc6a96e23db1482afabdb2c51 \ + --hash=sha256:ff56f4892c1c4bf0d814575ea23471c230d544203c7748e8c68f0089478d48eb + # via sphinx +backcall==0.2.0 \ + --hash=sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e \ + --hash=sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255 + # via ipython +black==22.8.0 \ + --hash=sha256:0a12e4e1353819af41df998b02c6742643cfef58282915f781d0e4dd7a200411 \ + --hash=sha256:0ad827325a3a634bae88ae7747db1a395d5ee02cf05d9aa7a9bd77dfb10e940c \ + --hash=sha256:32a4b17f644fc288c6ee2bafdf5e3b045f4eff84693ac069d87b1a347d861497 \ + --hash=sha256:3b2c25f8dea5e8444bdc6788a2f543e1fb01494e144480bc17f806178378005e \ + --hash=sha256:4a098a69a02596e1f2a58a2a1c8d5a05d5a74461af552b371e82f9fa4ada8342 \ + --hash=sha256:5107ea36b2b61917956d018bd25129baf9ad1125e39324a9b18248d362156a27 \ + --hash=sha256:53198e28a1fb865e9fe97f88220da2e44df6da82b18833b588b1883b16bb5d41 \ + --hash=sha256:5594efbdc35426e35a7defa1ea1a1cb97c7dbd34c0e49af7fb593a36bd45edab \ + --hash=sha256:5b879eb439094751185d1cfdca43023bc6786bd3c60372462b6f051efa6281a5 \ + --hash=sha256:78dd85caaab7c3153054756b9fe8c611efa63d9e7aecfa33e533060cb14b6d16 \ + --hash=sha256:792f7eb540ba9a17e8656538701d3eb1afcb134e3b45b71f20b25c77a8db7e6e \ + --hash=sha256:8ce13ffed7e66dda0da3e0b2eb1bdfc83f5812f66e09aca2b0978593ed636b6c \ + --hash=sha256:a05da0430bd5ced89176db098567973be52ce175a55677436a271102d7eaa3fe \ + --hash=sha256:a983526af1bea1e4cf6768e649990f28ee4f4137266921c2c3cee8116ae42ec3 \ + --hash=sha256:bc4d4123830a2d190e9cc42a2e43570f82ace35c3aeb26a512a2102bce5af7ec \ + --hash=sha256:c3a73f66b6d5ba7288cd5d6dad9b4c9b43f4e8a4b789a94bf5abfb878c663eb3 \ + --hash=sha256:ce957f1d6b78a8a231b18e0dd2d94a33d2ba738cd88a7fe64f53f659eea49fdd \ + --hash=sha256:cea1b2542d4e2c02c332e83150e41e3ca80dc0fb8de20df3c5e98e242156222c \ + --hash=sha256:d2c21d439b2baf7aa80d6dd4e3659259be64c6f49dfd0f32091063db0e006db4 \ + --hash=sha256:d839150f61d09e7217f52917259831fe2b689f5c8e5e32611736351b89bb2a90 \ + --hash=sha256:dd82842bb272297503cbec1a2600b6bfb338dae017186f8f215c8958f8acf869 \ + --hash=sha256:e8166b7bfe5dcb56d325385bd1d1e0f635f24aae14b3ae437102dedc0c186747 \ + --hash=sha256:e981e20ec152dfb3e77418fb616077937378b322d7b26aa1ff87717fb18b4875 + # via -r requirements.in bleach==5.0.1 \ --hash=sha256:085f7f33c15bd408dd9b17a4ad77c577db66d76203e5984b1bd59baeee948b2a \ --hash=sha256:0d03255c47eb9bd2f26aa9bb7f2107732e7e8fe195ca2f64709fcf3b0a4a085c @@ -98,6 +139,7 @@ click==8.0.4 \ --hash=sha256:6a7a62563bbfabfda3a38f3023a1db4a35978c0abd76f6c9605ecd6554d6d9b1 \ --hash=sha256:8458d7b1287c5fb128c90e23381cf99dcde74beaf6c7ff6384ce84d6fe090adb # via + # black # gcp-docuploader # gcp-releasetool colorlog==6.7.0 \ @@ -109,7 +151,9 @@ colorlog==6.7.0 \ commonmark==0.9.1 \ --hash=sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60 \ --hash=sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9 - # via rich + # via + # recommonmark + # rich cryptography==37.0.4 \ --hash=sha256:190f82f3e87033821828f60787cfa42bff98404483577b591429ed99bed39d59 \ --hash=sha256:2be53f9f5505673eeda5f2736bea736c40f051a739bfae2f92d18aed1eb54596 \ @@ -136,18 +180,35 @@ cryptography==37.0.4 \ # via # gcp-releasetool # secretstorage +decorator==5.1.1 \ + --hash=sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330 \ + --hash=sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186 + # via ipython distlib==0.3.6 \ --hash=sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46 \ --hash=sha256:f35c4b692542ca110de7ef0bea44d73981caeb34ca0b9b6b2e6d7790dda8f80e # via virtualenv -docutils==0.19 \ - --hash=sha256:33995a6753c30b7f577febfc2c50411fec6aac7f7ffeb7c4cfe5991072dcf9e6 \ - --hash=sha256:5e1de4d849fee02c63b040a4a3fd567f4ab104defd8a5511fbbc24a8a017efbc - # via readme-renderer +django==2.2 \ + --hash=sha256:7c3543e4fb070d14e10926189a7fcf42ba919263b7473dceaefce34d54e8a119 \ + --hash=sha256:a2814bffd1f007805b19194eb0b9a331933b82bd5da1c3ba3d7b7ba16e06dc4b + # via -r requirements.in +docutils==0.17.1 \ + --hash=sha256:686577d2e4c32380bb50cbb22f575ed742d58168cee37e99117a854bcd88f125 \ + --hash=sha256:cf316c8370a737a022b72b56874f6602acf974a37a9fba42ec2876387549fc61 + # via + # readme-renderer + # recommonmark + # sphinx +executing==1.0.0 \ + --hash=sha256:550d581b497228b572235e633599133eeee67073c65914ca346100ad56775349 \ + --hash=sha256:98daefa9d1916a4f0d944880d5aeaf079e05585689bebd9ff9b32e31dd5e1017 + # via stack-data filelock==3.8.0 \ --hash=sha256:55447caa666f2198c5b6b13a26d2084d26fa5b115c00d065664b2124680c4edc \ --hash=sha256:617eb4e5eedc82fc5f47b6d61e4d11cb837c56cb4544e39081099fa17ad109d4 - # via virtualenv + # via + # tox + # virtualenv gcp-docuploader==0.6.3 \ --hash=sha256:ba8c9d76b3bbac54b0311c503a373b00edc2dc02d6d54ea9507045adb8e870f7 \ --hash=sha256:c0f5aaa82ce1854a386197e4e359b120ad6d4e57ae2c812fce42219a3288026b @@ -235,16 +296,30 @@ idna==3.3 \ --hash=sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff \ --hash=sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d # via requests +imagesize==1.4.1 \ + --hash=sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b \ + --hash=sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a + # via sphinx importlib-metadata==4.12.0 \ --hash=sha256:637245b8bab2b6502fcbc752cc4b7a6f6243bb02b31c5c26156ad103d3d45670 \ --hash=sha256:7401a975809ea1fdc658c3aa4f78cc2195a0e019c5cbc4c06122884e9ae80c23 # via # -r requirements.in + # keyring + # sphinx # twine +ipython==8.5.0 \ + --hash=sha256:097bdf5cd87576fd066179c9f7f208004f7a6864ee1b20f37d346c0bcb099f84 \ + --hash=sha256:6f090e29ab8ef8643e521763a4f1f39dc3914db643122b1e9d3328ff2e43ada2 + # via -r requirements.in jaraco-classes==3.2.2 \ --hash=sha256:6745f113b0b588239ceb49532aa09c3ebb947433ce311ef2f8e3ad64ebb74594 \ --hash=sha256:e6ef6fd3fcf4579a7a019d87d1e56a883f4e4c35cfe925f86731abc58804e647 # via keyring +jedi==0.18.1 \ + --hash=sha256:637c9635fcf47945ceb91cd7f320234a7be540ded6f3e99a50cb6febdfd1ba8d \ + --hash=sha256:74137626a64a99c8eb6ae5832d99b3bdd7d29a3850fe2aa80a4126b2a7d949ab + # via ipython jeepney==0.8.0 \ --hash=sha256:5efe48d255973902f6badc3ce55e2aa6c5c3b3bc642059ef3a91247bcfcc5806 \ --hash=sha256:c0a454ad016ca575060802ee4d590dd912e35c122fa04e70306de3d076cce755 @@ -254,7 +329,9 @@ jeepney==0.8.0 \ jinja2==3.1.2 \ --hash=sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852 \ --hash=sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61 - # via gcp-releasetool + # via + # gcp-releasetool + # sphinx keyring==23.9.0 \ --hash=sha256:4c32a31174faaee48f43a7e2c7e9c3216ec5e95acf22a2bebfb4a1d05056ee44 \ --hash=sha256:98f060ec95ada2ab910c195a2d4317be6ef87936a766b239c46aa3c7aac4f0db @@ -303,10 +380,18 @@ markupsafe==2.1.1 \ --hash=sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a \ --hash=sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7 # via jinja2 +matplotlib-inline==0.1.6 \ + --hash=sha256:f1f41aab5328aa5aaea9b16d083b128102f8712542f819fe7e6a420ff581b311 \ + --hash=sha256:f887e5f10ba98e8d2b150ddcf4702c1e5f8b3a20005eb0f74bfdbd360ee6f304 + # via ipython more-itertools==8.14.0 \ --hash=sha256:1bc4f91ee5b1b31ac7ceacc17c09befe6a40a503907baf9c839c229b5095cfd2 \ --hash=sha256:c09443cd3d5438b8dafccd867a6bc1cb0894389e90cb53d227456b0b0bccb750 # via jaraco-classes +mypy-extensions==0.4.3 \ + --hash=sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d \ + --hash=sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8 + # via black nox==2022.8.7 \ --hash=sha256:1b894940551dc5c389f9271d197ca5d655d40bdc6ccf93ed6880e4042760a34b \ --hash=sha256:96cca88779e08282a699d672258ec01eb7c792d35bbbf538c723172bce23212c @@ -317,6 +402,28 @@ packaging==21.3 \ # via # gcp-releasetool # nox + # sphinx + # tox +parameterized==0.8.1 \ + --hash=sha256:41bbff37d6186430f77f900d777e5bb6a24928a1c46fb1de692f8b52b8833b5c \ + --hash=sha256:9cbb0b69a03e8695d68b3399a8a5825200976536fe1cb79db60ed6a4c8c9efe9 + # via -r requirements.in +parso==0.8.3 \ + --hash=sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0 \ + --hash=sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75 + # via jedi +pathspec==0.10.1 \ + --hash=sha256:46846318467efc4556ccfd27816e004270a9eeeeb4d062ce5e6fc7a87c573f93 \ + --hash=sha256:7ace6161b621d31e7902eb6b5ae148d12cfd23f4a249b9ffb6b9fee12084323d + # via black +pexpect==4.8.0 \ + --hash=sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937 \ + --hash=sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c + # via ipython +pickleshare==0.7.5 \ + --hash=sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca \ + --hash=sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56 + # via ipython pkginfo==1.8.3 \ --hash=sha256:848865108ec99d4901b2f7e84058b6e7660aae8ae10164e015a6dcf5b242a594 \ --hash=sha256:a84da4318dd86f870a9447a8c98340aa06216bfc6f2b7bdc4b8766984ae1867c @@ -324,7 +431,17 @@ pkginfo==1.8.3 \ platformdirs==2.5.2 \ --hash=sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788 \ --hash=sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19 - # via virtualenv + # via + # black + # virtualenv +pluggy==1.0.0 \ + --hash=sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159 \ + --hash=sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3 + # via tox +prompt-toolkit==3.0.31 \ + --hash=sha256:9696f386133df0fc8ca5af4895afe5d78f5fcfe5258111c2a79a1c3e41ffa96d \ + --hash=sha256:9ada952c9d1787f52ff6d5f3484d0b4df8952787c087edf6a1f7c2cb1ea88148 + # via ipython protobuf==3.20.1 \ --hash=sha256:06059eb6953ff01e56a25cd02cca1a9649a75a7e65397b5b9b4e929ed71d10cf \ --hash=sha256:097c5d8a9808302fb0da7e20edf0b8d4703274d140fd25c5edabddcde43e081f \ @@ -354,10 +471,20 @@ protobuf==3.20.1 \ # gcp-docuploader # gcp-releasetool # google-api-core +ptyprocess==0.7.0 \ + --hash=sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35 \ + --hash=sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220 + # via pexpect +pure-eval==0.2.2 \ + --hash=sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350 \ + --hash=sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3 + # via stack-data py==1.11.0 \ --hash=sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719 \ --hash=sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378 - # via nox + # via + # nox + # tox pyasn1==0.4.8 \ --hash=sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d \ --hash=sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba @@ -376,8 +503,10 @@ pygments==2.13.0 \ --hash=sha256:56a8508ae95f98e2b9bdf93a6be5ae3f7d8af858b43e02c5a2ff083726be40c1 \ --hash=sha256:f643f331ab57ba3c9d89212ee4a2dabc6e94f117cf4eefde99a0574720d14c42 # via + # ipython # readme-renderer # rich + # sphinx pyjwt==2.4.0 \ --hash=sha256:72d1d253f32dbd4f5c88eaf1fdc62f3a19f676ccbadb9dbc5d07e951b2b26daf \ --hash=sha256:d42908208c699b3b973cbeb01a969ba6a96c821eefb1c5bfe4c390c01d67abba @@ -393,10 +522,20 @@ python-dateutil==2.8.2 \ --hash=sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86 \ --hash=sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9 # via gcp-releasetool +pytz==2022.2.1 \ + --hash=sha256:220f481bdafa09c3955dfbdddb7b57780e9a94f5127e35456a48589b9e0c0197 \ + --hash=sha256:cea221417204f2d1a2aa03ddae3e867921971d0d76f14d87abb4414415bbdcf5 + # via + # babel + # django readme-renderer==37.0 \ --hash=sha256:07b7ea234e03e58f77cc222e206e6abb8f4c0435becce5104794ee591f9301c5 \ --hash=sha256:9fa416704703e509eeb900696751c908ddeb2011319d93700d8f18baff887a69 # via twine +recommonmark==0.7.1 \ + --hash=sha256:1b1db69af0231efce3fa21b94ff627ea33dee7079a01dd0a7f8482c3da148b3f \ + --hash=sha256:bdb4db649f2222dcd8d2d844f0006b958d627f732415d399791ee436a3686d67 + # via -r requirements.in requests==2.28.1 \ --hash=sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983 \ --hash=sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349 @@ -405,6 +544,7 @@ requests==2.28.1 \ # google-api-core # google-cloud-storage # requests-toolbelt + # sphinx # twine requests-toolbelt==0.9.1 \ --hash=sha256:380606e1d10dc85c3bd47bf5a6095f815ec007be7a8b69c878507068df059e6f \ @@ -430,10 +570,70 @@ six==1.16.0 \ --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 # via + # asttokens # bleach # gcp-docuploader # google-auth # python-dateutil + # tox +snowballstemmer==2.2.0 \ + --hash=sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1 \ + --hash=sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a + # via sphinx +sphinx==4.5.0 \ + --hash=sha256:7bf8ca9637a4ee15af412d1a1d9689fec70523a68ca9bb9127c2f3eeb344e2e6 \ + --hash=sha256:ebf612653238bcc8f4359627a9b7ce44ede6fdd75d9d30f68255c7383d3a6226 + # via + # -r requirements.in + # recommonmark +sphinxcontrib-applehelp==1.0.2 \ + --hash=sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a \ + --hash=sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58 + # via sphinx +sphinxcontrib-devhelp==1.0.2 \ + --hash=sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e \ + --hash=sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4 + # via sphinx +sphinxcontrib-htmlhelp==2.0.0 \ + --hash=sha256:d412243dfb797ae3ec2b59eca0e52dac12e75a241bf0e4eb861e450d06c6ed07 \ + --hash=sha256:f5f8bb2d0d629f398bf47d0d69c07bc13b65f75a81ad9e2f71a63d4b7a2f6db2 + # via sphinx +sphinxcontrib-jsmath==1.0.1 \ + --hash=sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178 \ + --hash=sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8 + # via sphinx +sphinxcontrib-qthelp==1.0.3 \ + --hash=sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72 \ + --hash=sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6 + # via sphinx +sphinxcontrib-serializinghtml==1.1.5 \ + --hash=sha256:352a9a00ae864471d3a7ead8d7d79f5fc0b57e8b3f95e9867eb9eb28999b92fd \ + --hash=sha256:aa5f6de5dfdf809ef505c4895e51ef5c9eac17d0f287933eb49ec495280b6952 + # via sphinx +sqlparse==0.4.2 \ + --hash=sha256:0c00730c74263a94e5a9919ade150dfc3b19c574389985446148402998287dae \ + --hash=sha256:48719e356bb8b42991bdbb1e8b83223757b93789c00910a616a071910ca4a64d + # via django +stack-data==0.5.0 \ + --hash=sha256:66d2ebd3d7f29047612ead465b6cae5371006a71f45037c7e2507d01367bce3b \ + --hash=sha256:715c8855fbf5c43587b141e46cc9d9339cc0d1f8d6e0f98ed0d01c6cb974e29f + # via ipython +tomli==2.0.1 \ + --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ + --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f + # via + # black + # tox +tox==3.26.0 \ + --hash=sha256:44f3c347c68c2c68799d7d44f1808f9d396fc8a1a500cbc624253375c7ae107e \ + --hash=sha256:bf037662d7c740d15c9924ba23bb3e587df20598697bb985ac2b49bdc2d847f6 + # via -r requirements.in +traitlets==5.4.0 \ + --hash=sha256:3f2c4e435e271592fe4390f1746ea56836e3a080f84e7833f0f801d9613fec39 \ + --hash=sha256:93663cc8236093d48150e2af5e2ed30fc7904a11a6195e21bab0408af4e6d6c8 + # via + # ipython + # matplotlib-inline twine==4.0.1 \ --hash=sha256:42026c18e394eac3e06693ee52010baa5313e4811d5a11050e7d48436cf41b9e \ --hash=sha256:96b1cf12f7ae611a4a40b6ae8e9570215daff0611828f5fe1f37a16255ab24a0 @@ -441,7 +641,9 @@ twine==4.0.1 \ typing-extensions==4.3.0 \ --hash=sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02 \ --hash=sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6 - # via -r requirements.in + # via + # -r requirements.in + # black urllib3==1.26.12 \ --hash=sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e \ --hash=sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997 @@ -451,7 +653,13 @@ urllib3==1.26.12 \ virtualenv==20.16.4 \ --hash=sha256:014f766e4134d0008dcaa1f95bafa0fb0f575795d07cae50b1bee514185d6782 \ --hash=sha256:035ed57acce4ac35c82c9d8802202b0e71adac011a511ff650cbcf9635006a22 - # via nox + # via + # nox + # tox +wcwidth==0.2.5 \ + --hash=sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784 \ + --hash=sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83 + # via prompt-toolkit webencodings==0.5.1 \ --hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \ --hash=sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923 diff --git a/packages/gcp-sphinx-docfx-yaml/owlbot.py b/packages/gcp-sphinx-docfx-yaml/owlbot.py index fc1abe226612..96c91507be66 100644 --- a/packages/gcp-sphinx-docfx-yaml/owlbot.py +++ b/packages/gcp-sphinx-docfx-yaml/owlbot.py @@ -41,11 +41,18 @@ ".kokoro/publish-docs.sh", ".kokoro/samples/**", # no samples ".kokoro/test-sample*", + ".kokoro/requirements.txt", # using custom requirements.txt file "CONTRIBUTING.rst", # repo has a CONTRIBUTING.md ".github/CONTRIBUTING.md", ".github/PULL_REQUEST_TEMPLATE.md", ".gitignore", ".github/workflows", # exclude templated gh actions - "README.rst", + "README.rst", ], ) + +s.replace( + ".kokoro/requirements.in", + r"nox", + "\\g<0>\ntox\nsphinx==4.5.0\nrecommonmark\ndjango==2.2\nipython\nblack==22.8.0\nparameterized==0.8.1" +) From 0b5464265bcc882e0eac886c260d5d3678441803 Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Mon, 3 Oct 2022 15:11:46 -0400 Subject: [PATCH 159/279] chore: update renovate and codeowner (#254) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: update renovate and codeowner * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * chore: update owlbot Co-authored-by: Owl Bot --- packages/gcp-sphinx-docfx-yaml/.github/CODEOWNERS | 8 ++++---- packages/gcp-sphinx-docfx-yaml/.repo-metadata.json | 2 +- packages/gcp-sphinx-docfx-yaml/owlbot.py | 1 + packages/gcp-sphinx-docfx-yaml/renovate.json | 1 - 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/.github/CODEOWNERS b/packages/gcp-sphinx-docfx-yaml/.github/CODEOWNERS index 828d46300d45..5464d215573a 100644 --- a/packages/gcp-sphinx-docfx-yaml/.github/CODEOWNERS +++ b/packages/gcp-sphinx-docfx-yaml/.github/CODEOWNERS @@ -5,8 +5,8 @@ # https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners#codeowners-syntax # Note: This file is autogenerated. To make changes to the codeowner team, please update .repo-metadata.json. -# @googleapis/yoshi-python @googleapis/cx-eng are the default owners for changes in this repo -* @googleapis/yoshi-python @googleapis/cx-eng +# @googleapis/yoshi-python @googleapis/dkp are the default owners for changes in this repo +* @googleapis/yoshi-python @googleapis/dkp -# @googleapis/python-samples-reviewers @googleapis/cx-eng are the default owners for samples changes -/samples/ @googleapis/python-samples-reviewers @googleapis/cx-eng +# @googleapis/python-samples-reviewers @googleapis/dkp are the default owners for samples changes +/samples/ @googleapis/python-samples-reviewers @googleapis/dkp diff --git a/packages/gcp-sphinx-docfx-yaml/.repo-metadata.json b/packages/gcp-sphinx-docfx-yaml/.repo-metadata.json index 0528f83fd251..780b4aa24c99 100644 --- a/packages/gcp-sphinx-docfx-yaml/.repo-metadata.json +++ b/packages/gcp-sphinx-docfx-yaml/.repo-metadata.json @@ -8,6 +8,6 @@ "language": "python", "repo": "googleapis/sphinx-docfx-yaml", "distribution_name": "gcp-sphinx-docfx-yaml", - "codeowner_team": "@googleapis/cx-eng", + "codeowner_team": "@googleapis/dkp", "library_type": "OTHER" } diff --git a/packages/gcp-sphinx-docfx-yaml/owlbot.py b/packages/gcp-sphinx-docfx-yaml/owlbot.py index 96c91507be66..d53660b85311 100644 --- a/packages/gcp-sphinx-docfx-yaml/owlbot.py +++ b/packages/gcp-sphinx-docfx-yaml/owlbot.py @@ -48,6 +48,7 @@ ".gitignore", ".github/workflows", # exclude templated gh actions "README.rst", + "renovate.json", ], ) diff --git a/packages/gcp-sphinx-docfx-yaml/renovate.json b/packages/gcp-sphinx-docfx-yaml/renovate.json index 39b2a0ec9296..e75a31a5cce2 100644 --- a/packages/gcp-sphinx-docfx-yaml/renovate.json +++ b/packages/gcp-sphinx-docfx-yaml/renovate.json @@ -1,7 +1,6 @@ { "extends": [ "config:base", - "group:all", ":preserveSemverRanges", ":disableDependencyDashboard" ], From 51d33dd727a0c51b1608f767475a63edaa292a60 Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Wed, 5 Oct 2022 13:25:03 -0400 Subject: [PATCH 160/279] feat: use GitHub's default README as index page (#255) * feat: use GitHub's default README as index page * feat: address review comemnts --- .../docfx_yaml/extension.py | 81 ++++++++++++------- .../tests/markdown_example_bad_image_links.md | 23 ++++++ .../markdown_example_bad_image_links_want.md | 11 +++ .../tests/test_helpers.py | 28 +++++++ 4 files changed, 115 insertions(+), 28 deletions(-) create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/markdown_example_bad_image_links.md create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/markdown_example_bad_image_links_want.md diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index 51afbd973a9d..11b4c3976ee3 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -1429,6 +1429,33 @@ def highlight_md_codeblocks(mdfile): mdfile_iterator.write(new_content) +def clean_image_links(mdfile_path: str) -> None: + """Cleans extra whitespace that breaks image links in index.html file.""" + image_link_pattern='\[\s*!\[image\]\(.*\)\s*\]\(.*\)' + new_lines = [] + with open(mdfile_path) as mdfile: + file_content = mdfile.read() + + prev_start = prev_end = 0 + + for matched_obj in re.finditer(image_link_pattern, file_content): + start = matched_obj.start() + end = matched_obj.end() + matched_str = file_content[start:end] + # Clean up all whitespaces for the image link. + clean_str = ''.join(matched_str.split()) + + new_lines.append(file_content[prev_end:start]) + new_lines.append(clean_str) + prev_start, prev_end = start, end + + new_lines.append(file_content[prev_end:]) + + with open(mdfile_path, 'w') as mdfile: + new_content = ''.join(new_lines) + mdfile.write(new_content) + + def prepend_markdown_header(filename: str, mdfile: Iterable[str]): """Prepends the filename as a Markdown header. @@ -1448,16 +1475,16 @@ def prepend_markdown_header(filename: str, mdfile: Iterable[str]): def find_markdown_pages(app, outdir): # Use this to ignore markdown files that are unnecessary. files_to_ignore = [ - "index.md", # merge index.md and README.md and index.yaml later. - # See https://github.com/googleapis/sphinx-docfx-yaml/issues/105. + "index.md", # use readme.md instead "reference.md", # Reference docs overlap with Overview. Will try and incorporate this in later. # See https://github.com/googleapis/sphinx-docfx-yaml/issues/106. - - "readme.md", # README does not seem to work in cloud site - # See https://github.com/googleapis/sphinx-docfx-yaml/issues/107. ] + files_to_rename = { + 'readme.md': 'index.md', + } + markdown_dir = Path(app.builder.outdir).parent / "markdown" if not markdown_dir.exists(): print("There's no markdown file to move.") @@ -1467,7 +1494,6 @@ def find_markdown_pages(app, outdir): for mdfile in markdown_dir.iterdir(): if mdfile.is_file() and mdfile.name.lower() not in files_to_ignore: mdfile_name = "" - highlight_md_codeblocks(markdown_dir / mdfile.name) # Extract the header name for TOC. with open(mdfile) as mdfile_iterator: @@ -1482,12 +1508,30 @@ def find_markdown_pages(app, outdir): prepend_markdown_header(name, mdfile_iterator) - shutil.copy(mdfile, f"{outdir}/{mdfile.name.lower()}") + mdfile_name_to_use = mdfile.name.lower() + if mdfile_name_to_use in files_to_rename: + mdfile_name_to_use = files_to_rename[mdfile_name_to_use] + + mdfile_outdir = f"{outdir}/{mdfile_name_to_use}" + + shutil.copy(mdfile, mdfile_outdir) + + highlight_md_codeblocks(mdfile_outdir) + clean_image_links(mdfile_outdir) + + # Use Overview as the name for index file. + if mdfile_name_to_use == 'index.md': + # Place the Overview page at the top of the list. + app.env.markdown_pages.insert( + 0, + {'name':'Overview', 'href': 'index.md'} + ) + continue # Add the file to the TOC later. app.env.markdown_pages.append({ 'name': name, - 'href': mdfile.name.lower(), + 'href': mdfile_name_to_use, }) def find_uid_to_convert( @@ -1941,7 +1985,7 @@ def convert_module_to_package_if_needed(obj): dump( [{ 'name': app.config.project, - 'items': [{'name': 'Overview', 'uid': 'project-' + app.config.project}] + app.env.markdown_pages + pkg_toc_yaml + 'items': app.env.markdown_pages + pkg_toc_yaml }], default_flow_style=False, ) @@ -2001,25 +2045,6 @@ def convert_module_to_package_if_needed(obj): 'fullname': item.get('uidname', ''), 'isExternal': False }) - with open(index_file, 'w') as index_file_obj: - index_file_obj.write('### YamlMime:UniversalReference\n') - dump( - { - 'items': [{ - 'uid': 'project-' + app.config.project, - 'name': app.config.project, - 'fullName': app.config.project, - 'langs': ['python'], - 'type': 'package', - 'kind': 'distribution', - 'summary': 'Reference API documentation for `{}`.'.format(app.config.project), - 'children': index_children - }], - 'references': index_references - }, - index_file_obj, - default_flow_style=False - ) ''' # TODO: handle xref for other products. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_bad_image_links.md b/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_bad_image_links.md new file mode 100644 index 000000000000..d09059c85195 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_bad_image_links.md @@ -0,0 +1,23 @@ +# Python Client for Google Cloud Storage API + +[ + +![image](https://img.shields.io/badge/support-stable-gold.svg) + +](https://github.com/googleapis/google-cloud-python/blob/main/README.rst#stability-levels) [ + +![image](https://img.shields.io/pypi/v/google-cloud-storage.svg) + +](https://pypi.org/project/google-cloud-storage/) [ + +![image](https://img.shields.io/pypi/pyversions/google-cloud-storage.svg) + +](https://pypi.org/project/google-cloud-storage/) + +[Google Cloud Storage API](https://cloud.google.com/storage): is a durable and highly available object storage service. Google Cloud Storage is almost infinitely scalable and guarantees consistency: when a write succeeds, the latest copy of the object will be returned to any GET, globally. + + +* [Client Library Documentation](https://cloud.google.com/python/docs/reference/storage/latest) + + +* [Product Documentation](https://cloud.google.com/storage) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_bad_image_links_want.md b/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_bad_image_links_want.md new file mode 100644 index 000000000000..fa01fb2989aa --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/markdown_example_bad_image_links_want.md @@ -0,0 +1,11 @@ +# Python Client for Google Cloud Storage API + +[![image](https://img.shields.io/badge/support-stable-gold.svg)](https://github.com/googleapis/google-cloud-python/blob/main/README.rst#stability-levels) [![image](https://img.shields.io/pypi/v/google-cloud-storage.svg)](https://pypi.org/project/google-cloud-storage/) [![image](https://img.shields.io/pypi/pyversions/google-cloud-storage.svg)](https://pypi.org/project/google-cloud-storage/) + +[Google Cloud Storage API](https://cloud.google.com/storage): is a durable and highly available object storage service. Google Cloud Storage is almost infinitely scalable and guarantees consistency: when a write succeeds, the latest copy of the object will be returned to any GET, globally. + + +* [Client Library Documentation](https://cloud.google.com/python/docs/reference/storage/latest) + + +* [Product Documentation](https://cloud.google.com/storage) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/test_helpers.py b/packages/gcp-sphinx-docfx-yaml/tests/test_helpers.py index 668b887aeb40..9436ee66b1eb 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/test_helpers.py +++ b/packages/gcp-sphinx-docfx-yaml/tests/test_helpers.py @@ -7,6 +7,7 @@ from docfx_yaml.extension import extract_product_name from docfx_yaml.extension import highlight_md_codeblocks from docfx_yaml.extension import prepend_markdown_header +from docfx_yaml.extension import clean_image_links import unittest from parameterized import parameterized @@ -310,6 +311,33 @@ def test_prepend_markdown_header(self, base_filename, want_filename): self.assertEqual(test_file.read(), mdfile_want.read()) + # Filenames to test cleaning up markdown image links. + test_markdown_filenames = [ + [ + "tests/markdown_example_bad_image_links.md", + "tests/markdown_example_bad_image_links_want.md" + ], + ] + @parameterized.expand(test_markdown_filenames) + def test_clean_image_links(self, base_filename, want_filename): + # Ensure image links are well formed in markdown files. + + # Copy the base file we'll need to test. + with tempfile.NamedTemporaryFile(mode='r+', delete=False) as test_file: + with open(base_filename) as base_file: + # Use same file name extraction as original code. + file_name = base_file.name.split("/")[-1].split(".")[0].capitalize() + test_file.write(base_file.read()) + test_file.flush() + test_file.seek(0) + + clean_image_links(test_file.name) + test_file.seek(0) + + with open(want_filename) as mdfile_want: + self.assertEqual(test_file.read(), mdfile_want.read()) + + test_reference_params = [ [ # If no reference keyword is found, check for None From 3cbb1b09b97dec582286d06436c0155149f116a5 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Fri, 7 Oct 2022 02:06:15 +0200 Subject: [PATCH 161/279] chore(deps): update dependency black to v22.10.0 (#257) --- packages/gcp-sphinx-docfx-yaml/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/requirements.txt b/packages/gcp-sphinx-docfx-yaml/requirements.txt index 28fea3c27d11..620b4c77c050 100644 --- a/packages/gcp-sphinx-docfx-yaml/requirements.txt +++ b/packages/gcp-sphinx-docfx-yaml/requirements.txt @@ -1,4 +1,4 @@ -black==22.8.0 +black==22.10.0 parameterized==0.8.1 # google-resumable-media-python requires manual update as this repo isn't templated. # python-api-core also requires manual update as it is not templated. From f9888d6cf4c63aa8cb7589a6ae2487be974935ee Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Fri, 7 Oct 2022 12:04:05 -0400 Subject: [PATCH 162/279] fix: render emphasis properly and markdown in tables (#258) * fix: render emphasis properly and markdown in tables * test: add and update unit test * fix: address review comments --- .../docfx_yaml/extension.py | 131 ++++++++++++++++-- .../tests/cross_references_post.yaml | 2 +- .../tests/test_helpers.py | 72 ++++++++++ 3 files changed, 191 insertions(+), 14 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index 11b4c3976ee3..d79ddb460ae7 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -83,12 +83,12 @@ class Bcolors: REFFUNCTION = 'func' INITPY = '__init__.py' # Regex expression for checking references of pattern like ":class:`~package_v1.module`" -REF_PATTERN = ':(py:)?(func|class|meth|mod|ref|attr|exc):`~?[a-zA-Z0-9_\.<> ]*(\(\))?`' +REF_PATTERN = ':(py:)?(func|class|meth|mod|ref|attr|exc):`~?[a-zA-Z0-9_.<> ]*(\(\))?`' # Regex expression for checking references of pattern like "~package_v1.subpackage.module" REF_PATTERN_LAST = '~([a-zA-Z0-9_<>]*\.)*[a-zA-Z0-9_<>]*(\(\))?' # Regex expression for checking references of pattern like # "[module][google.cloud.cloudkms_v1.module]" -REF_PATTERN_BRACKETS = '\[[a-zA-Z0-9\_\<\>\-\. ]+\]\[[a-zA-Z0-9\_\<\>\-\. ]+\]' +REF_PATTERN_BRACKETS = '\[[a-zA-Z0-9_<>\-. ]+\]\[[a-zA-Z0-9_<>\-. ]+\]' REF_PATTERNS = [ REF_PATTERN, @@ -758,12 +758,103 @@ def _extract_docstring_info(summary_info, summary, name): words = [] else: words.append(word) - + index += 1 return top_summary +def _reformat_codeblocks(content: str) -> str: + """Formats codeblocks from ``` to
."""
+    triple_backtick = '```'
+    current_tag = '
'
+    next_tag = '
' + # If there are no proper pairs of triple backticks, don't format docstring. + if content.count(triple_backtick) % 2 != 0: + print(f'Docstring is not formatted well, missing proper pairs of triple backticks (```): {content}') + return content + while triple_backtick in content: + content = content.replace(triple_backtick, current_tag, 1) + # Alternate between replacing with
 and 
. + current_tag, next_tag = next_tag, current_tag + + return content + + +def _reformat_code(content: str) -> str: + """Formats code from ` to .""" + reformatted_lines = [] + + code_pattern = '`[^`\n]+`' + code_start = '' + code_end = '' + prev_start = prev_end = 0 + # Convert `text` to text + for matched_obj in re.finditer(code_pattern, content): + start = matched_obj.start() + end = matched_obj.end() + code_content = content[start+1:end-1] + + reformatted_lines.append(content[prev_end:start]) + reformatted_lines.append(f'{code_start}{code_content}{code_end}') + prev_start, prev_end = start, end + + reformatted_lines.append(content[prev_end:]) + + return ''.join(reformatted_lines) + + +def reformat_markdown_to_html(content: str) -> str: + """Applies changes from markdown syntax to equivalent HTML. + + Acts as a wrapper function to format all Markdown to HTML. + + Markdown syntax cannot be used within HTML elements, and must be converted + at YAML level. + + Args: + content: the string to be reformatted. + + Returns: + Content that has been formatted with proper HTML. + """ + + content = _reformat_codeblocks(content) + content = _reformat_code(content) + + return content + + +def reformat_summary(summary: str) -> str: + """Applies any style changes to be made specifically for DocFX YAML. + + Makes the following changes: + - converts ``text`` to `text` + + Args: + summary: The summary to be modified. + + Returns: + Converted summary suitable for DocFX YAML. + """ + + reformatted_lines = [] + + single_backtick = '`' + double_backtick = '``' + triple_backtick = '```' + for line in summary.split('\n'): + # Check that we're only looking for double backtick (``) and not + # comments (```). + if triple_backtick not in line and double_backtick in line: + reformatted_lines.append(line.replace(double_backtick, single_backtick)) + + else: + reformatted_lines.append(line) + + return '\n'.join(reformatted_lines) + + # Returns appropriate product name to display for given full name of entry. def extract_product_name(name): if 'google.cloud' in name: @@ -953,6 +1044,7 @@ def _update_friendly_package_name(path): # Extract summary info into respective sections. if summary: + summary = reformat_summary(summary) top_summary = _extract_docstring_info(summary_info, summary, name) try: datam['summary'], datam['attributes'] = _parse_docstring_summary(top_summary) @@ -1645,81 +1737,94 @@ def search_cross_references(obj, current_object_name: str, known_uids: List[str] if obj["syntax"].get("parameters"): for param in obj["syntax"]["parameters"]: if param.get("description"): - param["description"] = convert_cross_references( + param_description = convert_cross_references( param["description"], current_object_name, known_uids ) + param["description"] = reformat_markdown_to_html(param_description) if param.get("id"): - param["id"] = convert_cross_references( + param_id = convert_cross_references( param["id"], current_object_name, known_uids ) + param["id"] = reformat_markdown_to_html(param_id) if param.get("var_type"): - param["var_type"] = convert_cross_references( + param_type = convert_cross_references( param["var_type"], current_object_name, known_uids ) + param["var_type"] = reformat_markdown_to_html(param_type) if obj["syntax"].get("exceptions"): for exception in obj["syntax"]["exceptions"]: if exception.get("description"): - exception["description"] = convert_cross_references( + exception_description = convert_cross_references( exception["description"], current_object_name, known_uids ) + exception["description"] = ( + reformat_markdown_to_html(exception_description)) if exception.get("var_type"): - exception["var_type"] = convert_cross_references( + exception_type = convert_cross_references( exception["var_type"], current_object_name, known_uids ) + exception["var_type"] = ( + reformat_markdown_to_html(exception_type)) if obj["syntax"].get("returns"): for ret in obj["syntax"]["returns"]: if ret.get("description"): - ret["description"] = convert_cross_references( + ret_description = convert_cross_references( ret["description"], current_object_name, known_uids ) + ret["description"] = reformat_markdown_to_html(ret_description) if ret.get("var_type"): - ret["var_type"] = convert_cross_references( + ret_type = convert_cross_references( ret["var_type"], current_object_name, known_uids ) + ret["var_type"] = reformat_markdown_to_html(ret_type) if obj.get("attributes"): for attribute in obj["attributes"]: if attribute.get("description"): - attribute["description"] = convert_cross_references( + attribute_description = convert_cross_references( attribute["description"], current_object_name, known_uids ) + attribute["description"] = ( + reformat_markdown_to_html(attribute_description)) if attribute.get("id"): - attribute["id"] = convert_cross_references( + attribute_id = convert_cross_references( attribute["id"], current_object_name, known_uids ) + attribute["id"] = reformat_markdown_to_html(attribute_id) if attribute.get("var_type"): - attribute["var_type"] = convert_cross_references( + attribute_type = convert_cross_references( attribute["var_type"], current_object_name, known_uids ) + attribute["var_type"] = reformat_markdown_to_html(attribute_type) def build_finished(app, exception): diff --git a/packages/gcp-sphinx-docfx-yaml/tests/cross_references_post.yaml b/packages/gcp-sphinx-docfx-yaml/tests/cross_references_post.yaml index a7be51817b7b..c61a7256a62d 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/cross_references_post.yaml +++ b/packages/gcp-sphinx-docfx-yaml/tests/cross_references_post.yaml @@ -40,7 +40,7 @@ items: var_type: google.api_core.exceptions.GoogleAPICallError parameters: - description: Required. Name of the stream to start reading from, of the form - `projects/{project_id}/locations/{location}/sessions/{session_id}/streams/{stream_id}` + projects/{project_id}/locations/{location}/sessions/{session_id}/streams/{stream_id} with google.cloud.bigquery_storage_v1.types.SplitReadStreamResponse id: row var_type: google.cloud.bigquery_storage_v1.types.AvroRows diff --git a/packages/gcp-sphinx-docfx-yaml/tests/test_helpers.py b/packages/gcp-sphinx-docfx-yaml/tests/test_helpers.py index 9436ee66b1eb..7cca1c6b87a0 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/test_helpers.py +++ b/packages/gcp-sphinx-docfx-yaml/tests/test_helpers.py @@ -8,6 +8,8 @@ from docfx_yaml.extension import highlight_md_codeblocks from docfx_yaml.extension import prepend_markdown_header from docfx_yaml.extension import clean_image_links +from docfx_yaml.extension import reformat_summary +from docfx_yaml.extension import reformat_markdown_to_html import unittest from parameterized import parameterized @@ -390,6 +392,76 @@ def test_find_uid_to_convert(self, current_word, uids, visited_words, cross_refe ) self.assertEqual(cross_reference_got, cross_reference_want) + test_summary = [ + [ + """Retrieve the ``ID`` for the object. + +See https://cloud.google.com/storage/docs/json_api/v1/objects + +The ID consists of the bucket name, object name, and generation number. + """, + """Retrieve the `ID` for the object. + +See https://cloud.google.com/storage/docs/json_api/v1/objects + +The ID consists of the bucket name, object name, and generation number. + """, + ], + [ + # Test that codeblocks don't get formatted. + """The ID of the blob or `None`. + +if the blob's resource has not been loaded from the server. + +For example: +``` + ID or None +``` + """, + """The ID of the blob or `None`. + +if the blob's resource has not been loaded from the server. + +For example: +``` + ID or None +``` + """, + ], + ] + @parameterized.expand(test_summary) + def test_reformat_summary(self, summary, summary_want): + summary_got = reformat_summary(summary) + self.assertEqual(summary_want, summary_got) + + + test_markdown_content = [ + [ + """The resource name or `None` + +if no Cloud KMS key was used, or the blob's resource has not been loaded from the server. + +For example: +``` + kms_key_name: ID +``` + """, + """The resource name or None + +if no Cloud KMS key was used, or the blob's resource has not been loaded from the server. + +For example: +
+    kms_key_name: ID
+
+ """, + ], + ] + @parameterized.expand(test_markdown_content) + def test_reformat_markdown_to_html(self, content, content_want): + content_got = reformat_markdown_to_html(content) + self.assertEqual(content_want, content_got) + if __name__ == '__main__': unittest.main() From ce3d812c22fa3504a3d6353f59480bfe78d38e72 Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Thu, 13 Oct 2022 11:50:27 -0400 Subject: [PATCH 163/279] refactor: move markdown into its own file & testing (#259) * refactor: move markdown features into its own util file * refactor: update unit tests * refactor: revert assignment operator for 3.7 compatibility * refactor: use typing import for compatibility over collections.abc * refactor: update to import modules only --- .../docfx_yaml/extension.py | 309 +---------------- .../docfx_yaml/markdown_utils.py | 326 ++++++++++++++++++ .../tests/test_helpers.py | 167 +-------- .../tests/test_markdown.py | 252 ++++++++++++++ .../gcp-sphinx-docfx-yaml/tests/test_unit.py | 211 ++---------- packages/gcp-sphinx-docfx-yaml/tox.ini | 2 +- 6 files changed, 642 insertions(+), 625 deletions(-) create mode 100644 packages/gcp-sphinx-docfx-yaml/docfx_yaml/markdown_utils.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/test_markdown.py diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index d79ddb460ae7..61c56830e2c0 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -51,6 +51,7 @@ from .monkeypatch import patch_docfields from .directives import RemarksDirective, TodoDirective from .nodes import remarks +from docfx_yaml import markdown_utils import subprocess import ast @@ -131,29 +132,10 @@ class Bcolors: # Disable blib2to3 output that clutters debugging log. logging.getLogger("blib2to3").setLevel(logging.ERROR) -# Run sphinx-build with Markdown builder in the plugin. -def run_sphinx_markdown(): - cwd = os.getcwd() - # Skip running sphinx-build for Markdown for some unit tests. - # Not required other than to output DocFX YAML. - if "docs" in cwd: - return - - return shell.run( - [ - "sphinx-build", - "-M", - "markdown", - "docs/", - "docs/_build", - ], - hide_output=False - ) - def build_init(app): print("Running sphinx-build with Markdown first...") - run_sphinx_markdown() + markdown_utils.run_sphinx_markdown() print("Completed running sphinx-build with Markdown files.") """ @@ -764,67 +746,6 @@ def _extract_docstring_info(summary_info, summary, name): return top_summary -def _reformat_codeblocks(content: str) -> str: - """Formats codeblocks from ``` to
."""
-    triple_backtick = '```'
-    current_tag = '
'
-    next_tag = '
' - # If there are no proper pairs of triple backticks, don't format docstring. - if content.count(triple_backtick) % 2 != 0: - print(f'Docstring is not formatted well, missing proper pairs of triple backticks (```): {content}') - return content - while triple_backtick in content: - content = content.replace(triple_backtick, current_tag, 1) - # Alternate between replacing with
 and 
. - current_tag, next_tag = next_tag, current_tag - - return content - - -def _reformat_code(content: str) -> str: - """Formats code from ` to .""" - reformatted_lines = [] - - code_pattern = '`[^`\n]+`' - code_start = '' - code_end = '' - prev_start = prev_end = 0 - # Convert `text` to text - for matched_obj in re.finditer(code_pattern, content): - start = matched_obj.start() - end = matched_obj.end() - code_content = content[start+1:end-1] - - reformatted_lines.append(content[prev_end:start]) - reformatted_lines.append(f'{code_start}{code_content}{code_end}') - prev_start, prev_end = start, end - - reformatted_lines.append(content[prev_end:]) - - return ''.join(reformatted_lines) - - -def reformat_markdown_to_html(content: str) -> str: - """Applies changes from markdown syntax to equivalent HTML. - - Acts as a wrapper function to format all Markdown to HTML. - - Markdown syntax cannot be used within HTML elements, and must be converted - at YAML level. - - Args: - content: the string to be reformatted. - - Returns: - Content that has been formatted with proper HTML. - """ - - content = _reformat_codeblocks(content) - content = _reformat_code(content) - - return content - - def reformat_summary(summary: str) -> str: """Applies any style changes to be made specifically for DocFX YAML. @@ -1426,206 +1347,6 @@ def pretty_package_name(package_group): return " ".join(capitalized_name) -# Check is the current lines conform to markdown header format. -def parse_markdown_header(header_line, prev_line): - # Markdown h1 prefix should have only 1 of '#' character followed by exactly one space. - h1_header_prefix = "# " - if h1_header_prefix in header_line and header_line.count("#") == 1: - # Check for proper h1 header formatting, ensure there's more than just - # the hashtag character, and exactly only one space after the hashtag. - if not header_line[header_line.index(h1_header_prefix)+2].isspace() and \ - len(header_line) > 2: - - return header_line[header_line.index(h1_header_prefix):].strip("#").strip() - - elif "=" in header_line: - # Check if we're inspecting an empty or undefined lines. - if not prev_line: - return "" - - # Check if the current line only has equal sign divider. - if header_line.count("=") == len(header_line.strip()): - # Update header to the previous line. - return prev_line.strip() - - return "" - - -def extract_header_from_markdown(mdfile: Iterable[str]) -> str: - """For a given markdown file, extract its header line. - - Args: - mdfile: iterator to the markdown file. - - Returns: - A string for header or empty string if header is not found. - """ - prev_line = "" - - for header_line in mdfile: - - # Ignore licenses and other non-headers prior to the header. - header = parse_markdown_header(header_line, prev_line) - # If we've found the header, return the header. - if header != "": - return header - - prev_line = header_line - - return "" - - -# For a given markdown file, adds syntax highlighting to code blocks. -def highlight_md_codeblocks(mdfile): - fence = '```' - fence_with_python = '```python' - new_lines = [] - - with open(mdfile) as mdfile_iterator: - file_content = mdfile_iterator.read() - # If there is an odd number of code block annotations, do not syntax - # highlight. - if file_content.count(fence) % 2 != 0: - print(f'{mdfile_iterator.name} contains wrong format of code blocks. Skipping syntax highlighting.') - return - # Retrieve code block positions to replace - codeblocks = [[m.start(), m.end()] for m in re.finditer( - fence, - file_content)] - - # This is equivalent to grabbing every odd index item. - codeblocks = codeblocks[::2] - # Used to store code blocks that come without language indicators. - blocks_without_indicators = [] - - # Check if the fence comes without a language indicator. If so, include - # this to a list to render. - for start, end in codeblocks: - if file_content[end] == '\n': - blocks_without_indicators.append([start, end]) - - # Stitch content that does not need to be parsed, and replace with - # `fence_with_python` for parsed portions. - prev_start = prev_end = 0 - for start, end in blocks_without_indicators: - new_lines.append(file_content[prev_end:start]) - new_lines.append(fence_with_python) - prev_start, prev_end = start, end - - # Include rest of the content. - new_lines.append(file_content[prev_end:]) - - # Overwrite with newly parsed content. - with open(mdfile, 'w') as mdfile_iterator: - new_content = ''.join(new_lines) - mdfile_iterator.write(new_content) - - -def clean_image_links(mdfile_path: str) -> None: - """Cleans extra whitespace that breaks image links in index.html file.""" - image_link_pattern='\[\s*!\[image\]\(.*\)\s*\]\(.*\)' - new_lines = [] - with open(mdfile_path) as mdfile: - file_content = mdfile.read() - - prev_start = prev_end = 0 - - for matched_obj in re.finditer(image_link_pattern, file_content): - start = matched_obj.start() - end = matched_obj.end() - matched_str = file_content[start:end] - # Clean up all whitespaces for the image link. - clean_str = ''.join(matched_str.split()) - - new_lines.append(file_content[prev_end:start]) - new_lines.append(clean_str) - prev_start, prev_end = start, end - - new_lines.append(file_content[prev_end:]) - - with open(mdfile_path, 'w') as mdfile: - new_content = ''.join(new_lines) - mdfile.write(new_content) - - -def prepend_markdown_header(filename: str, mdfile: Iterable[str]): - """Prepends the filename as a Markdown header. - - Args: - filename: the name of the markdown file to prepend. - mdfile: iterator to the markdown file that is both readable - and writable. - """ - file_content = f'# {filename}\n\n' + mdfile.read() - # Reset file position to the beginning to write - mdfile.seek(0) - mdfile.write(file_content) - - -# Given generated markdown files, incorporate them into the docfx_yaml output. -# The markdown file metadata will be added to top level of the TOC. -def find_markdown_pages(app, outdir): - # Use this to ignore markdown files that are unnecessary. - files_to_ignore = [ - "index.md", # use readme.md instead - - "reference.md", # Reference docs overlap with Overview. Will try and incorporate this in later. - # See https://github.com/googleapis/sphinx-docfx-yaml/issues/106. - ] - - files_to_rename = { - 'readme.md': 'index.md', - } - - markdown_dir = Path(app.builder.outdir).parent / "markdown" - if not markdown_dir.exists(): - print("There's no markdown file to move.") - return - - # For each file, if it is a markdown file move to the top level pages. - for mdfile in markdown_dir.iterdir(): - if mdfile.is_file() and mdfile.name.lower() not in files_to_ignore: - mdfile_name = "" - - # Extract the header name for TOC. - with open(mdfile) as mdfile_iterator: - name = extract_header_from_markdown(mdfile_iterator) - - if not name: - with open(mdfile, 'r+') as mdfile_iterator: - mdfile_name = mdfile_iterator.name.split("/")[-1].split(".")[0].capitalize() - - print(f"Could not find a title for {mdfile_iterator.name}. Using {mdfile_name} as the title instead.") - name = mdfile_name - - prepend_markdown_header(name, mdfile_iterator) - - mdfile_name_to_use = mdfile.name.lower() - if mdfile_name_to_use in files_to_rename: - mdfile_name_to_use = files_to_rename[mdfile_name_to_use] - - mdfile_outdir = f"{outdir}/{mdfile_name_to_use}" - - shutil.copy(mdfile, mdfile_outdir) - - highlight_md_codeblocks(mdfile_outdir) - clean_image_links(mdfile_outdir) - - # Use Overview as the name for index file. - if mdfile_name_to_use == 'index.md': - # Place the Overview page at the top of the list. - app.env.markdown_pages.insert( - 0, - {'name':'Overview', 'href': 'index.md'} - ) - continue - - # Add the file to the TOC later. - app.env.markdown_pages.append({ - 'name': name, - 'href': mdfile_name_to_use, - }) - def find_uid_to_convert( current_word: str, words: List[str], @@ -1742,7 +1463,8 @@ def search_cross_references(obj, current_object_name: str, known_uids: List[str] current_object_name, known_uids ) - param["description"] = reformat_markdown_to_html(param_description) + param["description"] = ( + markdown_utils.reformat_markdown_to_html(param_description)) if param.get("id"): param_id = convert_cross_references( @@ -1750,7 +1472,7 @@ def search_cross_references(obj, current_object_name: str, known_uids: List[str] current_object_name, known_uids ) - param["id"] = reformat_markdown_to_html(param_id) + param["id"] = markdown_utils.reformat_markdown_to_html(param_id) if param.get("var_type"): param_type = convert_cross_references( @@ -1758,7 +1480,8 @@ def search_cross_references(obj, current_object_name: str, known_uids: List[str] current_object_name, known_uids ) - param["var_type"] = reformat_markdown_to_html(param_type) + param["var_type"] = ( + markdown_utils.reformat_markdown_to_html(param_type)) if obj["syntax"].get("exceptions"): for exception in obj["syntax"]["exceptions"]: @@ -1769,7 +1492,7 @@ def search_cross_references(obj, current_object_name: str, known_uids: List[str] known_uids ) exception["description"] = ( - reformat_markdown_to_html(exception_description)) + markdown_utils.reformat_markdown_to_html(exception_description)) if exception.get("var_type"): exception_type = convert_cross_references( @@ -1778,7 +1501,7 @@ def search_cross_references(obj, current_object_name: str, known_uids: List[str] known_uids ) exception["var_type"] = ( - reformat_markdown_to_html(exception_type)) + markdown_utils.reformat_markdown_to_html(exception_type)) if obj["syntax"].get("returns"): for ret in obj["syntax"]["returns"]: @@ -1788,7 +1511,8 @@ def search_cross_references(obj, current_object_name: str, known_uids: List[str] current_object_name, known_uids ) - ret["description"] = reformat_markdown_to_html(ret_description) + ret["description"] = ( + markdown_utils.reformat_markdown_to_html(ret_description)) if ret.get("var_type"): ret_type = convert_cross_references( @@ -1796,7 +1520,7 @@ def search_cross_references(obj, current_object_name: str, known_uids: List[str] current_object_name, known_uids ) - ret["var_type"] = reformat_markdown_to_html(ret_type) + ret["var_type"] = markdown_utils.reformat_markdown_to_html(ret_type) if obj.get("attributes"): @@ -1808,7 +1532,7 @@ def search_cross_references(obj, current_object_name: str, known_uids: List[str] known_uids ) attribute["description"] = ( - reformat_markdown_to_html(attribute_description)) + markdown_utils.reformat_markdown_to_html(attribute_description)) if attribute.get("id"): attribute_id = convert_cross_references( @@ -1816,7 +1540,7 @@ def search_cross_references(obj, current_object_name: str, known_uids: List[str] current_object_name, known_uids ) - attribute["id"] = reformat_markdown_to_html(attribute_id) + attribute["id"] = markdown_utils.reformat_markdown_to_html(attribute_id) if attribute.get("var_type"): attribute_type = convert_cross_references( @@ -1824,7 +1548,8 @@ def search_cross_references(obj, current_object_name: str, known_uids: List[str] current_object_name, known_uids ) - attribute["var_type"] = reformat_markdown_to_html(attribute_type) + attribute["var_type"] = ( + markdown_utils.reformat_markdown_to_html(attribute_type)) def build_finished(app, exception): @@ -1875,7 +1600,7 @@ def convert_module_to_package_if_needed(obj): ensuredir(normalized_outdir) # Add markdown pages to the configured output directory. - find_markdown_pages(app, normalized_outdir) + markdown_utils.move_markdown_pages(app, normalized_outdir) pkg_toc_yaml = [] # Used to record filenames dumped to avoid confliction diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/markdown_utils.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/markdown_utils.py new file mode 100644 index 000000000000..0acf5c3ca8c2 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/markdown_utils.py @@ -0,0 +1,326 @@ +# Copyright 2022 Google LLC +# +# 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. + +# -*- coding: utf-8 -*- +"""Markdown related utilities for Sphinx DocFX YAML extension.""" + + +import os +from pathlib import Path +import re +import shutil +from typing import Iterable + +from docuploader import shell +import sphinx.application + + +def _reformat_codeblocks(content: str) -> str: + """Formats codeblocks from ``` to
."""
+    triple_backtick = '```'
+    current_tag = '
'
+    next_tag = '
' + # If there are no proper pairs of triple backticks, don't format docstring. + if content.count(triple_backtick) % 2 != 0: + print(f'Docstring is not formatted well, missing proper pairs of triple backticks (```): {content}') + return content + while triple_backtick in content: + content = content.replace(triple_backtick, current_tag, 1) + # Alternate between replacing with
 and 
. + current_tag, next_tag = next_tag, current_tag + + return content + + +def _reformat_code(content: str) -> str: + """Formats code from ` to .""" + reformatted_lines = [] + + code_pattern = '`[^`\n]+`' + code_start = '' + code_end = '' + prev_start = prev_end = 0 + # Convert `text` to text + for matched_obj in re.finditer(code_pattern, content): + start = matched_obj.start() + end = matched_obj.end() + code_content = content[start+1:end-1] + + reformatted_lines.append(content[prev_end:start]) + reformatted_lines.append(f'{code_start}{code_content}{code_end}') + prev_start, prev_end = start, end + + reformatted_lines.append(content[prev_end:]) + + return ''.join(reformatted_lines) + + +def reformat_markdown_to_html(content: str) -> str: + """Applies changes from markdown syntax to equivalent HTML. + + Acts as a wrapper function to format all Markdown to HTML. + + Markdown syntax cannot be used within HTML elements, and must be converted + at YAML level. + + Args: + content: the string to be reformatted. + + Returns: + Content that has been formatted with proper HTML. + """ + + content = _reformat_codeblocks(content) + content = _reformat_code(content) + + return content + + +def _parse_markdown_header(current_line: str, prev_line: str) -> str: + """Parses the H1 markdown header if found. + + Args: + current_line: line of markdown text to inspect. + prev_line: previous line to use if we found line divider for H1. + + Returns: + Header for the markdown file if valid header is found. + """ + # Markdown h1 prefix should have only 1 of '#' character followed by exactly one space. + h1_header_prefix = "# " + if h1_header_prefix in current_line and current_line.count("#") == 1: + # Check for proper h1 header formatting, ensure there's more than just + # the hashtag character, and exactly only one space after the hashtag. + if not current_line[current_line.index(h1_header_prefix)+2].isspace() and \ + len(current_line) > 2: + + return current_line[current_line.index(h1_header_prefix):].strip("#").strip() + + elif "=" in current_line: + # Check if we're inspecting an empty or undefined lines. + if not prev_line: + return "" + + # Check if the current line only has equal sign divider. + if current_line.count("=") == len(current_line.strip()): + # Update header to the previous line. + return prev_line.strip() + + return "" + + +def _extract_header_from_markdown(mdfile: Iterable[str]) -> str: + """For a given markdown file, extract its header line. + + Args: + mdfile: iterator to the markdown file. + + Returns: + A string for header or empty string if header is not found. + """ + prev_line = "" + + for line in mdfile: + + # Ignore licenses and other non-headers prior to the header. + # If we've found the header, return the header. + header = _parse_markdown_header(line, prev_line) + if header != "": + return header + + prev_line = line + + return "" + + +def _highlight_md_codeblocks(mdfile_path: str) -> None: + """Adds syntax highlighting to code blocks for a given markdown file.""" + fence = '```' + fence_with_python = '```python' + new_lines = [] + + with open(mdfile_path) as mdfile: + file_content = mdfile.read() + # If there is an odd number of code block annotations, do not syntax + # highlight. + if file_content.count(fence) % 2 != 0: + print(f'{mdfile.name} contains wrong format of code blocks. Skipping syntax highlighting.') + return + # Retrieve code block positions to replace + codeblocks = [[m.start(), m.end()] for m in re.finditer( + fence, + file_content)] + + # This is equivalent to grabbing every odd index item. + codeblocks = codeblocks[::2] + # Used to store code blocks that come without language indicators. + blocks_without_indicators = [] + + # Check if the fence comes without a language indicator. If so, include + # this to a list to render. + for start, end in codeblocks: + if file_content[end] == '\n': + blocks_without_indicators.append([start, end]) + + # Stitch content that does not need to be parsed, and replace with + # `fence_with_python` for parsed portions. + prev_start = prev_end = 0 + for start, end in blocks_without_indicators: + new_lines.append(file_content[prev_end:start]) + new_lines.append(fence_with_python) + prev_start, prev_end = start, end + + # Include rest of the content. + new_lines.append(file_content[prev_end:]) + + # Overwrite with newly parsed content. + with open(mdfile_path, 'w') as mdfile: + new_content = ''.join(new_lines) + mdfile.write(new_content) + + +def _clean_image_links(mdfile_path: str) -> None: + """Cleans extra whitespace that breaks image links in index.html file.""" + image_link_pattern='\[\s*!\[image\]\(.*\)\s*\]\(.*\)' + new_lines = [] + with open(mdfile_path) as mdfile: + file_content = mdfile.read() + + prev_start = prev_end = 0 + + for matched_obj in re.finditer(image_link_pattern, file_content): + start = matched_obj.start() + end = matched_obj.end() + matched_str = file_content[start:end] + # Clean up all whitespaces for the image link. + clean_str = ''.join(matched_str.split()) + + new_lines.append(file_content[prev_end:start]) + new_lines.append(clean_str) + prev_start, prev_end = start, end + + new_lines.append(file_content[prev_end:]) + + with open(mdfile_path, 'w') as mdfile: + new_content = ''.join(new_lines) + mdfile.write(new_content) + + +def _prepend_markdown_header(filename: str, mdfile: Iterable[str]) -> None: + """Prepends the filename as a Markdown header. + + Args: + filename: the name of the markdown file to prepend. + mdfile: iterator to the markdown file that is both readable + and writable. + """ + file_content = f'# {filename}\n\n' + mdfile.read() + # Reset file position to the beginning to write + mdfile.seek(0) + mdfile.write(file_content) + + +def move_markdown_pages(app: sphinx.application, outdir: Path) -> None: + """Moves markdown pages to be added to the generated reference documentation. + + Markdown pages may be hand written or auto generated. They're processed + through a third party library to process markdown, then does further + processing here then added to the top level of the TOC. + + Args: + app: Sphinx application. + outdir: The output directory to move markdown pages to. + """ + # Use this to ignore markdown files that are unnecessary. + files_to_ignore = [ + "index.md", # use readme.md instead + + "reference.md", # Reference docs overlap with Overview. Will try and incorporate this in later. + # See https://github.com/googleapis/sphinx-docfx-yaml/issues/106. + ] + + files_to_rename = { + 'readme.md': 'index.md', + } + + markdown_dir = Path(app.builder.outdir).parent / "markdown" + if not markdown_dir.exists(): + print("There's no markdown file to move.") + return + + # For each file, if it is a markdown file move to the top level pages. + for mdfile in markdown_dir.iterdir(): + if mdfile.is_file() and mdfile.name.lower() not in files_to_ignore: + mdfile_name = "" + + # Extract the header name for TOC. + with open(mdfile) as mdfile_iterator: + name = _extract_header_from_markdown(mdfile_iterator) + + if not name: + with open(mdfile, 'r+') as mdfile_iterator: + mdfile_name = mdfile_iterator.name.split("/")[-1].split(".")[0].capitalize() + + print(f"Could not find a title for {mdfile_iterator.name}. Using {mdfile_name} as the title instead.") + name = mdfile_name + + _prepend_markdown_header(name, mdfile_iterator) + + + mdfile_name_to_use = mdfile.name.lower() + if mdfile_name_to_use in files_to_rename: + mdfile_name_to_use = files_to_rename[mdfile_name_to_use] + + mdfile_outdir = f"{outdir}/{mdfile_name_to_use}" + + shutil.copy(mdfile, mdfile_outdir) + + _highlight_md_codeblocks(mdfile_outdir) + _clean_image_links(mdfile_outdir) + + # Use Overview as the name for index file. + if mdfile_name_to_use == 'index.md': + # Place the Overview page at the top of the list. + app.env.markdown_pages.insert( + 0, + {'name':'Overview', 'href': 'index.md'} + ) + continue + + # Add the file to the TOC later. + app.env.markdown_pages.append({ + 'name': name, + 'href': mdfile_name_to_use, + }) + + +def run_sphinx_markdown() -> None: + """Runs sphinx-build with Markdown builder in the plugin.""" + cwd = os.getcwd() + # Skip running sphinx-build for Markdown for some unit tests. + # Not required other than to output DocFX YAML. + if "docs" in cwd: + return + + return shell.run( + [ + "sphinx-build", + "-M", + "markdown", + "docs/", + "docs/_build", + ], + hide_output=False + ) + diff --git a/packages/gcp-sphinx-docfx-yaml/tests/test_helpers.py b/packages/gcp-sphinx-docfx-yaml/tests/test_helpers.py index 7cca1c6b87a0..366d669ff001 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/test_helpers.py +++ b/packages/gcp-sphinx-docfx-yaml/tests/test_helpers.py @@ -1,15 +1,4 @@ -from docfx_yaml.extension import extract_keyword -from docfx_yaml.extension import indent_code_left -from docfx_yaml.extension import find_uid_to_convert -from docfx_yaml.extension import convert_cross_references -from docfx_yaml.extension import search_cross_references -from docfx_yaml.extension import format_code -from docfx_yaml.extension import extract_product_name -from docfx_yaml.extension import highlight_md_codeblocks -from docfx_yaml.extension import prepend_markdown_header -from docfx_yaml.extension import clean_image_links -from docfx_yaml.extension import reformat_summary -from docfx_yaml.extension import reformat_markdown_to_html +from docfx_yaml import extension import unittest from parameterized import parameterized @@ -61,7 +50,7 @@ class TestGenerate(unittest.TestCase): def test_indent_code_left(self, code, code_want): parts = code.split("\n") tab_space = len(parts[0]) - len(parts[0].lstrip(" ")) - code_got = indent_code_left(code, tab_space) + code_got = extension.indent_code_left(code, tab_space) self.assertEqual(code_got, code_want) @@ -82,7 +71,7 @@ def test_indent_code_blocks_left(self): " return ('left-indented-blocks')\n" ] tab_space = len(code[0]) - len(code[0].lstrip(" ")) - code_got = "\n\n".join([indent_code_left(part, tab_space) for part in code]) + code_got = "\n\n".join([extension.indent_code_left(part, tab_space) for part in code]) self.assertEqual(code_got, code_want) @@ -91,7 +80,7 @@ def test_extract_keyword(self): keyword_want = "attribute" keyword_line = ".. attribute:: " - keyword_got = extract_keyword(keyword_line) + keyword_got = extension.extract_keyword(keyword_line) self.assertEqual(keyword_got, keyword_want) @@ -100,7 +89,7 @@ def test_extract_keyword(self): # Should raise an exception.. with self.assertRaises(ValueError): - keyword_got = extract_keyword(keyword_line) + keyword_got = extension.extract_keyword(keyword_line) cross_references_testdata = [ @@ -141,7 +130,7 @@ def test_convert_cross_references(self, content, content_want): ] current_object_name = "google.cloud.bigquery_storage_v1.types.SplitResponse" - content_got = convert_cross_references(content, current_object_name, keyword_map) + content_got = extension.convert_cross_references(content, current_object_name, keyword_map) self.assertEqual(content_got, content_want) @@ -159,23 +148,23 @@ def test_convert_cross_references_twice(self, content, content_want): ] current_name = "SplitRepsonse" - content_got = convert_cross_references(content, current_name, keyword_map) + content_got = extension.convert_cross_references(content, current_name, keyword_map) # Make sure that same entries are not processed twice. # The output should not be different. current = content_got - current_got = convert_cross_references(current, content, keyword_map) + current_got = extension.convert_cross_references(current, content, keyword_map) self.assertEqual(content_want, current_got) # If shorter version of the current name exists, it should not interfere # unless strictly necessary. keyword_map.append("google.cloud.bigquery_storage_v1.types") - long_name_got = convert_cross_references(content, current_name, keyword_map) + long_name_got = extension.convert_cross_references(content, current_name, keyword_map) self.assertEqual(long_name_got, content_want) shorter_name_want = "google.cloud.bigquery_storage_v1.types" shorter_name = "google.cloud.bigquery_storage_v1.types" - shorter_name_got = convert_cross_references(shorter_name, current_name, keyword_map) + shorter_name_got = extension.convert_cross_references(shorter_name, current_name, keyword_map) self.assertEqual(shorter_name_got, shorter_name_want) @@ -208,7 +197,7 @@ def test_search_cross_references(self): yaml_pre = load(test_file, Loader=Loader) for obj in yaml_pre['items']: - search_cross_references(obj, current_name, keyword_map) + extension.search_cross_references(obj, current_name, keyword_map) with open('tests/cross_references_post.yaml', 'r') as want_file: yaml_post = load(want_file, Loader=Loader) @@ -222,7 +211,7 @@ def test_format_code(self): code = 'batch_predict(*, gcs_source: Optional[Union[str, Sequence[str]]] = None, instances_format: str = "jsonl", gcs_destination_prefix: Optional[str] = None, predictions_format: str = "jsonl", model_parameters: Optional[Dict] = None, machine_type: Optional[str] = None, accelerator_type: Optional[str] = None, explanation_parameters: Optional[google.cloud.aiplatform_v1.types.explanation.ExplanationParameters] = None, labels: Optional[Dict[str, str]] = None, sync: bool = True,)' - code_got = format_code(code) + code_got = extension.format_code(code) self.assertEqual(code_want, code_got) @@ -230,116 +219,22 @@ def test_extract_product_name(self): # Test to ensure different name formats extract product name properly. name_want = "scheduler_v1.types.Digest" name = "google.cloud.scheduler_v1.types.Digest" - product_name = extract_product_name(name) + product_name = extension.extract_product_name(name) self.assertEqual(name_want, product_name) non_cloud_name = "google.scheduler_v1.types.Digest" - non_cloud_product_name = extract_product_name(non_cloud_name) + non_cloud_product_name = extension.extract_product_name(non_cloud_name) self.assertEqual(name_want, non_cloud_product_name) short_name_want = "Digest" short_name = "scheduler_v1.types.Digest" - short_product_name = extract_product_name(short_name) + short_product_name = extension.extract_product_name(short_name) self.assertEqual(short_name_want, short_product_name) - # Filenames to test markdown syntax highlight with. - test_markdown_filenames = [ - [ - "tests/markdown_syntax_highlight.md", - "tests/markdown_syntax_highlight_want.md" - ], - [ - "tests/markdown_no_highlight.md", - "tests/markdown_no_highlight_want.md" - ], - [ - "tests/markdown_mixed_highlight.md", - "tests/markdown_mixed_highlight_want.md" - ], - ] - @parameterized.expand(test_markdown_filenames) - def test_highlight_md_codeblocks(self, base_filename, want_filename): - # Test to ensure codeblocks in markdown files are correctly highlighted. - - # Copy the base file we'll need to test. - with tempfile.NamedTemporaryFile(mode='r+', delete=False) as test_file: - with open(base_filename) as base_file: - test_file.write(base_file.read()) - test_file.flush() - - highlight_md_codeblocks(test_file.name) - test_file.seek(0) - - with open(want_filename) as mdfile_want: - self.assertEqual(test_file.read(), mdfile_want.read()) - - - # Filenames to test prepending Markdown title.. - test_markdown_filenames = [ - [ - "tests/markdown_example_bad_header.md", - "tests/markdown_example_bad_header_want.md" - ], - [ - "tests/markdown_example_h2.md", - "tests/markdown_example_h2_want.md" - ], - [ - "tests/markdown_example_alternate_bad.md", - "tests/markdown_example_alternate_bad_want.md" - ], - ] - @parameterized.expand(test_markdown_filenames) - def test_prepend_markdown_header(self, base_filename, want_filename): - # Ensure markdown titles are correctly prepended. - - # Copy the base file we'll need to test. - with tempfile.NamedTemporaryFile(mode='r+', delete=False) as test_file: - with open(base_filename) as base_file: - # Use same file name extraction as original code. - file_name = base_file.name.split("/")[-1].split(".")[0].capitalize() - test_file.write(base_file.read()) - test_file.flush() - test_file.seek(0) - - prepend_markdown_header(file_name, test_file) - test_file.seek(0) - - with open(want_filename) as mdfile_want: - self.assertEqual(test_file.read(), mdfile_want.read()) - - - # Filenames to test cleaning up markdown image links. - test_markdown_filenames = [ - [ - "tests/markdown_example_bad_image_links.md", - "tests/markdown_example_bad_image_links_want.md" - ], - ] - @parameterized.expand(test_markdown_filenames) - def test_clean_image_links(self, base_filename, want_filename): - # Ensure image links are well formed in markdown files. - - # Copy the base file we'll need to test. - with tempfile.NamedTemporaryFile(mode='r+', delete=False) as test_file: - with open(base_filename) as base_file: - # Use same file name extraction as original code. - file_name = base_file.name.split("/")[-1].split(".")[0].capitalize() - test_file.write(base_file.read()) - test_file.flush() - test_file.seek(0) - - clean_image_links(test_file.name) - test_file.seek(0) - - with open(want_filename) as mdfile_want: - self.assertEqual(test_file.read(), mdfile_want.read()) - - test_reference_params = [ [ # If no reference keyword is found, check for None @@ -387,7 +282,7 @@ def test_find_uid_to_convert(self, current_word, uids, visited_words, cross_refe index = words.index(current_word) - cross_reference_got = find_uid_to_convert( + cross_reference_got = extension.find_uid_to_convert( current_word, words, index, uids, current_object_name, visited_words ) self.assertEqual(cross_reference_got, cross_reference_want) @@ -431,37 +326,9 @@ def test_find_uid_to_convert(self, current_word, uids, visited_words, cross_refe ] @parameterized.expand(test_summary) def test_reformat_summary(self, summary, summary_want): - summary_got = reformat_summary(summary) + summary_got = extension.reformat_summary(summary) self.assertEqual(summary_want, summary_got) - test_markdown_content = [ - [ - """The resource name or `None` - -if no Cloud KMS key was used, or the blob's resource has not been loaded from the server. - -For example: -``` - kms_key_name: ID -``` - """, - """The resource name or None - -if no Cloud KMS key was used, or the blob's resource has not been loaded from the server. - -For example: -
-    kms_key_name: ID
-
- """, - ], - ] - @parameterized.expand(test_markdown_content) - def test_reformat_markdown_to_html(self, content, content_want): - content_got = reformat_markdown_to_html(content) - self.assertEqual(content_want, content_got) - - if __name__ == '__main__': unittest.main() diff --git a/packages/gcp-sphinx-docfx-yaml/tests/test_markdown.py b/packages/gcp-sphinx-docfx-yaml/tests/test_markdown.py new file mode 100644 index 000000000000..5c78b8db392a --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/test_markdown.py @@ -0,0 +1,252 @@ +from docfx_yaml import markdown_utils + + +import unittest +from parameterized import parameterized + +from yaml import load, Loader + +import tempfile + +class TestGenerate(unittest.TestCase): + # Filenames to test markdown syntax highlight with. + test_markdown_filenames = [ + [ + "tests/markdown_syntax_highlight.md", + "tests/markdown_syntax_highlight_want.md" + ], + [ + "tests/markdown_no_highlight.md", + "tests/markdown_no_highlight_want.md" + ], + [ + "tests/markdown_mixed_highlight.md", + "tests/markdown_mixed_highlight_want.md" + ], + ] + @parameterized.expand(test_markdown_filenames) + def test_highlight_md_codeblocks(self, base_filename, want_filename): + # Test to ensure codeblocks in markdown files are correctly highlighted. + + # Copy the base file we'll need to test. + with tempfile.NamedTemporaryFile(mode='r+', delete=False) as test_file: + with open(base_filename) as base_file: + test_file.write(base_file.read()) + test_file.flush() + + markdown_utils._highlight_md_codeblocks(test_file.name) + test_file.seek(0) + + with open(want_filename) as mdfile_want: + self.assertEqual(test_file.read(), mdfile_want.read()) + + + # Filenames to test prepending Markdown title.. + test_markdown_filenames = [ + [ + "tests/markdown_example_bad_header.md", + "tests/markdown_example_bad_header_want.md" + ], + [ + "tests/markdown_example_h2.md", + "tests/markdown_example_h2_want.md" + ], + [ + "tests/markdown_example_alternate_bad.md", + "tests/markdown_example_alternate_bad_want.md" + ], + ] + @parameterized.expand(test_markdown_filenames) + def test_prepend_markdown_header(self, base_filename, want_filename): + # Ensure markdown titles are correctly prepended. + + # Copy the base file we'll need to test. + with tempfile.NamedTemporaryFile(mode='r+', delete=False) as test_file: + with open(base_filename) as base_file: + # Use same file name extraction as original code. + file_name = base_file.name.split("/")[-1].split(".")[0].capitalize() + test_file.write(base_file.read()) + test_file.flush() + test_file.seek(0) + + markdown_utils._prepend_markdown_header(file_name, test_file) + test_file.seek(0) + + with open(want_filename) as mdfile_want: + self.assertEqual(test_file.read(), mdfile_want.read()) + + + # Filenames to test cleaning up markdown image links. + test_markdown_filenames = [ + [ + "tests/markdown_example_bad_image_links.md", + "tests/markdown_example_bad_image_links_want.md" + ], + ] + @parameterized.expand(test_markdown_filenames) + def test_clean_image_links(self, base_filename, want_filename): + # Ensure image links are well formed in markdown files. + + # Copy the base file we'll need to test. + with tempfile.NamedTemporaryFile(mode='r+', delete=False) as test_file: + with open(base_filename) as base_file: + # Use same file name extraction as original code. + file_name = base_file.name.split("/")[-1].split(".")[0].capitalize() + test_file.write(base_file.read()) + test_file.flush() + test_file.seek(0) + + markdown_utils._clean_image_links(test_file.name) + test_file.seek(0) + + with open(want_filename) as mdfile_want: + self.assertEqual(test_file.read(), mdfile_want.read()) + + + test_markdown_content = [ + [ + """The resource name or `None` + +if no Cloud KMS key was used, or the blob's resource has not been loaded from the server. + +For example: +``` + kms_key_name: ID +``` + """, + """The resource name or None + +if no Cloud KMS key was used, or the blob's resource has not been loaded from the server. + +For example: +
+    kms_key_name: ID
+
+ """, + ], + ] + @parameterized.expand(test_markdown_content) + def test_reformat_markdown_to_html(self, content, content_want): + content_got = markdown_utils.reformat_markdown_to_html(content) + self.assertEqual(content_want, content_got) + + + test_markdown_content = [ + [ + # Test for simple header_line. + "# Test header", + "Test header", + "", + ], + [ + # Test for invalid input. + "#Test header", + "", + "", + ], + [ + # Test for invalid input. + "# Test header", + "", + "", + ], + [ + # Test for no header. + "-->", + "", + "limitations under the license.\n", + ], + [ + # Test for simple alternate header. + "============\n", + "Test header", + "Test header", + ], + [ + # Test for no header. + "============\n", + "", + "", + ], + [ + # Test for shorter divider. + "======\n", + "Test header", + "Test header", + ], + ] + @parameterized.expand(test_markdown_content) + def test_parse_markdown_header(self, header_line, header_line_want, prev_line): + header_line_got = markdown_utils._parse_markdown_header(header_line, prev_line) + + self.assertEqual(header_line_got, header_line_want) + + + test_markdown_filenames = [ + [ + # Check the header for a normal markdown file. + "tests/markdown_example.md" + ], + [ + # The header should be the same even with the license header. + "tests/markdown_example_header.md" + ], + ] + @parameterized.expand(test_markdown_filenames) + def test_extract_header_from_markdown(self, markdown_filename): + # Check the header for markdown files. + header_line_want = "Test header for a simple markdown file." + + with open(markdown_filename, 'r') as mdfile: + header_line_got = markdown_utils._extract_header_from_markdown(mdfile) + + self.assertEqual(header_line_got, header_line_want) + + + test_markdown_filenames = [ + [ + # Check the header for an alternate header style. + "tests/markdown_example_alternate.md" + ], + [ + # The header should be the same even with the license header. + "tests/markdown_example_alternate_header.md" + ], + [ + # Check the header for an alternate header style. + "tests/markdown_example_alternate_less.md" + ], + ] + @parameterized.expand(test_markdown_filenames) + def test_extract_header_from_markdown_alternate_header(self, markdown_filename): + # Check the header for different accepted styles. + header_line_want = "This is a simple alternate header" + + with open(markdown_filename, 'r') as mdfile: + header_line_got = markdown_utils._extract_header_from_markdown(mdfile) + + self.assertEqual(header_line_got, header_line_want) + + + test_markdown_filenames = [ + [ + "tests/markdown_example_bad_header.md" + ], + [ + "tests/markdown_example_h2.md" + ], + [ + "tests/markdown_example_alternate_bad.md" + ], + ] + @parameterized.expand(test_markdown_filenames) + def test_extract_header_from_markdown_bad_headers(self, markdown_filename): + # Check that empty string is returned if no valid header is found. + with open(markdown_filename, 'r') as mdfile: + header_line_got = markdown_utils._extract_header_from_markdown(mdfile) + + self.assertFalse(header_line_got) + + +if __name__ == '__main__': + unittest.main() diff --git a/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py b/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py index f104c7411822..9eb344139f54 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py +++ b/packages/gcp-sphinx-docfx-yaml/tests/test_unit.py @@ -1,16 +1,4 @@ -from docfx_yaml.extension import find_unique_name -from docfx_yaml.extension import disambiguate_toc_name -from docfx_yaml.extension import _resolve_reference_in_module_summary -from docfx_yaml.extension import REF_PATTERN -from docfx_yaml.extension import REF_PATTERN_LAST -from docfx_yaml.extension import REF_PATTERN_BRACKETS -from docfx_yaml.extension import _extract_docstring_info -from docfx_yaml.extension import find_package_group -from docfx_yaml.extension import pretty_package_name -from docfx_yaml.extension import group_by_package -from docfx_yaml.extension import extract_header_from_markdown -from docfx_yaml.extension import _parse_docstring_summary -from docfx_yaml.extension import parse_markdown_header +from docfx_yaml import extension import unittest from parameterized import parameterized @@ -35,8 +23,8 @@ def test_find_unique_name(self): else: entries[word] += 1 - got1 = find_unique_name(entry1.split("."), entries) - got2 = find_unique_name(entry2.split("."), entries) + got1 = extension.find_unique_name(entry1.split("."), entries) + got2 = extension.find_unique_name(entry2.split("."), entries) self.assertEqual(want1, ".".join(got1)) self.assertEqual(want2, ".".join(got2)) @@ -54,7 +42,7 @@ def test_disambiguate_toc_name(self): with open('tests/yaml_pre.yaml', 'r') as test_file: yaml_got = load(test_file, Loader=Loader) - disambiguated_names_got = disambiguate_toc_name(yaml_got) + disambiguated_names_got = extension.disambiguate_toc_name(yaml_got) self.assertEqual(yaml_want, yaml_got) self.assertEqual(disambiguated_names_want, disambiguated_names_got) @@ -71,7 +59,7 @@ def test_disambiguate_toc_name_duplicate(self): with open('tests/yaml_pre_duplicate.yaml', 'r') as test_file: yaml_got = load(test_file, Loader=Loader) - disambiguated_names_got = disambiguate_toc_name(yaml_got) + disambiguated_names_got = extension.disambiguate_toc_name(yaml_got) self.assertEqual(yaml_want, yaml_got) @@ -107,10 +95,10 @@ def test_reference_in_summary(self): lines_got = lines_got.split("\n") xrefs_got = [] # Resolve over different regular expressions for different types of reference patterns. - lines_got, xrefs = _resolve_reference_in_module_summary(REF_PATTERN, lines_got) + lines_got, xrefs = extension._resolve_reference_in_module_summary(extension.REF_PATTERN, lines_got) for xref in xrefs: xrefs_got.append(xref) - lines_got, xrefs = _resolve_reference_in_module_summary(REF_PATTERN_LAST, lines_got) + lines_got, xrefs = extension._resolve_reference_in_module_summary(extension.REF_PATTERN_LAST, lines_got) for xref in xrefs: xrefs_got.append(xref) @@ -174,10 +162,10 @@ def test_reference_in_summary_more_xrefs(self): lines_got = lines_got.split("\n") xrefs_got = [] # Resolve over different regular expressions for different types of reference patterns. - lines_got, xrefs = _resolve_reference_in_module_summary(REF_PATTERN, lines_got) + lines_got, xrefs = extension._resolve_reference_in_module_summary(extension.REF_PATTERN, lines_got) for xref in xrefs: xrefs_got.append(xref) - lines_got, xrefs = _resolve_reference_in_module_summary(REF_PATTERN_LAST, lines_got) + lines_got, xrefs = extension._resolve_reference_in_module_summary(extension.REF_PATTERN_LAST, lines_got) for xref in xrefs: xrefs_got.append(xref) @@ -257,7 +245,7 @@ def test_reference_square_brackets(self): """ summary = summary.split("\n") - summary_got, xrefs_got = _resolve_reference_in_module_summary(REF_PATTERN_BRACKETS, summary) + summary_got, xrefs_got = extension._resolve_reference_in_module_summary(extension.REF_PATTERN_BRACKETS, summary) self.assertEqual(summary_got, summary_want) self.assertCountEqual(xrefs_got, xrefs_want) @@ -266,7 +254,7 @@ def test_reference_square_brackets(self): # Check that other patterns throws an exception. def test_reference_check_error(self): with self.assertRaises(ValueError): - _resolve_reference_in_module_summary('.*', 'not a valid ref line'.split('\n')) + extension._resolve_reference_in_module_summary('.*', 'not a valid ref line'.split('\n')) def test_extract_docstring_info_normal_input(self): @@ -292,7 +280,7 @@ def test_extract_docstring_info_normal_input(self): AttributeError: if `condition x`. """ - top_summary1_got = _extract_docstring_info(summary_info1_got, summary1, "") + top_summary1_got = extension._extract_docstring_info(summary_info1_got, summary1, "") self.assertEqual(top_summary1_got, self.top_summary1_want) self.assertEqual(summary_info1_got, self.summary_info1_want) @@ -320,7 +308,7 @@ def test_extract_docstring_info_mixed_format(self): 'exceptions': [] } - top_summary2_got = _extract_docstring_info(summary_info2_got, summary2, "") + top_summary2_got = extension._extract_docstring_info(summary_info2_got, summary2, "") # Output should be same as test 1 with normal input. self.assertEqual(top_summary2_got, self.top_summary1_want) @@ -353,7 +341,7 @@ def test_extract_docstring_info_check_parser(self): # Nothing should change top_summary3_want = summary3 - top_summary3_got = _extract_docstring_info(summary_info3_got, summary3, "") + top_summary3_got = extension._extract_docstring_info(summary_info3_got, summary3, "") self.assertEqual(top_summary3_got, top_summary3_want) self.assertEqual(summary_info3_got, summary_info3_want) @@ -367,7 +355,7 @@ def test_extract_docstring_info_check_error(self): :returns:param: """ with self.assertRaises(ValueError): - _extract_docstring_info({}, summary4, "error string") + extension._extract_docstring_info({}, summary4, "error string") summary5 = """ Description of malformed docstring. @@ -376,7 +364,7 @@ def test_extract_docstring_info_check_error(self): Error that should fail: if condition `x`. """ with self.assertRaises(KeyError): - _extract_docstring_info({}, summary5, "malformed docstring") + extension._extract_docstring_info({}, summary5, "malformed docstring") def test_extract_docstring_info_with_xref(self): @@ -426,7 +414,7 @@ def test_extract_docstring_info_with_xref(self): 'exceptions': [] } - top_summary_got = _extract_docstring_info(summary_info_got, summary, "") + top_summary_got = extension._extract_docstring_info(summary_info_got, summary, "") # Same as the top summary from previous example, compare with that self.assertEqual(top_summary_got, self.top_summary1_want) self.assertDictEqual(summary_info_got, summary_info_want) @@ -452,7 +440,7 @@ def test_extract_docstring_info_no_summary(self): 'exceptions': [] } - top_summary_got = _extract_docstring_info(summary_info_got, summary, "") + top_summary_got = extension._extract_docstring_info(summary_info_got, summary, "") self.assertEqual(top_summary_got, "") self.assertDictEqual(summary_info_got, self.summary_info1_want) @@ -461,7 +449,7 @@ def test_find_package_group(self): package_group_want = "google.cloud.spanner_v1beta2" uid = "google.cloud.spanner_v1beta2.services.admin_database_v1.types" - package_group_got = find_package_group(uid) + package_group_got = extension.find_package_group(uid) self.assertEqual(package_group_got, package_group_want) @@ -469,7 +457,7 @@ def test_pretty_package_name(self): package_name_want = "Spanner V1beta2" package_group = "google.cloud.spanner_v1beta2" - package_name_got = pretty_package_name(package_group) + package_name_got = extension.pretty_package_name(package_group) self.assertEqual(package_name_got, package_name_want) @@ -588,152 +576,11 @@ def test_group_by_package(self): } ] - toc_yaml_got = group_by_package(toc_yaml) + toc_yaml_got = extension.group_by_package(toc_yaml) self.assertCountEqual(toc_yaml_got, toc_yaml_want) - def test_parse_markdown_header(self): - # Test for simple header_line. - header_line_want = "Test header" - - header_line = "# Test header" - prev_line = "" - - header_line_got = parse_markdown_header(header_line, prev_line) - - self.assertEqual(header_line_got, header_line_want) - - # Test for invalid input. - header_line_want = "" - - header_line = "#Test header" - prev_line = "" - - header_line_got = parse_markdown_header(header_line, prev_line) - - self.assertEqual(header_line_got, header_line_want) - - # Test for invalid input. - header_line_want = "" - - header_line = "# Test header" - prev_line = "" - - header_line_got = parse_markdown_header(header_line, prev_line) - - self.assertEqual(header_line_got, header_line_want) - - # Test for no header. - header_line_want = "" - - header_line = "-->" - prev_line = "limitations under the License.\n" - - header_line_got = parse_markdown_header(header_line, prev_line) - - self.assertEqual(header_line_got, header_line_want) - - - def test_parse_markdown_header_alternate(self): - # Test for simple alternate header. - header_line_want = "Test header" - - header_line = "============\n" - prev_line = "Test header" - - header_line_got = parse_markdown_header(header_line, prev_line) - - self.assertEqual(header_line_got, header_line_want) - - # Test for no header. - header_line_want = "" - - header_line = "============\n" - prev_line = "" - - header_line_got = parse_markdown_header(header_line, prev_line) - - self.assertEqual(header_line_got, header_line_want) - - - # Test for shorter divider. - header_line_want = "Test header" - - header_line = "======\n" - prev_line = "Test header" - - header_line_got = parse_markdown_header(header_line, prev_line) - - self.assertEqual(header_line_got, header_line_want) - - - test_markdown_filenames = [ - [ - # Check the header for a normal markdown file. - "tests/markdown_example.md" - ], - [ - # The header should be the same even with the license header. - "tests/markdown_example_header.md" - ], - ] - @parameterized.expand(test_markdown_filenames) - def test_extract_header_from_markdown(self, markdown_filename): - # Check the header for markdown files. - header_line_want = "Test header for a simple markdown file." - - with open(markdown_filename, 'r') as mdfile: - header_line_got = extract_header_from_markdown(mdfile) - - self.assertEqual(header_line_got, header_line_want) - - - test_markdown_filenames = [ - [ - # Check the header for an alternate header style. - "tests/markdown_example_alternate.md" - ], - [ - # The header should be the same even with the license header. - "tests/markdown_example_alternate_header.md" - ], - [ - # Check the header for an alternate header style. - "tests/markdown_example_alternate_less.md" - ], - ] - @parameterized.expand(test_markdown_filenames) - def test_extract_header_from_markdown_alternate_header(self, markdown_filename): - # Check the header for different accepted styles. - header_line_want = "This is a simple alternate header" - - with open(markdown_filename, 'r') as mdfile: - header_line_got = extract_header_from_markdown(mdfile) - - self.assertEqual(header_line_got, header_line_want) - - - test_markdown_filenames = [ - [ - "tests/markdown_example_bad_header.md" - ], - [ - "tests/markdown_example_h2.md" - ], - [ - "tests/markdown_example_alternate_bad.md" - ], - ] - @parameterized.expand(test_markdown_filenames) - def test_extract_header_from_markdown_bad_headers(self, markdown_filename): - # Check that empty string is returned if no valid header is found. - with open(markdown_filename, 'r') as mdfile: - header_line_got = extract_header_from_markdown(mdfile) - - self.assertFalse(header_line_got) - - def test_parse_docstring_summary(self): # Check that the summary gets parsed correctly. attributes_want = [] @@ -801,7 +648,7 @@ def get_client_cert(): \n \"client_cert_source\" : get_client_cert \n }) """ - summary_got, attributes_got = _parse_docstring_summary(summary) + summary_got, attributes_got = extension._parse_docstring_summary(summary) self.assertEqual(summary_got, summary_want) self.assertEqual(attributes_got, attributes_want) @@ -815,7 +662,7 @@ def get_client_cert(): """ summary_want = summary + "\n" - summary_got, attributes_got = _parse_docstring_summary(summary) + summary_got, attributes_got = extension._parse_docstring_summary(summary) self.assertEqual(summary_got, summary_want) self.assertEqual(attributes_got, attributes_want) @@ -831,7 +678,7 @@ def get_client_cert(): \n print(i) """ with self.assertRaises(ValueError): - _parse_docstring_summary(summary) + extension._parse_docstring_summary(summary) # Check that notices are processed properly. summary_want = \ @@ -862,7 +709,7 @@ def get_client_cert(): \n hyphenated term notice. """ - summary_got, attributes_got = _parse_docstring_summary(summary) + summary_got, attributes_got = extension._parse_docstring_summary(summary) self.assertEqual(summary_got, summary_want) self.assertEqual(attributes_got, attributes_want) @@ -874,7 +721,7 @@ def get_client_cert(): this is not a properly formatted warning. """ with self.assertRaises(ValueError): - _parse_docstring_summary(summary) + extension._parse_docstring_summary(summary) def test_parse_docstring_summary_attributes(self): # Test parsing docstring with attributes. @@ -896,7 +743,7 @@ def test_parse_docstring_summary_attributes(self): \n:type: str """ - summary_got, attributes_got = _parse_docstring_summary(summary) + summary_got, attributes_got = extension._parse_docstring_summary(summary) self.assertCountEqual(attributes_got, attributes_want) # Check multiple attributes are parsed. @@ -930,7 +777,7 @@ def test_parse_docstring_summary_attributes(self): \n:type: google.cloud.bigquery_logging_v1.types.TableInsertRequest """ - summary_got, attributes_got = _parse_docstring_summary(summary) + summary_got, attributes_got = extension._parse_docstring_summary(summary) self.assertCountEqual(attributes_got, attributes_want) for attribute_got, attribute_want in zip(attributes_got, attributes_want): @@ -961,7 +808,7 @@ def test_parse_docstring_summary_attributes(self): \n:type: str """ - summary_got, attributes_got = _parse_docstring_summary(summary) + summary_got, attributes_got = extension._parse_docstring_summary(summary) # Check that we are returned only one item. self.assertCountEqual(attributes_got, attributes_want) diff --git a/packages/gcp-sphinx-docfx-yaml/tox.ini b/packages/gcp-sphinx-docfx-yaml/tox.ini index c11d68cef3ce..04bfa7aaefbe 100644 --- a/packages/gcp-sphinx-docfx-yaml/tox.ini +++ b/packages/gcp-sphinx-docfx-yaml/tox.ini @@ -22,7 +22,7 @@ commands = deps = {[testenv]deps} commands = - python3 -m unittest tests/test_unit.py tests/test_helpers.py + python3 -m unittest tests/test_unit.py tests/test_helpers.py tests/test_markdown.py [testenv:librarytest] deps = From 1942dfb51fbc8f1e23bc4a92f780c89a00e35b7a Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Fri, 14 Oct 2022 11:46:54 -0500 Subject: [PATCH 164/279] chore(main): release 1.6.0 (#256) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/gcp-sphinx-docfx-yaml/CHANGELOG.md | 12 ++++++++++++ packages/gcp-sphinx-docfx-yaml/setup.py | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md index 9dd57c7a43d1..0f7a7ca5920e 100644 --- a/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md +++ b/packages/gcp-sphinx-docfx-yaml/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog +## [1.6.0](https://github.com/googleapis/sphinx-docfx-yaml/compare/v1.5.0...v1.6.0) (2022-10-13) + + +### Features + +* Use GitHub's default README as index page ([#255](https://github.com/googleapis/sphinx-docfx-yaml/issues/255)) ([17f6ca0](https://github.com/googleapis/sphinx-docfx-yaml/commit/17f6ca0ef8fe6aeed096a5356cac8944f8884b82)) + + +### Bug Fixes + +* Render emphasis properly and markdown in tables ([#258](https://github.com/googleapis/sphinx-docfx-yaml/issues/258)) ([4bbd921](https://github.com/googleapis/sphinx-docfx-yaml/commit/4bbd921f116cccd86d30597a254087f25f074728)) + ## [1.5.0](https://github.com/googleapis/sphinx-docfx-yaml/compare/v1.4.8...v1.5.0) (2022-07-11) diff --git a/packages/gcp-sphinx-docfx-yaml/setup.py b/packages/gcp-sphinx-docfx-yaml/setup.py index 0227bb434800..70c7123f245b 100644 --- a/packages/gcp-sphinx-docfx-yaml/setup.py +++ b/packages/gcp-sphinx-docfx-yaml/setup.py @@ -17,7 +17,7 @@ name = 'gcp-sphinx-docfx-yaml' description = 'Sphinx Python Domain to DocFX YAML Generator' -version = '1.5.0' +version = '1.6.0' dependencies = [ 'black', 'gcp-docuploader', From fc5d57f2a22acbfebdac3377418ec2b061e2e523 Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Mon, 31 Oct 2022 15:52:06 -0400 Subject: [PATCH 165/279] chore(deps): update dependencies (#261) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore(deps): update dependencies * chore(deps): add comments for extra installs * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * chore(deps): update Owlbot settings Co-authored-by: Owl Bot --- .../.kokoro/requirements.in | 21 +- .../.kokoro/requirements.txt | 461 ++++++++++++++++-- packages/gcp-sphinx-docfx-yaml/owlbot.py | 6 +- 3 files changed, 438 insertions(+), 50 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/requirements.in b/packages/gcp-sphinx-docfx-yaml/.kokoro/requirements.in index 3268861d3722..597a753f9a23 100644 --- a/packages/gcp-sphinx-docfx-yaml/.kokoro/requirements.in +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/requirements.in @@ -1,15 +1,12 @@ +# Library specific extra installations. +# Extra installations are required to ensure all documentation can be +# generated and not missed out with the generate-docs script. +django==2.2 +google-cloud-aiplatform[prediction] +grpcio-status==1.48.2 # must be pinned due to protobuf compatibility. +ipython + +# General installations. gcp-docuploader gcp-releasetool importlib-metadata -typing-extensions -twine -wheel -setuptools -nox -tox -sphinx==4.5.0 -recommonmark -django==2.2 -ipython -black==22.8.0 -parameterized==0.8.1 \ No newline at end of file diff --git a/packages/gcp-sphinx-docfx-yaml/.kokoro/requirements.txt b/packages/gcp-sphinx-docfx-yaml/.kokoro/requirements.txt index fa04dc96640c..cd4d06e2c8e9 100644 --- a/packages/gcp-sphinx-docfx-yaml/.kokoro/requirements.txt +++ b/packages/gcp-sphinx-docfx-yaml/.kokoro/requirements.txt @@ -8,6 +8,12 @@ alabaster==0.7.12 \ --hash=sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359 \ --hash=sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02 # via sphinx +anyio==3.6.2 \ + --hash=sha256:25ea0d673ae30af41a0c442f81cf3b38c7e79fdc7b60335a4c14e05eb0947421 \ + --hash=sha256:fbbe32bd270d2a2ef3ed1c5d45041250284e31fc0a4df4a5a6071842051a51e3 + # via + # starlette + # watchfiles argcomplete==2.0.0 \ --hash=sha256:6372ad78c89d662035101418ae253668445b391755cfe94ea52f1b9d22425b20 \ --hash=sha256:cffa11ea77999bb0dd27bb25ff6dc142a6796142f68d45b1a26b11f58724561e @@ -142,6 +148,7 @@ click==8.0.4 \ # black # gcp-docuploader # gcp-releasetool + # uvicorn colorlog==6.7.0 \ --hash=sha256:0d33ca236784a1ba3ff9c532d4964126d8a2c44f1f0cb1d2b0728196f512f662 \ --hash=sha256:bd94bd21c1e13fac7bd3153f4bc3a7dc0eb0974b8bc2fdf1a989e474f6e582e5 @@ -192,6 +199,10 @@ django==2.2 \ --hash=sha256:7c3543e4fb070d14e10926189a7fcf42ba919263b7473dceaefce34d54e8a119 \ --hash=sha256:a2814bffd1f007805b19194eb0b9a331933b82bd5da1c3ba3d7b7ba16e06dc4b # via -r requirements.in +docker==6.0.0 \ + --hash=sha256:19e330470af40167d293b0352578c1fa22d74b34d3edf5d4ff90ebc203bbb2f1 \ + --hash=sha256:6e06ee8eca46cd88733df09b6b80c24a1a556bc5cb1e1ae54b2c239886d245cf + # via google-cloud-aiplatform docutils==0.17.1 \ --hash=sha256:686577d2e4c32380bb50cbb22f575ed742d58168cee37e99117a854bcd88f125 \ --hash=sha256:cf316c8370a737a022b72b56874f6602acf974a37a9fba42ec2876387549fc61 @@ -203,6 +214,10 @@ executing==1.0.0 \ --hash=sha256:550d581b497228b572235e633599133eeee67073c65914ca346100ad56775349 \ --hash=sha256:98daefa9d1916a4f0d944880d5aeaf079e05585689bebd9ff9b32e31dd5e1017 # via stack-data +fastapi==0.75.2 \ + --hash=sha256:a70d31f4249b6b42dbe267667d22f83af645b2d857876c97f83ca9573215784f \ + --hash=sha256:b5dac161ee19d33346040d3f44d8b7a9ac09b37df9efff95891f5e7641fa482f + # via google-cloud-aiplatform filelock==3.8.0 \ --hash=sha256:55447caa666f2198c5b6b13a26d2084d26fa5b115c00d065664b2124680c4edc \ --hash=sha256:617eb4e5eedc82fc5f47b6d61e4d11cb837c56cb4544e39081099fa17ad109d4 @@ -217,11 +232,14 @@ gcp-releasetool==1.8.7 \ --hash=sha256:3d2a67c9db39322194afb3b427e9cb0476ce8f2a04033695f0aeb63979fc2b37 \ --hash=sha256:5e4d28f66e90780d77f3ecf1e9155852b0c3b13cbccb08ab07e66b2357c8da8d # via -r requirements.in -google-api-core==2.8.2 \ +google-api-core[grpc]==2.8.2 \ --hash=sha256:06f7244c640322b508b125903bb5701bebabce8832f85aba9335ec00b3d02edc \ --hash=sha256:93c6a91ccac79079ac6bbf8b74ee75db970cc899278b97d53bc012f35908cf50 # via + # google-cloud-aiplatform + # google-cloud-bigquery # google-cloud-core + # google-cloud-resource-manager # google-cloud-storage google-auth==2.11.0 \ --hash=sha256:be62acaae38d0049c21ca90f27a23847245c9f161ff54ede13af2cb6afecbac9 \ @@ -231,14 +249,30 @@ google-auth==2.11.0 \ # google-api-core # google-cloud-core # google-cloud-storage +google-cloud-aiplatform[prediction]==1.18.2 \ + --hash=sha256:ab4c034ebaa3a6537e4998745122736680735abd7e959ea17fd599444d7df1ad \ + --hash=sha256:b92de6dc3463b3ea070ef2e7220801e6a3280f77d9a0af7f7da0658bfcb9f12d + # via -r requirements.in +google-cloud-bigquery==2.34.4 \ + --hash=sha256:14a4f996411556757b5d32f11a0ebf34257d6fc5c60d53fb66e674a63a7bf9ca \ + --hash=sha256:7c6dc11e6bd65a5981a8bc18a472e6132e9aaa1fa5363f1680a9425dd3868660 + # via google-cloud-aiplatform google-cloud-core==2.3.2 \ --hash=sha256:8417acf6466be2fa85123441696c4badda48db314c607cf1e5d543fa8bdc22fe \ --hash=sha256:b9529ee7047fd8d4bf4a2182de619154240df17fbe60ead399078c1ae152af9a - # via google-cloud-storage + # via + # google-cloud-bigquery + # google-cloud-storage +google-cloud-resource-manager==1.6.3 \ + --hash=sha256:6cf8a9a74e65a03857896967c79307b75805c752ade3bc41224e6167774bc9c9 \ + --hash=sha256:e330883c53c5e3e38a651da85ae0bce201a736b5cd5f9df10941160c6a66ce6e + # via google-cloud-aiplatform google-cloud-storage==2.5.0 \ --hash=sha256:19a26c66c317ce542cea0830b7e787e8dac2588b6bfa4d3fd3b871ba16305ab0 \ --hash=sha256:382f34b91de2212e3c2e7b40ec079d27ee2e3dbbae99b75b1bcd8c63063ce235 - # via gcp-docuploader + # via + # gcp-docuploader + # google-cloud-aiplatform google-crc32c==1.3.0 \ --hash=sha256:04e7c220798a72fd0f08242bc8d7a05986b2a08a0573396187fd32c1dcdd58b3 \ --hash=sha256:05340b60bf05b574159e9bd940152a47d38af3fb43803ffe71f11d704b7696a6 \ @@ -287,15 +321,130 @@ google-crc32c==1.3.0 \ google-resumable-media==2.3.3 \ --hash=sha256:27c52620bd364d1c8116eaac4ea2afcbfb81ae9139fb3199652fcac1724bfb6c \ --hash=sha256:5b52774ea7a829a8cdaa8bd2d4c3d4bc660c91b30857ab2668d0eb830f4ea8c5 - # via google-cloud-storage -googleapis-common-protos==1.56.4 \ + # via + # google-cloud-bigquery + # google-cloud-storage +googleapis-common-protos[grpc]==1.56.4 \ --hash=sha256:8eb2cbc91b69feaf23e32452a7ae60e791e09967d81d4fcc7fc388182d1bd394 \ --hash=sha256:c25873c47279387cfdcbdafa36149887901d36202cb645a0e4f29686bf6e4417 - # via google-api-core + # via + # google-api-core + # grpc-google-iam-v1 + # grpcio-status +grpc-google-iam-v1==0.12.4 \ + --hash=sha256:312801ae848aeb8408c099ea372b96d253077e7851aae1a9e745df984f81f20c \ + --hash=sha256:3f0ac2c940b9a855d7ce7e31fde28bddb0d9ac362d32d07c67148306931a0e30 + # via google-cloud-resource-manager +grpcio==1.50.0 \ + --hash=sha256:05f7c248e440f538aaad13eee78ef35f0541e73498dd6f832fe284542ac4b298 \ + --hash=sha256:080b66253f29e1646ac53ef288c12944b131a2829488ac3bac8f52abb4413c0d \ + --hash=sha256:12b479839a5e753580b5e6053571de14006157f2ef9b71f38c56dc9b23b95ad6 \ + --hash=sha256:156f8009e36780fab48c979c5605eda646065d4695deea4cfcbcfdd06627ddb6 \ + --hash=sha256:15f9e6d7f564e8f0776770e6ef32dac172c6f9960c478616c366862933fa08b4 \ + --hash=sha256:177afaa7dba3ab5bfc211a71b90da1b887d441df33732e94e26860b3321434d9 \ + --hash=sha256:1a4cd8cb09d1bc70b3ea37802be484c5ae5a576108bad14728f2516279165dd7 \ + --hash=sha256:1d8d02dbb616c0a9260ce587eb751c9c7dc689bc39efa6a88cc4fa3e9c138a7b \ + --hash=sha256:2b71916fa8f9eb2abd93151fafe12e18cebb302686b924bd4ec39266211da525 \ + --hash=sha256:2d9fd6e38b16c4d286a01e1776fdf6c7a4123d99ae8d6b3f0b4a03a34bf6ce45 \ + --hash=sha256:3b611b3de3dfd2c47549ca01abfa9bbb95937eb0ea546ea1d762a335739887be \ + --hash=sha256:3e4244c09cc1b65c286d709658c061f12c61c814be0b7030a2d9966ff02611e0 \ + --hash=sha256:40838061e24f960b853d7bce85086c8e1b81c6342b1f4c47ff0edd44bbae2722 \ + --hash=sha256:4b123fbb7a777a2fedec684ca0b723d85e1d2379b6032a9a9b7851829ed3ca9a \ + --hash=sha256:531f8b46f3d3db91d9ef285191825d108090856b3bc86a75b7c3930f16ce432f \ + --hash=sha256:67dd41a31f6fc5c7db097a5c14a3fa588af54736ffc174af4411d34c4f306f68 \ + --hash=sha256:7489dbb901f4fdf7aec8d3753eadd40839c9085967737606d2c35b43074eea24 \ + --hash=sha256:8d4c8e73bf20fb53fe5a7318e768b9734cf122fe671fcce75654b98ba12dfb75 \ + --hash=sha256:8e69aa4e9b7f065f01d3fdcecbe0397895a772d99954bb82eefbb1682d274518 \ + --hash=sha256:8e8999a097ad89b30d584c034929f7c0be280cd7851ac23e9067111167dcbf55 \ + --hash=sha256:906f4d1beb83b3496be91684c47a5d870ee628715227d5d7c54b04a8de802974 \ + --hash=sha256:92d7635d1059d40d2ec29c8bf5ec58900120b3ce5150ef7414119430a4b2dd5c \ + --hash=sha256:931e746d0f75b2a5cff0a1197d21827a3a2f400c06bace036762110f19d3d507 \ + --hash=sha256:95ce51f7a09491fb3da8cf3935005bff19983b77c4e9437ef77235d787b06842 \ + --hash=sha256:9eea18a878cffc804506d39c6682d71f6b42ec1c151d21865a95fae743fda500 \ + --hash=sha256:a23d47f2fc7111869f0ff547f771733661ff2818562b04b9ed674fa208e261f4 \ + --hash=sha256:a4c23e54f58e016761b576976da6a34d876420b993f45f66a2bfb00363ecc1f9 \ + --hash=sha256:a50a1be449b9e238b9bd43d3857d40edf65df9416dea988929891d92a9f8a778 \ + --hash=sha256:ab5d0e3590f0a16cb88de4a3fa78d10eb66a84ca80901eb2c17c1d2c308c230f \ + --hash=sha256:ae23daa7eda93c1c49a9ecc316e027ceb99adbad750fbd3a56fa9e4a2ffd5ae0 \ + --hash=sha256:af98d49e56605a2912cf330b4627e5286243242706c3a9fa0bcec6e6f68646fc \ + --hash=sha256:b2f77a90ba7b85bfb31329f8eab9d9540da2cf8a302128fb1241d7ea239a5469 \ + --hash=sha256:baab51dcc4f2aecabf4ed1e2f57bceab240987c8b03533f1cef90890e6502067 \ + --hash=sha256:ca8a2254ab88482936ce941485c1c20cdeaef0efa71a61dbad171ab6758ec998 \ + --hash=sha256:cb11464f480e6103c59d558a3875bd84eed6723f0921290325ebe97262ae1347 \ + --hash=sha256:ce8513aee0af9c159319692bfbf488b718d1793d764798c3d5cff827a09e25ef \ + --hash=sha256:cf151f97f5f381163912e8952eb5b3afe89dec9ed723d1561d59cabf1e219a35 \ + --hash=sha256:d144ad10eeca4c1d1ce930faa105899f86f5d99cecfe0d7224f3c4c76265c15e \ + --hash=sha256:d534d169673dd5e6e12fb57cc67664c2641361e1a0885545495e65a7b761b0f4 \ + --hash=sha256:d75061367a69808ab2e84c960e9dce54749bcc1e44ad3f85deee3a6c75b4ede9 \ + --hash=sha256:d84d04dec64cc4ed726d07c5d17b73c343c8ddcd6b59c7199c801d6bbb9d9ed1 \ + --hash=sha256:de411d2b030134b642c092e986d21aefb9d26a28bf5a18c47dd08ded411a3bc5 \ + --hash=sha256:e07fe0d7ae395897981d16be61f0db9791f482f03fee7d1851fe20ddb4f69c03 \ + --hash=sha256:ea8ccf95e4c7e20419b7827aa5b6da6f02720270686ac63bd3493a651830235c \ + --hash=sha256:f7025930039a011ed7d7e7ef95a1cb5f516e23c5a6ecc7947259b67bea8e06ca + # via + # google-api-core + # google-cloud-bigquery + # grpc-google-iam-v1 + # grpcio-status +grpcio-status==1.48.2 \ + --hash=sha256:2c33bbdbe20188b2953f46f31af669263b6ee2a9b2d38fa0d36ee091532e21bf \ + --hash=sha256:53695f45da07437b7c344ee4ef60d370fd2850179f5a28bb26d8e2aa1102ec11 + # via + # -r requirements.in + # google-api-core +h11==0.14.0 \ + --hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \ + --hash=sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761 + # via uvicorn +httptools==0.5.0 \ + --hash=sha256:0297822cea9f90a38df29f48e40b42ac3d48a28637368f3ec6d15eebefd182f9 \ + --hash=sha256:1af91b3650ce518d226466f30bbba5b6376dbd3ddb1b2be8b0658c6799dd450b \ + --hash=sha256:1f90cd6fd97c9a1b7fe9215e60c3bd97336742a0857f00a4cb31547bc22560c2 \ + --hash=sha256:24bb4bb8ac3882f90aa95403a1cb48465de877e2d5298ad6ddcfdebec060787d \ + --hash=sha256:295874861c173f9101960bba332429bb77ed4dcd8cdf5cee9922eb00e4f6bc09 \ + --hash=sha256:3625a55886257755cb15194efbf209584754e31d336e09e2ffe0685a76cb4b60 \ + --hash=sha256:3a47a34f6015dd52c9eb629c0f5a8a5193e47bf2a12d9a3194d231eaf1bc451a \ + --hash=sha256:3cb8acf8f951363b617a8420768a9f249099b92e703c052f9a51b66342eea89b \ + --hash=sha256:4b098e4bb1174096a93f48f6193e7d9aa7071506a5877da09a783509ca5fff42 \ + --hash=sha256:4d9ebac23d2de960726ce45f49d70eb5466725c0087a078866043dad115f850f \ + --hash=sha256:50d4613025f15f4b11f1c54bbed4761c0020f7f921b95143ad6d58c151198142 \ + --hash=sha256:5230a99e724a1bdbbf236a1b58d6e8504b912b0552721c7c6b8570925ee0ccde \ + --hash=sha256:54465401dbbec9a6a42cf737627fb0f014d50dc7365a6b6cd57753f151a86ff0 \ + --hash=sha256:550059885dc9c19a072ca6d6735739d879be3b5959ec218ba3e013fd2255a11b \ + --hash=sha256:557be7fbf2bfa4a2ec65192c254e151684545ebab45eca5d50477d562c40f986 \ + --hash=sha256:5b65be160adcd9de7a7e6413a4966665756e263f0d5ddeffde277ffeee0576a5 \ + --hash=sha256:64eba6f168803a7469866a9c9b5263a7463fa8b7a25b35e547492aa7322036b6 \ + --hash=sha256:72ad589ba5e4a87e1d404cc1cb1b5780bfcb16e2aec957b88ce15fe879cc08ca \ + --hash=sha256:7d0c1044bce274ec6711f0770fd2d5544fe392591d204c68328e60a46f88843b \ + --hash=sha256:7e5eefc58d20e4c2da82c78d91b2906f1a947ef42bd668db05f4ab4201a99f49 \ + --hash=sha256:850fec36c48df5a790aa735417dca8ce7d4b48d59b3ebd6f83e88a8125cde324 \ + --hash=sha256:85b392aba273566c3d5596a0a490978c085b79700814fb22bfd537d381dd230c \ + --hash=sha256:8c2a56b6aad7cc8f5551d8e04ff5a319d203f9d870398b94702300de50190f63 \ + --hash=sha256:8f470c79061599a126d74385623ff4744c4e0f4a0997a353a44923c0b561ee51 \ + --hash=sha256:8ffce9d81c825ac1deaa13bc9694c0562e2840a48ba21cfc9f3b4c922c16f372 \ + --hash=sha256:9423a2de923820c7e82e18980b937893f4aa8251c43684fa1772e341f6e06887 \ + --hash=sha256:9b571b281a19762adb3f48a7731f6842f920fa71108aff9be49888320ac3e24d \ + --hash=sha256:a04fe458a4597aa559b79c7f48fe3dceabef0f69f562daf5c5e926b153817281 \ + --hash=sha256:aa47ffcf70ba6f7848349b8a6f9b481ee0f7637931d91a9860a1838bfc586901 \ + --hash=sha256:bede7ee075e54b9a5bde695b4fc8f569f30185891796b2e4e09e2226801d09bd \ + --hash=sha256:c1d2357f791b12d86faced7b5736dea9ef4f5ecdc6c3f253e445ee82da579449 \ + --hash=sha256:c6eeefd4435055a8ebb6c5cc36111b8591c192c56a95b45fe2af22d9881eee25 \ + --hash=sha256:ca1b7becf7d9d3ccdbb2f038f665c0f4857e08e1d8481cbcc1a86a0afcfb62b2 \ + --hash=sha256:e67d4f8734f8054d2c4858570cc4b233bf753f56e85217de4dfb2495904cf02e \ + --hash=sha256:e8a34e4c0ab7b1ca17b8763613783e2458e77938092c18ac919420ab8655c8c1 \ + --hash=sha256:e90491a4d77d0cb82e0e7a9cb35d86284c677402e4ce7ba6b448ccc7325c5421 \ + --hash=sha256:ef1616b3ba965cd68e6f759eeb5d34fbf596a79e84215eeceebf34ba3f61fdc7 \ + --hash=sha256:f222e1e9d3f13b68ff8a835574eda02e67277d51631d69d7cf7f8e07df678c86 \ + --hash=sha256:f5e3088f4ed33947e16fd865b8200f9cfae1144f41b64a8cf19b599508e096bc \ + --hash=sha256:f659d7a48401158c59933904040085c200b4be631cb5f23a7d561fbae593ec1f \ + --hash=sha256:fe9c766a0c35b7e3d6b6939393c8dfdd5da3ac5dec7f971ec9134f284c6c36d6 + # via uvicorn idna==3.3 \ --hash=sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff \ --hash=sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d - # via requests + # via + # anyio + # requests imagesize==1.4.1 \ --hash=sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b \ --hash=sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a @@ -400,7 +549,10 @@ packaging==21.3 \ --hash=sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb \ --hash=sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522 # via + # docker # gcp-releasetool + # google-cloud-aiplatform + # google-cloud-bigquery # nox # sphinx # tox @@ -442,35 +594,46 @@ prompt-toolkit==3.0.31 \ --hash=sha256:9696f386133df0fc8ca5af4895afe5d78f5fcfe5258111c2a79a1c3e41ffa96d \ --hash=sha256:9ada952c9d1787f52ff6d5f3484d0b4df8952787c087edf6a1f7c2cb1ea88148 # via ipython -protobuf==3.20.1 \ - --hash=sha256:06059eb6953ff01e56a25cd02cca1a9649a75a7e65397b5b9b4e929ed71d10cf \ - --hash=sha256:097c5d8a9808302fb0da7e20edf0b8d4703274d140fd25c5edabddcde43e081f \ - --hash=sha256:284f86a6207c897542d7e956eb243a36bb8f9564c1742b253462386e96c6b78f \ - --hash=sha256:32ca378605b41fd180dfe4e14d3226386d8d1b002ab31c969c366549e66a2bb7 \ - --hash=sha256:3cc797c9d15d7689ed507b165cd05913acb992d78b379f6014e013f9ecb20996 \ - --hash=sha256:62f1b5c4cd6c5402b4e2d63804ba49a327e0c386c99b1675c8a0fefda23b2067 \ - --hash=sha256:69ccfdf3657ba59569c64295b7d51325f91af586f8d5793b734260dfe2e94e2c \ - --hash=sha256:6f50601512a3d23625d8a85b1638d914a0970f17920ff39cec63aaef80a93fb7 \ - --hash=sha256:7403941f6d0992d40161aa8bb23e12575637008a5a02283a930addc0508982f9 \ - --hash=sha256:755f3aee41354ae395e104d62119cb223339a8f3276a0cd009ffabfcdd46bb0c \ - --hash=sha256:77053d28427a29987ca9caf7b72ccafee011257561259faba8dd308fda9a8739 \ - --hash=sha256:7e371f10abe57cee5021797126c93479f59fccc9693dafd6bd5633ab67808a91 \ - --hash=sha256:9016d01c91e8e625141d24ec1b20fed584703e527d28512aa8c8707f105a683c \ - --hash=sha256:9be73ad47579abc26c12024239d3540e6b765182a91dbc88e23658ab71767153 \ - --hash=sha256:adc31566d027f45efe3f44eeb5b1f329da43891634d61c75a5944e9be6dd42c9 \ - --hash=sha256:adfc6cf69c7f8c50fd24c793964eef18f0ac321315439d94945820612849c388 \ - --hash=sha256:af0ebadc74e281a517141daad9d0f2c5d93ab78e9d455113719a45a49da9db4e \ - --hash=sha256:cb29edb9eab15742d791e1025dd7b6a8f6fcb53802ad2f6e3adcb102051063ab \ - --hash=sha256:cd68be2559e2a3b84f517fb029ee611546f7812b1fdd0aa2ecc9bc6ec0e4fdde \ - --hash=sha256:cdee09140e1cd184ba9324ec1df410e7147242b94b5f8b0c64fc89e38a8ba531 \ - --hash=sha256:db977c4ca738dd9ce508557d4fce0f5aebd105e158c725beec86feb1f6bc20d8 \ - --hash=sha256:dd5789b2948ca702c17027c84c2accb552fc30f4622a98ab5c51fcfe8c50d3e7 \ - --hash=sha256:e250a42f15bf9d5b09fe1b293bdba2801cd520a9f5ea2d7fb7536d4441811d20 \ - --hash=sha256:ff8d8fa42675249bb456f5db06c00de6c2f4c27a065955917b28c4f15978b9c3 +proto-plus==1.22.1 \ + --hash=sha256:6c7dfd122dfef8019ff654746be4f5b1d9c80bba787fe9611b508dd88be3a2fa \ + --hash=sha256:ea8982669a23c379f74495bc48e3dcb47c822c484ce8ee1d1d7beb339d4e34c5 + # via + # google-cloud-aiplatform + # google-cloud-bigquery + # google-cloud-resource-manager +protobuf==3.20.3 \ + --hash=sha256:03038ac1cfbc41aa21f6afcbcd357281d7521b4157926f30ebecc8d4ea59dcb7 \ + --hash=sha256:28545383d61f55b57cf4df63eebd9827754fd2dc25f80c5253f9184235db242c \ + --hash=sha256:2e3427429c9cffebf259491be0af70189607f365c2f41c7c3764af6f337105f2 \ + --hash=sha256:398a9e0c3eaceb34ec1aee71894ca3299605fa8e761544934378bbc6c97de23b \ + --hash=sha256:44246bab5dd4b7fbd3c0c80b6f16686808fab0e4aca819ade6e8d294a29c7050 \ + --hash=sha256:447d43819997825d4e71bf5769d869b968ce96848b6479397e29fc24c4a5dfe9 \ + --hash=sha256:67a3598f0a2dcbc58d02dd1928544e7d88f764b47d4a286202913f0b2801c2e7 \ + --hash=sha256:74480f79a023f90dc6e18febbf7b8bac7508420f2006fabd512013c0c238f454 \ + --hash=sha256:819559cafa1a373b7096a482b504ae8a857c89593cf3a25af743ac9ecbd23480 \ + --hash=sha256:899dc660cd599d7352d6f10d83c95df430a38b410c1b66b407a6b29265d66469 \ + --hash=sha256:8c0c984a1b8fef4086329ff8dd19ac77576b384079247c770f29cc8ce3afa06c \ + --hash=sha256:9aae4406ea63d825636cc11ffb34ad3379335803216ee3a856787bcf5ccc751e \ + --hash=sha256:a7ca6d488aa8ff7f329d4c545b2dbad8ac31464f1d8b1c87ad1346717731e4db \ + --hash=sha256:b6cc7ba72a8850621bfec987cb72623e703b7fe2b9127a161ce61e61558ad905 \ + --hash=sha256:bf01b5720be110540be4286e791db73f84a2b721072a3711efff6c324cdf074b \ + --hash=sha256:c02ce36ec760252242a33967d51c289fd0e1c0e6e5cc9397e2279177716add86 \ + --hash=sha256:d9e4432ff660d67d775c66ac42a67cf2453c27cb4d738fc22cb53b5d84c135d4 \ + --hash=sha256:daa564862dd0d39c00f8086f88700fdbe8bc717e993a21e90711acfed02f2402 \ + --hash=sha256:de78575669dddf6099a8a0f46a27e82a1783c557ccc38ee620ed8cc96d3be7d7 \ + --hash=sha256:e64857f395505ebf3d2569935506ae0dfc4a15cb80dc25261176c784662cdcc4 \ + --hash=sha256:f4bd856d702e5b0d96a00ec6b307b0f51c1982c2bf9c0052cf9019e9a544ba99 \ + --hash=sha256:f4c42102bc82a51108e449cbb32b19b180022941c727bac0cfd50170341f16ee # via # gcp-docuploader # gcp-releasetool # google-api-core + # google-cloud-aiplatform + # google-cloud-bigquery + # google-cloud-resource-manager + # googleapis-common-protos + # grpcio-status + # proto-plus ptyprocess==0.7.0 \ --hash=sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35 \ --hash=sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220 @@ -499,6 +662,44 @@ pycparser==2.21 \ --hash=sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9 \ --hash=sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206 # via cffi +pydantic==1.10.2 \ + --hash=sha256:05e00dbebbe810b33c7a7362f231893183bcc4251f3f2ff991c31d5c08240c42 \ + --hash=sha256:06094d18dd5e6f2bbf93efa54991c3240964bb663b87729ac340eb5014310624 \ + --hash=sha256:0b959f4d8211fc964772b595ebb25f7652da3f22322c007b6fed26846a40685e \ + --hash=sha256:19b3b9ccf97af2b7519c42032441a891a5e05c68368f40865a90eb88833c2559 \ + --hash=sha256:1b6ee725bd6e83ec78b1aa32c5b1fa67a3a65badddde3976bca5fe4568f27709 \ + --hash=sha256:1ee433e274268a4b0c8fde7ad9d58ecba12b069a033ecc4645bb6303c062d2e9 \ + --hash=sha256:216f3bcbf19c726b1cc22b099dd409aa371f55c08800bcea4c44c8f74b73478d \ + --hash=sha256:2d0567e60eb01bccda3a4df01df677adf6b437958d35c12a3ac3e0f078b0ee52 \ + --hash=sha256:2e05aed07fa02231dbf03d0adb1be1d79cabb09025dd45aa094aa8b4e7b9dcda \ + --hash=sha256:352aedb1d71b8b0736c6d56ad2bd34c6982720644b0624462059ab29bd6e5912 \ + --hash=sha256:355639d9afc76bcb9b0c3000ddcd08472ae75318a6eb67a15866b87e2efa168c \ + --hash=sha256:37c90345ec7dd2f1bcef82ce49b6235b40f282b94d3eec47e801baf864d15525 \ + --hash=sha256:4b8795290deaae348c4eba0cebb196e1c6b98bdbe7f50b2d0d9a4a99716342fe \ + --hash=sha256:5760e164b807a48a8f25f8aa1a6d857e6ce62e7ec83ea5d5c5a802eac81bad41 \ + --hash=sha256:6eb843dcc411b6a2237a694f5e1d649fc66c6064d02b204a7e9d194dff81eb4b \ + --hash=sha256:7b5ba54d026c2bd2cb769d3468885f23f43710f651688e91f5fb1edcf0ee9283 \ + --hash=sha256:7c2abc4393dea97a4ccbb4ec7d8658d4e22c4765b7b9b9445588f16c71ad9965 \ + --hash=sha256:81a7b66c3f499108b448f3f004801fcd7d7165fb4200acb03f1c2402da73ce4c \ + --hash=sha256:91b8e218852ef6007c2b98cd861601c6a09f1aa32bbbb74fab5b1c33d4a1e410 \ + --hash=sha256:9300fcbebf85f6339a02c6994b2eb3ff1b9c8c14f502058b5bf349d42447dcf5 \ + --hash=sha256:9cabf4a7f05a776e7793e72793cd92cc865ea0e83a819f9ae4ecccb1b8aa6116 \ + --hash=sha256:a1f5a63a6dfe19d719b1b6e6106561869d2efaca6167f84f5ab9347887d78b98 \ + --hash=sha256:a4c805731c33a8db4b6ace45ce440c4ef5336e712508b4d9e1aafa617dc9907f \ + --hash=sha256:ae544c47bec47a86bc7d350f965d8b15540e27e5aa4f55170ac6a75e5f73b644 \ + --hash=sha256:b97890e56a694486f772d36efd2ba31612739bc6f3caeee50e9e7e3ebd2fdd13 \ + --hash=sha256:bb6ad4489af1bac6955d38ebcb95079a836af31e4c4f74aba1ca05bb9f6027bd \ + --hash=sha256:bedf309630209e78582ffacda64a21f96f3ed2e51fbf3962d4d488e503420254 \ + --hash=sha256:c1ba1afb396148bbc70e9eaa8c06c1716fdddabaf86e7027c5988bae2a829ab6 \ + --hash=sha256:c33602f93bfb67779f9c507e4d69451664524389546bacfe1bee13cae6dc7488 \ + --hash=sha256:c4aac8e7103bf598373208f6299fa9a5cfd1fc571f2d40bf1dd1955a63d6eeb5 \ + --hash=sha256:c6f981882aea41e021f72779ce2a4e87267458cc4d39ea990729e21ef18f0f8c \ + --hash=sha256:cc78cc83110d2f275ec1970e7a831f4e371ee92405332ebfe9860a715f8336e1 \ + --hash=sha256:d49f3db871575e0426b12e2f32fdb25e579dea16486a26e5a0474af87cb1ab0a \ + --hash=sha256:dd3f9a40c16daf323cf913593083698caee97df2804aa36c4b3175d5ac1b92a2 \ + --hash=sha256:e0bedafe4bc165ad0a56ac0bd7695df25c50f76961da29c050712596cf092d6d \ + --hash=sha256:e9069e1b01525a96e6ff49e25876d90d5a563bc31c658289a8772ae186552236 + # via fastapi pygments==2.13.0 \ --hash=sha256:56a8508ae95f98e2b9bdf93a6be5ae3f7d8af858b43e02c5a2ff083726be40c1 \ --hash=sha256:f643f331ab57ba3c9d89212ee4a2dabc6e94f117cf4eefde99a0574720d14c42 @@ -521,13 +722,61 @@ pyperclip==1.8.2 \ python-dateutil==2.8.2 \ --hash=sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86 \ --hash=sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9 - # via gcp-releasetool + # via + # gcp-releasetool + # google-cloud-bigquery +python-dotenv==0.21.0 \ + --hash=sha256:1684eb44636dd462b66c3ee016599815514527ad99965de77f43e0944634a7e5 \ + --hash=sha256:b77d08274639e3d34145dfa6c7008e66df0f04b7be7a75fd0d5292c191d79045 + # via uvicorn pytz==2022.2.1 \ --hash=sha256:220f481bdafa09c3955dfbdddb7b57780e9a94f5127e35456a48589b9e0c0197 \ --hash=sha256:cea221417204f2d1a2aa03ddae3e867921971d0d76f14d87abb4414415bbdcf5 # via # babel # django +pyyaml==6.0 \ + --hash=sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf \ + --hash=sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293 \ + --hash=sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b \ + --hash=sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57 \ + --hash=sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b \ + --hash=sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4 \ + --hash=sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07 \ + --hash=sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba \ + --hash=sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9 \ + --hash=sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287 \ + --hash=sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513 \ + --hash=sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0 \ + --hash=sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782 \ + --hash=sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0 \ + --hash=sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92 \ + --hash=sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f \ + --hash=sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2 \ + --hash=sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc \ + --hash=sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1 \ + --hash=sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c \ + --hash=sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86 \ + --hash=sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4 \ + --hash=sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c \ + --hash=sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34 \ + --hash=sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b \ + --hash=sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d \ + --hash=sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c \ + --hash=sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb \ + --hash=sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7 \ + --hash=sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737 \ + --hash=sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3 \ + --hash=sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d \ + --hash=sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358 \ + --hash=sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53 \ + --hash=sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78 \ + --hash=sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803 \ + --hash=sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a \ + --hash=sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f \ + --hash=sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174 \ + --hash=sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5 + # via uvicorn readme-renderer==37.0 \ --hash=sha256:07b7ea234e03e58f77cc222e206e6abb8f4c0435becce5104794ee591f9301c5 \ --hash=sha256:9fa416704703e509eeb900696751c908ddeb2011319d93700d8f18baff887a69 @@ -540,8 +789,10 @@ requests==2.28.1 \ --hash=sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983 \ --hash=sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349 # via + # docker # gcp-releasetool # google-api-core + # google-cloud-bigquery # google-cloud-storage # requests-toolbelt # sphinx @@ -574,8 +825,13 @@ six==1.16.0 \ # bleach # gcp-docuploader # google-auth + # grpcio # python-dateutil # tox +sniffio==1.3.0 \ + --hash=sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101 \ + --hash=sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384 + # via anyio snowballstemmer==2.2.0 \ --hash=sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1 \ --hash=sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a @@ -618,6 +874,12 @@ stack-data==0.5.0 \ --hash=sha256:66d2ebd3d7f29047612ead465b6cae5371006a71f45037c7e2507d01367bce3b \ --hash=sha256:715c8855fbf5c43587b141e46cc9d9339cc0d1f8d6e0f98ed0d01c6cb974e29f # via ipython +starlette==0.17.1 \ + --hash=sha256:26a18cbda5e6b651c964c12c88b36d9898481cd428ed6e063f5f29c418f73050 \ + --hash=sha256:57eab3cc975a28af62f6faec94d355a410634940f10b30d68d31cb5ec1b44ae8 + # via + # fastapi + # google-cloud-aiplatform tomli==2.0.1 \ --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f @@ -644,18 +906,76 @@ typing-extensions==4.3.0 \ # via # -r requirements.in # black + # pydantic urllib3==1.26.12 \ --hash=sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e \ --hash=sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997 # via + # docker # requests # twine +uvicorn[standard]==0.19.0 \ + --hash=sha256:cc277f7e73435748e69e075a721841f7c4a95dba06d12a72fe9874acced16f6f \ + --hash=sha256:cf538f3018536edb1f4a826311137ab4944ed741d52aeb98846f52215de57f25 + # via google-cloud-aiplatform +uvloop==0.17.0 \ + --hash=sha256:0949caf774b9fcefc7c5756bacbbbd3fc4c05a6b7eebc7c7ad6f825b23998d6d \ + --hash=sha256:0ddf6baf9cf11a1a22c71487f39f15b2cf78eb5bde7e5b45fbb99e8a9d91b9e1 \ + --hash=sha256:1436c8673c1563422213ac6907789ecb2b070f5939b9cbff9ef7113f2b531595 \ + --hash=sha256:23609ca361a7fc587031429fa25ad2ed7242941adec948f9d10c045bfecab06b \ + --hash=sha256:2a6149e1defac0faf505406259561bc14b034cdf1d4711a3ddcdfbaa8d825a05 \ + --hash=sha256:2deae0b0fb00a6af41fe60a675cec079615b01d68beb4cc7b722424406b126a8 \ + --hash=sha256:307958f9fc5c8bb01fad752d1345168c0abc5d62c1b72a4a8c6c06f042b45b20 \ + --hash=sha256:30babd84706115626ea78ea5dbc7dd8d0d01a2e9f9b306d24ca4ed5796c66ded \ + --hash=sha256:3378eb62c63bf336ae2070599e49089005771cc651c8769aaad72d1bd9385a7c \ + --hash=sha256:3d97672dc709fa4447ab83276f344a165075fd9f366a97b712bdd3fee05efae8 \ + --hash=sha256:3db8de10ed684995a7f34a001f15b374c230f7655ae840964d51496e2f8a8474 \ + --hash=sha256:3ebeeec6a6641d0adb2ea71dcfb76017602ee2bfd8213e3fcc18d8f699c5104f \ + --hash=sha256:45cea33b208971e87a31c17622e4b440cac231766ec11e5d22c76fab3bf9df62 \ + --hash=sha256:6708f30db9117f115eadc4f125c2a10c1a50d711461699a0cbfaa45b9a78e376 \ + --hash=sha256:68532f4349fd3900b839f588972b3392ee56042e440dd5873dfbbcd2cc67617c \ + --hash=sha256:6aafa5a78b9e62493539456f8b646f85abc7093dd997f4976bb105537cf2635e \ + --hash=sha256:7d37dccc7ae63e61f7b96ee2e19c40f153ba6ce730d8ba4d3b4e9738c1dccc1b \ + --hash=sha256:864e1197139d651a76c81757db5eb199db8866e13acb0dfe96e6fc5d1cf45fc4 \ + --hash=sha256:8887d675a64cfc59f4ecd34382e5b4f0ef4ae1da37ed665adba0c2badf0d6578 \ + --hash=sha256:8efcadc5a0003d3a6e887ccc1fb44dec25594f117a94e3127954c05cf144d811 \ + --hash=sha256:9b09e0f0ac29eee0451d71798878eae5a4e6a91aa275e114037b27f7db72702d \ + --hash=sha256:a4aee22ece20958888eedbad20e4dbb03c37533e010fb824161b4f05e641f738 \ + --hash=sha256:a5abddb3558d3f0a78949c750644a67be31e47936042d4f6c888dd6f3c95f4aa \ + --hash=sha256:c092a2c1e736086d59ac8e41f9c98f26bbf9b9222a76f21af9dfe949b99b2eb9 \ + --hash=sha256:c686a47d57ca910a2572fddfe9912819880b8765e2f01dc0dd12a9bf8573e539 \ + --hash=sha256:cbbe908fda687e39afd6ea2a2f14c2c3e43f2ca88e3a11964b297822358d0e6c \ + --hash=sha256:ce9f61938d7155f79d3cb2ffa663147d4a76d16e08f65e2c66b77bd41b356718 \ + --hash=sha256:dbbaf9da2ee98ee2531e0c780455f2841e4675ff580ecf93fe5c48fe733b5667 \ + --hash=sha256:f1e507c9ee39c61bfddd79714e4f85900656db1aec4d40c6de55648e85c2799c \ + --hash=sha256:ff3d00b70ce95adce264462c930fbaecb29718ba6563db354608f37e49e09024 + # via uvicorn virtualenv==20.16.4 \ --hash=sha256:014f766e4134d0008dcaa1f95bafa0fb0f575795d07cae50b1bee514185d6782 \ --hash=sha256:035ed57acce4ac35c82c9d8802202b0e71adac011a511ff650cbcf9635006a22 # via # nox # tox +watchfiles==0.18.0 \ + --hash=sha256:1686bc4ac40ffde7256b6543b0f9a2cc8b531ae45243786f1d3f1dda2fe39e24 \ + --hash=sha256:184799818c4fa7dbc6a1e4ca20bcbc6b85e4e0db07ce4554ea2f29b75ccd0cdc \ + --hash=sha256:27d64a6ed5e0aebef97c70fa3899a6958d4f7f049effc659e7dc3e81f3170a7b \ + --hash=sha256:320bcde0adaa972403ed3b70f784409437325a1a4df2de54ba0672203d8847e5 \ + --hash=sha256:39b932b044fef6c43e813e0bef908e0edf185bf7b5d8d53246651cb7ac9efe79 \ + --hash=sha256:4ba6d8c2f957cae3e888bc250bc60ed09fe869b3f55f09d020ed3fecbefb6a4c \ + --hash=sha256:4bbc8bfa0f3871b1867af42837a5635a9c1cbb2b68d039754b4750642c34aaee \ + --hash=sha256:76a4c4a8e25a2c9a4f7fa3d373bbaf5558c17b97b4cf8411d33de368fe6b68a9 \ + --hash=sha256:78b1e7c29b92dfc8fc32f15949019232b493767d236c2bff31848df13fdb9e8a \ + --hash=sha256:7f39fcdac5d5b9815a0c2ab9005d39854296b11fa15386a9a69c09cbbc5dde2c \ + --hash=sha256:8eddc2d19bf6f49aee224072ec0f4f3258125a49f11b5dcff1448e68718a745e \ + --hash=sha256:9d3a12e4de5446fb6e286b720d0cb3a080811caf0ef43e556c2db5fe10ef0342 \ + --hash=sha256:9e611a90482ac14ef3ec234c1604ed921d1b0c68970eba82f1cf0d59a3e4eb76 \ + --hash=sha256:bbe10d134eef1666451382015e48f092c941a6d4562a98ffa1a288f79a897c46 \ + --hash=sha256:be87c9b1fe2b02105a9ac6d9df7500a110652bbd97cf46b13964eeaef9a6c89c \ + --hash=sha256:cfdbfc4b6797c28dd1a8524581fed00ca333971b4111af8cd42fb7a92dcdc227 \ + --hash=sha256:d5d799614d4c56d29c5ba56f4f619f967210dc10a0d6965b62d326b9e2f72c9e \ + --hash=sha256:fd4215badad1e3d1ad5fb79f21432dd5157e2e7b0765d27a19dc2a28580c6979 + # via uvicorn wcwidth==0.2.5 \ --hash=sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784 \ --hash=sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83 @@ -664,6 +984,81 @@ webencodings==0.5.1 \ --hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \ --hash=sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923 # via bleach +websocket-client==1.4.1 \ + --hash=sha256:398909eb7e261f44b8f4bd474785b6ec5f5b499d4953342fe9755e01ef624090 \ + --hash=sha256:f9611eb65c8241a67fb373bef040b3cf8ad377a9f6546a12b620b6511e8ea9ef + # via docker +websockets==10.4 \ + --hash=sha256:00213676a2e46b6ebf6045bc11d0f529d9120baa6f58d122b4021ad92adabd41 \ + --hash=sha256:00c870522cdb69cd625b93f002961ffb0c095394f06ba8c48f17eef7c1541f96 \ + --hash=sha256:0154f7691e4fe6c2b2bc275b5701e8b158dae92a1ab229e2b940efe11905dff4 \ + --hash=sha256:05a7233089f8bd355e8cbe127c2e8ca0b4ea55467861906b80d2ebc7db4d6b72 \ + --hash=sha256:09a1814bb15eff7069e51fed0826df0bc0702652b5cb8f87697d469d79c23576 \ + --hash=sha256:0cff816f51fb33c26d6e2b16b5c7d48eaa31dae5488ace6aae468b361f422b63 \ + --hash=sha256:185929b4808b36a79c65b7865783b87b6841e852ef5407a2fb0c03381092fa3b \ + --hash=sha256:2fc8709c00704194213d45e455adc106ff9e87658297f72d544220e32029cd3d \ + --hash=sha256:33d69ca7612f0ddff3316b0c7b33ca180d464ecac2d115805c044bf0a3b0d032 \ + --hash=sha256:389f8dbb5c489e305fb113ca1b6bdcdaa130923f77485db5b189de343a179393 \ + --hash=sha256:38ea7b82bfcae927eeffc55d2ffa31665dc7fec7b8dc654506b8e5a518eb4d50 \ + --hash=sha256:3d3cac3e32b2c8414f4f87c1b2ab686fa6284a980ba283617404377cd448f631 \ + --hash=sha256:40e826de3085721dabc7cf9bfd41682dadc02286d8cf149b3ad05bff89311e4f \ + --hash=sha256:4239b6027e3d66a89446908ff3027d2737afc1a375f8fd3eea630a4842ec9a0c \ + --hash=sha256:45ec8e75b7dbc9539cbfafa570742fe4f676eb8b0d3694b67dabe2f2ceed8aa6 \ + --hash=sha256:47a2964021f2110116cc1125b3e6d87ab5ad16dea161949e7244ec583b905bb4 \ + --hash=sha256:48c08473563323f9c9debac781ecf66f94ad5a3680a38fe84dee5388cf5acaf6 \ + --hash=sha256:4c6d2264f485f0b53adf22697ac11e261ce84805c232ed5dbe6b1bcb84b00ff0 \ + --hash=sha256:4f72e5cd0f18f262f5da20efa9e241699e0cf3a766317a17392550c9ad7b37d8 \ + --hash=sha256:56029457f219ade1f2fc12a6504ea61e14ee227a815531f9738e41203a429112 \ + --hash=sha256:5c1289596042fad2cdceb05e1ebf7aadf9995c928e0da2b7a4e99494953b1b94 \ + --hash=sha256:62e627f6b6d4aed919a2052efc408da7a545c606268d5ab5bfab4432734b82b4 \ + --hash=sha256:74de2b894b47f1d21cbd0b37a5e2b2392ad95d17ae983e64727e18eb281fe7cb \ + --hash=sha256:7c584f366f46ba667cfa66020344886cf47088e79c9b9d39c84ce9ea98aaa331 \ + --hash=sha256:7d27a7e34c313b3a7f91adcd05134315002aaf8540d7b4f90336beafaea6217c \ + --hash=sha256:7d3f0b61c45c3fa9a349cf484962c559a8a1d80dae6977276df8fd1fa5e3cb8c \ + --hash=sha256:82ff5e1cae4e855147fd57a2863376ed7454134c2bf49ec604dfe71e446e2193 \ + --hash=sha256:84bc2a7d075f32f6ed98652db3a680a17a4edb21ca7f80fe42e38753a58ee02b \ + --hash=sha256:884be66c76a444c59f801ac13f40c76f176f1bfa815ef5b8ed44321e74f1600b \ + --hash=sha256:8a5cc00546e0a701da4639aa0bbcb0ae2bb678c87f46da01ac2d789e1f2d2038 \ + --hash=sha256:8dc96f64ae43dde92530775e9cb169979f414dcf5cff670455d81a6823b42089 \ + --hash=sha256:8f38706e0b15d3c20ef6259fd4bc1700cd133b06c3c1bb108ffe3f8947be15fa \ + --hash=sha256:90fcf8929836d4a0e964d799a58823547df5a5e9afa83081761630553be731f9 \ + --hash=sha256:931c039af54fc195fe6ad536fde4b0de04da9d5916e78e55405436348cfb0e56 \ + --hash=sha256:932af322458da7e4e35df32f050389e13d3d96b09d274b22a7aa1808f292fee4 \ + --hash=sha256:942de28af58f352a6f588bc72490ae0f4ccd6dfc2bd3de5945b882a078e4e179 \ + --hash=sha256:9bc42e8402dc5e9905fb8b9649f57efcb2056693b7e88faa8fb029256ba9c68c \ + --hash=sha256:a7a240d7a74bf8d5cb3bfe6be7f21697a28ec4b1a437607bae08ac7acf5b4882 \ + --hash=sha256:a9f9a735deaf9a0cadc2d8c50d1a5bcdbae8b6e539c6e08237bc4082d7c13f28 \ + --hash=sha256:ae5e95cfb53ab1da62185e23b3130e11d64431179debac6dc3c6acf08760e9b1 \ + --hash=sha256:b029fb2032ae4724d8ae8d4f6b363f2cc39e4c7b12454df8df7f0f563ed3e61a \ + --hash=sha256:b0d15c968ea7a65211e084f523151dbf8ae44634de03c801b8bd070b74e85033 \ + --hash=sha256:b343f521b047493dc4022dd338fc6db9d9282658862756b4f6fd0e996c1380e1 \ + --hash=sha256:b627c266f295de9dea86bd1112ed3d5fafb69a348af30a2422e16590a8ecba13 \ + --hash=sha256:b9968694c5f467bf67ef97ae7ad4d56d14be2751000c1207d31bf3bb8860bae8 \ + --hash=sha256:ba089c499e1f4155d2a3c2a05d2878a3428cf321c848f2b5a45ce55f0d7d310c \ + --hash=sha256:bbccd847aa0c3a69b5f691a84d2341a4f8a629c6922558f2a70611305f902d74 \ + --hash=sha256:bc0b82d728fe21a0d03e65f81980abbbcb13b5387f733a1a870672c5be26edab \ + --hash=sha256:c57e4c1349fbe0e446c9fa7b19ed2f8a4417233b6984277cce392819123142d3 \ + --hash=sha256:c94ae4faf2d09f7c81847c63843f84fe47bf6253c9d60b20f25edfd30fb12588 \ + --hash=sha256:c9b27d6c1c6cd53dc93614967e9ce00ae7f864a2d9f99fe5ed86706e1ecbf485 \ + --hash=sha256:d210abe51b5da0ffdbf7b43eed0cfdff8a55a1ab17abbec4301c9ff077dd0342 \ + --hash=sha256:d58804e996d7d2307173d56c297cf7bc132c52df27a3efaac5e8d43e36c21c48 \ + --hash=sha256:d6a4162139374a49eb18ef5b2f4da1dd95c994588f5033d64e0bbfda4b6b6fcf \ + --hash=sha256:da39dd03d130162deb63da51f6e66ed73032ae62e74aaccc4236e30edccddbb0 \ + --hash=sha256:db3c336f9eda2532ec0fd8ea49fef7a8df8f6c804cdf4f39e5c5c0d4a4ad9a7a \ + --hash=sha256:dd500e0a5e11969cdd3320935ca2ff1e936f2358f9c2e61f100a1660933320ea \ + --hash=sha256:dd9becd5fe29773d140d68d607d66a38f60e31b86df75332703757ee645b6faf \ + --hash=sha256:e0cb5cc6ece6ffa75baccfd5c02cffe776f3f5c8bf486811f9d3ea3453676ce8 \ + --hash=sha256:e23173580d740bf8822fd0379e4bf30aa1d5a92a4f252d34e893070c081050df \ + --hash=sha256:e3a686ecb4aa0d64ae60c9c9f1a7d5d46cab9bfb5d91a2d303d00e2cd4c4c5cc \ + --hash=sha256:e789376b52c295c4946403bd0efecf27ab98f05319df4583d3c48e43c7342c2f \ + --hash=sha256:edc344de4dac1d89300a053ac973299e82d3db56330f3494905643bb68801269 \ + --hash=sha256:eef610b23933c54d5d921c92578ae5f89813438fded840c2e9809d378dc765d3 \ + --hash=sha256:f2c38d588887a609191d30e902df2a32711f708abfd85d318ca9b367258cfd0c \ + --hash=sha256:f55b5905705725af31ccef50e55391621532cd64fbf0bc6f4bac935f0fccec46 \ + --hash=sha256:f5fc088b7a32f244c519a048c170f14cf2251b849ef0e20cbbb0fdf0fdaf556f \ + --hash=sha256:fe10ddc59b304cb19a1bdf5bd0a7719cbbc9fbdd57ac80ed436b709fcf889106 \ + --hash=sha256:ff64a1d38d156d429404aaa84b27305e957fd10c30e5880d1765c9480bea490f + # via uvicorn wheel==0.37.1 \ --hash=sha256:4bdcd7d840138086126cd09254dc6195fb4fc6f01c050a1d7236f2630db1d22a \ --hash=sha256:e9a504e793efbca1b8e0e9cb979a249cf4a0a7b5b8c9e8b65a5e39d49529c1c4 diff --git a/packages/gcp-sphinx-docfx-yaml/owlbot.py b/packages/gcp-sphinx-docfx-yaml/owlbot.py index d53660b85311..9feffe01c5e2 100644 --- a/packages/gcp-sphinx-docfx-yaml/owlbot.py +++ b/packages/gcp-sphinx-docfx-yaml/owlbot.py @@ -42,6 +42,7 @@ ".kokoro/samples/**", # no samples ".kokoro/test-sample*", ".kokoro/requirements.txt", # using custom requirements.txt file + ".kokoro/requirements.in", # using custom requirements.in file "CONTRIBUTING.rst", # repo has a CONTRIBUTING.md ".github/CONTRIBUTING.md", ".github/PULL_REQUEST_TEMPLATE.md", @@ -52,8 +53,3 @@ ], ) -s.replace( - ".kokoro/requirements.in", - r"nox", - "\\g<0>\ntox\nsphinx==4.5.0\nrecommonmark\ndjango==2.2\nipython\nblack==22.8.0\nparameterized==0.8.1" -) From d03c36832031bad1a0aa3992b789653fe08584dd Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Tue, 1 Nov 2022 14:35:33 -0400 Subject: [PATCH 166/279] feat: add golden testing (#262) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * test: add initial test data and update gitignore * test: add missing file * test: add goldens * test: add golden test * test: update gapic-combo to pubsub from bigquery * test: update goldens * test: remove unused tests * chore: remove further unused files * test: update golden test logic for repo * test: update goldens with new repo test: omit gapic-combo test: include gapic-combo again in goldens * fix: sort TOC alphabetically by href * test: restrict to 3.9 * test: address review comments for test_goldens * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * chore: update presubmit name * fix: address review comment Co-authored-by: Owl Bot --- .../.github/workflows/ci.yaml | 12 +- packages/gcp-sphinx-docfx-yaml/.gitignore | 1 + packages/gcp-sphinx-docfx-yaml/appveyor.yml | 41 - packages/gcp-sphinx-docfx-yaml/debug.py | 41 - .../docfx_yaml/markdown_utils.py | 29 +- .../gcp-sphinx-docfx-yaml/old_appveyor.yml | 57 - .../gcp-sphinx-docfx-yaml/requirements.txt | 10 +- .../{readthedocs.yml => tests/conftest.py} | 18 +- .../tests/example/conflict/foo.py | 203 - .../tests/example/doc/conf.py | 40 - .../tests/example/doc/format.google.rst | 22 - .../tests/example/doc/format.numpy.rst | 22 - .../tests/example/doc/format.rst | 19 - .../tests/example/doc/format.rst.rst | 38 - .../example/doc/nspkg.native.native_foo.rst | 10 - .../nspkg.pkg_resources.pkg_resources_foo.rst | 10 - .../tests/example/doc/nspkg.pkg_resources.rst | 17 - .../example/doc/nspkg.pkgutil.pkgutil_foo.rst | 10 - .../tests/example/doc/nspkg.pkgutil.rst | 17 - .../tests/example/doc/nspkg.rst | 18 - .../tests/example/format/google/foo.py | 183 - .../tests/example/format/numpy/foo.py | 204 - .../tests/example/format/rst/directives.py | 85 - .../tests/example/format/rst/foo.py | 203 - .../tests/example/nspkg/native/__init__.pyi | 2 - .../example/nspkg/pkg_resources/__init__.py | 19 - .../tests/example/nspkg/pkgutil/__init__.py | 19 - .../tests/example/setup.cfg | 2 - .../tests/example/setup.py | 27 - .../tests/test_goldens.py | 152 + .../gcp-sphinx-docfx-yaml/tests/test_yaml.py | 534 -- .../tests/testdata/gapic-auto/CHANGELOG.md | 381 ++ .../tests/testdata/gapic-auto/README.rst | 107 + .../tests/testdata/gapic-auto/UPGRADING.md | 151 + .../tests/testdata/gapic-auto/docs/README.rst | 1 + .../testdata/gapic-auto/docs/UPGRADING.md | 1 + .../gapic-auto/docs/_static/custom.css | 20 + .../gapic-auto/docs/_templates/layout.html | 50 + .../testdata/gapic-auto/docs/changelog.md | 1 + .../tests/testdata/gapic-auto/docs/conf.py | 384 ++ .../tests/testdata/gapic-auto/docs/index.rst | 45 + .../gapic-auto/docs/multiprocessing.rst | 7 + .../docs/texttospeech_v1/services.rst | 6 + .../docs/texttospeech_v1/text_to_speech.rst | 6 + .../gapic-auto/docs/texttospeech_v1/types.rst | 7 + .../docs/texttospeech_v1beta1/services.rst | 6 + .../texttospeech_v1beta1/text_to_speech.rst | 6 + .../docs/texttospeech_v1beta1/types.rst | 7 + .../google/cloud/texttospeech/__init__.py | 51 + .../google/cloud/texttospeech/py.typed | 2 + .../google/cloud/texttospeech_v1/__init__.py | 46 + .../cloud/texttospeech_v1/gapic_metadata.json | 43 + .../google/cloud/texttospeech_v1/py.typed | 2 + .../texttospeech_v1/services}/__init__.py | 11 +- .../services/text_to_speech/__init__.py | 22 + .../services/text_to_speech/async_client.py | 448 ++ .../services/text_to_speech/client.py | 682 +++ .../text_to_speech/transports/__init__.py | 32 + .../text_to_speech/transports/base.py | 177 + .../text_to_speech/transports/grpc.py | 294 ++ .../text_to_speech/transports/grpc_asyncio.py | 296 ++ .../cloud/texttospeech_v1/types/__init__.py | 42 + .../cloud/texttospeech_v1/types/cloud_tts.py | 388 ++ .../cloud/texttospeech_v1beta1/__init__.py | 48 + .../texttospeech_v1beta1/gapic_metadata.json | 43 + .../cloud/texttospeech_v1beta1/py.typed | 2 + .../services}/__init__.py | 12 +- .../services/text_to_speech/__init__.py | 22 + .../services/text_to_speech/async_client.py | 448 ++ .../services/text_to_speech/client.py | 682 +++ .../text_to_speech/transports/__init__.py | 32 + .../text_to_speech/transports/base.py | 177 + .../text_to_speech/transports/grpc.py | 294 ++ .../text_to_speech/transports/grpc_asyncio.py | 296 ++ .../texttospeech_v1beta1/types/__init__.py | 44 + .../texttospeech_v1beta1/types/cloud_tts.py | 444 ++ .../gapic-auto/scripts/decrypt-secrets.sh | 46 + .../gapic-auto/scripts/fixup_keywords.py | 178 + .../scripts/fixup_texttospeech_v1_keywords.py | 177 + .../fixup_texttospeech_v1beta1_keywords.py | 177 + .../scripts/readme-gen/readme_gen.py | 69 + .../readme-gen/templates/README.tmpl.rst | 87 + .../readme-gen/templates/auth.tmpl.rst | 9 + .../templates/auth_api_key.tmpl.rst | 14 + .../templates/install_deps.tmpl.rst | 29 + .../templates/install_portaudio.tmpl.rst | 35 + .../gapic-auto/setup.cfg} | 11 +- .../tests/testdata/gapic-auto/setup.py | 104 + .../tests/testdata/gapic-combo/CHANGELOG.md | 1149 +++++ .../tests/testdata/gapic-combo/README.rst | 233 + .../tests/testdata/gapic-combo/UPGRADING.md | 201 + .../testdata/gapic-combo/docs/README.rst | 1 + .../testdata/gapic-combo/docs/UPGRADING.md | 1 + .../gapic-combo/docs/_static/custom.css | 20 + .../gapic-combo/docs/_templates/layout.html | 50 + .../testdata/gapic-combo/docs/changelog.md | 1 + .../tests/testdata/gapic-combo/docs/conf.py | 384 ++ .../tests/testdata/gapic-combo/docs/index.rst | 43 + .../gapic-combo/docs/multiprocessing.rst | 7 + .../docs/pubsub/publisher/api/client.rst | 6 + .../docs/pubsub/publisher/api/futures.rst | 6 + .../docs/pubsub/publisher/api/pagers.rst | 6 + .../docs/pubsub/publisher/index.rst | 187 + .../docs/pubsub/subscriber/api/client.rst | 6 + .../docs/pubsub/subscriber/api/futures.rst | 6 + .../docs/pubsub/subscriber/api/message.rst | 6 + .../docs/pubsub/subscriber/api/pagers.rst | 6 + .../docs/pubsub/subscriber/api/scheduler.rst | 6 + .../docs/pubsub/subscriber/index.rst | 236 + .../gapic-combo/docs/pubsub/types.rst | 6 + .../gapic-combo/google}/__init__.py | 23 +- .../gapic-combo/google/cloud/__init__.py} | 26 +- .../google/cloud/pubsub/__init__.py} | 39 +- .../google/cloud/pubsub_v1/__init__.py | 35 + .../google/cloud/pubsub_v1/exceptions.py} | 18 +- .../google/cloud/pubsub_v1/futures.py | 56 + .../google/cloud/pubsub_v1/proto/pubsub.proto | 1344 +++++ .../google/cloud/pubsub_v1/proto/schema.proto | 286 ++ .../cloud/pubsub_v1/publisher}/__init__.py | 15 +- .../pubsub_v1/publisher/_batch/__init__.py} | 0 .../cloud/pubsub_v1/publisher/_batch/base.py | 170 + .../pubsub_v1/publisher/_batch/thread.py | 409 ++ .../publisher/_sequencer/__init__.py | 0 .../pubsub_v1/publisher/_sequencer/base.py | 82 + .../publisher/_sequencer/ordered_sequencer.py | 338 ++ .../_sequencer/unordered_sequencer.py | 165 + .../cloud/pubsub_v1/publisher/client.py | 519 ++ .../cloud/pubsub_v1/publisher/exceptions.py | 51 + .../pubsub_v1/publisher/flow_controller.py | 313 ++ .../cloud/pubsub_v1/publisher/futures.py | 83 + .../cloud/pubsub_v1/subscriber/__init__.py | 20 + .../subscriber/_protocol/__init__.py | 0 .../subscriber/_protocol/dispatcher.py | 406 ++ .../subscriber/_protocol/heartbeater.py | 77 + .../subscriber/_protocol/helper_threads.py | 122 + .../subscriber/_protocol/histogram.py | 159 + .../pubsub_v1/subscriber/_protocol/leaser.py | 241 + .../subscriber/_protocol/messages_on_hold.py | 168 + .../subscriber/_protocol/requests.py | 54 + .../_protocol/streaming_pull_manager.py | 1179 +++++ .../cloud/pubsub_v1/subscriber/client.py | 289 ++ .../cloud/pubsub_v1/subscriber/exceptions.py | 44 + .../cloud/pubsub_v1/subscriber/futures.py | 125 + .../cloud/pubsub_v1/subscriber/message.py | 488 ++ .../cloud/pubsub_v1/subscriber/scheduler.py | 170 + .../google/cloud/pubsub_v1/types.py | 238 + .../gapic-combo/google/pubsub/__init__.py | 148 + .../gapic-combo/google/pubsub/py.typed | 2 + .../gapic-combo/google/pubsub_v1/__init__.py | 146 + .../google/pubsub_v1/gapic_metadata.json | 361 ++ .../gapic-combo/google/pubsub_v1/py.typed | 2 + .../google/pubsub_v1/services}/__init__.py | 12 +- .../pubsub_v1/services/publisher}/__init__.py | 16 +- .../services/publisher/async_client.py | 1561 ++++++ .../pubsub_v1/services/publisher/client.py | 1754 +++++++ .../pubsub_v1/services/publisher/pagers.py | 411 ++ .../services/publisher/transports/__init__.py | 33 + .../services/publisher/transports/base.py | 406 ++ .../services/publisher/transports/grpc.py | 575 +++ .../publisher/transports/grpc_asyncio.py | 581 +++ .../services/schema_service/__init__.py | 22 + .../services/schema_service/async_client.py | 1154 +++++ .../services/schema_service/client.py | 1393 ++++++ .../services/schema_service/pagers.py | 155 + .../schema_service/transports/__init__.py | 33 + .../schema_service/transports/base.py | 270 + .../schema_service/transports/grpc.py | 478 ++ .../schema_service/transports/grpc_asyncio.py | 485 ++ .../pubsub_v1/services/subscriber/__init__.py | 22 + .../services/subscriber/async_client.py | 2517 ++++++++++ .../pubsub_v1/services/subscriber/client.py | 2644 ++++++++++ .../pubsub_v1/services/subscriber/pagers.py | 283 ++ .../subscriber/transports/__init__.py | 33 + .../services/subscriber/transports/base.py | 567 +++ .../services/subscriber/transports/grpc.py | 834 ++++ .../subscriber/transports/grpc_asyncio.py | 843 ++++ .../google/pubsub_v1/types/__init__.py | 147 + .../google/pubsub_v1/types/pubsub.py | 1867 +++++++ .../google/pubsub_v1/types/schema.py | 318 ++ .../gapic-combo/scripts/decrypt-secrets.sh | 46 + .../scripts/fixup_pubsub_v1_keywords.py | 209 + .../scripts/readme-gen/readme_gen.py | 69 + .../readme-gen/templates/README.tmpl.rst | 87 + .../readme-gen/templates/auth.tmpl.rst | 9 + .../templates/auth_api_key.tmpl.rst | 14 + .../templates/install_deps.tmpl.rst | 29 + .../templates/install_portaudio.tmpl.rst | 35 + .../gapic-combo/setup.cfg} | 11 +- .../tests/testdata/gapic-combo/setup.py | 95 + .../testdata/goldens/gapic-auto/changelog.md | 489 ++ ...text_to_speech.TextToSpeechAsyncClient.yml | 846 ++++ ...ices.text_to_speech.TextToSpeechClient.yml | 862 ++++ ...exttospeech_v1.services.text_to_speech.yml | 34 + ...loud.texttospeech_v1.types.AudioConfig.yml | 73 + ...ud.texttospeech_v1.types.AudioEncoding.yml | 42 + ....types.CustomVoiceParams.ReportedUsage.yml | 44 + ...exttospeech_v1.types.CustomVoiceParams.yml | 45 + ...exttospeech_v1.types.ListVoicesRequest.yml | 43 + ...xttospeech_v1.types.ListVoicesResponse.yml | 35 + ....texttospeech_v1.types.SsmlVoiceGender.yml | 42 + ...d.texttospeech_v1.types.SynthesisInput.yml | 60 + ...peech_v1.types.SynthesizeSpeechRequest.yml | 45 + ...eech_v1.types.SynthesizeSpeechResponse.yml | 42 + ...ogle.cloud.texttospeech_v1.types.Voice.yml | 46 + ...tospeech_v1.types.VoiceSelectionParams.yml | 61 + .../google.cloud.texttospeech_v1.types.yml | 88 + ...text_to_speech.TextToSpeechAsyncClient.yml | 846 ++++ ...ices.text_to_speech.TextToSpeechClient.yml | 862 ++++ ...speech_v1beta1.services.text_to_speech.yml | 34 + ...texttospeech_v1beta1.types.AudioConfig.yml | 73 + ...xttospeech_v1beta1.types.AudioEncoding.yml | 42 + ....types.CustomVoiceParams.ReportedUsage.yml | 44 + ...speech_v1beta1.types.CustomVoiceParams.yml | 45 + ...speech_v1beta1.types.ListVoicesRequest.yml | 43 + ...peech_v1beta1.types.ListVoicesResponse.yml | 35 + ...tospeech_v1beta1.types.SsmlVoiceGender.yml | 42 + ...ttospeech_v1beta1.types.SynthesisInput.yml | 60 + ....SynthesizeSpeechRequest.TimepointType.yml | 42 + ..._v1beta1.types.SynthesizeSpeechRequest.yml | 54 + ...v1beta1.types.SynthesizeSpeechResponse.yml | 50 + ...d.texttospeech_v1beta1.types.Timepoint.yml | 41 + ...cloud.texttospeech_v1beta1.types.Voice.yml | 46 + ...ech_v1beta1.types.VoiceSelectionParams.yml | 61 + ...oogle.cloud.texttospeech_v1beta1.types.yml | 94 + .../testdata/goldens/gapic-auto/index.md | 87 + .../goldens/gapic-auto/multiprocessing.md | 7 + .../tests/testdata/goldens/gapic-auto/toc.yml | 103 + .../testdata/goldens/gapic-auto/upgrading.md | 151 + .../testdata/goldens/gapic-combo/changelog.md | 1685 +++++++ ...loud.pubsub_v1.publisher.client.Client.yml | 1790 +++++++ ...oogle.cloud.pubsub_v1.publisher.client.yml | 28 + ...oud.pubsub_v1.publisher.futures.Future.yml | 438 ++ ...ogle.cloud.pubsub_v1.publisher.futures.yml | 28 + ...oud.pubsub_v1.subscriber.client.Client.yml | 2339 +++++++++ ...ogle.cloud.pubsub_v1.subscriber.client.yml | 28 + ...ud.pubsub_v1.subscriber.futures.Future.yml | 435 ++ ...subscriber.futures.StreamingPullFuture.yml | 431 ++ ...gle.cloud.pubsub_v1.subscriber.futures.yml | 34 + ...d.pubsub_v1.subscriber.message.Message.yml | 722 +++ ...bsub_v1.subscriber.scheduler.Scheduler.yml | 126 + ...1.subscriber.scheduler.ThreadScheduler.yml | 122 + ...e.cloud.pubsub_v1.subscriber.scheduler.yml | 43 + ...oud.pubsub_v1.types.AcknowledgeRequest.yml | 41 + ...ogle.cloud.pubsub_v1.types.AuditConfig.yml | 30 + ...cloud.pubsub_v1.types.AuditConfigDelta.yml | 30 + ...google.cloud.pubsub_v1.types.AuditData.yml | 30 + ...e.cloud.pubsub_v1.types.AuditLogConfig.yml | 30 + ...le.cloud.pubsub_v1.types.BatchSettings.yml | 157 + ...d.pubsub_v1.types.BigQueryConfig.State.yml | 40 + ...e.cloud.pubsub_v1.types.BigQueryConfig.yml | 63 + .../google.cloud.pubsub_v1.types.Binding.yml | 30 + ...gle.cloud.pubsub_v1.types.BindingDelta.yml | 30 + ...ypes.CreateSnapshotRequest.LabelsEntry.yml | 44 + ....pubsub_v1.types.CreateSnapshotRequest.yml | 58 + ...loud.pubsub_v1.types.CustomHttpPattern.yml | 30 + ...cloud.pubsub_v1.types.DeadLetterPolicy.yml | 61 + ....pubsub_v1.types.DeleteSnapshotRequest.yml | 35 + ...sub_v1.types.DeleteSubscriptionRequest.yml | 36 + ...oud.pubsub_v1.types.DeleteTopicRequest.yml | 35 + ...1.types.DescriptorProto.ExtensionRange.yml | 31 + ...v1.types.DescriptorProto.ReservedRange.yml | 30 + ....cloud.pubsub_v1.types.DescriptorProto.yml | 42 + ...sub_v1.types.DetachSubscriptionRequest.yml | 36 + ...ub_v1.types.DetachSubscriptionResponse.yml | 35 + .../google.cloud.pubsub_v1.types.Duration.yml | 33 + .../google.cloud.pubsub_v1.types.Empty.yml | 30 + ....EnumDescriptorProto.EnumReservedRange.yml | 31 + ...ud.pubsub_v1.types.EnumDescriptorProto.yml | 36 + ...ogle.cloud.pubsub_v1.types.EnumOptions.yml | 30 + ...bsub_v1.types.EnumValueDescriptorProto.yml | 30 + ...cloud.pubsub_v1.types.EnumValueOptions.yml | 30 + ...cloud.pubsub_v1.types.ExpirationPolicy.yml | 42 + ....pubsub_v1.types.ExtensionRangeOptions.yml | 30 + ...d.pubsub_v1.types.FieldDescriptorProto.yml | 30 + ...google.cloud.pubsub_v1.types.FieldMask.yml | 33 + ...gle.cloud.pubsub_v1.types.FieldOptions.yml | 30 + ...ud.pubsub_v1.types.FileDescriptorProto.yml | 30 + ...loud.pubsub_v1.types.FileDescriptorSet.yml | 30 + ...ogle.cloud.pubsub_v1.types.FileOptions.yml | 30 + ...ogle.cloud.pubsub_v1.types.FlowControl.yml | 221 + ..._v1.types.GeneratedCodeInfo.Annotation.yml | 30 + ...loud.pubsub_v1.types.GeneratedCodeInfo.yml | 36 + ...ud.pubsub_v1.types.GetIamPolicyRequest.yml | 30 + ...oud.pubsub_v1.types.GetSnapshotRequest.yml | 35 + ...pubsub_v1.types.GetSubscriptionRequest.yml | 36 + ....cloud.pubsub_v1.types.GetTopicRequest.yml | 35 + .../google.cloud.pubsub_v1.types.Http.yml | 30 + .../google.cloud.pubsub_v1.types.HttpRule.yml | 30 + ....pubsub_v1.types.LimitExceededBehavior.yml | 36 + ...d.pubsub_v1.types.ListSnapshotsRequest.yml | 44 + ....pubsub_v1.types.ListSnapshotsResponse.yml | 39 + ...bsub_v1.types.ListSubscriptionsRequest.yml | 45 + ...sub_v1.types.ListSubscriptionsResponse.yml | 41 + ...sub_v1.types.ListTopicSnapshotsRequest.yml | 45 + ...ub_v1.types.ListTopicSnapshotsResponse.yml | 41 + ...v1.types.ListTopicSubscriptionsRequest.yml | 45 + ...1.types.ListTopicSubscriptionsResponse.yml | 42 + ...loud.pubsub_v1.types.ListTopicsRequest.yml | 44 + ...oud.pubsub_v1.types.ListTopicsResponse.yml | 39 + ...e.cloud.pubsub_v1.types.MessageOptions.yml | 30 + ...d.pubsub_v1.types.MessageStoragePolicy.yml | 41 + ....pubsub_v1.types.MethodDescriptorProto.yml | 30 + ...le.cloud.pubsub_v1.types.MethodOptions.yml | 30 + ...bsub_v1.types.ModifyAckDeadlineRequest.yml | 49 + ...ubsub_v1.types.ModifyPushConfigRequest.yml | 43 + ...d.pubsub_v1.types.OneofDescriptorProto.yml | 30 + ...gle.cloud.pubsub_v1.types.OneofOptions.yml | 30 + .../google.cloud.pubsub_v1.types.Policy.yml | 30 + ...ogle.cloud.pubsub_v1.types.PolicyDelta.yml | 30 + ...oud.pubsub_v1.types.PublishFlowControl.yml | 155 + ...e.cloud.pubsub_v1.types.PublishRequest.yml | 39 + ....cloud.pubsub_v1.types.PublishResponse.yml | 37 + ...cloud.pubsub_v1.types.PublisherOptions.yml | 191 + ...v1.types.PubsubMessage.AttributesEntry.yml | 44 + ...le.cloud.pubsub_v1.types.PubsubMessage.yml | 84 + ...ogle.cloud.pubsub_v1.types.PullRequest.yml | 50 + ...gle.cloud.pubsub_v1.types.PullResponse.yml | 38 + ...ub_v1.types.PushConfig.AttributesEntry.yml | 44 + ...d.pubsub_v1.types.PushConfig.OidcToken.yml | 48 + ...oogle.cloud.pubsub_v1.types.PushConfig.yml | 74 + ....cloud.pubsub_v1.types.ReceivedMessage.yml | 51 + ...ogle.cloud.pubsub_v1.types.RetryPolicy.yml | 61 + ...e.cloud.pubsub_v1.types.SchemaSettings.yml | 41 + ...ogle.cloud.pubsub_v1.types.SeekRequest.yml | 65 + ...gle.cloud.pubsub_v1.types.SeekResponse.yml | 33 + ...pubsub_v1.types.ServiceDescriptorProto.yml | 30 + ...e.cloud.pubsub_v1.types.ServiceOptions.yml | 30 + ...ud.pubsub_v1.types.SetIamPolicyRequest.yml | 30 + ...d.pubsub_v1.types.Snapshot.LabelsEntry.yml | 44 + .../google.cloud.pubsub_v1.types.Snapshot.yml | 68 + ...ubsub_v1.types.SourceCodeInfo.Location.yml | 30 + ...e.cloud.pubsub_v1.types.SourceCodeInfo.yml | 36 + ...d.pubsub_v1.types.StreamingPullRequest.yml | 107 + ...ngPullResponse.AcknowledgeConfirmation.yml | 45 + ...Response.ModifyAckDeadlineConfirmation.yml | 42 + ...ingPullResponse.SubscriptionProperties.yml | 39 + ....pubsub_v1.types.StreamingPullResponse.yml | 66 + ...bsub_v1.types.Subscription.LabelsEntry.yml | 44 + ...oud.pubsub_v1.types.Subscription.State.yml | 40 + ...gle.cloud.pubsub_v1.types.Subscription.yml | 174 + ...sub_v1.types.TestIamPermissionsRequest.yml | 30 + ...ub_v1.types.TestIamPermissionsResponse.yml | 30 + ...google.cloud.pubsub_v1.types.Timestamp.yml | 33 + ...loud.pubsub_v1.types.Topic.LabelsEntry.yml | 44 + .../google.cloud.pubsub_v1.types.Topic.yml | 77 + ..._v1.types.UninterpretedOption.NamePart.yml | 30 + ...ud.pubsub_v1.types.UninterpretedOption.yml | 36 + ....pubsub_v1.types.UpdateSnapshotRequest.yml | 39 + ...sub_v1.types.UpdateSubscriptionRequest.yml | 40 + ...oud.pubsub_v1.types.UpdateTopicRequest.yml | 43 + .../google.cloud.pubsub_v1.types.yml | 562 +++ ...er.pagers.ListTopicSnapshotsAsyncPager.yml | 108 + ...blisher.pagers.ListTopicSnapshotsPager.yml | 106 + ...agers.ListTopicSubscriptionsAsyncPager.yml | 108 + ...her.pagers.ListTopicSubscriptionsPager.yml | 108 + ....publisher.pagers.ListTopicsAsyncPager.yml | 108 + ...vices.publisher.pagers.ListTopicsPager.yml | 106 + ...le.pubsub_v1.services.publisher.pagers.yml | 58 + ...scriber.pagers.ListSnapshotsAsyncPager.yml | 108 + ...s.subscriber.pagers.ListSnapshotsPager.yml | 106 + ...ber.pagers.ListSubscriptionsAsyncPager.yml | 108 + ...bscriber.pagers.ListSubscriptionsPager.yml | 106 + ...e.pubsub_v1.services.subscriber.pagers.yml | 46 + .../testdata/goldens/gapic-combo/index.md | 189 + .../goldens/gapic-combo/multiprocessing.md | 7 + .../testdata/goldens/gapic-combo/toc.yml | 345 ++ .../testdata/goldens/gapic-combo/upgrading.md | 201 + .../testdata/goldens/handwritten/changelog.md | 1377 ++++++ .../google.cloud.storage.acl.ACL.yml | 786 +++ .../google.cloud.storage.acl.BucketACL.yml | 155 + ...gle.cloud.storage.acl.DefaultObjectACL.yml | 35 + .../google.cloud.storage.acl.ObjectACL.yml | 155 + .../handwritten/google.cloud.storage.acl.yml | 50 + .../google.cloud.storage.batch.Batch.yml | 101 + ...loud.storage.batch.MIMEApplicationHTTP.yml | 113 + .../google.cloud.storage.batch.yml | 41 + .../google.cloud.storage.blob.Blob.yml | 3527 +++++++++++++ .../handwritten/google.cloud.storage.blob.yml | 32 + .../google.cloud.storage.bucket.Bucket.yml | 3266 ++++++++++++ ....cloud.storage.bucket.IAMConfiguration.yml | 591 +++ ...ycleRuleAbortIncompleteMultipartUpload.yml | 393 ++ ...storage.bucket.LifecycleRuleConditions.yml | 777 +++ ...oud.storage.bucket.LifecycleRuleDelete.yml | 385 ++ ...ge.bucket.LifecycleRuleSetStorageClass.yml | 393 ++ .../google.cloud.storage.bucket.yml | 62 + .../google.cloud.storage.client.Client.yml | 1069 ++++ .../google.cloud.storage.client.yml | 32 + .../google.cloud.storage.constants.yml | 26 + ...google.cloud.storage.fileio.BlobReader.yml | 330 ++ ...google.cloud.storage.fileio.BlobWriter.yml | 320 ++ ...gle.cloud.storage.fileio.SlidingBuffer.yml | 248 + .../google.cloud.storage.fileio.yml | 44 + ...cloud.storage.hmac_key.HMACKeyMetadata.yml | 606 +++ .../google.cloud.storage.hmac_key.yml | 36 + ...torage.notification.BucketNotification.yml | 679 +++ .../google.cloud.storage.notification.yml | 36 + ...d.storage.retry.ConditionalRetryPolicy.yml | 61 + .../google.cloud.storage.retry.yml | 156 + .../testdata/goldens/handwritten/index.md | 87 + .../testdata/goldens/handwritten/toc.yml | 95 + .../tests/testdata/handwritten/CHANGELOG.md | 932 ++++ .../tests/testdata/handwritten/README.rst | 107 + .../testdata/handwritten/docs/README.rst | 1 + .../handwritten/docs/_static/custom.css | 20 + .../handwritten/docs/_templates/layout.html | 50 + .../testdata/handwritten/docs/changelog.md | 1 + .../tests/testdata/handwritten/docs/conf.py | 385 ++ .../tests/testdata/handwritten/docs/index.rst | 31 + .../testdata/handwritten/docs/storage/acl.rst | 89 + .../handwritten/docs/storage/batch.rst | 6 + .../handwritten/docs/storage/blobs.rst | 7 + .../handwritten/docs/storage/buckets.rst | 7 + .../handwritten/docs/storage/client.rst | 6 + .../handwritten/docs/storage/constants.rst | 7 + .../handwritten/docs/storage/fileio.rst | 6 + .../storage/generation_metageneration.rst | 167 + .../handwritten/docs/storage/hmac_key.rst | 6 + .../handwritten/docs/storage/modules.rst | 17 + .../handwritten/docs/storage/notification.rst | 6 + .../handwritten/docs/storage/retry.rst | 6 + .../docs/storage/retry_timeout.rst | 159 + .../handwritten/docs/storage/snippets.py | 316 ++ .../testdata/handwritten/google/__init__.py | 22 + .../handwritten/google/cloud/__init__.py | 22 + .../google/cloud/storage/__init__.py | 41 + .../google/cloud/storage/_helpers.py | 614 +++ .../handwritten/google/cloud/storage/_http.py | 72 + .../google/cloud/storage/_signing.py | 720 +++ .../handwritten/google/cloud/storage/acl.py | 750 +++ .../handwritten/google/cloud/storage/batch.py | 339 ++ .../handwritten/google/cloud/storage/blob.py | 4389 +++++++++++++++++ .../google/cloud/storage/bucket.py | 3309 +++++++++++++ .../google/cloud/storage/client.py | 1701 +++++++ .../google/cloud/storage/constants.py | 134 + .../google/cloud/storage/fileio.py | 546 ++ .../google/cloud/storage/hmac_key.py | 301 ++ .../handwritten/google/cloud/storage/iam.py | 86 + .../google/cloud/storage/notification.py | 446 ++ .../handwritten/google/cloud/storage/retry.py | 169 + .../google/cloud/storage/transfer_manager.py | 557 +++ .../google/cloud/storage/version.py} | 5 +- .../tests/testdata/handwritten/setup.cfg | 19 + .../tests/testdata/handwritten/setup.py | 95 + packages/gcp-sphinx-docfx-yaml/tox.ini | 33 +- 444 files changed, 92518 insertions(+), 1997 deletions(-) delete mode 100644 packages/gcp-sphinx-docfx-yaml/appveyor.yml delete mode 100644 packages/gcp-sphinx-docfx-yaml/debug.py delete mode 100644 packages/gcp-sphinx-docfx-yaml/old_appveyor.yml rename packages/gcp-sphinx-docfx-yaml/{readthedocs.yml => tests/conftest.py} (62%) delete mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/conflict/foo.py delete mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/doc/conf.py delete mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/doc/format.google.rst delete mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/doc/format.numpy.rst delete mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/doc/format.rst delete mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/doc/format.rst.rst delete mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.native.native_foo.rst delete mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.pkg_resources.pkg_resources_foo.rst delete mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.pkg_resources.rst delete mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.pkgutil.pkgutil_foo.rst delete mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.pkgutil.rst delete mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.rst delete mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/format/google/foo.py delete mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/format/numpy/foo.py delete mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/format/rst/directives.py delete mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/format/rst/foo.py delete mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/native/__init__.pyi delete mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/pkg_resources/__init__.py delete mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/pkgutil/__init__.py delete mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/setup.cfg delete mode 100644 packages/gcp-sphinx-docfx-yaml/tests/example/setup.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/test_goldens.py delete mode 100644 packages/gcp-sphinx-docfx-yaml/tests/test_yaml.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/CHANGELOG.md create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/README.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/UPGRADING.md create mode 120000 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/README.rst create mode 120000 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/UPGRADING.md create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/_static/custom.css create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/_templates/layout.html create mode 120000 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/changelog.md create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/conf.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/index.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/multiprocessing.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/texttospeech_v1/services.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/texttospeech_v1/text_to_speech.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/texttospeech_v1/types.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/texttospeech_v1beta1/services.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/texttospeech_v1beta1/text_to_speech.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/texttospeech_v1beta1/types.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech/__init__.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech/py.typed create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/__init__.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/gapic_metadata.json create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/py.typed rename packages/gcp-sphinx-docfx-yaml/tests/{example/nspkg => testdata/gapic-auto/google/cloud/texttospeech_v1/services}/__init__.py (77%) create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/__init__.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/async_client.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/transports/__init__.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/transports/base.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/transports/grpc.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/transports/grpc_asyncio.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/__init__.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/__init__.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/gapic_metadata.json create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/py.typed rename packages/gcp-sphinx-docfx-yaml/tests/{example/nspkg/pkg_resources/pkg_resources_foo => testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services}/__init__.py (76%) create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/__init__.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/async_client.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/transports/__init__.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/transports/base.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/transports/grpc.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/transports/grpc_asyncio.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/__init__.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py create mode 100755 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/scripts/decrypt-secrets.sh create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/scripts/fixup_keywords.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/scripts/fixup_texttospeech_v1_keywords.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/scripts/fixup_texttospeech_v1beta1_keywords.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/scripts/readme-gen/readme_gen.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/scripts/readme-gen/templates/README.tmpl.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/scripts/readme-gen/templates/auth.tmpl.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/scripts/readme-gen/templates/auth_api_key.tmpl.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/scripts/readme-gen/templates/install_deps.tmpl.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/scripts/readme-gen/templates/install_portaudio.tmpl.rst rename packages/gcp-sphinx-docfx-yaml/tests/{example/format/numpy/__init__.py => testdata/gapic-auto/setup.cfg} (74%) create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/setup.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/CHANGELOG.md create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/README.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/UPGRADING.md create mode 120000 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/README.rst create mode 120000 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/UPGRADING.md create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/_static/custom.css create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/_templates/layout.html create mode 120000 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/changelog.md create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/conf.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/index.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/multiprocessing.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/pubsub/publisher/api/client.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/pubsub/publisher/api/futures.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/pubsub/publisher/api/pagers.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/pubsub/publisher/index.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/pubsub/subscriber/api/client.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/pubsub/subscriber/api/futures.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/pubsub/subscriber/api/message.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/pubsub/subscriber/api/pagers.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/pubsub/subscriber/api/scheduler.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/pubsub/subscriber/index.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/pubsub/types.rst rename packages/gcp-sphinx-docfx-yaml/tests/{example/format/rst => testdata/gapic-combo/google}/__init__.py (64%) rename packages/gcp-sphinx-docfx-yaml/tests/{example/format/rst/enum.py => testdata/gapic-combo/google/cloud/__init__.py} (60%) rename packages/gcp-sphinx-docfx-yaml/{prospector.yml => tests/testdata/gapic-combo/google/cloud/pubsub/__init__.py} (53%) create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/__init__.py rename packages/gcp-sphinx-docfx-yaml/tests/{example/conflict/__init__.py => testdata/gapic-combo/google/cloud/pubsub_v1/exceptions.py} (70%) create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/futures.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/proto/pubsub.proto create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/proto/schema.proto rename packages/gcp-sphinx-docfx-yaml/tests/{example/nspkg/pkgutil/pkgutil_foo => testdata/gapic-combo/google/cloud/pubsub_v1/publisher}/__init__.py (69%) rename packages/gcp-sphinx-docfx-yaml/tests/{example/doc/index.rst => testdata/gapic-combo/google/cloud/pubsub_v1/publisher/_batch/__init__.py} (100%) create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/_batch/base.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/_batch/thread.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/_sequencer/__init__.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/_sequencer/base.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/_sequencer/ordered_sequencer.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/_sequencer/unordered_sequencer.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/client.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/exceptions.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/flow_controller.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/futures.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/__init__.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/_protocol/__init__.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/_protocol/dispatcher.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/_protocol/heartbeater.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/_protocol/helper_threads.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/_protocol/histogram.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/_protocol/leaser.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/_protocol/messages_on_hold.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/_protocol/requests.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/_protocol/streaming_pull_manager.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/client.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/exceptions.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/futures.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/message.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/scheduler.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/types.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub/__init__.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub/py.typed create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/__init__.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/gapic_metadata.json create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/py.typed rename packages/gcp-sphinx-docfx-yaml/tests/{example/nspkg/native/native_foo => testdata/gapic-combo/google/pubsub_v1/services}/__init__.py (76%) rename packages/gcp-sphinx-docfx-yaml/tests/{example/format => testdata/gapic-combo/google/pubsub_v1/services/publisher}/__init__.py (66%) create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/async_client.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/pagers.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/transports/__init__.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/transports/base.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/transports/grpc.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/transports/grpc_asyncio.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/schema_service/__init__.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/schema_service/async_client.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/schema_service/client.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/schema_service/pagers.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/schema_service/transports/__init__.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/schema_service/transports/base.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/schema_service/transports/grpc.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/schema_service/transports/grpc_asyncio.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/__init__.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/async_client.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/pagers.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/transports/__init__.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/transports/base.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/transports/grpc.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/transports/grpc_asyncio.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/types/__init__.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/types/pubsub.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/types/schema.py create mode 100755 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/scripts/decrypt-secrets.sh create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/scripts/fixup_pubsub_v1_keywords.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/scripts/readme-gen/readme_gen.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/scripts/readme-gen/templates/README.tmpl.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/scripts/readme-gen/templates/auth.tmpl.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/scripts/readme-gen/templates/auth_api_key.tmpl.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/scripts/readme-gen/templates/install_deps.tmpl.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/scripts/readme-gen/templates/install_portaudio.tmpl.rst rename packages/gcp-sphinx-docfx-yaml/tests/{example/format/google/__init__.py => testdata/gapic-combo/setup.cfg} (74%) create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/setup.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/changelog.md create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.services.text_to_speech.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.AudioConfig.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.AudioEncoding.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.CustomVoiceParams.ReportedUsage.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.CustomVoiceParams.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.ListVoicesRequest.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.ListVoicesResponse.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.SsmlVoiceGender.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.SynthesisInput.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.SynthesizeSpeechRequest.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.SynthesizeSpeechResponse.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.Voice.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.VoiceSelectionParams.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.services.text_to_speech.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.AudioConfig.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.AudioEncoding.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.CustomVoiceParams.ReportedUsage.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.CustomVoiceParams.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.ListVoicesRequest.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.ListVoicesResponse.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.SsmlVoiceGender.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.SynthesisInput.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechRequest.TimepointType.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechRequest.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechResponse.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.Timepoint.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.Voice.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.VoiceSelectionParams.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/index.md create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/multiprocessing.md create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/toc.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/upgrading.md create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/changelog.md create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.publisher.client.Client.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.publisher.client.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.publisher.futures.Future.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.publisher.futures.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.subscriber.client.Client.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.subscriber.client.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.subscriber.futures.Future.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.subscriber.futures.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.subscriber.message.Message.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.subscriber.scheduler.Scheduler.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.subscriber.scheduler.ThreadScheduler.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.subscriber.scheduler.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.AcknowledgeRequest.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.AuditConfig.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.AuditConfigDelta.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.AuditData.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.AuditLogConfig.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.BatchSettings.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.BigQueryConfig.State.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.BigQueryConfig.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Binding.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.BindingDelta.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.CreateSnapshotRequest.LabelsEntry.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.CreateSnapshotRequest.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.CustomHttpPattern.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.DeadLetterPolicy.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.DeleteSnapshotRequest.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.DeleteSubscriptionRequest.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.DeleteTopicRequest.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.DescriptorProto.ExtensionRange.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.DescriptorProto.ReservedRange.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.DescriptorProto.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.DetachSubscriptionRequest.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.DetachSubscriptionResponse.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Duration.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Empty.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.EnumDescriptorProto.EnumReservedRange.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.EnumDescriptorProto.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.EnumOptions.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.EnumValueDescriptorProto.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.EnumValueOptions.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ExpirationPolicy.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ExtensionRangeOptions.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.FieldDescriptorProto.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.FieldMask.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.FieldOptions.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.FileDescriptorProto.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.FileDescriptorSet.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.FileOptions.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.FlowControl.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.GeneratedCodeInfo.Annotation.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.GeneratedCodeInfo.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.GetIamPolicyRequest.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.GetSnapshotRequest.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.GetSubscriptionRequest.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.GetTopicRequest.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Http.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.HttpRule.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.LimitExceededBehavior.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ListSnapshotsRequest.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ListSnapshotsResponse.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ListSubscriptionsRequest.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ListSubscriptionsResponse.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ListTopicSnapshotsRequest.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ListTopicSnapshotsResponse.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ListTopicSubscriptionsRequest.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ListTopicSubscriptionsResponse.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ListTopicsRequest.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ListTopicsResponse.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.MessageOptions.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.MessageStoragePolicy.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.MethodDescriptorProto.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.MethodOptions.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ModifyAckDeadlineRequest.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ModifyPushConfigRequest.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.OneofDescriptorProto.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.OneofOptions.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Policy.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PolicyDelta.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PublishFlowControl.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PublishRequest.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PublishResponse.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PublisherOptions.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PubsubMessage.AttributesEntry.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PubsubMessage.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PullRequest.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PullResponse.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PushConfig.AttributesEntry.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PushConfig.OidcToken.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PushConfig.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ReceivedMessage.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.RetryPolicy.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.SchemaSettings.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.SeekRequest.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.SeekResponse.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ServiceDescriptorProto.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ServiceOptions.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.SetIamPolicyRequest.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Snapshot.LabelsEntry.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Snapshot.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.SourceCodeInfo.Location.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.SourceCodeInfo.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.StreamingPullRequest.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.StreamingPullResponse.AcknowledgeConfirmation.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.StreamingPullResponse.ModifyAckDeadlineConfirmation.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.StreamingPullResponse.SubscriptionProperties.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.StreamingPullResponse.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Subscription.LabelsEntry.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Subscription.State.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Subscription.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.TestIamPermissionsRequest.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.TestIamPermissionsResponse.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Timestamp.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Topic.LabelsEntry.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Topic.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.UninterpretedOption.NamePart.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.UninterpretedOption.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.UpdateSnapshotRequest.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.UpdateSubscriptionRequest.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.UpdateTopicRequest.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.publisher.pagers.ListTopicSnapshotsAsyncPager.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.publisher.pagers.ListTopicSnapshotsPager.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.publisher.pagers.ListTopicSubscriptionsAsyncPager.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.publisher.pagers.ListTopicSubscriptionsPager.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.publisher.pagers.ListTopicsAsyncPager.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.publisher.pagers.ListTopicsPager.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.publisher.pagers.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.subscriber.pagers.ListSnapshotsAsyncPager.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.subscriber.pagers.ListSnapshotsPager.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.subscriber.pagers.ListSubscriptionsAsyncPager.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.subscriber.pagers.ListSubscriptionsPager.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.subscriber.pagers.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/index.md create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/multiprocessing.md create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/toc.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/upgrading.md create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/changelog.md create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.acl.ACL.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.acl.BucketACL.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.acl.DefaultObjectACL.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.acl.ObjectACL.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.acl.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.batch.Batch.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.batch.MIMEApplicationHTTP.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.batch.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.blob.Blob.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.blob.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.bucket.Bucket.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.bucket.IAMConfiguration.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.bucket.LifecycleRuleConditions.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.bucket.LifecycleRuleDelete.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.bucket.LifecycleRuleSetStorageClass.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.bucket.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.client.Client.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.client.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.constants.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.fileio.BlobReader.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.fileio.BlobWriter.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.fileio.SlidingBuffer.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.fileio.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.hmac_key.HMACKeyMetadata.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.hmac_key.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.notification.BucketNotification.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.notification.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.retry.ConditionalRetryPolicy.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.retry.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/index.md create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/toc.yml create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/CHANGELOG.md create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/README.rst create mode 120000 packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/README.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/_static/custom.css create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/_templates/layout.html create mode 120000 packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/changelog.md create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/conf.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/index.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/acl.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/batch.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/blobs.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/buckets.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/client.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/constants.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/fileio.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/generation_metageneration.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/hmac_key.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/modules.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/notification.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/retry.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/retry_timeout.rst create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/snippets.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/__init__.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/__init__.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/__init__.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/_helpers.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/_http.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/_signing.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/acl.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/batch.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/blob.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/bucket.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/client.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/constants.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/fileio.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/hmac_key.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/iam.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/notification.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/retry.py create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/transfer_manager.py rename packages/gcp-sphinx-docfx-yaml/tests/{__init__.py => testdata/handwritten/google/cloud/storage/version.py} (83%) create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/setup.cfg create mode 100644 packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/setup.py diff --git a/packages/gcp-sphinx-docfx-yaml/.github/workflows/ci.yaml b/packages/gcp-sphinx-docfx-yaml/.github/workflows/ci.yaml index a91fac013fce..8ed5a863a138 100644 --- a/packages/gcp-sphinx-docfx-yaml/.github/workflows/ci.yaml +++ b/packages/gcp-sphinx-docfx-yaml/.github/workflows/ci.yaml @@ -1,4 +1,4 @@ -name: ci +name: Presubmit tests on: [push] @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [3.7, 3.8, 3.9] + python-version: [3.9] steps: - uses: actions/checkout@v3 @@ -21,11 +21,5 @@ jobs: pip install tox - name: Run tests run: | - tox -e docs - - name: Run unittest - run: | - tox -e unittest - - name: Run librarytest - run: | - tox -e librarytest + tox -e tests diff --git a/packages/gcp-sphinx-docfx-yaml/.gitignore b/packages/gcp-sphinx-docfx-yaml/.gitignore index 53aa75199a50..dd0c769fb53a 100644 --- a/packages/gcp-sphinx-docfx-yaml/.gitignore +++ b/packages/gcp-sphinx-docfx-yaml/.gitignore @@ -46,6 +46,7 @@ pip-log.txt # Built documentation docs/_build +tests/testdata/*/docs/_build bigquery/docs/generated docs.metadata diff --git a/packages/gcp-sphinx-docfx-yaml/appveyor.yml b/packages/gcp-sphinx-docfx-yaml/appveyor.yml deleted file mode 100644 index 93653f855b20..000000000000 --- a/packages/gcp-sphinx-docfx-yaml/appveyor.yml +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright 2021 Google LLC -# -# 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. - -environment: - matrix: - - PYTHON: "C:/Python27" - -clone_folder: c:\projects\sphinx-docfx-yaml - -install: - # Nuget - - nuget install uref -Source https://www.myget.org/F/docfx/api/v3/index.json -ExcludeVersion -OutputDirectory c:\projects - - nuget install docfx.console -Source https://www.myget.org/F/docfx/api/v3/index.json -ExcludeVersion -OutputDirectory c:\projects - # Python - - ps: (new-object net.webclient).DownloadFile('https://bootstrap.pypa.io/get-pip.py', 'C:/get-pip.py') - - "%PYTHON%/python.exe C:/get-pip.py" - - "%PYTHON%/Scripts/pip.exe --version" - - "%PYTHON%/Scripts/pip.exe -q -q -q install tox sphinx msrest msrestazure sphinx_rtd_theme ." - -build_script: - - cd c:\projects\sphinx-docfx-yaml\docs - - "git clone https://github.com/ericholscher/azure-sdk-for-python/" - - cd azure-sdk-for-python - - python setup.py -q install - - cd doc - - "%PYTHON%/Scripts/sphinx-build.exe -b html -d _build/doctrees . _build/html" - - c:\projects\docfx.console\tools\docfx.exe build -t c:\projects\uref\content - -artifacts: - - path: 'docs/azure-sdk-for-python/doc/' diff --git a/packages/gcp-sphinx-docfx-yaml/debug.py b/packages/gcp-sphinx-docfx-yaml/debug.py deleted file mode 100644 index 48efa2b282de..000000000000 --- a/packages/gcp-sphinx-docfx-yaml/debug.py +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright 2021 Google LLC -# -# 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. - -import os -import shutil -import unittest -from contextlib import contextmanager -from sphinx.application import Sphinx - -@contextmanager -def sphinx_build(test_dir): - os.chdir('tests/{0}'.format(test_dir)) - - try: - app = Sphinx( - srcdir='doc', - confdir='doc', - outdir='_build/yaml', - doctreedir='_build/.doctrees', - buildername='html', - ) - app.build(force_all=True) - yield - finally: - # shutil.rmtree('_build') - os.chdir('../..') - -if __name__ == '__main__': - with sphinx_build('example'): - print('Debug finished.') diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/markdown_utils.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/markdown_utils.py index 0acf5c3ca8c2..d064feec4b52 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/markdown_utils.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/markdown_utils.py @@ -259,6 +259,9 @@ def move_markdown_pages(app: sphinx.application, outdir: Path) -> None: print("There's no markdown file to move.") return + # Used to keep track of the index page entry to insert later. + index_page_entry = None + # For each file, if it is a markdown file move to the top level pages. for mdfile in markdown_dir.iterdir(): if mdfile.is_file() and mdfile.name.lower() not in files_to_ignore: @@ -291,11 +294,11 @@ def move_markdown_pages(app: sphinx.application, outdir: Path) -> None: # Use Overview as the name for index file. if mdfile_name_to_use == 'index.md': - # Place the Overview page at the top of the list. - app.env.markdown_pages.insert( - 0, - {'name':'Overview', 'href': 'index.md'} - ) + # Save the index page entry. + index_page_entry = { + 'name': 'Overview', + 'href': 'index.md' + } continue # Add the file to the TOC later. @@ -304,6 +307,22 @@ def move_markdown_pages(app: sphinx.application, outdir: Path) -> None: 'href': mdfile_name_to_use, }) + if app.env.markdown_pages: + # Sort the TOC alphabetically based on href entry. + app.env.markdown_pages = sorted( + app.env.markdown_pages, + key=lambda entry: entry['href'], + ) + + if index_page_entry is None: + return + + # Place the Overview page at the top of the list. + app.env.markdown_pages.insert( + 0, + index_page_entry, + ) + def run_sphinx_markdown() -> None: """Runs sphinx-build with Markdown builder in the plugin.""" diff --git a/packages/gcp-sphinx-docfx-yaml/old_appveyor.yml b/packages/gcp-sphinx-docfx-yaml/old_appveyor.yml deleted file mode 100644 index 05a85f6ba8f6..000000000000 --- a/packages/gcp-sphinx-docfx-yaml/old_appveyor.yml +++ /dev/null @@ -1,57 +0,0 @@ -# Copyright 2021 Google LLC -# -# 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. - -build: false -before_build: - - nuget restore -environment: - matrix: - - PYTHON: "C:/Python27" -install: - - ps: (new-object net.webclient).DownloadFile('https://bootstrap.pypa.io/get-pip.py', 'C:/get-pip.py') - - "%PYTHON%/python.exe C:/get-pip.py" - - "%PYTHON%/Scripts/pip.exe --version" - - "%PYTHON%/Scripts/pip.exe install tox" -test_script: - - "docfx init -q" - - "git clone https://github.com/aspnet/Identity %APPVEYOR_BUILD_FOLDER%/tests/dotnetexample/example/Identity" - - "%PYTHON%/Scripts/tox.exe -e py27" - - -# V2 - -environment: - matrix: - - PYTHON: "C:/Python27" - -clone_folder: c:\projects\sphinx-docfx-yaml - -install: - # .NET - - ps: (new-object net.webclient).DownloadFile('https://github.com/dotnet/docfx/releases/download/v2.10.2/docfx.zip', 'c:\projects\sphinx-docfx-yaml\docfx.zip') - - cd c:\projects\sphinx-docfx-yaml - - 7z e docfx.zip -oc:\projects\sphinx-docfx-yaml\docfx - # Python - - ps: (new-object net.webclient).DownloadFile('https://bootstrap.pypa.io/get-pip.py', 'C:/get-pip.py') - - "%PYTHON%/python.exe C:/get-pip.py" - - "%PYTHON%/Scripts/pip.exe --version" - - "%PYTHON%/Scripts/pip.exe install tox sphinx sphinx_rtd_theme ." - -build_script: - - cd c:\projects\sphinx-docfx-yaml\docs - - "%PYTHON%/Scripts/sphinx-build.exe -b html -d _build/doctrees . _build/html" - - ..\docfx\docfx.exe build - -artifacts: - - path: 'docs' diff --git a/packages/gcp-sphinx-docfx-yaml/requirements.txt b/packages/gcp-sphinx-docfx-yaml/requirements.txt index 620b4c77c050..27731eaee91a 100644 --- a/packages/gcp-sphinx-docfx-yaml/requirements.txt +++ b/packages/gcp-sphinx-docfx-yaml/requirements.txt @@ -1,7 +1,15 @@ +# Install Sphinx plugin +-e . + +# Tox specific dependencies +tox +mock +pytest + +# Other dependencies black==22.10.0 parameterized==0.8.1 # google-resumable-media-python requires manual update as this repo isn't templated. # python-api-core also requires manual update as it is not templated. sphinx==4.5.0 -e . -tox diff --git a/packages/gcp-sphinx-docfx-yaml/readthedocs.yml b/packages/gcp-sphinx-docfx-yaml/tests/conftest.py similarity index 62% rename from packages/gcp-sphinx-docfx-yaml/readthedocs.yml rename to packages/gcp-sphinx-docfx-yaml/tests/conftest.py index 4966103142b9..c10e6fc39db3 100644 --- a/packages/gcp-sphinx-docfx-yaml/readthedocs.yml +++ b/packages/gcp-sphinx-docfx-yaml/tests/conftest.py @@ -1,10 +1,10 @@ -# Copyright 2021 Google LLC +# Copyright 2022 Google LLC # # 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 +# https://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, @@ -12,11 +12,13 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Don't build any extra formats +import pytest -formats: - - none -python: - version: 3 - setup_py_install: true +def pytest_addoption(parser): + parser.addoption("--update-goldens", action="store", default=False) + + +@pytest.fixture +def update_goldens(request): + return request.config.getoption("--update-goldens") diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/conflict/foo.py b/packages/gcp-sphinx-docfx-yaml/tests/example/conflict/foo.py deleted file mode 100644 index 46a7ebb6d971..000000000000 --- a/packages/gcp-sphinx-docfx-yaml/tests/example/conflict/foo.py +++ /dev/null @@ -1,203 +0,0 @@ -# Copyright 2021 Google LLC -# -# 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. - -# coding: utf-8 - -""" Docstring of :mod:`conflict.foo` module. -""" - -foo_var = [] -""" Docstring of module variable :any:`conflict.foo.foo_var`.""" - - -def function(arg1, arg2, arg3, arg4): - """ Docstring of :func:`conflict.foo.function` function. - - :param int arg1: Parameter arg1 of :func:`~conflict.foo.function`. - :param float arg2: Parameter arg2 of :func:`~conflict.foo.function`. - :param boolean arg3: Parameter arg3 of :func:`~conflict.foo.function`. - :param str arg4: Parameter arg4 of :func:`~conflict.foo.function`. - """ - pass - - -class Foo(object): - """ Docstring of :class:`conflict.foo.Foo` class in rst format. - - :var attr: Docstring of :class:`conflict.foo.Foo.attr` from class docstring. - :vartype attr: ~conflict.enum.EnumFoo - - :param init_arg1: Parameter init_arg1 from class docstring. - :type init_arg1: float - :param list[int] init_arg2: Parameter init_arg2 from class docstring. - """ - - attr = 1 - """ Docstring of :class:`conflict.foo.Foo.attr` from attrbute docstring.""" - - def __init__(self, init_arg1, init_arg2): - """ Docstring of constructor of Foo. Will not be shown. - - :param init_arg1: Parameter init_arg1 from constructor's docstring. - :type init_arg1: float - :param list[int] init_arg2: Parameter init_arg2 from constructor's docstring. - """ - - @property - def attr_getter(self): - """ Docstring of :meth:`conflict.foo.Foo.attr_getter` @property. - """ - return self.attr - - @classmethod - def class_method(cls, arg1): - """ Docstring of :class:`conflict.foo.Foo.class_method` @classmethod. - - :param cls: Class object of :class:`conflict.foo.Foo`. - :type cls: class - :param str arg1: Parameter arg1 of :meth:`conflict.foo.Foo.class_method`. - """ - pass - - @staticmethod - def static_method(): - """ Docstring of :meth:`conflict.foo.Foo.static_method` @staticmethod. - """ - pass - - def method(self): - """ Docstring of normal class method :meth:`conflict.foo.Foo.method`. - """ - pass - - def method_return(self): - """ Docstring of :meth:`conflict.foo.Foo.method_return`. - - :return: This method returns a value. - :rtype: boolean - """ - return False - - def method_multiline(self): - """ Docstring of :meth:`conflict.foo.Foo.method_multiline`. - This docstring has multiple lines of contents. - And this should work perfectly. - """ - pass - - def method_exception(self): - """ Docstring of :meth:`conflict.foo.Foo.method_exception`. - - :raises: :class:`Exception` This function raises - exception. - """ - raise Exception() - - def method_external_link(self): - """ Docstring of :meth:`conflict.foo.Foo.method_external_link`. - Inline link should be transformed to markdown: `Link Text `_. - And seperated link will fail: `Seperated Link`_ - - .. _Seperated Link: http://seperated.external.link - """ - pass - - def method_seealso(self): - """ Docstring of :meth:`conflict.foo.Foo.method_seealso`. - - .. seealso:: - Seealso contents. - Multi-line should be supported. - And reference to :class:`conflict.foo.Foo` should be okay. - """ - pass - - def method_note(self): - """ Docstring of :meth:`conflict.foo.Foo.method_note`. - - .. note:: - This is content of note. - Another line of note contents. - """ - pass - - def method_warning(self): - """ Docstring of :meth:`conflict.foo.Foo.method_warning`. - - .. warning:: - This is content of warning. - """ - pass - - def method_code(self): - """ Docstring of :meth:`conflict.foo.Foo.method_code`. - - .. code-block:: python - - >>> import numpy as np - >>> a = np.ndarray([1,2,3,4,5]) - - Another way of code block:: - - import numpy as np - b = np.random.random(10) - """ - pass - - def method_example(self): - """ Docstring of :meth:`conflict.foo.Foo.method_example`. - - .. admonition:: - This is Example content. - Should support multi-line. - Can also include file: - - .. literalinclude:: ../format/rst/enum.py - """ - pass - - def method_default_value(self, arg1='default string', arg2=None): - """ Docstring of :meth:`conflict.foo.Foo.method_default_value`. - - :param str arg1: Parameter arg1 of :meth:`conflict.foo.Foo.method_default_value`, default value is 'default string'. - :param object arg2: Paremeter arg2 of :meth:`conflict.foo.Foo.method_default_value` default value is None. - """ - pass - - def method_default_value_comma(self, arg1=(1,2,3)): - """ Docstring of :meth:`conflict.foo.Foo.method_default_value_comma`. - The default value of method parameter contains comma thus will fail to parse. - - :param tuple arg1: Parameter arg1 of :meth:`conflict.foo.Foo.method_default_value_comma`, default value is (1,2,3). - """ - pass - - def snapshot(self, **kw): - """Create a snapshot to perform a set of reads with shared staleness. - - See - https://cloud.google.com/spanner/reference/rpc/google.spanner.v1#google.spanner.v1.TransactionOptions.ReadOnly - - :type kw: dict - :param kw: Passed through to - :class:`~google.cloud.spanner_v1.snapshot.Snapshot` ctor. - - :rtype: :class:`~google.cloud.spanner_v1.snapshot.Snapshot` - :returns: a snapshot bound to this session - :raises ValueError: if the session has not yet been created. - """ - if self._session_id is None: - raise ValueError("Session has not been created.") - - return Snapshot(self, **kw) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/doc/conf.py b/packages/gcp-sphinx-docfx-yaml/tests/example/doc/conf.py deleted file mode 100644 index 5f118fa62c85..000000000000 --- a/packages/gcp-sphinx-docfx-yaml/tests/example/doc/conf.py +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright 2021 Google LLC -# -# 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. - -import sys -import os - -sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) - -source_suffix = '.rst' -master_doc = 'index' -project = u'example' -copyright = u'2018, Microsoft' -author = u'Yiding Tian' -version = '0.1' -release = '0.1' -language = None -exclude_patterns = ['_build'] -pygments_style = 'sphinx' -todo_include_todos = False -html_theme = 'alabaster' -html_static_path = ['_static'] -htmlhelp_basename = 'Example Document' -extensions = [ - 'sphinx.ext.autodoc', - 'sphinx.ext.napoleon', - 'sphinx.ext.intersphinx', - 'docfx_yaml.extension' -] -intersphinx_mapping = {'python': ('https://docs.python.org/3.6', None)} diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/doc/format.google.rst b/packages/gcp-sphinx-docfx-yaml/tests/example/doc/format.google.rst deleted file mode 100644 index 61d4bde179b7..000000000000 --- a/packages/gcp-sphinx-docfx-yaml/tests/example/doc/format.google.rst +++ /dev/null @@ -1,22 +0,0 @@ -format\.google package -====================== - -Submodules ----------- - -format\.google\.foo module --------------------------- - -.. automodule:: format.google.foo - :members: - :undoc-members: - :show-inheritance: - - -Module contents ---------------- - -.. automodule:: format.google - :members: - :undoc-members: - :show-inheritance: diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/doc/format.numpy.rst b/packages/gcp-sphinx-docfx-yaml/tests/example/doc/format.numpy.rst deleted file mode 100644 index f254b16908b7..000000000000 --- a/packages/gcp-sphinx-docfx-yaml/tests/example/doc/format.numpy.rst +++ /dev/null @@ -1,22 +0,0 @@ -format\.numpy package -===================== - -Submodules ----------- - -format\.numpy\.foo module -------------------------- - -.. automodule:: format.numpy.foo - :members: - :undoc-members: - :show-inheritance: - - -Module contents ---------------- - -.. automodule:: format.numpy - :members: - :undoc-members: - :show-inheritance: diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/doc/format.rst b/packages/gcp-sphinx-docfx-yaml/tests/example/doc/format.rst deleted file mode 100644 index fde29cdb7c98..000000000000 --- a/packages/gcp-sphinx-docfx-yaml/tests/example/doc/format.rst +++ /dev/null @@ -1,19 +0,0 @@ -format package -============== - -Subpackages ------------ - -.. toctree:: - - format.google - format.numpy - format.rst - -Module contents ---------------- - -.. automodule:: format - :members: - :undoc-members: - :show-inheritance: diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/doc/format.rst.rst b/packages/gcp-sphinx-docfx-yaml/tests/example/doc/format.rst.rst deleted file mode 100644 index fd7516a91412..000000000000 --- a/packages/gcp-sphinx-docfx-yaml/tests/example/doc/format.rst.rst +++ /dev/null @@ -1,38 +0,0 @@ -format\.rst package -=================== - -Submodules ----------- - -format\.rst\.directives module ------------------------------- - -.. automodule:: format.rst.directives - :members: - :undoc-members: - :show-inheritance: - -format\.rst\.enum module ------------------------- - -.. automodule:: format.rst.enum - :members: - :undoc-members: - :show-inheritance: - -format\.rst\.foo module ------------------------ - -.. automodule:: format.rst.foo - :members: - :undoc-members: - :show-inheritance: - - -Module contents ---------------- - -.. automodule:: format.rst - :members: - :undoc-members: - :show-inheritance: diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.native.native_foo.rst b/packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.native.native_foo.rst deleted file mode 100644 index 904c1defc1fd..000000000000 --- a/packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.native.native_foo.rst +++ /dev/null @@ -1,10 +0,0 @@ -nspkg\.native\.native\_foo package -================================== - -Module contents ---------------- - -.. automodule:: nspkg.native.native_foo - :members: - :undoc-members: - :show-inheritance: diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.pkg_resources.pkg_resources_foo.rst b/packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.pkg_resources.pkg_resources_foo.rst deleted file mode 100644 index ad10d564040b..000000000000 --- a/packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.pkg_resources.pkg_resources_foo.rst +++ /dev/null @@ -1,10 +0,0 @@ -nspkg\.pkg\_resources\.pkg\_resources\_foo package -================================================== - -Module contents ---------------- - -.. automodule:: nspkg.pkg_resources.pkg_resources_foo - :members: - :undoc-members: - :show-inheritance: diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.pkg_resources.rst b/packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.pkg_resources.rst deleted file mode 100644 index f72402973d3a..000000000000 --- a/packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.pkg_resources.rst +++ /dev/null @@ -1,17 +0,0 @@ -nspkg\.pkg\_resources package -============================= - -Subpackages ------------ - -.. toctree:: - - nspkg.pkg_resources.pkg_resources_foo - -Module contents ---------------- - -.. automodule:: nspkg.pkg_resources - :members: - :undoc-members: - :show-inheritance: diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.pkgutil.pkgutil_foo.rst b/packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.pkgutil.pkgutil_foo.rst deleted file mode 100644 index 60ec1af00c05..000000000000 --- a/packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.pkgutil.pkgutil_foo.rst +++ /dev/null @@ -1,10 +0,0 @@ -nspkg\.pkgutil\.pkgutil\_foo package -==================================== - -Module contents ---------------- - -.. automodule:: nspkg.pkgutil.pkgutil_foo - :members: - :undoc-members: - :show-inheritance: diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.pkgutil.rst b/packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.pkgutil.rst deleted file mode 100644 index 592411ee6476..000000000000 --- a/packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.pkgutil.rst +++ /dev/null @@ -1,17 +0,0 @@ -nspkg\.pkgutil package -====================== - -Subpackages ------------ - -.. toctree:: - - nspkg.pkgutil.pkgutil_foo - -Module contents ---------------- - -.. automodule:: nspkg.pkgutil - :members: - :undoc-members: - :show-inheritance: diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.rst b/packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.rst deleted file mode 100644 index 364d7680674f..000000000000 --- a/packages/gcp-sphinx-docfx-yaml/tests/example/doc/nspkg.rst +++ /dev/null @@ -1,18 +0,0 @@ -nspkg package -============= - -Subpackages ------------ - -.. toctree:: - - nspkg.pkg_resources - nspkg.pkgutil - -Module contents ---------------- - -.. automodule:: nspkg - :members: - :undoc-members: - :show-inheritance: diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/format/google/foo.py b/packages/gcp-sphinx-docfx-yaml/tests/example/format/google/foo.py deleted file mode 100644 index cd87600c86d8..000000000000 --- a/packages/gcp-sphinx-docfx-yaml/tests/example/format/google/foo.py +++ /dev/null @@ -1,183 +0,0 @@ -# Copyright 2021 Google LLC -# -# 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. - -# coding: utf-8 - -""" Docstring of :mod:`format.google.foo` module. -""" - -foo_var = [] -""" Docstring of module variable :any:`format.google.foo.foo_var`.""" - - -def function(arg1, arg2, arg3, arg4): - """ Docstring of :func:`format.google.foo.function` function. - - Args: - arg1 (int): Parameter arg1 of :func:`format.google.foo.function`. - arg2 (float): Parameter arg2 of :func:`format.google.foo.function`. - arg3 (boolean): Parameter arg3 of :func:`format.google.foo.function`. - arg4 (str): Parameter arg4 of :func:`format.google.foo.function`. - """ - pass - - -class Foo(object): - """ Docstring of :class:`format.google.foo.Foo` class in google format. - - Testing for xref with new regex: :class:`google.spanner.v1.types.ExecuteSqlRequest.QueryMode` class. - - Attributes: - attr (:class:`~format.rst.enum.EnumFoo`): Docstring of :any:`format.google.foo.Foo.attr` from class docstring. - - Arguments: - init_arg1 (float): Parameter init_arg1 from class docstring. - init_arg2 (list[int]): Parameter init_arg2 from class docstring. - """ - - attr = 1 - """ Docstring of :any:`format.google.foo.Foo.attr` from attrbute docstring.""" - - def __init__(self, init_arg1, init_arg2): - """ Docstring of constructor of :class:`format.google.foo.Foo`. - - Parameters: - init_arg1 (float): Parameter init_arg1 from constructor's docstring. - init_arg2 (list[int]): Parameter init_arg2 from constructor's docstring. - """ - - @property - def attr_getter(self): - """ Docstring of :meth:`format.google.foo.Foo.attr_getter` @property. - """ - return self.attr - - @classmethod - def class_method(cls, arg1): - """ Docstring of :meth:`format.google.foo.Foo.class_method` @classmethod. - - Args: - cls (class): Class object of :class:`format.google.foo.Foo`. - arg1 (str): Parameter arg1 of :meth:`format.google.foo.Foo.class_method`. - """ - pass - - @staticmethod - def static_method(): - """ Docstring of :meth:`format.google.foo.Foo.static_method` @staticmethod. - """ - pass - - def method(self): - """ Docstring of normal class method :meth:`format.google.foo.Foo.method`. - """ - pass - - def method_return(self): - """ Docstring of :meth:`format.google.foo.Foo.method_return`. - - Return: - bool: This method returns a value. - """ - return False - - def method_multiline(self): - """ Docstring of :meth:`format.google.foo.Foo.method_multiline`. - This docstring has multiple lines of contents. - And this should work perfectly. - """ - pass - - def method_exception(self): - """ Docstring of :meth:`format.google.foo.Foo.method_exception`. - - Raises: - format.rst.foo.FooException: This function raises - exception. - """ - raise FooException() - - def method_external_link(self): - """ Docstring of :meth:`format.google.foo.Foo.method_external_link`. - Inline link should be transformed to markdown: `Link Text `_. - And seperated link will fail: `Seprated Link`_ - - .. _Seprated Link: http://seperated.external.link - """ - pass - - def method_seealso(self): - """ Docstring of :meth:`format.google.foo.Foo.method_seealso`. - - See Also: - Seealso contents. - Multi-line should be supported. - """ - pass - - def method_note(self): - """ Docstring of :meth:`format.google.foo.Foo.method_note`. - - Note: - This is content of note. - Another line of note contents. - """ - pass - - def method_warning(self): - """ Docstring of :meth:`format.google.foo.Foo.method_warning`. - - Warning: - This is content of warning. - """ - pass - - def method_code(self): - """ Docstring of :meth:`format.google.foo.Foo.method_code`. - - .. code-block:: python - - >>> import numpy as np - >>> a = np.ndarray([1,2,3,4,5]) - - Another way of code block:: - - >>> import numpy as np - >>> b = np.random.random(10) - """ - pass - - def method_example(self): - """ Docstring of :meth:`format.google.foo.Foo.method_example`. - - Example: - This is example content. - Should support multi-line. - Can also include file: - - .. literalinclude:: ../format/rst/enum.py - """ - pass - - -class FooException(Exception): - """ Docstring of :class:`format.google.foo.FooException`. - Another class of :mod:`format.google.foo` module. - """ - - class InternalFoo(object): - """ Docstring of internal class :class:`format.google.foo.FooException.InternalFoo`. - This class is an internal class of :class:`format.google.foo.FooException`. - """ - pass diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/format/numpy/foo.py b/packages/gcp-sphinx-docfx-yaml/tests/example/format/numpy/foo.py deleted file mode 100644 index 4a4606a95606..000000000000 --- a/packages/gcp-sphinx-docfx-yaml/tests/example/format/numpy/foo.py +++ /dev/null @@ -1,204 +0,0 @@ -# Copyright 2021 Google LLC -# -# 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. - -# coding: utf-8 - -""" Docstring of :mod:`format.numpy.foo` module. -""" - -foo_var = [] -""" Docstring of module variable :any:`format.numpy.foo.foo_var`.""" - - -def function(arg1, arg2, arg3, arg4): - """ Docstring of :func:`format.numpy.foo.function` function. - - Args - ---- - arg1 : int - Parameter arg1 of :func:`format.numpy.foo.function`. - arg2 : float - Parameter arg2 of :func:`format.numpy.foo.function`. - arg3 : boolean - Parameter arg3 of :func:`format.numpy.foo.function`. - arg4 : str - Parameter arg4 of :func:`format.numpy.foo.function`. - """ - pass - - -class Foo(object): - """ Docstring of :class:`format.numpy.foo.Foo` class in numpy format. - - Attributes - ---------- - attr : :class:`~format.rst.enum.EnumFoo` - Docstring of :any:`format.numpy.foo.Foo.attr` from class docstring. - - Arguments - --------- - init_arg1 : float - Parameter init_arg1 from class docstring. - init_arg2 : list[int] - Parameter init_arg2 from class docstring. - """ - - attr = 1 - """ Docstring of :any:`format.numpy.foo.Foo.attr` from attrbute docstring.""" - - def __init__(self, init_arg1, init_arg2): - """ Docstring of constructor of :class:`format.numpy.foo.Foo`. - - Parameters - ---------- - init_arg1 : float - Parameter init_arg1 from constructor's docstring. - init_arg2 : list[int] - Parameter init_arg2 from constructor's docstring. - """ - - @property - def attr_getter(self): - """ Docstring of :meth:`fomrmat.numpy.foo.Foo.attr_getter` @property. - """ - return self.attr - - @classmethod - def class_method(cls, arg1): - """ Docstring of :meth:`fomrmat.numpy.foo.Foo.class_method` @classmethod. - - Args - ---- - cls : class - Class object of :class:`format.numpy.foo.Foo`. - arg1 : str - Parameter arg1 of :meth:`fomrmat.numpy.foo.Foo.class_method`. - """ - pass - - @staticmethod - def static_method(): - """ Docstring of :meth:`fomrmat.numpy.foo.Foo.static_method @staticmethod`. - """ - pass - - def method(self): - """ Docstring of normal class method :meth:`fomrmat.numpy.foo.Foo.method`. - """ - pass - - def method_return(self): - """ Docstring of :meth:`fomrmat.numpy.foo.Foo.method_return`. - - Returns - ------- - bool - This method returns a value. - """ - return False - - def method_multiline(self): - """ Docstring of :meth:`fomrmat.numpy.foo.Foo.method_multiline`. - This docstring has multiple lines of contents. - And this should work perfectly. - """ - pass - - def method_exception(self): - """ Docstring of :meth:`fomrmat.numpy.foo.Foo.method_exception`. - - Raises - ------ - format.rst.foo.FooException - This function raises - exception. - """ - raise FooException() - - def method_external_link(self): - """ Docstring of :meth:`fomrmat.numpy.foo.Foo.method_external_link`. - Inline link should be transformed to markdown: `Link Text `_. - And seperated link will fail: `Seprated Link`_ - - .. _Seprated Link: http://seperated.external.link - """ - pass - - def method_seealso(self): - """ Docstring of :meth:`fomrmat.numpy.foo.Foo.method_seealso`. - - See Also - -------- - format.numpy.foo.Foo.mathod_note : See also target. - """ - pass - - def method_note(self): - """ Docstring of :meth:`fomrmat.numpy.foo.Foo.method_note`. - - Note - ---- - This is content of note. - Another line of note contents. - """ - pass - - def method_warning(self): - """ Docstring of :meth:`fomrmat.numpy.foo.Foo.method_warning`. - - Warning - ------- - This is content of warning. - """ - pass - - def method_code(self): - """ Docstring of :meth:`fomrmat.numpy.foo.Foo.method_code`. - - .. code-block:: python - - import numpy as np - a = np.ndarray([1,2,3,4,5]) - - Another way of code block:: - - import numpy as np - b = np.random.random(10) - """ - pass - - def method_example(self): - """ Docstring of :meth:`fomrmat.numpy.foo.Foo.method_example`. - - Examples - -------- - This is Example content. - Should support multi-line. - Can also include file: - - .. literalinclude:: ../format/rst/enum.py - """ - pass - - -class FooException(Exception): - """ Docstring of :class:`format.numpy.foo.FooException`. - Another class of :mod:`format.numpy.foo` module. - """ - - class InternalFoo(object): - """ Docstring of internal class :class:`format.numpy.foo.FooException.InternalFoo`. - This class is an internal class of :class:`format.numpy.foo.FooException`. - """ - pass diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/format/rst/directives.py b/packages/gcp-sphinx-docfx-yaml/tests/example/format/rst/directives.py deleted file mode 100644 index b2985d5d7727..000000000000 --- a/packages/gcp-sphinx-docfx-yaml/tests/example/format/rst/directives.py +++ /dev/null @@ -1,85 +0,0 @@ -# Copyright 2021 Google LLC -# -# 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. - -# coding: utf-8 - -""" Docstring of module :mod:`format.rst.directives`. -This module is used for testing self-defined directives. - -.. remarks:: Remarks from module directives. -""" - -module_var = '' -""".. remarks:: Remarks from module variable.""" - - -def func(): - """ - .. remarks:: Remarks from module function. - """ - pass - - -class DirectivesFoo(object): - """ Docstring of class :class:`format.rst.directives.DirectivesFoo`. - - .. note:: - Note content from class docstring. - Second line of note content. - many lines of content. - - .. warning:: - Warning message from class docstring. - Second line. - - .. tip:: - Tip content. :class:`format.rst.foo.Foo` - - .. important:: - Important content. - - .. caution:: - Caution content. - - .. remarks:: Remarks from class. - Multi-line content should be supported. - - .. note:: - Note conetnt under class remarks. - Second line of note content. - - .. warning:: - Warning content under class remarks. - Second line. - :class:`format.rst.foo.Foo` - - .. tip:: - Tip content. - - .. important:: - Important content. - - .. caution:: - Caution content. - """ - - var_remarks = '' - """ .. remarks:: Remarks from class attribute :class:`format.rst.directives.DirectivesFoo.var_remarks`.""" - - def method_remarks(self): - """ - .. remarks:: Remarks from class method :meth:`format.rst.directives.DirectivesFoo.method_remarks` - Another reference: :class:`format.rst.directives.DirectivesFoo` - """ - pass diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/format/rst/foo.py b/packages/gcp-sphinx-docfx-yaml/tests/example/format/rst/foo.py deleted file mode 100644 index fd79ea5a3600..000000000000 --- a/packages/gcp-sphinx-docfx-yaml/tests/example/format/rst/foo.py +++ /dev/null @@ -1,203 +0,0 @@ -# Copyright 2021 Google LLC -# -# 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. - -# coding: utf-8 - -""" Docstring of :mod:`format.rst.foo` module. -""" - -from .enum import EnumFoo - -foo_var = [] -""" Docstring of module variable :any:`format.rst.foo.foo_var`.""" - - -def function(arg1, arg2, arg3, arg4): - """ Docstring of :func:`format.rst.foo.function` function. - - :param int arg1: Parameter arg1 of :func:`~format.rst.foo.function`. - :param float arg2: Parameter arg2 of :func:`~format.rst.foo.function`. - :param boolean arg3: Parameter arg3 of :func:`~format.rst.foo.function`. - :param str arg4: Parameter arg4 of :func:`~format.rst.foo.function`. - """ - pass - - -class Foo(object): - """ Docstring of :class:`format.rst.foo.Foo` class in rst format. - - :var attr: Docstring of :class:`format.rst.foo.Foo.attr` from class docstring. - :vartype attr: ~format.rst.enum.EnumFoo - - :param init_arg1: Parameter init_arg1 from class docstring. - :type init_arg1: float - :param list[int] init_arg2: Parameter init_arg2 from class docstring. - """ - - attr = EnumFoo.VALUE1 - """ Docstring of :class:`format.rst.foo.Foo.attr` from attrbute docstring.""" - - def __init__(self, init_arg1, init_arg2): - """ Docstring of constructor of Foo. Will not be shown. - - :param init_arg1: Parameter init_arg1 from constructor's docstring. - :type init_arg1: float - :param list[int] init_arg2: Parameter init_arg2 from constructor's docstring. - """ - - @property - def attr_getter(self): - """ Docstring of :meth:`format.rst.foo.Foo.attr_getter` @property. - """ - return self.attr - - @classmethod - def class_method(cls, arg1): - """ Docstring of :class:`format.rst.foo.Foo.class_method` @classmethod. - - :param cls: Class object of :class:`format.rst.foo.Foo`. - :type cls: class - :param str arg1: Parameter arg1 of :meth:`format.rst.foo.Foo.class_method`. - """ - pass - - @staticmethod - def static_method(): - """ Docstring of :meth:`format.rst.foo.Foo.static_method` @staticmethod. - """ - pass - - def method(self): - """ Docstring of normal class method :meth:`format.rst.foo.Foo.method`. - """ - pass - - def method_return(self): - """ Docstring of :meth:`format.rst.foo.Foo.method_return`. - - :return: This method returns a value. - :rtype: boolean - """ - return False - - def method_multiline(self): - """ Docstring of :meth:`format.rst.foo.Foo.method_multiline`. - This docstring has multiple lines of contents. - And this should work perfectly. - """ - pass - - def method_exception(self): - """ Docstring of :meth:`format.rst.foo.Foo.method_exception`. - - :raises: :class:`format.rst.foo.FooException` This function raises - exception. - """ - raise FooException() - - def method_external_link(self): - """ Docstring of :meth:`format.rst.foo.Foo.method_external_link`. - Inline link should be transformed to markdown: `Link Text `_. - And seperated link will fail: `Seperated Link`_ - - .. _Seperated Link: http://seperated.external.link - """ - pass - - def method_seealso(self): - """ Docstring of :meth:`format.rst.foo.Foo.method_seealso`. - - .. seealso:: - Seealso contents. - Multi-line should be supported. - And reference to :class:`format.rst.foo.Foo` should be okay. - """ - pass - - def method_note(self): - """ Docstring of :meth:`format.rst.foo.Foo.method_note`. - - .. note:: - This is content of note. - Another line of note contents. - """ - pass - - def method_warning(self): - """ Docstring of :meth:`format.rst.foo.Foo.method_warning`. - - .. warning:: - This is content of warning. - """ - pass - - def method_code(self): - """ Docstring of :meth:`format.rst.foo.Foo.method_code`. - - .. code-block:: python - - >>> import numpy as np - >>> a = np.ndarray([1,2,3,4,5]) - - Another way of code block:: - - import numpy as np - b = np.random.random(10) - """ - pass - - def method_example(self): - """ Docstring of :meth:`format.rst.foo.Foo.method_example`. - - .. admonition:: - This is Example content. - Should support multi-line. - Can also include file: - - .. literalinclude:: ../format/rst/enum.py - """ - pass - - def method_default_value(self, arg1='default string', arg2=None): - """ Docstring of :meth:`format.rst.foo.Foo.method_default_value`. - - :param str arg1: Parameter arg1 of :meth:`format.rst.foo.Foo.method_default_value`, default value is 'default string'. - :param object arg2: Paremeter arg2 of :meth:`format.rst.foo.Foo.method_default_value` default value is None. - """ - pass - - def method_default_value_comma(self, arg1=(1,2,3)): - """ Docstring of :meth:`format.rst.foo.Foo.method_default_value_comma`. - The default value of method parameter contains comma thus will fail to parse. - - :param tuple arg1: Parameter arg1 of :meth:`format.rst.foo.Foo.method_default_value_comma`, default value is (1,2,3). - """ - pass - -class FooException(Exception): - """ Docstring of :class:`format.rst.foo.FooException`. - Another class of :mod:`format.rst.foo` module. - """ - - class InternalFoo(object): - """ Docstring of internal class :class:`format.rst.foo.FooException.InternalFoo`. - This class is an internal class of :class:`format.rst.foo.FooException`. - """ - pass - -class InheritFoo(Foo, dict): - """ Docstring of :class:`format.rst.foo.InheritFoo`. - This class inherit from two classes: :class:`format.rst.foo.Foo` and :class:`format.rst.foo`. - """ - pass \ No newline at end of file diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/native/__init__.pyi b/packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/native/__init__.pyi deleted file mode 100644 index b15d3b22ce25..000000000000 --- a/packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/native/__init__.pyi +++ /dev/null @@ -1,2 +0,0 @@ -# coding: utf-8 -# .pyi is used to declare that this folder is a namespace package. \ No newline at end of file diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/pkg_resources/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/pkg_resources/__init__.py deleted file mode 100644 index ae64cf512547..000000000000 --- a/packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/pkg_resources/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright 2021 Google LLC -# -# 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. - -# coding: utf-8 -# Used for testing pkg_resources-style namespace package. -# See more: https://packaging.python.org/guides/packaging-namespace-packages/#pkg-resources-style-namespace-packages - -__import__('pkg_resources').declare_namespace(__name__) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/pkgutil/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/pkgutil/__init__.py deleted file mode 100644 index 57feff0c84eb..000000000000 --- a/packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/pkgutil/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright 2021 Google LLC -# -# 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. - -# coding: utf-8 -# Used for testing pkgutil-style namespace package. -# See more from: https://packaging.python.org/guides/packaging-namespace-packages/#pkgutil-style-namespace-packages - -__path__ = __import__('pkgutil').extend_path(__path__, __name__) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/setup.cfg b/packages/gcp-sphinx-docfx-yaml/tests/example/setup.cfg deleted file mode 100644 index 5e4090017a9b..000000000000 --- a/packages/gcp-sphinx-docfx-yaml/tests/example/setup.cfg +++ /dev/null @@ -1,2 +0,0 @@ -[wheel] -universal = 1 diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/setup.py b/packages/gcp-sphinx-docfx-yaml/tests/example/setup.py deleted file mode 100644 index 7c8ea3bc8c2d..000000000000 --- a/packages/gcp-sphinx-docfx-yaml/tests/example/setup.py +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright 2021 Google LLC -# -# 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. - -from setuptools import setup, find_packages - -setup( - name='example', - version='0.1', - author='Yiding Tian', - author_email='yitian@microsoft.com', - url='https://github.com/docascode/sphinx-docfx-yaml/tree/master/tests/example', - description='Test Package for sphinx-docfx-yaml', - package_dir={'': '.'}, - packages=find_packages('.', exclude=['doc']), - include_package_data=True -) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/test_goldens.py b/packages/gcp-sphinx-docfx-yaml/tests/test_goldens.py new file mode 100644 index 000000000000..637862a00714 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/test_goldens.py @@ -0,0 +1,152 @@ +# Copyright 2022 Google LLC +# +# 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 +# +# https://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. + +from pathlib import Path +import difflib +import filecmp +import os +import shutil +import sys + +from docuploader import shell + +import pytest + +from sphinx.application import Sphinx + + +@pytest.mark.parametrize( + "test_dir", ["handwritten", "gapic-combo", "gapic-auto"] +) +def test_goldens(update_goldens, test_dir): + source_dir = Path("tests/testdata") / test_dir + golden_dir = Path("tests/testdata/goldens") / test_dir + + docs_dir = source_dir / "docs" + build_dir = docs_dir / "_build" + + if build_dir.exists(): + shutil.rmtree(build_dir) + + out_dir = build_dir / "html/docfx_yaml" + + # Install dependencies. + try: + shell.run( + [ + sys.executable, + "-m", + "pip", + "install", + "-e", + ".[all]", + "recommonmark", + ], + cwd=source_dir, + hide_output=False, + ) + except Exception as e: + pytest.fail(f"build raised an exception: {e}") + + # Generate! + try: + shell.run( + [ + "sphinx-build", + # Settings to be used for sphinx-build + "-D", + # Extensions to be added + ( + "extensions=sphinx.ext.autodoc," + "sphinx.ext.autosummary," + "docfx_yaml.extension," + "sphinx.ext.intersphinx," + "sphinx.ext.coverage," + "sphinx.ext.napoleon," + "sphinx.ext.todo," + "sphinx.ext.viewcode," + "recommonmark" + ), + # builder to use + "-b", + "html", + # cache directory path + "-d", + "docs/_build/doctrees/", + # source directory + "docs/", + # output directory for HTML + "docs/_build/html", + ], + cwd=source_dir, + hide_output=False, + ) + except Exception as e: + pytest.fail(f"build raised an exception: {e}") + + if update_goldens: + shutil.rmtree(golden_dir, ignore_errors=True) + files_to_move = out_dir.rglob("*") + + # Overwrite incorrect repo data used compared to GH Action. + incorrect_repo = "git@github.com:googleapis/sphinx-docfx-yaml.git" + correct_repo = "https://github.com/googleapis/sphinx-docfx-yaml" + + for yaml_file in files_to_move: + with open(yaml_file) as file: + lines = file.read() + lines = lines.replace(incorrect_repo, correct_repo) + with open(yaml_file, 'w') as file: + file.write(lines) + + shutil.copytree(out_dir, golden_dir, dirs_exist_ok=True) + pytest.skip( + "Updated goldens! Re-run the test without the --update-goldens flag." + ) + + got_files = [os.path.relpath(f, out_dir) for f in out_dir.rglob("*")] + golden_files = [os.path.relpath(f, golden_dir) for f in golden_dir.rglob("*")] + + nl = "\n" + extra = "Extra:\n" + "\n+ ".join([f for f in got_files if f not in golden_files]) + missing = "Missing:\n" + "\n- ".join( + [f for f in golden_files if f not in got_files] + ) + + assert len(got_files) == len( + golden_files + ), f"got {len(got_files)} files, want {len(golden_files)}:{nl}{extra}{nl}{missing}" + + (eq, neq, other) = filecmp.cmpfiles(out_dir, golden_dir, got_files, shallow=False) + other = [(out_dir / f).as_posix() for f in other] + + if other: + pytest.fail(f"found unknown files (should never happen): {other}") + if neq: + diff = "" + for f in neq: + with open(out_dir / f) as out: + with open(golden_dir / f) as gold: + out_lines = out.readlines() + gold_lines = gold.readlines() + diff = "\n" + "\n".join( + difflib.context_diff( + gold_lines, + out_lines, + fromfile=str(golden_dir / f), + tofile=str(out_dir / f), + ) + ) + + pytest.fail(f"got files that don't match goldens: {diff}") diff --git a/packages/gcp-sphinx-docfx-yaml/tests/test_yaml.py b/packages/gcp-sphinx-docfx-yaml/tests/test_yaml.py deleted file mode 100644 index a1bba0994633..000000000000 --- a/packages/gcp-sphinx-docfx-yaml/tests/test_yaml.py +++ /dev/null @@ -1,534 +0,0 @@ -# Copyright 2021 Google LLC -# -# 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. - -import os -import re -import yaml -import shutil -import unittest - -from contextlib import contextmanager - -from sphinx.application import Sphinx - - -@contextmanager -def sphinx_build(test_dir): - """ Use contextmanager to ensure build cleaning after testing. - """ - - os.chdir('tests/{0}'.format(test_dir)) - - try: - app = Sphinx( - srcdir='./doc', - confdir='./doc', - outdir='_build/text', - doctreedir='_build/.doctrees', - buildername='html' - ) - app.build(force_all=True) - yield - finally: - shutil.rmtree('_build') - os.chdir('../..') - - -class YamlTests(unittest.TestCase): - build_path = '_build/text/docfx_yaml' #: Path of all the yaml files. - - yaml_files = { #: yaml files needed to be tested. - "class_files": { - "google": [ - "format.google.foo.Foo.yml", - "format.google.foo.FooException.InternalFoo.yml", - "format.google.foo.FooException.yml" - ], - "numpy": [ - "format.numpy.foo.Foo.yml", - "format.numpy.foo.FooException.InternalFoo.yml", - "format.numpy.foo.FooException.yml" - ], - "rst": [ - "format.rst.directives.DirectivesFoo.yml", - "format.rst.enum.EnumFoo.yml", - "format.rst.foo.Foo.yml", - "format.rst.foo.FooException.InternalFoo.yml", - "format.rst.foo.FooException.yml", - "format.rst.foo.InheritFoo.yml" - ], - "namespacepackage": [ - "nspkg.native.native_foo.Foo.yml", - "nspkg.pkgutil.pkgutil_foo.Foo.yml", - "nspkg.pkg_resources.pkg_resources_foo.Foo.yml" - ] - }, - "module_files": { - "google": [ - "format.google.foo.yml" - ], - "numpy": [ - "format.numpy.foo.yml" - ], - "rst": [ - "format.rst.directives.yml", - "format.rst.enum.yml", - "format.rst.foo.yml" - ] - }, - "package_files": { - "namesapcepackage": [ - "nspkg.yml", - "nspkg.native.native_foo.yml", - "nspkg.pkgutil.yml", - "nspkg.pkgutil.pkgutil_foo.yml", - "nspkg.pkg_resources.yml", - "nspkg.pkg_resources.pkg_resources_foo.yml" - ], - "format": [ - "format.yml", - "format.rst.yml", - "format.google.yml", - "format.numpy.yml" - ] - } - } - - def test_uid(self): - """ - Test whether uids are generated correctly. - """ - with sphinx_build('example'): - with open(os.path.join(self.build_path, self.yaml_files['class_files']['rst'][0]), 'r') as f: - # Test uids in format.rst.directives.DirectivesFoo.yml - data = yaml.safe_load(f) - - self.assertEqual( - data['items'][0]['uid'], - 'format.rst.directives.DirectivesFoo' - ) - - with open(os.path.join(self.build_path, self.yaml_files['module_files']['rst'][1]), 'r') as f: - # Test uids in format.rst.enum.yml - data = yaml.safe_load(f) - - self.assertEqual( - data['items'][0]['uid'], - 'format.rst.enum' - ) - - with open(os.path.join(self.build_path, self.yaml_files['package_files']['format'][2]), 'r') as f: - # Test uids in format.google.yml - data = yaml.safe_load(f) - - self.assertEqual( - data['items'][0]['uid'], - 'format.google' - ) - - def test_name(self): - """ - Test whether names are generated correctly. - """ - with sphinx_build('example'): - with open(os.path.join(self.build_path, self.yaml_files['class_files']['rst'][0]), 'r') as f: - # Test names in format.rst.directives.DirectivesFoo.yml - data = yaml.safe_load(f) - - self.assertEqual( - data['items'][0]['name'], - 'DirectivesFoo' - ) - - self.assertEqual( - data['items'][1]['name'], - 'method_remarks()' - ) # Test name of method format.rst.directives.DirectivesFoo.method_remarks - - with open(os.path.join(self.build_path, self.yaml_files['module_files']['rst'][1]), 'r') as f: - # Test names in format.rst.enum.yml - data = yaml.safe_load(f) - - self.assertEqual( - data['items'][0]['name'], - 'enum' - ) - - with open(os.path.join(self.build_path, self.yaml_files['package_files']['format'][2]), 'r') as f: - # Test names in format.google.yml - data = yaml.safe_load(f) - - self.assertEqual( - data['items'][0]['name'], - 'google' - ) - - def test_alert_box(self): - """ - Test whether alert boxes are generated correctly. - Avaliable alert boxes are Note, Warning, Tip and Important - """ - with sphinx_build('example'): - with open(os.path.join(self.build_path, self.yaml_files['class_files']['rst'][0]), 'r') as f: - # Test alert boxes in format.rst.directives.DirectivesFoo.yml - data = yaml.safe_load(f) - - self.assertEqual( - data['items'][0]['summary'], - 'Docstring of class .\n\n\n> [!NOTE]\n> Note content from class docstring.\n>\n> Second line of note content.\n>\n> many lines of content.\n>\n\n\n> [!WARNING]\n> Warning message from class docstring.\n>\n> Second line.\n>\n\n\n> [!TIP]\n> Tip content. \n>\n\n\n> [!IMPORTANT]\n> Important content.\n>\n\n\n> [!CAUTION]\n> Caution content.\n>' - ) # Test alert box in summary section - - self.assertEqual( - data['items'][0]['remarks'], - 'Remarks from class.\nMulti-line content should be supported.\n\n\n> [!NOTE]\n> Note conetnt under class remarks.\n>\n> Second line of note content.\n>\n> [!WARNING]\n> Warning content under class remarks.\n>\n> Second line.\n>\n> \n>\n> [!TIP]\n> Tip content.\n>\n> [!IMPORTANT]\n> Important content.\n>\n> [!CAUTION]\n> Caution content.\n>\n' - ) # Test alert box in remarks section - - def test_summary(self): - """ - Test module/package/class summary being extracted. - """ - with sphinx_build('example'): - with open(os.path.join(self.build_path, self.yaml_files['class_files']['rst'][3])) as f: - # Test summary in format.rst.foo.FooException.InternalFoo.yml - data = yaml.safe_load(f) - - self.assertEqual( - data['items'][0]['summary'].replace('\n', ' ').strip(), - 'Docstring of internal class . ' - 'This class is an internal class of .' - ) - - with open(os.path.join(self.build_path, self.yaml_files['module_files']['numpy'][0])) as f: - # Test summary in module format.numpy.foo.yml - data = yaml.safe_load(f) - - self.assertEqual( - data['items'][0]['summary'].strip(), - 'Docstring of module.' - ) - - with open(os.path.join(self.build_path, self.yaml_files['package_files']['format'][1])) as f: - # Test summary in format.rst.yml - data = yaml.safe_load(f) - - self.assertEqual( - data['items'][0]['summary'].strip(), - 'Docstring of package .' - ) - - def test_references(self): - """ - Test references are properly inserted. - """ - with sphinx_build('example'): - with open(os.path.join(self.build_path, self.yaml_files['class_files']['rst'][2])) as f: - # Test format.rst.foo.Foo.yml - data = yaml.safe_load(f) - - self.assertIn( - 'references', - data - ) # Test references is added. - - self.assertEqual( - data['references'][0]['parent'], - 'format.rst.foo.Foo' - ) # Test reference value - - self.assertEqual( - data['references'][-1]['spec.python'][2]['uid'], - 'int' - ) # Test reference spec - - def test_inheritance(self): - """ - Test multiple inheritance is properly resolved. - """ - with sphinx_build('example'): - with open(os.path.join(self.build_path, self.yaml_files['class_files']['rst'][5])) as f: - # Test format.rst.foo.InheritFoo.yml - data = yaml.safe_load(f) - - self.assertEqual( - data['items'][0]['inheritance'][0]['type'], - 'format.rst.foo.Foo' - ) - - self.assertEqual( - data['items'][0]['inheritance'][1]['type'], - 'builtins.dict' - ) - - def test_source(self): - """ - Test source info is parsed properly. - """ - with sphinx_build('example'): - with open(os.path.join(self.build_path, self.yaml_files['class_files']['namespacepackage'][1])) as f: - # Test source info of class Foo in nspkg.pkgutil.pkgutil_foo.Foo.yml - data = yaml.safe_load(f) - - self.assertIn( - 'source', - data['items'][0] - ) - - self.assertEqual( - data['items'][0]['source']['id'], - 'Foo' - ) - - self.assertIn( - 'format{sep}rst{sep}foo.py'.format(sep = os.sep), - data['items'][0]['source']['path'] - ) - - self.assertEqual( - 23, - data['items'][0]['source']['startLine'] - ) - - with open(os.path.join(self.build_path, self.yaml_files['module_files']['rst'][1])) as f: - # Test source info of module format.rst.enum in format.rst.enum.yml - data = yaml.safe_load(f) - - self.assertIn( - 'source', - data['items'][0] - ) - - self.assertEqual( - data['items'][0]['source']['id'], - 'enum' - ) - - self.assertIn( - 'format{sep}rst{sep}enum.py'.format(sep = os.sep), - data['items'][0]['source']['path'] - ) - - self.assertEqual( - 0, - data['items'][0]['source']['startLine'] - ) - - with open(os.path.join(self.build_path, self.yaml_files['package_files']['format'][2])) as f: - # Test source info of package google in format.google.yml - data = yaml.safe_load(f) - - self.assertIn( - 'source', - data['items'][0] - ) - - self.assertEqual( - data['items'][0]['source']['id'], - 'google' - ) - - self.assertIn( - 'format{sep}google{sep}__init__.py'.format(sep = os.sep), - data['items'][0]['source']['path'] - ) - - self.assertEqual( - 0, - data['items'][0]['source']['startLine'] - ) - - def test_external_link(self): - """ - Test external link should be written in markdown format. - """ - with sphinx_build('example'): - with open(os.path.join(self.build_path, self.yaml_files['class_files']['rst'][2])) as f: - # Test format.rst.foo.Foo.yml - data = yaml.safe_load(f) - - for item in data['items']: - if item['uid'] == 'format.rst.foo.Foo.method_external_link': - summary = re.sub(r'\n+', '\n', item['summary']).strip() - summary_lines = summary.split('\n') - - self.assertIn( - '[Link Text](http://inline.external.link)', - summary_lines[1] - ) - - self.assertNotIn( # Seperated link not supported. - '[Seperated Link](http://seperated.external.link)', - summary_lines[2] - ) - return - - self.fail() - - def test_google_format(self): - """ - Test google-style docstring. - """ - with sphinx_build('example'): - with open(os.path.join(self.build_path, self.yaml_files['class_files']['google'][0])) as f: - # Test format.google.foo.Foo.yml - data = yaml.safe_load(f) - - for item in data['items']: - if item['uid'] == 'format.google.foo.Foo.method_seealso': - self.assertEqual( - item['seealsoContent'].strip(), - 'Seealso contents.\n Multi-line should be supported.' - ) - - def test_numpy_format(self): - """ - Test numpy-style docstring. - """ - with sphinx_build('example'): - with open(os.path.join(self.build_path, self.yaml_files['class_files']['numpy'][0])) as f: - # Test format.numpy.foo.Foo.yml - data = yaml.safe_load(f) - - for item in data['items']: - if item['uid'] == 'format.numpy.foo.Foo.method_seealso': - self.assertEqual( - re.sub(r'\s+', ' ', item['seealsoContent']).strip(), - ' See also target.' - ) # Test see also centent from numpy format. - - def test_toc(self): - """ - Test toc structure. - """ - with sphinx_build('example'): - with open(os.path.join(self.build_path, 'toc.yml')) as f: - # Test toc.yml - data = yaml.safe_load(f) - - self.assertEqual( - data[0]['uid'], - 'project-example' - ) # Test project name node - - self.assertEqual( - len(data[0]['items']), - 3 - ) # Test there are three package nodes. - # Actually should be two, cuz namespace package should be placed in father nodes. - # TODO: To be fixed in future. - - self.assertEqual( - data[0]['items'][0]['uid'], - 'format' - ) # Test format package in toc. - - self.assertEqual( - data[0]['items'][1]['uid'], - 'nspkg' - ) # Test nspkg package in toc. - - def test_index(self): - """ - Test index information of project. - """ - with sphinx_build('example'): - with open(os.path.join(self.build_path, 'index.yml')) as yml_file: - # Test index.yml - data = yaml.safe_load(yml_file) - - self.assertEqual( - 'project-example', - data['items'][0]['uid'] - ) # Test there is only one item for project-example - - self.assertIn( - 'format', - data['items'][0]['children'] - ) # Test format package is in index.yml - - self.assertIn( - 'nspkg', - data['items'][0]['children'] - ) # Test nspkg package is in index.yml - - self.assertIn( - 'nspkg.native.native_foo', - data['items'][0]['children'] - ) # Test nspkg.native.native_foo package is in index.yml - # Actually this should not be in index. - # TODO: To be fixed in future. - - def test_examples(self): - """ - Test example contents - """ - with sphinx_build('example'): - with open(os.path.join(self.build_path, self.yaml_files['class_files']['rst'][2])) as f: - # Test format.rst.foo.Foo.yml - data = yaml.safe_load(f) - - for item in data['items']: - if item['uid'] == 'format.rst.foo.Foo.method_example': - self.assertIn( - 'example', - item - ) # Test example field existance - - self.assertIn( - 'VALUE0 = 0 #: Inline docstring of VALUE0', - item['example'][0] - ) # Test example content - - def test_seealso(self): - """ - Test seealso contents - """ - with sphinx_build('example'): - with open(os.path.join(self.build_path, self.yaml_files['class_files']['rst'][2])) as f: - # Test format.rst.foo.Foo.yml - data = yaml.safe_load(f) - - for item in data['items']: - if item['uid'] == 'format.rst.foo.Foo.method_seealso': - self.assertIn( - 'seealsoContent', - item - ) # Test seealso field existance - - self.assertIn( - 'Seealso contents.\n Multi-line should be supported.', - item['seealsoContent'] - ) # Test seealso content - - def test_enum(self): - """ - Test enum type support - """ - with sphinx_build('example'): - with open(os.path.join(self.build_path, self.yaml_files['class_files']['rst'][1])) as f: - data = yaml.safe_load(f) - for item in data['items']: - if item['uid'] == 'format.rst.enum.EnumFoo': - self.assertEqual( - item['children'], - ['format.rst.enum.EnumFoo.VALUE0', 'format.rst.enum.EnumFoo.VALUE1'] - ) # Test containing all enum values - if item['uid'] == 'format.rst.enum.EnumFoo.VALUE0': - self.assertEqual( - item['syntax'], - {'content': 'VALUE0 = 0', 'return': {'type': ['format.rst.enum.EnumFoo']}} - ) # Test enum value syntax - self.assertEqual( - item['type'], - 'attribute' - ) # Test enum value type diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/CHANGELOG.md b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/CHANGELOG.md new file mode 100644 index 000000000000..0d6959a728a2 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/CHANGELOG.md @@ -0,0 +1,381 @@ +# Changelog + +[PyPI History][1] + +[1]: https://pypi.org/project/google-cloud-texttospeech/#history + +## [2.12.3](https://github.com/googleapis/python-texttospeech/compare/v2.12.2...v2.12.3) (2022-10-07) + + +### Bug Fixes + +* **deps:** Allow protobuf 3.19.5 ([#338](https://github.com/googleapis/python-texttospeech/issues/338)) ([aa92121](https://github.com/googleapis/python-texttospeech/commit/aa921215c05588b6555b7b41381b30f8b0079d54)) + +## [2.12.2](https://github.com/googleapis/python-texttospeech/compare/v2.12.1...v2.12.2) (2022-10-03) + + +### Bug Fixes + +* **deps:** Require protobuf >= 3.20.2 ([#335](https://github.com/googleapis/python-texttospeech/issues/335)) ([50b394d](https://github.com/googleapis/python-texttospeech/commit/50b394dc5684b2df6cf544ba7bb5296d384ee0f8)) + +## [2.12.1](https://github.com/googleapis/python-texttospeech/compare/v2.12.0...v2.12.1) (2022-08-11) + + +### Bug Fixes + +* **deps:** allow protobuf < 5.0.0 ([#316](https://github.com/googleapis/python-texttospeech/issues/316)) ([ec75f1e](https://github.com/googleapis/python-texttospeech/commit/ec75f1e5382bd527d17fb347a7ecc7cd35f57ab0)) +* **deps:** require proto-plus >= 1.22.0 ([ec75f1e](https://github.com/googleapis/python-texttospeech/commit/ec75f1e5382bd527d17fb347a7ecc7cd35f57ab0)) + +## [2.12.0](https://github.com/googleapis/python-texttospeech/compare/v2.11.1...v2.12.0) (2022-07-16) + + +### Features + +* add audience parameter ([f450551](https://github.com/googleapis/python-texttospeech/commit/f450551482e52c7f5564bf735b705e22255dc5d8)) + + +### Bug Fixes + +* **deps:** require google-api-core>=1.32.0,>=2.8.0 ([#304](https://github.com/googleapis/python-texttospeech/issues/304)) ([f450551](https://github.com/googleapis/python-texttospeech/commit/f450551482e52c7f5564bf735b705e22255dc5d8)) +* require python 3.7+ ([#306](https://github.com/googleapis/python-texttospeech/issues/306)) ([192277b](https://github.com/googleapis/python-texttospeech/commit/192277b9b62338840b55fe8e24be582a19f390cd)) + +## [2.11.1](https://github.com/googleapis/python-texttospeech/compare/v2.11.0...v2.11.1) (2022-06-06) + + +### Bug Fixes + +* **deps:** require protobuf <4.0.0dev ([#293](https://github.com/googleapis/python-texttospeech/issues/293)) ([e5ab0d6](https://github.com/googleapis/python-texttospeech/commit/e5ab0d6b69e008653b1500742ede3ead3a748f58)) + + +### Documentation + +* fix changelog header to consistent size ([#294](https://github.com/googleapis/python-texttospeech/issues/294)) ([8a8b65c](https://github.com/googleapis/python-texttospeech/commit/8a8b65c0e4c39a5671e9998848ebb89ea38d301d)) + +## [2.11.0](https://github.com/googleapis/python-texttospeech/compare/v2.10.2...v2.11.0) (2022-03-10) + + +### Features + +* promote CustomVoiceParams to v1 ([#266](https://github.com/googleapis/python-texttospeech/issues/266)) ([f484e7f](https://github.com/googleapis/python-texttospeech/commit/f484e7fe036fe57a4f432bf30c6421a6541ea486)) + +## [2.10.2](https://github.com/googleapis/python-texttospeech/compare/v2.10.1...v2.10.2) (2022-03-05) + + +### Bug Fixes + +* **deps:** require google-api-core>=1.31.5, >=2.3.2 ([#261](https://github.com/googleapis/python-texttospeech/issues/261)) ([f993058](https://github.com/googleapis/python-texttospeech/commit/f993058b1535e8cc0c71877b8dca9beae3dffb1b)) +* **deps:** require proto-plus>=1.15.0 ([f993058](https://github.com/googleapis/python-texttospeech/commit/f993058b1535e8cc0c71877b8dca9beae3dffb1b)) + +## [2.10.1](https://github.com/googleapis/python-texttospeech/compare/v2.10.0...v2.10.1) (2022-02-26) + + +### Documentation + +* add generated snippets ([#249](https://github.com/googleapis/python-texttospeech/issues/249)) ([f918e82](https://github.com/googleapis/python-texttospeech/commit/f918e82df2e0c499356fa1e095b13f7ac2cd3b6b)) + +## [2.10.0](https://github.com/googleapis/python-texttospeech/compare/v2.9.1...v2.10.0) (2022-02-03) + + +### Features + +* add api key support ([#242](https://github.com/googleapis/python-texttospeech/issues/242)) ([3b4f0d0](https://github.com/googleapis/python-texttospeech/commit/3b4f0d0749529b04ed7fedec3c4b06b6d42c12cd)) + + +### Bug Fixes + +* resolve DuplicateCredentialArgs error when using credentials_file ([4c11b12](https://github.com/googleapis/python-texttospeech/commit/4c11b127ece0009082fe91062f3f36c8f18e8ffc)) + + +### Documentation + +* update comments for ListVoicesRequest ([#244](https://github.com/googleapis/python-texttospeech/issues/244)) ([bc5b73f](https://github.com/googleapis/python-texttospeech/commit/bc5b73fbc62900f89a01486c6e8d42d459c34fd6)) + +## [2.9.1](https://www.github.com/googleapis/python-texttospeech/compare/v2.9.0...v2.9.1) (2022-01-08) + + +### Documentation + +* Added virtualenv comment for clarity ([#225](https://www.github.com/googleapis/python-texttospeech/issues/225)) ([61a7fce](https://www.github.com/googleapis/python-texttospeech/commit/61a7fcec0611712cdb1692b830db4aaca4d411b0)) +* update comments for ListVoicesRequest ([#229](https://www.github.com/googleapis/python-texttospeech/issues/229)) ([9ea340c](https://www.github.com/googleapis/python-texttospeech/commit/9ea340cee20298630a6a15bed0ed2df9f69b3d13)) + +## [2.9.0](https://www.github.com/googleapis/python-texttospeech/compare/v2.8.0...v2.9.0) (2021-11-16) + + +### Features + +* update v1 proto ([#221](https://www.github.com/googleapis/python-texttospeech/issues/221)) ([e8776d7](https://www.github.com/googleapis/python-texttospeech/commit/e8776d7a482f495ed5ae0e1235609e3e2d3e6067)) + +## [2.8.0](https://www.github.com/googleapis/python-texttospeech/compare/v2.7.1...v2.8.0) (2021-11-13) + + +### Features + +* **v1beta1:** add CustomVoiceParams ([#215](https://www.github.com/googleapis/python-texttospeech/issues/215)) ([6a18d0f](https://www.github.com/googleapis/python-texttospeech/commit/6a18d0f097e992bd4d90eaf5032ce98aa4af004a)) + + +### Documentation + +* fix docstring formatting ([#218](https://www.github.com/googleapis/python-texttospeech/issues/218)) ([2c57f95](https://www.github.com/googleapis/python-texttospeech/commit/2c57f95a1af747b49dac41628bd43d485a68583e)) + +## [2.7.1](https://www.github.com/googleapis/python-texttospeech/compare/v2.7.0...v2.7.1) (2021-11-01) + + +### Bug Fixes + +* **deps:** drop packaging dependency ([99ac70b](https://www.github.com/googleapis/python-texttospeech/commit/99ac70ba45d7c500d0f19a30dead060c0db4453c)) +* **deps:** require google-api-core >= 1.28.0 ([99ac70b](https://www.github.com/googleapis/python-texttospeech/commit/99ac70ba45d7c500d0f19a30dead060c0db4453c)) + + +### Documentation + +* list oneofs in docstring ([99ac70b](https://www.github.com/googleapis/python-texttospeech/commit/99ac70ba45d7c500d0f19a30dead060c0db4453c)) + +## [2.7.0](https://www.github.com/googleapis/python-texttospeech/compare/v2.6.0...v2.7.0) (2021-10-18) + + +### Features + +* add support for python 3.10 ([#202](https://www.github.com/googleapis/python-texttospeech/issues/202)) ([2ffa70b](https://www.github.com/googleapis/python-texttospeech/commit/2ffa70b6c35707142d66476b0ef5e3bd8d6d0052)) + +## [2.6.0](https://www.github.com/googleapis/python-texttospeech/compare/v2.5.3...v2.6.0) (2021-10-07) + + +### Features + +* add context manager support in client ([#196](https://www.github.com/googleapis/python-texttospeech/issues/196)) ([73d9290](https://www.github.com/googleapis/python-texttospeech/commit/73d9290cdea69a00ba317ae017a1d07bcf734989)) + +## [2.5.3](https://www.github.com/googleapis/python-texttospeech/compare/v2.5.2...v2.5.3) (2021-09-24) + + +### Bug Fixes + +* add 'dict' annotation type to 'request' ([e74b994](https://www.github.com/googleapis/python-texttospeech/commit/e74b9942d480bf7e360bc61ff183909873fc20a6)) + +## [2.5.2](https://www.github.com/googleapis/python-texttospeech/compare/v2.5.1...v2.5.2) (2021-07-28) + + +### Bug Fixes + +* enable self signed jwt for grpc ([#171](https://www.github.com/googleapis/python-texttospeech/issues/171)) ([9c1c437](https://www.github.com/googleapis/python-texttospeech/commit/9c1c4371caa712a749b406257c09d98f6b428e7b)) + + +### Documentation + +* add Samples section to CONTRIBUTING.rst ([#166](https://www.github.com/googleapis/python-texttospeech/issues/166)) ([053abe3](https://www.github.com/googleapis/python-texttospeech/commit/053abe3afc1107bdacd164e6ca4cd60b5ca07df7)) + + +### Miscellaneous Chores + +* release as 2.5.2 ([#172](https://www.github.com/googleapis/python-texttospeech/issues/172)) ([3804727](https://www.github.com/googleapis/python-texttospeech/commit/3804727995d0357fa0c4c5c246210768e0ce7124)) + +## [2.5.1](https://www.github.com/googleapis/python-texttospeech/compare/v2.5.0...v2.5.1) (2021-07-20) + + +### Bug Fixes + +* **deps:** pin 'google-{api,cloud}-core', 'google-auth' to allow 2.x versions ([#165](https://www.github.com/googleapis/python-texttospeech/issues/165)) ([d78b384](https://www.github.com/googleapis/python-texttospeech/commit/d78b384d302a1976682f35875ce2d4f7b60d7a6c)) + +## [2.5.0](https://www.github.com/googleapis/python-texttospeech/compare/v2.4.0...v2.5.0) (2021-07-01) + + +### Features + +* add always_use_jwt_access ([#155](https://www.github.com/googleapis/python-texttospeech/issues/155)) ([cd10c37](https://www.github.com/googleapis/python-texttospeech/commit/cd10c3704db610f2abf65c9142cfdaa867d8490a)) + + +### Bug Fixes + +* disable always_use_jwt_access ([#159](https://www.github.com/googleapis/python-texttospeech/issues/159)) ([d109303](https://www.github.com/googleapis/python-texttospeech/commit/d109303898facc663a6e7fe9212440831c1eeb75)) + + +### Documentation + +* omit mention of Python 2.7 in 'CONTRIBUTING.rst' ([#1127](https://www.github.com/googleapis/python-texttospeech/issues/1127)) ([#150](https://www.github.com/googleapis/python-texttospeech/issues/150)) ([d2954ba](https://www.github.com/googleapis/python-texttospeech/commit/d2954ba91385db6d581f75154fb11c969f6ca0e2)), closes [#1126](https://www.github.com/googleapis/python-texttospeech/issues/1126) + +## [2.4.0](https://www.github.com/googleapis/python-texttospeech/compare/v2.3.0...v2.4.0) (2021-05-28) + + +### Features + +* support self-signed JWT flow for service accounts ([8a08836](https://www.github.com/googleapis/python-texttospeech/commit/8a08836487c1b7e4e58d3c07a4e26005d40793f0)) + + +### Bug Fixes + +* add async client to %name_%version/init.py ([8a08836](https://www.github.com/googleapis/python-texttospeech/commit/8a08836487c1b7e4e58d3c07a4e26005d40793f0)) + +## [2.3.0](https://www.github.com/googleapis/python-texttospeech/compare/v2.2.0...v2.3.0) (2021-03-31) + + +### Features + +* add `from_service_account_info` to clients ([139e6e8](https://www.github.com/googleapis/python-texttospeech/commit/139e6e8511cdce4c0be7983520f7efc47092f3b1)) +* Add ALAW support on client library and improve the ListVoiceRequest message's documentation ([#113](https://www.github.com/googleapis/python-texttospeech/issues/113)) ([8bbd380](https://www.github.com/googleapis/python-texttospeech/commit/8bbd38014fe796b30f4b12ae9432d3a05c130063)) +* add common resource helper methods ([139e6e8](https://www.github.com/googleapis/python-texttospeech/commit/139e6e8511cdce4c0be7983520f7efc47092f3b1)) +* support custom client info ([#82](https://www.github.com/googleapis/python-texttospeech/issues/82)) ([0612793](https://www.github.com/googleapis/python-texttospeech/commit/06127932a920f6318db8f25d6430755b35d09bb5)) + + +### Bug Fixes + +* change default retry and timeout settings ([139e6e8](https://www.github.com/googleapis/python-texttospeech/commit/139e6e8511cdce4c0be7983520f7efc47092f3b1)) + + +### Documentation + +* use sphinx-1.5.5 for sphinx-docfx-yaml ([#89](https://www.github.com/googleapis/python-texttospeech/issues/89)) ([feb04c5](https://www.github.com/googleapis/python-texttospeech/commit/feb04c50b56c2c3359b92d8b5887c8ee50be2b95)) + +## [2.2.0](https://www.github.com/googleapis/python-texttospeech/compare/v2.1.0...v2.2.0) (2020-08-10) + + +### Features + +* incorporate upstream changes ([#73](https://www.github.com/googleapis/python-texttospeech/issues/73)) ([8ee5447](https://www.github.com/googleapis/python-texttospeech/commit/8ee544740f18497d9925bcf77e5ab96695503589)) + * support MULAW audio encoding + * support MP3_64_KBPS audio encoding + * support timepointing via SSML tag + * support quota_project_id + +## [2.1.0](https://www.github.com/googleapis/python-texttospeech/compare/v2.0.0...v2.1.0) (2020-06-20) + + +### Features + +* add async client ([#53](https://www.github.com/googleapis/python-texttospeech/issues/53)) ([887d8d5](https://www.github.com/googleapis/python-texttospeech/commit/887d8d501ce9255fee44170b5fc40ebfb1ea953d)) + + +### Documentation + +* change relative URLs to absolute URLs to fix broken links ([#40](https://www.github.com/googleapis/python-texttospeech/issues/40)) ([b68df44](https://www.github.com/googleapis/python-texttospeech/commit/b68df446daa7983cad1d31553ece6df569c932b2)) + +## [2.0.0](https://www.github.com/googleapis/python-texttospeech/compare/v1.0.1...v2.0.0) (2020-06-01) + + +### ⚠ BREAKING CHANGES + +* This release has breaking changes. See the [2.0.0 Migration Guide](https://github.com/googleapis/python-texttospeech/blob/main/UPGRADING.md#200-migration-guide) for details. + +### Features + +* regenerate with microgenerator ([#30](https://www.github.com/googleapis/python-texttospeech/issues/30)) ([3181b55](https://www.github.com/googleapis/python-texttospeech/commit/3181b55733da7aecde37009a0dd77117434deceb)) + + +### Bug Fixes + +* address PR comments ([65f903b](https://www.github.com/googleapis/python-texttospeech/commit/65f903b00395716fad272ca4fc973755735e1e20)) + +## [1.0.1](https://www.github.com/googleapis/python-texttospeech/compare/v1.0.0...v1.0.1) (2020-02-28) + + +### Bug Fixes + +* update url in setup.py ([#13](https://www.github.com/googleapis/python-texttospeech/issues/13)) ([dc17707](https://www.github.com/googleapis/python-texttospeech/commit/dc17707c41feb885d94f1045ef14e4b9e0898716)) + +## [1.0.0](https://www.github.com/googleapis/python-texttospeech/compare/v0.5.0...v1.0.0) (2020-02-28) + + +### Features + +* bump release status to GA ([#9](https://www.github.com/googleapis/python-texttospeech/issues/9)) ([03a639e](https://www.github.com/googleapis/python-texttospeech/commit/03a639e16256d9211c1fe88991440f2cc22eccd6)) + +## 0.5.0 + +07-24-2019 17:48 PDT + + +### Implementation Changes +- Allow kwargs to be passed to create_channel (via synth). ([#8407](https://github.com/googleapis/google-cloud-python/pull/8407)) +- Reformat protos, update nox session docs (via synth). ([#7941](https://github.com/googleapis/google-cloud-python/pull/7941)) +- Remove classifier for Python 3.4 for end-of-life. ([#7535](https://github.com/googleapis/google-cloud-python/pull/7535)) + +### New Features +- Add 'client_options' support (via synth). ([#8525](https://github.com/googleapis/google-cloud-python/pull/8525)) + +### Dependencies +- Bump minimum version for google-api-core to 1.14.0. ([#8709](https://github.com/googleapis/google-cloud-python/pull/8709)) + +### Documentation +- Link to googleapis.dev documentation in READMEs. ([#8705](https://github.com/googleapis/google-cloud-python/pull/8705)) +- Add compatibility check badges to READMEs. ([#8288](https://github.com/googleapis/google-cloud-python/pull/8288)) +- Repair top-level API reference page. ([#8435](https://github.com/googleapis/google-cloud-python/pull/8435)) +- Updated client library documentation URLs. ([#7307](https://github.com/googleapis/google-cloud-python/pull/7307)) + +### Internal / Testing Changes +- Pin black version (via synth). ([#8599](https://github.com/googleapis/google-cloud-python/pull/8599)) +- Add docs job to publish to googleapis.dev. ([#8464](https://github.com/googleapis/google-cloud-python/pull/8464)) +- Declare encoding as utf-8 in pb2 files (via synth). ([#8367](https://github.com/googleapis/google-cloud-python/pull/8367)) +- Add disclaimer to auto-generated template files (via synth). ([#8331](https://github.com/googleapis/google-cloud-python/pull/8331)) +- Blacken (via synth). ([#8281](https://github.com/googleapis/google-cloud-python/pull/8281)) + +## 0.4.0 + +02-07-2019 15:21 PST + + +### Implementation Changes +- Pick up stub docstring fix in GAPIC generator. ([#6984](https://github.com/googleapis/google-cloud-python/pull/6984)) + +### New Features +- Protoc updates to include effects_profile_id. ([#7097](https://github.com/googleapis/google-cloud-python/pull/7097)) + +### Documentation +- Fix `Client Library Documentation` link ([#7109](https://github.com/googleapis/google-cloud-python/pull/7109)) + +### Internal / Testing Changes +- Copy proto files alongside protoc versions. +- Add protos as an artifact to library ([#7205](https://github.com/googleapis/google-cloud-python/pull/7205)) +- Update copyright headers and docstring quoting + +## 0.3.0 + +12-18-2018 09:54 PST + + +### Implementation Changes +- Import `iam.policy` from `google.api_core`. ([#6741](https://github.com/googleapis/google-cloud-python/pull/6741)) +- Pick up fixes to GAPIC generator. ([#6510](https://github.com/googleapis/google-cloud-python/pull/6510)) +- Fix `client_info` bug, update docstrings. ([#6423](https://github.com/googleapis/google-cloud-python/pull/6423)) +- Re-generate library using texttospeech/synth.py ([#5981](https://github.com/googleapis/google-cloud-python/pull/5981)) +- Add gRPC Transport layer. ([#5959](https://github.com/googleapis/google-cloud-python/pull/5959)) + +### Dependencies +- Bump minimum `api_core` version for all GAPIC libs to 1.4.1. ([#6391](https://github.com/googleapis/google-cloud-python/pull/6391)) +- Avoid broken 'google-common-apis 1.5.4' release. ([#6355](https://github.com/googleapis/google-cloud-python/pull/6355)) + +### Documentation +- Document Python 2 deprecation ([#6910](https://github.com/googleapis/google-cloud-python/pull/6910)) +- Docs: normalize use of support level badges ([#6159](https://github.com/googleapis/google-cloud-python/pull/6159)) +- Docs: Replace links to `/stable/` with `/latest/`. ([#5901](https://github.com/googleapis/google-cloud-python/pull/5901)) +- Fix docs links for TTS. ([#5483](https://github.com/googleapis/google-cloud-python/pull/5483)) + +### Internal / Testing Changes +- Add synth.metadata. ([#6870](https://github.com/googleapis/google-cloud-python/pull/6870)) +- Update noxfile. +- blacken all gen'd libs ([#6792](https://github.com/googleapis/google-cloud-python/pull/6792)) +- omit local deps ([#6701](https://github.com/googleapis/google-cloud-python/pull/6701)) +- Run black at end of synth.py ([#6698](https://github.com/googleapis/google-cloud-python/pull/6698)) +- Run Black on Generated libraries ([#6666](https://github.com/googleapis/google-cloud-python/pull/6666)) +- Add templates for flake8, coveragerc, noxfile, and black. ([#6642](https://github.com/googleapis/google-cloud-python/pull/6642)) +- Add 'mock' to unit test dependencies for autogen libs. ([#6402](https://github.com/googleapis/google-cloud-python/pull/6402)) +- Add / fix badges for PyPI / versions. ([#6158](https://github.com/googleapis/google-cloud-python/pull/6158)) +- Use new Nox ([#6175](https://github.com/googleapis/google-cloud-python/pull/6175)) + +## 0.2.0 + +### New Features + +- Add the text-to-speech v1 API surface. (#5468) +- Re-generate the text-to-speech v1beta1 API surface. (#5468) + +### Documentation + +- Rename releases to changelog and include from CHANGELOG.md (#5191) + +### Internal / Testing Changes + +- Add Test runs for Python 3.7 and remove 3.4 (#5295) + +## 0.1.0 + +### Interface additions + +- Added text-to-speech v1beta1. (#5049) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/README.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/README.rst new file mode 100644 index 000000000000..8d2e41bf68c2 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/README.rst @@ -0,0 +1,107 @@ +Python Client for Google Cloud Text-to-Speech API +================================================= + +|stable| |pypi| |versions| + +`Google Cloud Text-to-Speech API`_: enables easy integration of Google text recognition technologies into developer applications. Send text and receive synthesized audio output from the Cloud Text-to-Speech API service. + +- `Client Library Documentation`_ +- `Product Documentation`_ + +.. |stable| image:: https://img.shields.io/badge/support-stable-gold.svg + :target: https://github.com/googleapis/google-cloud-python/blob/main/README.rst#stability-levels +.. |pypi| image:: https://img.shields.io/pypi/v/google-cloud-texttospeech.svg + :target: https://pypi.org/project/google-cloud-texttospeech/ +.. |versions| image:: https://img.shields.io/pypi/pyversions/google-cloud-texttospeech.svg + :target: https://pypi.org/project/google-cloud-texttospeech/ +.. _Google Cloud Text-to-Speech API: https://cloud.google.com/text-to-speech +.. _Client Library Documentation: https://cloud.google.com/python/docs/reference/texttospeech/latest +.. _Product Documentation: https://cloud.google.com/text-to-speech + +Quick Start +----------- + +In order to use this library, you first need to go through the following steps: + +1. `Select or create a Cloud Platform project.`_ +2. `Enable billing for your project.`_ +3. `Enable the Google Cloud Text-to-Speech API.`_ +4. `Setup Authentication.`_ + +.. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project +.. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project +.. _Enable the Google Cloud Text-to-Speech API.: https://cloud.google.com/text-to-speech +.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html + +Installation +~~~~~~~~~~~~ + +Install this library in a `virtualenv`_ using pip. `virtualenv`_ is a tool to +create isolated Python environments. The basic problem it addresses is one of +dependencies and versions, and indirectly permissions. + +With `virtualenv`_, it's possible to install this library without needing system +install permissions, and without clashing with the installed system +dependencies. + +.. _`virtualenv`: https://virtualenv.pypa.io/en/latest/ + + +Code samples and snippets +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Code samples and snippets live in the `samples/` folder. + + +Supported Python Versions +^^^^^^^^^^^^^^^^^^^^^^^^^ +Our client libraries are compatible with all current `active`_ and `maintenance`_ versions of +Python. + +Python >= 3.7 + +.. _active: https://devguide.python.org/devcycle/#in-development-main-branch +.. _maintenance: https://devguide.python.org/devcycle/#maintenance-branches + +Unsupported Python Versions +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Python <= 3.6 + +If you are using an `end-of-life`_ +version of Python, we recommend that you update as soon as possible to an actively supported version. + +.. _end-of-life: https://devguide.python.org/devcycle/#end-of-life-branches + +Mac/Linux +^^^^^^^^^ + +.. code-block:: console + + pip install virtualenv + virtualenv + source /bin/activate + /bin/pip install google-cloud-texttospeech + + +Windows +^^^^^^^ + +.. code-block:: console + + pip install virtualenv + virtualenv + \Scripts\activate + \Scripts\pip.exe install google-cloud-texttospeech + +Next Steps +~~~~~~~~~~ + +- Read the `Client Library Documentation`_ for Google Cloud Text-to-Speech API + to see other available methods on the client. +- Read the `Google Cloud Text-to-Speech API Product documentation`_ to learn + more about the product and see How-to Guides. +- View this `README`_ to see the full list of Cloud + APIs that we cover. + +.. _Google Cloud Text-to-Speech API Product documentation: https://cloud.google.com/text-to-speech +.. _README: https://github.com/googleapis/google-cloud-python/blob/main/README.rst diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/UPGRADING.md b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/UPGRADING.md new file mode 100644 index 000000000000..f1450b1f23f2 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/UPGRADING.md @@ -0,0 +1,151 @@ +# 2.0.0 Migration Guide + +The 2.0 release of the `google-cloud-texttospeech` client is a significant upgrade based on a [next-gen code generator](https://github.com/googleapis/gapic-generator-python), and includes substantial interface changes. Existing code written for earlier versions of this library will likely require updates to use this version. This document describes the changes that have been made, and what you need to do to update your usage. + +If you experience issues or have questions, please file an [issue](https://github.com/googleapis/python-texttospeech/issues). + +## Supported Python Versions + +> **WARNING**: Breaking change + +The 2.0.0 release requires Python 3.6+. + + +## Method Calls + +> **WARNING**: Breaking change + +Methods expect request objects. We provide a script that will convert most common use cases. + +* Install the library and `libcst`. + +```py +python3 -m pip install google-cloud-texttospeech libcst +``` + +* The script `fixup_keywords.py` is shipped with the library. It expects +an input directory (with the code to convert) and an empty destination directory. + +```sh +$ fixup_keywords.py --input-directory .samples/ --output-directory samples/ +``` + +**Before:** +```py +from google.cloud import texttospeech + +client = texttospeech.TextToSpeechClient() + +voices = client.list_voices(language_code="no") +``` + + +**After:** +```py +from google.cloud import texttospeech + +client = texttospeech.TextToSpeechClient() + +voices = client.list_voices(request={"language_code": "no"}) +``` + +### More Details + +In `google-cloud-texttospeech<2.0.0`, parameters required by the API were positional parameters and optional parameters were keyword parameters. + +**Before:** +```py + def synthesize_speech( + self, + input_, + voice, + audio_config, + retry=google.api_core.gapic_v1.method.DEFAULT, + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None, + ): +``` + +In the 2.0.0 release, all methods have a single positional parameter `request`. Method docstrings indicate whether a parameter is required or optional. + +Some methods have additional keyword only parameters. The available parameters depend on the [`google.api.method_signature` annotation](https://github.com/googleapis/googleapis/blob/master/google/cloud/texttospeech/v1/cloud_tts.proto#L53) specified by the API producer. + + +**After:** +```py + def synthesize_speech( + self, + request: cloud_tts.SynthesizeSpeechRequest = None, + *, + input: cloud_tts.SynthesisInput = None, + voice: cloud_tts.VoiceSelectionParams = None, + audio_config: cloud_tts.AudioConfig = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> cloud_tts.SynthesizeSpeechResponse: +``` + +> **NOTE:** The `request` parameter and flattened keyword parameters for the API are mutually exclusive. +> Passing both will result in an error. + + +Both of these calls are valid: + +```py +response = client.synthesize_speech( + request={ + "input": input_text, + "voice": voice, + "audio_config": audio_config + } +) +``` + +```py +response = client.synthesize_speech( + input=input_text, + voice=voice, + audio_config=audio_config +) +``` + +This call is invalid because it mixes `request` with a keyword argument `audio_config`. Executing this code +will result in an error. + +```py +response = client.synthesize_speech( + request={ + "input": input_text, + "voice": voice, + }, + audio_config=audio_config +) +``` + + + +## Enums and Types + + +> **WARNING**: Breaking change + +The submodules `enums` and `types` have been removed. + +**Before:** +```py + +from google.cloud import texttospeech + +encoding = texttospeech.enums.AudioEncoding.MP3 +voice = texttospeech.types.VoiceSelectionParams(language_code="en-US") +``` + + +**After:** +```py +from google.cloud import texttospeech + +encoding = texttospeech.AudioEncoding.MP3 +voice = texttospeech.VoiceSelectionParams(language_code="en-US") +``` diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/README.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/README.rst new file mode 120000 index 000000000000..89a0106941ff --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/README.rst @@ -0,0 +1 @@ +../README.rst \ No newline at end of file diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/UPGRADING.md b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/UPGRADING.md new file mode 120000 index 000000000000..01097c8c0fb8 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/UPGRADING.md @@ -0,0 +1 @@ +../UPGRADING.md \ No newline at end of file diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/_static/custom.css b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/_static/custom.css new file mode 100644 index 000000000000..b0a295464b23 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/_static/custom.css @@ -0,0 +1,20 @@ +div#python2-eol { + border-color: red; + border-width: medium; +} + +/* Ensure minimum width for 'Parameters' / 'Returns' column */ +dl.field-list > dt { + min-width: 100px +} + +/* Insert space between methods for readability */ +dl.method { + padding-top: 10px; + padding-bottom: 10px +} + +/* Insert empty space between classes */ +dl.class { + padding-bottom: 50px +} diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/_templates/layout.html b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/_templates/layout.html new file mode 100644 index 000000000000..6316a537f72b --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/_templates/layout.html @@ -0,0 +1,50 @@ + +{% extends "!layout.html" %} +{%- block content %} +{%- if theme_fixed_sidebar|lower == 'true' %} +
+ {{ sidebar() }} + {%- block document %} +
+ {%- if render_sidebar %} +
+ {%- endif %} + + {%- block relbar_top %} + {%- if theme_show_relbar_top|tobool %} + + {%- endif %} + {% endblock %} + +
+
+ As of January 1, 2020 this library no longer supports Python 2 on the latest released version. + Library versions released prior to that date will continue to be available. For more information please + visit Python 2 support on Google Cloud. +
+ {% block body %} {% endblock %} +
+ + {%- block relbar_bottom %} + {%- if theme_show_relbar_bottom|tobool %} + + {%- endif %} + {% endblock %} + + {%- if render_sidebar %} +
+ {%- endif %} +
+ {%- endblock %} +
+
+{%- else %} +{{ super() }} +{%- endif %} +{%- endblock %} diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/changelog.md b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/changelog.md new file mode 120000 index 000000000000..04c99a55caae --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/changelog.md @@ -0,0 +1 @@ +../CHANGELOG.md \ No newline at end of file diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/conf.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/conf.py new file mode 100644 index 000000000000..769307eaa56e --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/conf.py @@ -0,0 +1,384 @@ +# -*- coding: utf-8 -*- +# Copyright 2021 Google LLC +# +# 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. +# +# google-cloud-texttospeech documentation build configuration file +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import os +import shlex +import sys + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +sys.path.insert(0, os.path.abspath("..")) + +# For plugins that can not read conf.py. +# See also: https://github.com/docascode/sphinx-docfx-yaml/issues/85 +sys.path.insert(0, os.path.abspath(".")) + +__version__ = "" + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +needs_sphinx = "1.5.5" + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + "sphinx.ext.autodoc", + "sphinx.ext.autosummary", + "sphinx.ext.intersphinx", + "sphinx.ext.coverage", + "sphinx.ext.doctest", + "sphinx.ext.napoleon", + "sphinx.ext.todo", + "sphinx.ext.viewcode", + "recommonmark", +] + +# autodoc/autosummary flags +autoclass_content = "both" +autodoc_default_options = {"members": True} +autosummary_generate = True + + +# Add any paths that contain templates here, relative to this directory. +templates_path = ["_templates"] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# source_suffix = ['.rst', '.md'] +source_suffix = [".rst", ".md"] + +# The encoding of source files. +# source_encoding = 'utf-8-sig' + +# The root toctree document. +root_doc = "index" + +# General information about the project. +project = "google-cloud-texttospeech" +copyright = "2019, Google" +author = "Google APIs" + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The full version, including alpha/beta/rc tags. +release = __version__ +# The short X.Y version. +version = ".".join(release.split(".")[0:2]) + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +# today = '' +# Else, today_fmt is used as the format for a strftime call. +# today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = [ + "_build", + "**/.nox/**/*", + "samples/AUTHORING_GUIDE.md", + "samples/CONTRIBUTING.md", + "samples/snippets/README.rst", +] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +# default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +# add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +# add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +# show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = "sphinx" + +# A list of ignored prefixes for module index sorting. +# modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +# keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = True + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = "alabaster" + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +html_theme_options = { + "description": "Google Cloud Client Libraries for google-cloud-texttospeech", + "github_user": "googleapis", + "github_repo": "python-texttospeech", + "github_banner": True, + "font_family": "'Roboto', Georgia, sans", + "head_font_family": "'Roboto', Georgia, serif", + "code_font_family": "'Roboto Mono', 'Consolas', monospace", +} + +# Add any paths that contain custom themes here, relative to this directory. +# html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +# html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +# html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +# html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +# html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ["_static"] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +# html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +# html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +# html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +# html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +# html_additional_pages = {} + +# If false, no module index is generated. +# html_domain_indices = True + +# If false, no index is generated. +# html_use_index = True + +# If true, the index is split into individual pages for each letter. +# html_split_index = False + +# If true, links to the reST sources are added to the pages. +# html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +# html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +# html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +# html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +# html_file_suffix = None + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr' +# html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# Now only 'ja' uses this config value +# html_search_options = {'type': 'default'} + +# The name of a javascript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +# html_search_scorer = 'scorer.js' + +# Output file base name for HTML help builder. +htmlhelp_basename = "google-cloud-texttospeech-doc" + +# -- Options for warnings ------------------------------------------------------ + + +suppress_warnings = [ + # Temporarily suppress this to avoid "more than one target found for + # cross-reference" warning, which are intractable for us to avoid while in + # a mono-repo. + # See https://github.com/sphinx-doc/sphinx/blob + # /2a65ffeef5c107c19084fabdd706cdff3f52d93c/sphinx/domains/python.py#L843 + "ref.python" +] + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + #'papersize': 'letterpaper', + # The font size ('10pt', '11pt' or '12pt'). + #'pointsize': '10pt', + # Additional stuff for the LaTeX preamble. + #'preamble': '', + # Latex figure (float) alignment + #'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + ( + root_doc, + "google-cloud-texttospeech.tex", + "google-cloud-texttospeech Documentation", + author, + "manual", + ) +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +# latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +# latex_use_parts = False + +# If true, show page references after internal links. +# latex_show_pagerefs = False + +# If true, show URL addresses after external links. +# latex_show_urls = False + +# Documents to append as an appendix to all manuals. +# latex_appendices = [] + +# If false, no module index is generated. +# latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ( + root_doc, + "google-cloud-texttospeech", + "google-cloud-texttospeech Documentation", + [author], + 1, + ) +] + +# If true, show URL addresses after external links. +# man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ( + root_doc, + "google-cloud-texttospeech", + "google-cloud-texttospeech Documentation", + author, + "google-cloud-texttospeech", + "google-cloud-texttospeech Library", + "APIs", + ) +] + +# Documents to append as an appendix to all manuals. +# texinfo_appendices = [] + +# If false, no module index is generated. +# texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +# texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +# texinfo_no_detailmenu = False + + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = { + "python": ("https://python.readthedocs.org/en/latest/", None), + "google-auth": ("https://googleapis.dev/python/google-auth/latest/", None), + "google.api_core": ( + "https://googleapis.dev/python/google-api-core/latest/", + None, + ), + "grpc": ("https://grpc.github.io/grpc/python/", None), + "proto-plus": ("https://proto-plus-python.readthedocs.io/en/latest/", None), + "protobuf": ("https://googleapis.dev/python/protobuf/latest/", None), +} + + +# Napoleon settings +napoleon_google_docstring = True +napoleon_numpy_docstring = True +napoleon_include_private_with_doc = False +napoleon_include_special_with_doc = True +napoleon_use_admonition_for_examples = False +napoleon_use_admonition_for_notes = False +napoleon_use_admonition_for_references = False +napoleon_use_ivar = False +napoleon_use_param = True +napoleon_use_rtype = True diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/index.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/index.rst new file mode 100644 index 000000000000..316b071e77d0 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/index.rst @@ -0,0 +1,45 @@ +.. include:: README.rst + +.. include:: multiprocessing.rst + +This package includes clients for multiple versions of Google Cloud Text-to-Speech. +By default, you will get version ``texttospeech_v1``. + + +API Reference +------------- +.. toctree:: + :maxdepth: 2 + + texttospeech_v1/services + texttospeech_v1/types + +API Reference +------------- +.. toctree:: + :maxdepth: 2 + + texttospeech_v1beta1/services + texttospeech_v1beta1/types + + +Migration Guide +--------------- + +See the guide below for instructions on migrating to the latest version. + +.. toctree:: + :maxdepth: 2 + +  UPGRADING + + +Changelog +--------- + +For a list of all ``google-cloud-texttospeech`` releases: + +.. toctree:: + :maxdepth: 2 + + changelog diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/multiprocessing.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/multiprocessing.rst new file mode 100644 index 000000000000..536d17b2ea65 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/multiprocessing.rst @@ -0,0 +1,7 @@ +.. note:: + + Because this client uses :mod:`grpc` library, it is safe to + share instances across threads. In multiprocessing scenarios, the best + practice is to create client instances *after* the invocation of + :func:`os.fork` by :class:`multiprocessing.pool.Pool` or + :class:`multiprocessing.Process`. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/texttospeech_v1/services.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/texttospeech_v1/services.rst new file mode 100644 index 000000000000..a77f816765f5 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/texttospeech_v1/services.rst @@ -0,0 +1,6 @@ +Services for Google Cloud Texttospeech v1 API +============================================= +.. toctree:: + :maxdepth: 2 + + text_to_speech diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/texttospeech_v1/text_to_speech.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/texttospeech_v1/text_to_speech.rst new file mode 100644 index 000000000000..2ad3a8e92df5 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/texttospeech_v1/text_to_speech.rst @@ -0,0 +1,6 @@ +TextToSpeech +------------------------------ + +.. automodule:: google.cloud.texttospeech_v1.services.text_to_speech + :members: + :inherited-members: diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/texttospeech_v1/types.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/texttospeech_v1/types.rst new file mode 100644 index 000000000000..646ebdc95702 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/texttospeech_v1/types.rst @@ -0,0 +1,7 @@ +Types for Google Cloud Texttospeech v1 API +========================================== + +.. automodule:: google.cloud.texttospeech_v1.types + :members: + :undoc-members: + :show-inheritance: diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/texttospeech_v1beta1/services.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/texttospeech_v1beta1/services.rst new file mode 100644 index 000000000000..67852d055ac2 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/texttospeech_v1beta1/services.rst @@ -0,0 +1,6 @@ +Services for Google Cloud Texttospeech v1beta1 API +================================================== +.. toctree:: + :maxdepth: 2 + + text_to_speech diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/texttospeech_v1beta1/text_to_speech.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/texttospeech_v1beta1/text_to_speech.rst new file mode 100644 index 000000000000..8521daf8070a --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/texttospeech_v1beta1/text_to_speech.rst @@ -0,0 +1,6 @@ +TextToSpeech +------------------------------ + +.. automodule:: google.cloud.texttospeech_v1beta1.services.text_to_speech + :members: + :inherited-members: diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/texttospeech_v1beta1/types.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/texttospeech_v1beta1/types.rst new file mode 100644 index 000000000000..0306c6cdcb4a --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/docs/texttospeech_v1beta1/types.rst @@ -0,0 +1,7 @@ +Types for Google Cloud Texttospeech v1beta1 API +=============================================== + +.. automodule:: google.cloud.texttospeech_v1beta1.types + :members: + :undoc-members: + :show-inheritance: diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech/__init__.py new file mode 100644 index 000000000000..9b09ec2f8da8 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech/__init__.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# + +from google.cloud.texttospeech_v1.services.text_to_speech.async_client import ( + TextToSpeechAsyncClient, +) +from google.cloud.texttospeech_v1.services.text_to_speech.client import ( + TextToSpeechClient, +) +from google.cloud.texttospeech_v1.types.cloud_tts import ( + AudioConfig, + AudioEncoding, + CustomVoiceParams, + ListVoicesRequest, + ListVoicesResponse, + SsmlVoiceGender, + SynthesisInput, + SynthesizeSpeechRequest, + SynthesizeSpeechResponse, + Voice, + VoiceSelectionParams, +) + +__all__ = ( + "TextToSpeechClient", + "TextToSpeechAsyncClient", + "AudioConfig", + "CustomVoiceParams", + "ListVoicesRequest", + "ListVoicesResponse", + "SynthesisInput", + "SynthesizeSpeechRequest", + "SynthesizeSpeechResponse", + "Voice", + "VoiceSelectionParams", + "AudioEncoding", + "SsmlVoiceGender", +) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech/py.typed b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech/py.typed new file mode 100644 index 000000000000..9b87c1e1cbf9 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech/py.typed @@ -0,0 +1,2 @@ +# Marker file for PEP 561. +# The google-cloud-texttospeech package uses inline types. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/__init__.py new file mode 100644 index 000000000000..8d191f15ded8 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/__init__.py @@ -0,0 +1,46 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# + +from .services.text_to_speech import TextToSpeechAsyncClient, TextToSpeechClient +from .types.cloud_tts import ( + AudioConfig, + AudioEncoding, + CustomVoiceParams, + ListVoicesRequest, + ListVoicesResponse, + SsmlVoiceGender, + SynthesisInput, + SynthesizeSpeechRequest, + SynthesizeSpeechResponse, + Voice, + VoiceSelectionParams, +) + +__all__ = ( + "TextToSpeechAsyncClient", + "AudioConfig", + "AudioEncoding", + "CustomVoiceParams", + "ListVoicesRequest", + "ListVoicesResponse", + "SsmlVoiceGender", + "SynthesisInput", + "SynthesizeSpeechRequest", + "SynthesizeSpeechResponse", + "TextToSpeechClient", + "Voice", + "VoiceSelectionParams", +) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/gapic_metadata.json b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/gapic_metadata.json new file mode 100644 index 000000000000..f9c0c9bd6f4a --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/gapic_metadata.json @@ -0,0 +1,43 @@ + { + "comment": "This file maps proto services/RPCs to the corresponding library clients/methods", + "language": "python", + "libraryPackage": "google.cloud.texttospeech_v1", + "protoPackage": "google.cloud.texttospeech.v1", + "schema": "1.0", + "services": { + "TextToSpeech": { + "clients": { + "grpc": { + "libraryClient": "TextToSpeechClient", + "rpcs": { + "ListVoices": { + "methods": [ + "list_voices" + ] + }, + "SynthesizeSpeech": { + "methods": [ + "synthesize_speech" + ] + } + } + }, + "grpc-async": { + "libraryClient": "TextToSpeechAsyncClient", + "rpcs": { + "ListVoices": { + "methods": [ + "list_voices" + ] + }, + "SynthesizeSpeech": { + "methods": [ + "synthesize_speech" + ] + } + } + } + } + } + } +} diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/py.typed b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/py.typed new file mode 100644 index 000000000000..9b87c1e1cbf9 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/py.typed @@ -0,0 +1,2 @@ +# Marker file for PEP 561. +# The google-cloud-texttospeech package uses inline types. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/__init__.py similarity index 77% rename from packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/__init__.py rename to packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/__init__.py index 93af25cd734c..e8e1c3845db5 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/__init__.py +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/__init__.py @@ -1,18 +1,15 @@ -# Copyright 2021 Google LLC +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC # # 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 +# 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. - -# coding: utf-8 - -""" Package used for namespace package test. -""" \ No newline at end of file +# diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/__init__.py new file mode 100644 index 000000000000..f70edab7c5c7 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +from .async_client import TextToSpeechAsyncClient +from .client import TextToSpeechClient + +__all__ = ( + "TextToSpeechClient", + "TextToSpeechAsyncClient", +) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/async_client.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/async_client.py new file mode 100644 index 000000000000..c243fbc18822 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/async_client.py @@ -0,0 +1,448 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +from collections import OrderedDict +import functools +import re +from typing import Dict, Mapping, Optional, Sequence, Tuple, Type, Union + +from google.api_core import exceptions as core_exceptions +from google.api_core import gapic_v1 +from google.api_core import retry as retries +from google.api_core.client_options import ClientOptions +from google.auth import credentials as ga_credentials # type: ignore +from google.oauth2 import service_account # type: ignore +import pkg_resources + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + +from google.cloud.texttospeech_v1.types import cloud_tts + +from .client import TextToSpeechClient +from .transports.base import DEFAULT_CLIENT_INFO, TextToSpeechTransport +from .transports.grpc_asyncio import TextToSpeechGrpcAsyncIOTransport + + +class TextToSpeechAsyncClient: + """Service that implements Google Cloud Text-to-Speech API.""" + + _client: TextToSpeechClient + + DEFAULT_ENDPOINT = TextToSpeechClient.DEFAULT_ENDPOINT + DEFAULT_MTLS_ENDPOINT = TextToSpeechClient.DEFAULT_MTLS_ENDPOINT + + model_path = staticmethod(TextToSpeechClient.model_path) + parse_model_path = staticmethod(TextToSpeechClient.parse_model_path) + common_billing_account_path = staticmethod( + TextToSpeechClient.common_billing_account_path + ) + parse_common_billing_account_path = staticmethod( + TextToSpeechClient.parse_common_billing_account_path + ) + common_folder_path = staticmethod(TextToSpeechClient.common_folder_path) + parse_common_folder_path = staticmethod(TextToSpeechClient.parse_common_folder_path) + common_organization_path = staticmethod(TextToSpeechClient.common_organization_path) + parse_common_organization_path = staticmethod( + TextToSpeechClient.parse_common_organization_path + ) + common_project_path = staticmethod(TextToSpeechClient.common_project_path) + parse_common_project_path = staticmethod( + TextToSpeechClient.parse_common_project_path + ) + common_location_path = staticmethod(TextToSpeechClient.common_location_path) + parse_common_location_path = staticmethod( + TextToSpeechClient.parse_common_location_path + ) + + @classmethod + def from_service_account_info(cls, info: dict, *args, **kwargs): + """Creates an instance of this client using the provided credentials + info. + + Args: + info (dict): The service account private key info. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + TextToSpeechAsyncClient: The constructed client. + """ + return TextToSpeechClient.from_service_account_info.__func__(TextToSpeechAsyncClient, info, *args, **kwargs) # type: ignore + + @classmethod + def from_service_account_file(cls, filename: str, *args, **kwargs): + """Creates an instance of this client using the provided credentials + file. + + Args: + filename (str): The path to the service account private key json + file. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + TextToSpeechAsyncClient: The constructed client. + """ + return TextToSpeechClient.from_service_account_file.__func__(TextToSpeechAsyncClient, filename, *args, **kwargs) # type: ignore + + from_service_account_json = from_service_account_file + + @classmethod + def get_mtls_endpoint_and_cert_source( + cls, client_options: Optional[ClientOptions] = None + ): + """Return the API endpoint and client cert source for mutual TLS. + + The client cert source is determined in the following order: + (1) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not "true", the + client cert source is None. + (2) if `client_options.client_cert_source` is provided, use the provided one; if the + default client cert source exists, use the default one; otherwise the client cert + source is None. + + The API endpoint is determined in the following order: + (1) if `client_options.api_endpoint` if provided, use the provided one. + (2) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is "always", use the + default mTLS endpoint; if the environment variabel is "never", use the default API + endpoint; otherwise if client cert source exists, use the default mTLS endpoint, otherwise + use the default API endpoint. + + More details can be found at https://google.aip.dev/auth/4114. + + Args: + client_options (google.api_core.client_options.ClientOptions): Custom options for the + client. Only the `api_endpoint` and `client_cert_source` properties may be used + in this method. + + Returns: + Tuple[str, Callable[[], Tuple[bytes, bytes]]]: returns the API endpoint and the + client cert source to use. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If any errors happen. + """ + return TextToSpeechClient.get_mtls_endpoint_and_cert_source(client_options) # type: ignore + + @property + def transport(self) -> TextToSpeechTransport: + """Returns the transport used by the client instance. + + Returns: + TextToSpeechTransport: The transport used by the client instance. + """ + return self._client.transport + + get_transport_class = functools.partial( + type(TextToSpeechClient).get_transport_class, type(TextToSpeechClient) + ) + + def __init__( + self, + *, + credentials: ga_credentials.Credentials = None, + transport: Union[str, TextToSpeechTransport] = "grpc_asyncio", + client_options: ClientOptions = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + ) -> None: + """Instantiates the text to speech client. + + Args: + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + transport (Union[str, ~.TextToSpeechTransport]): The + transport to use. If set to None, a transport is chosen + automatically. + client_options (ClientOptions): Custom options for the client. It + won't take effect if a ``transport`` instance is provided. + (1) The ``api_endpoint`` property can be used to override the + default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT + environment variable can also be used to override the endpoint: + "always" (always use the default mTLS endpoint), "never" (always + use the default regular endpoint) and "auto" (auto switch to the + default mTLS endpoint if client certificate is present, this is + the default value). However, the ``api_endpoint`` property takes + precedence if provided. + (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable + is "true", then the ``client_cert_source`` property can be used + to provide client certificate for mutual TLS transport. If + not provided, the default SSL client certificate will be used if + present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not + set, no client certificate will be used. + + Raises: + google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport + creation failed for any reason. + """ + self._client = TextToSpeechClient( + credentials=credentials, + transport=transport, + client_options=client_options, + client_info=client_info, + ) + + async def list_voices( + self, + request: Union[cloud_tts.ListVoicesRequest, dict] = None, + *, + language_code: str = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> cloud_tts.ListVoicesResponse: + r"""Returns a list of Voice supported for synthesis. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google.cloud import texttospeech_v1 + + async def sample_list_voices(): + # Create a client + client = texttospeech_v1.TextToSpeechAsyncClient() + + # Initialize request argument(s) + request = texttospeech_v1.ListVoicesRequest( + ) + + # Make the request + response = await client.list_voices(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.cloud.texttospeech_v1.types.ListVoicesRequest, dict]): + The request object. The top-level message sent by the + client for the `ListVoices` method. + language_code (:class:`str`): + Optional. Recommended. + `BCP-47 `__ + language tag. If not specified, the API will return all + supported voices. If specified, the ListVoices call will + only return voices that can be used to synthesize this + language_code. For example, if you specify ``"en-NZ"``, + all ``"en-NZ"`` voices will be returned. If you specify + ``"no"``, both ``"no-\*"`` (Norwegian) and ``"nb-\*"`` + (Norwegian Bokmal) voices will be returned. + + This corresponds to the ``language_code`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.texttospeech_v1.types.ListVoicesResponse: + The message returned to the client by the ListVoices + method. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([language_code]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = cloud_tts.ListVoicesRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if language_code is not None: + request.language_code = language_code + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.list_voices, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def synthesize_speech( + self, + request: Union[cloud_tts.SynthesizeSpeechRequest, dict] = None, + *, + input: cloud_tts.SynthesisInput = None, + voice: cloud_tts.VoiceSelectionParams = None, + audio_config: cloud_tts.AudioConfig = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> cloud_tts.SynthesizeSpeechResponse: + r"""Synthesizes speech synchronously: receive results + after all text input has been processed. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google.cloud import texttospeech_v1 + + async def sample_synthesize_speech(): + # Create a client + client = texttospeech_v1.TextToSpeechAsyncClient() + + # Initialize request argument(s) + input = texttospeech_v1.SynthesisInput() + input.text = "text_value" + + voice = texttospeech_v1.VoiceSelectionParams() + voice.language_code = "language_code_value" + + audio_config = texttospeech_v1.AudioConfig() + audio_config.audio_encoding = "ALAW" + + request = texttospeech_v1.SynthesizeSpeechRequest( + input=input, + voice=voice, + audio_config=audio_config, + ) + + # Make the request + response = await client.synthesize_speech(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.cloud.texttospeech_v1.types.SynthesizeSpeechRequest, dict]): + The request object. The top-level message sent by the + client for the `SynthesizeSpeech` method. + input (:class:`google.cloud.texttospeech_v1.types.SynthesisInput`): + Required. The Synthesizer requires + either plain text or SSML as input. + + This corresponds to the ``input`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + voice (:class:`google.cloud.texttospeech_v1.types.VoiceSelectionParams`): + Required. The desired voice of the + synthesized audio. + + This corresponds to the ``voice`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + audio_config (:class:`google.cloud.texttospeech_v1.types.AudioConfig`): + Required. The configuration of the + synthesized audio. + + This corresponds to the ``audio_config`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.texttospeech_v1.types.SynthesizeSpeechResponse: + The message returned to the client by the + SynthesizeSpeech method. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([input, voice, audio_config]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = cloud_tts.SynthesizeSpeechRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if input is not None: + request.input = input + if voice is not None: + request.voice = voice + if audio_config is not None: + request.audio_config = audio_config + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.synthesize_speech, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc, tb): + await self.transport.close() + + +try: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=pkg_resources.get_distribution( + "google-cloud-texttospeech", + ).version, + ) +except pkg_resources.DistributionNotFound: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() + + +__all__ = ("TextToSpeechAsyncClient",) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py new file mode 100644 index 000000000000..4ad59c0b6413 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py @@ -0,0 +1,682 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +from collections import OrderedDict +import os +import re +from typing import Dict, Mapping, Optional, Sequence, Tuple, Type, Union + +from google.api_core import client_options as client_options_lib +from google.api_core import exceptions as core_exceptions +from google.api_core import gapic_v1 +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.exceptions import MutualTLSChannelError # type: ignore +from google.auth.transport import mtls # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.oauth2 import service_account # type: ignore +import pkg_resources + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + +from google.cloud.texttospeech_v1.types import cloud_tts + +from .transports.base import DEFAULT_CLIENT_INFO, TextToSpeechTransport +from .transports.grpc import TextToSpeechGrpcTransport +from .transports.grpc_asyncio import TextToSpeechGrpcAsyncIOTransport + + +class TextToSpeechClientMeta(type): + """Metaclass for the TextToSpeech client. + + This provides class-level methods for building and retrieving + support objects (e.g. transport) without polluting the client instance + objects. + """ + + _transport_registry = OrderedDict() # type: Dict[str, Type[TextToSpeechTransport]] + _transport_registry["grpc"] = TextToSpeechGrpcTransport + _transport_registry["grpc_asyncio"] = TextToSpeechGrpcAsyncIOTransport + + def get_transport_class( + cls, + label: str = None, + ) -> Type[TextToSpeechTransport]: + """Returns an appropriate transport class. + + Args: + label: The name of the desired transport. If none is + provided, then the first transport in the registry is used. + + Returns: + The transport class to use. + """ + # If a specific transport is requested, return that one. + if label: + return cls._transport_registry[label] + + # No transport is requested; return the default (that is, the first one + # in the dictionary). + return next(iter(cls._transport_registry.values())) + + +class TextToSpeechClient(metaclass=TextToSpeechClientMeta): + """Service that implements Google Cloud Text-to-Speech API.""" + + @staticmethod + def _get_default_mtls_endpoint(api_endpoint): + """Converts api endpoint to mTLS endpoint. + + Convert "*.sandbox.googleapis.com" and "*.googleapis.com" to + "*.mtls.sandbox.googleapis.com" and "*.mtls.googleapis.com" respectively. + Args: + api_endpoint (Optional[str]): the api endpoint to convert. + Returns: + str: converted mTLS api endpoint. + """ + if not api_endpoint: + return api_endpoint + + mtls_endpoint_re = re.compile( + r"(?P[^.]+)(?P\.mtls)?(?P\.sandbox)?(?P\.googleapis\.com)?" + ) + + m = mtls_endpoint_re.match(api_endpoint) + name, mtls, sandbox, googledomain = m.groups() + if mtls or not googledomain: + return api_endpoint + + if sandbox: + return api_endpoint.replace( + "sandbox.googleapis.com", "mtls.sandbox.googleapis.com" + ) + + return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com") + + DEFAULT_ENDPOINT = "texttospeech.googleapis.com" + DEFAULT_MTLS_ENDPOINT = _get_default_mtls_endpoint.__func__( # type: ignore + DEFAULT_ENDPOINT + ) + + @classmethod + def from_service_account_info(cls, info: dict, *args, **kwargs): + """Creates an instance of this client using the provided credentials + info. + + Args: + info (dict): The service account private key info. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + TextToSpeechClient: The constructed client. + """ + credentials = service_account.Credentials.from_service_account_info(info) + kwargs["credentials"] = credentials + return cls(*args, **kwargs) + + @classmethod + def from_service_account_file(cls, filename: str, *args, **kwargs): + """Creates an instance of this client using the provided credentials + file. + + Args: + filename (str): The path to the service account private key json + file. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + TextToSpeechClient: The constructed client. + """ + credentials = service_account.Credentials.from_service_account_file(filename) + kwargs["credentials"] = credentials + return cls(*args, **kwargs) + + from_service_account_json = from_service_account_file + + @property + def transport(self) -> TextToSpeechTransport: + """Returns the transport used by the client instance. + + Returns: + TextToSpeechTransport: The transport used by the client + instance. + """ + return self._transport + + @staticmethod + def model_path( + project: str, + location: str, + model: str, + ) -> str: + """Returns a fully-qualified model string.""" + return "projects/{project}/locations/{location}/models/{model}".format( + project=project, + location=location, + model=model, + ) + + @staticmethod + def parse_model_path(path: str) -> Dict[str, str]: + """Parses a model path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/locations/(?P.+?)/models/(?P.+?)$", + path, + ) + return m.groupdict() if m else {} + + @staticmethod + def common_billing_account_path( + billing_account: str, + ) -> str: + """Returns a fully-qualified billing_account string.""" + return "billingAccounts/{billing_account}".format( + billing_account=billing_account, + ) + + @staticmethod + def parse_common_billing_account_path(path: str) -> Dict[str, str]: + """Parse a billing_account path into its component segments.""" + m = re.match(r"^billingAccounts/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_folder_path( + folder: str, + ) -> str: + """Returns a fully-qualified folder string.""" + return "folders/{folder}".format( + folder=folder, + ) + + @staticmethod + def parse_common_folder_path(path: str) -> Dict[str, str]: + """Parse a folder path into its component segments.""" + m = re.match(r"^folders/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_organization_path( + organization: str, + ) -> str: + """Returns a fully-qualified organization string.""" + return "organizations/{organization}".format( + organization=organization, + ) + + @staticmethod + def parse_common_organization_path(path: str) -> Dict[str, str]: + """Parse a organization path into its component segments.""" + m = re.match(r"^organizations/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_project_path( + project: str, + ) -> str: + """Returns a fully-qualified project string.""" + return "projects/{project}".format( + project=project, + ) + + @staticmethod + def parse_common_project_path(path: str) -> Dict[str, str]: + """Parse a project path into its component segments.""" + m = re.match(r"^projects/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_location_path( + project: str, + location: str, + ) -> str: + """Returns a fully-qualified location string.""" + return "projects/{project}/locations/{location}".format( + project=project, + location=location, + ) + + @staticmethod + def parse_common_location_path(path: str) -> Dict[str, str]: + """Parse a location path into its component segments.""" + m = re.match(r"^projects/(?P.+?)/locations/(?P.+?)$", path) + return m.groupdict() if m else {} + + @classmethod + def get_mtls_endpoint_and_cert_source( + cls, client_options: Optional[client_options_lib.ClientOptions] = None + ): + """Return the API endpoint and client cert source for mutual TLS. + + The client cert source is determined in the following order: + (1) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not "true", the + client cert source is None. + (2) if `client_options.client_cert_source` is provided, use the provided one; if the + default client cert source exists, use the default one; otherwise the client cert + source is None. + + The API endpoint is determined in the following order: + (1) if `client_options.api_endpoint` if provided, use the provided one. + (2) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is "always", use the + default mTLS endpoint; if the environment variabel is "never", use the default API + endpoint; otherwise if client cert source exists, use the default mTLS endpoint, otherwise + use the default API endpoint. + + More details can be found at https://google.aip.dev/auth/4114. + + Args: + client_options (google.api_core.client_options.ClientOptions): Custom options for the + client. Only the `api_endpoint` and `client_cert_source` properties may be used + in this method. + + Returns: + Tuple[str, Callable[[], Tuple[bytes, bytes]]]: returns the API endpoint and the + client cert source to use. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If any errors happen. + """ + if client_options is None: + client_options = client_options_lib.ClientOptions() + use_client_cert = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false") + use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto") + if use_client_cert not in ("true", "false"): + raise ValueError( + "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`" + ) + if use_mtls_endpoint not in ("auto", "never", "always"): + raise MutualTLSChannelError( + "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`" + ) + + # Figure out the client cert source to use. + client_cert_source = None + if use_client_cert == "true": + if client_options.client_cert_source: + client_cert_source = client_options.client_cert_source + elif mtls.has_default_client_cert_source(): + client_cert_source = mtls.default_client_cert_source() + + # Figure out which api endpoint to use. + if client_options.api_endpoint is not None: + api_endpoint = client_options.api_endpoint + elif use_mtls_endpoint == "always" or ( + use_mtls_endpoint == "auto" and client_cert_source + ): + api_endpoint = cls.DEFAULT_MTLS_ENDPOINT + else: + api_endpoint = cls.DEFAULT_ENDPOINT + + return api_endpoint, client_cert_source + + def __init__( + self, + *, + credentials: Optional[ga_credentials.Credentials] = None, + transport: Union[str, TextToSpeechTransport, None] = None, + client_options: Optional[client_options_lib.ClientOptions] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + ) -> None: + """Instantiates the text to speech client. + + Args: + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + transport (Union[str, TextToSpeechTransport]): The + transport to use. If set to None, a transport is chosen + automatically. + client_options (google.api_core.client_options.ClientOptions): Custom options for the + client. It won't take effect if a ``transport`` instance is provided. + (1) The ``api_endpoint`` property can be used to override the + default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT + environment variable can also be used to override the endpoint: + "always" (always use the default mTLS endpoint), "never" (always + use the default regular endpoint) and "auto" (auto switch to the + default mTLS endpoint if client certificate is present, this is + the default value). However, the ``api_endpoint`` property takes + precedence if provided. + (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable + is "true", then the ``client_cert_source`` property can be used + to provide client certificate for mutual TLS transport. If + not provided, the default SSL client certificate will be used if + present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not + set, no client certificate will be used. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport + creation failed for any reason. + """ + if isinstance(client_options, dict): + client_options = client_options_lib.from_dict(client_options) + if client_options is None: + client_options = client_options_lib.ClientOptions() + + api_endpoint, client_cert_source_func = self.get_mtls_endpoint_and_cert_source( + client_options + ) + + api_key_value = getattr(client_options, "api_key", None) + if api_key_value and credentials: + raise ValueError( + "client_options.api_key and credentials are mutually exclusive" + ) + + # Save or instantiate the transport. + # Ordinarily, we provide the transport, but allowing a custom transport + # instance provides an extensibility point for unusual situations. + if isinstance(transport, TextToSpeechTransport): + # transport is a TextToSpeechTransport instance. + if credentials or client_options.credentials_file or api_key_value: + raise ValueError( + "When providing a transport instance, " + "provide its credentials directly." + ) + if client_options.scopes: + raise ValueError( + "When providing a transport instance, provide its scopes " + "directly." + ) + self._transport = transport + else: + import google.auth._default # type: ignore + + if api_key_value and hasattr( + google.auth._default, "get_api_key_credentials" + ): + credentials = google.auth._default.get_api_key_credentials( + api_key_value + ) + + Transport = type(self).get_transport_class(transport) + self._transport = Transport( + credentials=credentials, + credentials_file=client_options.credentials_file, + host=api_endpoint, + scopes=client_options.scopes, + client_cert_source_for_mtls=client_cert_source_func, + quota_project_id=client_options.quota_project_id, + client_info=client_info, + always_use_jwt_access=True, + api_audience=client_options.api_audience, + ) + + def list_voices( + self, + request: Union[cloud_tts.ListVoicesRequest, dict] = None, + *, + language_code: str = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> cloud_tts.ListVoicesResponse: + r"""Returns a list of Voice supported for synthesis. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google.cloud import texttospeech_v1 + + def sample_list_voices(): + # Create a client + client = texttospeech_v1.TextToSpeechClient() + + # Initialize request argument(s) + request = texttospeech_v1.ListVoicesRequest( + ) + + # Make the request + response = client.list_voices(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.cloud.texttospeech_v1.types.ListVoicesRequest, dict]): + The request object. The top-level message sent by the + client for the `ListVoices` method. + language_code (str): + Optional. Recommended. + `BCP-47 `__ + language tag. If not specified, the API will return all + supported voices. If specified, the ListVoices call will + only return voices that can be used to synthesize this + language_code. For example, if you specify ``"en-NZ"``, + all ``"en-NZ"`` voices will be returned. If you specify + ``"no"``, both ``"no-\*"`` (Norwegian) and ``"nb-\*"`` + (Norwegian Bokmal) voices will be returned. + + This corresponds to the ``language_code`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.texttospeech_v1.types.ListVoicesResponse: + The message returned to the client by the ListVoices + method. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([language_code]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a cloud_tts.ListVoicesRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, cloud_tts.ListVoicesRequest): + request = cloud_tts.ListVoicesRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if language_code is not None: + request.language_code = language_code + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.list_voices] + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def synthesize_speech( + self, + request: Union[cloud_tts.SynthesizeSpeechRequest, dict] = None, + *, + input: cloud_tts.SynthesisInput = None, + voice: cloud_tts.VoiceSelectionParams = None, + audio_config: cloud_tts.AudioConfig = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> cloud_tts.SynthesizeSpeechResponse: + r"""Synthesizes speech synchronously: receive results + after all text input has been processed. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google.cloud import texttospeech_v1 + + def sample_synthesize_speech(): + # Create a client + client = texttospeech_v1.TextToSpeechClient() + + # Initialize request argument(s) + input = texttospeech_v1.SynthesisInput() + input.text = "text_value" + + voice = texttospeech_v1.VoiceSelectionParams() + voice.language_code = "language_code_value" + + audio_config = texttospeech_v1.AudioConfig() + audio_config.audio_encoding = "ALAW" + + request = texttospeech_v1.SynthesizeSpeechRequest( + input=input, + voice=voice, + audio_config=audio_config, + ) + + # Make the request + response = client.synthesize_speech(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.cloud.texttospeech_v1.types.SynthesizeSpeechRequest, dict]): + The request object. The top-level message sent by the + client for the `SynthesizeSpeech` method. + input (google.cloud.texttospeech_v1.types.SynthesisInput): + Required. The Synthesizer requires + either plain text or SSML as input. + + This corresponds to the ``input`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + voice (google.cloud.texttospeech_v1.types.VoiceSelectionParams): + Required. The desired voice of the + synthesized audio. + + This corresponds to the ``voice`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + audio_config (google.cloud.texttospeech_v1.types.AudioConfig): + Required. The configuration of the + synthesized audio. + + This corresponds to the ``audio_config`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.texttospeech_v1.types.SynthesizeSpeechResponse: + The message returned to the client by the + SynthesizeSpeech method. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([input, voice, audio_config]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a cloud_tts.SynthesizeSpeechRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, cloud_tts.SynthesizeSpeechRequest): + request = cloud_tts.SynthesizeSpeechRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if input is not None: + request.input = input + if voice is not None: + request.voice = voice + if audio_config is not None: + request.audio_config = audio_config + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.synthesize_speech] + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def __enter__(self): + return self + + def __exit__(self, type, value, traceback): + """Releases underlying transport's resources. + + .. warning:: + ONLY use as a context manager if the transport is NOT shared + with other clients! Exiting the with block will CLOSE the transport + and may cause errors in other clients! + """ + self.transport.close() + + +try: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=pkg_resources.get_distribution( + "google-cloud-texttospeech", + ).version, + ) +except pkg_resources.DistributionNotFound: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() + + +__all__ = ("TextToSpeechClient",) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/transports/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/transports/__init__.py new file mode 100644 index 000000000000..9a13500994d8 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/transports/__init__.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +from collections import OrderedDict +from typing import Dict, Type + +from .base import TextToSpeechTransport +from .grpc import TextToSpeechGrpcTransport +from .grpc_asyncio import TextToSpeechGrpcAsyncIOTransport + +# Compile a registry of transports. +_transport_registry = OrderedDict() # type: Dict[str, Type[TextToSpeechTransport]] +_transport_registry["grpc"] = TextToSpeechGrpcTransport +_transport_registry["grpc_asyncio"] = TextToSpeechGrpcAsyncIOTransport + +__all__ = ( + "TextToSpeechTransport", + "TextToSpeechGrpcTransport", + "TextToSpeechGrpcAsyncIOTransport", +) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/transports/base.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/transports/base.py new file mode 100644 index 000000000000..93ee86f7b929 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/transports/base.py @@ -0,0 +1,177 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +import abc +from typing import Awaitable, Callable, Dict, Optional, Sequence, Union + +import google.api_core +from google.api_core import exceptions as core_exceptions +from google.api_core import gapic_v1 +from google.api_core import retry as retries +import google.auth # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.oauth2 import service_account # type: ignore +import pkg_resources + +from google.cloud.texttospeech_v1.types import cloud_tts + +try: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=pkg_resources.get_distribution( + "google-cloud-texttospeech", + ).version, + ) +except pkg_resources.DistributionNotFound: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() + + +class TextToSpeechTransport(abc.ABC): + """Abstract transport class for TextToSpeech.""" + + AUTH_SCOPES = ("https://www.googleapis.com/auth/cloud-platform",) + + DEFAULT_HOST: str = "texttospeech.googleapis.com" + + def __init__( + self, + *, + host: str = DEFAULT_HOST, + credentials: ga_credentials.Credentials = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + api_audience: Optional[str] = None, + **kwargs, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is mutually exclusive with credentials. + scopes (Optional[Sequence[str]]): A list of scopes. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + """ + + scopes_kwargs = {"scopes": scopes, "default_scopes": self.AUTH_SCOPES} + + # Save the scopes. + self._scopes = scopes + + # If no credentials are provided, then determine the appropriate + # defaults. + if credentials and credentials_file: + raise core_exceptions.DuplicateCredentialArgs( + "'credentials_file' and 'credentials' are mutually exclusive" + ) + + if credentials_file is not None: + credentials, _ = google.auth.load_credentials_from_file( + credentials_file, **scopes_kwargs, quota_project_id=quota_project_id + ) + elif credentials is None: + credentials, _ = google.auth.default( + **scopes_kwargs, quota_project_id=quota_project_id + ) + # Don't apply audience if the credentials file passed from user. + if hasattr(credentials, "with_gdch_audience"): + credentials = credentials.with_gdch_audience( + api_audience if api_audience else host + ) + + # If the credentials are service account credentials, then always try to use self signed JWT. + if ( + always_use_jwt_access + and isinstance(credentials, service_account.Credentials) + and hasattr(service_account.Credentials, "with_always_use_jwt_access") + ): + credentials = credentials.with_always_use_jwt_access(True) + + # Save the credentials. + self._credentials = credentials + + # Save the hostname. Default to port 443 (HTTPS) if none is specified. + if ":" not in host: + host += ":443" + self._host = host + + def _prep_wrapped_messages(self, client_info): + # Precompute the wrapped methods. + self._wrapped_methods = { + self.list_voices: gapic_v1.method.wrap_method( + self.list_voices, + default_timeout=None, + client_info=client_info, + ), + self.synthesize_speech: gapic_v1.method.wrap_method( + self.synthesize_speech, + default_timeout=None, + client_info=client_info, + ), + } + + def close(self): + """Closes resources associated with the transport. + + .. warning:: + Only call this method if the transport is NOT shared + with other clients - this may cause errors in other clients! + """ + raise NotImplementedError() + + @property + def list_voices( + self, + ) -> Callable[ + [cloud_tts.ListVoicesRequest], + Union[cloud_tts.ListVoicesResponse, Awaitable[cloud_tts.ListVoicesResponse]], + ]: + raise NotImplementedError() + + @property + def synthesize_speech( + self, + ) -> Callable[ + [cloud_tts.SynthesizeSpeechRequest], + Union[ + cloud_tts.SynthesizeSpeechResponse, + Awaitable[cloud_tts.SynthesizeSpeechResponse], + ], + ]: + raise NotImplementedError() + + @property + def kind(self) -> str: + raise NotImplementedError() + + +__all__ = ("TextToSpeechTransport",) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/transports/grpc.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/transports/grpc.py new file mode 100644 index 000000000000..a6edeb474967 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/transports/grpc.py @@ -0,0 +1,294 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +from typing import Callable, Dict, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import gapic_v1, grpc_helpers +import google.auth # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +import grpc # type: ignore + +from google.cloud.texttospeech_v1.types import cloud_tts + +from .base import DEFAULT_CLIENT_INFO, TextToSpeechTransport + + +class TextToSpeechGrpcTransport(TextToSpeechTransport): + """gRPC backend transport for TextToSpeech. + + Service that implements Google Cloud Text-to-Speech API. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends protocol buffers over the wire using gRPC (which is built on + top of HTTP/2); the ``grpcio`` package must be installed. + """ + + _stubs: Dict[str, Callable] + + def __init__( + self, + *, + host: str = "texttospeech.googleapis.com", + credentials: ga_credentials.Credentials = None, + credentials_file: str = None, + scopes: Sequence[str] = None, + channel: grpc.Channel = None, + api_mtls_endpoint: str = None, + client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, + ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + This argument is ignored if ``channel`` is provided. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + channel (Optional[grpc.Channel]): A ``Channel`` instance through + which to make calls. + api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. + If provided, it overrides the ``host`` argument and tries to create + a mutual TLS channel with client SSL credentials from + ``client_cert_source`` or application default SSL credentials. + client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): + Deprecated. A callback to provide client SSL certificate bytes and + private key bytes, both in PEM format. It is ignored if + ``api_mtls_endpoint`` is None. + ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials + for the grpc channel. It is ignored if ``channel`` is provided. + client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): + A callback to provide client certificate bytes and private key bytes, + both in PEM format. It is used to configure a mutual TLS channel. It is + ignored if ``channel`` or ``ssl_channel_credentials`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport + creation failed for any reason. + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + self._grpc_channel = None + self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} + + if api_mtls_endpoint: + warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning) + if client_cert_source: + warnings.warn("client_cert_source is deprecated", DeprecationWarning) + + if channel: + # Ignore credentials if a channel was passed. + credentials = False + # If a channel was explicitly provided, set it. + self._grpc_channel = channel + self._ssl_channel_credentials = None + + else: + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials + + else: + if client_cert_source_for_mtls and not ssl_channel_credentials: + cert, key = client_cert_source_for_mtls() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + + # The base transport sets the host, credentials and scopes + super().__init__( + host=host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + + if not self._grpc_channel: + self._grpc_channel = type(self).create_channel( + self._host, + # use the credentials which are saved + credentials=self._credentials, + # Set ``credentials_file`` to ``None`` here as + # the credentials that we saved earlier should be used. + credentials_file=None, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, + quota_project_id=quota_project_id, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) + + @classmethod + def create_channel( + cls, + host: str = "texttospeech.googleapis.com", + credentials: ga_credentials.Credentials = None, + credentials_file: str = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + **kwargs, + ) -> grpc.Channel: + """Create and return a gRPC channel object. + Args: + host (Optional[str]): The host for the channel to use. + credentials (Optional[~.Credentials]): The + authorization credentials to attach to requests. These + credentials identify this application to the service. If + none are specified, the client will attempt to ascertain + the credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is mutually exclusive with credentials. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + kwargs (Optional[dict]): Keyword arguments, which are passed to the + channel creation. + Returns: + grpc.Channel: A gRPC channel object. + + Raises: + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + + return grpc_helpers.create_channel( + host, + credentials=credentials, + credentials_file=credentials_file, + quota_project_id=quota_project_id, + default_scopes=cls.AUTH_SCOPES, + scopes=scopes, + default_host=cls.DEFAULT_HOST, + **kwargs, + ) + + @property + def grpc_channel(self) -> grpc.Channel: + """Return the channel designed to connect to this service.""" + return self._grpc_channel + + @property + def list_voices( + self, + ) -> Callable[[cloud_tts.ListVoicesRequest], cloud_tts.ListVoicesResponse]: + r"""Return a callable for the list voices method over gRPC. + + Returns a list of Voice supported for synthesis. + + Returns: + Callable[[~.ListVoicesRequest], + ~.ListVoicesResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_voices" not in self._stubs: + self._stubs["list_voices"] = self.grpc_channel.unary_unary( + "/google.cloud.texttospeech.v1.TextToSpeech/ListVoices", + request_serializer=cloud_tts.ListVoicesRequest.serialize, + response_deserializer=cloud_tts.ListVoicesResponse.deserialize, + ) + return self._stubs["list_voices"] + + @property + def synthesize_speech( + self, + ) -> Callable[ + [cloud_tts.SynthesizeSpeechRequest], cloud_tts.SynthesizeSpeechResponse + ]: + r"""Return a callable for the synthesize speech method over gRPC. + + Synthesizes speech synchronously: receive results + after all text input has been processed. + + Returns: + Callable[[~.SynthesizeSpeechRequest], + ~.SynthesizeSpeechResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "synthesize_speech" not in self._stubs: + self._stubs["synthesize_speech"] = self.grpc_channel.unary_unary( + "/google.cloud.texttospeech.v1.TextToSpeech/SynthesizeSpeech", + request_serializer=cloud_tts.SynthesizeSpeechRequest.serialize, + response_deserializer=cloud_tts.SynthesizeSpeechResponse.deserialize, + ) + return self._stubs["synthesize_speech"] + + def close(self): + self.grpc_channel.close() + + @property + def kind(self) -> str: + return "grpc" + + +__all__ = ("TextToSpeechGrpcTransport",) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/transports/grpc_asyncio.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/transports/grpc_asyncio.py new file mode 100644 index 000000000000..e7d304cd44f5 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/transports/grpc_asyncio.py @@ -0,0 +1,296 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +from typing import Awaitable, Callable, Dict, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import gapic_v1, grpc_helpers_async +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +import grpc # type: ignore +from grpc.experimental import aio # type: ignore + +from google.cloud.texttospeech_v1.types import cloud_tts + +from .base import DEFAULT_CLIENT_INFO, TextToSpeechTransport +from .grpc import TextToSpeechGrpcTransport + + +class TextToSpeechGrpcAsyncIOTransport(TextToSpeechTransport): + """gRPC AsyncIO backend transport for TextToSpeech. + + Service that implements Google Cloud Text-to-Speech API. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends protocol buffers over the wire using gRPC (which is built on + top of HTTP/2); the ``grpcio`` package must be installed. + """ + + _grpc_channel: aio.Channel + _stubs: Dict[str, Callable] = {} + + @classmethod + def create_channel( + cls, + host: str = "texttospeech.googleapis.com", + credentials: ga_credentials.Credentials = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + **kwargs, + ) -> aio.Channel: + """Create and return a gRPC AsyncIO channel object. + Args: + host (Optional[str]): The host for the channel to use. + credentials (Optional[~.Credentials]): The + authorization credentials to attach to requests. These + credentials identify this application to the service. If + none are specified, the client will attempt to ascertain + the credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + kwargs (Optional[dict]): Keyword arguments, which are passed to the + channel creation. + Returns: + aio.Channel: A gRPC AsyncIO channel object. + """ + + return grpc_helpers_async.create_channel( + host, + credentials=credentials, + credentials_file=credentials_file, + quota_project_id=quota_project_id, + default_scopes=cls.AUTH_SCOPES, + scopes=scopes, + default_host=cls.DEFAULT_HOST, + **kwargs, + ) + + def __init__( + self, + *, + host: str = "texttospeech.googleapis.com", + credentials: ga_credentials.Credentials = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + channel: aio.Channel = None, + api_mtls_endpoint: str = None, + client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, + ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, + quota_project_id=None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + This argument is ignored if ``channel`` is provided. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + channel (Optional[aio.Channel]): A ``Channel`` instance through + which to make calls. + api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. + If provided, it overrides the ``host`` argument and tries to create + a mutual TLS channel with client SSL credentials from + ``client_cert_source`` or application default SSL credentials. + client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): + Deprecated. A callback to provide client SSL certificate bytes and + private key bytes, both in PEM format. It is ignored if + ``api_mtls_endpoint`` is None. + ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials + for the grpc channel. It is ignored if ``channel`` is provided. + client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): + A callback to provide client certificate bytes and private key bytes, + both in PEM format. It is used to configure a mutual TLS channel. It is + ignored if ``channel`` or ``ssl_channel_credentials`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + + Raises: + google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport + creation failed for any reason. + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + self._grpc_channel = None + self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} + + if api_mtls_endpoint: + warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning) + if client_cert_source: + warnings.warn("client_cert_source is deprecated", DeprecationWarning) + + if channel: + # Ignore credentials if a channel was passed. + credentials = False + # If a channel was explicitly provided, set it. + self._grpc_channel = channel + self._ssl_channel_credentials = None + else: + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials + + else: + if client_cert_source_for_mtls and not ssl_channel_credentials: + cert, key = client_cert_source_for_mtls() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + + # The base transport sets the host, credentials and scopes + super().__init__( + host=host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + + if not self._grpc_channel: + self._grpc_channel = type(self).create_channel( + self._host, + # use the credentials which are saved + credentials=self._credentials, + # Set ``credentials_file`` to ``None`` here as + # the credentials that we saved earlier should be used. + credentials_file=None, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, + quota_project_id=quota_project_id, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) + + @property + def grpc_channel(self) -> aio.Channel: + """Create the channel designed to connect to this service. + + This property caches on the instance; repeated calls return + the same channel. + """ + # Return the channel from cache. + return self._grpc_channel + + @property + def list_voices( + self, + ) -> Callable[ + [cloud_tts.ListVoicesRequest], Awaitable[cloud_tts.ListVoicesResponse] + ]: + r"""Return a callable for the list voices method over gRPC. + + Returns a list of Voice supported for synthesis. + + Returns: + Callable[[~.ListVoicesRequest], + Awaitable[~.ListVoicesResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_voices" not in self._stubs: + self._stubs["list_voices"] = self.grpc_channel.unary_unary( + "/google.cloud.texttospeech.v1.TextToSpeech/ListVoices", + request_serializer=cloud_tts.ListVoicesRequest.serialize, + response_deserializer=cloud_tts.ListVoicesResponse.deserialize, + ) + return self._stubs["list_voices"] + + @property + def synthesize_speech( + self, + ) -> Callable[ + [cloud_tts.SynthesizeSpeechRequest], + Awaitable[cloud_tts.SynthesizeSpeechResponse], + ]: + r"""Return a callable for the synthesize speech method over gRPC. + + Synthesizes speech synchronously: receive results + after all text input has been processed. + + Returns: + Callable[[~.SynthesizeSpeechRequest], + Awaitable[~.SynthesizeSpeechResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "synthesize_speech" not in self._stubs: + self._stubs["synthesize_speech"] = self.grpc_channel.unary_unary( + "/google.cloud.texttospeech.v1.TextToSpeech/SynthesizeSpeech", + request_serializer=cloud_tts.SynthesizeSpeechRequest.serialize, + response_deserializer=cloud_tts.SynthesizeSpeechResponse.deserialize, + ) + return self._stubs["synthesize_speech"] + + def close(self): + return self.grpc_channel.close() + + +__all__ = ("TextToSpeechGrpcAsyncIOTransport",) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/__init__.py new file mode 100644 index 000000000000..f7225093bd64 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/__init__.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +from .cloud_tts import ( + AudioConfig, + AudioEncoding, + CustomVoiceParams, + ListVoicesRequest, + ListVoicesResponse, + SsmlVoiceGender, + SynthesisInput, + SynthesizeSpeechRequest, + SynthesizeSpeechResponse, + Voice, + VoiceSelectionParams, +) + +__all__ = ( + "AudioConfig", + "CustomVoiceParams", + "ListVoicesRequest", + "ListVoicesResponse", + "SynthesisInput", + "SynthesizeSpeechRequest", + "SynthesizeSpeechResponse", + "Voice", + "VoiceSelectionParams", + "AudioEncoding", + "SsmlVoiceGender", +) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py new file mode 100644 index 000000000000..b70b7515fa60 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py @@ -0,0 +1,388 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +import proto # type: ignore + +__protobuf__ = proto.module( + package="google.cloud.texttospeech.v1", + manifest={ + "SsmlVoiceGender", + "AudioEncoding", + "ListVoicesRequest", + "ListVoicesResponse", + "Voice", + "SynthesizeSpeechRequest", + "SynthesisInput", + "VoiceSelectionParams", + "AudioConfig", + "CustomVoiceParams", + "SynthesizeSpeechResponse", + }, +) + + +class SsmlVoiceGender(proto.Enum): + r"""Gender of the voice as described in `SSML voice + element `__. + """ + SSML_VOICE_GENDER_UNSPECIFIED = 0 + MALE = 1 + FEMALE = 2 + NEUTRAL = 3 + + +class AudioEncoding(proto.Enum): + r"""Configuration to set up audio encoder. The encoding + determines the output audio format that we'd like. + """ + AUDIO_ENCODING_UNSPECIFIED = 0 + LINEAR16 = 1 + MP3 = 2 + OGG_OPUS = 3 + MULAW = 5 + ALAW = 6 + + +class ListVoicesRequest(proto.Message): + r"""The top-level message sent by the client for the ``ListVoices`` + method. + + Attributes: + language_code (str): + Optional. Recommended. + `BCP-47 `__ + language tag. If not specified, the API will return all + supported voices. If specified, the ListVoices call will + only return voices that can be used to synthesize this + language_code. For example, if you specify ``"en-NZ"``, all + ``"en-NZ"`` voices will be returned. If you specify + ``"no"``, both ``"no-\*"`` (Norwegian) and ``"nb-\*"`` + (Norwegian Bokmal) voices will be returned. + """ + + language_code = proto.Field( + proto.STRING, + number=1, + ) + + +class ListVoicesResponse(proto.Message): + r"""The message returned to the client by the ``ListVoices`` method. + + Attributes: + voices (Sequence[google.cloud.texttospeech_v1.types.Voice]): + The list of voices. + """ + + voices = proto.RepeatedField( + proto.MESSAGE, + number=1, + message="Voice", + ) + + +class Voice(proto.Message): + r"""Description of a voice supported by the TTS service. + + Attributes: + language_codes (Sequence[str]): + The languages that this voice supports, expressed as + `BCP-47 `__ + language tags (e.g. "en-US", "es-419", "cmn-tw"). + name (str): + The name of this voice. Each distinct voice + has a unique name. + ssml_gender (google.cloud.texttospeech_v1.types.SsmlVoiceGender): + The gender of this voice. + natural_sample_rate_hertz (int): + The natural sample rate (in hertz) for this + voice. + """ + + language_codes = proto.RepeatedField( + proto.STRING, + number=1, + ) + name = proto.Field( + proto.STRING, + number=2, + ) + ssml_gender = proto.Field( + proto.ENUM, + number=3, + enum="SsmlVoiceGender", + ) + natural_sample_rate_hertz = proto.Field( + proto.INT32, + number=4, + ) + + +class SynthesizeSpeechRequest(proto.Message): + r"""The top-level message sent by the client for the + ``SynthesizeSpeech`` method. + + Attributes: + input (google.cloud.texttospeech_v1.types.SynthesisInput): + Required. The Synthesizer requires either + plain text or SSML as input. + voice (google.cloud.texttospeech_v1.types.VoiceSelectionParams): + Required. The desired voice of the + synthesized audio. + audio_config (google.cloud.texttospeech_v1.types.AudioConfig): + Required. The configuration of the + synthesized audio. + """ + + input = proto.Field( + proto.MESSAGE, + number=1, + message="SynthesisInput", + ) + voice = proto.Field( + proto.MESSAGE, + number=2, + message="VoiceSelectionParams", + ) + audio_config = proto.Field( + proto.MESSAGE, + number=3, + message="AudioConfig", + ) + + +class SynthesisInput(proto.Message): + r"""Contains text input to be synthesized. Either ``text`` or ``ssml`` + must be supplied. Supplying both or neither returns + [google.rpc.Code.INVALID_ARGUMENT][]. The input size is limited to + 5000 characters. + + This message has `oneof`_ fields (mutually exclusive fields). + For each oneof, at most one member field can be set at the same time. + Setting any member of the oneof automatically clears all other + members. + + .. _oneof: https://proto-plus-python.readthedocs.io/en/stable/fields.html#oneofs-mutually-exclusive-fields + + Attributes: + text (str): + The raw text to be synthesized. + + This field is a member of `oneof`_ ``input_source``. + ssml (str): + The SSML document to be synthesized. The SSML document must + be valid and well-formed. Otherwise the RPC will fail and + return [google.rpc.Code.INVALID_ARGUMENT][]. For more + information, see + `SSML `__. + + This field is a member of `oneof`_ ``input_source``. + """ + + text = proto.Field( + proto.STRING, + number=1, + oneof="input_source", + ) + ssml = proto.Field( + proto.STRING, + number=2, + oneof="input_source", + ) + + +class VoiceSelectionParams(proto.Message): + r"""Description of which voice to use for a synthesis request. + + Attributes: + language_code (str): + Required. The language (and potentially also the region) of + the voice expressed as a + `BCP-47 `__ + language tag, e.g. "en-US". This should not include a script + tag (e.g. use "cmn-cn" rather than "cmn-Hant-cn"), because + the script will be inferred from the input provided in the + SynthesisInput. The TTS service will use this parameter to + help choose an appropriate voice. Note that the TTS service + may choose a voice with a slightly different language code + than the one selected; it may substitute a different region + (e.g. using en-US rather than en-CA if there isn't a + Canadian voice available), or even a different language, + e.g. using "nb" (Norwegian Bokmal) instead of "no" + (Norwegian)". + name (str): + The name of the voice. If not set, the service will choose a + voice based on the other parameters such as language_code + and gender. + ssml_gender (google.cloud.texttospeech_v1.types.SsmlVoiceGender): + The preferred gender of the voice. If not set, the service + will choose a voice based on the other parameters such as + language_code and name. Note that this is only a preference, + not requirement; if a voice of the appropriate gender is not + available, the synthesizer should substitute a voice with a + different gender rather than failing the request. + custom_voice (google.cloud.texttospeech_v1.types.CustomVoiceParams): + The configuration for a custom voice. If + [CustomVoiceParams.model] is set, the service will choose + the custom voice matching the specified configuration. + """ + + language_code = proto.Field( + proto.STRING, + number=1, + ) + name = proto.Field( + proto.STRING, + number=2, + ) + ssml_gender = proto.Field( + proto.ENUM, + number=3, + enum="SsmlVoiceGender", + ) + custom_voice = proto.Field( + proto.MESSAGE, + number=4, + message="CustomVoiceParams", + ) + + +class AudioConfig(proto.Message): + r"""Description of audio data to be synthesized. + + Attributes: + audio_encoding (google.cloud.texttospeech_v1.types.AudioEncoding): + Required. The format of the audio byte + stream. + speaking_rate (float): + Optional. Input only. Speaking rate/speed, in the range + [0.25, 4.0]. 1.0 is the normal native speed supported by the + specific voice. 2.0 is twice as fast, and 0.5 is half as + fast. If unset(0.0), defaults to the native 1.0 speed. Any + other values < 0.25 or > 4.0 will return an error. + pitch (float): + Optional. Input only. Speaking pitch, in the range [-20.0, + 20.0]. 20 means increase 20 semitones from the original + pitch. -20 means decrease 20 semitones from the original + pitch. + volume_gain_db (float): + Optional. Input only. Volume gain (in dB) of the normal + native volume supported by the specific voice, in the range + [-96.0, 16.0]. If unset, or set to a value of 0.0 (dB), will + play at normal native signal amplitude. A value of -6.0 (dB) + will play at approximately half the amplitude of the normal + native signal amplitude. A value of +6.0 (dB) will play at + approximately twice the amplitude of the normal native + signal amplitude. Strongly recommend not to exceed +10 (dB) + as there's usually no effective increase in loudness for any + value greater than that. + sample_rate_hertz (int): + Optional. The synthesis sample rate (in hertz) for this + audio. When this is specified in SynthesizeSpeechRequest, if + this is different from the voice's natural sample rate, then + the synthesizer will honor this request by converting to the + desired sample rate (which might result in worse audio + quality), unless the specified sample rate is not supported + for the encoding chosen, in which case it will fail the + request and return [google.rpc.Code.INVALID_ARGUMENT][]. + effects_profile_id (Sequence[str]): + Optional. Input only. An identifier which selects 'audio + effects' profiles that are applied on (post synthesized) + text to speech. Effects are applied on top of each other in + the order they are given. See `audio + profiles `__ + for current supported profile ids. + """ + + audio_encoding = proto.Field( + proto.ENUM, + number=1, + enum="AudioEncoding", + ) + speaking_rate = proto.Field( + proto.DOUBLE, + number=2, + ) + pitch = proto.Field( + proto.DOUBLE, + number=3, + ) + volume_gain_db = proto.Field( + proto.DOUBLE, + number=4, + ) + sample_rate_hertz = proto.Field( + proto.INT32, + number=5, + ) + effects_profile_id = proto.RepeatedField( + proto.STRING, + number=6, + ) + + +class CustomVoiceParams(proto.Message): + r"""Description of the custom voice to be synthesized. + + Attributes: + model (str): + Required. The name of the AutoML model that + synthesizes the custom voice. + reported_usage (google.cloud.texttospeech_v1.types.CustomVoiceParams.ReportedUsage): + Optional. The usage of the synthesized audio + to be reported. + """ + + class ReportedUsage(proto.Enum): + r"""The usage of the synthesized audio. You must report your + honest and correct usage of the service as it's regulated by + contract and will cause significant difference in billing. + """ + REPORTED_USAGE_UNSPECIFIED = 0 + REALTIME = 1 + OFFLINE = 2 + + model = proto.Field( + proto.STRING, + number=1, + ) + reported_usage = proto.Field( + proto.ENUM, + number=3, + enum=ReportedUsage, + ) + + +class SynthesizeSpeechResponse(proto.Message): + r"""The message returned to the client by the ``SynthesizeSpeech`` + method. + + Attributes: + audio_content (bytes): + The audio data bytes encoded as specified in the request, + including the header for encodings that are wrapped in + containers (e.g. MP3, OGG_OPUS). For LINEAR16 audio, we + include the WAV header. Note: as with all bytes fields, + protobuffers use a pure binary representation, whereas JSON + representations use base64. + """ + + audio_content = proto.Field( + proto.BYTES, + number=1, + ) + + +__all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/__init__.py new file mode 100644 index 000000000000..c7a1e4dd4b80 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/__init__.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# + +from .services.text_to_speech import TextToSpeechAsyncClient, TextToSpeechClient +from .types.cloud_tts import ( + AudioConfig, + AudioEncoding, + CustomVoiceParams, + ListVoicesRequest, + ListVoicesResponse, + SsmlVoiceGender, + SynthesisInput, + SynthesizeSpeechRequest, + SynthesizeSpeechResponse, + Timepoint, + Voice, + VoiceSelectionParams, +) + +__all__ = ( + "TextToSpeechAsyncClient", + "AudioConfig", + "AudioEncoding", + "CustomVoiceParams", + "ListVoicesRequest", + "ListVoicesResponse", + "SsmlVoiceGender", + "SynthesisInput", + "SynthesizeSpeechRequest", + "SynthesizeSpeechResponse", + "TextToSpeechClient", + "Timepoint", + "Voice", + "VoiceSelectionParams", +) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/gapic_metadata.json b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/gapic_metadata.json new file mode 100644 index 000000000000..2a31677f51b1 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/gapic_metadata.json @@ -0,0 +1,43 @@ + { + "comment": "This file maps proto services/RPCs to the corresponding library clients/methods", + "language": "python", + "libraryPackage": "google.cloud.texttospeech_v1beta1", + "protoPackage": "google.cloud.texttospeech.v1beta1", + "schema": "1.0", + "services": { + "TextToSpeech": { + "clients": { + "grpc": { + "libraryClient": "TextToSpeechClient", + "rpcs": { + "ListVoices": { + "methods": [ + "list_voices" + ] + }, + "SynthesizeSpeech": { + "methods": [ + "synthesize_speech" + ] + } + } + }, + "grpc-async": { + "libraryClient": "TextToSpeechAsyncClient", + "rpcs": { + "ListVoices": { + "methods": [ + "list_voices" + ] + }, + "SynthesizeSpeech": { + "methods": [ + "synthesize_speech" + ] + } + } + } + } + } + } +} diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/py.typed b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/py.typed new file mode 100644 index 000000000000..9b87c1e1cbf9 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/py.typed @@ -0,0 +1,2 @@ +# Marker file for PEP 561. +# The google-cloud-texttospeech package uses inline types. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/pkg_resources/pkg_resources_foo/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/__init__.py similarity index 76% rename from packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/pkg_resources/pkg_resources_foo/__init__.py rename to packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/__init__.py index d5e5048bcc9c..e8e1c3845db5 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/pkg_resources/pkg_resources_foo/__init__.py +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/__init__.py @@ -1,19 +1,15 @@ -# Copyright 2021 Google LLC +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC # # 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 +# 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. - -# coding: utf-8 - -from format.rst.foo import Foo - -__all__ = ['Foo'] \ No newline at end of file +# diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/__init__.py new file mode 100644 index 000000000000..f70edab7c5c7 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +from .async_client import TextToSpeechAsyncClient +from .client import TextToSpeechClient + +__all__ = ( + "TextToSpeechClient", + "TextToSpeechAsyncClient", +) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/async_client.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/async_client.py new file mode 100644 index 000000000000..fdadf8855dcd --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/async_client.py @@ -0,0 +1,448 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +from collections import OrderedDict +import functools +import re +from typing import Dict, Mapping, Optional, Sequence, Tuple, Type, Union + +from google.api_core import exceptions as core_exceptions +from google.api_core import gapic_v1 +from google.api_core import retry as retries +from google.api_core.client_options import ClientOptions +from google.auth import credentials as ga_credentials # type: ignore +from google.oauth2 import service_account # type: ignore +import pkg_resources + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + +from google.cloud.texttospeech_v1beta1.types import cloud_tts + +from .client import TextToSpeechClient +from .transports.base import DEFAULT_CLIENT_INFO, TextToSpeechTransport +from .transports.grpc_asyncio import TextToSpeechGrpcAsyncIOTransport + + +class TextToSpeechAsyncClient: + """Service that implements Google Cloud Text-to-Speech API.""" + + _client: TextToSpeechClient + + DEFAULT_ENDPOINT = TextToSpeechClient.DEFAULT_ENDPOINT + DEFAULT_MTLS_ENDPOINT = TextToSpeechClient.DEFAULT_MTLS_ENDPOINT + + model_path = staticmethod(TextToSpeechClient.model_path) + parse_model_path = staticmethod(TextToSpeechClient.parse_model_path) + common_billing_account_path = staticmethod( + TextToSpeechClient.common_billing_account_path + ) + parse_common_billing_account_path = staticmethod( + TextToSpeechClient.parse_common_billing_account_path + ) + common_folder_path = staticmethod(TextToSpeechClient.common_folder_path) + parse_common_folder_path = staticmethod(TextToSpeechClient.parse_common_folder_path) + common_organization_path = staticmethod(TextToSpeechClient.common_organization_path) + parse_common_organization_path = staticmethod( + TextToSpeechClient.parse_common_organization_path + ) + common_project_path = staticmethod(TextToSpeechClient.common_project_path) + parse_common_project_path = staticmethod( + TextToSpeechClient.parse_common_project_path + ) + common_location_path = staticmethod(TextToSpeechClient.common_location_path) + parse_common_location_path = staticmethod( + TextToSpeechClient.parse_common_location_path + ) + + @classmethod + def from_service_account_info(cls, info: dict, *args, **kwargs): + """Creates an instance of this client using the provided credentials + info. + + Args: + info (dict): The service account private key info. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + TextToSpeechAsyncClient: The constructed client. + """ + return TextToSpeechClient.from_service_account_info.__func__(TextToSpeechAsyncClient, info, *args, **kwargs) # type: ignore + + @classmethod + def from_service_account_file(cls, filename: str, *args, **kwargs): + """Creates an instance of this client using the provided credentials + file. + + Args: + filename (str): The path to the service account private key json + file. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + TextToSpeechAsyncClient: The constructed client. + """ + return TextToSpeechClient.from_service_account_file.__func__(TextToSpeechAsyncClient, filename, *args, **kwargs) # type: ignore + + from_service_account_json = from_service_account_file + + @classmethod + def get_mtls_endpoint_and_cert_source( + cls, client_options: Optional[ClientOptions] = None + ): + """Return the API endpoint and client cert source for mutual TLS. + + The client cert source is determined in the following order: + (1) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not "true", the + client cert source is None. + (2) if `client_options.client_cert_source` is provided, use the provided one; if the + default client cert source exists, use the default one; otherwise the client cert + source is None. + + The API endpoint is determined in the following order: + (1) if `client_options.api_endpoint` if provided, use the provided one. + (2) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is "always", use the + default mTLS endpoint; if the environment variabel is "never", use the default API + endpoint; otherwise if client cert source exists, use the default mTLS endpoint, otherwise + use the default API endpoint. + + More details can be found at https://google.aip.dev/auth/4114. + + Args: + client_options (google.api_core.client_options.ClientOptions): Custom options for the + client. Only the `api_endpoint` and `client_cert_source` properties may be used + in this method. + + Returns: + Tuple[str, Callable[[], Tuple[bytes, bytes]]]: returns the API endpoint and the + client cert source to use. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If any errors happen. + """ + return TextToSpeechClient.get_mtls_endpoint_and_cert_source(client_options) # type: ignore + + @property + def transport(self) -> TextToSpeechTransport: + """Returns the transport used by the client instance. + + Returns: + TextToSpeechTransport: The transport used by the client instance. + """ + return self._client.transport + + get_transport_class = functools.partial( + type(TextToSpeechClient).get_transport_class, type(TextToSpeechClient) + ) + + def __init__( + self, + *, + credentials: ga_credentials.Credentials = None, + transport: Union[str, TextToSpeechTransport] = "grpc_asyncio", + client_options: ClientOptions = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + ) -> None: + """Instantiates the text to speech client. + + Args: + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + transport (Union[str, ~.TextToSpeechTransport]): The + transport to use. If set to None, a transport is chosen + automatically. + client_options (ClientOptions): Custom options for the client. It + won't take effect if a ``transport`` instance is provided. + (1) The ``api_endpoint`` property can be used to override the + default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT + environment variable can also be used to override the endpoint: + "always" (always use the default mTLS endpoint), "never" (always + use the default regular endpoint) and "auto" (auto switch to the + default mTLS endpoint if client certificate is present, this is + the default value). However, the ``api_endpoint`` property takes + precedence if provided. + (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable + is "true", then the ``client_cert_source`` property can be used + to provide client certificate for mutual TLS transport. If + not provided, the default SSL client certificate will be used if + present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not + set, no client certificate will be used. + + Raises: + google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport + creation failed for any reason. + """ + self._client = TextToSpeechClient( + credentials=credentials, + transport=transport, + client_options=client_options, + client_info=client_info, + ) + + async def list_voices( + self, + request: Union[cloud_tts.ListVoicesRequest, dict] = None, + *, + language_code: str = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> cloud_tts.ListVoicesResponse: + r"""Returns a list of Voice supported for synthesis. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google.cloud import texttospeech_v1beta1 + + async def sample_list_voices(): + # Create a client + client = texttospeech_v1beta1.TextToSpeechAsyncClient() + + # Initialize request argument(s) + request = texttospeech_v1beta1.ListVoicesRequest( + ) + + # Make the request + response = await client.list_voices(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.cloud.texttospeech_v1beta1.types.ListVoicesRequest, dict]): + The request object. The top-level message sent by the + client for the `ListVoices` method. + language_code (:class:`str`): + Optional. Recommended. + `BCP-47 `__ + language tag. If not specified, the API will return all + supported voices. If specified, the ListVoices call will + only return voices that can be used to synthesize this + language_code. For example, if you specify ``"en-NZ"``, + all ``"en-NZ"`` voices will be returned. If you specify + ``"no"``, both ``"no-\*"`` (Norwegian) and ``"nb-\*"`` + (Norwegian Bokmal) voices will be returned. + + This corresponds to the ``language_code`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.texttospeech_v1beta1.types.ListVoicesResponse: + The message returned to the client by the ListVoices + method. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([language_code]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = cloud_tts.ListVoicesRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if language_code is not None: + request.language_code = language_code + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.list_voices, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def synthesize_speech( + self, + request: Union[cloud_tts.SynthesizeSpeechRequest, dict] = None, + *, + input: cloud_tts.SynthesisInput = None, + voice: cloud_tts.VoiceSelectionParams = None, + audio_config: cloud_tts.AudioConfig = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> cloud_tts.SynthesizeSpeechResponse: + r"""Synthesizes speech synchronously: receive results + after all text input has been processed. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google.cloud import texttospeech_v1beta1 + + async def sample_synthesize_speech(): + # Create a client + client = texttospeech_v1beta1.TextToSpeechAsyncClient() + + # Initialize request argument(s) + input = texttospeech_v1beta1.SynthesisInput() + input.text = "text_value" + + voice = texttospeech_v1beta1.VoiceSelectionParams() + voice.language_code = "language_code_value" + + audio_config = texttospeech_v1beta1.AudioConfig() + audio_config.audio_encoding = "ALAW" + + request = texttospeech_v1beta1.SynthesizeSpeechRequest( + input=input, + voice=voice, + audio_config=audio_config, + ) + + # Make the request + response = await client.synthesize_speech(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechRequest, dict]): + The request object. The top-level message sent by the + client for the `SynthesizeSpeech` method. + input (:class:`google.cloud.texttospeech_v1beta1.types.SynthesisInput`): + Required. The Synthesizer requires + either plain text or SSML as input. + + This corresponds to the ``input`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + voice (:class:`google.cloud.texttospeech_v1beta1.types.VoiceSelectionParams`): + Required. The desired voice of the + synthesized audio. + + This corresponds to the ``voice`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + audio_config (:class:`google.cloud.texttospeech_v1beta1.types.AudioConfig`): + Required. The configuration of the + synthesized audio. + + This corresponds to the ``audio_config`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechResponse: + The message returned to the client by the + SynthesizeSpeech method. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([input, voice, audio_config]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = cloud_tts.SynthesizeSpeechRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if input is not None: + request.input = input + if voice is not None: + request.voice = voice + if audio_config is not None: + request.audio_config = audio_config + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.synthesize_speech, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc, tb): + await self.transport.close() + + +try: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=pkg_resources.get_distribution( + "google-cloud-texttospeech", + ).version, + ) +except pkg_resources.DistributionNotFound: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() + + +__all__ = ("TextToSpeechAsyncClient",) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py new file mode 100644 index 000000000000..c67467d3f51b --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py @@ -0,0 +1,682 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +from collections import OrderedDict +import os +import re +from typing import Dict, Mapping, Optional, Sequence, Tuple, Type, Union + +from google.api_core import client_options as client_options_lib +from google.api_core import exceptions as core_exceptions +from google.api_core import gapic_v1 +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.exceptions import MutualTLSChannelError # type: ignore +from google.auth.transport import mtls # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.oauth2 import service_account # type: ignore +import pkg_resources + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + +from google.cloud.texttospeech_v1beta1.types import cloud_tts + +from .transports.base import DEFAULT_CLIENT_INFO, TextToSpeechTransport +from .transports.grpc import TextToSpeechGrpcTransport +from .transports.grpc_asyncio import TextToSpeechGrpcAsyncIOTransport + + +class TextToSpeechClientMeta(type): + """Metaclass for the TextToSpeech client. + + This provides class-level methods for building and retrieving + support objects (e.g. transport) without polluting the client instance + objects. + """ + + _transport_registry = OrderedDict() # type: Dict[str, Type[TextToSpeechTransport]] + _transport_registry["grpc"] = TextToSpeechGrpcTransport + _transport_registry["grpc_asyncio"] = TextToSpeechGrpcAsyncIOTransport + + def get_transport_class( + cls, + label: str = None, + ) -> Type[TextToSpeechTransport]: + """Returns an appropriate transport class. + + Args: + label: The name of the desired transport. If none is + provided, then the first transport in the registry is used. + + Returns: + The transport class to use. + """ + # If a specific transport is requested, return that one. + if label: + return cls._transport_registry[label] + + # No transport is requested; return the default (that is, the first one + # in the dictionary). + return next(iter(cls._transport_registry.values())) + + +class TextToSpeechClient(metaclass=TextToSpeechClientMeta): + """Service that implements Google Cloud Text-to-Speech API.""" + + @staticmethod + def _get_default_mtls_endpoint(api_endpoint): + """Converts api endpoint to mTLS endpoint. + + Convert "*.sandbox.googleapis.com" and "*.googleapis.com" to + "*.mtls.sandbox.googleapis.com" and "*.mtls.googleapis.com" respectively. + Args: + api_endpoint (Optional[str]): the api endpoint to convert. + Returns: + str: converted mTLS api endpoint. + """ + if not api_endpoint: + return api_endpoint + + mtls_endpoint_re = re.compile( + r"(?P[^.]+)(?P\.mtls)?(?P\.sandbox)?(?P\.googleapis\.com)?" + ) + + m = mtls_endpoint_re.match(api_endpoint) + name, mtls, sandbox, googledomain = m.groups() + if mtls or not googledomain: + return api_endpoint + + if sandbox: + return api_endpoint.replace( + "sandbox.googleapis.com", "mtls.sandbox.googleapis.com" + ) + + return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com") + + DEFAULT_ENDPOINT = "texttospeech.googleapis.com" + DEFAULT_MTLS_ENDPOINT = _get_default_mtls_endpoint.__func__( # type: ignore + DEFAULT_ENDPOINT + ) + + @classmethod + def from_service_account_info(cls, info: dict, *args, **kwargs): + """Creates an instance of this client using the provided credentials + info. + + Args: + info (dict): The service account private key info. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + TextToSpeechClient: The constructed client. + """ + credentials = service_account.Credentials.from_service_account_info(info) + kwargs["credentials"] = credentials + return cls(*args, **kwargs) + + @classmethod + def from_service_account_file(cls, filename: str, *args, **kwargs): + """Creates an instance of this client using the provided credentials + file. + + Args: + filename (str): The path to the service account private key json + file. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + TextToSpeechClient: The constructed client. + """ + credentials = service_account.Credentials.from_service_account_file(filename) + kwargs["credentials"] = credentials + return cls(*args, **kwargs) + + from_service_account_json = from_service_account_file + + @property + def transport(self) -> TextToSpeechTransport: + """Returns the transport used by the client instance. + + Returns: + TextToSpeechTransport: The transport used by the client + instance. + """ + return self._transport + + @staticmethod + def model_path( + project: str, + location: str, + model: str, + ) -> str: + """Returns a fully-qualified model string.""" + return "projects/{project}/locations/{location}/models/{model}".format( + project=project, + location=location, + model=model, + ) + + @staticmethod + def parse_model_path(path: str) -> Dict[str, str]: + """Parses a model path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/locations/(?P.+?)/models/(?P.+?)$", + path, + ) + return m.groupdict() if m else {} + + @staticmethod + def common_billing_account_path( + billing_account: str, + ) -> str: + """Returns a fully-qualified billing_account string.""" + return "billingAccounts/{billing_account}".format( + billing_account=billing_account, + ) + + @staticmethod + def parse_common_billing_account_path(path: str) -> Dict[str, str]: + """Parse a billing_account path into its component segments.""" + m = re.match(r"^billingAccounts/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_folder_path( + folder: str, + ) -> str: + """Returns a fully-qualified folder string.""" + return "folders/{folder}".format( + folder=folder, + ) + + @staticmethod + def parse_common_folder_path(path: str) -> Dict[str, str]: + """Parse a folder path into its component segments.""" + m = re.match(r"^folders/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_organization_path( + organization: str, + ) -> str: + """Returns a fully-qualified organization string.""" + return "organizations/{organization}".format( + organization=organization, + ) + + @staticmethod + def parse_common_organization_path(path: str) -> Dict[str, str]: + """Parse a organization path into its component segments.""" + m = re.match(r"^organizations/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_project_path( + project: str, + ) -> str: + """Returns a fully-qualified project string.""" + return "projects/{project}".format( + project=project, + ) + + @staticmethod + def parse_common_project_path(path: str) -> Dict[str, str]: + """Parse a project path into its component segments.""" + m = re.match(r"^projects/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_location_path( + project: str, + location: str, + ) -> str: + """Returns a fully-qualified location string.""" + return "projects/{project}/locations/{location}".format( + project=project, + location=location, + ) + + @staticmethod + def parse_common_location_path(path: str) -> Dict[str, str]: + """Parse a location path into its component segments.""" + m = re.match(r"^projects/(?P.+?)/locations/(?P.+?)$", path) + return m.groupdict() if m else {} + + @classmethod + def get_mtls_endpoint_and_cert_source( + cls, client_options: Optional[client_options_lib.ClientOptions] = None + ): + """Return the API endpoint and client cert source for mutual TLS. + + The client cert source is determined in the following order: + (1) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not "true", the + client cert source is None. + (2) if `client_options.client_cert_source` is provided, use the provided one; if the + default client cert source exists, use the default one; otherwise the client cert + source is None. + + The API endpoint is determined in the following order: + (1) if `client_options.api_endpoint` if provided, use the provided one. + (2) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is "always", use the + default mTLS endpoint; if the environment variabel is "never", use the default API + endpoint; otherwise if client cert source exists, use the default mTLS endpoint, otherwise + use the default API endpoint. + + More details can be found at https://google.aip.dev/auth/4114. + + Args: + client_options (google.api_core.client_options.ClientOptions): Custom options for the + client. Only the `api_endpoint` and `client_cert_source` properties may be used + in this method. + + Returns: + Tuple[str, Callable[[], Tuple[bytes, bytes]]]: returns the API endpoint and the + client cert source to use. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If any errors happen. + """ + if client_options is None: + client_options = client_options_lib.ClientOptions() + use_client_cert = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false") + use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto") + if use_client_cert not in ("true", "false"): + raise ValueError( + "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`" + ) + if use_mtls_endpoint not in ("auto", "never", "always"): + raise MutualTLSChannelError( + "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`" + ) + + # Figure out the client cert source to use. + client_cert_source = None + if use_client_cert == "true": + if client_options.client_cert_source: + client_cert_source = client_options.client_cert_source + elif mtls.has_default_client_cert_source(): + client_cert_source = mtls.default_client_cert_source() + + # Figure out which api endpoint to use. + if client_options.api_endpoint is not None: + api_endpoint = client_options.api_endpoint + elif use_mtls_endpoint == "always" or ( + use_mtls_endpoint == "auto" and client_cert_source + ): + api_endpoint = cls.DEFAULT_MTLS_ENDPOINT + else: + api_endpoint = cls.DEFAULT_ENDPOINT + + return api_endpoint, client_cert_source + + def __init__( + self, + *, + credentials: Optional[ga_credentials.Credentials] = None, + transport: Union[str, TextToSpeechTransport, None] = None, + client_options: Optional[client_options_lib.ClientOptions] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + ) -> None: + """Instantiates the text to speech client. + + Args: + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + transport (Union[str, TextToSpeechTransport]): The + transport to use. If set to None, a transport is chosen + automatically. + client_options (google.api_core.client_options.ClientOptions): Custom options for the + client. It won't take effect if a ``transport`` instance is provided. + (1) The ``api_endpoint`` property can be used to override the + default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT + environment variable can also be used to override the endpoint: + "always" (always use the default mTLS endpoint), "never" (always + use the default regular endpoint) and "auto" (auto switch to the + default mTLS endpoint if client certificate is present, this is + the default value). However, the ``api_endpoint`` property takes + precedence if provided. + (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable + is "true", then the ``client_cert_source`` property can be used + to provide client certificate for mutual TLS transport. If + not provided, the default SSL client certificate will be used if + present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not + set, no client certificate will be used. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport + creation failed for any reason. + """ + if isinstance(client_options, dict): + client_options = client_options_lib.from_dict(client_options) + if client_options is None: + client_options = client_options_lib.ClientOptions() + + api_endpoint, client_cert_source_func = self.get_mtls_endpoint_and_cert_source( + client_options + ) + + api_key_value = getattr(client_options, "api_key", None) + if api_key_value and credentials: + raise ValueError( + "client_options.api_key and credentials are mutually exclusive" + ) + + # Save or instantiate the transport. + # Ordinarily, we provide the transport, but allowing a custom transport + # instance provides an extensibility point for unusual situations. + if isinstance(transport, TextToSpeechTransport): + # transport is a TextToSpeechTransport instance. + if credentials or client_options.credentials_file or api_key_value: + raise ValueError( + "When providing a transport instance, " + "provide its credentials directly." + ) + if client_options.scopes: + raise ValueError( + "When providing a transport instance, provide its scopes " + "directly." + ) + self._transport = transport + else: + import google.auth._default # type: ignore + + if api_key_value and hasattr( + google.auth._default, "get_api_key_credentials" + ): + credentials = google.auth._default.get_api_key_credentials( + api_key_value + ) + + Transport = type(self).get_transport_class(transport) + self._transport = Transport( + credentials=credentials, + credentials_file=client_options.credentials_file, + host=api_endpoint, + scopes=client_options.scopes, + client_cert_source_for_mtls=client_cert_source_func, + quota_project_id=client_options.quota_project_id, + client_info=client_info, + always_use_jwt_access=True, + api_audience=client_options.api_audience, + ) + + def list_voices( + self, + request: Union[cloud_tts.ListVoicesRequest, dict] = None, + *, + language_code: str = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> cloud_tts.ListVoicesResponse: + r"""Returns a list of Voice supported for synthesis. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google.cloud import texttospeech_v1beta1 + + def sample_list_voices(): + # Create a client + client = texttospeech_v1beta1.TextToSpeechClient() + + # Initialize request argument(s) + request = texttospeech_v1beta1.ListVoicesRequest( + ) + + # Make the request + response = client.list_voices(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.cloud.texttospeech_v1beta1.types.ListVoicesRequest, dict]): + The request object. The top-level message sent by the + client for the `ListVoices` method. + language_code (str): + Optional. Recommended. + `BCP-47 `__ + language tag. If not specified, the API will return all + supported voices. If specified, the ListVoices call will + only return voices that can be used to synthesize this + language_code. For example, if you specify ``"en-NZ"``, + all ``"en-NZ"`` voices will be returned. If you specify + ``"no"``, both ``"no-\*"`` (Norwegian) and ``"nb-\*"`` + (Norwegian Bokmal) voices will be returned. + + This corresponds to the ``language_code`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.texttospeech_v1beta1.types.ListVoicesResponse: + The message returned to the client by the ListVoices + method. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([language_code]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a cloud_tts.ListVoicesRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, cloud_tts.ListVoicesRequest): + request = cloud_tts.ListVoicesRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if language_code is not None: + request.language_code = language_code + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.list_voices] + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def synthesize_speech( + self, + request: Union[cloud_tts.SynthesizeSpeechRequest, dict] = None, + *, + input: cloud_tts.SynthesisInput = None, + voice: cloud_tts.VoiceSelectionParams = None, + audio_config: cloud_tts.AudioConfig = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> cloud_tts.SynthesizeSpeechResponse: + r"""Synthesizes speech synchronously: receive results + after all text input has been processed. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google.cloud import texttospeech_v1beta1 + + def sample_synthesize_speech(): + # Create a client + client = texttospeech_v1beta1.TextToSpeechClient() + + # Initialize request argument(s) + input = texttospeech_v1beta1.SynthesisInput() + input.text = "text_value" + + voice = texttospeech_v1beta1.VoiceSelectionParams() + voice.language_code = "language_code_value" + + audio_config = texttospeech_v1beta1.AudioConfig() + audio_config.audio_encoding = "ALAW" + + request = texttospeech_v1beta1.SynthesizeSpeechRequest( + input=input, + voice=voice, + audio_config=audio_config, + ) + + # Make the request + response = client.synthesize_speech(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechRequest, dict]): + The request object. The top-level message sent by the + client for the `SynthesizeSpeech` method. + input (google.cloud.texttospeech_v1beta1.types.SynthesisInput): + Required. The Synthesizer requires + either plain text or SSML as input. + + This corresponds to the ``input`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + voice (google.cloud.texttospeech_v1beta1.types.VoiceSelectionParams): + Required. The desired voice of the + synthesized audio. + + This corresponds to the ``voice`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + audio_config (google.cloud.texttospeech_v1beta1.types.AudioConfig): + Required. The configuration of the + synthesized audio. + + This corresponds to the ``audio_config`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechResponse: + The message returned to the client by the + SynthesizeSpeech method. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([input, voice, audio_config]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a cloud_tts.SynthesizeSpeechRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, cloud_tts.SynthesizeSpeechRequest): + request = cloud_tts.SynthesizeSpeechRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if input is not None: + request.input = input + if voice is not None: + request.voice = voice + if audio_config is not None: + request.audio_config = audio_config + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.synthesize_speech] + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def __enter__(self): + return self + + def __exit__(self, type, value, traceback): + """Releases underlying transport's resources. + + .. warning:: + ONLY use as a context manager if the transport is NOT shared + with other clients! Exiting the with block will CLOSE the transport + and may cause errors in other clients! + """ + self.transport.close() + + +try: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=pkg_resources.get_distribution( + "google-cloud-texttospeech", + ).version, + ) +except pkg_resources.DistributionNotFound: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() + + +__all__ = ("TextToSpeechClient",) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/transports/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/transports/__init__.py new file mode 100644 index 000000000000..9a13500994d8 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/transports/__init__.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +from collections import OrderedDict +from typing import Dict, Type + +from .base import TextToSpeechTransport +from .grpc import TextToSpeechGrpcTransport +from .grpc_asyncio import TextToSpeechGrpcAsyncIOTransport + +# Compile a registry of transports. +_transport_registry = OrderedDict() # type: Dict[str, Type[TextToSpeechTransport]] +_transport_registry["grpc"] = TextToSpeechGrpcTransport +_transport_registry["grpc_asyncio"] = TextToSpeechGrpcAsyncIOTransport + +__all__ = ( + "TextToSpeechTransport", + "TextToSpeechGrpcTransport", + "TextToSpeechGrpcAsyncIOTransport", +) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/transports/base.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/transports/base.py new file mode 100644 index 000000000000..c3e04552e701 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/transports/base.py @@ -0,0 +1,177 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +import abc +from typing import Awaitable, Callable, Dict, Optional, Sequence, Union + +import google.api_core +from google.api_core import exceptions as core_exceptions +from google.api_core import gapic_v1 +from google.api_core import retry as retries +import google.auth # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.oauth2 import service_account # type: ignore +import pkg_resources + +from google.cloud.texttospeech_v1beta1.types import cloud_tts + +try: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + gapic_version=pkg_resources.get_distribution( + "google-cloud-texttospeech", + ).version, + ) +except pkg_resources.DistributionNotFound: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() + + +class TextToSpeechTransport(abc.ABC): + """Abstract transport class for TextToSpeech.""" + + AUTH_SCOPES = ("https://www.googleapis.com/auth/cloud-platform",) + + DEFAULT_HOST: str = "texttospeech.googleapis.com" + + def __init__( + self, + *, + host: str = DEFAULT_HOST, + credentials: ga_credentials.Credentials = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + api_audience: Optional[str] = None, + **kwargs, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is mutually exclusive with credentials. + scopes (Optional[Sequence[str]]): A list of scopes. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + """ + + scopes_kwargs = {"scopes": scopes, "default_scopes": self.AUTH_SCOPES} + + # Save the scopes. + self._scopes = scopes + + # If no credentials are provided, then determine the appropriate + # defaults. + if credentials and credentials_file: + raise core_exceptions.DuplicateCredentialArgs( + "'credentials_file' and 'credentials' are mutually exclusive" + ) + + if credentials_file is not None: + credentials, _ = google.auth.load_credentials_from_file( + credentials_file, **scopes_kwargs, quota_project_id=quota_project_id + ) + elif credentials is None: + credentials, _ = google.auth.default( + **scopes_kwargs, quota_project_id=quota_project_id + ) + # Don't apply audience if the credentials file passed from user. + if hasattr(credentials, "with_gdch_audience"): + credentials = credentials.with_gdch_audience( + api_audience if api_audience else host + ) + + # If the credentials are service account credentials, then always try to use self signed JWT. + if ( + always_use_jwt_access + and isinstance(credentials, service_account.Credentials) + and hasattr(service_account.Credentials, "with_always_use_jwt_access") + ): + credentials = credentials.with_always_use_jwt_access(True) + + # Save the credentials. + self._credentials = credentials + + # Save the hostname. Default to port 443 (HTTPS) if none is specified. + if ":" not in host: + host += ":443" + self._host = host + + def _prep_wrapped_messages(self, client_info): + # Precompute the wrapped methods. + self._wrapped_methods = { + self.list_voices: gapic_v1.method.wrap_method( + self.list_voices, + default_timeout=None, + client_info=client_info, + ), + self.synthesize_speech: gapic_v1.method.wrap_method( + self.synthesize_speech, + default_timeout=None, + client_info=client_info, + ), + } + + def close(self): + """Closes resources associated with the transport. + + .. warning:: + Only call this method if the transport is NOT shared + with other clients - this may cause errors in other clients! + """ + raise NotImplementedError() + + @property + def list_voices( + self, + ) -> Callable[ + [cloud_tts.ListVoicesRequest], + Union[cloud_tts.ListVoicesResponse, Awaitable[cloud_tts.ListVoicesResponse]], + ]: + raise NotImplementedError() + + @property + def synthesize_speech( + self, + ) -> Callable[ + [cloud_tts.SynthesizeSpeechRequest], + Union[ + cloud_tts.SynthesizeSpeechResponse, + Awaitable[cloud_tts.SynthesizeSpeechResponse], + ], + ]: + raise NotImplementedError() + + @property + def kind(self) -> str: + raise NotImplementedError() + + +__all__ = ("TextToSpeechTransport",) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/transports/grpc.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/transports/grpc.py new file mode 100644 index 000000000000..b09b58170ca9 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/transports/grpc.py @@ -0,0 +1,294 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +from typing import Callable, Dict, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import gapic_v1, grpc_helpers +import google.auth # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +import grpc # type: ignore + +from google.cloud.texttospeech_v1beta1.types import cloud_tts + +from .base import DEFAULT_CLIENT_INFO, TextToSpeechTransport + + +class TextToSpeechGrpcTransport(TextToSpeechTransport): + """gRPC backend transport for TextToSpeech. + + Service that implements Google Cloud Text-to-Speech API. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends protocol buffers over the wire using gRPC (which is built on + top of HTTP/2); the ``grpcio`` package must be installed. + """ + + _stubs: Dict[str, Callable] + + def __init__( + self, + *, + host: str = "texttospeech.googleapis.com", + credentials: ga_credentials.Credentials = None, + credentials_file: str = None, + scopes: Sequence[str] = None, + channel: grpc.Channel = None, + api_mtls_endpoint: str = None, + client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, + ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + This argument is ignored if ``channel`` is provided. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + channel (Optional[grpc.Channel]): A ``Channel`` instance through + which to make calls. + api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. + If provided, it overrides the ``host`` argument and tries to create + a mutual TLS channel with client SSL credentials from + ``client_cert_source`` or application default SSL credentials. + client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): + Deprecated. A callback to provide client SSL certificate bytes and + private key bytes, both in PEM format. It is ignored if + ``api_mtls_endpoint`` is None. + ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials + for the grpc channel. It is ignored if ``channel`` is provided. + client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): + A callback to provide client certificate bytes and private key bytes, + both in PEM format. It is used to configure a mutual TLS channel. It is + ignored if ``channel`` or ``ssl_channel_credentials`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport + creation failed for any reason. + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + self._grpc_channel = None + self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} + + if api_mtls_endpoint: + warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning) + if client_cert_source: + warnings.warn("client_cert_source is deprecated", DeprecationWarning) + + if channel: + # Ignore credentials if a channel was passed. + credentials = False + # If a channel was explicitly provided, set it. + self._grpc_channel = channel + self._ssl_channel_credentials = None + + else: + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials + + else: + if client_cert_source_for_mtls and not ssl_channel_credentials: + cert, key = client_cert_source_for_mtls() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + + # The base transport sets the host, credentials and scopes + super().__init__( + host=host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + + if not self._grpc_channel: + self._grpc_channel = type(self).create_channel( + self._host, + # use the credentials which are saved + credentials=self._credentials, + # Set ``credentials_file`` to ``None`` here as + # the credentials that we saved earlier should be used. + credentials_file=None, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, + quota_project_id=quota_project_id, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) + + @classmethod + def create_channel( + cls, + host: str = "texttospeech.googleapis.com", + credentials: ga_credentials.Credentials = None, + credentials_file: str = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + **kwargs, + ) -> grpc.Channel: + """Create and return a gRPC channel object. + Args: + host (Optional[str]): The host for the channel to use. + credentials (Optional[~.Credentials]): The + authorization credentials to attach to requests. These + credentials identify this application to the service. If + none are specified, the client will attempt to ascertain + the credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is mutually exclusive with credentials. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + kwargs (Optional[dict]): Keyword arguments, which are passed to the + channel creation. + Returns: + grpc.Channel: A gRPC channel object. + + Raises: + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + + return grpc_helpers.create_channel( + host, + credentials=credentials, + credentials_file=credentials_file, + quota_project_id=quota_project_id, + default_scopes=cls.AUTH_SCOPES, + scopes=scopes, + default_host=cls.DEFAULT_HOST, + **kwargs, + ) + + @property + def grpc_channel(self) -> grpc.Channel: + """Return the channel designed to connect to this service.""" + return self._grpc_channel + + @property + def list_voices( + self, + ) -> Callable[[cloud_tts.ListVoicesRequest], cloud_tts.ListVoicesResponse]: + r"""Return a callable for the list voices method over gRPC. + + Returns a list of Voice supported for synthesis. + + Returns: + Callable[[~.ListVoicesRequest], + ~.ListVoicesResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_voices" not in self._stubs: + self._stubs["list_voices"] = self.grpc_channel.unary_unary( + "/google.cloud.texttospeech.v1beta1.TextToSpeech/ListVoices", + request_serializer=cloud_tts.ListVoicesRequest.serialize, + response_deserializer=cloud_tts.ListVoicesResponse.deserialize, + ) + return self._stubs["list_voices"] + + @property + def synthesize_speech( + self, + ) -> Callable[ + [cloud_tts.SynthesizeSpeechRequest], cloud_tts.SynthesizeSpeechResponse + ]: + r"""Return a callable for the synthesize speech method over gRPC. + + Synthesizes speech synchronously: receive results + after all text input has been processed. + + Returns: + Callable[[~.SynthesizeSpeechRequest], + ~.SynthesizeSpeechResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "synthesize_speech" not in self._stubs: + self._stubs["synthesize_speech"] = self.grpc_channel.unary_unary( + "/google.cloud.texttospeech.v1beta1.TextToSpeech/SynthesizeSpeech", + request_serializer=cloud_tts.SynthesizeSpeechRequest.serialize, + response_deserializer=cloud_tts.SynthesizeSpeechResponse.deserialize, + ) + return self._stubs["synthesize_speech"] + + def close(self): + self.grpc_channel.close() + + @property + def kind(self) -> str: + return "grpc" + + +__all__ = ("TextToSpeechGrpcTransport",) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/transports/grpc_asyncio.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/transports/grpc_asyncio.py new file mode 100644 index 000000000000..43974466147a --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/transports/grpc_asyncio.py @@ -0,0 +1,296 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +from typing import Awaitable, Callable, Dict, Optional, Sequence, Tuple, Union +import warnings + +from google.api_core import gapic_v1, grpc_helpers_async +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +import grpc # type: ignore +from grpc.experimental import aio # type: ignore + +from google.cloud.texttospeech_v1beta1.types import cloud_tts + +from .base import DEFAULT_CLIENT_INFO, TextToSpeechTransport +from .grpc import TextToSpeechGrpcTransport + + +class TextToSpeechGrpcAsyncIOTransport(TextToSpeechTransport): + """gRPC AsyncIO backend transport for TextToSpeech. + + Service that implements Google Cloud Text-to-Speech API. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends protocol buffers over the wire using gRPC (which is built on + top of HTTP/2); the ``grpcio`` package must be installed. + """ + + _grpc_channel: aio.Channel + _stubs: Dict[str, Callable] = {} + + @classmethod + def create_channel( + cls, + host: str = "texttospeech.googleapis.com", + credentials: ga_credentials.Credentials = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + **kwargs, + ) -> aio.Channel: + """Create and return a gRPC AsyncIO channel object. + Args: + host (Optional[str]): The host for the channel to use. + credentials (Optional[~.Credentials]): The + authorization credentials to attach to requests. These + credentials identify this application to the service. If + none are specified, the client will attempt to ascertain + the credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + kwargs (Optional[dict]): Keyword arguments, which are passed to the + channel creation. + Returns: + aio.Channel: A gRPC AsyncIO channel object. + """ + + return grpc_helpers_async.create_channel( + host, + credentials=credentials, + credentials_file=credentials_file, + quota_project_id=quota_project_id, + default_scopes=cls.AUTH_SCOPES, + scopes=scopes, + default_host=cls.DEFAULT_HOST, + **kwargs, + ) + + def __init__( + self, + *, + host: str = "texttospeech.googleapis.com", + credentials: ga_credentials.Credentials = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + channel: aio.Channel = None, + api_mtls_endpoint: str = None, + client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, + ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, + quota_project_id=None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + This argument is ignored if ``channel`` is provided. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + channel (Optional[aio.Channel]): A ``Channel`` instance through + which to make calls. + api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. + If provided, it overrides the ``host`` argument and tries to create + a mutual TLS channel with client SSL credentials from + ``client_cert_source`` or application default SSL credentials. + client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): + Deprecated. A callback to provide client SSL certificate bytes and + private key bytes, both in PEM format. It is ignored if + ``api_mtls_endpoint`` is None. + ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials + for the grpc channel. It is ignored if ``channel`` is provided. + client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): + A callback to provide client certificate bytes and private key bytes, + both in PEM format. It is used to configure a mutual TLS channel. It is + ignored if ``channel`` or ``ssl_channel_credentials`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + + Raises: + google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport + creation failed for any reason. + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + self._grpc_channel = None + self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} + + if api_mtls_endpoint: + warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning) + if client_cert_source: + warnings.warn("client_cert_source is deprecated", DeprecationWarning) + + if channel: + # Ignore credentials if a channel was passed. + credentials = False + # If a channel was explicitly provided, set it. + self._grpc_channel = channel + self._ssl_channel_credentials = None + else: + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials + + else: + if client_cert_source_for_mtls and not ssl_channel_credentials: + cert, key = client_cert_source_for_mtls() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + + # The base transport sets the host, credentials and scopes + super().__init__( + host=host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + + if not self._grpc_channel: + self._grpc_channel = type(self).create_channel( + self._host, + # use the credentials which are saved + credentials=self._credentials, + # Set ``credentials_file`` to ``None`` here as + # the credentials that we saved earlier should be used. + credentials_file=None, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, + quota_project_id=quota_project_id, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ], + ) + + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) + + @property + def grpc_channel(self) -> aio.Channel: + """Create the channel designed to connect to this service. + + This property caches on the instance; repeated calls return + the same channel. + """ + # Return the channel from cache. + return self._grpc_channel + + @property + def list_voices( + self, + ) -> Callable[ + [cloud_tts.ListVoicesRequest], Awaitable[cloud_tts.ListVoicesResponse] + ]: + r"""Return a callable for the list voices method over gRPC. + + Returns a list of Voice supported for synthesis. + + Returns: + Callable[[~.ListVoicesRequest], + Awaitable[~.ListVoicesResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_voices" not in self._stubs: + self._stubs["list_voices"] = self.grpc_channel.unary_unary( + "/google.cloud.texttospeech.v1beta1.TextToSpeech/ListVoices", + request_serializer=cloud_tts.ListVoicesRequest.serialize, + response_deserializer=cloud_tts.ListVoicesResponse.deserialize, + ) + return self._stubs["list_voices"] + + @property + def synthesize_speech( + self, + ) -> Callable[ + [cloud_tts.SynthesizeSpeechRequest], + Awaitable[cloud_tts.SynthesizeSpeechResponse], + ]: + r"""Return a callable for the synthesize speech method over gRPC. + + Synthesizes speech synchronously: receive results + after all text input has been processed. + + Returns: + Callable[[~.SynthesizeSpeechRequest], + Awaitable[~.SynthesizeSpeechResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "synthesize_speech" not in self._stubs: + self._stubs["synthesize_speech"] = self.grpc_channel.unary_unary( + "/google.cloud.texttospeech.v1beta1.TextToSpeech/SynthesizeSpeech", + request_serializer=cloud_tts.SynthesizeSpeechRequest.serialize, + response_deserializer=cloud_tts.SynthesizeSpeechResponse.deserialize, + ) + return self._stubs["synthesize_speech"] + + def close(self): + return self.grpc_channel.close() + + +__all__ = ("TextToSpeechGrpcAsyncIOTransport",) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/__init__.py new file mode 100644 index 000000000000..2a34ccab0090 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/__init__.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +from .cloud_tts import ( + AudioConfig, + AudioEncoding, + CustomVoiceParams, + ListVoicesRequest, + ListVoicesResponse, + SsmlVoiceGender, + SynthesisInput, + SynthesizeSpeechRequest, + SynthesizeSpeechResponse, + Timepoint, + Voice, + VoiceSelectionParams, +) + +__all__ = ( + "AudioConfig", + "CustomVoiceParams", + "ListVoicesRequest", + "ListVoicesResponse", + "SynthesisInput", + "SynthesizeSpeechRequest", + "SynthesizeSpeechResponse", + "Timepoint", + "Voice", + "VoiceSelectionParams", + "AudioEncoding", + "SsmlVoiceGender", +) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py new file mode 100644 index 000000000000..786961c5d61d --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py @@ -0,0 +1,444 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +import proto # type: ignore + +__protobuf__ = proto.module( + package="google.cloud.texttospeech.v1beta1", + manifest={ + "SsmlVoiceGender", + "AudioEncoding", + "ListVoicesRequest", + "ListVoicesResponse", + "Voice", + "SynthesizeSpeechRequest", + "SynthesisInput", + "VoiceSelectionParams", + "AudioConfig", + "CustomVoiceParams", + "SynthesizeSpeechResponse", + "Timepoint", + }, +) + + +class SsmlVoiceGender(proto.Enum): + r"""Gender of the voice as described in `SSML voice + element `__. + """ + SSML_VOICE_GENDER_UNSPECIFIED = 0 + MALE = 1 + FEMALE = 2 + NEUTRAL = 3 + + +class AudioEncoding(proto.Enum): + r"""Configuration to set up audio encoder. The encoding + determines the output audio format that we'd like. + """ + AUDIO_ENCODING_UNSPECIFIED = 0 + LINEAR16 = 1 + MP3 = 2 + MP3_64_KBPS = 4 + OGG_OPUS = 3 + MULAW = 5 + ALAW = 6 + + +class ListVoicesRequest(proto.Message): + r"""The top-level message sent by the client for the ``ListVoices`` + method. + + Attributes: + language_code (str): + Optional. Recommended. + `BCP-47 `__ + language tag. If not specified, the API will return all + supported voices. If specified, the ListVoices call will + only return voices that can be used to synthesize this + language_code. For example, if you specify ``"en-NZ"``, all + ``"en-NZ"`` voices will be returned. If you specify + ``"no"``, both ``"no-\*"`` (Norwegian) and ``"nb-\*"`` + (Norwegian Bokmal) voices will be returned. + """ + + language_code = proto.Field( + proto.STRING, + number=1, + ) + + +class ListVoicesResponse(proto.Message): + r"""The message returned to the client by the ``ListVoices`` method. + + Attributes: + voices (Sequence[google.cloud.texttospeech_v1beta1.types.Voice]): + The list of voices. + """ + + voices = proto.RepeatedField( + proto.MESSAGE, + number=1, + message="Voice", + ) + + +class Voice(proto.Message): + r"""Description of a voice supported by the TTS service. + + Attributes: + language_codes (Sequence[str]): + The languages that this voice supports, expressed as + `BCP-47 `__ + language tags (e.g. "en-US", "es-419", "cmn-tw"). + name (str): + The name of this voice. Each distinct voice + has a unique name. + ssml_gender (google.cloud.texttospeech_v1beta1.types.SsmlVoiceGender): + The gender of this voice. + natural_sample_rate_hertz (int): + The natural sample rate (in hertz) for this + voice. + """ + + language_codes = proto.RepeatedField( + proto.STRING, + number=1, + ) + name = proto.Field( + proto.STRING, + number=2, + ) + ssml_gender = proto.Field( + proto.ENUM, + number=3, + enum="SsmlVoiceGender", + ) + natural_sample_rate_hertz = proto.Field( + proto.INT32, + number=4, + ) + + +class SynthesizeSpeechRequest(proto.Message): + r"""The top-level message sent by the client for the + ``SynthesizeSpeech`` method. + + Attributes: + input (google.cloud.texttospeech_v1beta1.types.SynthesisInput): + Required. The Synthesizer requires either + plain text or SSML as input. + voice (google.cloud.texttospeech_v1beta1.types.VoiceSelectionParams): + Required. The desired voice of the + synthesized audio. + audio_config (google.cloud.texttospeech_v1beta1.types.AudioConfig): + Required. The configuration of the + synthesized audio. + enable_time_pointing (Sequence[google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechRequest.TimepointType]): + Whether and what timepoints are returned in + the response. + """ + + class TimepointType(proto.Enum): + r"""The type of timepoint information that is returned in the + response. + """ + TIMEPOINT_TYPE_UNSPECIFIED = 0 + SSML_MARK = 1 + + input = proto.Field( + proto.MESSAGE, + number=1, + message="SynthesisInput", + ) + voice = proto.Field( + proto.MESSAGE, + number=2, + message="VoiceSelectionParams", + ) + audio_config = proto.Field( + proto.MESSAGE, + number=3, + message="AudioConfig", + ) + enable_time_pointing = proto.RepeatedField( + proto.ENUM, + number=4, + enum=TimepointType, + ) + + +class SynthesisInput(proto.Message): + r"""Contains text input to be synthesized. Either ``text`` or ``ssml`` + must be supplied. Supplying both or neither returns + [google.rpc.Code.INVALID_ARGUMENT][]. The input size is limited to + 5000 characters. + + This message has `oneof`_ fields (mutually exclusive fields). + For each oneof, at most one member field can be set at the same time. + Setting any member of the oneof automatically clears all other + members. + + .. _oneof: https://proto-plus-python.readthedocs.io/en/stable/fields.html#oneofs-mutually-exclusive-fields + + Attributes: + text (str): + The raw text to be synthesized. + + This field is a member of `oneof`_ ``input_source``. + ssml (str): + The SSML document to be synthesized. The SSML document must + be valid and well-formed. Otherwise the RPC will fail and + return [google.rpc.Code.INVALID_ARGUMENT][]. For more + information, see + `SSML `__. + + This field is a member of `oneof`_ ``input_source``. + """ + + text = proto.Field( + proto.STRING, + number=1, + oneof="input_source", + ) + ssml = proto.Field( + proto.STRING, + number=2, + oneof="input_source", + ) + + +class VoiceSelectionParams(proto.Message): + r"""Description of which voice to use for a synthesis request. + + Attributes: + language_code (str): + Required. The language (and potentially also the region) of + the voice expressed as a + `BCP-47 `__ + language tag, e.g. "en-US". This should not include a script + tag (e.g. use "cmn-cn" rather than "cmn-Hant-cn"), because + the script will be inferred from the input provided in the + SynthesisInput. The TTS service will use this parameter to + help choose an appropriate voice. Note that the TTS service + may choose a voice with a slightly different language code + than the one selected; it may substitute a different region + (e.g. using en-US rather than en-CA if there isn't a + Canadian voice available), or even a different language, + e.g. using "nb" (Norwegian Bokmal) instead of "no" + (Norwegian)". + name (str): + The name of the voice. If not set, the service will choose a + voice based on the other parameters such as language_code + and gender. + ssml_gender (google.cloud.texttospeech_v1beta1.types.SsmlVoiceGender): + The preferred gender of the voice. If not set, the service + will choose a voice based on the other parameters such as + language_code and name. Note that this is only a preference, + not requirement; if a voice of the appropriate gender is not + available, the synthesizer should substitute a voice with a + different gender rather than failing the request. + custom_voice (google.cloud.texttospeech_v1beta1.types.CustomVoiceParams): + The configuration for a custom voice. If + [CustomVoiceParams.model] is set, the service will choose + the custom voice matching the specified configuration. + """ + + language_code = proto.Field( + proto.STRING, + number=1, + ) + name = proto.Field( + proto.STRING, + number=2, + ) + ssml_gender = proto.Field( + proto.ENUM, + number=3, + enum="SsmlVoiceGender", + ) + custom_voice = proto.Field( + proto.MESSAGE, + number=4, + message="CustomVoiceParams", + ) + + +class AudioConfig(proto.Message): + r"""Description of audio data to be synthesized. + + Attributes: + audio_encoding (google.cloud.texttospeech_v1beta1.types.AudioEncoding): + Required. The format of the audio byte + stream. + speaking_rate (float): + Optional. Input only. Speaking rate/speed, in the range + [0.25, 4.0]. 1.0 is the normal native speed supported by the + specific voice. 2.0 is twice as fast, and 0.5 is half as + fast. If unset(0.0), defaults to the native 1.0 speed. Any + other values < 0.25 or > 4.0 will return an error. + pitch (float): + Optional. Input only. Speaking pitch, in the range [-20.0, + 20.0]. 20 means increase 20 semitones from the original + pitch. -20 means decrease 20 semitones from the original + pitch. + volume_gain_db (float): + Optional. Input only. Volume gain (in dB) of the normal + native volume supported by the specific voice, in the range + [-96.0, 16.0]. If unset, or set to a value of 0.0 (dB), will + play at normal native signal amplitude. A value of -6.0 (dB) + will play at approximately half the amplitude of the normal + native signal amplitude. A value of +6.0 (dB) will play at + approximately twice the amplitude of the normal native + signal amplitude. Strongly recommend not to exceed +10 (dB) + as there's usually no effective increase in loudness for any + value greater than that. + sample_rate_hertz (int): + Optional. The synthesis sample rate (in hertz) for this + audio. When this is specified in SynthesizeSpeechRequest, if + this is different from the voice's natural sample rate, then + the synthesizer will honor this request by converting to the + desired sample rate (which might result in worse audio + quality), unless the specified sample rate is not supported + for the encoding chosen, in which case it will fail the + request and return [google.rpc.Code.INVALID_ARGUMENT][]. + effects_profile_id (Sequence[str]): + Optional. Input only. An identifier which selects 'audio + effects' profiles that are applied on (post synthesized) + text to speech. Effects are applied on top of each other in + the order they are given. See `audio + profiles `__ + for current supported profile ids. + """ + + audio_encoding = proto.Field( + proto.ENUM, + number=1, + enum="AudioEncoding", + ) + speaking_rate = proto.Field( + proto.DOUBLE, + number=2, + ) + pitch = proto.Field( + proto.DOUBLE, + number=3, + ) + volume_gain_db = proto.Field( + proto.DOUBLE, + number=4, + ) + sample_rate_hertz = proto.Field( + proto.INT32, + number=5, + ) + effects_profile_id = proto.RepeatedField( + proto.STRING, + number=6, + ) + + +class CustomVoiceParams(proto.Message): + r"""Description of the custom voice to be synthesized. + + Attributes: + model (str): + Required. The name of the AutoML model that + synthesizes the custom voice. + reported_usage (google.cloud.texttospeech_v1beta1.types.CustomVoiceParams.ReportedUsage): + Optional. The usage of the synthesized audio + to be reported. + """ + + class ReportedUsage(proto.Enum): + r"""The usage of the synthesized audio. You must report your + honest and correct usage of the service as it's regulated by + contract and will cause significant difference in billing. + """ + REPORTED_USAGE_UNSPECIFIED = 0 + REALTIME = 1 + OFFLINE = 2 + + model = proto.Field( + proto.STRING, + number=1, + ) + reported_usage = proto.Field( + proto.ENUM, + number=3, + enum=ReportedUsage, + ) + + +class SynthesizeSpeechResponse(proto.Message): + r"""The message returned to the client by the ``SynthesizeSpeech`` + method. + + Attributes: + audio_content (bytes): + The audio data bytes encoded as specified in the request, + including the header for encodings that are wrapped in + containers (e.g. MP3, OGG_OPUS). For LINEAR16 audio, we + include the WAV header. Note: as with all bytes fields, + protobuffers use a pure binary representation, whereas JSON + representations use base64. + timepoints (Sequence[google.cloud.texttospeech_v1beta1.types.Timepoint]): + A link between a position in the original request input and + a corresponding time in the output audio. It's only + supported via ```` of SSML input. + audio_config (google.cloud.texttospeech_v1beta1.types.AudioConfig): + The audio metadata of ``audio_content``. + """ + + audio_content = proto.Field( + proto.BYTES, + number=1, + ) + timepoints = proto.RepeatedField( + proto.MESSAGE, + number=2, + message="Timepoint", + ) + audio_config = proto.Field( + proto.MESSAGE, + number=4, + message="AudioConfig", + ) + + +class Timepoint(proto.Message): + r"""This contains a mapping between a certain point in the input + text and a corresponding time in the output audio. + + Attributes: + mark_name (str): + Timepoint name as received from the client within ```` + tag. + time_seconds (float): + Time offset in seconds from the start of the + synthesized audio. + """ + + mark_name = proto.Field( + proto.STRING, + number=4, + ) + time_seconds = proto.Field( + proto.DOUBLE, + number=3, + ) + + +__all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/scripts/decrypt-secrets.sh b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/scripts/decrypt-secrets.sh new file mode 100755 index 000000000000..21f6d2a26d90 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/scripts/decrypt-secrets.sh @@ -0,0 +1,46 @@ +#!/bin/bash + +# Copyright 2015 Google Inc. 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. + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +ROOT=$( dirname "$DIR" ) + +# Work from the project root. +cd $ROOT + +# Prevent it from overriding files. +# We recommend that sample authors use their own service account files and cloud project. +# In that case, they are supposed to prepare these files by themselves. +if [[ -f "testing/test-env.sh" ]] || \ + [[ -f "testing/service-account.json" ]] || \ + [[ -f "testing/client-secrets.json" ]]; then + echo "One or more target files exist, aborting." + exit 1 +fi + +# Use SECRET_MANAGER_PROJECT if set, fallback to cloud-devrel-kokoro-resources. +PROJECT_ID="${SECRET_MANAGER_PROJECT:-cloud-devrel-kokoro-resources}" + +gcloud secrets versions access latest --secret="python-docs-samples-test-env" \ + --project="${PROJECT_ID}" \ + > testing/test-env.sh +gcloud secrets versions access latest \ + --secret="python-docs-samples-service-account" \ + --project="${PROJECT_ID}" \ + > testing/service-account.json +gcloud secrets versions access latest \ + --secret="python-docs-samples-client-secrets" \ + --project="${PROJECT_ID}" \ + > testing/client-secrets.json diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/scripts/fixup_keywords.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/scripts/fixup_keywords.py new file mode 100644 index 000000000000..c216d0bad6d9 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/scripts/fixup_keywords.py @@ -0,0 +1,178 @@ +# -*- coding: utf-8 -*- + +# Copyright 2020 Google LLC +# +# 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. +# + +import argparse +import os +import libcst as cst +import pathlib +import sys +from typing import (Any, Callable, Dict, List, Sequence, Tuple) + + +def partition( + predicate: Callable[[Any], bool], + iterator: Sequence[Any] +) -> Tuple[List[Any], List[Any]]: + """A stable, out-of-place partition.""" + results = ([], []) + + for i in iterator: + results[int(predicate(i))].append(i) + + # Returns trueList, falseList + return results[1], results[0] + + +class texttospeechCallTransformer(cst.CSTTransformer): + CTRL_PARAMS: Tuple[str] = ('retry', 'timeout', 'metadata') + METHOD_TO_PARAMS: Dict[str, Tuple[str]] = { + 'list_voices': ('language_code', ), + 'synthesize_speech': ('input', 'voice', 'audio_config', ), + } + + def leave_Call(self, original: cst.Call, updated: cst.Call) -> cst.CSTNode: + try: + key = original.func.attr.value + kword_params = self.METHOD_TO_PARAMS[key] + except (AttributeError, KeyError): + # Either not a method from the API or too convoluted to be sure. + return updated + + # If the existing code is valid, keyword args come after positional args. + # Therefore, all positional args must map to the first parameters. + args, kwargs = partition(lambda a: not bool(a.keyword), updated.args) + if any(k.keyword.value == "request" for k in kwargs): + # We've already fixed this file, don't fix it again. + return updated + + kwargs, ctrl_kwargs = partition( + lambda a: not a.keyword.value in self.CTRL_PARAMS, + kwargs + ) + + args, ctrl_args = args[:len(kword_params)], args[len(kword_params):] + ctrl_kwargs.extend(cst.Arg(value=a.value, keyword=cst.Name(value=ctrl)) + for a, ctrl in zip(ctrl_args, self.CTRL_PARAMS)) + + request_arg = cst.Arg( + value=cst.Dict([ + cst.DictElement( + cst.SimpleString("'{}'".format(name)), + cst.Element(value=arg.value) + ) + # Note: the args + kwargs looks silly, but keep in mind that + # the control parameters had to be stripped out, and that + # those could have been passed positionally or by keyword. + for name, arg in zip(kword_params, args + kwargs)]), + keyword=cst.Name("request") + ) + + return updated.with_changes( + args=[request_arg] + ctrl_kwargs + ) + + +def fix_files( + in_dir: pathlib.Path, + out_dir: pathlib.Path, + *, + transformer=texttospeechCallTransformer(), +): + """Duplicate the input dir to the output dir, fixing file method calls. + + Preconditions: + * in_dir is a real directory + * out_dir is a real, empty directory + """ + pyfile_gen = ( + pathlib.Path(os.path.join(root, f)) + for root, _, files in os.walk(in_dir) + for f in files if os.path.splitext(f)[1] == ".py" + ) + + for fpath in pyfile_gen: + with open(fpath, 'r') as f: + src = f.read() + + # Parse the code and insert method call fixes. + tree = cst.parse_module(src) + updated = tree.visit(transformer) + + # Create the path and directory structure for the new file. + updated_path = out_dir.joinpath(fpath.relative_to(in_dir)) + updated_path.parent.mkdir(parents=True, exist_ok=True) + + # Generate the updated source file at the corresponding path. + with open(updated_path, 'w') as f: + f.write(updated.code) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser( + description="""Fix up source that uses the texttospeech client library. + +The existing sources are NOT overwritten but are copied to output_dir with changes made. + +Note: This tool operates at a best-effort level at converting positional + parameters in client method calls to keyword based parameters. + Cases where it WILL FAIL include + A) * or ** expansion in a method call. + B) Calls via function or method alias (includes free function calls) + C) Indirect or dispatched calls (e.g. the method is looked up dynamically) + + These all constitute false negatives. The tool will also detect false + positives when an API method shares a name with another method. +""") + parser.add_argument( + '-d', + '--input-directory', + required=True, + dest='input_dir', + help='the input directory to walk for python files to fix up', + ) + parser.add_argument( + '-o', + '--output-directory', + required=True, + dest='output_dir', + help='the directory to output files fixed via un-flattening', + ) + args = parser.parse_args() + input_dir = pathlib.Path(args.input_dir) + output_dir = pathlib.Path(args.output_dir) + if not input_dir.is_dir(): + print( + f"input directory '{input_dir}' does not exist or is not a directory", + file=sys.stderr, + ) + sys.exit(-1) + + if not output_dir.is_dir(): + print( + f"output directory '{output_dir}' does not exist or is not a directory", + file=sys.stderr, + ) + sys.exit(-1) + + if os.listdir(output_dir): + print( + f"output directory '{output_dir}' is not empty", + file=sys.stderr, + ) + sys.exit(-1) + + fix_files(input_dir, output_dir) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/scripts/fixup_texttospeech_v1_keywords.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/scripts/fixup_texttospeech_v1_keywords.py new file mode 100644 index 000000000000..22feca289b87 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/scripts/fixup_texttospeech_v1_keywords.py @@ -0,0 +1,177 @@ +#! /usr/bin/env python3 +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +import argparse +import os +import libcst as cst +import pathlib +import sys +from typing import (Any, Callable, Dict, List, Sequence, Tuple) + + +def partition( + predicate: Callable[[Any], bool], + iterator: Sequence[Any] +) -> Tuple[List[Any], List[Any]]: + """A stable, out-of-place partition.""" + results = ([], []) + + for i in iterator: + results[int(predicate(i))].append(i) + + # Returns trueList, falseList + return results[1], results[0] + + +class texttospeechCallTransformer(cst.CSTTransformer): + CTRL_PARAMS: Tuple[str] = ('retry', 'timeout', 'metadata') + METHOD_TO_PARAMS: Dict[str, Tuple[str]] = { + 'list_voices': ('language_code', ), + 'synthesize_speech': ('input', 'voice', 'audio_config', ), + } + + def leave_Call(self, original: cst.Call, updated: cst.Call) -> cst.CSTNode: + try: + key = original.func.attr.value + kword_params = self.METHOD_TO_PARAMS[key] + except (AttributeError, KeyError): + # Either not a method from the API or too convoluted to be sure. + return updated + + # If the existing code is valid, keyword args come after positional args. + # Therefore, all positional args must map to the first parameters. + args, kwargs = partition(lambda a: not bool(a.keyword), updated.args) + if any(k.keyword.value == "request" for k in kwargs): + # We've already fixed this file, don't fix it again. + return updated + + kwargs, ctrl_kwargs = partition( + lambda a: a.keyword.value not in self.CTRL_PARAMS, + kwargs + ) + + args, ctrl_args = args[:len(kword_params)], args[len(kword_params):] + ctrl_kwargs.extend(cst.Arg(value=a.value, keyword=cst.Name(value=ctrl)) + for a, ctrl in zip(ctrl_args, self.CTRL_PARAMS)) + + request_arg = cst.Arg( + value=cst.Dict([ + cst.DictElement( + cst.SimpleString("'{}'".format(name)), +cst.Element(value=arg.value) + ) + # Note: the args + kwargs looks silly, but keep in mind that + # the control parameters had to be stripped out, and that + # those could have been passed positionally or by keyword. + for name, arg in zip(kword_params, args + kwargs)]), + keyword=cst.Name("request") + ) + + return updated.with_changes( + args=[request_arg] + ctrl_kwargs + ) + + +def fix_files( + in_dir: pathlib.Path, + out_dir: pathlib.Path, + *, + transformer=texttospeechCallTransformer(), +): + """Duplicate the input dir to the output dir, fixing file method calls. + + Preconditions: + * in_dir is a real directory + * out_dir is a real, empty directory + """ + pyfile_gen = ( + pathlib.Path(os.path.join(root, f)) + for root, _, files in os.walk(in_dir) + for f in files if os.path.splitext(f)[1] == ".py" + ) + + for fpath in pyfile_gen: + with open(fpath, 'r') as f: + src = f.read() + + # Parse the code and insert method call fixes. + tree = cst.parse_module(src) + updated = tree.visit(transformer) + + # Create the path and directory structure for the new file. + updated_path = out_dir.joinpath(fpath.relative_to(in_dir)) + updated_path.parent.mkdir(parents=True, exist_ok=True) + + # Generate the updated source file at the corresponding path. + with open(updated_path, 'w') as f: + f.write(updated.code) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser( + description="""Fix up source that uses the texttospeech client library. + +The existing sources are NOT overwritten but are copied to output_dir with changes made. + +Note: This tool operates at a best-effort level at converting positional + parameters in client method calls to keyword based parameters. + Cases where it WILL FAIL include + A) * or ** expansion in a method call. + B) Calls via function or method alias (includes free function calls) + C) Indirect or dispatched calls (e.g. the method is looked up dynamically) + + These all constitute false negatives. The tool will also detect false + positives when an API method shares a name with another method. +""") + parser.add_argument( + '-d', + '--input-directory', + required=True, + dest='input_dir', + help='the input directory to walk for python files to fix up', + ) + parser.add_argument( + '-o', + '--output-directory', + required=True, + dest='output_dir', + help='the directory to output files fixed via un-flattening', + ) + args = parser.parse_args() + input_dir = pathlib.Path(args.input_dir) + output_dir = pathlib.Path(args.output_dir) + if not input_dir.is_dir(): + print( + f"input directory '{input_dir}' does not exist or is not a directory", + file=sys.stderr, + ) + sys.exit(-1) + + if not output_dir.is_dir(): + print( + f"output directory '{output_dir}' does not exist or is not a directory", + file=sys.stderr, + ) + sys.exit(-1) + + if os.listdir(output_dir): + print( + f"output directory '{output_dir}' is not empty", + file=sys.stderr, + ) + sys.exit(-1) + + fix_files(input_dir, output_dir) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/scripts/fixup_texttospeech_v1beta1_keywords.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/scripts/fixup_texttospeech_v1beta1_keywords.py new file mode 100644 index 000000000000..51094d944153 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/scripts/fixup_texttospeech_v1beta1_keywords.py @@ -0,0 +1,177 @@ +#! /usr/bin/env python3 +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +import argparse +import os +import libcst as cst +import pathlib +import sys +from typing import (Any, Callable, Dict, List, Sequence, Tuple) + + +def partition( + predicate: Callable[[Any], bool], + iterator: Sequence[Any] +) -> Tuple[List[Any], List[Any]]: + """A stable, out-of-place partition.""" + results = ([], []) + + for i in iterator: + results[int(predicate(i))].append(i) + + # Returns trueList, falseList + return results[1], results[0] + + +class texttospeechCallTransformer(cst.CSTTransformer): + CTRL_PARAMS: Tuple[str] = ('retry', 'timeout', 'metadata') + METHOD_TO_PARAMS: Dict[str, Tuple[str]] = { + 'list_voices': ('language_code', ), + 'synthesize_speech': ('input', 'voice', 'audio_config', 'enable_time_pointing', ), + } + + def leave_Call(self, original: cst.Call, updated: cst.Call) -> cst.CSTNode: + try: + key = original.func.attr.value + kword_params = self.METHOD_TO_PARAMS[key] + except (AttributeError, KeyError): + # Either not a method from the API or too convoluted to be sure. + return updated + + # If the existing code is valid, keyword args come after positional args. + # Therefore, all positional args must map to the first parameters. + args, kwargs = partition(lambda a: not bool(a.keyword), updated.args) + if any(k.keyword.value == "request" for k in kwargs): + # We've already fixed this file, don't fix it again. + return updated + + kwargs, ctrl_kwargs = partition( + lambda a: a.keyword.value not in self.CTRL_PARAMS, + kwargs + ) + + args, ctrl_args = args[:len(kword_params)], args[len(kword_params):] + ctrl_kwargs.extend(cst.Arg(value=a.value, keyword=cst.Name(value=ctrl)) + for a, ctrl in zip(ctrl_args, self.CTRL_PARAMS)) + + request_arg = cst.Arg( + value=cst.Dict([ + cst.DictElement( + cst.SimpleString("'{}'".format(name)), +cst.Element(value=arg.value) + ) + # Note: the args + kwargs looks silly, but keep in mind that + # the control parameters had to be stripped out, and that + # those could have been passed positionally or by keyword. + for name, arg in zip(kword_params, args + kwargs)]), + keyword=cst.Name("request") + ) + + return updated.with_changes( + args=[request_arg] + ctrl_kwargs + ) + + +def fix_files( + in_dir: pathlib.Path, + out_dir: pathlib.Path, + *, + transformer=texttospeechCallTransformer(), +): + """Duplicate the input dir to the output dir, fixing file method calls. + + Preconditions: + * in_dir is a real directory + * out_dir is a real, empty directory + """ + pyfile_gen = ( + pathlib.Path(os.path.join(root, f)) + for root, _, files in os.walk(in_dir) + for f in files if os.path.splitext(f)[1] == ".py" + ) + + for fpath in pyfile_gen: + with open(fpath, 'r') as f: + src = f.read() + + # Parse the code and insert method call fixes. + tree = cst.parse_module(src) + updated = tree.visit(transformer) + + # Create the path and directory structure for the new file. + updated_path = out_dir.joinpath(fpath.relative_to(in_dir)) + updated_path.parent.mkdir(parents=True, exist_ok=True) + + # Generate the updated source file at the corresponding path. + with open(updated_path, 'w') as f: + f.write(updated.code) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser( + description="""Fix up source that uses the texttospeech client library. + +The existing sources are NOT overwritten but are copied to output_dir with changes made. + +Note: This tool operates at a best-effort level at converting positional + parameters in client method calls to keyword based parameters. + Cases where it WILL FAIL include + A) * or ** expansion in a method call. + B) Calls via function or method alias (includes free function calls) + C) Indirect or dispatched calls (e.g. the method is looked up dynamically) + + These all constitute false negatives. The tool will also detect false + positives when an API method shares a name with another method. +""") + parser.add_argument( + '-d', + '--input-directory', + required=True, + dest='input_dir', + help='the input directory to walk for python files to fix up', + ) + parser.add_argument( + '-o', + '--output-directory', + required=True, + dest='output_dir', + help='the directory to output files fixed via un-flattening', + ) + args = parser.parse_args() + input_dir = pathlib.Path(args.input_dir) + output_dir = pathlib.Path(args.output_dir) + if not input_dir.is_dir(): + print( + f"input directory '{input_dir}' does not exist or is not a directory", + file=sys.stderr, + ) + sys.exit(-1) + + if not output_dir.is_dir(): + print( + f"output directory '{output_dir}' does not exist or is not a directory", + file=sys.stderr, + ) + sys.exit(-1) + + if os.listdir(output_dir): + print( + f"output directory '{output_dir}' is not empty", + file=sys.stderr, + ) + sys.exit(-1) + + fix_files(input_dir, output_dir) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/scripts/readme-gen/readme_gen.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/scripts/readme-gen/readme_gen.py new file mode 100644 index 000000000000..91b59676bfc7 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/scripts/readme-gen/readme_gen.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python + +# Copyright 2016 Google Inc +# +# 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. + +"""Generates READMEs using configuration defined in yaml.""" + +import argparse +import io +import os +import subprocess + +import jinja2 +import yaml + + +jinja_env = jinja2.Environment( + trim_blocks=True, + loader=jinja2.FileSystemLoader( + os.path.abspath(os.path.join(os.path.dirname(__file__), "templates")) + ), + autoescape=True, +) + +README_TMPL = jinja_env.get_template('README.tmpl.rst') + + +def get_help(file): + return subprocess.check_output(['python', file, '--help']).decode() + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('source') + parser.add_argument('--destination', default='README.rst') + + args = parser.parse_args() + + source = os.path.abspath(args.source) + root = os.path.dirname(source) + destination = os.path.join(root, args.destination) + + jinja_env.globals['get_help'] = get_help + + with io.open(source, 'r') as f: + config = yaml.load(f) + + # This allows get_help to execute in the right directory. + os.chdir(root) + + output = README_TMPL.render(config) + + with io.open(destination, 'w') as f: + f.write(output) + + +if __name__ == '__main__': + main() diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/scripts/readme-gen/templates/README.tmpl.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/scripts/readme-gen/templates/README.tmpl.rst new file mode 100644 index 000000000000..4fd239765b0a --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/scripts/readme-gen/templates/README.tmpl.rst @@ -0,0 +1,87 @@ +{# The following line is a lie. BUT! Once jinja2 is done with it, it will + become truth! #} +.. This file is automatically generated. Do not edit this file directly. + +{{product.name}} Python Samples +=============================================================================== + +.. image:: https://gstatic.com/cloudssh/images/open-btn.png + :target: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor={{folder}}/README.rst + + +This directory contains samples for {{product.name}}. {{product.description}} + +{{description}} + +.. _{{product.name}}: {{product.url}} + +{% if required_api_url %} +To run the sample, you need to enable the API at: {{required_api_url}} +{% endif %} + +{% if required_role %} +To run the sample, you need to have `{{required_role}}` role. +{% endif %} + +{{other_required_steps}} + +{% if setup %} +Setup +------------------------------------------------------------------------------- + +{% for section in setup %} + +{% include section + '.tmpl.rst' %} + +{% endfor %} +{% endif %} + +{% if samples %} +Samples +------------------------------------------------------------------------------- + +{% for sample in samples %} +{{sample.name}} ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +{% if not sample.hide_cloudshell_button %} +.. image:: https://gstatic.com/cloudssh/images/open-btn.png + :target: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor={{folder}}/{{sample.file}},{{folder}}/README.rst +{% endif %} + + +{{sample.description}} + +To run this sample: + +.. code-block:: bash + + $ python {{sample.file}} +{% if sample.show_help %} + + {{get_help(sample.file)|indent}} +{% endif %} + + +{% endfor %} +{% endif %} + +{% if cloud_client_library %} + +The client library +------------------------------------------------------------------------------- + +This sample uses the `Google Cloud Client Library for Python`_. +You can read the documentation for more details on API usage and use GitHub +to `browse the source`_ and `report issues`_. + +.. _Google Cloud Client Library for Python: + https://googlecloudplatform.github.io/google-cloud-python/ +.. _browse the source: + https://github.com/GoogleCloudPlatform/google-cloud-python +.. _report issues: + https://github.com/GoogleCloudPlatform/google-cloud-python/issues + +{% endif %} + +.. _Google Cloud SDK: https://cloud.google.com/sdk/ \ No newline at end of file diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/scripts/readme-gen/templates/auth.tmpl.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/scripts/readme-gen/templates/auth.tmpl.rst new file mode 100644 index 000000000000..1446b94a5e3a --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/scripts/readme-gen/templates/auth.tmpl.rst @@ -0,0 +1,9 @@ +Authentication +++++++++++++++ + +This sample requires you to have authentication setup. Refer to the +`Authentication Getting Started Guide`_ for instructions on setting up +credentials for applications. + +.. _Authentication Getting Started Guide: + https://cloud.google.com/docs/authentication/getting-started diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/scripts/readme-gen/templates/auth_api_key.tmpl.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/scripts/readme-gen/templates/auth_api_key.tmpl.rst new file mode 100644 index 000000000000..11957ce2714a --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/scripts/readme-gen/templates/auth_api_key.tmpl.rst @@ -0,0 +1,14 @@ +Authentication +++++++++++++++ + +Authentication for this service is done via an `API Key`_. To obtain an API +Key: + +1. Open the `Cloud Platform Console`_ +2. Make sure that billing is enabled for your project. +3. From the **Credentials** page, create a new **API Key** or use an existing + one for your project. + +.. _API Key: + https://developers.google.com/api-client-library/python/guide/aaa_apikeys +.. _Cloud Console: https://console.cloud.google.com/project?_ diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/scripts/readme-gen/templates/install_deps.tmpl.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/scripts/readme-gen/templates/install_deps.tmpl.rst new file mode 100644 index 000000000000..6f069c6c87a5 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/scripts/readme-gen/templates/install_deps.tmpl.rst @@ -0,0 +1,29 @@ +Install Dependencies +++++++++++++++++++++ + +#. Clone python-docs-samples and change directory to the sample directory you want to use. + + .. code-block:: bash + + $ git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git + +#. Install `pip`_ and `virtualenv`_ if you do not already have them. You may want to refer to the `Python Development Environment Setup Guide`_ for Google Cloud Platform for instructions. + + .. _Python Development Environment Setup Guide: + https://cloud.google.com/python/setup + +#. Create a virtualenv. Samples are compatible with Python 3.7+. + + .. code-block:: bash + + $ virtualenv env + $ source env/bin/activate + +#. Install the dependencies needed to run the samples. + + .. code-block:: bash + + $ pip install -r requirements.txt + +.. _pip: https://pip.pypa.io/ +.. _virtualenv: https://virtualenv.pypa.io/ diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/scripts/readme-gen/templates/install_portaudio.tmpl.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/scripts/readme-gen/templates/install_portaudio.tmpl.rst new file mode 100644 index 000000000000..5ea33d18c00c --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/scripts/readme-gen/templates/install_portaudio.tmpl.rst @@ -0,0 +1,35 @@ +Install PortAudio ++++++++++++++++++ + +Install `PortAudio`_. This is required by the `PyAudio`_ library to stream +audio from your computer's microphone. PyAudio depends on PortAudio for cross-platform compatibility, and is installed differently depending on the +platform. + +* For Mac OS X, you can use `Homebrew`_:: + + brew install portaudio + + **Note**: if you encounter an error when running `pip install` that indicates + it can't find `portaudio.h`, try running `pip install` with the following + flags:: + + pip install --global-option='build_ext' \ + --global-option='-I/usr/local/include' \ + --global-option='-L/usr/local/lib' \ + pyaudio + +* For Debian / Ubuntu Linux:: + + apt-get install portaudio19-dev python-all-dev + +* Windows may work without having to install PortAudio explicitly (it will get + installed with PyAudio). + +For more details, see the `PyAudio installation`_ page. + + +.. _PyAudio: https://people.csail.mit.edu/hubert/pyaudio/ +.. _PortAudio: http://www.portaudio.com/ +.. _PyAudio installation: + https://people.csail.mit.edu/hubert/pyaudio/#downloads +.. _Homebrew: http://brew.sh diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/format/numpy/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/setup.cfg similarity index 74% rename from packages/gcp-sphinx-docfx-yaml/tests/example/format/numpy/__init__.py rename to packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/setup.cfg index ea6283339a06..c3a2b39f6528 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/example/format/numpy/__init__.py +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/setup.cfg @@ -1,10 +1,12 @@ -# Copyright 2021 Google LLC +# -*- coding: utf-8 -*- +# +# Copyright 2020 Google LLC # # 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 +# https://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, @@ -12,5 +14,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -# coding: utf-8 -# This package is used to test numpy style docstring. +# Generated by synthtool. DO NOT EDIT! +[bdist_wheel] +universal = 1 diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/setup.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/setup.py new file mode 100644 index 000000000000..ff386677707e --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-auto/setup.py @@ -0,0 +1,104 @@ +# Copyright 2018 Google LLC +# +# 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 +# +# https://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. +# Copyright 2018 Google LLC +# +# 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. + +import io +import os + +import setuptools + +# Package metadata. + +name = "google-cloud-texttospeech" +description = "Google Cloud Text-to-Speech API client library" +version = "2.12.3" +# Should be one of: +# 'Development Status :: 3 - Alpha' +# 'Development Status :: 4 - Beta' +# 'Development Status :: 5 - Production/Stable' +release_status = "Development Status :: 5 - Production/Stable" +dependencies = [ + "google-api-core[grpc] >= 1.32.0, <3.0.0dev,!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*", + "proto-plus >= 1.22.0, <2.0.0dev", + "protobuf>=3.19.5,<5.0.0dev,!=3.20.0,!=3.20.1,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", +] +extras = {} + + +# Setup boilerplate below this line. + +package_root = os.path.abspath(os.path.dirname(__file__)) + +readme_filename = os.path.join(package_root, "README.rst") +with io.open(readme_filename, encoding="utf-8") as readme_file: + readme = readme_file.read() + +# Only include packages under the 'google' namespace. Do not include tests, +# benchmarks, etc. +packages = [ + package + for package in setuptools.PEP420PackageFinder.find() + if package.startswith("google") +] + +# Determine which namespaces are needed. +namespaces = ["google"] +if "google.cloud" in packages: + namespaces.append("google.cloud") + + +setuptools.setup( + name=name, + version=version, + description=description, + long_description=readme, + author="Google LLC", + author_email="googleapis-packages@google.com", + license="Apache 2.0", + url="https://github.com/googleapis/python-texttospeech", + classifiers=[ + release_status, + "Intended Audience :: Developers", + "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Operating System :: OS Independent", + "Topic :: Internet", + ], + platforms="Posix; MacOS X; Windows", + packages=packages, + namespace_packages=namespaces, + install_requires=dependencies, + extras_require=extras, + python_requires=">=3.7", + scripts=["scripts/fixup_keywords.py"], + include_package_data=True, + zip_safe=False, +) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/CHANGELOG.md b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/CHANGELOG.md new file mode 100644 index 000000000000..76c13f4f41fa --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/CHANGELOG.md @@ -0,0 +1,1149 @@ +# Changelog + +[PyPI History][1] + +[1]: https://pypi.org/project/google-cloud-pubsub/#history + + +## [2.13.10](https://github.com/googleapis/python-pubsub/compare/v2.13.8...v2.13.10) (2022-10-14) + + +### Bug Fixes + +* Batch at most 1,000 ack ids per request ([#802](https://github.com/googleapis/python-pubsub/issues/802)) ([4361e67](https://github.com/googleapis/python-pubsub/commit/4361e6735004a5600ee73979b99e6b9dd587c49b)) +* **deps:** Allow protobuf 3.19.5 ([#801](https://github.com/googleapis/python-pubsub/issues/801)) ([fa23503](https://github.com/googleapis/python-pubsub/commit/fa235033481783c2ec378b2a26b223bdff206461)) +* Silence invalid_ack_id warnings for receipt modacks ([#798](https://github.com/googleapis/python-pubsub/issues/798)) ([17feea5](https://github.com/googleapis/python-pubsub/commit/17feea5783f3a878b4dcfb3a8570585f7637378f)) + + +### Miscellaneous Chores + +* release as 2.13.10 ([34f022b](https://github.com/googleapis/python-pubsub/commit/34f022b4ee62d53a193bc2babafad508e2f2540b)) + +## [2.13.8](https://github.com/googleapis/python-pubsub/compare/v2.13.7...v2.13.8) (2022-10-03) + + +### Bug Fixes + +* **deps:** Require protobuf >= 3.20.2 ([#792](https://github.com/googleapis/python-pubsub/issues/792)) ([1a54f7c](https://github.com/googleapis/python-pubsub/commit/1a54f7cd3d997270e0a5d70f7caea32d8753be76)) + +## [2.13.7](https://github.com/googleapis/python-pubsub/compare/v2.13.6...v2.13.7) (2022-09-22) + + +### Bug Fixes + +* Remove expired ack_ids ([#787](https://github.com/googleapis/python-pubsub/issues/787)) ([b4b809d](https://github.com/googleapis/python-pubsub/commit/b4b809d616cf93881815d6baadf2dd322ab566d1)) + +## [2.13.6](https://github.com/googleapis/python-pubsub/compare/v2.13.5...v2.13.6) (2022-08-11) + + +### Bug Fixes + +* **deps:** allow protobuf < 5.0.0 ([#762](https://github.com/googleapis/python-pubsub/issues/762)) ([260bd18](https://github.com/googleapis/python-pubsub/commit/260bd183ffe19992be9a1c1d298438c1f44d3fa9)) +* **deps:** require proto-plus >= 1.22.0 ([260bd18](https://github.com/googleapis/python-pubsub/commit/260bd183ffe19992be9a1c1d298438c1f44d3fa9)) +* set stream_ack_deadline to max_duration_per_lease_extension or 60 s, set ack_deadline to min_duration_per_lease_extension or 10 s ([#760](https://github.com/googleapis/python-pubsub/issues/760)) ([4444129](https://github.com/googleapis/python-pubsub/commit/4444129b28a19296752e865b73827b78e99adea5)) +* Update stream_ack_deadline with ack_deadline ([#763](https://github.com/googleapis/python-pubsub/issues/763)) ([e600ad8](https://github.com/googleapis/python-pubsub/commit/e600ad8228930445765ffa0c45500a7779e25817)) + +## [2.13.5](https://github.com/googleapis/python-pubsub/compare/v2.13.4...v2.13.5) (2022-08-10) + + +### Documentation + +* reorganize sphinx structure ([#751](https://github.com/googleapis/python-pubsub/issues/751)) ([b6de574](https://github.com/googleapis/python-pubsub/commit/b6de57458a1976a068dd229208b9b678a9d3f866)) + +## [2.13.4](https://github.com/googleapis/python-pubsub/compare/v2.13.3...v2.13.4) (2022-07-15) + + +### Bug Fixes + +* Remove bidi modacks on StreamingPull initial request ([#738](https://github.com/googleapis/python-pubsub/issues/738)) ([1e7d469](https://github.com/googleapis/python-pubsub/commit/1e7d46901c4472a3534980621e88d81aa2e50760)) + +## [2.13.3](https://github.com/googleapis/python-pubsub/compare/v2.13.2...v2.13.3) (2022-07-13) + + +### Bug Fixes + +* **deps:** require google-api-core>=1.32.0,>=2.8.0 ([#735](https://github.com/googleapis/python-pubsub/issues/735)) ([a5624fb](https://github.com/googleapis/python-pubsub/commit/a5624fbee2951c7f0c3e413d7d399a41fa0aa4bf)) + +## [2.13.2](https://github.com/googleapis/python-pubsub/compare/v2.13.1...v2.13.2) (2022-07-08) + + +### Bug Fixes + +* **deps:** require google-api-core >= 2.8.0 ([#726](https://github.com/googleapis/python-pubsub/issues/726)) ([c80ad41](https://github.com/googleapis/python-pubsub/commit/c80ad41abf36c709f8299a6fa22f3672705b1b6d)) + +## [2.13.1](https://github.com/googleapis/python-pubsub/compare/v2.13.0...v2.13.1) (2022-07-07) + + +### Bug Fixes + +* change info logs to debug ([#693](https://github.com/googleapis/python-pubsub/issues/693)) ([950fbce](https://github.com/googleapis/python-pubsub/commit/950fbce009fd56a55feea971f8e6083fa84d54fc)) +* require python 3.7+ ([#730](https://github.com/googleapis/python-pubsub/issues/730)) ([0d949b8](https://github.com/googleapis/python-pubsub/commit/0d949b8da096d1b0a5e26f607b1cd79fb560252a)) + +## [2.13.0](https://github.com/googleapis/python-pubsub/compare/v2.12.1...v2.13.0) (2022-06-06) + + +### Features + +* add BigQuery configuration for subscriptions ([#685](https://github.com/googleapis/python-pubsub/issues/685)) ([6fa03be](https://github.com/googleapis/python-pubsub/commit/6fa03be779d6a7105bb7c029b95d4c357d2a49df)) + + +### Bug Fixes + +* add info log for bidi streaming pull ack_deadline requests ([#692](https://github.com/googleapis/python-pubsub/issues/692)) ([fcb67dd](https://github.com/googleapis/python-pubsub/commit/fcb67dd0d8fff5a583ebe0a3a08d0219601df8e9)) +* **deps:** require protobuf <4.0.0dev ([#699](https://github.com/googleapis/python-pubsub/issues/699)) ([dcdf013](https://github.com/googleapis/python-pubsub/commit/dcdf0137905949662ce191adcb6dd588bd74f9fe)) + + +### Documentation + +* fix changelog header to consistent size ([#700](https://github.com/googleapis/python-pubsub/issues/700)) ([93f2b62](https://github.com/googleapis/python-pubsub/commit/93f2b62a18f622d8da71043a6b6d3f53295db308)) + +## [2.12.1](https://github.com/googleapis/python-pubsub/compare/v2.12.0...v2.12.1) (2022-05-11) + + +### Bug Fixes + +* Add emulator support to schema service ([#658](https://github.com/googleapis/python-pubsub/issues/658)) ([1a07d7c](https://github.com/googleapis/python-pubsub/commit/1a07d7ce3b3580191f74b7895dd1b8afb13baccb)) +* Handle duplicate acks with streaming pull ([#662](https://github.com/googleapis/python-pubsub/issues/662)) ([219491e](https://github.com/googleapis/python-pubsub/commit/219491ea1e615f33e1955e3afc204a0281c525db)) +* set min snooze on lease management to .01 sec ([#678](https://github.com/googleapis/python-pubsub/issues/678)) ([91c6e69](https://github.com/googleapis/python-pubsub/commit/91c6e69e96953919bc86004692edd3a52c7b9796)) + + +### Documentation + +* fix project_path typo in UPGRADING.md ([#660](https://github.com/googleapis/python-pubsub/issues/660)) ([20d661c](https://github.com/googleapis/python-pubsub/commit/20d661c8562cc1f777ac7b3f1ba03dcad7a831c0)) +* mark eod as preview ([#657](https://github.com/googleapis/python-pubsub/issues/657)) ([418e1a3](https://github.com/googleapis/python-pubsub/commit/418e1a3783441469713ca8ec8776007ff0fdb15d)) + +## [2.12.0](https://github.com/googleapis/python-pubsub/compare/v2.11.0...v2.12.0) (2022-04-06) + + +### Features + +* increase GRPC max metadata size to 4 MB ([#623](https://github.com/googleapis/python-pubsub/issues/623)) ([54b9e07](https://github.com/googleapis/python-pubsub/commit/54b9e07401b7309f16ecfe2a7afc36ea69f24a9c)) + + +### Bug Fixes + +* mypy errors ([#622](https://github.com/googleapis/python-pubsub/issues/622)) ([dab13d5](https://github.com/googleapis/python-pubsub/commit/dab13d5fb1d723c971cd84ae20f18462e624a26d)) +* process ErrorInfo / GRPC errors for ack/modack only when exactly-once delivery is enabled ([#626](https://github.com/googleapis/python-pubsub/issues/626)) ([cc1953b](https://github.com/googleapis/python-pubsub/commit/cc1953bcf942fb394a92ba50ba615adf822bfe7d)) + +## [2.11.0](https://github.com/googleapis/python-pubsub/compare/v2.10.0...v2.11.0) (2022-03-09) + + +### Features + +* retry temporary GRPC statuses for ack/modack/nack when exactly-once delivery is enabled ([#607](https://github.com/googleapis/python-pubsub/issues/607)) ([a91bed8](https://github.com/googleapis/python-pubsub/commit/a91bed829c9040fcc6c1e70b99b66188ac4ded40)) +* return singleton success future for exactly-once methods in Message ([#608](https://github.com/googleapis/python-pubsub/issues/608)) ([253ced2](https://github.com/googleapis/python-pubsub/commit/253ced28f308450c7a1a93cc38f6d101ecd7d4c0)) + + +### Bug Fixes + +* **deps:** require google-api-core>=1.31.5, >=2.3.2 ([#600](https://github.com/googleapis/python-pubsub/issues/600)) ([1608b7f](https://github.com/googleapis/python-pubsub/commit/1608b7ffdd5b5db87e1e55fde763440ca9a4086e)) +* **deps:** require proto-plus>=1.15.0 ([1608b7f](https://github.com/googleapis/python-pubsub/commit/1608b7ffdd5b5db87e1e55fde763440ca9a4086e)) + +## [2.10.0](https://github.com/googleapis/python-pubsub/compare/v2.9.0...v2.10.0) (2022-03-04) + + +### Features + +* add api key support ([#571](https://github.com/googleapis/python-pubsub/issues/571)) ([cdda762](https://github.com/googleapis/python-pubsub/commit/cdda762f6d15d96f5e2d7fac975f3494dc49eaa9)) +* add exactly once delivery flag ([#577](https://github.com/googleapis/python-pubsub/issues/577)) ([d6614e2](https://github.com/googleapis/python-pubsub/commit/d6614e274328c58449e67dfc788e2e7986c0c10b)) +* add support for exactly once delivery ([#578](https://github.com/googleapis/python-pubsub/issues/578)) ([95a86fa](https://github.com/googleapis/python-pubsub/commit/95a86fa5f528701b760064f0cece0efa4e60cd44)) +* exactly-once delivery support ([#550](https://github.com/googleapis/python-pubsub/issues/550)) ([2fb6e15](https://github.com/googleapis/python-pubsub/commit/2fb6e1533192ae81dceee5c71283169a0a85a015)) + + +### Bug Fixes + +* **deps:** move libcst to extras ([#585](https://github.com/googleapis/python-pubsub/issues/585)) ([0846762](https://github.com/googleapis/python-pubsub/commit/084676243ca4afd54cda601e589b80883f9703a3)) +* refactor client classes for safer type checking ([#552](https://github.com/googleapis/python-pubsub/issues/552)) ([7f705be](https://github.com/googleapis/python-pubsub/commit/7f705beb927383f14b9d56f0341ee0de101f7c05)) +* resolve DuplicateCredentialArgs error when using credentials_file ([8ca8cf2](https://github.com/googleapis/python-pubsub/commit/8ca8cf27333baf823a1dffd081e63079f1a12625)) + + +### Samples +* samples: create subscription with filtering enabled [#580](https://github.com/googleapis/python-pubsub/pull/580) +* samples: handle empty response in sync pull samples [#586](https://github.com/googleapis/python-pubsub/pull/586) +* samples: sample for receiving messages with exactly-once delivery enabled [#588](https://github.com/googleapis/python-pubsub/pull/588) +* samples: create subscription with exactly once delivery [#592](https://github.com/googleapis/python-pubsub/pull/592) +(https://github.com/googleapis/python-pubsub/pull/588 + + +### Documentation + +* add autogenerated code snippets ([aa3754c](https://github.com/googleapis/python-pubsub/commit/aa3754cf432bd02be2734a23a32d5b36cd216aee)) +* Docs have inconsistent default values for max_latency and max_bytes ([#572](https://github.com/googleapis/python-pubsub/issues/572)) ([d136dfd](https://github.com/googleapis/python-pubsub/commit/d136dfdb69ebeebd1411a1415f863b94d07078f0)) + +## [2.9.0](https://www.github.com/googleapis/python-pubsub/compare/v2.8.0...v2.9.0) (2021-11-10) + + +### Features + +* add context manager support in client ([#516](https://www.github.com/googleapis/python-pubsub/issues/516)) ([51eae67](https://www.github.com/googleapis/python-pubsub/commit/51eae67c47e2ce7d2f7620209e98df4a129801b5)) +* add support for Python 3.10 ([#518](https://www.github.com/googleapis/python-pubsub/issues/518)) ([bb25d75](https://www.github.com/googleapis/python-pubsub/commit/bb25d755d70ba19e69d8a281be65f13eb994967d)) + + +### Bug Fixes + +* add 'dict' annotation type to 'request' ([b72522a](https://www.github.com/googleapis/python-pubsub/commit/b72522a4617c4b2773fb6a5a631038791aa08300)) +* **deps:** drop packaging dependency ([290b9c5](https://www.github.com/googleapis/python-pubsub/commit/290b9c5615eaa03674b773a27b756483abd76195)) +* **deps:** require google-api-core >= 1.28.0 ([290b9c5](https://www.github.com/googleapis/python-pubsub/commit/290b9c5615eaa03674b773a27b756483abd76195)) +* improper types in pagers generation ([2ad639d](https://www.github.com/googleapis/python-pubsub/commit/2ad639d6370c7a085498595d7bd0d7eaadfff3c1)) + + +### Documentation + +* add type annotations to codebase ([#509](https://www.github.com/googleapis/python-pubsub/issues/509)) ([093cabf](https://www.github.com/googleapis/python-pubsub/commit/093cabff9f0464b1dfaa8f373b6fffbc439518de)) +* list oneofs in docstring ([290b9c5](https://www.github.com/googleapis/python-pubsub/commit/290b9c5615eaa03674b773a27b756483abd76195)) + +## [2.8.0](https://www.github.com/googleapis/python-pubsub/compare/v2.7.1...v2.8.0) (2021-09-02) + + +### Features + +* closed subscriber as context manager raises ([#488](https://www.github.com/googleapis/python-pubsub/issues/488)) ([a05a3f2](https://www.github.com/googleapis/python-pubsub/commit/a05a3f250cf8567ffe0d2eb3ecc45856a2bcd07c)) + + +### Documentation + +* clarify the types of Message parameters ([#486](https://www.github.com/googleapis/python-pubsub/issues/486)) ([633e91b](https://www.github.com/googleapis/python-pubsub/commit/633e91bbfc0a8f4f484089acff6812b754f40c75)) + +## [2.7.1](https://www.github.com/googleapis/python-pubsub/compare/v2.7.0...v2.7.1) (2021-08-13) + + +### Bug Fixes + +* remove dependency on pytz ([#472](https://www.github.com/googleapis/python-pubsub/issues/472)) ([972cc16](https://www.github.com/googleapis/python-pubsub/commit/972cc163f5a1477b37a5ab7e329faf1468637fa2)) + +## [2.7.0](https://www.github.com/googleapis/python-pubsub/compare/v2.6.1...v2.7.0) (2021-07-24) + + +### Features + +* Add `always_use_jwt_access`. ([1f30ef7](https://www.github.com/googleapis/python-pubsub/commit/1f30ef7f26ae1156751bc42305b1eb156115b5e5)) +* Add method signature for `Subscriber.Pull` without the deprecated `return_immediately` field. ([1f30ef7](https://www.github.com/googleapis/python-pubsub/commit/1f30ef7f26ae1156751bc42305b1eb156115b5e5)) +* Add Pub/Sub topic retention fields. ([#456](https://www.github.com/googleapis/python-pubsub/issues/456)) ([911829d](https://www.github.com/googleapis/python-pubsub/commit/911829d85c6ec36a87b873cbfe34497b1a493dde)) +* Add subscription properties to streaming pull response. ([1f30ef7](https://www.github.com/googleapis/python-pubsub/commit/1f30ef7f26ae1156751bc42305b1eb156115b5e5)) +* Support self-signed JWT flow for service accounts. ([1f30ef7](https://www.github.com/googleapis/python-pubsub/commit/1f30ef7f26ae1156751bc42305b1eb156115b5e5)) + + +### Bug Fixes + +* Add async client to `%name_%version/init.py`. ([1f30ef7](https://www.github.com/googleapis/python-pubsub/commit/1f30ef7f26ae1156751bc42305b1eb156115b5e5)) +* Disable `always_use_jwt_access`. ([1f30ef7](https://www.github.com/googleapis/python-pubsub/commit/1f30ef7f26ae1156751bc42305b1eb156115b5e5)) +* Enable self signed JWT for gRPC. ([#458](https://www.github.com/googleapis/python-pubsub/issues/458)) ([c6e0ff6](https://www.github.com/googleapis/python-pubsub/commit/c6e0ff69faeda614aa6088af59d3420e16720d27)) + +### Dependencies + +* Add `packaging` requirement. ([1f30ef7](https://www.github.com/googleapis/python-pubsub/commit/1f30ef7f26ae1156751bc42305b1eb156115b5e5)) +* Require `google-api-core >= 1.26.0`. ([1f30ef7](https://www.github.com/googleapis/python-pubsub/commit/1f30ef7f26ae1156751bc42305b1eb156115b5e5)) + +## 2.6.1 + +07-05-2021 10:33 PDT + +### Dependencies + +- Fix possible crash by requiring `grpcio >= 1.38.1`. ([#414](https://github.com/googleapis/python-pubsub/issues/414)) ([7037a28](https://github.com/googleapis/python-pubsub/pull/435/commits/7037a28090aa4efa01808231721716bca80bb0b7)) + +### Documentation + +- Adjust samples for publishing with error handler and flow control. ([#433](https://github.com/googleapis/python-pubsub/pull/433)) + +### Internal / Testing Changes + +- Fix flaky sync pull sample test. ([#434](https://github.com/googleapis/python-pubsub/pull/434)) +- Mitigate flaky snippets tests. ([#432](https://github.com/googleapis/python-pubsub/pull/432)) + +## [2.6.0](https://www.github.com/googleapis/python-pubsub/compare/v2.5.0...v2.6.0) (2021-06-17) + + +### Features + +* support customizable retry and timeout settings on the publisher client ([#299](https://www.github.com/googleapis/python-pubsub/issues/299)) ([7597604](https://www.github.com/googleapis/python-pubsub/commit/7597604b41fa3a1e9bf34addc35c8647dde007cc)) + + +### Bug Fixes + +* ACK deadline set for received messages can be too low ([#416](https://www.github.com/googleapis/python-pubsub/issues/416)) ([e907f6e](https://www.github.com/googleapis/python-pubsub/commit/e907f6e05f59f64a3b08df3304e92ec960997be6)) +* threads can skip the line in publisher flow controller ([#422](https://www.github.com/googleapis/python-pubsub/issues/422)) ([ef89f55](https://www.github.com/googleapis/python-pubsub/commit/ef89f55a41044e9ad26b91132b4b1be9c7b2c127)) + + +### Documentation + +* block until the streaming pull shuts down ([#424](https://www.github.com/googleapis/python-pubsub/issues/424)) ([d0d0b70](https://www.github.com/googleapis/python-pubsub/commit/d0d0b704642df8dee893d3f585aeb666e19696fb)) +* explain that future.cancel() is non-blocking ([#420](https://www.github.com/googleapis/python-pubsub/issues/420)) ([c825789](https://www.github.com/googleapis/python-pubsub/commit/c825789bdff310f44cbb132a723e99d1e6331d8f)) + +## [2.5.0](https://www.github.com/googleapis/python-pubsub/compare/v2.4.2...v2.5.0) (2021-05-18) + + +### Features + +* Make publish futures compatible with `concurrent.futures.as_completed()`. ([#397](https://www.github.com/googleapis/python-pubsub/issues/397)) ([e29a2c0](https://www.github.com/googleapis/python-pubsub/commit/e29a2c0ac6c5d2ebf2311646e552a02f184cfedc)) + + +### Bug Fixes + +* Scheduler errors when executor in shutdown. ([#399](https://www.github.com/googleapis/python-pubsub/issues/399)) ([39a83d3](https://www.github.com/googleapis/python-pubsub/commit/39a83d3eef196e88478ad8362201a2ab12e9f681)) + +## 2.4.2 + +05-06-2021 23:50 PDT + + +### Implementation Changes + +- Fix memory leak when publishing messages. ([#406](https://github.com/googleapis/python-pubsub/pull/406)) +- Do not crash if distribution cannot be found when extracting semantic version. ([#393](https://github.com/googleapis/python-pubsub/pull/393)) +- Emit a warning if `return_immediately` is set with synchronous pull. ([#355](https://github.com/googleapis/python-pubsub/pull/355)) +- Regenerate GAPIC layer with latest changes, use explicit default timeouts. ([#345](https://github.com/googleapis/python-pubsub/pull/345)) + + +### Documentation + +- Add additional info on `use_legacy_flow_control` parameter. ([#301](https://github.com/googleapis/python-pubsub/pull/301)) +- Remove EXPERIMENTAL tag for ordering keys in `publisher/client.py`. ([#324](https://github.com/googleapis/python-pubsub/pull/324)) +- Fix `create_topic()` call in README. ([#360](https://github.com/googleapis/python-pubsub/pull/360)) +- Generate PyPI token in secrets manager, fix spacing in docs (via synth). ([#384](https://github.com/googleapis/python-pubsub/pull/384)) +- Add `SECURITY.md`. ([#401](https://github.com/googleapis/python-pubsub/pull/401)) + + +### Internal / Testing Changes + +- Require 100% unit test coverage (via synth). ([#359](https://github.com/googleapis/python-pubsub/pull/359)) +- Bump test coverage to 100%. ([#364](https://github.com/googleapis/python-pubsub/pull/364)) +- Fix streaming pull close unit test flakiness. ([#361](https://github.com/googleapis/python-pubsub/pull/361)) +- Pass explicit credentials in all unit tests creating clients. ([#369](https://github.com/googleapis/python-pubsub/pull/369)) +- Fix flaky test for blocking pull shutdown. ([#378](https://github.com/googleapis/python-pubsub/pull/378)) +- Add missing licence header. ([#377](https://github.com/googleapis/python-pubsub/pull/377)) + +## [2.4.1](https://www.github.com/googleapis/python-pubsub/compare/v2.4.0...v2.4.1) (2021-03-30) + +### Bug Fixes + +* Move `await_msg_callbacks` flag to `subscribe()` method, fixing a regression in Pub/Sub Lite client. + ([#320](https://www.github.com/googleapis/python-pubsub/issues/320)) ([d40d027](https://www.github.com/googleapis/python-pubsub/commit/d40d02713c8c189937ae5c21d099b88a3131a59f)) +* SSL error when using the client with the emulator. ([#297](https://www.github.com/googleapis/python-pubsub/issues/297)) ([83db672](https://www.github.com/googleapis/python-pubsub/commit/83db67239d3521457138699109f766d574a0a2c4)) + +### Implementation Changes + +* (samples) Bump the max_time to 10 minutes for a flaky test. ([#311](https://www.github.com/googleapis/python-pubsub/issues/311)) ([e2678d4](https://www.github.com/googleapis/python-pubsub/commit/e2678d47c08e6b03782d2d744a4e630b933fdd51)), closes [#291](https://www.github.com/googleapis/python-pubsub/issues/291) +* (samples) Mark delivery attempts test as flaky. ([#326](https://www.github.com/googleapis/python-pubsub/issues/326)) ([5a97ef1](https://www.github.com/googleapis/python-pubsub/commit/5a97ef1bb7512fe814a8f72a43b3e9698434cd8d)) +* (samples) Mitigate flakiness in subscriber_tests. ([#304](https://www.github.com/googleapis/python-pubsub/issues/304)) ([271a385](https://www.github.com/googleapis/python-pubsub/commit/271a3856d835967f18f6becdae5ad53d585d0ccf)) +* (samples) Retry `InternalServerError` in dead letter policy test. ([#329](https://www.github.com/googleapis/python-pubsub/issues/329)) ([34c9b11](https://www.github.com/googleapis/python-pubsub/commit/34c9b11ae697c280f32642c3101b7f7da971f589)), closes [#321](https://www.github.com/googleapis/python-pubsub/issues/321) + +### Documentation + +* Remove EXPERIMENTAL tag for ordering keys in `types.py`. ([#323](https://www.github.com/googleapis/python-pubsub/issues/323)) ([659cd7a](https://www.github.com/googleapis/python-pubsub/commit/659cd7ae2784245d4217fbc722dac04bd3222d32)) +* Remove EXPERIMENTAL tag from `Schema` service (via synth). ([#307](https://www.github.com/googleapis/python-pubsub/issues/307)) ([ad85202](https://www.github.com/googleapis/python-pubsub/commit/ad852028836520db779c5cc33689ffd7e5458a7d)) + + +## 2.4.0 + +02-22-2021 05:02 PST + + +### Implementation Changes + +### New Features + +- Add graceful streaming pull shutdown. ([#292](https://github.com/googleapis/python-pubsub/pull/292)) + +### Documentation + +- Update samples with using the subscriber client as a context manager. ([#254](https://github.com/googleapis/python-pubsub/pull/254)) + +## [2.3.0](https://www.github.com/googleapis/python-pubsub/compare/v2.2.0...v2.3.0) (2021-02-08) + + +### Features + +* surface SchemaServiceClient in google.cloud.pubsub ([#281](https://www.github.com/googleapis/python-pubsub/issues/281)) ([8751bcc](https://www.github.com/googleapis/python-pubsub/commit/8751bcc5eb782df55769b48253629a3bde3d4661)) + + +### Bug Fixes + +* client version missing from the user agent header ([#275](https://www.github.com/googleapis/python-pubsub/issues/275)) ([b112f4f](https://www.github.com/googleapis/python-pubsub/commit/b112f4fcbf6f2bce8dcf37871bdc540b11f54fe3)) +* Don't open the google.cloud package by adding pubsub.py ([#269](https://www.github.com/googleapis/python-pubsub/issues/269)) ([542d79d](https://www.github.com/googleapis/python-pubsub/commit/542d79d7c5fb7403016150ba477485756cd4097b)) +* flaky samples tests ([#263](https://www.github.com/googleapis/python-pubsub/issues/263)) ([3d6a29d](https://www.github.com/googleapis/python-pubsub/commit/3d6a29de07cc09be663c90a3333f4cd33633994f)) +* Modify synth.py to update grpc transport options ([#266](https://www.github.com/googleapis/python-pubsub/issues/266)) ([41dcd30](https://www.github.com/googleapis/python-pubsub/commit/41dcd30636168f3dd1248f1d99170d531fc9bcb8)) +* pass anonymous credentials for emulator ([#250](https://www.github.com/googleapis/python-pubsub/issues/250)) ([8eed8e1](https://www.github.com/googleapis/python-pubsub/commit/8eed8e16019510dc8b20fb6b009d61a7ac532d26)) +* remove grpc send/recieve limits ([#259](https://www.github.com/googleapis/python-pubsub/issues/259)) ([fd2840c](https://www.github.com/googleapis/python-pubsub/commit/fd2840c10f92b03da7f4b40ac69c602220757c0a)) + +## [2.2.0](https://www.github.com/googleapis/python-pubsub/compare/v2.1.0...v2.2.0) (2020-11-16) + + +### Features + +* Add dead lettering max delivery attempts argument ([#236](https://www.github.com/googleapis/python-pubsub/issues/236)) ([7687ae5](https://www.github.com/googleapis/python-pubsub/commit/7687ae500bdb9c76e3ffb23302b4f32dc9627d81)) +* Enable server side flow control by default with the option to turn it off ([#231](https://www.github.com/googleapis/python-pubsub/issues/231)) ([94d738c](https://www.github.com/googleapis/python-pubsub/commit/94d738c07c6404a152c6729f5ba4b106b1fe9355)) + + +### Bug Fixes + +* fix mtls issue in handwritten layer ([#226](https://www.github.com/googleapis/python-pubsub/issues/226)) ([09a409c](https://www.github.com/googleapis/python-pubsub/commit/09a409c6240a74dcb46d8f3f86d4fb95a52274a7)) +* make fixup script consistent with migration docs ([#208](https://www.github.com/googleapis/python-pubsub/issues/208)) ([b64e218](https://www.github.com/googleapis/python-pubsub/commit/b64e2187ab0810437575580d6ddb5315ff60e274)) + + +### Documentation + +* document potentially unexpected blocking behavior of publish() method ([#214](https://www.github.com/googleapis/python-pubsub/issues/214)) ([b6d9bd7](https://www.github.com/googleapis/python-pubsub/commit/b6d9bd7c38d4fe597c25b7b5869fd4a1259c7687)) +* fix get topic_path in subscriber sample ([#210](https://www.github.com/googleapis/python-pubsub/issues/210)) ([7228f6c](https://www.github.com/googleapis/python-pubsub/commit/7228f6c9a4c050bf22bb4bc3582b89b04eaa8702)) + +## 2.1.0 + +09-21-2020 02:19 PDT + + +### Implementation Changes + +- Convert all RPC error types to exceptions. ([#163](https://github.com/googleapis/python-pubsub/issues/163)) ([#170](https://github.com/googleapis/python-pubsub/pull/170)) +- Pass client options to publisher and subscriber clients. ([#166](https://github.com/googleapis/python-pubsub/issues/166)) ([#190](https://github.com/googleapis/python-pubsub/pull/190)) + + +### New Features + +- Regenerate the client lib to pick new mtls env (via synth). ([#197](https://github.com/googleapis/python-pubsub/pull/197)) + + +### Documentation + +- Add subscription detachment sample. ([#152](https://github.com/googleapis/python-pubsub/pull/152)) +- Use new call syntax in subscriber docs. ([#198](https://github.com/googleapis/python-pubsub/issues/198)) ([#203](https://github.com/googleapis/python-pubsub/pull/203)) + + +### Internal / Testing Changes + +- Update CODEOWNERS. ([#193](https://github.com/googleapis/python-pubsub/pull/193)) + +## 2.0.0 + +09-11-2020 05:03 PDT + + +### Implementation Changes + +- Transition the library to microgenerator. ([#158](https://github.com/googleapis/python-pubsub/pull/158)) + This is a **breaking change** that introduces several **method signature changes** and **drops support + for Python 2.7 and 3.5**. + +### Documentation + +- Add samples for using ordering keys. ([#156](https://github.com/googleapis/python-pubsub/pull/156)) +- Remove extra white space in delivery attempt sample. ([#159](https://github.com/googleapis/python-pubsub/pull/159)) + +### Internal / Testing Changes + +- Fix flaky sequencer unit tests. ([#187](https://github.com/googleapis/python-pubsub/pull/187)) + +## [1.7.0](https://www.github.com/googleapis/python-pubsub/compare/v1.6.1...v1.7.0) (2020-07-13) + +This is the last release that supports Python 2.7 and 3.5. + +### New Features + +- Add support for server-side flow control. ([#143](https://github.com/googleapis/python-pubsub/pull/143)) ([04e261c](https://www.github.com/googleapis/python-pubsub/commit/04e261c602a2919cc75b3efa3dab099fb2cf704c)) + +### Dependencies + +- Update samples dependency `google-cloud-pubsub` to `v1.6.1`. ([#144](https://github.com/googleapis/python-pubsub/pull/144)) ([1cb6746](https://github.com/googleapis/python-pubsub/commit/1cb6746b00ebb23dbf1663bae301b32c3fc65a88)) + +### Documentation + +- Add pubsub/cloud-client samples from the common samples repo (with commit history). ([#151](https://github.com/googleapis/python-pubsub/pull/151)) +- Add flow control section to publish overview. ([#129](https://github.com/googleapis/python-pubsub/pull/129)) ([acc19eb](https://www.github.com/googleapis/python-pubsub/commit/acc19eb048eef067d9818ef3e310b165d9c6307e)) +- Add a link to Pub/Sub filtering language public documentation to `pubsub.proto`. ([#121](https://github.com/googleapis/python-pubsub/pull/121)) ([8802d81](https://www.github.com/googleapis/python-pubsub/commit/8802d8126247f22e26057e68a42f5b5a82dcbf0d)) + + +## [1.6.1](https://www.github.com/googleapis/python-pubsub/compare/v1.6.0...v1.6.1) (2020-06-30) + + +### Documentation + +* added Python2 sunset notice (synth) ([#140](https://www.github.com/googleapis/python-pubsub/issues/140)) ([c8f6378](https://www.github.com/googleapis/python-pubsub/commit/c8f63788636c2e3436c8ce6a01ef3b59e3df772a)) +* explain how to nack a sync pull message ([#123](https://www.github.com/googleapis/python-pubsub/issues/123)) ([f2eec65](https://www.github.com/googleapis/python-pubsub/commit/f2eec65cec43066ba7a2d1d45efa979e6b7add4f)) + +## [1.6.0](https://www.github.com/googleapis/python-pubsub/compare/v1.5.0...v1.6.0) (2020-06-09) + + +### Features + +* Add flow control for message publishing ([#96](https://www.github.com/googleapis/python-pubsub/issues/96)) ([06085c4](https://www.github.com/googleapis/python-pubsub/commit/06085c4083b9dccdd50383257799904510bbf3a0)) + + +### Bug Fixes + +* Fix PubSub incompatibility with api-core 1.17.0+ ([#103](https://www.github.com/googleapis/python-pubsub/issues/103)) ([c02060f](https://www.github.com/googleapis/python-pubsub/commit/c02060fbbe6e2ca4664bee08d2de10665d41dc0b)) + + +### Documentation +- Clarify that Schedulers shouldn't be used with multiple SubscriberClients ([#100](https://github.com/googleapis/python-pubsub/pull/100)) ([cf9e87c](https://github.com/googleapis/python-pubsub/commit/cf9e87c80c0771f3fa6ef784a8d76cb760ad37ef)) +- Fix update subscription/snapshot/topic samples ([#113](https://github.com/googleapis/python-pubsub/pull/113)) ([e62c38b](https://github.com/googleapis/python-pubsub/commit/e62c38bb33de2434e32f866979de769382dea34a)) + + +### Internal / Testing Changes +- Re-generated service implementaton using synth: removed experimental notes from the RetryPolicy and filtering features in anticipation of GA, added DetachSubscription (experimental) ([#114](https://github.com/googleapis/python-pubsub/pull/114)) ([0132a46](https://github.com/googleapis/python-pubsub/commit/0132a4680e0727ce45d5e27d98ffc9f3541a0962)) +- Incorporate will_accept() checks into publish() ([#108](https://github.com/googleapis/python-pubsub/pull/108)) ([6c7677e](https://github.com/googleapis/python-pubsub/commit/6c7677ecb259672bbb9b6f7646919e602c698570)) + +## [1.5.0](https://www.github.com/googleapis/python-pubsub/compare/v1.4.3...v1.5.0) (2020-05-04) + + +### Features + +* add methods for listing snapshots (via synth) ([#66](https://www.github.com/googleapis/python-pubsub/issues/66)) ([4ce898e](https://www.github.com/googleapis/python-pubsub/commit/4ce898e80eeb16b18d1ee29c678ade149804d186)) +* send client id with StreamingPullRequest ([#58](https://www.github.com/googleapis/python-pubsub/issues/58)) ([9f8acfa](https://www.github.com/googleapis/python-pubsub/commit/9f8acfacfbe93224f59439bb51a17fc28b06c22a)), closes [#62](https://www.github.com/googleapis/python-pubsub/issues/62) + +## [1.4.3](https://www.github.com/googleapis/python-pubsub/compare/v1.4.2...v1.4.3) (2020-04-16) + + +### Bug Fixes + +* fix docs warnings in Sphinx 3.0+ ([#70](https://www.github.com/googleapis/python-pubsub/issues/70)) ([21e761e](https://www.github.com/googleapis/python-pubsub/commit/21e761ee89a4c03e105dc9cddbab0a34be9a9fda)) +* restrict api-core dependency to < 1.17.0 ([#76](https://www.github.com/googleapis/python-pubsub/issues/76)) ([191b051](https://www.github.com/googleapis/python-pubsub/commit/191b0516335f5c60828a818ba79e99d6c68aa7bd)) + +## [1.4.2](https://www.github.com/googleapis/python-pubsub/compare/v1.4.1...v1.4.2) (2020-03-25) + +### Bug Fixes + +* update generated retry timings for publish and pull rpcs via synth ([#43](https://www.github.com/googleapis/python-pubsub/issues/43)) ([4f7fe85](https://www.github.com/googleapis/python-pubsub/commit/4f7fe85618d811fea94cb46b5dc758aa78c328a8)) +* use client_options.api_endpoint parameter instead of ignoring it ([#59](https://www.github.com/googleapis/python-pubsub/issues/59)) ([56b8d7b](https://www.github.com/googleapis/python-pubsub/commit/56b8d7b046a495ce2ce59bebdd354385147a5013)), closes [#61](https://www.github.com/googleapis/python-pubsub/issues/61) + +## [1.4.1](https://www.github.com/googleapis/python-pubsub/compare/v1.4.0...v1.4.1) (2020-03-23) + +### Bug Fixes + +* Don't assert on unordered publishes after publish error. ([#49](https://www.github.com/googleapis/python-pubsub/issues/49)) ([ea19ce6](https://www.github.com/googleapis/python-pubsub/commit/ea19ce616f6961e8993b72cd2921f7f3e61541f9)) + +## [1.4.0](https://www.github.com/googleapis/python-pubsub/compare/v1.3.1...v1.4.0) (2020-03-06) + +### Features + +* **pubsub:** implement max_duration_per_lease_extension option ([#38](https://www.github.com/googleapis/python-pubsub/issues/38)) ([d911a2d](https://www.github.com/googleapis/python-pubsub/commit/d911a2dc8edf3c348ad3f128368b30e32dbc449e)) + +## [1.3.1](https://www.github.com/googleapis/python-pubsub/compare/v1.3.0...v1.3.1) (2020-02-28) + +### Bug Fixes + +* shutdown error on streaming pull callback error ([#40](https://www.github.com/googleapis/python-pubsub/issues/40)) ([552539e](https://www.github.com/googleapis/python-pubsub/commit/552539e7beb30833c39dd29bfcb0183a07895f97)) + +## [1.3.0](https://www.github.com/googleapis/python-pubsub/compare/v1.2.0...v1.3.0) (2020-02-20) + +### Features + +* **pubsub:** ordering keys ([#26](https://www.github.com/googleapis/python-pubsub/issues/26)) ([cc3093a](https://www.github.com/googleapis/python-pubsub/commit/cc3093a2c0304259bc374bc2eeec9630e4a11a5e)) +* add context manager capability to subscriber ([#32](https://www.github.com/googleapis/python-pubsub/issues/32)) ([b58d0d8](https://www.github.com/googleapis/python-pubsub/commit/b58d0d8e404c0a085b89d3407e6640651e81568c)) + +## [1.2.0](https://www.github.com/googleapis/python-pubsub/compare/v1.1.0...v1.2.0) (2020-02-05) + +### Features + +* **pubsub:** add delivery attempt property to message object received by user code ([#10205](https://www.github.com/googleapis/google-cloud-python/issues/10205)) ([a0937c1](https://www.github.com/googleapis/python-pubsub/commit/a0937c13107b92271913de579b60f24b2aaac177)) +* add `StreamingPullRequest.client_id` field (via synth) ([199d56a](https://www.github.com/googleapis/python-pubsub/commit/199d56a939bb6244f67138f843dafdd80721f0d3)) + +### Bug Fixes + +* **pubsub:** handle None in on response callback ([#9982](https://www.github.com/googleapis/google-cloud-python/issues/9982)) ([6596c4b](https://www.github.com/googleapis/python-pubsub/commit/6596c4bae5526d82f5c1b5e0c243b2883404d51f)) +* replace unsafe six.PY3 with PY2 for better future compatibility with Python 4 ([#10081](https://www.github.com/googleapis/google-cloud-python/issues/10081)) ([975c1ac](https://www.github.com/googleapis/python-pubsub/commit/975c1ac2cfdac0ce4403c0b56ad19f2ee7241f1a)) + +## 1.1.0 + +12-09-2019 18:51 PST + +### Implementation Changes +- Update client configurations (via synth). ([#9784](https://github.com/googleapis/google-cloud-python/pull/9784)) +- Include request overhead when computing publish batch size overflow. ([#9911](https://github.com/googleapis/google-cloud-python/pull/9911)) +- Split large (mod)ACK requests into smaller ones. ([#9594](https://github.com/googleapis/google-cloud-python/pull/9594)) +- Fix messages delivered multiple times despite a long ACK deadline. ([#9525](https://github.com/googleapis/google-cloud-python/pull/9525)) +- Update batching and flow control parameters to be same as the other client libraries. ([#9597](https://github.com/googleapis/google-cloud-python/pull/9597)) +- Add `StreamingPullManager._should_terminate`. ([#9335](https://github.com/googleapis/google-cloud-python/pull/9335)) + +### New Features +- Add stop method. ([#9365](https://github.com/googleapis/google-cloud-python/pull/9365)) + +### Dependencies +- Add Python 2 sunset banner to documentation. ([#9036](https://github.com/googleapis/google-cloud-python/pull/9036)) + +### Documentation +- Change spacing in docs templates (via synth). ([#9759](https://github.com/googleapis/google-cloud-python/pull/9759)) + +### Internal / Testing Changes +- Refactor fake leaser test helper. ([#9632](https://github.com/googleapis/google-cloud-python/pull/9632)) +- Add subscriber role test for streaming. ([#9507](https://github.com/googleapis/google-cloud-python/pull/9507)) + +## 1.0.2 + +09-30-2019 11:57 PDT + + +### Implementation Changes + +- Streaming pull shouldn't need `subscriptions.get` permission ([#9360](https://github.com/googleapis/google-cloud-python/pull/9360)). + +## 1.0.1 + +09-27-2019 07:01 PDT + + +### Implementation Changes +- Set default stream ACK deadline to subscriptions'. ([#9268](https://github.com/googleapis/google-cloud-python/pull/9268)) + +### Documentation +- Fix intersphinx reference to requests. ([#9294](https://github.com/googleapis/google-cloud-python/pull/9294)) +- Link to correct TimeoutError in futures docs. ([#9216](https://github.com/googleapis/google-cloud-python/pull/9216)) + +### Internal / Testing Changes +- Adjust messaging RPC timeout settings (via synth). [#9279](https://github.com/googleapis/google-cloud-python/pull/9279) + +## 1.0.0 + +08-29-2019 09:27 PDT + +### Implementation Changes +- Add 'ReceivedMessage.delivery_attempt' field (via synth). ([#9098](https://github.com/googleapis/google-cloud-python/pull/9098)) +- Remove send/recv msg size limit, update docstrings (via synth). ([#8964](https://github.com/googleapis/google-cloud-python/pull/8964)) + +### Documentation +- Update docstrings for client kwargs and fix return types uris ([#9037](https://github.com/googleapis/google-cloud-python/pull/9037)) +- Remove CI for gh-pages, use googleapis.dev for api_core refs. ([#9085](https://github.com/googleapis/google-cloud-python/pull/9085)) +- Remove compatability badges from READMEs. ([#9035](https://github.com/googleapis/google-cloud-python/pull/9035)) + +### Internal / Testing Changes +- Add dead-letter-policy field in preparation for its implementation (via synth) ([#9078](https://github.com/googleapis/google-cloud-python/pull/9078)) + +## 0.45.0 + +07-31-2019 02:03 PDT + + +### Implementation Changes + +- Remove deprecated methods and settings ([#8836](https://github.com/googleapis/google-cloud-python/pull/8836)) + + +### Documentation + +- Use double backticks for ReST correctness. ([#8829](https://github.com/googleapis/google-cloud-python/pull/8829)) +- Update intersphinx mapping for requests. ([#8805](https://github.com/googleapis/google-cloud-python/pull/8805)) + +## 0.44.0 + +07-29-2019 04:28 PDT + + +### Implementation Changes + +- PubSub: Deprecate several FlowControl settings and things in Message class ([#8796](https://github.com/googleapis/google-cloud-python/pull/8796)) + +### Documentation + +- Pub/Sub: document regional endpoint ([#8789](https://github.com/googleapis/google-cloud-python/pull/8789)) + +## 0.43.0 + +07-24-2019 17:13 PDT + + +### Implementation Changes +- Accomodate new location of 'IAMPolicyStub' (via synth). ([#8680](https://github.com/googleapis/google-cloud-python/pull/8680)) +- Use kwargs in test_subscriber_client ([#8414](https://github.com/googleapis/google-cloud-python/pull/8414)) + +### New Features +- Add `options_` argument to clients' `get_iam_policy`; pin black version (via synth). ([#8657](https://github.com/googleapis/google-cloud-python/pull/8657)) +- Add 'client_options' support, update list method docstrings (via synth). ([#8518](https://github.com/googleapis/google-cloud-python/pull/8518)) + +### Dependencies +- Bump minimum version for google-api-core to 1.14.0. ([#8709](https://github.com/googleapis/google-cloud-python/pull/8709)) +- Update pin for 'grpc-google-iam-v1' to 0.12.3+. ([#8647](https://github.com/googleapis/google-cloud-python/pull/8647)) + +### Documentation +- Link to googleapis.dev documentation in READMEs. ([#8705](https://github.com/googleapis/google-cloud-python/pull/8705)) +- Add compatibility check badges to READMEs. ([#8288](https://github.com/googleapis/google-cloud-python/pull/8288)) +- Fix typo in publisher index. ([#8619](https://github.com/googleapis/google-cloud-python/pull/8619)) +- Document how to choose the PubSub auth method ([#8429](https://github.com/googleapis/google-cloud-python/pull/8429)) +- Document different PuSub received message types ([#8468](https://github.com/googleapis/google-cloud-python/pull/8468)) +- PubSub: Document batch settings, make synth operations idempotent ([#8448](https://github.com/googleapis/google-cloud-python/pull/8448)) +- Add custom docstrings for FlowControl enum and values (via synth). ([#8426](https://github.com/googleapis/google-cloud-python/pull/8426)) + +### Internal / Testing Changes +- Add docs job to publish to googleapis.dev. ([#8464](https://github.com/googleapis/google-cloud-python/pull/8464)) +- Add system tests for PubSub clients ([#8277](https://github.com/googleapis/google-cloud-python/pull/8277)) + +## 0.42.1 + +06-18-2019 15:14 PDT + + +### Implementation Changes +- Increase the minimum allowed version for api core. ([#8419](https://github.com/googleapis/google-cloud-python/pull/8419)) +- Allow kwargs to be passed to create_channel. ([#8399](https://github.com/googleapis/google-cloud-python/pull/8399)) + +## 0.42.0 + +06-18-2019 11:32 PDT + +### Implementation Changes +- Core: Mitigate busy reopen loop in ResumableBidiRpc consuming 100% CPU ([#8193](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/8193)) +- Pub/Sub: Increase initial_rpc_timeout for messaging (via synth). ([#8219](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/8219)) +- PubSub: Release the state lock before calling the publish api ([#8234](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/8234)) +- Pub/Sub: Expose publish retry settings ([#8231](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/8231)) +- Prevent unhandled background error on SPM shutdown ([#8111](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/8111)) +- Update timeouts, blacken noxfile.py, setup.py (via synth). ([#8128](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/8128)) +- PubSub: Fix streaming pull incorrectly handling FlowControl max_messages setting ([#7948](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/7948)) + +### Documentation +- Document PubSub FlowControl settings ([#8293](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/8293)) +- Replace readthedocs links with links to github docs. ([#8291](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/8291)) +- Pub/Sub: surface publish future in documentation ([#8229](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/8229)) +- Pubsub: Separate subscriber and publish future documentation. ([#8205](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/8205)) +- Drop mention of long-removed 'policy' object. ([#8081](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/8081)) + +### Internal / Testing Changes +- Pub/Sub: staticmethod check ([#8091](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/8091)) +- Add empty lines (via synth). ([#8067](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/8067)) + +## 0.41.0 + +05-15-2019 13:57 PDT + + +### New Features +- Add `kms_key_name` arg to `create_topic`; remove BETA warnings (via synth). ([#7936](https://github.com/googleapis/google-cloud-python/pull/7936)) +- Add message ordering (via synth). ([#7551](https://github.com/googleapis/google-cloud-python/pull/7551)) + +### Implementation Changes +- Propagate subscribe callback errors to main thread ([#7954](https://github.com/googleapis/google-cloud-python/pull/7954)) +- Fix pubsub Streaming Pull shutdown on RetryError ([#7863](https://github.com/googleapis/google-cloud-python/pull/7863)) +- Make PubSub subscriber Scheduler inherit from ABC ([#7690](https://github.com/googleapis/google-cloud-python/pull/7690)) +- Add routing header to method metadata (via synth). ([#7623](https://github.com/googleapis/google-cloud-python/pull/7623)) + +### Internal / Testing Changes +- Remove classifier for Python 3.4 for end-of-life. ([#7535](https://github.com/googleapis/google-cloud-python/pull/7535)) +- Add nox session `docs` (via synth). ([#7778](https://github.com/googleapis/google-cloud-python/pull/7778)) +- Pub/Sub (nit): wrong var name in sample ([#7705](https://github.com/googleapis/google-cloud-python/pull/7705)) + +## 0.40.0 + +03-15-2019 14:09 PDT + + +### Implementation Changes +- Propagate 'RetryError' in 'PublisherClient.publish'. ([#7071](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/7071)) +- Protoc-generated serialization update.. ([#7091](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/7091)) + +### New Features +- Add 'authentication_method' to 'PushConfig' (via synth). ([#7512](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/7512)) +- Add protos as an artifact to library ([#7205](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/7205)) +- Pub/sub: pass transport w/ custom channel to GAPIC API clients. ([#7008](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/7008)) + +### Dependencies + +### Documentation +- Updated client library documentation URLs. ([#7307](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/7307)) +- Update copyright headers +- Fix broken docstring cross-reference links. ([#7132](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/7132)) +- Docstring changes from updates to .proto files. ([#7054](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/7054)) +- Pick up stub docstring fix in GAPIC generator. ([#6978](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/6978)) + +### Internal / Testing Changes +- Copy proto files alongside protoc versions. + +## 0.39.1 + +12-17-2018 16:57 PST + + +### Implementation Changes +- Initialize `StreamingPullFuture._cancelled` as True. ([#6901](https://github.com/googleapis/google-cloud-python/pull/6901)) +- Import `iam.policy` from `google.api_core`. ([#6741](https://github.com/googleapis/google-cloud-python/pull/6741)) + +### Documentation +- Document Python 2 deprecation ([#6910](https://github.com/googleapis/google-cloud-python/pull/6910)) +- Emphasize that returned futures may differ from stdlib futures. ([#6875](https://github.com/googleapis/google-cloud-python/pull/6875)) + +### Internal / Testing Changes +- Add baseline for synth.metadata +- Update noxfile. +- blacken all gen'd libs ([#6792](https://github.com/googleapis/google-cloud-python/pull/6792)) +- omit local deps ([#6701](https://github.com/googleapis/google-cloud-python/pull/6701)) +- Run black at end of synth.py ([#6698](https://github.com/googleapis/google-cloud-python/pull/6698)) +- Run Black on Generated libraries ([#6666](https://github.com/googleapis/google-cloud-python/pull/6666)) +- Add templates for flake8, coveragerc, noxfile, and black. ([#6642](https://github.com/googleapis/google-cloud-python/pull/6642)) + +## 0.39.0 + +11-27-2018 13:32 PST + +### Implementation Changes +- Pick up fixes to GAPIC generator. ([#6503](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/6503)) +- Override client classmethod factories inherited from GAPIC. ([#6453](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/6453)) +- Fix imports for hand-written client docstring examples. ([#6345](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/6345)) +- Fix path for patch of 'bidi' elements. ([#6243](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/6243)) +- Move bidi to api-core. ([#6211](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/6211)) +- Re-generate library using pubsub/synth.py ([#6059](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/6059)) +- Re-generate library using pubsub/synth.py ([#5978](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/5978)) + +### New Features +- Add 'expiration_policy' to subscriber client. ([#6223](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/6223)) + +### Dependencies +- Bump minimum 'api_core' version for all GAPIC libs to 1.4.1. ([#6391](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/6391)) +- Update IAM version in dependencies. ([#6362](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/6362)) +- Bump minimum 'api_core' version to '1.4.1'. ([#6134](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/6134)) + +### Documentation +- Fix client_info bug, update docstrings. ([#6418](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/6418)) +- Fix docstring reference to wrong future class. ([#6382](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/6382)) +- Normalize use of support level badges. ([#6159](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/6159)) +- Update subscriber example in README to current patterns. ([#6194](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/6194)) +- Prep pubsub docs for repo split. ([#6001](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/6001)) + +### Internal / Testing Changes +- Fix error from new flake8 version. ([#6346](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/6346)) +- Use new Nox. ([#6175](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/6175)) + +## 0.38.0 + +### Implementation Changes + +- Fix race condition in recv()'s usage of self.call. ([#5935](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/5935)) +- Re-generate the underlying library from protos. ([#5953](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/5953)) +- Change 'BatchSettings.max_bytes' default. ([#5899](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/5899)) +- Fix race condition where pending Ack IDs can be modified by another thread. ([#5929](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/5929)) + +### Internal / Testing Changes + +- Nox: use inplace installs ([#5865](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/5865)) + +## 0.37.2 + +### Implementation Changes + +- Fix classmethod wrapping (#5826) + +### Documentation + +- Fix Sphinx rendering for publisher client. (#5822) + +### Internal / Testing Changes + +- Re-generate library, removing obsolete synth modifications. (#5825) +- Add test for testing invoking a wrapped class method on the class itself (#5828) + +## 0.37.1 + +### Implementation Changes + +- Make get_initial_request more resilient to race conditions. (#5803) + +## 0.37.0 + +### Implementation Changes + +- Make Publisher batch-related interfaces private (#5784) + +## 0.36.0 + +### Implementation Changes +- Pubsub: Make 'Message.publish_time' return datetime (#5633) +- Ensure SPM methods check that 'self._consumer' is not None before use. (#5758) + +### New Features +- PubSub: add geo-fencing support (#5769) +- Add 'Message.ack_id' property. (#5693) + +## 0.35.4 + +### Implementation Changes + +- Recover streams during the gRPC error callback. (#5446) +- Use operational lock when checking for activity on streams. (#5445) + +## 0.35.3 + +### Implementation Changes + +- Add additional error handling to unary RPCs (#5438) + +## 0.35.2 + +### Implementation Changes +- Add heartbeating to the streaming pull manager (#5413) +- Fix retrying of bidirectional RPCs and closing the streaming pull manager (#5412) + +## 0.35.1 + +### Implementation Changes +- Catch errors when re-retying send() or recv() in addition to open() (#5402) + +## 0.35.0 + +### Implementation Changes + +- Send requests during streaming pull over a separate unary RPC (#5377) +- Initialize references to helper threads before starting them (#5374) +- Make leaser exit more quickly (#5373) +- Make re-open failures bubble to callbacks (#5372) +- Avoid overwriting '__module__' of messages from shared modules. (#5364) +- Normalize overflow handling for max count and bytes (#5343) + +### New Features + +- Restore the synchronous pull method (#5379) +- Promote subscribe_experimental() to subscribe(), remove old subscriber implementation. (#5274) +- Wire up scheduler argument for subscribe() (#5279) + +### Documentation + +- Add link to streaming pull behavior documentation (#5378) +- Fix example in subscribe's documentation (#5375) + +### Internal / Testing Changes + +- Add Test runs for Python 3.7 and remove 3.4 (#5295) +- Modify system tests to use prerelease versions of grpcio (#5304) + +## 0.34.0 + +### Implementation Changes + +- Lower the flow control defaults. (#5248) + +### New Features + +- A new implementation of the subscriber has been added. This is available as `SubscriberClient.subscribe_experimental`. In the next release, this will be replace the current `subscribe` method. If you use this, please report your findings to us on GitHub. (#5189, #5201, #5210, #5229, #5230, #5237, #5256) + +### Dependencies + +- Remove psutil dependency. (#5248) + +## 0.33.1 + +### Implementation changes + +- Surface publish RPC errors back to the publish futures (#5124) +- Make the pausable response iterator aware of the RPC state to prevent deadlock (#5108) +- Properly handle graceful stop in request generator (#5097) + +## 0.33.0 + +### Implementation changes + +- Drop leased messages after flow_control.max_lease_duration has passed. (#5020) +- Fix mantain leases to not modack messages it just dropped (#5045) +- Avoid race condition in maintain_leases by copying leased_messages (#5035) +- Retry subscription stream on InternalServerError, Unknown, and GatewayTimeout (#5021) +- Use the rpc's status to determine when to exit the request generator thread (#5054) +- Fix missing iter on request stream (#5078) +- Nack messages when the subscriber callback errors (#5019) + +### Testing + +- pubsub nox.py cleanup (#5056) +- Fix test that checks for retryable exceptions (#5034) + +## 0.32.1 + +### Dependencies + +- Update dependency range for api-core to include v1.0.0 releases (#4944) + +### Testing and internal changes + +- Install local dependencies when running lint (#4936) +- Re-enable lint for tests, remove usage of pylint (#4921) + +## 0.32.0 + +### Implementation changes + +- Added support for streaming pull receipts. (#4878) + +## 0.31.0 + +### New features + +- Added the ability for subscriber to batch requests. (#4895) +- Added pending request backpressure for subscriber. (#4892) + +### Implementation changes + +- Raise `ValueError` when a message is too large for a batch. (#4872) +- Updated the default batch size to 10 MB. (#4857) +- Allow a custom `Event` type in Pub / Sub futures. (#4643) + +### Documentation + +- Clarify that `modify_ack_deadline` resets the deadline. (#4822) + +### Testing + +- Fix unit test for default `max_bytes` value. (#4860) + +## 0.30.1 + +### Notable Implementation Changes + +- Moving lock factory used in publisher client to the Batch + implementation (#4628). +- Use a UUID (rather than a sentinel object) on `Future` (#4634). +- Apply scopes to explicitly provided credentials if needed (#4594). + Fixes #4479. This feature comes as part of `google-api-core==0.1.3`. + +### Dependencies + +- Upgrading to `google-api-core==0.1.3` which depends on the latest + `grpcio==1.8.2` (#4642). This fixes #4600. For details, see related + gRPC [bug](https://github.com/grpc/grpc/issues/9688) and + [fix](https://github.com/grpc/grpc/pull/13665). + +PyPI: https://pypi.org/project/google-cloud-pubsub/0.30.1/ + +## 0.30.0 + +### Notable Implementation Changes + +- Dropping redundant `Policy._paused` data member (#4568). +- Removing redundant "active" check in policy (#4603). +- Adding a `Consumer.active` property (#4604). +- Making it impossible to call `Policy.open()` on an already opened + policy (#4606). +- **Bug fix** (#4575): Fix bug with async publish for batches. There + were two related bugs. The first: if a batch exceeds the `max_messages` + from the batch settings, then the `commit()` will fail. The second: + when a "monitor" worker calls `commit()` after `max_latency` seconds, + a failure can occur if a new message is added to the batch **during** + the commit. To fix, the following changes were implemented: + + - Adding a "STARTING" status for `Batch.commit()` (#4614). This + fixes the issue when the batch exceeds `max_messages`. + - Adding extra check in `Batch.will_accept` for the number of + messages (#4612). + - Moving `will_accept()` check out of `PublisherClient.batch()` + factory (#4613). + - Checking `Batch.will_accept` in thread-safe way (#4616). +- **Breaking API change**: As part of #4613, changing `PublisherClient.batch()` + to no longer accept a `message` (since the `will_accept` check needs to + happen in a more concurrency friendly way). In addition, changing the + `create` argument so that it means "create even if batch already exists" + rather than "create if missing". + +### Documentation + +- Add more explicit documentation for `Message.attributes` (#4601). +- Make `Message.__repr__` a bit prettier / more useful (#4602). + +PyPI: https://pypi.org/project/google-cloud-pubsub/0.30.0/ + +## 0.29.4 + +### Notable Implementation Changes + +- **Bug fix**: Restore previous behavior of the subscription lease + maintenance worker. This was accidentally "stopped" in `0.29.3` + due to a change in implementation that went from an `active` + boolean to an "inactive" / `stopped` boolean, so `True` became + `False` and vice-versa (#4564). + +PyPI: https://pypi.org/project/google-cloud-pubsub/0.29.4/ + +## 0.29.3 + +### Notable Implementation Changes + +- In subscription consumer thread: Making sure the request generator + attached to an inactive bidirectional streaming pull is stopped before + spawning a new request generator. This way we have a (fairly strong) + guarantee that requests in the queue don't get sent into an inactive + stream (#4503, #4554). +- Adding `pause` / `resume` to subscription consumer thread and using these + methods during flow control. The previous implementation tried to close the + subscription (which involved 3 worker threads and 10 executors in a thread + pool) and then re-open a new subscription. But, this was not entirely + possible to shut down correctly from **within** one of the worker threads. + Instead, we only pause the worker (of the 3) that is pulling new responses + from the bidirectional streaming pull (#4558). +- **Bug fix** (#4516): Using `max` where `min` was used by mistake to + ensure the number of bytes tracked for subscription flow control + remained non-negative (#4514). +- Raising `TypeError` if `SubscriberClient.subscribe` receives a + non-callable callback (#4497). +- Shutting down thread pool executor when closing a subscriber + policy (#4522). +- Renaming `Policy.on_callback_request` to `Policy.dispatch_callback` + and making the behavior much less dynamic (#4511). +- Make sure subscription consumer thread doesn't try to join itself + when exiting in error (#4540). + +### Dependencies + +- Upgrading `google-api-core` dependency to latest revision (`0.1.2`) + since we rely on the latest version of the `concurrent.futures` backport + to provide the `thread_name_prefix` argument for thread pool + executor (#4521, #4559). + +PyPI: https://pypi.org/project/google-cloud-pubsub/0.29.3/ + +## 0.29.2 + +### Notable Implementation Changes + +- **Bug fix** (#4463): Making a subscription consumer actually stop + running after encountering an exception (#4472, #4498). This bug + is the **only** reason for the `0.29.2` release. +- Thread Changes + + - Added names to all threads created directly by Pub / Sub (#4474, + #4476, #4480). Also removing spaces and colons from thread + names (#4476). +- Logging changes + + - Adding debug logs when lease management exits (#4484) + - Adding debug logs when `QueueCallbackThread` exits (#4494). + Instances handle the processing of messages in a + subscription (e.g. to `ack`). + - Using a named logger in `publisher.batch.thread` (#4473) + - Adding newlines before logging protobuf payloads (#4471) + +PyPI: https://pypi.org/project/google-cloud-pubsub/0.29.2/ + +## 0.29.1 + +### Notable Implementation Changes + +- **Bug fix** (#4234): Adding retries for connection `UNAVAILABLE`. This + bug made the Pub / Sub client mostly unusable for subscribers to topics + that don't have a steady stream of messages. After ~2 minutes of inactivity, + the gRPC connection would timeout and raise `UNAVAILABLE` locally, i.e. not + due to a response from the backend. (#4444) +- Updating autogenerated packages (#4438) + +### Documentation + +- Fixing broken examples in quick start (#4398) +- Fixing broken example in README (#4402, h/t to @mehmetboraezer) +- Updating old/dead link to usage doc in README (#4406, h/t to @mehmetboraezer) + +### Dependencies + +- Dropping dependency on `google-cloud-core` in exchange for + `google-api-core` (#4438) + +PyPI: https://pypi.org/project/google-cloud-pubsub/0.29.1/ + +## 0.29.0 + +### Notable Implementation Changes + +- Honor `max_messages` always (#4262) +- Add futures for subscriptions (#4265) +- Set gRPC message options and keepalive (#4269) + +### Documentation + +- Added link to "Python Development Environment Setup Guide" in + project README (#4187, h/t to @michaelawyu) + +### Dependencies + +- Upgrading to `google-cloud-core >= 0.28.0` and adding dependency + on `google-api-core` (#4221, #4280) +- Deferring to `google-api-core` for `grpcio` and + `googleapis-common-protos` dependencies (#4096, #4098) + +PyPI: https://pypi.org/project/google-cloud-pubsub/0.29.0/ diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/README.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/README.rst new file mode 100644 index 000000000000..ed1965b8834d --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/README.rst @@ -0,0 +1,233 @@ +Python Client for Google Cloud Pub / Sub +======================================== + +|GA| |pypi| |versions| + +`Google Cloud Pub / Sub`_ is a fully-managed real-time messaging service that +allows you to send and receive messages between independent applications. You +can leverage Cloud Pub/Sub’s flexibility to decouple systems and components +hosted on Google Cloud Platform or elsewhere on the Internet. By building on +the same technology Google uses, Cloud Pub / Sub is designed to provide “at +least once” delivery at low latency with on-demand scalability to 1 million +messages per second (and beyond). + +Publisher applications can send messages to a ``topic`` and other applications +can subscribe to that topic to receive the messages. By decoupling senders and +receivers, Google Cloud Pub/Sub allows developers to communicate between +independently written applications. + +- `Product Documentation`_ +- `Client Library Documentation`_ + +.. |GA| image:: https://img.shields.io/badge/support-GA-gold.svg + :target: https://github.com/googleapis/google-cloud-python/blob/main/README.rst#general-availability +.. |pypi| image:: https://img.shields.io/pypi/v/google-cloud-pubsub.svg + :target: https://pypi.org/project/google-cloud-pubsub/ +.. |versions| image:: https://img.shields.io/pypi/pyversions/google-cloud-pubsub.svg + :target: https://pypi.org/project/google-cloud-pubsub/ +.. _Google Cloud Pub / Sub: https://cloud.google.com/pubsub/ +.. _Product Documentation: https://cloud.google.com/pubsub/docs +.. _Client Library Documentation: https://cloud.google.com/python/docs/reference/pubsub/latest + +Quick Start +----------- + +In order to use this library, you first need to go through the following steps: + +1. `Select or create a Cloud Platform project.`_ +2. `Enable billing for your project.`_ +3. `Enable the Google Cloud Pub / Sub API.`_ +4. `Setup Authentication.`_ + +.. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project +.. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project +.. _Enable the Google Cloud Pub / Sub API.: https://cloud.google.com/pubsub +.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html + +Installation +~~~~~~~~~~~~ + +Install this library in a `virtualenv`_ using pip. `virtualenv`_ is a tool to +create isolated Python environments. The basic problem it addresses is one of +dependencies and versions, and indirectly permissions. + +With `virtualenv`_, it's possible to install this library without needing system +install permissions, and without clashing with the installed system +dependencies. + +.. _`virtualenv`: https://virtualenv.pypa.io/en/latest/ + + +Supported Python Versions +^^^^^^^^^^^^^^^^^^^^^^^^^ +Python >= 3.7 + +Deprecated Python Versions +^^^^^^^^^^^^^^^^^^^^^^^^^^ +Python <= 3.6. + +The last version of this library compatible with Python 2.7 is google-cloud-pubsub==1.7.0. + + +Mac/Linux +^^^^^^^^^ + +.. code-block:: console + + pip install virtualenv + virtualenv + source /bin/activate + /bin/pip install google-cloud-pubsub + + +Windows +^^^^^^^ + +.. code-block:: console + + pip install virtualenv + virtualenv + \Scripts\activate + \Scripts\pip.exe install google-cloud-pubsub + + +Example Usage +~~~~~~~~~~~~~ + +Publishing +^^^^^^^^^^ + +To publish data to Cloud Pub/Sub you must create a topic, and then publish +messages to it + +.. code-block:: python + + import os + from google.cloud import pubsub_v1 + + publisher = pubsub_v1.PublisherClient() + topic_name = 'projects/{project_id}/topics/{topic}'.format( + project_id=os.getenv('GOOGLE_CLOUD_PROJECT'), + topic='MY_TOPIC_NAME', # Set this to something appropriate. + ) + publisher.create_topic(name=topic_name) + future = publisher.publish(topic_name, b'My first message!', spam='eggs') + future.result() + +To learn more, consult the `publishing documentation`_. + +.. _publishing documentation: https://cloud.google.com/python/docs/reference/pubsub/latest + + +Subscribing +^^^^^^^^^^^ + +To subscribe to data in Cloud Pub/Sub, you create a subscription based on +the topic, and subscribe to that, passing a callback function. + +.. code-block:: python + + import os + from google.cloud import pubsub_v1 + + topic_name = 'projects/{project_id}/topics/{topic}'.format( + project_id=os.getenv('GOOGLE_CLOUD_PROJECT'), + topic='MY_TOPIC_NAME', # Set this to something appropriate. + ) + + subscription_name = 'projects/{project_id}/subscriptions/{sub}'.format( + project_id=os.getenv('GOOGLE_CLOUD_PROJECT'), + sub='MY_SUBSCRIPTION_NAME', # Set this to something appropriate. + ) + + def callback(message): + print(message.data) + message.ack() + + with pubsub_v1.SubscriberClient() as subscriber: + subscriber.create_subscription( + name=subscription_name, topic=topic_name) + future = subscriber.subscribe(subscription_name, callback) + +The future returned by the call to ``subscriber.subscribe`` can be used to +block the current thread until a given condition obtains: + +.. code-block:: python + + try: + future.result() + except KeyboardInterrupt: + future.cancel() + +It is also possible to pull messages in a synchronous (blocking) fashion. To +learn more about subscribing, consult the `subscriber documentation`_. + +.. _subscriber documentation: https://cloud.google.com/python/docs/reference/pubsub/latest + + +Authentication +^^^^^^^^^^^^^^ + +It is possible to specify the authentication method to use with the Pub/Sub +clients. This can be done by providing an explicit `Credentials`_ instance. Support +for various authentication methods is available from the `google-auth`_ library. + +For example, to use JSON Web Tokens, provide a `google.auth.jwt.Credentials`_ instance: + +.. code-block:: python + + import json + from google.auth import jwt + + service_account_info = json.load(open("service-account-info.json")) + audience = "https://pubsub.googleapis.com/google.pubsub.v1.Subscriber" + + credentials = jwt.Credentials.from_service_account_info( + service_account_info, audience=audience + ) + + subscriber = pubsub_v1.SubscriberClient(credentials=credentials) + + # The same for the publisher, except that the "audience" claim needs to be adjusted + publisher_audience = "https://pubsub.googleapis.com/google.pubsub.v1.Publisher" + credentials_pub = credentials.with_claims(audience=publisher_audience) + publisher = pubsub_v1.PublisherClient(credentials=credentials_pub) + +.. _Credentials: https://google-auth.readthedocs.io/en/latest/reference/google.auth.credentials.html#google.auth.credentials.Credentials +.. _google-auth: https://google-auth.readthedocs.io/en/latest/index.html +.. _google.auth.jwt.Credentials: https://google-auth.readthedocs.io/en/latest/reference/google.auth.jwt.html#google.auth.jwt.Credentials + + +Versioning +---------- + +This library follows `Semantic Versioning`_. + +It is currently in major version one (1.y.z), which means that the public API should be considered stable. + +.. _Semantic Versioning: http://semver.org/ + +Contributing +------------ + +Contributions to this library are always welcome and highly encouraged. + +See the `CONTRIBUTING doc`_ for more information on how to get started. + +.. _CONTRIBUTING doc: https://github.com/googleapis/google-cloud-python/blob/main/CONTRIBUTING.rst + +Community +--------- + +Google Cloud Platform Python developers hang out in `Slack`_ in the ``#python`` +channel, click here to `get an invitation`_. + +.. _Slack: https://googlecloud-community.slack.com +.. _get an invitation: https://gcp-slack.appspot.com/ + +License +------- + +Apache 2.0 - See `the LICENSE`_ for more information. + +.. _the LICENSE: https://github.com/googleapis/google-cloud-python/blob/main/LICENSE diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/UPGRADING.md b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/UPGRADING.md new file mode 100644 index 000000000000..83081c1ac69e --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/UPGRADING.md @@ -0,0 +1,201 @@ +# 2.0.0 Migration Guide + +The 2.0 release of the `google-cloud-pubsub` client is a significant upgrade based +on a [next-gen code generator](https://github.com/googleapis/gapic-generator-python), +and includes substantial interface changes. Existing code written for earlier versions +of this library will likely require updates to use this version. This document +describes the changes that have been made, and what you need to do to update your usage. + +If you experience issues or have questions, please file an +[issue](https://github.com/googleapis/python-pubsub/issues). + + +## Supported Python Versions + +> **WARNING**: Breaking change + +The 2.0.0 release requires Python 3.6+. + + +## Method Calls + +> **WARNING**: Breaking change + +Almost all methods that send requests to the backend expect request objects. We +provide a script that will convert most common use cases. + +* Install the library with the `libcst` extra. + +```py +python3 -m pip install google-cloud-pubsub[libcst] +``` + +* The script `fixup_pubsub_v1_keywords.py` is shipped with the library. It expects +an input directory (with the code to convert) and an empty destination directory. + +```sh +$ scripts/fixup_pubsub_v1_keywords.py --input-directory .samples/ --output-directory samples/ +``` + +**Before:** +```py +from google.cloud import pubsub + +publisher = pubsub.PublisherClient() + +project_path = "projects/{}".format(PROJECT_ID) +topics = publisher.list_topics(project_path) +``` + + +**After:** +```py +from google.cloud import pubsub + +publisher = pubsub.PublisherClient() + +project_path = f"projects/{PROJECT_ID}" +topics = publisher.list_topics(request={"project": project_path}) +``` + +### More Details + +In `google-cloud-pubsub<2.0.0`, parameters required by the API were positional +parameters and optional parameters were keyword parameters. + +**Before:** +```py + def list_topics( + self, + project, + page_size=None, + retry=google.api_core.gapic_v1.method.DEFAULT, + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None, + ): +``` + +In the 2.0.0 release, almost all methods that interact with the backend have a single +positional parameter `request`. Method docstrings indicate whether a parameter is +required or optional. + +> **NOTE:** The exception are hand written methods such as `publisher.publish()` and +> `subscriber.subscribe()` that implement additional logic (e.g. request batching) and +> sit on top of the API methods from the generated parts of the library. The signatures +> of these methods have in large part been preserved. + +Some methods have additional keyword only parameters. The available parameters depend +on the [`google.api.method_signature` annotation](https://github.com/googleapis/python-pubsub/blob/main/google/cloud/pubsub_v1/proto/pubsub.proto#L88) +specified by the API producer. + + +**After:** +```py + def list_topics( + self, + request: pubsub.ListTopicsRequest = None, + *, + project: str = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: google.pubsub_v1.types.TimeoutType = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListTopicsPager: +``` + +> **NOTE:** The `request` parameter and flattened keyword parameters for the API are +> mutually exclusive. Passing both will result in an error. + + +Both of these calls are valid: + +```py +response = client.list_topics( + request={ + "project": project_path, + "metadata": [("foo", "bar"), ("baz", "quux")], + } +) +``` + +```py +response = client.list_topics( + project=project_path, + metadata=[("foo", "bar"), ("baz", "quux")], +) +``` + +This call is invalid because it mixes `request` with a keyword argument `metadata`. +Executing this code will result in an error: + +```py +response = client.synthesize_speech( + request={"project": project_path}, + metadata=[("foo", "bar"), ("baz", "quux")], +) +``` + +> **NOTE:** The `request` parameter of some methods can also contain a more rich set of +> options that are otherwise not available as explicit keyword only parameters, thus +> these _must_ be passed through `request`. + + +## Removed Utility Methods + +> **WARNING**: Breaking change + +Some utility methods such as publisher client's `subscription_path()` have been removed +and now only exist in the relevant client, e.g. `subscriber.subscription_path()`. + +The `project_path()` method has been removed from both the publisher and subscriber +client, this path must now be constructed manually: +```py +project_path = f"projects/{PROJECT_ID}" +``` + +## Removed `client_config` Parameter + +The publisher and subscriber clients cannot be constructed with `client_config` +argument anymore. If you want to customize retry and timeout settings for a particular +method, you need to do it upon method invocation by passing the custom `timeout` and +`retry` arguments, respectively. + + +## Custom Retry and Timeout settings for Publisher Client + +The ``publisher_options`` parameter to the Publisher Client, as well as all of the +client's methods, now accept custom retry and timeout settings: + +```py +custom_retry = api_core.retry.Retry( + initial=0.250, # seconds (default: 0.1) + maximum=90.0, # seconds (default: 60.0) + multiplier=1.45, # default: 1.3 + deadline=300.0, # seconds (default: 60.0) + predicate=api_core.retry.if_exception_type( + api_core.exceptions.Aborted, + api_core.exceptions.DeadlineExceeded, + api_core.exceptions.InternalServerError, + api_core.exceptions.ResourceExhausted, + api_core.exceptions.ServiceUnavailable, + api_core.exceptions.Unknown, + api_core.exceptions.Cancelled, + ), +) + +custom_timeout=api_core.timeout.ExponentialTimeout( + initial=1.0, + maximum=10.0, + multiplier=1.0, + deadline=300.0, +) + +publisher = pubsub_v1.PublisherClient( + publisher_options = pubsub_v1.types.PublisherOptions( + retry=custom_retry, + timeout=custom_timeout, + ), +) +``` + +The timeout can be either an instance of `google.api_core.timeout.ConstantTimeout`, +or an instance of `google.api_core.timeout.ExponentialTimeout`, as in the example. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/README.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/README.rst new file mode 120000 index 000000000000..89a0106941ff --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/README.rst @@ -0,0 +1 @@ +../README.rst \ No newline at end of file diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/UPGRADING.md b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/UPGRADING.md new file mode 120000 index 000000000000..01097c8c0fb8 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/UPGRADING.md @@ -0,0 +1 @@ +../UPGRADING.md \ No newline at end of file diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/_static/custom.css b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/_static/custom.css new file mode 100644 index 000000000000..b0a295464b23 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/_static/custom.css @@ -0,0 +1,20 @@ +div#python2-eol { + border-color: red; + border-width: medium; +} + +/* Ensure minimum width for 'Parameters' / 'Returns' column */ +dl.field-list > dt { + min-width: 100px +} + +/* Insert space between methods for readability */ +dl.method { + padding-top: 10px; + padding-bottom: 10px +} + +/* Insert empty space between classes */ +dl.class { + padding-bottom: 50px +} diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/_templates/layout.html b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/_templates/layout.html new file mode 100644 index 000000000000..6316a537f72b --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/_templates/layout.html @@ -0,0 +1,50 @@ + +{% extends "!layout.html" %} +{%- block content %} +{%- if theme_fixed_sidebar|lower == 'true' %} +
+ {{ sidebar() }} + {%- block document %} +
+ {%- if render_sidebar %} +
+ {%- endif %} + + {%- block relbar_top %} + {%- if theme_show_relbar_top|tobool %} + + {%- endif %} + {% endblock %} + +
+
+ As of January 1, 2020 this library no longer supports Python 2 on the latest released version. + Library versions released prior to that date will continue to be available. For more information please + visit Python 2 support on Google Cloud. +
+ {% block body %} {% endblock %} +
+ + {%- block relbar_bottom %} + {%- if theme_show_relbar_bottom|tobool %} + + {%- endif %} + {% endblock %} + + {%- if render_sidebar %} +
+ {%- endif %} +
+ {%- endblock %} +
+
+{%- else %} +{{ super() }} +{%- endif %} +{%- endblock %} diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/changelog.md b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/changelog.md new file mode 120000 index 000000000000..04c99a55caae --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/changelog.md @@ -0,0 +1 @@ +../CHANGELOG.md \ No newline at end of file diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/conf.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/conf.py new file mode 100644 index 000000000000..9245a8edfc51 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/conf.py @@ -0,0 +1,384 @@ +# -*- coding: utf-8 -*- +# Copyright 2021 Google LLC +# +# 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. +# +# google-cloud-pubsub documentation build configuration file +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os +import shlex + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +sys.path.insert(0, os.path.abspath("..")) + +# For plugins that can not read conf.py. +# See also: https://github.com/docascode/sphinx-docfx-yaml/issues/85 +sys.path.insert(0, os.path.abspath(".")) + +__version__ = "" + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +needs_sphinx = "1.5.5" + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + "sphinx.ext.autodoc", + "sphinx.ext.autosummary", + "sphinx.ext.intersphinx", + "sphinx.ext.coverage", + "sphinx.ext.doctest", + "sphinx.ext.napoleon", + "sphinx.ext.todo", + "sphinx.ext.viewcode", + "recommonmark", +] + +# autodoc/autosummary flags +autoclass_content = "both" +autodoc_default_options = {"members": True} +autosummary_generate = True + + +# Add any paths that contain templates here, relative to this directory. +templates_path = ["_templates"] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# source_suffix = ['.rst', '.md'] +source_suffix = [".rst", ".md"] + +# The encoding of source files. +# source_encoding = 'utf-8-sig' + +# The root toctree document. +root_doc = "index" + +# General information about the project. +project = "google-cloud-pubsub" +copyright = "2019, Google" +author = "Google APIs" + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The full version, including alpha/beta/rc tags. +release = __version__ +# The short X.Y version. +version = ".".join(release.split(".")[0:2]) + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +# today = '' +# Else, today_fmt is used as the format for a strftime call. +# today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = [ + "_build", + "**/.nox/**/*", + "samples/AUTHORING_GUIDE.md", + "samples/CONTRIBUTING.md", + "samples/snippets/README.rst", +] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +# default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +# add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +# add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +# show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = "sphinx" + +# A list of ignored prefixes for module index sorting. +# modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +# keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = True + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = "alabaster" + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +html_theme_options = { + "description": "Google Cloud Client Libraries for google-cloud-pubsub", + "github_user": "googleapis", + "github_repo": "python-pubsub", + "github_banner": True, + "font_family": "'Roboto', Georgia, sans", + "head_font_family": "'Roboto', Georgia, serif", + "code_font_family": "'Roboto Mono', 'Consolas', monospace", +} + +# Add any paths that contain custom themes here, relative to this directory. +# html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +# html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +# html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +# html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +# html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ["_static"] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +# html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +# html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +# html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +# html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +# html_additional_pages = {} + +# If false, no module index is generated. +# html_domain_indices = True + +# If false, no index is generated. +# html_use_index = True + +# If true, the index is split into individual pages for each letter. +# html_split_index = False + +# If true, links to the reST sources are added to the pages. +# html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +# html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +# html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +# html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +# html_file_suffix = None + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr' +# html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# Now only 'ja' uses this config value +# html_search_options = {'type': 'default'} + +# The name of a javascript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +# html_search_scorer = 'scorer.js' + +# Output file base name for HTML help builder. +htmlhelp_basename = "google-cloud-pubsub-doc" + +# -- Options for warnings ------------------------------------------------------ + + +suppress_warnings = [ + # Temporarily suppress this to avoid "more than one target found for + # cross-reference" warning, which are intractable for us to avoid while in + # a mono-repo. + # See https://github.com/sphinx-doc/sphinx/blob + # /2a65ffeef5c107c19084fabdd706cdff3f52d93c/sphinx/domains/python.py#L843 + "ref.python" +] + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + #'papersize': 'letterpaper', + # The font size ('10pt', '11pt' or '12pt'). + #'pointsize': '10pt', + # Additional stuff for the LaTeX preamble. + #'preamble': '', + # Latex figure (float) alignment + #'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + ( + root_doc, + "google-cloud-pubsub.tex", + "google-cloud-pubsub Documentation", + author, + "manual", + ) +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +# latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +# latex_use_parts = False + +# If true, show page references after internal links. +# latex_show_pagerefs = False + +# If true, show URL addresses after external links. +# latex_show_urls = False + +# Documents to append as an appendix to all manuals. +# latex_appendices = [] + +# If false, no module index is generated. +# latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ( + root_doc, + "google-cloud-pubsub", + "google-cloud-pubsub Documentation", + [author], + 1, + ) +] + +# If true, show URL addresses after external links. +# man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ( + root_doc, + "google-cloud-pubsub", + "google-cloud-pubsub Documentation", + author, + "google-cloud-pubsub", + "google-cloud-pubsub Library", + "APIs", + ) +] + +# Documents to append as an appendix to all manuals. +# texinfo_appendices = [] + +# If false, no module index is generated. +# texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +# texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +# texinfo_no_detailmenu = False + + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = { + "python": ("https://python.readthedocs.org/en/latest/", None), + "google-auth": ("https://googleapis.dev/python/google-auth/latest/", None), + "google.api_core": ( + "https://googleapis.dev/python/google-api-core/latest/", + None, + ), + "grpc": ("https://grpc.github.io/grpc/python/", None), + "proto-plus": ("https://proto-plus-python.readthedocs.io/en/latest/", None), + "protobuf": ("https://googleapis.dev/python/protobuf/latest/", None), +} + + +# Napoleon settings +napoleon_google_docstring = True +napoleon_numpy_docstring = True +napoleon_include_private_with_doc = False +napoleon_include_special_with_doc = True +napoleon_use_admonition_for_examples = False +napoleon_use_admonition_for_notes = False +napoleon_use_admonition_for_references = False +napoleon_use_ivar = False +napoleon_use_param = True +napoleon_use_rtype = True diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/index.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/index.rst new file mode 100644 index 000000000000..6b3e1583bd23 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/index.rst @@ -0,0 +1,43 @@ +.. include:: README.rst + +.. include:: multiprocessing.rst + + +API Documentation +----------------- + +.. note:: + + The client library version (currently ``2.x``) should not be confused with the + backend API version (currently ``v1``), hence some references to ``v1`` can be found + across the documentation. + +.. toctree:: + :maxdepth: 4 + + Publisher Client + Subscriber Client + Types + + +Migration Guide +--------------- + +See the guide below for instructions on migrating to the 2.x release of this library. + +.. toctree:: + :maxdepth: 2 + + UPGRADING + + +Changelog +--------- + +For a list of all ``google-cloud-pubsub`` releases: + +.. toctree:: + :maxdepth: 2 + + changelog + diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/multiprocessing.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/multiprocessing.rst new file mode 100644 index 000000000000..536d17b2ea65 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/multiprocessing.rst @@ -0,0 +1,7 @@ +.. note:: + + Because this client uses :mod:`grpc` library, it is safe to + share instances across threads. In multiprocessing scenarios, the best + practice is to create client instances *after* the invocation of + :func:`os.fork` by :class:`multiprocessing.pool.Pool` or + :class:`multiprocessing.Process`. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/pubsub/publisher/api/client.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/pubsub/publisher/api/client.rst new file mode 100644 index 000000000000..d1a54ff5e380 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/pubsub/publisher/api/client.rst @@ -0,0 +1,6 @@ +Publisher Client API (v1) +========================= + +.. automodule:: google.cloud.pubsub_v1.publisher.client + :members: + :inherited-members: diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/pubsub/publisher/api/futures.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/pubsub/publisher/api/futures.rst new file mode 100644 index 000000000000..b02b9bf9039d --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/pubsub/publisher/api/futures.rst @@ -0,0 +1,6 @@ +Futures +======= + +.. automodule:: google.cloud.pubsub_v1.publisher.futures + :members: + :inherited-members: diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/pubsub/publisher/api/pagers.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/pubsub/publisher/api/pagers.rst new file mode 100644 index 000000000000..3bbfff33ca87 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/pubsub/publisher/api/pagers.rst @@ -0,0 +1,6 @@ +Pagers +====== + +.. automodule:: google.pubsub_v1.services.publisher.pagers + :members: + :inherited-members: diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/pubsub/publisher/index.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/pubsub/publisher/index.rst new file mode 100644 index 000000000000..2a0ad320eb3d --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/pubsub/publisher/index.rst @@ -0,0 +1,187 @@ +Publishing Messages +=================== + +Publishing messages is handled through the +:class:`~.pubsub_v1.publisher.client.Client` class (aliased as +``google.cloud.pubsub.PublisherClient``). This class provides methods to +create topics, and (most importantly) a +:meth:`~.pubsub_v1.publisher.client.Client.publish` method that publishes +messages to Pub/Sub. + +Instantiating a publishing client is straightforward: + +.. code-block:: python + + from google.cloud import pubsub + publish_client = pubsub.PublisherClient() + + +Publish a Message +----------------- + +To publish a message, use the +:meth:`~.pubsub_v1.publisher.client.Client.publish` method. This method accepts +two positional arguments: the topic to publish to, and the body of the message. +It also accepts arbitrary keyword arguments, which are passed along as +attributes of the message. + +The topic is passed along as a string; all topics have the canonical form of +``projects/{project_name}/topics/{topic_name}``. + +Therefore, a very basic publishing call looks like: + +.. code-block:: python + + topic = 'projects/{project}/topics/{topic}' + future = publish_client.publish(topic, b'This is my message.') + +.. note:: + + The message data in Pub/Sub is an opaque blob of bytes, and as such, you + *must* send a ``bytes`` object in Python 3 (``str`` object in Python 2). + If you send a text string (``str`` in Python 3, ``unicode`` in Python 2), + the method will raise :exc:`TypeError`. + + The reason it works this way is because there is no reasonable guarantee + that the same language or environment is being used by the subscriber, + and so it is the responsibility of the publisher to properly encode + the payload. + +If you want to include attributes, simply add keyword arguments: + +.. code-block:: python + + topic = 'projects/{project}/topics/{topic}' + future = publish_client.publish(topic, b'This is my message.', foo='bar') + + +Batching +-------- + +Whenever you publish a message, the publisher will automatically batch the +messages over a small time window to avoid making too many separate requests to +the service. This helps increase throughput. + +.. note:: + + By default, this uses ``threading``, and you will need to be in an + environment with threading enabled. It is possible to provide an + alternative batch class that uses another concurrency strategy. + +The way that this works is that on the first message that you send, a new batch +is created automatically. For every subsequent message, if there is already a +valid batch that is still accepting messages, then that batch is used. When the +batch is created, it begins a countdown that publishes the batch once +sufficient time has elapsed (by default, this is 0.01 seconds). + +If you need different batching settings, simply provide a +:class:`~.pubsub_v1.types.BatchSettings` object when you instantiate the +:class:`~.pubsub_v1.publisher.client.Client`: + +.. code-block:: python + + from google.cloud import pubsub + from google.cloud.pubsub import types + + client = pubsub.PublisherClient( + batch_settings=types.BatchSettings( + max_messages=500, # default 100 + max_bytes=1024, # default 1 MB + max_latency=1 # default .01 seconds + ), + ) + +The `max_bytes` argument is the maximum total size of the messages to collect +before automatically publishing the batch, (in bytes) including any byte size +overhead of the publish request itself. The maximum value is bound by the +server-side limit of 10_000_000 bytes. The default value is 1 MB. + +The `max_messages` argument is the maximum number of messages to collect +before automatically publishing the batch, the default value is 100 messages. + +The `max_latency` is the maximum number of seconds to wait for additional +messages before automatically publishing the batch, the default is .01 seconds. + + +Futures +------- + +Every call to :meth:`~.pubsub_v1.publisher.client.Client.publish` returns +an instance of :class:`~.pubsub_v1.publisher.futures.Future`. + +.. note:: + + The returned future conforms for the most part to the interface of + the standard library's :class:`~concurrent.futures.Future`, but might not + be usable in all cases which expect that exact implementaton. + +You can use this to ensure that the publish succeeded: + +.. code-block:: python + + # The .result() method will block until the future is complete. + # If there is an error, it will raise an exception. + future = client.publish(topic, b'My awesome message.') + message_id = future.result() + +You can also attach a callback to the future: + +.. code-block:: python + + # Callbacks receive the future as their only argument, as defined in + # the Future interface. + def callback(future): + message_id = future.result() + do_something_with(message_id) + + # The callback is added once you get the future. If you add a callback + # and the future is already done, it will simply be executed immediately. + future = client.publish(topic, b'My awesome message.') + future.add_done_callback(callback) + + +Publish Flow Control +-------------------- + +If publishing large amounts of messages or very large messages in quick +succession, some of the publish requests might time out, especially if the +bandwidth available is limited. To mitigate this the client can be +configured with custom :class:`~.pubsub_v1.types.PublishFlowControl` settings. + +You can configure the maximum desired number of messages and their maximum total +size, as well as the action that should be taken when the threshold is reached. + +.. code-block:: python + + from google.cloud import pubsub_v1 + + client = pubsub_v1.PublisherClient( + publisher_options=pubsub_v1.types.PublisherOptions( + flow_control=pubsub_v1.types.PublishFlowControl( + message_limit=500, + byte_limit=2 * 1024 * 1024, + limit_exceeded_behavior=pubsub_v1.types.LimitExceededBehavior.BLOCK, + ), + ), + ) + +The action to be taken on overflow can be one of the following: + +* :attr:`~.pubsub_v1.types.LimitExceededBehavior.IGNORE` (default): Ignore the + overflow and continue publishing the messages as normal. +* :attr:`~.pubsub_v1.types.LimitExceededBehavior.ERROR`: Raise + :exc:`~.pubsub_v1.publisher.exceptions.FlowControlLimitError` and reject the message. +* :attr:`~.pubsub_v1.types.LimitExceededBehavior.BLOCK`: Temporarily block in the + :meth:`~.pubsub_v1.publisher.client.Client.publish` method until there is + enough capacity available. + + +API Reference +------------- + +.. toctree:: + :maxdepth: 2 + + api/client + api/futures + api/pagers diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/pubsub/subscriber/api/client.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/pubsub/subscriber/api/client.rst new file mode 100644 index 000000000000..d26243eba820 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/pubsub/subscriber/api/client.rst @@ -0,0 +1,6 @@ +Subscriber Client API (v1) +========================== + +.. automodule:: google.cloud.pubsub_v1.subscriber.client + :members: + :inherited-members: diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/pubsub/subscriber/api/futures.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/pubsub/subscriber/api/futures.rst new file mode 100644 index 000000000000..fb0264279cf6 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/pubsub/subscriber/api/futures.rst @@ -0,0 +1,6 @@ +Futures +======= + +.. automodule:: google.cloud.pubsub_v1.subscriber.futures + :members: + :inherited-members: diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/pubsub/subscriber/api/message.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/pubsub/subscriber/api/message.rst new file mode 100644 index 000000000000..6e7a55ded6c7 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/pubsub/subscriber/api/message.rst @@ -0,0 +1,6 @@ +Messages +======== + +.. autoclass:: google.cloud.pubsub_v1.subscriber.message.Message + :members: + :noindex: diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/pubsub/subscriber/api/pagers.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/pubsub/subscriber/api/pagers.rst new file mode 100644 index 000000000000..367c65ca71d4 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/pubsub/subscriber/api/pagers.rst @@ -0,0 +1,6 @@ +Pagers +====== + +.. automodule:: google.pubsub_v1.services.subscriber.pagers + :members: + :inherited-members: diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/pubsub/subscriber/api/scheduler.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/pubsub/subscriber/api/scheduler.rst new file mode 100644 index 000000000000..06e839f219e6 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/pubsub/subscriber/api/scheduler.rst @@ -0,0 +1,6 @@ +Scheduler +========= + +.. automodule:: google.cloud.pubsub_v1.subscriber.scheduler + :members: + :inherited-members: diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/pubsub/subscriber/index.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/pubsub/subscriber/index.rst new file mode 100644 index 000000000000..aa21cd37bce7 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/pubsub/subscriber/index.rst @@ -0,0 +1,236 @@ +Subscribing to Messages +======================= + +Subscribing to messages is handled through the +:class:`~.pubsub_v1.subscriber.client.Client` class (aliased as +``google.cloud.pubsub.SubscriberClient``). This class provides a +:meth:`~.pubsub_v1.subscriber.client.Client.subscribe` method to +attach to subscriptions on existing topics. + +Instantiating a subscriber client is straightforward: + +.. code-block:: python + + from google.cloud import pubsub + + with pubsub.SubscriberClient() as subscriber: + # ... + +Creating a Subscription +----------------------- + +In Pub/Sub, a **subscription** is a discrete pull of messages from a topic. +If multiple clients pull the same subscription, then messages are split +between them. If multiple clients create a subscription each, then each client +will get every message. + +.. note:: + + Remember that Pub/Sub operates under the principle of "everything at least + once". Even in the case where multiple clients pull the same subscription, + *some* redundancy is likely. + +Creating a subscription requires that you already know what topic you want +to subscribe to, and it must already exist. Once you have that, it is easy: + +.. code-block:: python + + # Substitute PROJECT, SUBSCRIPTION, and TOPIC with appropriate values for + # your application. + + # from google.cloud import pubsub + # publisher = pubsub.PublisherClient() + + topic_path = publisher.topic_path(PROJECT, TOPIC) + + with pubsub.SubscriberClient() as subscriber: + sub_path = subscriber.subscription_path(PROJECT, SUBSCRIPTION) + subscriber.create_subscription(request={"name": sub_path, "topic": topic_path}) + +Once you have created a subscription (or if you already had one), the next +step is to pull data from it. + + +Pulling a Subscription Synchronously +------------------------------------ + +To pull the messages synchronously, use the client's +:meth:`~.pubsub_v1.subscriber.client.Client.pull` method. + +.. code-block:: python + + # Wrap the following code in `with pubsub.SubscriberClient() as subscriber:` + + # Substitute PROJECT and SUBSCRIPTION with appropriate values for your + # application. + subscription_path = subscriber.subscription_path(PROJECT, SUBSCRIPTION) + response = subscriber.pull( + request={ + "subscription": subscription_path, + "max_messages": 5, + } + ) + + for msg in response.received_messages: + print("Received message:", msg.message.data) + + ack_ids = [msg.ack_id for msg in response.received_messages] + subscriber.acknowledge( + request={ + "subscription": subscription_path, + "ack_ids": ack_ids, + } + ) + +The method returns a :class:`~.pubsub_v1.types.PullResponse` instance that +contains a list of received :class:`~.pubsub_v1.types.ReceivedMessage` +instances. + +If you want to **nack** some of the received messages (see :ref:`explaining-ack` below), +you can use the :meth:`~.pubsub_v1.subscriber.client.Client.modify_ack_deadline` +method and set their acknowledge deadlines to zero. This will cause them to +be dropped by this client and the backend will try to re-deliver them. + +.. code-block:: python + + # Wrap the following code in `with pubsub.SubscriberClient() as subscriber:` + + ack_ids = [] # TODO: populate with `ack_ids` of the messages to NACK + ack_deadline_seconds = 0 + subscriber.modify_ack_deadline( + request={ + "subscription": subscription_path, + "ack_ids": ack_ids, + "ack_deadline_seconds": ack_deadline_seconds, + } + ) + + +Pulling a Subscription Asynchronously +------------------------------------- + +The subscriber client uses the +:meth:`~.pubsub_v1.subscriber.client.Client.subscribe` method to start a +background thread to receive messages from Pub/Sub and calls a callback with +each message received. + +.. code-block:: python + + # Wrap the following code in `with pubsub.SubscriberClient() as subscriber:` + + # Substitute PROJECT and SUBSCRIPTION with appropriate values for your + # application. + subscription_path = subscriber.subscription_path(PROJECT, SUBSCRIPTION) + future = subscriber.subscribe(subscription_path, callback) + +This will return a +:class:`~.pubsub_v1.subscriber.futures.StreamingPullFuture`. This future allows +you to control the background thread that is managing the subscription. + + +Subscription Callbacks +---------------------- + +Messages received from a subscription are processed asynchronously through +**callbacks**. + +The basic idea: Define a function that takes one argument; this argument +will be a :class:`~.pubsub_v1.subscriber.message.Message` instance, which is +a convenience wrapper around the :class:`~.pubsub_v1.types.PubsubMessage` +instance received from the server (and stored under the ``message`` attribute). + +This function should do whatever processing is necessary. At the end, the +function should either :meth:`~.pubsub_v1.subscriber.message.Message.ack` +or :meth:`~.pubsub_v1.subscriber.message.Message.nack` the message. + +When you call :meth:`~.pubsub_v1.subscriber.client.Client.subscribe`, you +must pass the callback that will be used. + +Here is an example: + +.. code-block:: python + + # Define the callback. + # Note that the callback is defined *before* the subscription is opened. + def callback(message): + do_something_with(message) # Replace this with your actual logic. + message.ack() # Asynchronously acknowledge the message. + + # Wrap the following code in `with pubsub.SubscriberClient() as subscriber:` + + # Substitute PROJECT and SUBSCRIPTION with appropriate values for your + # application. + subscription_path = subscriber.subscription_path(PROJECT, SUBSCRIPTION) + + # Open the subscription, passing the callback. + future = subscriber.subscribe(subscription_path, callback) + +The :meth:`~.pubsub_v1.subscriber.client.Client.subscribe` method returns +a :class:`~.pubsub_v1.subscriber.futures.StreamingPullFuture`, which is both +the interface to wait on messages (e.g. block the primary thread) and to +address exceptions. + +To block the thread you are in while messages are coming in the stream, +use the :meth:`~.pubsub_v1.subscriber.futures.Future.result` method: + +.. code-block:: python + + future.result() + +.. note: This will block forever assuming no errors or that ``cancel`` is never + called. + +You can also use this for error handling; any exceptions that crop up on a +thread will be set on the future. + +.. code-block:: python + + try: + future.result() + except Exception as ex: + # Close the subscriber if not using a context manager. + subscriber.close() + raise + +Finally, you can use +:meth:`~.pubsub_v1.subscriber.futures.StreamingPullFuture.cancel` to stop +receiving messages. + + +.. code-block:: python + + future.cancel() + + +.. _explaining-ack: + +Explaining Ack +-------------- + +In Pub/Sub, the term **ack** stands for "acknowledge". You should ack a +message when your processing of that message *has completed*. When you ack +a message, you are telling Pub/Sub that you do not need to see it again. + +It might be tempting to ack messages immediately on receipt. While there +are valid use cases for this, in general it is unwise. The reason why: If +there is some error or edge case in your processing logic, and processing +of the message fails, you will have already told Pub/Sub that you successfully +processed the message. By contrast, if you ack only upon completion, then +Pub/Sub will eventually re-deliver the unacknowledged message. + +It is also possible to **nack** a message, which is the opposite. When you +nack, it tells Pub/Sub that you are unable or unwilling to deal with the +message, and that the service should redeliver it. + + +API Reference +------------- + +.. toctree:: + :maxdepth: 2 + + api/client + api/message + api/futures + api/pagers + api/scheduler diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/pubsub/types.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/pubsub/types.rst new file mode 100644 index 000000000000..308f66971e05 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/docs/pubsub/types.rst @@ -0,0 +1,6 @@ +Pub/Sub Client Types +==================== + +.. automodule:: google.cloud.pubsub_v1.types + :members: + :noindex: diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/format/rst/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/__init__.py similarity index 64% rename from packages/gcp-sphinx-docfx-yaml/tests/example/format/rst/__init__.py rename to packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/__init__.py index e67d510b06ff..9a1b64a6d586 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/example/format/rst/__init__.py +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/__init__.py @@ -1,10 +1,12 @@ -# Copyright 2021 Google LLC +# -*- coding: utf-8 -*- +# +# Copyright 2020 Google LLC # # 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 +# https://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, @@ -12,12 +14,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -# coding: utf-8 - -""" Docstring of package :mod:`format.rst`. -""" - -def module_function(): - """ Docstring of module function :func:`format.rst.module_function`. - """ - pass +try: + import pkg_resources + + pkg_resources.declare_namespace(__name__) +except ImportError: + import pkgutil + + __path__ = pkgutil.extend_path(__path__, __name__) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/format/rst/enum.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/__init__.py similarity index 60% rename from packages/gcp-sphinx-docfx-yaml/tests/example/format/rst/enum.py rename to packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/__init__.py index 368dd77fb3ae..e1f8a4d20fd1 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/example/format/rst/enum.py +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/__init__.py @@ -1,10 +1,12 @@ -# Copyright 2021 Google LLC +# -*- coding: utf-8 -*- +# +# Copyright 2020 Google LLC # # 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 +# https://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, @@ -12,13 +14,13 @@ # See the License for the specific language governing permissions and # limitations under the License. -# coding: utf-8 - -from enum import Enum - -class EnumFoo(Enum): - """ Docstring of :class:`format.rst.enum.EnumFoo` class. - """ - - VALUE0 = 0 #: Inline docstring of VALUE0 - VALUE1 = 1 #: Inlune docstring of VALUE1 +from typing import List + +try: + import pkg_resources + + pkg_resources.declare_namespace(__name__) +except ImportError: + import pkgutil + + __path__: List[str] = pkgutil.extend_path(__path__, __name__) # type: ignore diff --git a/packages/gcp-sphinx-docfx-yaml/prospector.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub/__init__.py similarity index 53% rename from packages/gcp-sphinx-docfx-yaml/prospector.yml rename to packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub/__init__.py index 42f01dfdb10e..2a6994231cfe 100644 --- a/packages/gcp-sphinx-docfx-yaml/prospector.yml +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub/__init__.py @@ -1,10 +1,12 @@ -# Copyright 2021 Google LLC +# -*- coding: utf-8 -*- +# +# Copyright 2020 Google LLC # # 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 +# https://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, @@ -12,29 +14,18 @@ # See the License for the specific language governing permissions and # limitations under the License. -strictness: low - -test-warnings: false -doc-warnings: true - -ignore-paths: - - docs - -ignore-patterns: - - ^docfx_yaml/writer.py$ -pep8: - full: true - options: - max-line-length: 100 +from __future__ import absolute_import -pylint: - max-line-length: 100 - disable: - - interface-not-implemented +from google.cloud.pubsub_v1 import PublisherClient +from google.cloud.pubsub_v1 import SubscriberClient +from google.cloud.pubsub_v1 import SchemaServiceClient +from google.cloud.pubsub_v1 import types -mccabe: - run: false -pep257: - run: false +__all__ = ( + "types", + "PublisherClient", + "SubscriberClient", + "SchemaServiceClient", +) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/__init__.py new file mode 100644 index 000000000000..99bc3e9c8503 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/__init__.py @@ -0,0 +1,35 @@ +# Copyright 2017, Google LLC 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. + +from __future__ import absolute_import + +from google.cloud.pubsub_v1 import types +from google.cloud.pubsub_v1 import publisher +from google.cloud.pubsub_v1 import subscriber +from google.pubsub_v1.services import schema_service + + +class PublisherClient(publisher.Client): + __doc__ = publisher.Client.__doc__ + + +class SubscriberClient(subscriber.Client): + __doc__ = subscriber.Client.__doc__ + + +class SchemaServiceClient(schema_service.client.SchemaServiceClient): + __doc__ = schema_service.client.SchemaServiceClient.__doc__ + + +__all__ = ("types", "PublisherClient", "SubscriberClient", "SchemaServiceClient") diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/conflict/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/exceptions.py similarity index 70% rename from packages/gcp-sphinx-docfx-yaml/tests/example/conflict/__init__.py rename to packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/exceptions.py index 3f7e879b9928..5ab750d0477c 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/example/conflict/__init__.py +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/exceptions.py @@ -1,10 +1,10 @@ -# Copyright 2021 Google LLC +# Copyright 2017, Google LLC 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 +# 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, @@ -12,11 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -# coding: utf-8 - -""" Package used to test YAML file conflicting. -""" - -from .foo import Foo - -__all__ = ['Foo'] \ No newline at end of file +from __future__ import absolute_import + +from concurrent.futures import TimeoutError + + +__all__ = ("TimeoutError",) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/futures.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/futures.py new file mode 100644 index 000000000000..5527d21d0683 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/futures.py @@ -0,0 +1,56 @@ +# Copyright 2017, Google LLC 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. + +from __future__ import absolute_import + +import concurrent.futures +from typing import Any, NoReturn, Optional + +import google.api_core.future + + +class Future(concurrent.futures.Future, google.api_core.future.Future): + """Encapsulation of the asynchronous execution of an action. + + This object is returned from asychronous Pub/Sub calls, and is the + interface to determine the status of those calls. + + This object should not be created directly, but is returned by other + methods in this library. + """ + + def running(self) -> bool: + """Return ``True`` if the associated Pub/Sub action has not yet completed.""" + return not self.done() + + def set_running_or_notify_cancel(self) -> NoReturn: + raise NotImplementedError( + "Only used by executors from `concurrent.futures` package." + ) + + def set_result(self, result: Any): + """Set the return value of work associated with the future. + + Do not use this method, it should only be used internally by the library and its + unit tests. + """ + return super().set_result(result=result) + + def set_exception(self, exception: Optional[BaseException]): + """Set the result of the future as being the given exception. + + Do not use this method, it should only be used internally by the library and its + unit tests. + """ + return super().set_exception(exception=exception) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/proto/pubsub.proto b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/proto/pubsub.proto new file mode 100644 index 000000000000..716c7ba05cb4 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/proto/pubsub.proto @@ -0,0 +1,1344 @@ +// Copyright 2021 Google LLC +// +// 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. + +syntax = "proto3"; + +package google.pubsub.v1; + +import "google/api/annotations.proto"; +import "google/api/client.proto"; +import "google/api/field_behavior.proto"; +import "google/api/resource.proto"; +import "google/protobuf/duration.proto"; +import "google/protobuf/empty.proto"; +import "google/protobuf/field_mask.proto"; +import "google/protobuf/timestamp.proto"; +import "google/pubsub/v1/schema.proto"; + +option cc_enable_arenas = true; +option csharp_namespace = "Google.Cloud.PubSub.V1"; +option go_package = "google.golang.org/genproto/googleapis/pubsub/v1;pubsub"; +option java_multiple_files = true; +option java_outer_classname = "PubsubProto"; +option java_package = "com.google.pubsub.v1"; +option php_namespace = "Google\\Cloud\\PubSub\\V1"; +option ruby_package = "Google::Cloud::PubSub::V1"; + +// The service that an application uses to manipulate topics, and to send +// messages to a topic. +service Publisher { + option (google.api.default_host) = "pubsub.googleapis.com"; + option (google.api.oauth_scopes) = + "https://www.googleapis.com/auth/cloud-platform," + "https://www.googleapis.com/auth/pubsub"; + + // Creates the given topic with the given name. See the [resource name rules] + // (https://cloud.google.com/pubsub/docs/admin#resource_names). + rpc CreateTopic(Topic) returns (Topic) { + option (google.api.http) = { + put: "/v1/{name=projects/*/topics/*}" + body: "*" + }; + option (google.api.method_signature) = "name"; + } + + // Updates an existing topic. Note that certain properties of a + // topic are not modifiable. + rpc UpdateTopic(UpdateTopicRequest) returns (Topic) { + option (google.api.http) = { + patch: "/v1/{topic.name=projects/*/topics/*}" + body: "*" + }; + } + + // Adds one or more messages to the topic. Returns `NOT_FOUND` if the topic + // does not exist. + rpc Publish(PublishRequest) returns (PublishResponse) { + option (google.api.http) = { + post: "/v1/{topic=projects/*/topics/*}:publish" + body: "*" + }; + option (google.api.method_signature) = "topic,messages"; + } + + // Gets the configuration of a topic. + rpc GetTopic(GetTopicRequest) returns (Topic) { + option (google.api.http) = { + get: "/v1/{topic=projects/*/topics/*}" + }; + option (google.api.method_signature) = "topic"; + } + + // Lists matching topics. + rpc ListTopics(ListTopicsRequest) returns (ListTopicsResponse) { + option (google.api.http) = { + get: "/v1/{project=projects/*}/topics" + }; + option (google.api.method_signature) = "project"; + } + + // Lists the names of the attached subscriptions on this topic. + rpc ListTopicSubscriptions(ListTopicSubscriptionsRequest) + returns (ListTopicSubscriptionsResponse) { + option (google.api.http) = { + get: "/v1/{topic=projects/*/topics/*}/subscriptions" + }; + option (google.api.method_signature) = "topic"; + } + + // Lists the names of the snapshots on this topic. Snapshots are used in + // [Seek](https://cloud.google.com/pubsub/docs/replay-overview) operations, + // which allow you to manage message acknowledgments in bulk. That is, you can + // set the acknowledgment state of messages in an existing subscription to the + // state captured by a snapshot. + rpc ListTopicSnapshots(ListTopicSnapshotsRequest) + returns (ListTopicSnapshotsResponse) { + option (google.api.http) = { + get: "/v1/{topic=projects/*/topics/*}/snapshots" + }; + option (google.api.method_signature) = "topic"; + } + + // Deletes the topic with the given name. Returns `NOT_FOUND` if the topic + // does not exist. After a topic is deleted, a new topic may be created with + // the same name; this is an entirely new topic with none of the old + // configuration or subscriptions. Existing subscriptions to this topic are + // not deleted, but their `topic` field is set to `_deleted-topic_`. + rpc DeleteTopic(DeleteTopicRequest) returns (google.protobuf.Empty) { + option (google.api.http) = { + delete: "/v1/{topic=projects/*/topics/*}" + }; + option (google.api.method_signature) = "topic"; + } + + // Detaches a subscription from this topic. All messages retained in the + // subscription are dropped. Subsequent `Pull` and `StreamingPull` requests + // will return FAILED_PRECONDITION. If the subscription is a push + // subscription, pushes to the endpoint will stop. + rpc DetachSubscription(DetachSubscriptionRequest) + returns (DetachSubscriptionResponse) { + option (google.api.http) = { + post: "/v1/{subscription=projects/*/subscriptions/*}:detach" + }; + } +} + +// A policy constraining the storage of messages published to the topic. +message MessageStoragePolicy { + // A list of IDs of GCP regions where messages that are published to the topic + // may be persisted in storage. Messages published by publishers running in + // non-allowed GCP regions (or running outside of GCP altogether) will be + // routed for storage in one of the allowed regions. An empty list means that + // no regions are allowed, and is not a valid configuration. + repeated string allowed_persistence_regions = 1; +} + +// Settings for validating messages published against a schema. +message SchemaSettings { + // Required. The name of the schema that messages published should be + // validated against. Format is `projects/{project}/schemas/{schema}`. The + // value of this field will be `_deleted-schema_` if the schema has been + // deleted. + string schema = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { type: "pubsub.googleapis.com/Schema" } + ]; + + // The encoding of messages validated against `schema`. + Encoding encoding = 2; +} + +// A topic resource. +message Topic { + option (google.api.resource) = { + type: "pubsub.googleapis.com/Topic" + pattern: "projects/{project}/topics/{topic}" + pattern: "_deleted-topic_" + }; + + // Required. The name of the topic. It must have the format + // `"projects/{project}/topics/{topic}"`. `{topic}` must start with a letter, + // and contain only letters (`[A-Za-z]`), numbers (`[0-9]`), dashes (`-`), + // underscores (`_`), periods (`.`), tildes (`~`), plus (`+`) or percent + // signs (`%`). It must be between 3 and 255 characters in length, and it + // must not start with `"goog"`. + string name = 1 [(google.api.field_behavior) = REQUIRED]; + + // See [Creating and managing labels] + // (https://cloud.google.com/pubsub/docs/labels). + map labels = 2; + + // Policy constraining the set of Google Cloud Platform regions where messages + // published to the topic may be stored. If not present, then no constraints + // are in effect. + MessageStoragePolicy message_storage_policy = 3; + + // The resource name of the Cloud KMS CryptoKey to be used to protect access + // to messages published on this topic. + // + // The expected format is `projects/*/locations/*/keyRings/*/cryptoKeys/*`. + string kms_key_name = 5; + + // Settings for validating messages published against a schema. + SchemaSettings schema_settings = 6; + + // Reserved for future use. This field is set only in responses from the + // server; it is ignored if it is set in any requests. + bool satisfies_pzs = 7; + + // Indicates the minimum duration to retain a message after it is published to + // the topic. If this field is set, messages published to the topic in the + // last `message_retention_duration` are always available to subscribers. For + // instance, it allows any attached subscription to [seek to a + // timestamp](https://cloud.google.com/pubsub/docs/replay-overview#seek_to_a_time) + // that is up to `message_retention_duration` in the past. If this field is + // not set, message retention is controlled by settings on individual + // subscriptions. Cannot be more than 7 days or less than 10 minutes. + google.protobuf.Duration message_retention_duration = 8; +} + +// A message that is published by publishers and consumed by subscribers. The +// message must contain either a non-empty data field or at least one attribute. +// Note that client libraries represent this object differently +// depending on the language. See the corresponding [client library +// documentation](https://cloud.google.com/pubsub/docs/reference/libraries) for +// more information. See [quotas and limits] +// (https://cloud.google.com/pubsub/quotas) for more information about message +// limits. +message PubsubMessage { + // The message data field. If this field is empty, the message must contain + // at least one attribute. + bytes data = 1; + + // Attributes for this message. If this field is empty, the message must + // contain non-empty data. This can be used to filter messages on the + // subscription. + map attributes = 2; + + // ID of this message, assigned by the server when the message is published. + // Guaranteed to be unique within the topic. This value may be read by a + // subscriber that receives a `PubsubMessage` via a `Pull` call or a push + // delivery. It must not be populated by the publisher in a `Publish` call. + string message_id = 3; + + // The time at which the message was published, populated by the server when + // it receives the `Publish` call. It must not be populated by the + // publisher in a `Publish` call. + google.protobuf.Timestamp publish_time = 4; + + // If non-empty, identifies related messages for which publish order should be + // respected. If a `Subscription` has `enable_message_ordering` set to `true`, + // messages published with the same non-empty `ordering_key` value will be + // delivered to subscribers in the order in which they are received by the + // Pub/Sub system. All `PubsubMessage`s published in a given `PublishRequest` + // must specify the same `ordering_key` value. + string ordering_key = 5; +} + +// Request for the GetTopic method. +message GetTopicRequest { + // Required. The name of the topic to get. + // Format is `projects/{project}/topics/{topic}`. + string topic = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { type: "pubsub.googleapis.com/Topic" } + ]; +} + +// Request for the UpdateTopic method. +message UpdateTopicRequest { + // Required. The updated topic object. + Topic topic = 1 [(google.api.field_behavior) = REQUIRED]; + + // Required. Indicates which fields in the provided topic to update. Must be + // specified and non-empty. Note that if `update_mask` contains + // "message_storage_policy" but the `message_storage_policy` is not set in + // the `topic` provided above, then the updated value is determined by the + // policy configured at the project or organization level. + google.protobuf.FieldMask update_mask = 2 + [(google.api.field_behavior) = REQUIRED]; +} + +// Request for the Publish method. +message PublishRequest { + // Required. The messages in the request will be published on this topic. + // Format is `projects/{project}/topics/{topic}`. + string topic = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { type: "pubsub.googleapis.com/Topic" } + ]; + + // Required. The messages to publish. + repeated PubsubMessage messages = 2 [(google.api.field_behavior) = REQUIRED]; +} + +// Response for the `Publish` method. +message PublishResponse { + // The server-assigned ID of each published message, in the same order as + // the messages in the request. IDs are guaranteed to be unique within + // the topic. + repeated string message_ids = 1; +} + +// Request for the `ListTopics` method. +message ListTopicsRequest { + // Required. The name of the project in which to list topics. + // Format is `projects/{project-id}`. + string project = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + type: "cloudresourcemanager.googleapis.com/Project" + } + ]; + + // Maximum number of topics to return. + int32 page_size = 2; + + // The value returned by the last `ListTopicsResponse`; indicates that this is + // a continuation of a prior `ListTopics` call, and that the system should + // return the next page of data. + string page_token = 3; +} + +// Response for the `ListTopics` method. +message ListTopicsResponse { + // The resulting topics. + repeated Topic topics = 1; + + // If not empty, indicates that there may be more topics that match the + // request; this value should be passed in a new `ListTopicsRequest`. + string next_page_token = 2; +} + +// Request for the `ListTopicSubscriptions` method. +message ListTopicSubscriptionsRequest { + // Required. The name of the topic that subscriptions are attached to. + // Format is `projects/{project}/topics/{topic}`. + string topic = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { type: "pubsub.googleapis.com/Topic" } + ]; + + // Maximum number of subscription names to return. + int32 page_size = 2; + + // The value returned by the last `ListTopicSubscriptionsResponse`; indicates + // that this is a continuation of a prior `ListTopicSubscriptions` call, and + // that the system should return the next page of data. + string page_token = 3; +} + +// Response for the `ListTopicSubscriptions` method. +message ListTopicSubscriptionsResponse { + // The names of subscriptions attached to the topic specified in the request. + repeated string subscriptions = 1 [(google.api.resource_reference) = { + type: "pubsub.googleapis.com/Subscription" + }]; + + // If not empty, indicates that there may be more subscriptions that match + // the request; this value should be passed in a new + // `ListTopicSubscriptionsRequest` to get more subscriptions. + string next_page_token = 2; +} + +// Request for the `ListTopicSnapshots` method. +message ListTopicSnapshotsRequest { + // Required. The name of the topic that snapshots are attached to. + // Format is `projects/{project}/topics/{topic}`. + string topic = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { type: "pubsub.googleapis.com/Topic" } + ]; + + // Maximum number of snapshot names to return. + int32 page_size = 2; + + // The value returned by the last `ListTopicSnapshotsResponse`; indicates + // that this is a continuation of a prior `ListTopicSnapshots` call, and + // that the system should return the next page of data. + string page_token = 3; +} + +// Response for the `ListTopicSnapshots` method. +message ListTopicSnapshotsResponse { + // The names of the snapshots that match the request. + repeated string snapshots = 1; + + // If not empty, indicates that there may be more snapshots that match + // the request; this value should be passed in a new + // `ListTopicSnapshotsRequest` to get more snapshots. + string next_page_token = 2; +} + +// Request for the `DeleteTopic` method. +message DeleteTopicRequest { + // Required. Name of the topic to delete. + // Format is `projects/{project}/topics/{topic}`. + string topic = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { type: "pubsub.googleapis.com/Topic" } + ]; +} + +// Request for the DetachSubscription method. +message DetachSubscriptionRequest { + // Required. The subscription to detach. + // Format is `projects/{project}/subscriptions/{subscription}`. + string subscription = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + type: "pubsub.googleapis.com/Subscription" + } + ]; +} + +// Response for the DetachSubscription method. +// Reserved for future use. +message DetachSubscriptionResponse {} + +// The service that an application uses to manipulate subscriptions and to +// consume messages from a subscription via the `Pull` method or by +// establishing a bi-directional stream using the `StreamingPull` method. +service Subscriber { + option (google.api.default_host) = "pubsub.googleapis.com"; + option (google.api.oauth_scopes) = + "https://www.googleapis.com/auth/cloud-platform," + "https://www.googleapis.com/auth/pubsub"; + + // Creates a subscription to a given topic. See the [resource name rules] + // (https://cloud.google.com/pubsub/docs/admin#resource_names). + // If the subscription already exists, returns `ALREADY_EXISTS`. + // If the corresponding topic doesn't exist, returns `NOT_FOUND`. + // + // If the name is not provided in the request, the server will assign a random + // name for this subscription on the same project as the topic, conforming + // to the [resource name format] + // (https://cloud.google.com/pubsub/docs/admin#resource_names). The generated + // name is populated in the returned Subscription object. Note that for REST + // API requests, you must specify a name in the request. + rpc CreateSubscription(Subscription) returns (Subscription) { + option (google.api.http) = { + put: "/v1/{name=projects/*/subscriptions/*}" + body: "*" + }; + option (google.api.method_signature) = + "name,topic,push_config,ack_deadline_seconds"; + } + + // Gets the configuration details of a subscription. + rpc GetSubscription(GetSubscriptionRequest) returns (Subscription) { + option (google.api.http) = { + get: "/v1/{subscription=projects/*/subscriptions/*}" + }; + option (google.api.method_signature) = "subscription"; + } + + // Updates an existing subscription. Note that certain properties of a + // subscription, such as its topic, are not modifiable. + rpc UpdateSubscription(UpdateSubscriptionRequest) returns (Subscription) { + option (google.api.http) = { + patch: "/v1/{subscription.name=projects/*/subscriptions/*}" + body: "*" + }; + } + + // Lists matching subscriptions. + rpc ListSubscriptions(ListSubscriptionsRequest) + returns (ListSubscriptionsResponse) { + option (google.api.http) = { + get: "/v1/{project=projects/*}/subscriptions" + }; + option (google.api.method_signature) = "project"; + } + + // Deletes an existing subscription. All messages retained in the subscription + // are immediately dropped. Calls to `Pull` after deletion will return + // `NOT_FOUND`. After a subscription is deleted, a new one may be created with + // the same name, but the new one has no association with the old + // subscription or its topic unless the same topic is specified. + rpc DeleteSubscription(DeleteSubscriptionRequest) + returns (google.protobuf.Empty) { + option (google.api.http) = { + delete: "/v1/{subscription=projects/*/subscriptions/*}" + }; + option (google.api.method_signature) = "subscription"; + } + + // Modifies the ack deadline for a specific message. This method is useful + // to indicate that more time is needed to process a message by the + // subscriber, or to make the message available for redelivery if the + // processing was interrupted. Note that this does not modify the + // subscription-level `ackDeadlineSeconds` used for subsequent messages. + rpc ModifyAckDeadline(ModifyAckDeadlineRequest) + returns (google.protobuf.Empty) { + option (google.api.http) = { + post: "/v1/{subscription=projects/*/subscriptions/*}:modifyAckDeadline" + body: "*" + }; + option (google.api.method_signature) = + "subscription,ack_ids,ack_deadline_seconds"; + } + + // Acknowledges the messages associated with the `ack_ids` in the + // `AcknowledgeRequest`. The Pub/Sub system can remove the relevant messages + // from the subscription. + // + // Acknowledging a message whose ack deadline has expired may succeed, + // but such a message may be redelivered later. Acknowledging a message more + // than once will not result in an error. + rpc Acknowledge(AcknowledgeRequest) returns (google.protobuf.Empty) { + option (google.api.http) = { + post: "/v1/{subscription=projects/*/subscriptions/*}:acknowledge" + body: "*" + }; + option (google.api.method_signature) = "subscription,ack_ids"; + } + + // Pulls messages from the server. The server may return `UNAVAILABLE` if + // there are too many concurrent pull requests pending for the given + // subscription. + rpc Pull(PullRequest) returns (PullResponse) { + option (google.api.http) = { + post: "/v1/{subscription=projects/*/subscriptions/*}:pull" + body: "*" + }; + option (google.api.method_signature) = + "subscription,return_immediately,max_messages"; + option (google.api.method_signature) = "subscription,max_messages"; + } + + // Establishes a stream with the server, which sends messages down to the + // client. The client streams acknowledgements and ack deadline modifications + // back to the server. The server will close the stream and return the status + // on any error. The server may close the stream with status `UNAVAILABLE` to + // reassign server-side resources, in which case, the client should + // re-establish the stream. Flow control can be achieved by configuring the + // underlying RPC channel. + rpc StreamingPull(stream StreamingPullRequest) + returns (stream StreamingPullResponse) {} + + // Modifies the `PushConfig` for a specified subscription. + // + // This may be used to change a push subscription to a pull one (signified by + // an empty `PushConfig`) or vice versa, or change the endpoint URL and other + // attributes of a push subscription. Messages will accumulate for delivery + // continuously through the call regardless of changes to the `PushConfig`. + rpc ModifyPushConfig(ModifyPushConfigRequest) + returns (google.protobuf.Empty) { + option (google.api.http) = { + post: "/v1/{subscription=projects/*/subscriptions/*}:modifyPushConfig" + body: "*" + }; + option (google.api.method_signature) = "subscription,push_config"; + } + + // Gets the configuration details of a snapshot. Snapshots are used in + // Seek + // operations, which allow you to manage message acknowledgments in bulk. That + // is, you can set the acknowledgment state of messages in an existing + // subscription to the state captured by a snapshot. + rpc GetSnapshot(GetSnapshotRequest) returns (Snapshot) { + option (google.api.http) = { + get: "/v1/{snapshot=projects/*/snapshots/*}" + }; + option (google.api.method_signature) = "snapshot"; + } + + // Lists the existing snapshots. Snapshots are used in [Seek]( + // https://cloud.google.com/pubsub/docs/replay-overview) operations, which + // allow you to manage message acknowledgments in bulk. That is, you can set + // the acknowledgment state of messages in an existing subscription to the + // state captured by a snapshot. + rpc ListSnapshots(ListSnapshotsRequest) returns (ListSnapshotsResponse) { + option (google.api.http) = { + get: "/v1/{project=projects/*}/snapshots" + }; + option (google.api.method_signature) = "project"; + } + + // Creates a snapshot from the requested subscription. Snapshots are used in + // [Seek](https://cloud.google.com/pubsub/docs/replay-overview) operations, + // which allow you to manage message acknowledgments in bulk. That is, you can + // set the acknowledgment state of messages in an existing subscription to the + // state captured by a snapshot. + // If the snapshot already exists, returns `ALREADY_EXISTS`. + // If the requested subscription doesn't exist, returns `NOT_FOUND`. + // If the backlog in the subscription is too old -- and the resulting snapshot + // would expire in less than 1 hour -- then `FAILED_PRECONDITION` is returned. + // See also the `Snapshot.expire_time` field. If the name is not provided in + // the request, the server will assign a random + // name for this snapshot on the same project as the subscription, conforming + // to the [resource name format] + // (https://cloud.google.com/pubsub/docs/admin#resource_names). The + // generated name is populated in the returned Snapshot object. Note that for + // REST API requests, you must specify a name in the request. + rpc CreateSnapshot(CreateSnapshotRequest) returns (Snapshot) { + option (google.api.http) = { + put: "/v1/{name=projects/*/snapshots/*}" + body: "*" + }; + option (google.api.method_signature) = "name,subscription"; + } + + // Updates an existing snapshot. Snapshots are used in + // Seek + // operations, which allow + // you to manage message acknowledgments in bulk. That is, you can set the + // acknowledgment state of messages in an existing subscription to the state + // captured by a snapshot. + rpc UpdateSnapshot(UpdateSnapshotRequest) returns (Snapshot) { + option (google.api.http) = { + patch: "/v1/{snapshot.name=projects/*/snapshots/*}" + body: "*" + }; + } + + // Removes an existing snapshot. Snapshots are used in [Seek] + // (https://cloud.google.com/pubsub/docs/replay-overview) operations, which + // allow you to manage message acknowledgments in bulk. That is, you can set + // the acknowledgment state of messages in an existing subscription to the + // state captured by a snapshot. + // When the snapshot is deleted, all messages retained in the snapshot + // are immediately dropped. After a snapshot is deleted, a new one may be + // created with the same name, but the new one has no association with the old + // snapshot or its subscription, unless the same subscription is specified. + rpc DeleteSnapshot(DeleteSnapshotRequest) returns (google.protobuf.Empty) { + option (google.api.http) = { + delete: "/v1/{snapshot=projects/*/snapshots/*}" + }; + option (google.api.method_signature) = "snapshot"; + } + + // Seeks an existing subscription to a point in time or to a given snapshot, + // whichever is provided in the request. Snapshots are used in [Seek] + // (https://cloud.google.com/pubsub/docs/replay-overview) operations, which + // allow you to manage message acknowledgments in bulk. That is, you can set + // the acknowledgment state of messages in an existing subscription to the + // state captured by a snapshot. Note that both the subscription and the + // snapshot must be on the same topic. + rpc Seek(SeekRequest) returns (SeekResponse) { + option (google.api.http) = { + post: "/v1/{subscription=projects/*/subscriptions/*}:seek" + body: "*" + }; + } +} + +// A subscription resource. +message Subscription { + option (google.api.resource) = { + type: "pubsub.googleapis.com/Subscription" + pattern: "projects/{project}/subscriptions/{subscription}" + }; + + // Required. The name of the subscription. It must have the format + // `"projects/{project}/subscriptions/{subscription}"`. `{subscription}` must + // start with a letter, and contain only letters (`[A-Za-z]`), numbers + // (`[0-9]`), dashes (`-`), underscores (`_`), periods (`.`), tildes (`~`), + // plus (`+`) or percent signs (`%`). It must be between 3 and 255 characters + // in length, and it must not start with `"goog"`. + string name = 1 [(google.api.field_behavior) = REQUIRED]; + + // Required. The name of the topic from which this subscription is receiving + // messages. Format is `projects/{project}/topics/{topic}`. The value of this + // field will be `_deleted-topic_` if the topic has been deleted. + string topic = 2 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { type: "pubsub.googleapis.com/Topic" } + ]; + + // If push delivery is used with this subscription, this field is + // used to configure it. An empty `pushConfig` signifies that the subscriber + // will pull and ack messages using API methods. + PushConfig push_config = 4; + + // The approximate amount of time (on a best-effort basis) Pub/Sub waits for + // the subscriber to acknowledge receipt before resending the message. In the + // interval after the message is delivered and before it is acknowledged, it + // is considered to be outstanding. During that time period, the + // message will not be redelivered (on a best-effort basis). + // + // For pull subscriptions, this value is used as the initial value for the ack + // deadline. To override this value for a given message, call + // `ModifyAckDeadline` with the corresponding `ack_id` if using + // non-streaming pull or send the `ack_id` in a + // `StreamingModifyAckDeadlineRequest` if using streaming pull. + // The minimum custom deadline you can specify is 10 seconds. + // The maximum custom deadline you can specify is 600 seconds (10 minutes). + // If this parameter is 0, a default value of 10 seconds is used. + // + // For push delivery, this value is also used to set the request timeout for + // the call to the push endpoint. + // + // If the subscriber never acknowledges the message, the Pub/Sub + // system will eventually redeliver the message. + int32 ack_deadline_seconds = 5; + + // Indicates whether to retain acknowledged messages. If true, then + // messages are not expunged from the subscription's backlog, even if they are + // acknowledged, until they fall out of the `message_retention_duration` + // window. This must be true if you would like to [Seek to a timestamp] + // (https://cloud.google.com/pubsub/docs/replay-overview#seek_to_a_time). + bool retain_acked_messages = 7; + + // How long to retain unacknowledged messages in the subscription's backlog, + // from the moment a message is published. + // If `retain_acked_messages` is true, then this also configures the retention + // of acknowledged messages, and thus configures how far back in time a `Seek` + // can be done. Defaults to 7 days. Cannot be more than 7 days or less than 10 + // minutes. + google.protobuf.Duration message_retention_duration = 8; + + // See Creating and + // managing labels. + map labels = 9; + + // If true, messages published with the same `ordering_key` in `PubsubMessage` + // will be delivered to the subscribers in the order in which they + // are received by the Pub/Sub system. Otherwise, they may be delivered in + // any order. + bool enable_message_ordering = 10; + + // A policy that specifies the conditions for this subscription's expiration. + // A subscription is considered active as long as any connected subscriber is + // successfully consuming messages from the subscription or is issuing + // operations on the subscription. If `expiration_policy` is not set, a + // *default policy* with `ttl` of 31 days will be used. The minimum allowed + // value for `expiration_policy.ttl` is 1 day. + ExpirationPolicy expiration_policy = 11; + + // An expression written in the Pub/Sub [filter + // language](https://cloud.google.com/pubsub/docs/filtering). If non-empty, + // then only `PubsubMessage`s whose `attributes` field matches the filter are + // delivered on this subscription. If empty, then no messages are filtered + // out. + string filter = 12; + + // A policy that specifies the conditions for dead lettering messages in + // this subscription. If dead_letter_policy is not set, dead lettering + // is disabled. + // + // The Cloud Pub/Sub service account associated with this subscriptions's + // parent project (i.e., + // service-{project_number}@gcp-sa-pubsub.iam.gserviceaccount.com) must have + // permission to Acknowledge() messages on this subscription. + DeadLetterPolicy dead_letter_policy = 13; + + // A policy that specifies how Pub/Sub retries message delivery for this + // subscription. + // + // If not set, the default retry policy is applied. This generally implies + // that messages will be retried as soon as possible for healthy subscribers. + // RetryPolicy will be triggered on NACKs or acknowledgement deadline + // exceeded events for a given message. + RetryPolicy retry_policy = 14; + + // Indicates whether the subscription is detached from its topic. Detached + // subscriptions don't receive messages from their topic and don't retain any + // backlog. `Pull` and `StreamingPull` requests will return + // FAILED_PRECONDITION. If the subscription is a push subscription, pushes to + // the endpoint will not be made. + bool detached = 15; + + // Output only. Indicates the minimum duration for which a message is retained + // after it is published to the subscription's topic. If this field is set, + // messages published to the subscription's topic in the last + // `topic_message_retention_duration` are always available to subscribers. See + // the `message_retention_duration` field in `Topic`. This field is set only + // in responses from the server; it is ignored if it is set in any requests. + google.protobuf.Duration topic_message_retention_duration = 17 + [(google.api.field_behavior) = OUTPUT_ONLY]; +} + +// A policy that specifies how Cloud Pub/Sub retries message delivery. +// +// Retry delay will be exponential based on provided minimum and maximum +// backoffs. https://en.wikipedia.org/wiki/Exponential_backoff. +// +// RetryPolicy will be triggered on NACKs or acknowledgement deadline exceeded +// events for a given message. +// +// Retry Policy is implemented on a best effort basis. At times, the delay +// between consecutive deliveries may not match the configuration. That is, +// delay can be more or less than configured backoff. +message RetryPolicy { + // The minimum delay between consecutive deliveries of a given message. + // Value should be between 0 and 600 seconds. Defaults to 10 seconds. + google.protobuf.Duration minimum_backoff = 1; + + // The maximum delay between consecutive deliveries of a given message. + // Value should be between 0 and 600 seconds. Defaults to 600 seconds. + google.protobuf.Duration maximum_backoff = 2; +} + +// Dead lettering is done on a best effort basis. The same message might be +// dead lettered multiple times. +// +// If validation on any of the fields fails at subscription creation/updation, +// the create/update subscription request will fail. +message DeadLetterPolicy { + // The name of the topic to which dead letter messages should be published. + // Format is `projects/{project}/topics/{topic}`.The Cloud Pub/Sub service + // account associated with the enclosing subscription's parent project (i.e., + // service-{project_number}@gcp-sa-pubsub.iam.gserviceaccount.com) must have + // permission to Publish() to this topic. + // + // The operation will fail if the topic does not exist. + // Users should ensure that there is a subscription attached to this topic + // since messages published to a topic with no subscriptions are lost. + string dead_letter_topic = 1; + + // The maximum number of delivery attempts for any message. The value must be + // between 5 and 100. + // + // The number of delivery attempts is defined as 1 + (the sum of number of + // NACKs and number of times the acknowledgement deadline has been exceeded + // for the message). + // + // A NACK is any call to ModifyAckDeadline with a 0 deadline. Note that + // client libraries may automatically extend ack_deadlines. + // + // This field will be honored on a best effort basis. + // + // If this parameter is 0, a default value of 5 is used. + int32 max_delivery_attempts = 2; +} + +// A policy that specifies the conditions for resource expiration (i.e., +// automatic resource deletion). +message ExpirationPolicy { + // Specifies the "time-to-live" duration for an associated resource. The + // resource expires if it is not active for a period of `ttl`. The definition + // of "activity" depends on the type of the associated resource. The minimum + // and maximum allowed values for `ttl` depend on the type of the associated + // resource, as well. If `ttl` is not set, the associated resource never + // expires. + google.protobuf.Duration ttl = 1; +} + +// Configuration for a push delivery endpoint. +message PushConfig { + // Contains information needed for generating an + // [OpenID Connect + // token](https://developers.google.com/identity/protocols/OpenIDConnect). + message OidcToken { + // [Service account + // email](https://cloud.google.com/iam/docs/service-accounts) + // to be used for generating the OIDC token. The caller (for + // CreateSubscription, UpdateSubscription, and ModifyPushConfig RPCs) must + // have the iam.serviceAccounts.actAs permission for the service account. + string service_account_email = 1; + + // Audience to be used when generating OIDC token. The audience claim + // identifies the recipients that the JWT is intended for. The audience + // value is a single case-sensitive string. Having multiple values (array) + // for the audience field is not supported. More info about the OIDC JWT + // token audience here: https://tools.ietf.org/html/rfc7519#section-4.1.3 + // Note: if not specified, the Push endpoint URL will be used. + string audience = 2; + } + + // A URL locating the endpoint to which messages should be pushed. + // For example, a Webhook endpoint might use `https://example.com/push`. + string push_endpoint = 1; + + // Endpoint configuration attributes that can be used to control different + // aspects of the message delivery. + // + // The only currently supported attribute is `x-goog-version`, which you can + // use to change the format of the pushed message. This attribute + // indicates the version of the data expected by the endpoint. This + // controls the shape of the pushed message (i.e., its fields and metadata). + // + // If not present during the `CreateSubscription` call, it will default to + // the version of the Pub/Sub API used to make such call. If not present in a + // `ModifyPushConfig` call, its value will not be changed. `GetSubscription` + // calls will always return a valid version, even if the subscription was + // created without this attribute. + // + // The only supported values for the `x-goog-version` attribute are: + // + // * `v1beta1`: uses the push format defined in the v1beta1 Pub/Sub API. + // * `v1` or `v1beta2`: uses the push format defined in the v1 Pub/Sub API. + // + // For example: + //
attributes { "x-goog-version": "v1" } 
+ map attributes = 2; + + // An authentication method used by push endpoints to verify the source of + // push requests. This can be used with push endpoints that are private by + // default to allow requests only from the Cloud Pub/Sub system, for example. + // This field is optional and should be set only by users interested in + // authenticated push. + oneof authentication_method { + // If specified, Pub/Sub will generate and attach an OIDC JWT token as an + // `Authorization` header in the HTTP request for every pushed message. + OidcToken oidc_token = 3; + } +} + +// A message and its corresponding acknowledgment ID. +message ReceivedMessage { + // This ID can be used to acknowledge the received message. + string ack_id = 1; + + // The message. + PubsubMessage message = 2; + + // The approximate number of times that Cloud Pub/Sub has attempted to deliver + // the associated message to a subscriber. + // + // More precisely, this is 1 + (number of NACKs) + + // (number of ack_deadline exceeds) for this message. + // + // A NACK is any call to ModifyAckDeadline with a 0 deadline. An ack_deadline + // exceeds event is whenever a message is not acknowledged within + // ack_deadline. Note that ack_deadline is initially + // Subscription.ackDeadlineSeconds, but may get extended automatically by + // the client library. + // + // Upon the first delivery of a given message, `delivery_attempt` will have a + // value of 1. The value is calculated at best effort and is approximate. + // + // If a DeadLetterPolicy is not set on the subscription, this will be 0. + int32 delivery_attempt = 3; +} + +// Request for the GetSubscription method. +message GetSubscriptionRequest { + // Required. The name of the subscription to get. + // Format is `projects/{project}/subscriptions/{sub}`. + string subscription = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + type: "pubsub.googleapis.com/Subscription" + } + ]; +} + +// Request for the UpdateSubscription method. +message UpdateSubscriptionRequest { + // Required. The updated subscription object. + Subscription subscription = 1 [(google.api.field_behavior) = REQUIRED]; + + // Required. Indicates which fields in the provided subscription to update. + // Must be specified and non-empty. + google.protobuf.FieldMask update_mask = 2 + [(google.api.field_behavior) = REQUIRED]; +} + +// Request for the `ListSubscriptions` method. +message ListSubscriptionsRequest { + // Required. The name of the project in which to list subscriptions. + // Format is `projects/{project-id}`. + string project = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + type: "cloudresourcemanager.googleapis.com/Project" + } + ]; + + // Maximum number of subscriptions to return. + int32 page_size = 2; + + // The value returned by the last `ListSubscriptionsResponse`; indicates that + // this is a continuation of a prior `ListSubscriptions` call, and that the + // system should return the next page of data. + string page_token = 3; +} + +// Response for the `ListSubscriptions` method. +message ListSubscriptionsResponse { + // The subscriptions that match the request. + repeated Subscription subscriptions = 1; + + // If not empty, indicates that there may be more subscriptions that match + // the request; this value should be passed in a new + // `ListSubscriptionsRequest` to get more subscriptions. + string next_page_token = 2; +} + +// Request for the DeleteSubscription method. +message DeleteSubscriptionRequest { + // Required. The subscription to delete. + // Format is `projects/{project}/subscriptions/{sub}`. + string subscription = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + type: "pubsub.googleapis.com/Subscription" + } + ]; +} + +// Request for the ModifyPushConfig method. +message ModifyPushConfigRequest { + // Required. The name of the subscription. + // Format is `projects/{project}/subscriptions/{sub}`. + string subscription = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + type: "pubsub.googleapis.com/Subscription" + } + ]; + + // Required. The push configuration for future deliveries. + // + // An empty `pushConfig` indicates that the Pub/Sub system should + // stop pushing messages from the given subscription and allow + // messages to be pulled and acknowledged - effectively pausing + // the subscription if `Pull` or `StreamingPull` is not called. + PushConfig push_config = 2 [(google.api.field_behavior) = REQUIRED]; +} + +// Request for the `Pull` method. +message PullRequest { + // Required. The subscription from which messages should be pulled. + // Format is `projects/{project}/subscriptions/{sub}`. + string subscription = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + type: "pubsub.googleapis.com/Subscription" + } + ]; + + // Optional. If this field set to true, the system will respond immediately + // even if it there are no messages available to return in the `Pull` + // response. Otherwise, the system may wait (for a bounded amount of time) + // until at least one message is available, rather than returning no messages. + // Warning: setting this field to `true` is discouraged because it adversely + // impacts the performance of `Pull` operations. We recommend that users do + // not set this field. + bool return_immediately = 2 + [deprecated = true, (google.api.field_behavior) = OPTIONAL]; + + // Required. The maximum number of messages to return for this request. Must + // be a positive integer. The Pub/Sub system may return fewer than the number + // specified. + int32 max_messages = 3 [(google.api.field_behavior) = REQUIRED]; +} + +// Response for the `Pull` method. +message PullResponse { + // Received Pub/Sub messages. The list will be empty if there are no more + // messages available in the backlog. For JSON, the response can be entirely + // empty. The Pub/Sub system may return fewer than the `maxMessages` requested + // even if there are more messages available in the backlog. + repeated ReceivedMessage received_messages = 1; +} + +// Request for the ModifyAckDeadline method. +message ModifyAckDeadlineRequest { + // Required. The name of the subscription. + // Format is `projects/{project}/subscriptions/{sub}`. + string subscription = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + type: "pubsub.googleapis.com/Subscription" + } + ]; + + // Required. List of acknowledgment IDs. + repeated string ack_ids = 4 [(google.api.field_behavior) = REQUIRED]; + + // Required. The new ack deadline with respect to the time this request was + // sent to the Pub/Sub system. For example, if the value is 10, the new ack + // deadline will expire 10 seconds after the `ModifyAckDeadline` call was + // made. Specifying zero might immediately make the message available for + // delivery to another subscriber client. This typically results in an + // increase in the rate of message redeliveries (that is, duplicates). + // The minimum deadline you can specify is 0 seconds. + // The maximum deadline you can specify is 600 seconds (10 minutes). + int32 ack_deadline_seconds = 3 [(google.api.field_behavior) = REQUIRED]; +} + +// Request for the Acknowledge method. +message AcknowledgeRequest { + // Required. The subscription whose message is being acknowledged. + // Format is `projects/{project}/subscriptions/{sub}`. + string subscription = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + type: "pubsub.googleapis.com/Subscription" + } + ]; + + // Required. The acknowledgment ID for the messages being acknowledged that + // was returned by the Pub/Sub system in the `Pull` response. Must not be + // empty. + repeated string ack_ids = 2 [(google.api.field_behavior) = REQUIRED]; +} + +// Request for the `StreamingPull` streaming RPC method. This request is used to +// establish the initial stream as well as to stream acknowledgements and ack +// deadline modifications from the client to the server. +message StreamingPullRequest { + // Required. The subscription for which to initialize the new stream. This + // must be provided in the first request on the stream, and must not be set in + // subsequent requests from client to server. + // Format is `projects/{project}/subscriptions/{sub}`. + string subscription = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + type: "pubsub.googleapis.com/Subscription" + } + ]; + + // List of acknowledgement IDs for acknowledging previously received messages + // (received on this stream or a different stream). If an ack ID has expired, + // the corresponding message may be redelivered later. Acknowledging a message + // more than once will not result in an error. If the acknowledgement ID is + // malformed, the stream will be aborted with status `INVALID_ARGUMENT`. + repeated string ack_ids = 2; + + // The list of new ack deadlines for the IDs listed in + // `modify_deadline_ack_ids`. The size of this list must be the same as the + // size of `modify_deadline_ack_ids`. If it differs the stream will be aborted + // with `INVALID_ARGUMENT`. Each element in this list is applied to the + // element in the same position in `modify_deadline_ack_ids`. The new ack + // deadline is with respect to the time this request was sent to the Pub/Sub + // system. Must be >= 0. For example, if the value is 10, the new ack deadline + // will expire 10 seconds after this request is received. If the value is 0, + // the message is immediately made available for another streaming or + // non-streaming pull request. If the value is < 0 (an error), the stream will + // be aborted with status `INVALID_ARGUMENT`. + repeated int32 modify_deadline_seconds = 3; + + // List of acknowledgement IDs whose deadline will be modified based on the + // corresponding element in `modify_deadline_seconds`. This field can be used + // to indicate that more time is needed to process a message by the + // subscriber, or to make the message available for redelivery if the + // processing was interrupted. + repeated string modify_deadline_ack_ids = 4; + + // Required. The ack deadline to use for the stream. This must be provided in + // the first request on the stream, but it can also be updated on subsequent + // requests from client to server. The minimum deadline you can specify is 10 + // seconds. The maximum deadline you can specify is 600 seconds (10 minutes). + int32 stream_ack_deadline_seconds = 5 + [(google.api.field_behavior) = REQUIRED]; + + // A unique identifier that is used to distinguish client instances from each + // other. Only needs to be provided on the initial request. When a stream + // disconnects and reconnects for the same stream, the client_id should be set + // to the same value so that state associated with the old stream can be + // transferred to the new stream. The same client_id should not be used for + // different client instances. + string client_id = 6; + + // Flow control settings for the maximum number of outstanding messages. When + // there are `max_outstanding_messages` or more currently sent to the + // streaming pull client that have not yet been acked or nacked, the server + // stops sending more messages. The sending of messages resumes once the + // number of outstanding messages is less than this value. If the value is + // <= 0, there is no limit to the number of outstanding messages. This + // property can only be set on the initial StreamingPullRequest. If it is set + // on a subsequent request, the stream will be aborted with status + // `INVALID_ARGUMENT`. + int64 max_outstanding_messages = 7; + + // Flow control settings for the maximum number of outstanding bytes. When + // there are `max_outstanding_bytes` or more worth of messages currently sent + // to the streaming pull client that have not yet been acked or nacked, the + // server will stop sending more messages. The sending of messages resumes + // once the number of outstanding bytes is less than this value. If the value + // is <= 0, there is no limit to the number of outstanding bytes. This + // property can only be set on the initial StreamingPullRequest. If it is set + // on a subsequent request, the stream will be aborted with status + // `INVALID_ARGUMENT`. + int64 max_outstanding_bytes = 8; +} + +// Response for the `StreamingPull` method. This response is used to stream +// messages from the server to the client. +message StreamingPullResponse { + // Subscription properties sent as part of the response. + message SubscriptionProperties { + bool exactly_once_delivery_enabled = 1; + // True iff message ordering is enabled for this subscription. + bool message_ordering_enabled = 2; + } + + // Received Pub/Sub messages. This will not be empty. + repeated ReceivedMessage received_messages = 1; + + // Properties associated with this subscription. + SubscriptionProperties subscription_properties = 4; +} + +// Request for the `CreateSnapshot` method. +message CreateSnapshotRequest { + // Required. User-provided name for this snapshot. If the name is not provided + // in the request, the server will assign a random name for this snapshot on + // the same project as the subscription. Note that for REST API requests, you + // must specify a name. See the resource + // name rules. Format is `projects/{project}/snapshots/{snap}`. + string name = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { type: "pubsub.googleapis.com/Snapshot" } + ]; + + // Required. The subscription whose backlog the snapshot retains. + // Specifically, the created snapshot is guaranteed to retain: + // (a) The existing backlog on the subscription. More precisely, this is + // defined as the messages in the subscription's backlog that are + // unacknowledged upon the successful completion of the + // `CreateSnapshot` request; as well as: + // (b) Any messages published to the subscription's topic following the + // successful completion of the CreateSnapshot request. + // Format is `projects/{project}/subscriptions/{sub}`. + string subscription = 2 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + type: "pubsub.googleapis.com/Subscription" + } + ]; + + // See Creating and + // managing labels. + map labels = 3; +} + +// Request for the UpdateSnapshot method. +message UpdateSnapshotRequest { + // Required. The updated snapshot object. + Snapshot snapshot = 1 [(google.api.field_behavior) = REQUIRED]; + + // Required. Indicates which fields in the provided snapshot to update. + // Must be specified and non-empty. + google.protobuf.FieldMask update_mask = 2 + [(google.api.field_behavior) = REQUIRED]; +} + +// A snapshot resource. Snapshots are used in +// [Seek](https://cloud.google.com/pubsub/docs/replay-overview) +// operations, which allow you to manage message acknowledgments in bulk. That +// is, you can set the acknowledgment state of messages in an existing +// subscription to the state captured by a snapshot. +message Snapshot { + option (google.api.resource) = { + type: "pubsub.googleapis.com/Snapshot" + pattern: "projects/{project}/snapshots/{snapshot}" + }; + + // The name of the snapshot. + string name = 1; + + // The name of the topic from which this snapshot is retaining messages. + string topic = 2 [ + (google.api.resource_reference) = { type: "pubsub.googleapis.com/Topic" } + ]; + + // The snapshot is guaranteed to exist up until this time. + // A newly-created snapshot expires no later than 7 days from the time of its + // creation. Its exact lifetime is determined at creation by the existing + // backlog in the source subscription. Specifically, the lifetime of the + // snapshot is `7 days - (age of oldest unacked message in the subscription)`. + // For example, consider a subscription whose oldest unacked message is 3 days + // old. If a snapshot is created from this subscription, the snapshot -- which + // will always capture this 3-day-old backlog as long as the snapshot + // exists -- will expire in 4 days. The service will refuse to create a + // snapshot that would expire in less than 1 hour after creation. + google.protobuf.Timestamp expire_time = 3; + + // See [Creating and managing labels] + // (https://cloud.google.com/pubsub/docs/labels). + map labels = 4; +} + +// Request for the GetSnapshot method. +message GetSnapshotRequest { + // Required. The name of the snapshot to get. + // Format is `projects/{project}/snapshots/{snap}`. + string snapshot = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { type: "pubsub.googleapis.com/Snapshot" } + ]; +} + +// Request for the `ListSnapshots` method. +message ListSnapshotsRequest { + // Required. The name of the project in which to list snapshots. + // Format is `projects/{project-id}`. + string project = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + type: "cloudresourcemanager.googleapis.com/Project" + } + ]; + + // Maximum number of snapshots to return. + int32 page_size = 2; + + // The value returned by the last `ListSnapshotsResponse`; indicates that this + // is a continuation of a prior `ListSnapshots` call, and that the system + // should return the next page of data. + string page_token = 3; +} + +// Response for the `ListSnapshots` method. +message ListSnapshotsResponse { + // The resulting snapshots. + repeated Snapshot snapshots = 1; + + // If not empty, indicates that there may be more snapshot that match the + // request; this value should be passed in a new `ListSnapshotsRequest`. + string next_page_token = 2; +} + +// Request for the `DeleteSnapshot` method. +message DeleteSnapshotRequest { + // Required. The name of the snapshot to delete. + // Format is `projects/{project}/snapshots/{snap}`. + string snapshot = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { type: "pubsub.googleapis.com/Snapshot" } + ]; +} + +// Request for the `Seek` method. +message SeekRequest { + // Required. The subscription to affect. + string subscription = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + type: "pubsub.googleapis.com/Subscription" + } + ]; + + oneof target { + // The time to seek to. + // Messages retained in the subscription that were published before this + // time are marked as acknowledged, and messages retained in the + // subscription that were published after this time are marked as + // unacknowledged. Note that this operation affects only those messages + // retained in the subscription (configured by the combination of + // `message_retention_duration` and `retain_acked_messages`). For example, + // if `time` corresponds to a point before the message retention + // window (or to a point before the system's notion of the subscription + // creation time), only retained messages will be marked as unacknowledged, + // and already-expunged messages will not be restored. + google.protobuf.Timestamp time = 2; + + // The snapshot to seek to. The snapshot's topic must be the same as that of + // the provided subscription. + // Format is `projects/{project}/snapshots/{snap}`. + string snapshot = 3 [(google.api.resource_reference) = { + type: "pubsub.googleapis.com/Snapshot" + }]; + } +} + +// Response for the `Seek` method (this response is empty). +message SeekResponse {} diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/proto/schema.proto b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/proto/schema.proto new file mode 100644 index 000000000000..1ace7ef3b0d7 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/proto/schema.proto @@ -0,0 +1,286 @@ +// Copyright 2020 Google LLC +// +// 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. + +syntax = "proto3"; + +package google.pubsub.v1; + +import "google/api/annotations.proto"; +import "google/api/client.proto"; +import "google/api/field_behavior.proto"; +import "google/api/resource.proto"; +import "google/protobuf/empty.proto"; + +option cc_enable_arenas = true; +option csharp_namespace = "Google.Cloud.PubSub.V1"; +option go_package = "google.golang.org/genproto/googleapis/pubsub/v1;pubsub"; +option java_multiple_files = true; +option java_outer_classname = "SchemaProto"; +option java_package = "com.google.pubsub.v1"; +option php_namespace = "Google\\Cloud\\PubSub\\V1"; +option ruby_package = "Google::Cloud::PubSub::V1"; + +// Service for doing schema-related operations. +service SchemaService { + option (google.api.default_host) = "pubsub.googleapis.com"; + option (google.api.oauth_scopes) = + "https://www.googleapis.com/auth/cloud-platform," + "https://www.googleapis.com/auth/pubsub"; + + // Creates a schema. + rpc CreateSchema(CreateSchemaRequest) returns (Schema) { + option (google.api.http) = { + post: "/v1/{parent=projects/*}/schemas" + body: "schema" + }; + option (google.api.method_signature) = "parent,schema,schema_id"; + } + + // Gets a schema. + rpc GetSchema(GetSchemaRequest) returns (Schema) { + option (google.api.http) = { + get: "/v1/{name=projects/*/schemas/*}" + }; + option (google.api.method_signature) = "name"; + } + + // Lists schemas in a project. + rpc ListSchemas(ListSchemasRequest) returns (ListSchemasResponse) { + option (google.api.http) = { + get: "/v1/{parent=projects/*}/schemas" + }; + option (google.api.method_signature) = "parent"; + } + + // Deletes a schema. + rpc DeleteSchema(DeleteSchemaRequest) returns (google.protobuf.Empty) { + option (google.api.http) = { + delete: "/v1/{name=projects/*/schemas/*}" + }; + option (google.api.method_signature) = "name"; + } + + // Validates a schema. + rpc ValidateSchema(ValidateSchemaRequest) returns (ValidateSchemaResponse) { + option (google.api.http) = { + post: "/v1/{parent=projects/*}/schemas:validate" + body: "*" + }; + option (google.api.method_signature) = "parent,schema"; + } + + // Validates a message against a schema. + rpc ValidateMessage(ValidateMessageRequest) + returns (ValidateMessageResponse) { + option (google.api.http) = { + post: "/v1/{parent=projects/*}/schemas:validateMessage" + body: "*" + }; + } +} + +// A schema resource. +message Schema { + option (google.api.resource) = { + type: "pubsub.googleapis.com/Schema" + pattern: "projects/{project}/schemas/{schema}" + }; + + // Possible schema definition types. + enum Type { + // Default value. This value is unused. + TYPE_UNSPECIFIED = 0; + + // A Protocol Buffer schema definition. + PROTOCOL_BUFFER = 1; + + // An Avro schema definition. + AVRO = 2; + } + + // Required. Name of the schema. + // Format is `projects/{project}/schemas/{schema}`. + string name = 1 [(google.api.field_behavior) = REQUIRED]; + + // The type of the schema definition. + Type type = 2; + + // The definition of the schema. This should contain a string representing + // the full definition of the schema that is a valid schema definition of + // the type specified in `type`. + string definition = 3; +} + +// Request for the CreateSchema method. +message CreateSchemaRequest { + // Required. The name of the project in which to create the schema. + // Format is `projects/{project-id}`. + string parent = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + child_type: "pubsub.googleapis.com/Schema" + } + ]; + + // Required. The schema object to create. + // + // This schema's `name` parameter is ignored. The schema object returned + // by CreateSchema will have a `name` made using the given `parent` and + // `schema_id`. + Schema schema = 2 [(google.api.field_behavior) = REQUIRED]; + + // The ID to use for the schema, which will become the final component of + // the schema's resource name. + // + // See https://cloud.google.com/pubsub/docs/admin#resource_names for resource + // name constraints. + string schema_id = 3; +} + +// View of Schema object fields to be returned by GetSchema and ListSchemas. +enum SchemaView { + // The default / unset value. + // The API will default to the BASIC view. + SCHEMA_VIEW_UNSPECIFIED = 0; + + // Include the name and type of the schema, but not the definition. + BASIC = 1; + + // Include all Schema object fields. + FULL = 2; +} + +// Request for the GetSchema method. +message GetSchemaRequest { + // Required. The name of the schema to get. + // Format is `projects/{project}/schemas/{schema}`. + string name = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { type: "pubsub.googleapis.com/Schema" } + ]; + + // The set of fields to return in the response. If not set, returns a Schema + // with `name` and `type`, but not `definition`. Set to `FULL` to retrieve all + // fields. + SchemaView view = 2; +} + +// Request for the `ListSchemas` method. +message ListSchemasRequest { + // Required. The name of the project in which to list schemas. + // Format is `projects/{project-id}`. + string parent = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + type: "cloudresourcemanager.googleapis.com/Project" + } + ]; + + // The set of Schema fields to return in the response. If not set, returns + // Schemas with `name` and `type`, but not `definition`. Set to `FULL` to + // retrieve all fields. + SchemaView view = 2; + + // Maximum number of schemas to return. + int32 page_size = 3; + + // The value returned by the last `ListSchemasResponse`; indicates that + // this is a continuation of a prior `ListSchemas` call, and that the + // system should return the next page of data. + string page_token = 4; +} + +// Response for the `ListSchemas` method. +message ListSchemasResponse { + // The resulting schemas. + repeated Schema schemas = 1; + + // If not empty, indicates that there may be more schemas that match the + // request; this value should be passed in a new `ListSchemasRequest`. + string next_page_token = 2; +} + +// Request for the `DeleteSchema` method. +message DeleteSchemaRequest { + // Required. Name of the schema to delete. + // Format is `projects/{project}/schemas/{schema}`. + string name = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { type: "pubsub.googleapis.com/Schema" } + ]; +} + +// Request for the `ValidateSchema` method. +message ValidateSchemaRequest { + // Required. The name of the project in which to validate schemas. + // Format is `projects/{project-id}`. + string parent = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + type: "cloudresourcemanager.googleapis.com/Project" + } + ]; + + // Required. The schema object to validate. + Schema schema = 2 [(google.api.field_behavior) = REQUIRED]; +} + +// Response for the `ValidateSchema` method. +message ValidateSchemaResponse {} + +// Request for the `ValidateMessage` method. +message ValidateMessageRequest { + // Required. The name of the project in which to validate schemas. + // Format is `projects/{project-id}`. + string parent = 1 [ + (google.api.field_behavior) = REQUIRED, + (google.api.resource_reference) = { + type: "cloudresourcemanager.googleapis.com/Project" + } + ]; + + oneof schema_spec { + // Name of the schema against which to validate. + // + // Format is `projects/{project}/schemas/{schema}`. + string name = 2 [ + (google.api.resource_reference) = { type: "pubsub.googleapis.com/Schema" } + ]; + + // Ad-hoc schema against which to validate + Schema schema = 3; + } + + // Message to validate against the provided `schema_spec`. + bytes message = 4; + + // The encoding expected for messages + Encoding encoding = 5; +} + +// Response for the `ValidateMessage` method. +message ValidateMessageResponse {} + +// Possible encoding types for messages. +enum Encoding { + // Unspecified + ENCODING_UNSPECIFIED = 0; + + // JSON encoding + JSON = 1; + + // Binary encoding, as defined by the schema type. For some schema types, + // binary encoding may not be available. + BINARY = 2; +} diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/pkgutil/pkgutil_foo/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/__init__.py similarity index 69% rename from packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/pkgutil/pkgutil_foo/__init__.py rename to packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/__init__.py index d5e5048bcc9c..688ee744b7b4 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/pkgutil/pkgutil_foo/__init__.py +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/__init__.py @@ -1,10 +1,10 @@ -# Copyright 2021 Google LLC +# Copyright 2017, Google LLC 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 +# 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, @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -# coding: utf-8 - -from format.rst.foo import Foo - -__all__ = ['Foo'] \ No newline at end of file +from __future__ import absolute_import + +from google.cloud.pubsub_v1.publisher.client import Client + + +__all__ = ("Client",) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/doc/index.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/_batch/__init__.py similarity index 100% rename from packages/gcp-sphinx-docfx-yaml/tests/example/doc/index.rst rename to packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/_batch/__init__.py diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/_batch/base.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/_batch/base.py new file mode 100644 index 000000000000..52505996be0b --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/_batch/base.py @@ -0,0 +1,170 @@ +# Copyright 2017, Google LLC 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. + +from __future__ import absolute_import + +import abc +import enum +import typing +from typing import Optional, Sequence + + +if typing.TYPE_CHECKING: # pragma: NO COVER + from google.cloud import pubsub_v1 + from google.cloud.pubsub_v1 import types + from google.pubsub_v1 import types as gapic_types + + +class Batch(metaclass=abc.ABCMeta): + """The base batching class for Pub/Sub publishing. + + Although the :class:`~.pubsub_v1.publisher.batch.thread.Batch` class, based + on :class:`threading.Thread`, is fine for most cases, advanced + users may need to implement something based on a different concurrency + model. + + This class defines the interface for the Batch implementation; + subclasses may be passed as the ``batch_class`` argument to + :class:`~.pubsub_v1.client.PublisherClient`. + + The batching behavior works like this: When the + :class:`~.pubsub_v1.publisher.client.Client` is asked to publish a new + message, it requires a batch. The client will see if there is an + already-opened batch for the given topic; if there is, then the message + is sent to that batch. If there is not, then a new batch is created + and the message put there. + + When a new batch is created, it automatically starts a timer counting + down to the maximum latency before the batch should commit. + Essentially, if enough time passes, the batch automatically commits + regardless of how much is in it. However, if either the message count or + size thresholds are encountered first, then the batch will commit early. + """ + + def __len__(self): + """Return the number of messages currently in the batch.""" + return len(self.messages) + + @staticmethod + @abc.abstractmethod + def make_lock(): # pragma: NO COVER + """Return a lock in the chosen concurrency model. + + Returns: + ContextManager: A newly created lock. + """ + raise NotImplementedError + + @property + @abc.abstractmethod + def messages(self) -> Sequence["gapic_types.PubsubMessage"]: # pragma: NO COVER + """Return the messages currently in the batch. + + Returns: + The messages currently in the batch. + """ + raise NotImplementedError + + @property + @abc.abstractmethod + def size(self) -> int: # pragma: NO COVER + """Return the total size of all of the messages currently in the batch. + + The size includes any overhead of the actual ``PublishRequest`` that is + sent to the backend. + + Returns: + int: The total size of all of the messages currently + in the batch (including the request overhead), in bytes. + """ + raise NotImplementedError + + @property + @abc.abstractmethod + def settings(self) -> "types.BatchSettings": # pragma: NO COVER + """Return the batch settings. + + Returns: + The batch settings. These are considered immutable once the batch has + been opened. + """ + raise NotImplementedError + + @property + @abc.abstractmethod + def status(self) -> "BatchStatus": # pragma: NO COVER + """Return the status of this batch. + + Returns: + The status of this batch. All statuses are human-readable, all-lowercase + strings. The ones represented in the :class:`BaseBatch.Status` enum are + special, but other statuses are permitted. + """ + raise NotImplementedError + + def cancel( + self, cancellation_reason: "BatchCancellationReason" + ) -> None: # pragma: NO COVER + """Complete pending futures with an exception. + + This method must be called before publishing starts (ie: while the + batch is still accepting messages.) + + Args: + cancellation_reason: + The reason why this batch has been cancelled. + """ + raise NotImplementedError + + @abc.abstractmethod + def publish( + self, message: "gapic_types.PubsubMessage" + ) -> Optional["pubsub_v1.publisher.futures.Future"]: # pragma: NO COVER + """Publish a single message. + + Add the given message to this object; this will cause it to be + published once the batch either has enough messages or a sufficient + period of time has elapsed. + + This method is called by :meth:`~.PublisherClient.publish`. + + Args: + message: The Pub/Sub message. + + Returns: + An object conforming to the :class:`concurrent.futures.Future` interface. + If :data:`None` is returned, that signals that the batch cannot + accept a message. + """ + raise NotImplementedError + + +class BatchStatus(str, enum.Enum): + """An enum-like class representing valid statuses for a batch.""" + + ACCEPTING_MESSAGES = "accepting messages" + STARTING = "starting" + IN_PROGRESS = "in progress" + ERROR = "error" + SUCCESS = "success" + + +class BatchCancellationReason(str, enum.Enum): + """An enum-like class representing reasons why a batch was cancelled.""" + + PRIOR_ORDERED_MESSAGE_FAILED = ( + "Batch cancelled because prior ordered message for the same key has " + "failed. This batch has been cancelled to avoid out-of-order publish." + ) + CLIENT_STOPPED = "Batch cancelled because the publisher client has been stopped." diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/_batch/thread.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/_batch/thread.py new file mode 100644 index 000000000000..8b868eaee88f --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/_batch/thread.py @@ -0,0 +1,409 @@ +# Copyright 2017, Google LLC 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. + +from __future__ import absolute_import + +import logging +import threading +import time +import typing +from typing import Any, Callable, List, Optional, Sequence + +import google.api_core.exceptions +from google.api_core import gapic_v1 +from google.cloud.pubsub_v1.publisher import exceptions +from google.cloud.pubsub_v1.publisher import futures +from google.cloud.pubsub_v1.publisher._batch import base +from google.pubsub_v1 import types as gapic_types + +if typing.TYPE_CHECKING: # pragma: NO COVER + from google.cloud import pubsub_v1 + from google.cloud.pubsub_v1 import types + from google.cloud.pubsub_v1.publisher import Client as PublisherClient + from google.pubsub_v1.services.publisher.client import OptionalRetry + +_LOGGER = logging.getLogger(__name__) +_CAN_COMMIT = (base.BatchStatus.ACCEPTING_MESSAGES, base.BatchStatus.STARTING) +_SERVER_PUBLISH_MAX_BYTES = 10 * 1000 * 1000 # max accepted size of PublishRequest + +_raw_proto_pubbsub_message = gapic_types.PubsubMessage.pb() + + +class Batch(base.Batch): + """A batch of messages. + + The batch is the internal group of messages which are either awaiting + publication or currently in progress. + + A batch is automatically created by the PublisherClient when the first + message to be published is received; subsequent messages are added to + that batch until the process of actual publishing _starts_. + + Once this occurs, any new messages sent to :meth:`publish` open a new + batch. + + If you are using this library, you most likely do not need to instantiate + batch objects directly; they will be created for you. If you want to + change the actual batching settings, see the ``batching`` argument on + :class:`~.pubsub_v1.PublisherClient`. + + Any properties or methods on this class which are not defined in + :class:`~.pubsub_v1.publisher.batch.BaseBatch` should be considered + implementation details. + + Args: + client: + The publisher client used to create this batch. + topic: + The topic. The format for this is ``projects/{project}/topics/{topic}``. + settings: + The settings for batch publishing. These should be considered immutable + once the batch has been opened. + batch_done_callback: + Callback called when the response for a batch publish has been received. + Called with one boolean argument: successfully published or a permanent + error occurred. Temporary errors are not surfaced because they are retried + at a lower level. + commit_when_full: + Whether to commit the batch when the batch is full. + commit_retry: + Designation of what errors, if any, should be retried when commiting + the batch. If not provided, a default retry is used. + commit_timeout: + The timeout to apply when commiting the batch. If not provided, a default + timeout is used. + """ + + def __init__( + self, + client: "PublisherClient", + topic: str, + settings: "types.BatchSettings", + batch_done_callback: Callable[[bool], Any] = None, + commit_when_full: bool = True, + commit_retry: "OptionalRetry" = gapic_v1.method.DEFAULT, + commit_timeout: "types.OptionalTimeout" = gapic_v1.method.DEFAULT, + ): + self._client = client + self._topic = topic + self._settings = settings + self._batch_done_callback = batch_done_callback + self._commit_when_full = commit_when_full + + self._state_lock = threading.Lock() + # These members are all communicated between threads; ensure that + # any writes to them use the "state lock" to remain atomic. + # _futures list should remain unchanged after batch + # status changed from ACCEPTING_MESSAGES to any other + # in order to avoid race conditions + self._futures: List[futures.Future] = [] + self._messages: List[gapic_types.PubsubMessage] = [] + self._status = base.BatchStatus.ACCEPTING_MESSAGES + + # The initial size is not zero, we need to account for the size overhead + # of the PublishRequest message itself. + self._base_request_size = gapic_types.PublishRequest(topic=topic)._pb.ByteSize() + self._size = self._base_request_size + + self._commit_retry = commit_retry + self._commit_timeout = commit_timeout + + @staticmethod + def make_lock() -> threading.Lock: + """Return a threading lock. + + Returns: + A newly created lock. + """ + return threading.Lock() + + @property + def client(self) -> "PublisherClient": + """A publisher client.""" + return self._client + + @property + def messages(self) -> Sequence[gapic_types.PubsubMessage]: + """The messages currently in the batch.""" + return self._messages + + @property + def settings(self) -> "types.BatchSettings": + """Return the batch settings. + + Returns: + The batch settings. These are considered immutable once the batch has + been opened. + """ + return self._settings + + @property + def size(self) -> int: + """Return the total size of all of the messages currently in the batch. + + The size includes any overhead of the actual ``PublishRequest`` that is + sent to the backend. + + Returns: + The total size of all of the messages currently in the batch (including + the request overhead), in bytes. + """ + return self._size + + @property + def status(self) -> base.BatchStatus: + """Return the status of this batch. + + Returns: + The status of this batch. All statuses are human-readable, all-lowercase + strings. + """ + return self._status + + def cancel(self, cancellation_reason: base.BatchCancellationReason) -> None: + """Complete pending futures with an exception. + + This method must be called before publishing starts (ie: while the + batch is still accepting messages.) + + Args: + The reason why this batch has been cancelled. + """ + + with self._state_lock: + assert ( + self._status == base.BatchStatus.ACCEPTING_MESSAGES + ), "Cancel should not be called after sending has started." + + exc = RuntimeError(cancellation_reason.value) + for future in self._futures: + future.set_exception(exc) + self._status = base.BatchStatus.ERROR + + def commit(self) -> None: + """Actually publish all of the messages on the active batch. + + .. note:: + + This method is non-blocking. It opens a new thread, which calls + :meth:`_commit`, which does block. + + This synchronously sets the batch status to "starting", and then opens + a new thread, which handles actually sending the messages to Pub/Sub. + + If the current batch is **not** accepting messages, this method + does nothing. + """ + + # Set the status to "starting" synchronously, to ensure that + # this batch will necessarily not accept new messages. + with self._state_lock: + if self._status == base.BatchStatus.ACCEPTING_MESSAGES: + self._status = base.BatchStatus.STARTING + else: + return + + self._start_commit_thread() + + def _start_commit_thread(self) -> None: + """Start a new thread to actually handle the commit.""" + # NOTE: If the thread is *not* a daemon, a memory leak exists due to a CPython issue. + # https://github.com/googleapis/python-pubsub/issues/395#issuecomment-829910303 + # https://github.com/googleapis/python-pubsub/issues/395#issuecomment-830092418 + commit_thread = threading.Thread( + name="Thread-CommitBatchPublisher", target=self._commit, daemon=True + ) + commit_thread.start() + + def _commit(self) -> None: + """Actually publish all of the messages on the active batch. + + This moves the batch out from being the active batch to an in progress + batch on the publisher, and then the batch is discarded upon + completion. + + .. note:: + + This method blocks. The :meth:`commit` method is the non-blocking + version, which calls this one. + """ + with self._state_lock: + if self._status in _CAN_COMMIT: + self._status = base.BatchStatus.IN_PROGRESS + else: + # If, in the intervening period between when this method was + # called and now, the batch started to be committed, or + # completed a commit, then no-op at this point. + _LOGGER.debug( + "Batch is already in progress or has been cancelled, " + "exiting commit" + ) + return + + # Once in the IN_PROGRESS state, no other thread can publish additional + # messages or initiate a commit (those operations become a no-op), thus + # it is safe to release the state lock here. Releasing the lock avoids + # blocking other threads in case api.publish() below takes a long time + # to complete. + # https://github.com/googleapis/google-cloud-python/issues/8036 + + # Sanity check: If there are no messages, no-op. + if not self._messages: + _LOGGER.debug("No messages to publish, exiting commit") + self._status = base.BatchStatus.SUCCESS + return + + # Begin the request to publish these messages. + # Log how long the underlying request takes. + start = time.time() + + batch_transport_succeeded = True + try: + # Performs retries for errors defined by the retry configuration. + response = self._client._gapic_publish( + topic=self._topic, + messages=self._messages, + retry=self._commit_retry, + timeout=self._commit_timeout, + ) + except google.api_core.exceptions.GoogleAPIError as exc: + # We failed to publish, even after retries, so set the exception on + # all futures and exit. + self._status = base.BatchStatus.ERROR + + for future in self._futures: + future.set_exception(exc) + + batch_transport_succeeded = False + if self._batch_done_callback is not None: + # Failed to publish batch. + self._batch_done_callback(batch_transport_succeeded) + + _LOGGER.exception("Failed to publish %s messages.", len(self._futures)) + return + + end = time.time() + _LOGGER.debug("gRPC Publish took %s seconds.", end - start) + + if len(response.message_ids) == len(self._futures): + # Iterate over the futures on the queue and return the response + # IDs. We are trusting that there is a 1:1 mapping, and raise + # an exception if not. + self._status = base.BatchStatus.SUCCESS + for message_id, future in zip(response.message_ids, self._futures): + future.set_result(message_id) + else: + # Sanity check: If the number of message IDs is not equal to + # the number of futures I have, then something went wrong. + self._status = base.BatchStatus.ERROR + exception = exceptions.PublishError( + "Some messages were not successfully published." + ) + + for future in self._futures: + future.set_exception(exception) + + # Unknown error -> batch failed to be correctly transported/ + batch_transport_succeeded = False + + _LOGGER.error( + "Only %s of %s messages were published.", + len(response.message_ids), + len(self._futures), + ) + + if self._batch_done_callback is not None: + self._batch_done_callback(batch_transport_succeeded) + + def publish( + self, message: gapic_types.PubsubMessage + ) -> Optional["pubsub_v1.publisher.futures.Future"]: + """Publish a single message. + + Add the given message to this object; this will cause it to be + published once the batch either has enough messages or a sufficient + period of time has elapsed. If the batch is full or the commit is + already in progress, the method does not do anything. + + This method is called by :meth:`~.PublisherClient.publish`. + + Args: + message: The Pub/Sub message. + + Returns: + An object conforming to the :class:`~concurrent.futures.Future` interface + or :data:`None`. If :data:`None` is returned, that signals that the batch + cannot accept a message. + + Raises: + pubsub_v1.publisher.exceptions.MessageTooLargeError: If publishing + the ``message`` would exceed the max size limit on the backend. + """ + + # Coerce the type, just in case. + if not isinstance(message, gapic_types.PubsubMessage): + # For performance reasons, the message should be constructed by directly + # using the raw protobuf class, and only then wrapping it into the + # higher-level PubsubMessage class. + vanilla_pb = _raw_proto_pubbsub_message(**message) + message = gapic_types.PubsubMessage.wrap(vanilla_pb) + + future = None + + with self._state_lock: + assert ( + self._status != base.BatchStatus.ERROR + ), "Publish after stop() or publish error." + + if self.status != base.BatchStatus.ACCEPTING_MESSAGES: + return None + + size_increase = gapic_types.PublishRequest( + messages=[message] + )._pb.ByteSize() + + if (self._base_request_size + size_increase) > _SERVER_PUBLISH_MAX_BYTES: + err_msg = ( + "The message being published would produce too large a publish " + "request that would exceed the maximum allowed size on the " + "backend ({} bytes).".format(_SERVER_PUBLISH_MAX_BYTES) + ) + raise exceptions.MessageTooLargeError(err_msg) + + new_size = self._size + size_increase + new_count = len(self._messages) + 1 + + size_limit = min(self.settings.max_bytes, _SERVER_PUBLISH_MAX_BYTES) + overflow = new_size > size_limit or new_count >= self.settings.max_messages + + if not self._messages or not overflow: + + # Store the actual message in the batch's message queue. + self._messages.append(message) + self._size = new_size + + # Track the future on this batch (so that the result of the + # future can be set). + future = futures.Future() + self._futures.append(future) + + # Try to commit, but it must be **without** the lock held, since + # ``commit()`` will try to obtain the lock. + if self._commit_when_full and overflow: + self.commit() + + return future + + def _set_status(self, status: base.BatchStatus): + self._status = status diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/_sequencer/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/_sequencer/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/_sequencer/base.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/_sequencer/base.py new file mode 100644 index 000000000000..58ec5a571bb8 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/_sequencer/base.py @@ -0,0 +1,82 @@ +# Copyright 2019, Google LLC 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. + +from __future__ import absolute_import + +import abc +import typing + +from google.api_core import gapic_v1 +from google.pubsub_v1 import types as gapic_types + +if typing.TYPE_CHECKING: # pragma: NO COVER + from concurrent import futures + from google.pubsub_v1.services.publisher.client import OptionalRetry + + +class Sequencer(metaclass=abc.ABCMeta): + """The base class for sequencers for Pub/Sub publishing. A sequencer + sequences messages to be published. + """ + + @abc.abstractmethod + def is_finished(self) -> bool: # pragma: NO COVER + """Whether the sequencer is finished and should be cleaned up. + + Returns: + bool: Whether the sequencer is finished and should be cleaned up. + """ + raise NotImplementedError + + @abc.abstractmethod + def unpause(self) -> None: # pragma: NO COVER + """Unpauses this sequencer. + + Raises: + RuntimeError: + If called when the sequencer has not been paused. + """ + raise NotImplementedError + + @abc.abstractmethod + def publish( + self, + message: gapic_types.PubsubMessage, + retry: "OptionalRetry" = gapic_v1.method.DEFAULT, + timeout: gapic_types.TimeoutType = gapic_v1.method.DEFAULT, + ) -> "futures.Future": # pragma: NO COVER + """Publish message for this ordering key. + + Args: + message: + The Pub/Sub message. + retry: + The retry settings to apply when publishing the message. + timeout: + The timeout to apply when publishing the message. + + Returns: + A class instance that conforms to Python Standard library's + :class:`~concurrent.futures.Future` interface. The future might return + immediately with a + `pubsub_v1.publisher.exceptions.PublishToPausedOrderingKeyException` + if the ordering key is paused. Otherwise, the future tracks the + lifetime of the message publish. + + Raises: + RuntimeError: + If called after this sequencer has been stopped, either by + a call to stop() or after all batches have been published. + """ + raise NotImplementedError diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/_sequencer/ordered_sequencer.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/_sequencer/ordered_sequencer.py new file mode 100644 index 000000000000..30c76a44f4d2 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/_sequencer/ordered_sequencer.py @@ -0,0 +1,338 @@ +# Copyright 2019, Google LLC 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. + +import enum +import collections +import threading +import typing +from typing import Deque, Iterable, Sequence + +from google.api_core import gapic_v1 +from google.cloud.pubsub_v1.publisher import futures +from google.cloud.pubsub_v1.publisher import exceptions +from google.cloud.pubsub_v1.publisher._sequencer import base as sequencer_base +from google.cloud.pubsub_v1.publisher._batch import base as batch_base +from google.pubsub_v1 import types as gapic_types + +if typing.TYPE_CHECKING: # pragma: NO COVER + from google.cloud.pubsub_v1 import types + from google.cloud.pubsub_v1.publisher import _batch + from google.cloud.pubsub_v1.publisher.client import Client as PublisherClient + from google.pubsub_v1.services.publisher.client import OptionalRetry + + +class _OrderedSequencerStatus(str, enum.Enum): + """An enum-like class representing valid statuses for an OrderedSequencer. + + Starting state: ACCEPTING_MESSAGES + Valid transitions: + ACCEPTING_MESSAGES -> PAUSED (on permanent error) + ACCEPTING_MESSAGES -> STOPPED (when user calls stop() explicitly) + ACCEPTING_MESSAGES -> FINISHED (all batch publishes finish normally) + + PAUSED -> ACCEPTING_MESSAGES (when user unpauses) + PAUSED -> STOPPED (when user calls stop() explicitly) + + STOPPED -> FINISHED (user stops client and the one remaining batch finishes + publish) + STOPPED -> PAUSED (stop() commits one batch, which fails permanently) + + FINISHED -> ACCEPTING_MESSAGES (publish happens while waiting for cleanup) + FINISHED -> STOPPED (when user calls stop() explicitly) + Illegal transitions: + PAUSED -> FINISHED (since all batches are cancelled on pause, there should + not be any that finish normally. paused sequencers + should not be cleaned up because their presence + indicates that the ordering key needs to be resumed) + STOPPED -> ACCEPTING_MESSAGES (no way to make a user-stopped sequencer + accept messages again. this is okay since + stop() should only be called on shutdown.) + FINISHED -> PAUSED (no messages remain in flight, so they can't cause a + permanent error and pause the sequencer) + """ + + # Accepting publishes and/or waiting for result of batch publish + ACCEPTING_MESSAGES = "accepting messages" + # Permanent error occurred. User must unpause this sequencer to resume + # publishing. This is done to maintain ordering. + PAUSED = "paused" + # No more publishes allowed. There may be an outstanding batch that will + # call the _batch_done_callback when it's done (success or error.) + STOPPED = "stopped" + # No more work to do. Waiting to be cleaned-up. A publish will transform + # this sequencer back into the normal accepting-messages state. + FINISHED = "finished" + + +class OrderedSequencer(sequencer_base.Sequencer): + """Sequences messages into batches ordered by an ordering key for one topic. + + A sequencer always has at least one batch in it, unless paused or stopped. + When no batches remain, the |publishes_done_callback| is called so the + client can perform cleanup. + + Public methods are thread-safe. + + Args: + client: + The publisher client used to create this sequencer. + topic: + The topic. The format for this is ``projects/{project}/topics/{topic}``. + ordering_key: + The ordering key for this sequencer. + """ + + def __init__(self, client: "PublisherClient", topic: str, ordering_key: str): + self._client = client + self._topic = topic + self._ordering_key = ordering_key + # Guards the variables below + self._state_lock = threading.Lock() + # Batches ordered from first (head/left) to last (right/tail). + # Invariant: always has at least one batch after the first publish, + # unless paused or stopped. + self._ordered_batches: Deque["_batch.thread.Batch"] = collections.deque() + # See _OrderedSequencerStatus for valid state transitions. + self._state = _OrderedSequencerStatus.ACCEPTING_MESSAGES + + def is_finished(self) -> bool: + """Whether the sequencer is finished and should be cleaned up. + + Returns: + Whether the sequencer is finished and should be cleaned up. + """ + with self._state_lock: + return self._state == _OrderedSequencerStatus.FINISHED + + def stop(self) -> None: + """Permanently stop this sequencer. + + This differs from pausing, which may be resumed. Immediately commits + the first batch and cancels the rest. + + Raises: + RuntimeError: + If called after stop() has already been called. + """ + with self._state_lock: + if self._state == _OrderedSequencerStatus.STOPPED: + raise RuntimeError("Ordered sequencer already stopped.") + + self._state = _OrderedSequencerStatus.STOPPED + if self._ordered_batches: + # Give only the first batch the chance to finish. + self._ordered_batches[0].commit() + + # Cancel the rest of the batches and remove them from the deque + # of batches. + while len(self._ordered_batches) > 1: + # Pops from the tail until it leaves only the head in the + # deque. + batch = self._ordered_batches.pop() + batch.cancel(batch_base.BatchCancellationReason.CLIENT_STOPPED) + + def commit(self) -> None: + """Commit the first batch, if unpaused. + + If paused or no batches exist, this method does nothing. + + Raises: + RuntimeError: + If called after stop() has already been called. + """ + with self._state_lock: + if self._state == _OrderedSequencerStatus.STOPPED: + raise RuntimeError("Ordered sequencer already stopped.") + + if self._state != _OrderedSequencerStatus.PAUSED and self._ordered_batches: + # It's okay to commit the same batch more than once. The + # operation is idempotent. + self._ordered_batches[0].commit() + + def _batch_done_callback(self, success: bool) -> None: + """Deal with completion of a batch. + + Called when a batch has finished publishing, with either a success + or a failure. (Temporary failures are retried infinitely when + ordering keys are enabled.) + """ + ensure_cleanup_and_commit_timer_runs = False + with self._state_lock: + assert self._state != _OrderedSequencerStatus.PAUSED, ( + "This method should not be called after pause() because " + "pause() should have cancelled all of the batches." + ) + assert self._state != _OrderedSequencerStatus.FINISHED, ( + "This method should not be called after all batches have been " + "finished." + ) + + # Message futures for the batch have been completed (either with a + # result or an exception) already, so remove the batch. + self._ordered_batches.popleft() + + if success: + if len(self._ordered_batches) == 0: + # Mark this sequencer as finished. + # If new messages come in for this ordering key and this + # sequencer hasn't been cleaned up yet, it will go back + # into accepting-messages state. Otherwise, the client + # must create a new OrderedSequencer. + self._state = _OrderedSequencerStatus.FINISHED + # Ensure cleanup thread runs at some point. + ensure_cleanup_and_commit_timer_runs = True + elif len(self._ordered_batches) == 1: + # Wait for messages and/or commit timeout + # Ensure there's actually a commit timer thread that'll commit + # after a delay. + ensure_cleanup_and_commit_timer_runs = True + else: + # If there is more than one batch, we know that the next batch + # must be full and, therefore, ready to be committed. + self._ordered_batches[0].commit() + else: + # Unrecoverable error detected + self._pause() + + if ensure_cleanup_and_commit_timer_runs: + self._client.ensure_cleanup_and_commit_timer_runs() + + def _pause(self) -> None: + """Pause this sequencer: set state to paused, cancel all batches, and + clear the list of ordered batches. + + _state_lock must be taken before calling this method. + """ + assert ( + self._state != _OrderedSequencerStatus.FINISHED + ), "Pause should not be called after all batches have finished." + self._state = _OrderedSequencerStatus.PAUSED + for batch in self._ordered_batches: + batch.cancel( + batch_base.BatchCancellationReason.PRIOR_ORDERED_MESSAGE_FAILED + ) + self._ordered_batches.clear() + + def unpause(self) -> None: + """Unpause this sequencer. + + Raises: + RuntimeError: + If called when the ordering key has not been paused. + """ + with self._state_lock: + if self._state != _OrderedSequencerStatus.PAUSED: + raise RuntimeError("Ordering key is not paused.") + self._state = _OrderedSequencerStatus.ACCEPTING_MESSAGES + + def _create_batch( + self, + commit_retry: "OptionalRetry" = gapic_v1.method.DEFAULT, + commit_timeout: "types.OptionalTimeout" = gapic_v1.method.DEFAULT, + ) -> "_batch.thread.Batch": + """Create a new batch using the client's batch class and other stored + settings. + + Args: + commit_retry: + The retry settings to apply when publishing the batch. + commit_timeout: + The timeout to apply when publishing the batch. + """ + return self._client._batch_class( + client=self._client, + topic=self._topic, + settings=self._client.batch_settings, + batch_done_callback=self._batch_done_callback, + commit_when_full=False, + commit_retry=commit_retry, + commit_timeout=commit_timeout, + ) + + def publish( + self, + message: gapic_types.PubsubMessage, + retry: "OptionalRetry" = gapic_v1.method.DEFAULT, + timeout: "types.OptionalTimeout" = gapic_v1.method.DEFAULT, + ) -> futures.Future: + """Publish message for this ordering key. + + Args: + message: + The Pub/Sub message. + retry: + The retry settings to apply when publishing the message. + timeout: + The timeout to apply when publishing the message. + + Returns: + A class instance that conforms to Python Standard library's + :class:`~concurrent.futures.Future` interface (but not an + instance of that class). The future might return immediately with a + PublishToPausedOrderingKeyException if the ordering key is paused. + Otherwise, the future tracks the lifetime of the message publish. + + Raises: + RuntimeError: + If called after this sequencer has been stopped, either by + a call to stop() or after all batches have been published. + """ + with self._state_lock: + if self._state == _OrderedSequencerStatus.PAUSED: + errored_future = futures.Future() + exception = exceptions.PublishToPausedOrderingKeyException( + self._ordering_key + ) + errored_future.set_exception(exception) + return errored_future + + # If waiting to be cleaned-up, convert to accepting messages to + # prevent this sequencer from being cleaned-up only to have another + # one with the same ordering key created immediately afterward. + if self._state == _OrderedSequencerStatus.FINISHED: + self._state = _OrderedSequencerStatus.ACCEPTING_MESSAGES + + if self._state == _OrderedSequencerStatus.STOPPED: + raise RuntimeError("Cannot publish on a stopped sequencer.") + + assert ( + self._state == _OrderedSequencerStatus.ACCEPTING_MESSAGES + ), "Publish is only allowed in accepting-messages state." + + if not self._ordered_batches: + new_batch = self._create_batch( + commit_retry=retry, commit_timeout=timeout + ) + self._ordered_batches.append(new_batch) + + batch = self._ordered_batches[-1] + future = batch.publish(message) + while future is None: + batch = self._create_batch(commit_retry=retry, commit_timeout=timeout) + self._ordered_batches.append(batch) + future = batch.publish(message) + + return future + + # Used only for testing. + def _set_batch(self, batch: "_batch.thread.Batch") -> None: + self._ordered_batches = collections.deque([batch]) + + # Used only for testing. + def _set_batches(self, batches: Iterable["_batch.thread.Batch"]) -> None: + self._ordered_batches = collections.deque(batches) + + # Used only for testing. + def _get_batches(self) -> Sequence["_batch.thread.Batch"]: + return self._ordered_batches diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/_sequencer/unordered_sequencer.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/_sequencer/unordered_sequencer.py new file mode 100644 index 000000000000..7d57aa8218b9 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/_sequencer/unordered_sequencer.py @@ -0,0 +1,165 @@ +# Copyright 2019, Google LLC 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. + +import typing +from typing import Optional + +from google.api_core import gapic_v1 + +from google.cloud.pubsub_v1.publisher._sequencer import base +from google.pubsub_v1 import types as gapic_types + +if typing.TYPE_CHECKING: # pragma: NO COVER + from google.cloud.pubsub_v1.publisher import _batch + from google.cloud.pubsub_v1.publisher import futures + from google.cloud.pubsub_v1.publisher.client import Client as PublisherClient + from google.pubsub_v1.services.publisher.client import OptionalRetry + + from google.cloud.pubsub_v1 import types + + +class UnorderedSequencer(base.Sequencer): + """Sequences messages into batches for one topic without any ordering. + + Public methods are NOT thread-safe. + """ + + def __init__(self, client: "PublisherClient", topic: str): + self._client = client + self._topic = topic + self._current_batch: Optional["_batch.thread.Batch"] = None + self._stopped = False + + def is_finished(self) -> bool: + """Whether the sequencer is finished and should be cleaned up. + + Returns: + Whether the sequencer is finished and should be cleaned up. + """ + # TODO: Implement. Not implementing yet because of possible performance + # impact due to extra locking required. This does mean that + # UnorderedSequencers don't get cleaned up, but this is the same as + # previously existing behavior. + return False + + def stop(self) -> None: + """Stop the sequencer. + + Subsequent publishes will fail. + + Raises: + RuntimeError: + If called after stop() has already been called. + """ + if self._stopped: + raise RuntimeError("Unordered sequencer already stopped.") + self.commit() + self._stopped = True + + def commit(self) -> None: + """Commit the batch. + + Raises: + RuntimeError: + If called after stop() has already been called. + """ + if self._stopped: + raise RuntimeError("Unordered sequencer already stopped.") + if self._current_batch: + self._current_batch.commit() + + # At this point, we lose track of the old batch, but we don't + # care since we just committed it. + # Setting this to None guarantees the next publish() creates a new + # batch. + self._current_batch = None + + def unpause(self) -> typing.NoReturn: + """Not relevant for this class.""" + raise NotImplementedError + + def _create_batch( + self, + commit_retry: "OptionalRetry" = gapic_v1.method.DEFAULT, + commit_timeout: "types.OptionalTimeout" = gapic_v1.method.DEFAULT, + ) -> "_batch.thread.Batch": + """Create a new batch using the client's batch class and other stored + settings. + + Args: + commit_retry: + The retry settings to apply when publishing the batch. + commit_timeout: + The timeout to apply when publishing the batch. + """ + return self._client._batch_class( + client=self._client, + topic=self._topic, + settings=self._client.batch_settings, + batch_done_callback=None, + commit_when_full=True, + commit_retry=commit_retry, + commit_timeout=commit_timeout, + ) + + def publish( + self, + message: gapic_types.PubsubMessage, + retry: "OptionalRetry" = gapic_v1.method.DEFAULT, + timeout: "types.OptionalTimeout" = gapic_v1.method.DEFAULT, + ) -> "futures.Future": + """Batch message into existing or new batch. + + Args: + message: + The Pub/Sub message. + retry: + The retry settings to apply when publishing the message. + timeout: + The timeout to apply when publishing the message. + + Returns: + An object conforming to the :class:`~concurrent.futures.Future` interface. + The future tracks the publishing status of the message. + + Raises: + RuntimeError: + If called after stop() has already been called. + + pubsub_v1.publisher.exceptions.MessageTooLargeError: If publishing + the ``message`` would exceed the max size limit on the backend. + """ + if self._stopped: + raise RuntimeError("Unordered sequencer already stopped.") + + if not self._current_batch: + newbatch = self._create_batch(commit_retry=retry, commit_timeout=timeout) + self._current_batch = newbatch + + batch = self._current_batch + future = None + while future is None: + # Might throw MessageTooLargeError + future = batch.publish(message) + # batch is full, triggering commit_when_full + if future is None: + batch = self._create_batch(commit_retry=retry, commit_timeout=timeout) + # At this point, we lose track of the old batch, but we don't + # care since it's already committed (because it was full.) + self._current_batch = batch + return future + + # Used only for testing. + def _set_batch(self, batch: "_batch.thread.Batch") -> None: + self._current_batch = batch diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/client.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/client.py new file mode 100644 index 000000000000..e3266e57f854 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/client.py @@ -0,0 +1,519 @@ +# Copyright 2019, Google LLC 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. + +from __future__ import absolute_import + +import copy +import logging +import os +import pkg_resources +import threading +import time +import typing +from typing import Any, Dict, Optional, Sequence, Tuple, Type, Union +import warnings + +from google.api_core import gapic_v1 +from google.auth.credentials import AnonymousCredentials # type: ignore +from google.oauth2 import service_account # type: ignore + +from google.cloud.pubsub_v1 import types +from google.cloud.pubsub_v1.publisher import exceptions +from google.cloud.pubsub_v1.publisher import futures +from google.cloud.pubsub_v1.publisher._batch import thread +from google.cloud.pubsub_v1.publisher._sequencer import ordered_sequencer +from google.cloud.pubsub_v1.publisher._sequencer import unordered_sequencer +from google.cloud.pubsub_v1.publisher.flow_controller import FlowController +from google.pubsub_v1 import types as gapic_types +from google.pubsub_v1.services.publisher import client as publisher_client + +try: + __version__ = pkg_resources.get_distribution("google-cloud-pubsub").version +except pkg_resources.DistributionNotFound: + # Distribution might not be available if we are not running from within a + # PIP package. + __version__ = "0.0" + +if typing.TYPE_CHECKING: # pragma: NO COVER + from google.cloud import pubsub_v1 + from google.cloud.pubsub_v1.publisher import _batch + from google.pubsub_v1.services.publisher.client import OptionalRetry + from google.pubsub_v1.types import pubsub as pubsub_types + + +_LOGGER = logging.getLogger(__name__) + + +_raw_proto_pubbsub_message = gapic_types.PubsubMessage.pb() + +SequencerType = Union[ + ordered_sequencer.OrderedSequencer, unordered_sequencer.UnorderedSequencer +] + + +class Client(publisher_client.PublisherClient): + """A publisher client for Google Cloud Pub/Sub. + + This creates an object that is capable of publishing messages. + Generally, you can instantiate this client with no arguments, and you + get sensible defaults. + + Args: + batch_settings: + The settings for batch publishing. + publisher_options: + The options for the publisher client. Note that enabling message ordering + will override the publish retry timeout to be infinite. + kwargs: + Any additional arguments provided are sent as keyword arguments to the + underlying + :class:`~google.cloud.pubsub_v1.gapic.publisher_client.PublisherClient`. + Generally you should not need to set additional keyword + arguments. Regional endpoints can be set via ``client_options`` that + takes a single key-value pair that defines the endpoint. + + Example: + + .. code-block:: python + + from google.cloud import pubsub_v1 + + publisher_client = pubsub_v1.PublisherClient( + # Optional + batch_settings = pubsub_v1.types.BatchSettings( + max_bytes=1024, # One kilobyte + max_latency=1, # One second + ), + + # Optional + publisher_options = pubsub_v1.types.PublisherOptions( + enable_message_ordering=False, + flow_control=pubsub_v1.types.PublishFlowControl( + message_limit=2000, + limit_exceeded_behavior=pubsub_v1.types.LimitExceededBehavior.BLOCK, + ), + ), + + # Optional + client_options = { + "api_endpoint": REGIONAL_ENDPOINT + } + ) + """ + + def __init__( + self, + batch_settings: Union[types.BatchSettings, Sequence] = (), + publisher_options: Union[types.PublisherOptions, Sequence] = (), + **kwargs: Any, + ): + assert ( + type(batch_settings) is types.BatchSettings or len(batch_settings) == 0 + ), "batch_settings must be of type BatchSettings or an empty sequence." + assert ( + type(publisher_options) is types.PublisherOptions + or len(publisher_options) == 0 + ), "publisher_options must be of type PublisherOptions or an empty sequence." + + # Sanity check: Is our goal to use the emulator? + # If so, create a grpc insecure channel with the emulator host + # as the target. + if os.environ.get("PUBSUB_EMULATOR_HOST"): + kwargs["client_options"] = { + "api_endpoint": os.environ.get("PUBSUB_EMULATOR_HOST") + } + kwargs["credentials"] = AnonymousCredentials() + + # For a transient failure, retry publishing the message infinitely. + self.publisher_options = types.PublisherOptions(*publisher_options) + self._enable_message_ordering = self.publisher_options[0] + + # Add the metrics headers, and instantiate the underlying GAPIC + # client. + super().__init__(**kwargs) + self._target = self._transport._host + self._batch_class = thread.Batch + self.batch_settings = types.BatchSettings(*batch_settings) + + # The batches on the publisher client are responsible for holding + # messages. One batch exists for each topic. + self._batch_lock = self._batch_class.make_lock() + # (topic, ordering_key) => sequencers object + self._sequencers: Dict[Tuple[str, str], SequencerType] = {} + self._is_stopped = False + # Thread created to commit all sequencers after a timeout. + self._commit_thread: Optional[threading.Thread] = None + + # The object controlling the message publishing flow + self._flow_controller = FlowController(self.publisher_options.flow_control) + + @classmethod + def from_service_account_file( # type: ignore[override] + cls, + filename: str, + batch_settings: Union[types.BatchSettings, Sequence] = (), + **kwargs: Any, + ) -> "Client": + """Creates an instance of this client using the provided credentials + file. + + Args: + filename: + The path to the service account private key JSON file. + batch_settings: + The settings for batch publishing. + kwargs: + Additional arguments to pass to the constructor. + + Returns: + A Publisher instance that is the constructed client. + """ + credentials = service_account.Credentials.from_service_account_file(filename) + kwargs["credentials"] = credentials + return cls(batch_settings, **kwargs) + + from_service_account_json = from_service_account_file # type: ignore[assignment] + + @property + def target(self) -> str: + """Return the target (where the API is). + + Returns: + The location of the API. + """ + return self._target + + @property + def api(self): + """The underlying gapic API client. + + .. versionchanged:: 2.10.0 + Instead of a GAPIC ``PublisherClient`` client instance, this property is a + proxy object to it with the same interface. + + .. deprecated:: 2.10.0 + Use the GAPIC methods and properties on the client instance directly + instead of through the :attr:`api` attribute. + """ + msg = ( + 'The "api" property only exists for backward compatibility, access its ' + 'attributes directly thorugh the client instance (e.g. "client.foo" ' + 'instead of "client.api.foo").' + ) + warnings.warn(msg, category=DeprecationWarning) + return super() + + def _get_or_create_sequencer(self, topic: str, ordering_key: str) -> SequencerType: + """Get an existing sequencer or create a new one given the (topic, + ordering_key) pair. + """ + sequencer_key = (topic, ordering_key) + sequencer = self._sequencers.get(sequencer_key) + if sequencer is None: + if ordering_key == "": + sequencer = unordered_sequencer.UnorderedSequencer(self, topic) + else: + sequencer = ordered_sequencer.OrderedSequencer( + self, topic, ordering_key + ) + self._sequencers[sequencer_key] = sequencer + + return sequencer + + def resume_publish(self, topic: str, ordering_key: str) -> None: + """Resume publish on an ordering key that has had unrecoverable errors. + + Args: + topic: The topic to publish messages to. + ordering_key: A string that identifies related messages for which + publish order should be respected. + + Raises: + RuntimeError: + If called after publisher has been stopped by a `stop()` method + call. + ValueError: + If the topic/ordering key combination has not been seen before + by this client. + """ + with self._batch_lock: + if self._is_stopped: + raise RuntimeError("Cannot resume publish on a stopped publisher.") + + if not self._enable_message_ordering: + raise ValueError( + "Cannot resume publish on a topic/ordering key if ordering " + "is not enabled." + ) + + sequencer_key = (topic, ordering_key) + sequencer = self._sequencers.get(sequencer_key) + if sequencer is None: + _LOGGER.debug( + "Error: The topic/ordering key combination has not " + "been seen before." + ) + else: + sequencer.unpause() + + def _gapic_publish(self, *args, **kwargs) -> "pubsub_types.PublishResponse": + """Call the GAPIC public API directly.""" + return super().publish(*args, **kwargs) + + def publish( # type: ignore[override] + self, + topic: str, + data: bytes, + ordering_key: str = "", + retry: "OptionalRetry" = gapic_v1.method.DEFAULT, + timeout: "types.OptionalTimeout" = gapic_v1.method.DEFAULT, + **attrs: Union[bytes, str], + ) -> "pubsub_v1.publisher.futures.Future": + """Publish a single message. + + .. note:: + Messages in Pub/Sub are blobs of bytes. They are *binary* data, + not text. You must send data as a bytestring + (``bytes`` in Python 3; ``str`` in Python 2), and this library + will raise an exception if you send a text string. + + The reason that this is so important (and why we do not try to + coerce for you) is because Pub/Sub is also platform independent + and there is no way to know how to decode messages properly on + the other side; therefore, encoding and decoding is a required + exercise for the developer. + + Add the given message to this object; this will cause it to be + published once the batch either has enough messages or a sufficient + period of time has elapsed. + This method may block if LimitExceededBehavior.BLOCK is used in the + flow control settings. + + Example: + >>> from google.cloud import pubsub_v1 + >>> client = pubsub_v1.PublisherClient() + >>> topic = client.topic_path('[PROJECT]', '[TOPIC]') + >>> data = b'The rain in Wales falls mainly on the snails.' + >>> response = client.publish(topic, data, username='guido') + + Args: + topic: The topic to publish messages to. + data: A bytestring representing the message body. This + must be a bytestring. + ordering_key: A string that identifies related messages for which + publish order should be respected. Message ordering must be + enabled for this client to use this feature. + retry: + Designation of what errors, if any, should be retried. If `ordering_key` + is specified, the total retry deadline will be changed to "infinity". + If given, it overides any retry passed into the client through + the ``publisher_options`` argument. + timeout: + The timeout for the RPC request. Can be used to override any timeout + passed in through ``publisher_options`` when instantiating the client. + + attrs: A dictionary of attributes to be + sent as metadata. (These may be text strings or byte strings.) + + Returns: + A :class:`~google.cloud.pubsub_v1.publisher.futures.Future` + instance that conforms to Python Standard library's + :class:`~concurrent.futures.Future` interface (but not an + instance of that class). + + Raises: + RuntimeError: + If called after publisher has been stopped by a `stop()` method + call. + + pubsub_v1.publisher.exceptions.MessageTooLargeError: If publishing + the ``message`` would exceed the max size limit on the backend. + """ + # Sanity check: Is the data being sent as a bytestring? + # If it is literally anything else, complain loudly about it. + if not isinstance(data, bytes): + raise TypeError( + "Data being published to Pub/Sub must be sent as a bytestring." + ) + + if not self._enable_message_ordering and ordering_key != "": + raise ValueError( + "Cannot publish a message with an ordering key when message " + "ordering is not enabled." + ) + + # Coerce all attributes to text strings. + for k, v in copy.copy(attrs).items(): + if isinstance(v, str): + continue + if isinstance(v, bytes): + attrs[k] = v.decode("utf-8") + continue + raise TypeError( + "All attributes being published to Pub/Sub must " + "be sent as text strings." + ) + + # Create the Pub/Sub message object. For performance reasons, the message + # should be constructed by directly using the raw protobuf class, and only + # then wrapping it into the higher-level PubsubMessage class. + vanilla_pb = _raw_proto_pubbsub_message( + data=data, ordering_key=ordering_key, attributes=attrs + ) + message = gapic_types.PubsubMessage.wrap(vanilla_pb) + + # Messages should go through flow control to prevent excessive + # queuing on the client side (depending on the settings). + try: + self._flow_controller.add(message) + except exceptions.FlowControlLimitError as exc: + future = futures.Future() + future.set_exception(exc) + return future + + def on_publish_done(future): + self._flow_controller.release(message) + + if retry is gapic_v1.method.DEFAULT: # if custom retry not passed in + retry = self.publisher_options.retry + + if timeout is gapic_v1.method.DEFAULT: # if custom timeout not passed in + timeout = self.publisher_options.timeout + + with self._batch_lock: + if self._is_stopped: + raise RuntimeError("Cannot publish on a stopped publisher.") + + # Set retry timeout to "infinite" when message ordering is enabled. + # Note that this then also impacts messages added with an empty + # ordering key. + if self._enable_message_ordering: + if retry is gapic_v1.method.DEFAULT: + # use the default retry for the publish GRPC method as a base + transport = self._transport + base_retry = transport._wrapped_methods[transport.publish]._retry + retry = base_retry.with_deadline(2.0**32) + else: + retry = retry.with_deadline(2.0**32) + + # Delegate the publishing to the sequencer. + sequencer = self._get_or_create_sequencer(topic, ordering_key) + future = sequencer.publish(message, retry=retry, timeout=timeout) + future.add_done_callback(on_publish_done) + + # Create a timer thread if necessary to enforce the batching + # timeout. + self._ensure_commit_timer_runs_no_lock() + + return future + + def ensure_cleanup_and_commit_timer_runs(self) -> None: + """Ensure a cleanup/commit timer thread is running. + + If a cleanup/commit timer thread is already running, this does nothing. + """ + with self._batch_lock: + self._ensure_commit_timer_runs_no_lock() + + def _ensure_commit_timer_runs_no_lock(self) -> None: + """Ensure a commit timer thread is running, without taking + _batch_lock. + + _batch_lock must be held before calling this method. + """ + if not self._commit_thread and self.batch_settings.max_latency < float("inf"): + self._start_commit_thread() + + def _start_commit_thread(self) -> None: + """Start a new thread to actually wait and commit the sequencers.""" + # NOTE: If the thread is *not* a daemon, a memory leak exists due to a CPython issue. + # https://github.com/googleapis/python-pubsub/issues/395#issuecomment-829910303 + # https://github.com/googleapis/python-pubsub/issues/395#issuecomment-830092418 + self._commit_thread = threading.Thread( + name="Thread-PubSubBatchCommitter", + target=self._wait_and_commit_sequencers, + daemon=True, + ) + self._commit_thread.start() + + def _wait_and_commit_sequencers(self) -> None: + """Wait up to the batching timeout, and commit all sequencers.""" + # Sleep for however long we should be waiting. + time.sleep(self.batch_settings.max_latency) + _LOGGER.debug("Commit thread is waking up") + + with self._batch_lock: + if self._is_stopped: + return + self._commit_sequencers() + self._commit_thread = None + + def _commit_sequencers(self) -> None: + """Clean up finished sequencers and commit the rest.""" + finished_sequencer_keys = [ + key + for key, sequencer in self._sequencers.items() + if sequencer.is_finished() + ] + for sequencer_key in finished_sequencer_keys: + del self._sequencers[sequencer_key] + + for sequencer in self._sequencers.values(): + sequencer.commit() + + def stop(self) -> None: + """Immediately publish all outstanding messages. + + Asynchronously sends all outstanding messages and + prevents future calls to `publish()`. Method should + be invoked prior to deleting this `Client()` object + in order to ensure that no pending messages are lost. + + .. note:: + + This method is non-blocking. Use `Future()` objects + returned by `publish()` to make sure all publish + requests completed, either in success or error. + + Raises: + RuntimeError: + If called after publisher has been stopped by a `stop()` method + call. + """ + with self._batch_lock: + if self._is_stopped: + raise RuntimeError("Cannot stop a publisher already stopped.") + + self._is_stopped = True + + for sequencer in self._sequencers.values(): + sequencer.stop() + + # Used only for testing. + def _set_batch( + self, topic: str, batch: "_batch.thread.Batch", ordering_key: str = "" + ) -> None: + sequencer = self._get_or_create_sequencer(topic, ordering_key) + sequencer._set_batch(batch) + + # Used only for testing. + def _set_batch_class(self, batch_class: Type) -> None: + self._batch_class = batch_class + + # Used only for testing. + def _set_sequencer( + self, topic: str, sequencer: SequencerType, ordering_key: str = "" + ) -> None: + sequencer_key = (topic, ordering_key) + self._sequencers[sequencer_key] = sequencer diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/exceptions.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/exceptions.py new file mode 100644 index 000000000000..f2b65299e1f2 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/exceptions.py @@ -0,0 +1,51 @@ +# Copyright 2017, Google LLC 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. + +from __future__ import absolute_import + +from google.api_core.exceptions import GoogleAPICallError +from google.cloud.pubsub_v1.exceptions import TimeoutError + + +class PublishError(GoogleAPICallError): + pass + + +class MessageTooLargeError(ValueError): + """Attempt to publish a message that would exceed the server max size limit.""" + + +class PublishToPausedOrderingKeyException(Exception): + """Publish attempted to paused ordering key. To resume publishing, call + the resumePublish method on the publisher Client object with this + ordering key. Ordering keys are paused if an unrecoverable error + occurred during publish of a batch for that key. + """ + + def __init__(self, ordering_key: str): + self.ordering_key = ordering_key + super(PublishToPausedOrderingKeyException, self).__init__() + + +class FlowControlLimitError(Exception): + """An action resulted in exceeding the flow control limits.""" + + +__all__ = ( + "FlowControlLimitError", + "MessageTooLargeError", + "PublishError", + "TimeoutError", + "PublishToPausedOrderingKeyException", +) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/flow_controller.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/flow_controller.py new file mode 100644 index 000000000000..baf6ba8ff838 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/flow_controller.py @@ -0,0 +1,313 @@ +# Copyright 2020, Google LLC 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. + +from collections import OrderedDict +import logging +import threading +from typing import Dict, Optional, Type +import warnings + +from google.cloud.pubsub_v1 import types +from google.cloud.pubsub_v1.publisher import exceptions + + +_LOGGER = logging.getLogger(__name__) + + +MessageType = Type[types.PubsubMessage] # type: ignore + + +class _QuantityReservation: + """A (partial) reservation of quantifiable resources.""" + + def __init__(self, bytes_reserved: int, bytes_needed: int, has_slot: bool): + self.bytes_reserved = bytes_reserved + self.bytes_needed = bytes_needed + self.has_slot = has_slot + + def __repr__(self): + return ( + f"{type(self).__name__}(" + f"bytes_reserved={self.bytes_reserved}, " + f"bytes_needed={self.bytes_needed}, " + f"has_slot={self.has_slot})" + ) + + +class FlowController(object): + """A class used to control the flow of messages passing through it. + + Args: + settings: Desired flow control configuration. + """ + + def __init__(self, settings: types.PublishFlowControl): + self._settings = settings + + # Load statistics. They represent the number of messages added, but not + # yet released (and their total size). + self._message_count = 0 + self._total_bytes = 0 + + # A FIFO queue of threads blocked on adding a message that also tracks their + # reservations of available flow control bytes and message slots. + # Only relevant if the configured limit exceeded behavior is BLOCK. + self._waiting: Dict[threading.Thread, _QuantityReservation] = OrderedDict() + + self._reserved_bytes = 0 + self._reserved_slots = 0 + + # The lock is used to protect all internal state (message and byte count, + # waiting threads to add, etc.). + self._operational_lock = threading.Lock() + + # The condition for blocking the flow if capacity is exceeded. + self._has_capacity = threading.Condition(lock=self._operational_lock) + + def add(self, message: MessageType) -> None: + """Add a message to flow control. + + Adding a message updates the internal load statistics, and an action is + taken if these limits are exceeded (depending on the flow control settings). + + Args: + message: + The message entering the flow control. + + Raises: + :exception:`~pubsub_v1.publisher.exceptions.FlowControlLimitError`: + Raised when the desired action is + :attr:`~google.cloud.pubsub_v1.types.LimitExceededBehavior.ERROR` and + the message would exceed flow control limits, or when the desired action + is :attr:`~google.cloud.pubsub_v1.types.LimitExceededBehavior.BLOCK` and + the message would block forever against the flow control limits. + """ + if self._settings.limit_exceeded_behavior == types.LimitExceededBehavior.IGNORE: + return + + with self._operational_lock: + if not self._would_overflow(message): + self._message_count += 1 + self._total_bytes += message._pb.ByteSize() + return + + # Adding a message would overflow, react. + if ( + self._settings.limit_exceeded_behavior + == types.LimitExceededBehavior.ERROR + ): + # Raising an error means rejecting a message, thus we do not + # add anything to the existing load, but we do report the would-be + # load if we accepted the message. + load_info = self._load_info( + message_count=self._message_count + 1, + total_bytes=self._total_bytes + message._pb.ByteSize(), + ) + error_msg = "Flow control limits would be exceeded - {}.".format( + load_info + ) + raise exceptions.FlowControlLimitError(error_msg) + + assert ( + self._settings.limit_exceeded_behavior + == types.LimitExceededBehavior.BLOCK + ) + + # Sanity check - if a message exceeds total flow control limits all + # by itself, it would block forever, thus raise error. + if ( + message._pb.ByteSize() > self._settings.byte_limit + or self._settings.message_limit < 1 + ): + load_info = self._load_info( + message_count=1, total_bytes=message._pb.ByteSize() + ) + error_msg = ( + "Total flow control limits too low for the message, " + "would block forever - {}.".format(load_info) + ) + raise exceptions.FlowControlLimitError(error_msg) + + current_thread = threading.current_thread() + + while self._would_overflow(message): + if current_thread not in self._waiting: + reservation = _QuantityReservation( + bytes_reserved=0, + bytes_needed=message._pb.ByteSize(), + has_slot=False, + ) + self._waiting[current_thread] = reservation # Will be placed last. + + _LOGGER.debug( + "Blocking until there is enough free capacity in the flow - " + "{}.".format(self._load_info()) + ) + + self._has_capacity.wait() + + _LOGGER.debug( + "Woke up from waiting on free capacity in the flow - " + "{}.".format(self._load_info()) + ) + + # Message accepted, increase the load and remove thread stats. + self._message_count += 1 + self._total_bytes += message._pb.ByteSize() + self._reserved_bytes -= self._waiting[current_thread].bytes_reserved + self._reserved_slots -= 1 + del self._waiting[current_thread] + + def release(self, message: MessageType) -> None: + """Release a mesage from flow control. + + Args: + message: + The message entering the flow control. + """ + if self._settings.limit_exceeded_behavior == types.LimitExceededBehavior.IGNORE: + return + + with self._operational_lock: + # Releasing a message decreases the load. + self._message_count -= 1 + self._total_bytes -= message._pb.ByteSize() + + if self._message_count < 0 or self._total_bytes < 0: + warnings.warn( + "Releasing a message that was never added or already released.", + category=RuntimeWarning, + stacklevel=2, + ) + self._message_count = max(0, self._message_count) + self._total_bytes = max(0, self._total_bytes) + + self._distribute_available_capacity() + + # If at least one thread waiting to add() can be unblocked, wake them up. + if self._ready_to_unblock(): + _LOGGER.debug("Notifying threads waiting to add messages to flow.") + self._has_capacity.notify_all() + + def _distribute_available_capacity(self) -> None: + """Distribute available capacity among the waiting threads in FIFO order. + + The method assumes that the caller has obtained ``_operational_lock``. + """ + available_slots = ( + self._settings.message_limit - self._message_count - self._reserved_slots + ) + available_bytes = ( + self._settings.byte_limit - self._total_bytes - self._reserved_bytes + ) + + for reservation in self._waiting.values(): + if available_slots <= 0 and available_bytes <= 0: + break # Santa is now empty-handed, better luck next time. + + # Distribute any free slots. + if available_slots > 0 and not reservation.has_slot: + reservation.has_slot = True + self._reserved_slots += 1 + available_slots -= 1 + + # Distribute any free bytes. + if available_bytes <= 0: + continue + + bytes_still_needed = reservation.bytes_needed - reservation.bytes_reserved + + if bytes_still_needed < 0: # Sanity check for any internal inconsistencies. + msg = "Too many bytes reserved: {} / {}".format( + reservation.bytes_reserved, reservation.bytes_needed + ) + warnings.warn(msg, category=RuntimeWarning) + bytes_still_needed = 0 + + can_give = min(bytes_still_needed, available_bytes) + reservation.bytes_reserved += can_give + self._reserved_bytes += can_give + available_bytes -= can_give + + def _ready_to_unblock(self) -> bool: + """Determine if any of the threads waiting to add a message can proceed. + + The method assumes that the caller has obtained ``_operational_lock``. + """ + if self._waiting: + # It's enough to only check the head of the queue, because FIFO + # distribution of any free capacity. + first_reservation = next(iter(self._waiting.values())) + return ( + first_reservation.bytes_reserved >= first_reservation.bytes_needed + and first_reservation.has_slot + ) + + return False + + def _would_overflow(self, message: MessageType) -> bool: + """Determine if accepting a message would exceed flow control limits. + + The method assumes that the caller has obtained ``_operational_lock``. + + Args: + message: The message entering the flow control. + """ + reservation = self._waiting.get(threading.current_thread()) + + if reservation: + enough_reserved = reservation.bytes_reserved >= reservation.bytes_needed + has_slot = reservation.has_slot + else: + enough_reserved = False + has_slot = False + + bytes_taken = self._total_bytes + self._reserved_bytes + message._pb.ByteSize() + size_overflow = bytes_taken > self._settings.byte_limit and not enough_reserved + + msg_count_overflow = not has_slot and ( + (self._message_count + self._reserved_slots + 1) + > self._settings.message_limit + ) + + return size_overflow or msg_count_overflow + + def _load_info( + self, message_count: Optional[int] = None, total_bytes: Optional[int] = None + ) -> str: + """Return the current flow control load information. + + The caller can optionally adjust some of the values to fit its reporting + needs. + + The method assumes that the caller has obtained ``_operational_lock``. + + Args: + message_count: + The value to override the current message count with. + total_bytes: + The value to override the current total bytes with. + """ + if message_count is None: + message_count = self._message_count + + if total_bytes is None: + total_bytes = self._total_bytes + + return ( + f"messages: {message_count} / {self._settings.message_limit} " + f"(reserved: {self._reserved_slots}), " + f"bytes: {total_bytes} / {self._settings.byte_limit} " + f"(reserved: {self._reserved_bytes})" + ) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/futures.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/futures.py new file mode 100644 index 000000000000..c7cc66f18d2c --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/futures.py @@ -0,0 +1,83 @@ +# Copyright 2019, Google LLC 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. + +from __future__ import absolute_import + +import typing +from typing import Any, Callable, Union + +from google.cloud.pubsub_v1 import futures + +if typing.TYPE_CHECKING: # pragma: NO COVER + from google.cloud import pubsub_v1 + + +class Future(futures.Future): + """This future object is returned from asychronous Pub/Sub publishing + calls. + + Calling :meth:`result` will resolve the future by returning the message + ID, unless an error occurs. + """ + + def cancel(self) -> bool: + """Actions in Pub/Sub generally may not be canceled. + + This method always returns ``False``. + """ + return False + + def cancelled(self) -> bool: + """Actions in Pub/Sub generally may not be canceled. + + This method always returns ``False``. + """ + return False + + def result(self, timeout: Union[int, float] = None) -> str: + """Return the message ID or raise an exception. + + This blocks until the message has been published successfully and + returns the message ID unless an exception is raised. + + Args: + timeout: The number of seconds before this call + times out and raises TimeoutError. + + Returns: + The message ID. + + Raises: + concurrent.futures.TimeoutError: If the request times out. + Exception: For undefined exceptions in the underlying + call execution. + """ + return super().result(timeout=timeout) + + # This exists to make the type checkers happy. + def add_done_callback( + self, callback: Callable[["pubsub_v1.publisher.futures.Future"], Any] + ) -> None: + """Attach a callable that will be called when the future finishes. + + Args: + callback: + A callable that will be called with this future as its only + argument when the future completes or is cancelled. The callable + will always be called by a thread in the same process in which + it was added. If the future has already completed or been + cancelled then the callable will be called immediately. These + callables are called in the order that they were added. + """ + return super().add_done_callback(callback) # type: ignore diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/__init__.py new file mode 100644 index 000000000000..a444c3ea7571 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/__init__.py @@ -0,0 +1,20 @@ +# Copyright 2017, Google LLC 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. + +from __future__ import absolute_import + +from google.cloud.pubsub_v1.subscriber.client import Client + + +__all__ = ("Client",) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/_protocol/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/_protocol/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/_protocol/dispatcher.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/_protocol/dispatcher.py new file mode 100644 index 000000000000..ed2f5d21777a --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/_protocol/dispatcher.py @@ -0,0 +1,406 @@ +# Copyright 2017, Google LLC +# +# 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 +# +# https://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. + +from __future__ import absolute_import +from __future__ import division + +import functools +import itertools +import logging +import math +import time +import threading +import typing +from typing import List, Optional, Sequence, Union +import warnings +from google.api_core.retry import exponential_sleep_generator + +from google.cloud.pubsub_v1.subscriber._protocol import helper_threads +from google.cloud.pubsub_v1.subscriber._protocol import requests +from google.cloud.pubsub_v1.subscriber.exceptions import ( + AcknowledgeStatus, +) + +if typing.TYPE_CHECKING: # pragma: NO COVER + import queue + from google.cloud.pubsub_v1.subscriber._protocol.streaming_pull_manager import ( + StreamingPullManager, + ) + + +RequestItem = Union[ + requests.AckRequest, + requests.DropRequest, + requests.LeaseRequest, + requests.ModAckRequest, + requests.NackRequest, +] + + +_LOGGER = logging.getLogger(__name__) +_CALLBACK_WORKER_NAME = "Thread-CallbackRequestDispatcher" + + +_MAX_BATCH_SIZE = 100 +"""The maximum number of requests to process and dispatch at a time.""" + +_MAX_BATCH_LATENCY = 0.01 +"""The maximum amount of time in seconds to wait for additional request items +before processing the next batch of requests.""" + +_ACK_IDS_BATCH_SIZE = 1000 +"""The maximum number of ACK IDs to send in a single StreamingPullRequest. +""" + +_MIN_EXACTLY_ONCE_DELIVERY_ACK_MODACK_RETRY_DURATION_SECS = 1 +"""The time to wait for the first retry of failed acks and modacks when exactly-once +delivery is enabled.""" + +_MAX_EXACTLY_ONCE_DELIVERY_ACK_MODACK_RETRY_DURATION_SECS = 10 * 60 +"""The maximum amount of time in seconds to retry failed acks and modacks when +exactly-once delivery is enabled.""" + + +class Dispatcher(object): + def __init__(self, manager: "StreamingPullManager", queue: "queue.Queue"): + self._manager = manager + self._queue = queue + self._thread: Optional[threading.Thread] = None + self._operational_lock = threading.Lock() + + def start(self) -> None: + """Start a thread to dispatch requests queued up by callbacks. + + Spawns a thread to run :meth:`dispatch_callback`. + """ + with self._operational_lock: + if self._thread is not None: + raise ValueError("Dispatcher is already running.") + + worker = helper_threads.QueueCallbackWorker( + self._queue, + self.dispatch_callback, + max_items=_MAX_BATCH_SIZE, + max_latency=_MAX_BATCH_LATENCY, + ) + # Create and start the helper thread. + thread = threading.Thread(name=_CALLBACK_WORKER_NAME, target=worker) + thread.daemon = True + thread.start() + _LOGGER.debug("Started helper thread %s", thread.name) + self._thread = thread + + def stop(self) -> None: + with self._operational_lock: + if self._thread is not None: + # Signal the worker to stop by queueing a "poison pill" + self._queue.put(helper_threads.STOP) + self._thread.join() + + self._thread = None + + def dispatch_callback(self, items: Sequence[RequestItem]) -> None: + """Map the callback request to the appropriate gRPC request. + + Args: + items: + Queued requests to dispatch. + """ + lease_requests: List[requests.LeaseRequest] = [] + modack_requests: List[requests.ModAckRequest] = [] + ack_requests: List[requests.AckRequest] = [] + nack_requests: List[requests.NackRequest] = [] + drop_requests: List[requests.DropRequest] = [] + + lease_ids = set() + modack_ids = set() + ack_ids = set() + nack_ids = set() + drop_ids = set() + exactly_once_delivery_enabled = self._manager._exactly_once_delivery_enabled() + + for item in items: + if isinstance(item, requests.LeaseRequest): + if ( + item.ack_id not in lease_ids + ): # LeaseRequests have no futures to handle. + lease_ids.add(item.ack_id) + lease_requests.append(item) + elif isinstance(item, requests.ModAckRequest): + if item.ack_id in modack_ids: + self._handle_duplicate_request_future( + exactly_once_delivery_enabled, item + ) + else: + modack_ids.add(item.ack_id) + modack_requests.append(item) + elif isinstance(item, requests.AckRequest): + if item.ack_id in ack_ids: + self._handle_duplicate_request_future( + exactly_once_delivery_enabled, item + ) + else: + ack_ids.add(item.ack_id) + ack_requests.append(item) + elif isinstance(item, requests.NackRequest): + if item.ack_id in nack_ids: + self._handle_duplicate_request_future( + exactly_once_delivery_enabled, item + ) + else: + nack_ids.add(item.ack_id) + nack_requests.append(item) + elif isinstance(item, requests.DropRequest): + if ( + item.ack_id not in drop_ids + ): # DropRequests have no futures to handle. + drop_ids.add(item.ack_id) + drop_requests.append(item) + else: + warnings.warn( + f'Skipping unknown request item of type "{type(item)}"', + category=RuntimeWarning, + ) + + _LOGGER.debug("Handling %d batched requests", len(items)) + + if lease_requests: + self.lease(lease_requests) + + if modack_requests: + self.modify_ack_deadline(modack_requests) + + # Note: Drop and ack *must* be after lease. It's possible to get both + # the lease and the ack/drop request in the same batch. + if ack_requests: + self.ack(ack_requests) + + if nack_requests: + self.nack(nack_requests) + + if drop_requests: + self.drop(drop_requests) + + def _handle_duplicate_request_future( + self, + exactly_once_delivery_enabled: bool, + item: Union[requests.AckRequest, requests.ModAckRequest, requests.NackRequest], + ) -> None: + _LOGGER.debug( + "This is a duplicate %s with the same ack_id: %s.", + type(item), + item.ack_id, + ) + if item.future: + if exactly_once_delivery_enabled: + item.future.set_exception( + ValueError(f"Duplicate ack_id for {type(item)}") + ) + # Futures may be present even with exactly-once delivery + # disabled, in transition periods after the setting is changed on + # the subscription. + else: + # When exactly-once delivery is NOT enabled, acks/modacks are considered + # best-effort, so the future should succeed even though this is a duplicate. + item.future.set_result(AcknowledgeStatus.SUCCESS) + + def ack(self, items: Sequence[requests.AckRequest]) -> None: + """Acknowledge the given messages. + + Args: + items: The items to acknowledge. + """ + # If we got timing information, add it to the histogram. + for item in items: + time_to_ack = item.time_to_ack + if time_to_ack is not None: + self._manager.ack_histogram.add(time_to_ack) + + # We must potentially split the request into multiple smaller requests + # to avoid the server-side max request size limit. + items_gen = iter(items) + ack_ids_gen = (item.ack_id for item in items) + total_chunks = int(math.ceil(len(items) / _ACK_IDS_BATCH_SIZE)) + + for _ in range(total_chunks): + ack_reqs_dict = { + req.ack_id: req + for req in itertools.islice(items_gen, _ACK_IDS_BATCH_SIZE) + } + requests_completed, requests_to_retry = self._manager.send_unary_ack( + ack_ids=list(itertools.islice(ack_ids_gen, _ACK_IDS_BATCH_SIZE)), + ack_reqs_dict=ack_reqs_dict, + ) + + # Remove the completed messages from lease management. + self.drop(requests_completed) + + # Retry on a separate thread so the dispatcher thread isn't blocked + # by sleeps. + if requests_to_retry: + self._start_retry_thread( + "Thread-RetryAcks", + functools.partial(self._retry_acks, requests_to_retry), + ) + + def _start_retry_thread(self, thread_name, thread_target): + # note: if the thread is *not* a daemon, a memory leak exists due to a cpython issue. + # https://github.com/googleapis/python-pubsub/issues/395#issuecomment-829910303 + # https://github.com/googleapis/python-pubsub/issues/395#issuecomment-830092418 + retry_thread = threading.Thread( + name=thread_name, + target=thread_target, + daemon=True, + ) + # The thread finishes when the requests succeed or eventually fail with + # a back-end timeout error or other permanent failure. + retry_thread.start() + + def _retry_acks(self, requests_to_retry): + retry_delay_gen = exponential_sleep_generator( + initial=_MIN_EXACTLY_ONCE_DELIVERY_ACK_MODACK_RETRY_DURATION_SECS, + maximum=_MAX_EXACTLY_ONCE_DELIVERY_ACK_MODACK_RETRY_DURATION_SECS, + ) + while requests_to_retry: + time_to_wait = next(retry_delay_gen) + _LOGGER.debug( + "Retrying {len(requests_to_retry)} ack(s) after delay of " + + str(time_to_wait) + + " seconds" + ) + time.sleep(time_to_wait) + + ack_reqs_dict = {req.ack_id: req for req in requests_to_retry} + requests_completed, requests_to_retry = self._manager.send_unary_ack( + ack_ids=[req.ack_id for req in requests_to_retry], + ack_reqs_dict=ack_reqs_dict, + ) + assert ( + len(requests_to_retry) <= _ACK_IDS_BATCH_SIZE + ), "Too many requests to be retried." + # Remove the completed messages from lease management. + self.drop(requests_completed) + + def drop( + self, + items: Sequence[ + Union[requests.AckRequest, requests.DropRequest, requests.NackRequest] + ], + ) -> None: + """Remove the given messages from lease management. + + Args: + items: The items to drop. + """ + assert self._manager.leaser is not None + self._manager.leaser.remove(items) + ordering_keys = (k.ordering_key for k in items if k.ordering_key) + self._manager.activate_ordering_keys(ordering_keys) + self._manager.maybe_resume_consumer() + + def lease(self, items: Sequence[requests.LeaseRequest]) -> None: + """Add the given messages to lease management. + + Args: + items: The items to lease. + """ + assert self._manager.leaser is not None + self._manager.leaser.add(items) + self._manager.maybe_pause_consumer() + + def modify_ack_deadline(self, items: Sequence[requests.ModAckRequest]) -> None: + """Modify the ack deadline for the given messages. + + Args: + items: The items to modify. + """ + # We must potentially split the request into multiple smaller requests + # to avoid the server-side max request size limit. + items_gen = iter(items) + ack_ids_gen = (item.ack_id for item in items) + deadline_seconds_gen = (item.seconds for item in items) + total_chunks = int(math.ceil(len(items) / _ACK_IDS_BATCH_SIZE)) + + for _ in range(total_chunks): + ack_reqs_dict = { + req.ack_id: req + for req in itertools.islice(items_gen, _ACK_IDS_BATCH_SIZE) + } + # no further work needs to be done for `requests_to_retry` + requests_completed, requests_to_retry = self._manager.send_unary_modack( + modify_deadline_ack_ids=list( + itertools.islice(ack_ids_gen, _ACK_IDS_BATCH_SIZE) + ), + modify_deadline_seconds=list( + itertools.islice(deadline_seconds_gen, _ACK_IDS_BATCH_SIZE) + ), + ack_reqs_dict=ack_reqs_dict, + ) + assert ( + len(requests_to_retry) <= _ACK_IDS_BATCH_SIZE + ), "Too many requests to be retried." + + # Retry on a separate thread so the dispatcher thread isn't blocked + # by sleeps. + if requests_to_retry: + self._start_retry_thread( + "Thread-RetryModAcks", + functools.partial(self._retry_modacks, requests_to_retry), + ) + + def _retry_modacks(self, requests_to_retry): + retry_delay_gen = exponential_sleep_generator( + initial=_MIN_EXACTLY_ONCE_DELIVERY_ACK_MODACK_RETRY_DURATION_SECS, + maximum=_MAX_EXACTLY_ONCE_DELIVERY_ACK_MODACK_RETRY_DURATION_SECS, + ) + while requests_to_retry: + time_to_wait = next(retry_delay_gen) + _LOGGER.debug( + "Retrying {len(requests_to_retry)} modack(s) after delay of " + + str(time_to_wait) + + " seconds" + ) + time.sleep(time_to_wait) + + ack_reqs_dict = {req.ack_id: req for req in requests_to_retry} + requests_completed, requests_to_retry = self._manager.send_unary_modack( + modify_deadline_ack_ids=[req.ack_id for req in requests_to_retry], + modify_deadline_seconds=[req.seconds for req in requests_to_retry], + ack_reqs_dict=ack_reqs_dict, + ) + + def nack(self, items: Sequence[requests.NackRequest]) -> None: + """Explicitly deny receipt of messages. + + Args: + items: The items to deny. + """ + self.modify_ack_deadline( + [ + requests.ModAckRequest( + ack_id=item.ack_id, seconds=0, future=item.future + ) + for item in items + ] + ) + self.drop( + [ + requests.DropRequest( + ack_id=item.ack_id, + byte_size=item.byte_size, + ordering_key=item.ordering_key, + ) + for item in items + ] + ) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/_protocol/heartbeater.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/_protocol/heartbeater.py new file mode 100644 index 000000000000..a053d5fe4e08 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/_protocol/heartbeater.py @@ -0,0 +1,77 @@ +# Copyright 2018, Google LLC +# +# 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 +# +# https://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. + +from __future__ import absolute_import + +import logging +import threading +import typing +from typing import Optional + +if typing.TYPE_CHECKING: # pragma: NO COVER + from google.cloud.pubsub_v1.subscriber._protocol.streaming_pull_manager import ( + StreamingPullManager, + ) + + +_LOGGER = logging.getLogger(__name__) +_HEARTBEAT_WORKER_NAME = "Thread-Heartbeater" +# How often to send heartbeats in seconds. Determined as half the period of +# time where the Pub/Sub server will close the stream as inactive, which is +# 60 seconds. +_DEFAULT_PERIOD = 30 + + +class Heartbeater(object): + def __init__(self, manager: "StreamingPullManager", period: int = _DEFAULT_PERIOD): + self._thread: Optional[threading.Thread] = None + self._operational_lock = threading.Lock() + self._manager = manager + self._stop_event = threading.Event() + self._period = period + + def heartbeat(self) -> None: + """Periodically send streaming pull heartbeats.""" + while not self._stop_event.is_set(): + if self._manager.heartbeat(): + _LOGGER.debug("Sent heartbeat.") + self._stop_event.wait(timeout=self._period) + + _LOGGER.debug("%s exiting.", _HEARTBEAT_WORKER_NAME) + + def start(self) -> None: + with self._operational_lock: + if self._thread is not None: + raise ValueError("Heartbeater is already running.") + + # Create and start the helper thread. + self._stop_event.clear() + thread = threading.Thread( + name=_HEARTBEAT_WORKER_NAME, target=self.heartbeat + ) + thread.daemon = True + thread.start() + _LOGGER.debug("Started helper thread %s", thread.name) + self._thread = thread + + def stop(self) -> None: + with self._operational_lock: + self._stop_event.set() + + if self._thread is not None: + # The thread should automatically exit when the consumer is + # inactive. + self._thread.join() + + self._thread = None diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/_protocol/helper_threads.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/_protocol/helper_threads.py new file mode 100644 index 000000000000..fbcab781df84 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/_protocol/helper_threads.py @@ -0,0 +1,122 @@ +# Copyright 2017, Google LLC 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. + +import logging +import queue +import time +from typing import Any, Callable, List, Sequence +import uuid + + +__all__ = ("QueueCallbackWorker", "STOP") + +_LOGGER = logging.getLogger(__name__) + + +# Helper thread stop indicator. This could be a sentinel object or None, +# but the sentinel object's ID can change if the process is forked, and +# None has the possibility of a user accidentally killing the helper +# thread. +STOP = uuid.uuid4() + + +def _get_many( + queue_: queue.Queue, max_items: int = None, max_latency: float = 0 +) -> List[Any]: + """Get multiple items from a Queue. + + Gets at least one (blocking) and at most ``max_items`` items + (non-blocking) from a given Queue. Does not mark the items as done. + + Args: + queue_: The Queue to get items from. + max_items: + The maximum number of items to get. If ``None``, then all available items + in the queue are returned. + max_latency: + The maximum number of seconds to wait for more than one item from a queue. + This number includes the time required to retrieve the first item. + + Returns: + A sequence of items retrieved from the queue. + """ + start = time.time() + # Always return at least one item. + items = [queue_.get()] + while max_items is None or len(items) < max_items: + try: + elapsed = time.time() - start + timeout = max(0, max_latency - elapsed) + items.append(queue_.get(timeout=timeout)) + except queue.Empty: + break + return items + + +class QueueCallbackWorker(object): + """A helper that executes a callback for items sent in a queue. + + Calls a blocking ``get()`` on the ``queue`` until it encounters + :attr:`STOP`. + + Args: + queue: + A Queue instance, appropriate for crossing the concurrency boundary + implemented by ``executor``. Items will be popped off (with a blocking + ``get()``) until :attr:`STOP` is encountered. + callback: + A callback that can process items pulled off of the queue. Multiple items + will be passed to the callback in batches. + max_items: + The maximum amount of items that will be passed to the callback at a time. + max_latency: + The maximum amount of time in seconds to wait for additional items before + executing the callback. + """ + + def __init__( + self, + queue: queue.Queue, + callback: Callable[[Sequence[Any]], Any], + max_items: int = 100, + max_latency: float = 0, + ): + self.queue = queue + self._callback = callback + self.max_items = max_items + self.max_latency = max_latency + + def __call__(self) -> None: + continue_ = True + while continue_: + items = _get_many( + self.queue, max_items=self.max_items, max_latency=self.max_latency + ) + + # If stop is in the items, process all items up to STOP and then + # exit. + try: + items = items[: items.index(STOP)] + continue_ = False + except ValueError: + pass + + # Run the callback. If any exceptions occur, log them and + # continue. + try: + self._callback(items) + except Exception as exc: + _LOGGER.exception("Error in queue callback worker: %s", exc) + + _LOGGER.debug("Exiting the QueueCallbackWorker.") diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/_protocol/histogram.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/_protocol/histogram.py new file mode 100644 index 000000000000..d922bbf685c7 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/_protocol/histogram.py @@ -0,0 +1,159 @@ +# Copyright 2017, Google LLC 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. + +from typing import Dict, Optional, Union + + +MIN_ACK_DEADLINE = 10 +MAX_ACK_DEADLINE = 600 + + +class Histogram(object): + """Representation of a single histogram. + + The purpose of this class is to store actual ack timing information + in order to predict how long to renew leases. + + The default implementation uses the 99th percentile of previous ack + times to implicitly lease messages; however, custom + :class:`~.pubsub_v1.subscriber._consumer.Consumer` subclasses + are free to use a different formula. + + The precision of data stored is to the nearest integer. Additionally, + values outside the range of ``MIN_ACK_DEADLINE <= x <= MAX_ACK_DEADLINE`` are stored + as ``MIN_ACK_DEADLINE`` or ``MAX_ACK_DEADLINE``, since these are the boundaries of + leases in the actual API. + """ + + def __init__(self, data: Optional[Dict[int, int]] = None): + """Instantiate the histogram. + + Args: + data: + The data strucure to be used to store the underlying data. The default + is an empty dictionary. This can be set to a dictionary-like object if + required (for example, if a special object is needed for concurrency + reasons). + """ + # The data is stored as a dictionary, with the keys being the + # value being added and the values being the number of times that + # value was added to the dictionary. + # + # This is depending on the Python interpreter's implicit ordering + # of dictionaries, which is a bitwise sort by the key's ``hash()`` + # value. Because ``hash(int i) -> i`` and all of our keys are + # positive integers (negatives would be a problem because the sort + # is bitwise), we can rely on this. + if data is None: + data = {} + self._data = data + self._len = 0 + + def __len__(self) -> int: + """Return the total number of data points in this histogram. + + This is cached on a separate counter (rather than computing it using + ``sum([v for v in self._data.values()])``) to optimize lookup. + + Returns: + The total number of data points in this histogram. + """ + return self._len + + def __contains__(self, needle: int) -> bool: + """Return ``True`` if needle is present in the histogram, ``False`` otherwise.""" + return needle in self._data + + def __repr__(self): + return "".format( + len=len(self), max=self.max, min=self.min + ) + + @property + def max(self) -> int: + """Return the maximum value in this histogram. + + If there are no values in the histogram at all, return ``MAX_ACK_DEADLINE``. + + Returns: + The maximum value in the histogram. + """ + if len(self._data) == 0: + return MAX_ACK_DEADLINE + return next(iter(reversed(sorted(self._data.keys())))) + + @property + def min(self) -> int: + """Return the minimum value in this histogram. + + If there are no values in the histogram at all, return ``MIN_ACK_DEADLINE``. + + Returns: + The minimum value in the histogram. + """ + if len(self._data) == 0: + return MIN_ACK_DEADLINE + return next(iter(sorted(self._data.keys()))) + + def add(self, value: Union[int, float]) -> None: + """Add the value to this histogram. + + Args: + value: + The value. Values outside of + ``MIN_ACK_DEADLINE <= x <= MAX_ACK_DEADLINE`` + will be raised to ``MIN_ACK_DEADLINE`` or reduced to + ``MAX_ACK_DEADLINE``. + """ + # If the value is out of bounds, bring it in bounds. + value = int(value) + if value < MIN_ACK_DEADLINE: + value = MIN_ACK_DEADLINE + elif value > MAX_ACK_DEADLINE: + value = MAX_ACK_DEADLINE + + # Add the value to the histogram's data dictionary. + self._data.setdefault(value, 0) + self._data[value] += 1 + self._len += 1 + + def percentile(self, percent: Union[int, float]) -> int: + """Return the value that is the Nth precentile in the histogram. + + Args: + percent: + The precentile being sought. The default consumer implementations + consistently use ``99``. + + Returns: + The value corresponding to the requested percentile. + """ + # Sanity check: Any value over 100 should become 100. + if percent >= 100: + percent = 100 + + # Determine the actual target number. + target = len(self) - len(self) * (percent / 100) + + # Iterate over the values in reverse, dropping the target by the + # number of times each value has been seen. When the target passes + # 0, return the value we are currently viewing. + for k in reversed(sorted(self._data.keys())): + target -= self._data[k] + if target < 0: + return k + + # The only way to get here is if there was no data. + # In this case, just return the shortest possible deadline. + return MIN_ACK_DEADLINE diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/_protocol/leaser.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/_protocol/leaser.py new file mode 100644 index 000000000000..508f4d7cefcb --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/_protocol/leaser.py @@ -0,0 +1,241 @@ +# Copyright 2017, Google LLC +# +# 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 +# +# https://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. + +from __future__ import absolute_import + +import copy +import logging +import random +import threading +import time +import typing +from typing import Dict, Iterable, Optional, Union + +from google.cloud.pubsub_v1.subscriber._protocol.dispatcher import _MAX_BATCH_LATENCY + +try: + from collections.abc import KeysView + + KeysView[None] # KeysView is only subscriptable in Python 3.9+ +except TypeError: + # Deprecated since Python 3.9, thus only use as a fallback in older Python versions + from typing import KeysView + +from google.cloud.pubsub_v1.subscriber._protocol import requests + +if typing.TYPE_CHECKING: # pragma: NO COVER + from google.cloud.pubsub_v1.subscriber._protocol.streaming_pull_manager import ( + StreamingPullManager, + ) + + +_LOGGER = logging.getLogger(__name__) +_LEASE_WORKER_NAME = "Thread-LeaseMaintainer" + + +class _LeasedMessage(typing.NamedTuple): + sent_time: float + """The local time when ACK ID was initially leased in seconds since the epoch.""" + + size: int + ordering_key: Optional[str] + + +class Leaser(object): + def __init__(self, manager: "StreamingPullManager"): + self._thread: Optional[threading.Thread] = None + self._manager = manager + + # a lock used for start/stop operations, protecting the _thread attribute + self._operational_lock = threading.Lock() + + # A lock ensuring that add/remove operations are atomic and cannot be + # intertwined. Protects the _leased_messages and _bytes attributes. + self._add_remove_lock = threading.Lock() + + # Dict of ack_id -> _LeasedMessage + self._leased_messages: Dict[str, _LeasedMessage] = {} + + self._bytes = 0 + """The total number of bytes consumed by leased messages.""" + + self._stop_event = threading.Event() + + @property + def message_count(self) -> int: + """The number of leased messages.""" + return len(self._leased_messages) + + @property + def ack_ids(self) -> KeysView[str]: + """The ack IDs of all leased messages.""" + return self._leased_messages.keys() + + @property + def bytes(self) -> int: + """The total size, in bytes, of all leased messages.""" + return self._bytes + + def add(self, items: Iterable[requests.LeaseRequest]) -> None: + """Add messages to be managed by the leaser.""" + with self._add_remove_lock: + for item in items: + # Add the ack ID to the set of managed ack IDs, and increment + # the size counter. + if item.ack_id not in self._leased_messages: + self._leased_messages[item.ack_id] = _LeasedMessage( + sent_time=float("inf"), + size=item.byte_size, + ordering_key=item.ordering_key, + ) + self._bytes += item.byte_size + else: + _LOGGER.debug("Message %s is already lease managed", item.ack_id) + + def start_lease_expiry_timer(self, ack_ids: Iterable[str]) -> None: + """Start the lease expiry timer for `items`. + + Args: + items: Sequence of ack-ids for which to start lease expiry timers. + """ + with self._add_remove_lock: + for ack_id in ack_ids: + lease_info = self._leased_messages.get(ack_id) + # Lease info might not exist for this ack_id because it has already + # been removed by remove(). + if lease_info: + self._leased_messages[ack_id] = lease_info._replace( + sent_time=time.time() + ) + + def remove( + self, + items: Iterable[ + Union[requests.AckRequest, requests.DropRequest, requests.NackRequest] + ], + ) -> None: + """Remove messages from lease management.""" + with self._add_remove_lock: + # Remove the ack ID from lease management, and decrement the + # byte counter. + for item in items: + if self._leased_messages.pop(item.ack_id, None) is not None: + self._bytes -= item.byte_size + else: + _LOGGER.debug("Item %s was not managed.", item.ack_id) + + if self._bytes < 0: + _LOGGER.debug("Bytes was unexpectedly negative: %d", self._bytes) + self._bytes = 0 + + def maintain_leases(self) -> None: + """Maintain all of the leases being managed. + + This method modifies the ack deadline for all of the managed + ack IDs, then waits for most of that time (but with jitter), and + repeats. + """ + while not self._stop_event.is_set(): + # Determine the appropriate duration for the lease. This is + # based off of how long previous messages have taken to ack, with + # a sensible default and within the ranges allowed by Pub/Sub. + # Also update the deadline currently used if enough new ACK data has been + # gathered since the last deadline update. + deadline = self._manager._obtain_ack_deadline(maybe_update=True) + _LOGGER.debug("The current deadline value is %d seconds.", deadline) + + # Make a copy of the leased messages. This is needed because it's + # possible for another thread to modify the dictionary while + # we're iterating over it. + leased_messages = copy.copy(self._leased_messages) + + # Drop any leases that are beyond the max lease time. This ensures + # that in the event of a badly behaving actor, we can drop messages + # and allow the Pub/Sub server to resend them. + cutoff = time.time() - self._manager.flow_control.max_lease_duration + to_drop = [ + requests.DropRequest(ack_id, item.size, item.ordering_key) + for ack_id, item in leased_messages.items() + if item.sent_time < cutoff + ] + + if to_drop: + _LOGGER.warning( + "Dropping %s items because they were leased too long.", len(to_drop) + ) + assert self._manager.dispatcher is not None + self._manager.dispatcher.drop(to_drop) + + # Remove dropped items from our copy of the leased messages (they + # have already been removed from the real one by + # self._manager.drop(), which calls self.remove()). + for item in to_drop: + leased_messages.pop(item.ack_id) + + # Create a modack request. + # We do not actually call `modify_ack_deadline` over and over + # because it is more efficient to make a single request. + ack_ids = leased_messages.keys() + if ack_ids: + _LOGGER.debug("Renewing lease for %d ack IDs.", len(ack_ids)) + + # NOTE: This may not work as expected if ``consumer.active`` + # has changed since we checked it. An implementation + # without any sort of race condition would require a + # way for ``send_request`` to fail when the consumer + # is inactive. + assert self._manager.dispatcher is not None + ack_id_gen = (ack_id for ack_id in ack_ids) + self._manager._send_lease_modacks(ack_id_gen, deadline) + + # Now wait an appropriate period of time and do this again. + # + # We determine the appropriate period of time based on a random + # period between: + # minimum: MAX_BATCH_LATENCY (to prevent duplicate modacks being created in one batch) + # maximum: 90% of the deadline + # This maximum time attempts to prevent ack expiration before new lease modacks arrive at the server. + # This use of jitter (http://bit.ly/2s2ekL7) helps decrease contention in cases + # where there are many clients. + snooze = random.uniform(_MAX_BATCH_LATENCY, deadline * 0.9) + _LOGGER.debug("Snoozing lease management for %f seconds.", snooze) + self._stop_event.wait(timeout=snooze) + + _LOGGER.debug("%s exiting.", _LEASE_WORKER_NAME) + + def start(self) -> None: + with self._operational_lock: + if self._thread is not None: + raise ValueError("Leaser is already running.") + + # Create and start the helper thread. + self._stop_event.clear() + thread = threading.Thread( + name=_LEASE_WORKER_NAME, target=self.maintain_leases + ) + thread.daemon = True + thread.start() + _LOGGER.debug("Started helper thread %s", thread.name) + self._thread = thread + + def stop(self) -> None: + with self._operational_lock: + self._stop_event.set() + + if self._thread is not None: + # The thread should automatically exit when the consumer is + # inactive. + self._thread.join() + + self._thread = None diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/_protocol/messages_on_hold.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/_protocol/messages_on_hold.py new file mode 100644 index 000000000000..5c3cc1a75e8e --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/_protocol/messages_on_hold.py @@ -0,0 +1,168 @@ +# Copyright 2020, Google LLC +# +# 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 +# +# https://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. + +import collections +import typing +from typing import Any, Callable, Iterable, Optional + +if typing.TYPE_CHECKING: # pragma: NO COVER + from google.cloud.pubsub_v1 import subscriber + + +class MessagesOnHold(object): + """Tracks messages on hold by ordering key. Not thread-safe.""" + + def __init__(self): + self._size = 0 + + # A FIFO queue for the messages that have been received from the server, + # but not yet sent to the user callback. + # Both ordered and unordered messages may be in this queue. Ordered + # message state tracked in _pending_ordered_messages once ordered + # messages are taken off this queue. + # The tail of the queue is to the right side of the deque; the head is + # to the left side. + self._messages_on_hold = collections.deque() + + # Dict of ordering_key -> queue of ordered messages that have not been + # delivered to the user. + # All ordering keys in this collection have a message in flight. Once + # that one is acked or nacked, the next message in the queue for that + # ordering key will be sent. + # If the queue is empty, it means there's a message for that key in + # flight, but there are no pending messages. + self._pending_ordered_messages = {} + + @property + def size(self) -> int: + """Return the number of messages on hold across ordered and unordered messages. + + Note that this object may still store information about ordered messages + in flight even if size is zero. + + Returns: + The size value. + """ + return self._size + + def get(self) -> Optional["subscriber.message.Message"]: + """Gets a message from the on-hold queue. A message with an ordering + key wont be returned if there's another message with the same key in + flight. + + Returns: + A message that hasn't been sent to the user yet or ``None`` if there are no + messages available. + """ + while self._messages_on_hold: + msg = self._messages_on_hold.popleft() + + if msg.ordering_key: + pending_queue = self._pending_ordered_messages.get(msg.ordering_key) + if pending_queue is None: + # Create empty queue to indicate a message with the + # ordering key is in flight. + self._pending_ordered_messages[ + msg.ordering_key + ] = collections.deque() + self._size = self._size - 1 + return msg + else: + # Another message is in flight so add message to end of + # queue for this ordering key. + pending_queue.append(msg) + else: + # Unordered messages can be returned without any + # restrictions. + self._size = self._size - 1 + return msg + + return None + + def put(self, message: "subscriber.message.Message") -> None: + """Put a message on hold. + + Args: + message: The message to put on hold. + """ + self._messages_on_hold.append(message) + self._size = self._size + 1 + + def activate_ordering_keys( + self, + ordering_keys: Iterable[str], + schedule_message_callback: Callable[["subscriber.message.Message"], Any], + ) -> None: + """Send the next message in the queue for each of the passed-in + ordering keys, if they exist. Clean up state for keys that no longer + have any queued messages. + + See comment at streaming_pull_manager.activate_ordering_keys() for more + detail about the impact of this method on load. + + Args: + ordering_keys: + The ordering keys to activate. May be empty. + schedule_message_callback: + The callback to call to schedule a message to be sent to the user. + """ + for key in ordering_keys: + assert ( + self._pending_ordered_messages.get(key) is not None + ), "A message queue should exist for every ordered message in flight." + next_msg = self._get_next_for_ordering_key(key) + if next_msg: + # Schedule the next message because the previous was dropped. + # Note that this may overload the user's `max_bytes` limit, but + # not their `max_messages` limit. + schedule_message_callback(next_msg) + else: + # No more messages for this ordering key, so do clean-up. + self._clean_up_ordering_key(key) + + def _get_next_for_ordering_key( + self, ordering_key: str + ) -> Optional["subscriber.message.Message"]: + """Get next message for ordering key. + + The client should call clean_up_ordering_key() if this method returns + None. + + Args: + ordering_key: Ordering key for which to get the next message. + + Returns: + The next message for this ordering key or None if there aren't any. + """ + queue_for_key = self._pending_ordered_messages.get(ordering_key) + if queue_for_key: + self._size = self._size - 1 + return queue_for_key.popleft() + return None + + def _clean_up_ordering_key(self, ordering_key: str) -> None: + """Clean up state for an ordering key with no pending messages. + + Args: + ordering_key: The ordering key to clean up. + """ + message_queue = self._pending_ordered_messages.get(ordering_key) + assert ( + message_queue is not None + ), "Cleaning up ordering key that does not exist." + assert not len(message_queue), ( + "Ordering key must only be removed if there are no messages " + "left for that key." + ) + del self._pending_ordered_messages[ordering_key] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/_protocol/requests.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/_protocol/requests.py new file mode 100644 index 000000000000..9cd387545909 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/_protocol/requests.py @@ -0,0 +1,54 @@ +# Copyright 2017, Google LLC 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. + +import typing +from typing import NamedTuple, Optional + +if typing.TYPE_CHECKING: # pragma: NO COVER + from google.cloud.pubsub_v1.subscriber import futures + + +# Namedtuples for management requests. Used by the Message class to communicate +# items of work back to the policy. +class AckRequest(NamedTuple): + ack_id: str + byte_size: int + time_to_ack: float + ordering_key: Optional[str] + future: Optional["futures.Future"] + + +class DropRequest(NamedTuple): + ack_id: str + byte_size: int + ordering_key: Optional[str] + + +class LeaseRequest(NamedTuple): + ack_id: str + byte_size: int + ordering_key: Optional[str] + + +class ModAckRequest(NamedTuple): + ack_id: str + seconds: float + future: Optional["futures.Future"] + + +class NackRequest(NamedTuple): + ack_id: str + byte_size: int + ordering_key: Optional[str] + future: Optional["futures.Future"] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/_protocol/streaming_pull_manager.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/_protocol/streaming_pull_manager.py new file mode 100644 index 000000000000..89dc93e74ee8 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/_protocol/streaming_pull_manager.py @@ -0,0 +1,1179 @@ +# Copyright 2017, Google LLC +# +# 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 +# +# https://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. + +from __future__ import division + +import collections +import functools +import itertools +import logging +import threading +import typing +from typing import Any, Dict, Callable, Iterable, List, Optional, Tuple +import uuid + +import grpc # type: ignore + +from google.api_core import bidi +from google.api_core import exceptions +from google.cloud.pubsub_v1 import types +from google.cloud.pubsub_v1.subscriber._protocol import dispatcher +from google.cloud.pubsub_v1.subscriber._protocol import heartbeater +from google.cloud.pubsub_v1.subscriber._protocol import histogram +from google.cloud.pubsub_v1.subscriber._protocol import leaser +from google.cloud.pubsub_v1.subscriber._protocol import messages_on_hold +from google.cloud.pubsub_v1.subscriber._protocol import requests +from google.cloud.pubsub_v1.subscriber.exceptions import ( + AcknowledgeError, + AcknowledgeStatus, +) +import google.cloud.pubsub_v1.subscriber.message +from google.cloud.pubsub_v1.subscriber import futures +from google.cloud.pubsub_v1.subscriber.scheduler import ThreadScheduler +from google.pubsub_v1 import types as gapic_types +from grpc_status import rpc_status # type: ignore +from google.rpc.error_details_pb2 import ErrorInfo # type: ignore +from google.rpc import code_pb2 # type: ignore +from google.rpc import status_pb2 + +if typing.TYPE_CHECKING: # pragma: NO COVER + from google.cloud.pubsub_v1 import subscriber + + +_LOGGER = logging.getLogger(__name__) +_REGULAR_SHUTDOWN_THREAD_NAME = "Thread-RegularStreamShutdown" +_RPC_ERROR_THREAD_NAME = "Thread-OnRpcTerminated" +_RETRYABLE_STREAM_ERRORS = ( + exceptions.DeadlineExceeded, + exceptions.ServiceUnavailable, + exceptions.InternalServerError, + exceptions.Unknown, + exceptions.GatewayTimeout, + exceptions.Aborted, +) +_TERMINATING_STREAM_ERRORS = (exceptions.Cancelled,) +_MAX_LOAD = 1.0 +"""The load threshold above which to pause the incoming message stream.""" + +_RESUME_THRESHOLD = 0.8 +"""The load threshold below which to resume the incoming message stream.""" + +_MIN_ACK_DEADLINE_SECS_WHEN_EXACTLY_ONCE_ENABLED = 60 +"""The minimum ack_deadline, in seconds, for when exactly_once is enabled for +a subscription. We do this to reduce premature ack expiration. +""" + +_DEFAULT_STREAM_ACK_DEADLINE: float = 60 +"""The default stream ack deadline in seconds.""" + +_MAX_STREAM_ACK_DEADLINE: float = 600 +"""The maximum stream ack deadline in seconds.""" + +_MIN_STREAM_ACK_DEADLINE: float = 10 +"""The minimum stream ack deadline in seconds.""" + +_EXACTLY_ONCE_DELIVERY_TEMPORARY_RETRY_ERRORS = { + code_pb2.DEADLINE_EXCEEDED, + code_pb2.RESOURCE_EXHAUSTED, + code_pb2.ABORTED, + code_pb2.INTERNAL, + code_pb2.UNAVAILABLE, +} + + +def _wrap_as_exception(maybe_exception: Any) -> BaseException: + """Wrap an object as a Python exception, if needed. + + Args: + maybe_exception: The object to wrap, usually a gRPC exception class. + + Returns: + The argument itself if an instance of ``BaseException``, otherwise + the argument represented as an instance of ``Exception`` (sub)class. + """ + if isinstance(maybe_exception, grpc.RpcError): + return exceptions.from_grpc_error(maybe_exception) + elif isinstance(maybe_exception, BaseException): + return maybe_exception + + return Exception(maybe_exception) + + +def _wrap_callback_errors( + callback: Callable[["google.cloud.pubsub_v1.subscriber.message.Message"], Any], + on_callback_error: Callable[[Exception], Any], + message: "google.cloud.pubsub_v1.subscriber.message.Message", +): + """Wraps a user callback so that if an exception occurs the message is + nacked. + + Args: + callback: The user callback. + message: The Pub/Sub message. + """ + try: + callback(message) + except Exception as exc: + # Note: the likelihood of this failing is extremely low. This just adds + # a message to a queue, so if this doesn't work the world is in an + # unrecoverable state and this thread should just bail. + _LOGGER.exception( + "Top-level exception occurred in callback while processing a message" + ) + message.nack() + on_callback_error(exc) + + +def _get_status( + exc: exceptions.GoogleAPICallError, +) -> Optional["status_pb2.Status"]: + if not exc.response: + _LOGGER.debug("No response obj in errored RPC call.") + return None + try: + return rpc_status.from_call(exc.response) + # Possible "If the gRPC call’s code or details are inconsistent + # with the status code and message inside of the + # google.rpc.status.Status" + except ValueError: + _LOGGER.debug("ValueError when parsing ErrorInfo.", exc_info=True) + return None + + +def _get_ack_errors( + exc: exceptions.GoogleAPICallError, +) -> Optional[Dict[str, str]]: + status = _get_status(exc) + if not status: + _LOGGER.debug("Unable to get status of errored RPC.") + return None + for detail in status.details: + info = ErrorInfo() + if not (detail.Is(ErrorInfo.DESCRIPTOR) and detail.Unpack(info)): + _LOGGER.debug("Unable to unpack ErrorInfo.") + return None + return info.metadata + return None + + +def _process_requests( + error_status: Optional["status_pb2.Status"], + ack_reqs_dict: Dict[str, requests.AckRequest], + errors_dict: Optional[Dict[str, str]], +): + """Process requests when exactly-once delivery is enabled by referring to + error_status and errors_dict. + + The errors returned by the server in as `error_status` or in `errors_dict` + are used to complete the request futures in `ack_reqs_dict` (with a success + or exception) or to return requests for further retries. + """ + requests_completed = [] + requests_to_retry = [] + for ack_id in ack_reqs_dict: + # Handle special errors returned for ack/modack RPCs via the ErrorInfo + # sidecar metadata when exactly-once delivery is enabled. + if errors_dict and ack_id in errors_dict: + exactly_once_error = errors_dict[ack_id] + if exactly_once_error.startswith("TRANSIENT_"): + requests_to_retry.append(ack_reqs_dict[ack_id]) + else: + if exactly_once_error == "PERMANENT_FAILURE_INVALID_ACK_ID": + exc = AcknowledgeError(AcknowledgeStatus.INVALID_ACK_ID, info=None) + else: + exc = AcknowledgeError(AcknowledgeStatus.OTHER, exactly_once_error) + future = ack_reqs_dict[ack_id].future + if future is not None: + future.set_exception(exc) + requests_completed.append(ack_reqs_dict[ack_id]) + # Temporary GRPC errors are retried + elif ( + error_status + and error_status.code in _EXACTLY_ONCE_DELIVERY_TEMPORARY_RETRY_ERRORS + ): + requests_to_retry.append(ack_reqs_dict[ack_id]) + # Other GRPC errors are NOT retried + elif error_status: + if error_status.code == code_pb2.PERMISSION_DENIED: + exc = AcknowledgeError(AcknowledgeStatus.PERMISSION_DENIED, info=None) + elif error_status.code == code_pb2.FAILED_PRECONDITION: + exc = AcknowledgeError(AcknowledgeStatus.FAILED_PRECONDITION, info=None) + else: + exc = AcknowledgeError(AcknowledgeStatus.OTHER, str(error_status)) + future = ack_reqs_dict[ack_id].future + if future is not None: + future.set_exception(exc) + requests_completed.append(ack_reqs_dict[ack_id]) + # Since no error occurred, requests with futures are completed successfully. + elif ack_reqs_dict[ack_id].future: + future = ack_reqs_dict[ack_id].future + # success + assert future is not None + future.set_result(AcknowledgeStatus.SUCCESS) + requests_completed.append(ack_reqs_dict[ack_id]) + # All other requests are considered completed. + else: + requests_completed.append(ack_reqs_dict[ack_id]) + + return requests_completed, requests_to_retry + + +class StreamingPullManager(object): + """The streaming pull manager coordinates pulling messages from Pub/Sub, + leasing them, and scheduling them to be processed. + + Args: + client: + The subscriber client used to create this instance. + subscription: + The name of the subscription. The canonical format for this is + ``projects/{project}/subscriptions/{subscription}``. + flow_control: + The flow control settings. + scheduler: + The scheduler to use to process messages. If not provided, a thread + pool-based scheduler will be used. + use_legacy_flow_control: + If set to ``True``, flow control at the Cloud Pub/Sub server is disabled, + though client-side flow control is still enabled. If set to ``False`` + (default), both server-side and client-side flow control are enabled. + await_callbacks_on_shutdown: + If ``True``, the shutdown thread will wait until all scheduler threads + terminate and only then proceed with shutting down the remaining running + helper threads. + + If ``False`` (default), the shutdown thread will shut the scheduler down, + but it will not wait for the currently executing scheduler threads to + terminate. + + This setting affects when the on close callbacks get invoked, and + consequently, when the StreamingPullFuture associated with the stream gets + resolved. + """ + + def __init__( + self, + client: "subscriber.Client", + subscription: str, + flow_control: types.FlowControl = types.FlowControl(), + scheduler: ThreadScheduler = None, + use_legacy_flow_control: bool = False, + await_callbacks_on_shutdown: bool = False, + ): + self._client = client + self._subscription = subscription + self._exactly_once_enabled = False + self._flow_control = flow_control + self._use_legacy_flow_control = use_legacy_flow_control + self._await_callbacks_on_shutdown = await_callbacks_on_shutdown + self._ack_histogram = histogram.Histogram() + self._last_histogram_size = 0 + + # If max_duration_per_lease_extension is the default + # we set the stream_ack_deadline to the default of 60 + if self._flow_control.max_duration_per_lease_extension == 0: + self._stream_ack_deadline = _DEFAULT_STREAM_ACK_DEADLINE + # We will not be able to extend more than the default minimum + elif ( + self._flow_control.max_duration_per_lease_extension + < _MIN_STREAM_ACK_DEADLINE + ): + self._stream_ack_deadline = _MIN_STREAM_ACK_DEADLINE + # Will not be able to extend past the max + elif ( + self._flow_control.max_duration_per_lease_extension + > _MAX_STREAM_ACK_DEADLINE + ): + self._stream_ack_deadline = _MAX_STREAM_ACK_DEADLINE + else: + self._stream_ack_deadline = ( + self._flow_control.max_duration_per_lease_extension + ) + + self._ack_deadline = max( + min( + self._flow_control.min_duration_per_lease_extension, + histogram.MAX_ACK_DEADLINE, + ), + histogram.MIN_ACK_DEADLINE, + ) + + self._rpc: Optional[bidi.ResumableBidiRpc] = None + self._callback: Optional[functools.partial] = None + self._closing = threading.Lock() + self._closed = False + self._close_callbacks: List[Callable[["StreamingPullManager", Any], Any]] = [] + # Guarded by self._exactly_once_enabled_lock + self._send_new_ack_deadline = False + + # A shutdown thread is created on intentional shutdown. + self._regular_shutdown_thread: Optional[threading.Thread] = None + + # Generate a random client id tied to this object. All streaming pull + # connections (initial and re-connects) will then use the same client + # id. Doing so lets the server establish affinity even across stream + # disconncetions. + self._client_id = str(uuid.uuid4()) + + if scheduler is None: + self._scheduler: Optional[ThreadScheduler] = ThreadScheduler() + else: + self._scheduler = scheduler + + # A collection for the messages that have been received from the server, + # but not yet sent to the user callback. + self._messages_on_hold = messages_on_hold.MessagesOnHold() + + # The total number of bytes consumed by the messages currently on hold + self._on_hold_bytes = 0 + + # A lock ensuring that pausing / resuming the consumer are both atomic + # operations that cannot be executed concurrently. Needed for properly + # syncing these operations with the current leaser load. Additionally, + # the lock is used to protect modifications of internal data that + # affects the load computation, i.e. the count and size of the messages + # currently on hold. + self._pause_resume_lock = threading.Lock() + + # A lock guarding the self._exactly_once_enabled variable. We may also + # acquire the self._ack_deadline_lock while this lock is held, but not + # the reverse. So, we maintain a simple ordering of these two locks to + # prevent deadlocks. + self._exactly_once_enabled_lock = threading.Lock() + + # A lock protecting the current ACK deadline used in the lease management. This + # value can be potentially updated both by the leaser thread and by the message + # consumer thread when invoking the internal _on_response() callback. + self._ack_deadline_lock = threading.Lock() + + # The threads created in ``.open()``. + self._dispatcher: Optional[dispatcher.Dispatcher] = None + self._leaser: Optional[leaser.Leaser] = None + self._consumer: Optional[bidi.BackgroundConsumer] = None + self._heartbeater: Optional[heartbeater.Heartbeater] = None + + @property + def is_active(self) -> bool: + """``True`` if this manager is actively streaming. + + Note that ``False`` does not indicate this is complete shut down, + just that it stopped getting new messages. + """ + return self._consumer is not None and self._consumer.is_active + + @property + def flow_control(self) -> types.FlowControl: + """The active flow control settings.""" + return self._flow_control + + @property + def dispatcher(self) -> Optional[dispatcher.Dispatcher]: + """The dispatcher helper.""" + return self._dispatcher + + @property + def leaser(self) -> Optional[leaser.Leaser]: + """The leaser helper.""" + return self._leaser + + @property + def ack_histogram(self) -> histogram.Histogram: + """The histogram tracking time-to-acknowledge.""" + return self._ack_histogram + + @property + def ack_deadline(self) -> float: + """Return the current ACK deadline based on historical data without updating it. + + Returns: + The ack deadline. + """ + return self._obtain_ack_deadline(maybe_update=False) + + def _obtain_ack_deadline(self, maybe_update: bool) -> float: + """The actual `ack_deadline` implementation. + + This method is "sticky". It will only perform the computations to check on the + right ACK deadline if explicitly requested AND if the histogram with past + time-to-ack data has gained a significant amount of new information. + + Args: + maybe_update: + If ``True``, also update the current ACK deadline before returning it if + enough new ACK data has been gathered. + + Returns: + The current ACK deadline in seconds to use. + """ + with self._ack_deadline_lock: + if not maybe_update: + return self._ack_deadline + + target_size = min( + self._last_histogram_size * 2, self._last_histogram_size + 100 + ) + hist_size = len(self.ack_histogram) + + if hist_size > target_size: + self._last_histogram_size = hist_size + self._ack_deadline = self.ack_histogram.percentile(percent=99) + + if self.flow_control.max_duration_per_lease_extension > 0: + # The setting in flow control could be too low, adjust if needed. + flow_control_setting = max( + self.flow_control.max_duration_per_lease_extension, + histogram.MIN_ACK_DEADLINE, + ) + self._ack_deadline = min(self._ack_deadline, flow_control_setting) + + # If the user explicitly sets a min ack_deadline, respect it. + if self.flow_control.min_duration_per_lease_extension > 0: + # The setting in flow control could be too high, adjust if needed. + flow_control_setting = min( + self.flow_control.min_duration_per_lease_extension, + histogram.MAX_ACK_DEADLINE, + ) + self._ack_deadline = max(self._ack_deadline, flow_control_setting) + elif self._exactly_once_enabled: + # Higher minimum ack_deadline for subscriptions with + # exactly-once delivery enabled. + self._ack_deadline = max( + self._ack_deadline, _MIN_ACK_DEADLINE_SECS_WHEN_EXACTLY_ONCE_ENABLED + ) + # If we have updated the ack_deadline and it is longer than the stream_ack_deadline + # set the stream_ack_deadline to the new ack_deadline. + if self._ack_deadline > self._stream_ack_deadline: + self._stream_ack_deadline = self._ack_deadline + return self._ack_deadline + + @property + def load(self) -> float: + """Return the current load. + + The load is represented as a float, where 1.0 represents having + hit one of the flow control limits, and values between 0.0 and 1.0 + represent how close we are to them. (0.5 means we have exactly half + of what the flow control setting allows, for example.) + + There are (currently) two flow control settings; this property + computes how close the manager is to each of them, and returns + whichever value is higher. (It does not matter that we have lots of + running room on setting A if setting B is over.) + + Returns: + The load value. + """ + if self._leaser is None: + return 0.0 + + # Messages that are temporarily put on hold are not being delivered to + # user's callbacks, thus they should not contribute to the flow control + # load calculation. + # However, since these messages must still be lease-managed to avoid + # unnecessary ACK deadline expirations, their count and total size must + # be subtracted from the leaser's values. + return max( + [ + (self._leaser.message_count - self._messages_on_hold.size) + / self._flow_control.max_messages, + (self._leaser.bytes - self._on_hold_bytes) + / self._flow_control.max_bytes, + ] + ) + + def add_close_callback( + self, callback: Callable[["StreamingPullManager", Any], Any] + ) -> None: + """Schedules a callable when the manager closes. + + Args: + The method to call. + """ + self._close_callbacks.append(callback) + + def activate_ordering_keys(self, ordering_keys: Iterable[str]) -> None: + """Send the next message in the queue for each of the passed-in + ordering keys, if they exist. Clean up state for keys that no longer + have any queued messages. + + Since the load went down by one message, it's probably safe to send the + user another message for the same key. Since the released message may be + bigger than the previous one, this may increase the load above the maximum. + This decision is by design because it simplifies MessagesOnHold. + + Args: + ordering_keys: + A sequence of ordering keys to activate. May be empty. + """ + with self._pause_resume_lock: + if self._scheduler is None: + return # We are shutting down, don't try to dispatch any more messages. + + self._messages_on_hold.activate_ordering_keys( + ordering_keys, self._schedule_message_on_hold + ) + + def maybe_pause_consumer(self) -> None: + """Check the current load and pause the consumer if needed.""" + with self._pause_resume_lock: + if self.load >= _MAX_LOAD: + if self._consumer is not None and not self._consumer.is_paused: + _LOGGER.debug( + "Message backlog over load at %.2f, pausing.", self.load + ) + self._consumer.pause() + + def maybe_resume_consumer(self) -> None: + """Check the load and held messages and resume the consumer if needed. + + If there are messages held internally, release those messages before + resuming the consumer. That will avoid leaser overload. + """ + with self._pause_resume_lock: + # If we have been paused by flow control, check and see if we are + # back within our limits. + # + # In order to not thrash too much, require us to have passed below + # the resume threshold (80% by default) of each flow control setting + # before restarting. + if self._consumer is None or not self._consumer.is_paused: + return + + _LOGGER.debug("Current load: %.2f", self.load) + + # Before maybe resuming the background consumer, release any messages + # currently on hold, if the current load allows for it. + self._maybe_release_messages() + + if self.load < _RESUME_THRESHOLD: + _LOGGER.debug("Current load is %.2f, resuming consumer.", self.load) + self._consumer.resume() + else: + _LOGGER.debug("Did not resume, current load is %.2f.", self.load) + + def _maybe_release_messages(self) -> None: + """Release (some of) the held messages if the current load allows for it. + + The method tries to release as many messages as the current leaser load + would allow. Each released message is added to the lease management, + and the user callback is scheduled for it. + + If there are currently no messages on hold, or if the leaser is + already overloaded, this method is effectively a no-op. + + The method assumes the caller has acquired the ``_pause_resume_lock``. + """ + released_ack_ids = [] + while self.load < _MAX_LOAD: + msg = self._messages_on_hold.get() + if not msg: + break + + self._schedule_message_on_hold(msg) + released_ack_ids.append(msg.ack_id) + + assert self._leaser is not None + self._leaser.start_lease_expiry_timer(released_ack_ids) + + def _schedule_message_on_hold( + self, msg: "google.cloud.pubsub_v1.subscriber.message.Message" + ): + """Schedule a message on hold to be sent to the user and change on-hold-bytes. + + The method assumes the caller has acquired the ``_pause_resume_lock``. + + Args: + msg: The message to schedule to be sent to the user. + """ + assert msg, "Message must not be None." + + # On-hold bytes goes down, increasing load. + self._on_hold_bytes -= msg.size + + if self._on_hold_bytes < 0: + _LOGGER.warning( + "On hold bytes was unexpectedly negative: %s", self._on_hold_bytes + ) + self._on_hold_bytes = 0 + + _LOGGER.debug( + "Released held message, scheduling callback for it, " + "still on hold %s (bytes %s).", + self._messages_on_hold.size, + self._on_hold_bytes, + ) + assert self._scheduler is not None + assert self._callback is not None + self._scheduler.schedule(self._callback, msg) + + def send_unary_ack( + self, ack_ids, ack_reqs_dict + ) -> Tuple[List[requests.AckRequest], List[requests.AckRequest]]: + """Send a request using a separate unary request instead of over the stream. + + If a RetryError occurs, the manager shutdown is triggered, and the + error is re-raised. + """ + assert ack_ids + assert len(ack_ids) == len(ack_reqs_dict) + + error_status = None + ack_errors_dict = None + try: + self._client.acknowledge(subscription=self._subscription, ack_ids=ack_ids) + except exceptions.GoogleAPICallError as exc: + _LOGGER.debug( + "Exception while sending unary RPC. This is typically " + "non-fatal as stream requests are best-effort.", + exc_info=True, + ) + error_status = _get_status(exc) + ack_errors_dict = _get_ack_errors(exc) + except exceptions.RetryError as exc: + exactly_once_delivery_enabled = self._exactly_once_delivery_enabled() + # Makes sure to complete futures so they don't block forever. + for req in ack_reqs_dict.values(): + # Futures may be present even with exactly-once delivery + # disabled, in transition periods after the setting is changed on + # the subscription. + if req.future: + if exactly_once_delivery_enabled: + e = AcknowledgeError( + AcknowledgeStatus.OTHER, "RetryError while sending ack RPC." + ) + req.future.set_exception(e) + else: + req.future.set_result(AcknowledgeStatus.SUCCESS) + + _LOGGER.debug( + "RetryError while sending ack RPC. Waiting on a transient " + "error resolution for too long, will now trigger shutdown.", + exc_info=False, + ) + # The underlying channel has been suffering from a retryable error + # for too long, time to give up and shut the streaming pull down. + self._on_rpc_done(exc) + raise + + if self._exactly_once_delivery_enabled(): + requests_completed, requests_to_retry = _process_requests( + error_status, ack_reqs_dict, ack_errors_dict + ) + else: + requests_completed = [] + requests_to_retry = [] + # When exactly-once delivery is NOT enabled, acks/modacks are considered + # best-effort. So, they always succeed even if the RPC fails. + for req in ack_reqs_dict.values(): + # Futures may be present even with exactly-once delivery + # disabled, in transition periods after the setting is changed on + # the subscription. + if req.future: + req.future.set_result(AcknowledgeStatus.SUCCESS) + requests_completed.append(req) + + return requests_completed, requests_to_retry + + def send_unary_modack( + self, modify_deadline_ack_ids, modify_deadline_seconds, ack_reqs_dict + ) -> Tuple[List[requests.ModAckRequest], List[requests.ModAckRequest]]: + """Send a request using a separate unary request instead of over the stream. + + If a RetryError occurs, the manager shutdown is triggered, and the + error is re-raised. + """ + assert modify_deadline_ack_ids + + error_status = None + modack_errors_dict = None + try: + # Send ack_ids with the same deadline seconds together. + deadline_to_ack_ids = collections.defaultdict(list) + + for n, ack_id in enumerate(modify_deadline_ack_ids): + deadline = modify_deadline_seconds[n] + deadline_to_ack_ids[deadline].append(ack_id) + + for deadline, ack_ids in deadline_to_ack_ids.items(): + self._client.modify_ack_deadline( + subscription=self._subscription, + ack_ids=ack_ids, + ack_deadline_seconds=deadline, + ) + except exceptions.GoogleAPICallError as exc: + _LOGGER.debug( + "Exception while sending unary RPC. This is typically " + "non-fatal as stream requests are best-effort.", + exc_info=True, + ) + error_status = _get_status(exc) + modack_errors_dict = _get_ack_errors(exc) + except exceptions.RetryError as exc: + exactly_once_delivery_enabled = self._exactly_once_delivery_enabled() + # Makes sure to complete futures so they don't block forever. + for req in ack_reqs_dict.values(): + # Futures may be present even with exactly-once delivery + # disabled, in transition periods after the setting is changed on + # the subscription. + if req.future: + if exactly_once_delivery_enabled: + e = AcknowledgeError( + AcknowledgeStatus.OTHER, + "RetryError while sending modack RPC.", + ) + req.future.set_exception(e) + else: + req.future.set_result(AcknowledgeStatus.SUCCESS) + + _LOGGER.debug( + "RetryError while sending modack RPC. Waiting on a transient " + "error resolution for too long, will now trigger shutdown.", + exc_info=False, + ) + # The underlying channel has been suffering from a retryable error + # for too long, time to give up and shut the streaming pull down. + self._on_rpc_done(exc) + raise + + if self._exactly_once_delivery_enabled(): + requests_completed, requests_to_retry = _process_requests( + error_status, ack_reqs_dict, modack_errors_dict + ) + else: + requests_completed = [] + requests_to_retry = [] + # When exactly-once delivery is NOT enabled, acks/modacks are considered + # best-effort. So, they always succeed even if the RPC fails. + for req in ack_reqs_dict.values(): + # Futures may be present even with exactly-once delivery + # disabled, in transition periods after the setting is changed on + # the subscription. + if req.future: + req.future.set_result(AcknowledgeStatus.SUCCESS) + requests_completed.append(req) + + return requests_completed, requests_to_retry + + def heartbeat(self) -> bool: + """Sends a heartbeat request over the streaming pull RPC. + + The request is empty by default, but may contain the current ack_deadline + if the self._exactly_once_enabled flag has changed. + + Returns: + If a heartbeat request has actually been sent. + """ + if self._rpc is not None and self._rpc.is_active: + send_new_ack_deadline = False + with self._exactly_once_enabled_lock: + send_new_ack_deadline = self._send_new_ack_deadline + self._send_new_ack_deadline = False + + if send_new_ack_deadline: + request = gapic_types.StreamingPullRequest( + stream_ack_deadline_seconds=self._stream_ack_deadline + ) + _LOGGER.debug( + "Sending new ack_deadline of %d seconds.", self._stream_ack_deadline + ) + else: + request = gapic_types.StreamingPullRequest() + + self._rpc.send(request) + return True + + return False + + def open( + self, + callback: Callable[["google.cloud.pubsub_v1.subscriber.message.Message"], Any], + on_callback_error: Callable[[Exception], Any], + ) -> None: + """Begin consuming messages. + + Args: + callback: + A callback that will be called for each message received on the + stream. + on_callback_error: + A callable that will be called if an exception is raised in + the provided `callback`. + """ + if self.is_active: + raise ValueError("This manager is already open.") + + if self._closed: + raise ValueError("This manager has been closed and can not be re-used.") + + self._callback = functools.partial( + _wrap_callback_errors, callback, on_callback_error + ) + + # Create the RPC + stream_ack_deadline_seconds = self._stream_ack_deadline + + get_initial_request = functools.partial( + self._get_initial_request, stream_ack_deadline_seconds + ) + self._rpc = bidi.ResumableBidiRpc( + start_rpc=self._client.streaming_pull, + initial_request=get_initial_request, + should_recover=self._should_recover, + should_terminate=self._should_terminate, + throttle_reopen=True, + ) + self._rpc.add_done_callback(self._on_rpc_done) + + _LOGGER.debug( + "Creating a stream, default ACK deadline set to {} seconds.".format( + self._stream_ack_deadline + ) + ) + + # Create references to threads + assert self._scheduler is not None + scheduler_queue = self._scheduler.queue + self._dispatcher = dispatcher.Dispatcher(self, scheduler_queue) + self._consumer = bidi.BackgroundConsumer(self._rpc, self._on_response) + self._leaser = leaser.Leaser(self) + self._heartbeater = heartbeater.Heartbeater(self) + + # Start the thread to pass the requests. + self._dispatcher.start() + + # Start consuming messages. + self._consumer.start() + + # Start the lease maintainer thread. + self._leaser.start() + + # Start the stream heartbeater thread. + self._heartbeater.start() + + def close(self, reason: Any = None) -> None: + """Stop consuming messages and shutdown all helper threads. + + This method is idempotent. Additional calls will have no effect. + + The method does not block, it delegates the shutdown operations to a background + thread. + + Args: + reason: + The reason to close this. If ``None``, this is considered + an "intentional" shutdown. This is passed to the callbacks + specified via :meth:`add_close_callback`. + """ + self._regular_shutdown_thread = threading.Thread( + name=_REGULAR_SHUTDOWN_THREAD_NAME, + daemon=True, + target=self._shutdown, + kwargs={"reason": reason}, + ) + self._regular_shutdown_thread.start() + + def _shutdown(self, reason: Any = None) -> None: + """Run the actual shutdown sequence (stop the stream and all helper threads). + + Args: + reason: + The reason to close the stream. If ``None``, this is considered + an "intentional" shutdown. + """ + with self._closing: + if self._closed: + return + + # Stop consuming messages. + if self.is_active: + _LOGGER.debug("Stopping consumer.") + assert self._consumer is not None + self._consumer.stop() + self._consumer = None + + # Shutdown all helper threads + _LOGGER.debug("Stopping scheduler.") + assert self._scheduler is not None + dropped_messages = self._scheduler.shutdown( + await_msg_callbacks=self._await_callbacks_on_shutdown + ) + self._scheduler = None + + # Leaser and dispatcher reference each other through the shared + # StreamingPullManager instance, i.e. "self", thus do not set their + # references to None until both have been shut down. + # + # NOTE: Even if the dispatcher operates on an inactive leaser using + # the latter's add() and remove() methods, these have no impact on + # the stopped leaser (the leaser is never again re-started). Ditto + # for the manager's maybe_resume_consumer() / maybe_pause_consumer(), + # because the consumer gets shut down first. + _LOGGER.debug("Stopping leaser.") + assert self._leaser is not None + self._leaser.stop() + + total = len(dropped_messages) + len( + self._messages_on_hold._messages_on_hold + ) + _LOGGER.debug(f"NACK-ing all not-yet-dispatched messages (total: {total}).") + messages_to_nack = itertools.chain( + dropped_messages, self._messages_on_hold._messages_on_hold + ) + for msg in messages_to_nack: + msg.nack() + + _LOGGER.debug("Stopping dispatcher.") + assert self._dispatcher is not None + self._dispatcher.stop() + self._dispatcher = None + # dispatcher terminated, OK to dispose the leaser reference now + self._leaser = None + + _LOGGER.debug("Stopping heartbeater.") + assert self._heartbeater is not None + self._heartbeater.stop() + self._heartbeater = None + + self._rpc = None + self._closed = True + _LOGGER.debug("Finished stopping manager.") + + for callback in self._close_callbacks: + callback(self, reason) + + def _get_initial_request( + self, stream_ack_deadline_seconds: int + ) -> gapic_types.StreamingPullRequest: + """Return the initial request for the RPC. + + This defines the initial request that must always be sent to Pub/Sub + immediately upon opening the subscription. + + Args: + stream_ack_deadline_seconds: + The default message acknowledge deadline for the stream. + + Returns: + A request suitable for being the first request on the stream (and not + suitable for any other purpose). + """ + # Put the request together. + # We need to set streaming ack deadline, but it's not useful since we'll modack to send receipt + # anyway. Set to some big-ish value in case we modack late. + request = gapic_types.StreamingPullRequest( + stream_ack_deadline_seconds=stream_ack_deadline_seconds, + modify_deadline_ack_ids=[], + modify_deadline_seconds=[], + subscription=self._subscription, + client_id=self._client_id, + max_outstanding_messages=( + 0 if self._use_legacy_flow_control else self._flow_control.max_messages + ), + max_outstanding_bytes=( + 0 if self._use_legacy_flow_control else self._flow_control.max_bytes + ), + ) + + # Return the initial request. + return request + + def _send_lease_modacks( + self, ack_ids: Iterable[str], ack_deadline: float, warn_on_invalid=True + ) -> List[str]: + exactly_once_enabled = False + with self._exactly_once_enabled_lock: + exactly_once_enabled = self._exactly_once_enabled + if exactly_once_enabled: + items = [] + for ack_id in ack_ids: + future = futures.Future() + request = requests.ModAckRequest(ack_id, ack_deadline, future) + items.append(request) + + assert self._dispatcher is not None + self._dispatcher.modify_ack_deadline(items) + + expired_ack_ids = [] + for req in items: + try: + assert req.future is not None + req.future.result() + except AcknowledgeError as ack_error: + if ( + ack_error.error_code != AcknowledgeStatus.INVALID_ACK_ID + or warn_on_invalid + ): + _LOGGER.warning( + "AcknowledgeError when lease-modacking a message.", + exc_info=True, + ) + if ack_error.error_code == AcknowledgeStatus.INVALID_ACK_ID: + expired_ack_ids.append(req.ack_id) + return expired_ack_ids + else: + items = [ + requests.ModAckRequest(ack_id, self.ack_deadline, None) + for ack_id in ack_ids + ] + assert self._dispatcher is not None + self._dispatcher.modify_ack_deadline(items) + return [] + + def _exactly_once_delivery_enabled(self) -> bool: + """Whether exactly-once delivery is enabled for the subscription.""" + with self._exactly_once_enabled_lock: + return self._exactly_once_enabled + + def _on_response(self, response: gapic_types.StreamingPullResponse) -> None: + """Process all received Pub/Sub messages. + + For each message, send a modified acknowledgment request to the + server. This prevents expiration of the message due to buffering by + gRPC or proxy/firewall. This makes the server and client expiration + timer closer to each other thus preventing the message being + redelivered multiple times. + + After the messages have all had their ack deadline updated, execute + the callback for each message using the executor. + """ + if response is None: + _LOGGER.debug( + "Response callback invoked with None, likely due to a " + "transport shutdown." + ) + return + + # IMPORTANT: Circumvent the wrapper class and operate on the raw underlying + # protobuf message to significantly gain on attribute access performance. + received_messages = response._pb.received_messages + + _LOGGER.debug( + "Processing %s received message(s), currently on hold %s (bytes %s).", + len(received_messages), + self._messages_on_hold.size, + self._on_hold_bytes, + ) + + with self._exactly_once_enabled_lock: + if ( + response.subscription_properties.exactly_once_delivery_enabled + != self._exactly_once_enabled + ): + self._exactly_once_enabled = ( + response.subscription_properties.exactly_once_delivery_enabled + ) + # Update ack_deadline, whose minimum depends on self._exactly_once_enabled + # This method acquires the self._ack_deadline_lock lock. + self._obtain_ack_deadline(maybe_update=True) + self._send_new_ack_deadline = True + + # Immediately (i.e. without waiting for the auto lease management) + # modack the messages we received, as this tells the server that we've + # received them. + ack_id_gen = (message.ack_id for message in received_messages) + expired_ack_ids = set( + self._send_lease_modacks( + ack_id_gen, self.ack_deadline, warn_on_invalid=False + ) + ) + + with self._pause_resume_lock: + assert self._scheduler is not None + assert self._leaser is not None + + for received_message in received_messages: + if ( + not self._exactly_once_delivery_enabled() + or received_message.ack_id not in expired_ack_ids + ): + message = google.cloud.pubsub_v1.subscriber.message.Message( + received_message.message, + received_message.ack_id, + received_message.delivery_attempt, + self._scheduler.queue, + self._exactly_once_delivery_enabled, + ) + self._messages_on_hold.put(message) + self._on_hold_bytes += message.size + req = requests.LeaseRequest( + ack_id=message.ack_id, + byte_size=message.size, + ordering_key=message.ordering_key, + ) + self._leaser.add([req]) + + self._maybe_release_messages() + + self.maybe_pause_consumer() + + def _should_recover(self, exception: BaseException) -> bool: + """Determine if an error on the RPC stream should be recovered. + + If the exception is one of the retryable exceptions, this will signal + to the consumer thread that it should "recover" from the failure. + + This will cause the stream to exit when it returns :data:`False`. + + Returns: + Indicates if the caller should recover or shut down. + Will be :data:`True` if the ``exception`` is "acceptable", i.e. + in a list of retryable / idempotent exceptions. + """ + exception = _wrap_as_exception(exception) + # If this is in the list of idempotent exceptions, then we want to + # recover. + if isinstance(exception, _RETRYABLE_STREAM_ERRORS): + _LOGGER.debug("Observed recoverable stream error %s", exception) + return True + _LOGGER.debug("Observed non-recoverable stream error %s", exception) + return False + + def _should_terminate(self, exception: BaseException) -> bool: + """Determine if an error on the RPC stream should be terminated. + + If the exception is one of the terminating exceptions, this will signal + to the consumer thread that it should terminate. + + This will cause the stream to exit when it returns :data:`True`. + + Returns: + Indicates if the caller should terminate or attempt recovery. + Will be :data:`True` if the ``exception`` is "acceptable", i.e. + in a list of terminating exceptions. + """ + exception = _wrap_as_exception(exception) + if isinstance(exception, _TERMINATING_STREAM_ERRORS): + _LOGGER.debug("Observed terminating stream error %s", exception) + return True + _LOGGER.debug("Observed non-terminating stream error %s", exception) + return False + + def _on_rpc_done(self, future: Any) -> None: + """Triggered whenever the underlying RPC terminates without recovery. + + This is typically triggered from one of two threads: the background + consumer thread (when calling ``recv()`` produces a non-recoverable + error) or the grpc management thread (when cancelling the RPC). + + This method is *non-blocking*. It will start another thread to deal + with shutting everything down. This is to prevent blocking in the + background consumer and preventing it from being ``joined()``. + """ + _LOGGER.debug("RPC termination has signaled streaming pull manager shutdown.") + error = _wrap_as_exception(future) + thread = threading.Thread( + name=_RPC_ERROR_THREAD_NAME, target=self._shutdown, kwargs={"reason": error} + ) + thread.daemon = True + thread.start() diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/client.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/client.py new file mode 100644 index 000000000000..9c12a0bfba3f --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/client.py @@ -0,0 +1,289 @@ +# Copyright 2019, Google LLC 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. + +from __future__ import absolute_import + +import os +import pkg_resources +import typing +from typing import cast, Any, Callable, Optional, Sequence, Union +import warnings + +from google.auth.credentials import AnonymousCredentials # type: ignore +from google.oauth2 import service_account # type: ignore + +from google.cloud.pubsub_v1 import types +from google.cloud.pubsub_v1.subscriber import futures +from google.cloud.pubsub_v1.subscriber._protocol import streaming_pull_manager +from google.pubsub_v1.services.subscriber import client as subscriber_client + +if typing.TYPE_CHECKING: # pragma: NO COVER + from google.cloud.pubsub_v1 import subscriber + from google.pubsub_v1.services.subscriber.transports.grpc import ( + SubscriberGrpcTransport, + ) + + +try: + __version__ = pkg_resources.get_distribution("google-cloud-pubsub").version +except pkg_resources.DistributionNotFound: + # Distribution might not be available if we are not running from within + # a PIP package. + __version__ = "0.0" + + +class Client(subscriber_client.SubscriberClient): + """A subscriber client for Google Cloud Pub/Sub. + + This creates an object that is capable of subscribing to messages. + Generally, you can instantiate this client with no arguments, and you + get sensible defaults. + + Args: + kwargs: Any additional arguments provided are sent as keyword + keyword arguments to the underlying + :class:`~google.cloud.pubsub_v1.gapic.subscriber_client.SubscriberClient`. + Generally you should not need to set additional keyword + arguments. Optionally, regional endpoints can be set via + ``client_options`` that takes a single key-value pair that + defines the endpoint. + + Example: + + .. code-block:: python + + from google.cloud import pubsub_v1 + + subscriber_client = pubsub_v1.SubscriberClient( + # Optional + client_options = { + "api_endpoint": REGIONAL_ENDPOINT + } + ) + """ + + def __init__(self, **kwargs: Any): + # Sanity check: Is our goal to use the emulator? + # If so, create a grpc insecure channel with the emulator host + # as the target. + if os.environ.get("PUBSUB_EMULATOR_HOST"): + kwargs["client_options"] = { + "api_endpoint": os.environ.get("PUBSUB_EMULATOR_HOST") + } + kwargs["credentials"] = AnonymousCredentials() + + # Instantiate the underlying GAPIC client. + super().__init__(**kwargs) + self._target = self._transport._host + self._closed = False + + @classmethod + def from_service_account_file( # type: ignore[override] + cls, filename: str, **kwargs: Any + ) -> "Client": + """Creates an instance of this client using the provided credentials + file. + + Args: + filename: The path to the service account private key json file. + kwargs: Additional arguments to pass to the constructor. + + Returns: + A Subscriber :class:`~google.cloud.pubsub_v1.subscriber.client.Client` + instance that is the constructed client. + """ + credentials = service_account.Credentials.from_service_account_file(filename) + kwargs["credentials"] = credentials + return cls(**kwargs) + + from_service_account_json = from_service_account_file # type: ignore[assignment] + + @property + def target(self) -> str: + """Return the target (where the API is). + + Returns: + The location of the API. + """ + return self._target + + @property + def closed(self) -> bool: + """Return whether the client has been closed and cannot be used anymore. + + .. versionadded:: 2.8.0 + """ + return self._closed + + @property + def api(self): + """The underlying gapic API client. + + .. versionchanged:: 2.10.0 + Instead of a GAPIC ``SubscriberClient`` client instance, this property is a + proxy object to it with the same interface. + + .. deprecated:: 2.10.0 + Use the GAPIC methods and properties on the client instance directly + instead of through the :attr:`api` attribute. + """ + msg = ( + 'The "api" property only exists for backward compatibility, access its ' + 'attributes directly thorugh the client instance (e.g. "client.foo" ' + 'instead of "client.api.foo").' + ) + warnings.warn(msg, category=DeprecationWarning) + return super() + + def subscribe( + self, + subscription: str, + callback: Callable[["subscriber.message.Message"], Any], + flow_control: Union[types.FlowControl, Sequence] = (), + scheduler: Optional["subscriber.scheduler.ThreadScheduler"] = None, + use_legacy_flow_control: bool = False, + await_callbacks_on_shutdown: bool = False, + ) -> futures.StreamingPullFuture: + """Asynchronously start receiving messages on a given subscription. + + This method starts a background thread to begin pulling messages from + a Pub/Sub subscription and scheduling them to be processed using the + provided ``callback``. + + The ``callback`` will be called with an individual + :class:`google.cloud.pubsub_v1.subscriber.message.Message`. It is the + responsibility of the callback to either call ``ack()`` or ``nack()`` + on the message when it finished processing. If an exception occurs in + the callback during processing, the exception is logged and the message + is ``nack()`` ed. + + The ``flow_control`` argument can be used to control the rate of at + which messages are pulled. The settings are relatively conservative by + default to prevent "message hoarding" - a situation where the client + pulls a large number of messages but can not process them fast enough + leading it to "starve" other clients of messages. Increasing these + settings may lead to faster throughput for messages that do not take + a long time to process. + + The ``use_legacy_flow_control`` argument disables enforcing flow control + settings at the Cloud Pub/Sub server, and only the client side flow control + will be enforced. + + This method starts the receiver in the background and returns a + *Future* representing its execution. Waiting on the future (calling + ``result()``) will block forever or until a non-recoverable error + is encountered (such as loss of network connectivity). Cancelling the + future will signal the process to shutdown gracefully and exit. + + .. note:: This uses Pub/Sub's *streaming pull* feature. This feature + properties that may be surprising. Please take a look at + https://cloud.google.com/pubsub/docs/pull#streamingpull for + more details on how streaming pull behaves compared to the + synchronous pull method. + + Example: + + .. code-block:: python + + from google.cloud import pubsub_v1 + + subscriber_client = pubsub_v1.SubscriberClient() + + # existing subscription + subscription = subscriber_client.subscription_path( + 'my-project-id', 'my-subscription') + + def callback(message): + print(message) + message.ack() + + future = subscriber_client.subscribe( + subscription, callback) + + try: + future.result() + except KeyboardInterrupt: + future.cancel() # Trigger the shutdown. + future.result() # Block until the shutdown is complete. + + Args: + subscription: + The name of the subscription. The subscription should have already been + created (for example, by using :meth:`create_subscription`). + callback: + The callback function. This function receives the message as + its only argument and will be called from a different thread/ + process depending on the scheduling strategy. + flow_control: + The flow control settings. Use this to prevent situations where you are + inundated with too many messages at once. + scheduler: + An optional *scheduler* to use when executing the callback. This + controls how callbacks are executed concurrently. This object must not + be shared across multiple ``SubscriberClient`` instances. + use_legacy_flow_control (bool): + If set to ``True``, flow control at the Cloud Pub/Sub server is disabled, + though client-side flow control is still enabled. If set to ``False`` + (default), both server-side and client-side flow control are enabled. + await_callbacks_on_shutdown: + If ``True``, after canceling the returned future, the latter's + ``result()`` method will block until the background stream and its + helper threads have been terminated, and all currently executing message + callbacks are done processing. + + If ``False`` (default), the returned future's ``result()`` method will + not block after canceling the future. The method will instead return + immediately after the background stream and its helper threads have been + terminated, but some of the message callback threads might still be + running at that point. + + Returns: + A future instance that can be used to manage the background stream. + """ + flow_control = types.FlowControl(*flow_control) + + manager = streaming_pull_manager.StreamingPullManager( + self, + subscription, + flow_control=flow_control, + scheduler=scheduler, + use_legacy_flow_control=use_legacy_flow_control, + await_callbacks_on_shutdown=await_callbacks_on_shutdown, + ) + + future = futures.StreamingPullFuture(manager) + + manager.open(callback=callback, on_callback_error=future.set_exception) + + return future + + def close(self) -> None: + """Close the underlying channel to release socket resources. + + After a channel has been closed, the client instance cannot be used + anymore. + + This method is idempotent. + """ + transport = cast("SubscriberGrpcTransport", self._transport) + transport.grpc_channel.close() + self._closed = True + + def __enter__(self) -> "Client": + if self._closed: + raise RuntimeError("Closed subscriber cannot be used as context manager.") + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.close() diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/exceptions.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/exceptions.py new file mode 100644 index 000000000000..a5dad31a9998 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/exceptions.py @@ -0,0 +1,44 @@ +# Copyright 2017, Google LLC 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. + +from __future__ import absolute_import + +from enum import Enum +from google.api_core.exceptions import GoogleAPICallError +from typing import Optional + + +class AcknowledgeStatus(Enum): + SUCCESS = 1 + PERMISSION_DENIED = 2 + FAILED_PRECONDITION = 3 + INVALID_ACK_ID = 4 + OTHER = 5 + + +class AcknowledgeError(GoogleAPICallError): + """Error during ack/modack/nack operation on exactly-once-enabled subscription.""" + + def __init__(self, error_code: AcknowledgeStatus, info: Optional[str]): + self.error_code = error_code + self.info = info + message = None + if info: + message = str(self.error_code) + " : " + str(self.info) + else: + message = str(self.error_code) + super(AcknowledgeError, self).__init__(message) + + +__all__ = ("AcknowledgeError",) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/futures.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/futures.py new file mode 100644 index 000000000000..f043b7eb517e --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/futures.py @@ -0,0 +1,125 @@ +# Copyright 2017, Google LLC 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. + +from __future__ import absolute_import + +import typing +from typing import Any +from typing import Union + +from google.cloud.pubsub_v1 import futures +from google.cloud.pubsub_v1.subscriber.exceptions import AcknowledgeStatus + +if typing.TYPE_CHECKING: # pragma: NO COVER + from google.cloud.pubsub_v1.subscriber._protocol.streaming_pull_manager import ( + StreamingPullManager, + ) + + +class StreamingPullFuture(futures.Future): + """Represents a process that asynchronously performs streaming pull and + schedules messages to be processed. + + This future is resolved when the process is stopped (via :meth:`cancel`) or + if it encounters an unrecoverable error. Calling `.result()` will cause + the calling thread to block indefinitely. + """ + + def __init__(self, manager: "StreamingPullManager"): + super(StreamingPullFuture, self).__init__() + self.__manager = manager + self.__manager.add_close_callback(self._on_close_callback) + self.__cancelled = False + + def _on_close_callback(self, manager: "StreamingPullManager", result: Any): + if self.done(): + # The future has already been resolved in a different thread, + # nothing to do on the streaming pull manager shutdown. + return + + if result is None: + self.set_result(True) + else: + self.set_exception(result) + + def cancel(self) -> bool: + """Stops pulling messages and shutdowns the background thread consuming + messages. + + The method always returns ``True``, as the shutdown is always initiated. + However, if the background stream is already being shut down or the shutdown + has completed, this method is a no-op. + + .. versionchanged:: 2.4.1 + The method does not block anymore, it just triggers the shutdown and returns + immediately. To block until the background stream is terminated, call + :meth:`result()` after cancelling the future. + + .. versionchanged:: 2.10.0 + The method always returns ``True`` instead of ``None``. + """ + # NOTE: We circumvent the base future's self._state to track the cancellation + # state, as this state has different meaning with streaming pull futures. + self.__cancelled = True + self.__manager.close() + return True + + def cancelled(self) -> bool: + """ + Returns: + ``True`` if the subscription has been cancelled. + """ + return self.__cancelled + + +class Future(futures.Future): + """This future object is for subscribe-side calls. + + Calling :meth:`result` will resolve the future by returning the message + ID, unless an error occurs. + """ + + def cancel(self) -> bool: + """Actions in Pub/Sub generally may not be canceled. + + This method always returns ``False``. + """ + return False + + def cancelled(self) -> bool: + """Actions in Pub/Sub generally may not be canceled. + + This method always returns ``False``. + """ + return False + + def result(self, timeout: Union[int, float] = None) -> AcknowledgeStatus: + """Return a success code or raise an exception. + + This blocks until the operation completes successfully and + returns the error code unless an exception is raised. + + Args: + timeout: The number of seconds before this call + times out and raises TimeoutError. + + Returns: + AcknowledgeStatus.SUCCESS if the operation succeeded. + + Raises: + concurrent.futures.TimeoutError: If the request times out. + AcknowledgeError: If the operation did not succeed for another + reason. + """ + return super().result(timeout=timeout) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/message.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/message.py new file mode 100644 index 000000000000..c0a2e70ea965 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/message.py @@ -0,0 +1,488 @@ +# Copyright 2017, Google LLC 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. + +from __future__ import absolute_import + +import datetime as dt +import json +import math +import time +import typing +from typing import Optional, Callable + +from google.cloud.pubsub_v1.subscriber._protocol import requests +from google.cloud.pubsub_v1.subscriber import futures +from google.cloud.pubsub_v1.subscriber.exceptions import AcknowledgeStatus + + +if typing.TYPE_CHECKING: # pragma: NO COVER + import datetime + import queue + from google.cloud.pubsub_v1 import types + from google.protobuf.internal import containers + + +_MESSAGE_REPR = """\ +Message {{ + data: {!r} + ordering_key: {!r} + attributes: {} +}}""" + +_SUCCESS_FUTURE = futures.Future() +_SUCCESS_FUTURE.set_result(AcknowledgeStatus.SUCCESS) + + +def _indent(lines: str, prefix: str = " ") -> str: + """Indent some text. + + Note that this is present as ``textwrap.indent``, but not in Python 2. + + Args: + lines: + The newline delimited string to be indented. + prefix: + The prefix to indent each line with. Defaults to two spaces. + + Returns: + The newly indented content. + """ + indented = [] + for line in lines.split("\n"): + indented.append(prefix + line) + return "\n".join(indented) + + +class Message(object): + """A representation of a single Pub/Sub message. + + The common way to interact with + :class:`~.pubsub_v1.subscriber.message.Message` objects is to receive + them in callbacks on subscriptions; most users should never have a need + to instantiate them by hand. (The exception to this is if you are + implementing a custom subclass to + :class:`~.pubsub_v1.subscriber._consumer.Consumer`.) + + Attributes: + message_id: + The message ID. In general, you should not need to use this directly. + data: + The data in the message. Note that this will be a :class:`bytes`, + not a text string. + attributes: + The attributes sent along with the message. See :attr:`attributes` for more + information on this type. + publish_time: + The time that this message was originally published. + """ + + def __init__( + self, + message: "types.PubsubMessage._meta._pb", # type: ignore + ack_id: str, + delivery_attempt: int, + request_queue: "queue.Queue", + exactly_once_delivery_enabled_func: Callable[[], bool] = lambda: False, + ): + """Construct the Message. + + .. note:: + + This class should not be constructed directly; it is the + responsibility of :class:`BasePolicy` subclasses to do so. + + Args: + message: + The message received from Pub/Sub. For performance reasons it should be + the raw protobuf message normally wrapped by + :class:`~pubsub_v1.types.PubsubMessage`. A raw message can be obtained + from a :class:`~pubsub_v1.types.PubsubMessage` instance through the + latter's ``._pb`` attribute. + ack_id: + The ack_id received from Pub/Sub. + delivery_attempt: + The delivery attempt counter received from Pub/Sub if a DeadLetterPolicy + is set on the subscription, and zero otherwise. + request_queue: + A queue provided by the policy that can accept requests; the policy is + responsible for handling those requests. + exactly_once_delivery_enabled_func: + A Callable that returns whether exactly-once delivery is currently-enabled. Defaults to a lambda that always returns False. + """ + self._message = message + self._ack_id = ack_id + self._delivery_attempt = delivery_attempt if delivery_attempt > 0 else None + self._request_queue = request_queue + self._exactly_once_delivery_enabled_func = exactly_once_delivery_enabled_func + self.message_id = message.message_id + + # The instantiation time is the time that this message + # was received. Tracking this provides us a way to be smart about + # the default lease deadline. + self._received_timestamp = time.time() + + # Store the message attributes directly to speed up attribute access, i.e. + # to avoid two lookups if self._message. pattern was used in + # properties. + self._attributes = message.attributes + self._data = message.data + self._publish_time = dt.datetime.fromtimestamp( + message.publish_time.seconds + message.publish_time.nanos / 1e9, + tz=dt.timezone.utc, + ) + self._ordering_key = message.ordering_key + self._size = message.ByteSize() + + def __repr__(self): + # Get an abbreviated version of the data. + abbv_data = self._message.data + if len(abbv_data) > 50: + abbv_data = abbv_data[:50] + b"..." + + pretty_attrs = json.dumps( + dict(self.attributes), indent=2, separators=(",", ": "), sort_keys=True + ) + pretty_attrs = _indent(pretty_attrs) + # We don't actually want the first line indented. + pretty_attrs = pretty_attrs.lstrip() + return _MESSAGE_REPR.format(abbv_data, str(self.ordering_key), pretty_attrs) + + @property + def attributes(self) -> "containers.ScalarMap": + """Return the attributes of the underlying Pub/Sub Message. + + .. warning:: + + A ``ScalarMap`` behaves slightly differently than a + ``dict``. For a Pub / Sub message this is a ``string->string`` map. + When trying to access a value via ``map['key']``, if the key is + not in the map, then the default value for the string type will + be returned, which is an empty string. It may be more intuitive + to just cast the map to a ``dict`` or to one use ``map.get``. + + Returns: + The message's attributes. This is a ``dict``-like object provided by + ``google.protobuf``. + """ + return self._attributes + + @property + def data(self) -> bytes: + """Return the data for the underlying Pub/Sub Message. + + Returns: + The message data. This is always a bytestring; if you want a text string, + call :meth:`bytes.decode`. + """ + return self._data + + @property + def publish_time(self) -> "datetime.datetime": + """Return the time that the message was originally published. + + Returns: + The date and time that the message was published. + """ + return self._publish_time + + @property + def ordering_key(self) -> str: + """The ordering key used to publish the message.""" + return self._ordering_key + + @property + def size(self) -> int: + """Return the size of the underlying message, in bytes.""" + return self._size + + @property + def ack_id(self) -> str: + """the ID used to ack the message.""" + return self._ack_id + + @property + def delivery_attempt(self) -> Optional[int]: + """The delivery attempt counter is 1 + (the sum of number of NACKs + and number of ack_deadline exceeds) for this message. It is set to None + if a DeadLetterPolicy is not set on the subscription. + + A NACK is any call to ModifyAckDeadline with a 0 deadline. An ack_deadline + exceeds event is whenever a message is not acknowledged within + ack_deadline. Note that ack_deadline is initially + Subscription.ackDeadlineSeconds, but may get extended automatically by + the client library. + + The first delivery of a given message will have this value as 1. The value + is calculated at best effort and is approximate. + + Returns: + The delivery attempt counter or ``None``. + """ + return self._delivery_attempt + + def ack(self) -> None: + """Acknowledge the given message. + + Acknowledging a message in Pub/Sub means that you are done + with it, and it will not be delivered to this subscription again. + You should avoid acknowledging messages until you have + *finished* processing them, so that in the event of a failure, + you receive the message again. + + .. warning:: + Acks in Pub/Sub are best effort. You should always + ensure that your processing code is idempotent, as you may + receive any given message more than once. If you need strong + guarantees about acks and re-deliveres, enable exactly-once + delivery on your subscription and use the `ack_with_response` + method instead. Exactly once delivery is a preview feature. + For more details, see: + https://cloud.google.com/pubsub/docs/exactly-once-delivery." + + """ + time_to_ack = math.ceil(time.time() - self._received_timestamp) + self._request_queue.put( + requests.AckRequest( + ack_id=self._ack_id, + byte_size=self.size, + time_to_ack=time_to_ack, + ordering_key=self.ordering_key, + future=None, + ) + ) + + def ack_with_response(self) -> "futures.Future": + """Acknowledge the given message. + + Acknowledging a message in Pub/Sub means that you are done + with it, and it will not be delivered to this subscription again. + You should avoid acknowledging messages until you have + *finished* processing them, so that in the event of a failure, + you receive the message again. + + If exactly-once delivery is NOT enabled on the subscription, the + future returns immediately with an AcknowledgeStatus.SUCCESS. + Since acks in Cloud Pub/Sub are best effort when exactly-once + delivery is disabled, the message may be re-delivered. Because + re-deliveries are possible, you should ensure that your processing + code is idempotent, as you may receive any given message more than + once. + + If exactly-once delivery is enabled on the subscription, the + future returned by this method tracks the state of acknowledgement + operation. If the future completes successfully, the message is + guaranteed NOT to be re-delivered. Otherwise, the future will + contain an exception with more details about the failure and the + message may be re-delivered. + + Exactly once delivery is a preview feature. For more details, + see https://cloud.google.com/pubsub/docs/exactly-once-delivery." + + Returns: + A :class:`~google.cloud.pubsub_v1.subscriber.futures.Future` + instance that conforms to Python Standard library's + :class:`~concurrent.futures.Future` interface (but not an + instance of that class). Call `result()` to get the result + of the operation; upon success, a + pubsub_v1.subscriber.exceptions.AcknowledgeStatus.SUCCESS + will be returned and upon an error, an + pubsub_v1.subscriber.exceptions.AcknowledgeError exception + will be thrown. + """ + req_future: Optional[futures.Future] + if self._exactly_once_delivery_enabled_func(): + future = futures.Future() + req_future = future + else: + future = _SUCCESS_FUTURE + req_future = None + time_to_ack = math.ceil(time.time() - self._received_timestamp) + self._request_queue.put( + requests.AckRequest( + ack_id=self._ack_id, + byte_size=self.size, + time_to_ack=time_to_ack, + ordering_key=self.ordering_key, + future=req_future, + ) + ) + return future + + def drop(self) -> None: + """Release the message from lease management. + + This informs the policy to no longer hold on to the lease for this + message. Pub/Sub will re-deliver the message if it is not acknowledged + before the existing lease expires. + + .. warning:: + For most use cases, the only reason to drop a message from + lease management is on `ack` or `nack`; this library + automatically drop()s the message on `ack` or `nack`. You probably + do not want to call this method directly. + """ + self._request_queue.put( + requests.DropRequest( + ack_id=self._ack_id, byte_size=self.size, ordering_key=self.ordering_key + ) + ) + + def modify_ack_deadline(self, seconds: int) -> None: + """Resets the deadline for acknowledgement. + + New deadline will be the given value of seconds from now. + + The default implementation handles automatically modacking received messages for you; + you should not need to manually deal with setting ack deadlines. The exception case is + if you are implementing your own custom subclass of + :class:`~.pubsub_v1.subcriber._consumer.Consumer`. + + Args: + seconds: + The number of seconds to set the lease deadline to. This should be + between 0 and 600. Due to network latency, values below 10 are advised + against. + """ + self._request_queue.put( + requests.ModAckRequest(ack_id=self._ack_id, seconds=seconds, future=None) + ) + + def modify_ack_deadline_with_response(self, seconds: int) -> "futures.Future": + """Resets the deadline for acknowledgement and returns the response + status via a future. + + New deadline will be the given value of seconds from now. + + The default implementation handles automatically modacking received messages for you; + you should not need to manually deal with setting ack deadlines. The exception case is + if you are implementing your own custom subclass of + :class:`~.pubsub_v1.subcriber._consumer.Consumer`. + + If exactly-once delivery is NOT enabled on the subscription, the + future returns immediately with an AcknowledgeStatus.SUCCESS. + Since modify-ack-deadline operations in Cloud Pub/Sub are best effort + when exactly-once delivery is disabled, the message may be re-delivered + within the set deadline. + + If exactly-once delivery is enabled on the subscription, the + future returned by this method tracks the state of the + modify-ack-deadline operation. If the future completes successfully, + the message is guaranteed NOT to be re-delivered within the new deadline. + Otherwise, the future will contain an exception with more details about + the failure and the message will be redelivered according to its + currently-set ack deadline. + + Exactly once delivery is a preview feature. For more details, + see https://cloud.google.com/pubsub/docs/exactly-once-delivery." + + Args: + seconds: + The number of seconds to set the lease deadline to. This should be + between 0 and 600. Due to network latency, values below 10 are advised + against. + Returns: + A :class:`~google.cloud.pubsub_v1.subscriber.futures.Future` + instance that conforms to Python Standard library's + :class:`~concurrent.futures.Future` interface (but not an + instance of that class). Call `result()` to get the result + of the operation; upon success, a + pubsub_v1.subscriber.exceptions.AcknowledgeStatus.SUCCESS + will be returned and upon an error, an + pubsub_v1.subscriber.exceptions.AcknowledgeError exception + will be thrown. + + """ + req_future: Optional[futures.Future] + if self._exactly_once_delivery_enabled_func(): + future = futures.Future() + req_future = future + else: + future = _SUCCESS_FUTURE + req_future = None + + self._request_queue.put( + requests.ModAckRequest( + ack_id=self._ack_id, seconds=seconds, future=req_future + ) + ) + + return future + + def nack(self) -> None: + """Decline to acknowledge the given message. + + This will cause the message to be re-delivered to subscribers. Re-deliveries + may take place immediately or after a delay, and may arrive at this subscriber + or another. + """ + self._request_queue.put( + requests.NackRequest( + ack_id=self._ack_id, + byte_size=self.size, + ordering_key=self.ordering_key, + future=None, + ) + ) + + def nack_with_response(self) -> "futures.Future": + """Decline to acknowledge the given message, returning the response status via + a future. + + This will cause the message to be re-delivered to subscribers. Re-deliveries + may take place immediately or after a delay, and may arrive at this subscriber + or another. + + If exactly-once delivery is NOT enabled on the subscription, the + future returns immediately with an AcknowledgeStatus.SUCCESS. + + If exactly-once delivery is enabled on the subscription, the + future returned by this method tracks the state of the + nack operation. If the future completes successfully, + the future's result will be an AcknowledgeStatus.SUCCESS. + Otherwise, the future will contain an exception with more details about + the failure. + + Exactly once delivery is a preview feature. For more details, + see https://cloud.google.com/pubsub/docs/exactly-once-delivery." + + Returns: + A :class:`~google.cloud.pubsub_v1.subscriber.futures.Future` + instance that conforms to Python Standard library's + :class:`~concurrent.futures.Future` interface (but not an + instance of that class). Call `result()` to get the result + of the operation; upon success, a + pubsub_v1.subscriber.exceptions.AcknowledgeStatus.SUCCESS + will be returned and upon an error, an + pubsub_v1.subscriber.exceptions.AcknowledgeError exception + will be thrown. + + """ + req_future: Optional[futures.Future] + if self._exactly_once_delivery_enabled_func(): + future = futures.Future() + req_future = future + else: + future = _SUCCESS_FUTURE + req_future = None + + self._request_queue.put( + requests.NackRequest( + ack_id=self._ack_id, + byte_size=self.size, + ordering_key=self.ordering_key, + future=req_future, + ) + ) + + return future diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/scheduler.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/scheduler.py new file mode 100644 index 000000000000..ca270a077dfb --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/scheduler.py @@ -0,0 +1,170 @@ +# Copyright 2018, Google LLC +# +# 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 +# +# https://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. + +"""Schedulers provide means to *schedule* callbacks asynchronously. + +These are used by the subscriber to call the user-provided callback to process +each message. +""" + +import abc +import concurrent.futures +import queue +import typing +from typing import Callable, List, Optional +import warnings + +if typing.TYPE_CHECKING: # pragma: NO COVER + from google.cloud import pubsub_v1 + + +class Scheduler(metaclass=abc.ABCMeta): + """Abstract base class for schedulers. + + Schedulers are used to schedule callbacks asynchronously. + """ + + @property + @abc.abstractmethod + def queue(self) -> queue.Queue: # pragma: NO COVER + """Queue: A concurrency-safe queue specific to the underlying + concurrency implementation. + + This queue is used to send messages *back* to the scheduling actor. + """ + raise NotImplementedError + + @abc.abstractmethod + def schedule(self, callback: Callable, *args, **kwargs) -> None: # pragma: NO COVER + """Schedule the callback to be called asynchronously. + + Args: + callback: The function to call. + args: Positional arguments passed to the callback. + kwargs: Key-word arguments passed to the callback. + + Returns: + None + """ + raise NotImplementedError + + @abc.abstractmethod + def shutdown( + self, await_msg_callbacks: bool = False + ) -> List["pubsub_v1.subscriber.message.Message"]: # pragma: NO COVER + """Shuts down the scheduler and immediately end all pending callbacks. + + Args: + await_msg_callbacks: + If ``True``, the method will block until all currently executing + callbacks are done processing. If ``False`` (default), the + method will not wait for the currently running callbacks to complete. + + Returns: + The messages submitted to the scheduler that were not yet dispatched + to their callbacks. + It is assumed that each message was submitted to the scheduler as the + first positional argument to the provided callback. + """ + raise NotImplementedError + + +def _make_default_thread_pool_executor() -> concurrent.futures.ThreadPoolExecutor: + return concurrent.futures.ThreadPoolExecutor( + max_workers=10, thread_name_prefix="ThreadPoolExecutor-ThreadScheduler" + ) + + +class ThreadScheduler(Scheduler): + """A thread pool-based scheduler. It must not be shared across + SubscriberClients. + + This scheduler is useful in typical I/O-bound message processing. + + Args: + executor: + An optional executor to use. If not specified, a default one + will be created. + """ + + def __init__( + self, executor: Optional[concurrent.futures.ThreadPoolExecutor] = None + ): + self._queue: queue.Queue = queue.Queue() + if executor is None: + self._executor = _make_default_thread_pool_executor() + else: + self._executor = executor + + @property + def queue(self): + """Queue: A thread-safe queue used for communication between callbacks + and the scheduling thread.""" + return self._queue + + def schedule(self, callback: Callable, *args, **kwargs) -> None: + """Schedule the callback to be called asynchronously in a thread pool. + + Args: + callback: The function to call. + args: Positional arguments passed to the callback. + kwargs: Key-word arguments passed to the callback. + + Returns: + None + """ + try: + self._executor.submit(callback, *args, **kwargs) + except RuntimeError: + warnings.warn( + "Scheduling a callback after executor shutdown.", + category=RuntimeWarning, + stacklevel=2, + ) + + def shutdown( + self, await_msg_callbacks: bool = False + ) -> List["pubsub_v1.subscriber.message.Message"]: + """Shut down the scheduler and immediately end all pending callbacks. + + Args: + await_msg_callbacks: + If ``True``, the method will block until all currently executing + executor threads are done processing. If ``False`` (default), the + method will not wait for the currently running threads to complete. + + Returns: + The messages submitted to the scheduler that were not yet dispatched + to their callbacks. + It is assumed that each message was submitted to the scheduler as the + first positional argument to the provided callback. + """ + dropped_messages = [] + + # Drop all pending item from the executor. Without this, the executor will also + # try to process any pending work items before termination, which is undesirable. + # + # TODO: Replace the logic below by passing `cancel_futures=True` to shutdown() + # once we only need to support Python 3.9+. + try: + while True: + work_item = self._executor._work_queue.get(block=False) + if work_item is None: # Exceutor in shutdown mode. + continue + dropped_messages.append(work_item.args[0]) + except queue.Empty: + pass + + self._executor.shutdown(wait=await_msg_callbacks) + return dropped_messages diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/types.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/types.py new file mode 100644 index 000000000000..109d4aadc8a7 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/cloud/pubsub_v1/types.py @@ -0,0 +1,238 @@ +# Copyright 2017, Google LLC 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. + +from __future__ import absolute_import + +import collections +import enum +import inspect +import sys +import typing +from typing import Dict, NamedTuple, Union + +import proto # type: ignore + +from google.api import http_pb2 # type: ignore +from google.api_core import gapic_v1 +from google.iam.v1 import iam_policy_pb2 # type: ignore +from google.iam.v1 import policy_pb2 +from google.iam.v1.logging import audit_data_pb2 # type: ignore +from google.protobuf import descriptor_pb2 +from google.protobuf import duration_pb2 +from google.protobuf import empty_pb2 +from google.protobuf import field_mask_pb2 +from google.protobuf import timestamp_pb2 + +from google.api_core.protobuf_helpers import get_messages + +from google.pubsub_v1.types import pubsub as pubsub_gapic_types + + +if typing.TYPE_CHECKING: # pragma: NO COVER + from types import ModuleType + from google.pubsub_v1 import types as gapic_types + from google.pubsub_v1.services.publisher.client import OptionalRetry + + # TODO: Eventually implement OptionalTimeout in the GAPIC code generator and import + # it from the generated code. It's the same solution that is used for OptionalRetry. + # https://github.com/googleapis/gapic-generator-python/pull/1032/files + # https://github.com/googleapis/gapic-generator-python/pull/1065/files + if hasattr(gapic_v1.method, "_MethodDefault"): + # _MethodDefault was only added in google-api-core==2.2.2 + OptionalTimeout = Union[gapic_types.TimeoutType, gapic_v1.method._MethodDefault] + else: + OptionalTimeout = Union[gapic_types.TimeoutType, object] # type: ignore + + +# Define the default values for batching. +# +# This class is used when creating a publisher or subscriber client, and +# these settings can be altered to tweak Pub/Sub behavior. +# The defaults should be fine for most use cases. +class BatchSettings(NamedTuple): + """The settings for batch publishing the messages.""" + + max_bytes: int = 1 * 1000 * 1000 # 1 MB + ( + "The maximum total size of the messages to collect before automatically " + "publishing the batch, including any byte size overhead of the publish " + "request itself. The maximum value is bound by the server-side limit of " + "10_000_000 bytes." + ) + + max_latency: float = 0.01 # 10 ms + ( + "The maximum number of seconds to wait for additional messages before " + "automatically publishing the batch." + ) + + max_messages: int = 100 + ( + "The maximum number of messages to collect before automatically " + "publishing the batch." + ) + + +class LimitExceededBehavior(str, enum.Enum): + """The possible actions when exceeding the publish flow control limits.""" + + IGNORE = "ignore" + BLOCK = "block" + ERROR = "error" + + +class PublishFlowControl(NamedTuple): + """The client flow control settings for message publishing.""" + + message_limit: int = 10 * BatchSettings.__new__.__defaults__[2] # type: ignore + """The maximum number of messages awaiting to be published.""" + + byte_limit: int = 10 * BatchSettings.__new__.__defaults__[0] # type: ignore + """The maximum total size of messages awaiting to be published.""" + + limit_exceeded_behavior: LimitExceededBehavior = LimitExceededBehavior.IGNORE + """The action to take when publish flow control limits are exceeded.""" + + +# Define the default publisher options. +# +# This class is used when creating a publisher client to pass in options +# to enable/disable features. +class PublisherOptions(NamedTuple): + """The options for the publisher client.""" + + enable_message_ordering: bool = False + """Whether to order messages in a batch by a supplied ordering key.""" + + flow_control: PublishFlowControl = PublishFlowControl() + ( + "Flow control settings for message publishing by the client. By default " + "the publisher client does not do any throttling." + ) + + retry: "OptionalRetry" = gapic_v1.method.DEFAULT # use api_core default + ( + "Retry settings for message publishing by the client. This should be " + "an instance of :class:`google.api_core.retry.Retry`." + ) + + timeout: "OptionalTimeout" = gapic_v1.method.DEFAULT # use api_core default + ( + "Timeout settings for message publishing by the client. It should be " + "compatible with :class:`~.pubsub_v1.types.TimeoutType`." + ) + + +# Define the type class and default values for flow control settings. +# +# This class is used when creating a publisher or subscriber client, and +# these settings can be altered to tweak Pub/Sub behavior. +# The defaults should be fine for most use cases. +class FlowControl(NamedTuple): + """The settings for controlling the rate at which messages are pulled + with an asynchronous subscription. + """ + + max_bytes: int = 100 * 1024 * 1024 # 100 MiB + ( + "The maximum total size of received - but not yet processed - messages " + "before pausing the message stream." + ) + + max_messages: int = 1000 + ( + "The maximum number of received - but not yet processed - messages before " + "pausing the message stream." + ) + + max_lease_duration: float = 1 * 60 * 60 # 1 hour + ( + "The maximum amount of time in seconds to hold a lease on a message " + "before dropping it from the lease management." + ) + + min_duration_per_lease_extension: float = 0 + ( + "The min amount of time in seconds for a single lease extension attempt. " + "Must be between 10 and 600 (inclusive). Ignored by default, but set to " + "60 seconds if the subscription has exactly-once delivery enabled." + ) + + max_duration_per_lease_extension: float = 0 # disabled by default + ( + "The max amount of time in seconds for a single lease extension attempt. " + "Bounds the delay before a message redelivery if the subscriber " + "fails to extend the deadline. Must be between 10 and 600 (inclusive). Ignored " + "if set to 0." + ) + + +# The current api core helper does not find new proto messages of type proto.Message, +# thus we need our own helper. Adjusted from +# https://github.com/googleapis/python-api-core/blob/8595f620e7d8295b6a379d6fd7979af3bef717e2/google/api_core/protobuf_helpers.py#L101-L118 +def _get_protobuf_messages(module: "ModuleType") -> Dict[str, proto.Message]: + """Discover all protobuf Message classes in a given import module. + + Args: + module (module): A Python module; :func:`dir` will be run against this + module to find Message subclasses. + + Returns: + dict[str, proto.Message]: A dictionary with the + Message class names as keys, and the Message subclasses themselves + as values. + """ + answer = collections.OrderedDict() + for name in dir(module): + candidate = getattr(module, name) + if inspect.isclass(candidate) and issubclass(candidate, proto.Message): + answer[name] = candidate + return answer + + +_shared_modules = [ + http_pb2, + iam_policy_pb2, + policy_pb2, + audit_data_pb2, + descriptor_pb2, + duration_pb2, + empty_pb2, + field_mask_pb2, + timestamp_pb2, +] + +_local_modules = [pubsub_gapic_types] + +names = [ + "BatchSettings", + "LimitExceededBehavior", + "PublishFlowControl", + "PublisherOptions", + "FlowControl", +] + +for module in _shared_modules: + for name, message in get_messages(module).items(): + setattr(sys.modules[__name__], name, message) + names.append(name) + +for module in _local_modules: + for name, message in _get_protobuf_messages(module).items(): + message.__module__ = "google.cloud.pubsub_v1.types" + setattr(sys.modules[__name__], name, message) + names.append(name) + + +__all__ = tuple(sorted(names)) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub/__init__.py new file mode 100644 index 000000000000..7c94c23082b0 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub/__init__.py @@ -0,0 +1,148 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# + +from google.pubsub_v1.services.publisher.client import PublisherClient +from google.pubsub_v1.services.publisher.async_client import PublisherAsyncClient +from google.pubsub_v1.services.schema_service.client import SchemaServiceClient +from google.pubsub_v1.services.schema_service.async_client import ( + SchemaServiceAsyncClient, +) +from google.pubsub_v1.services.subscriber.client import SubscriberClient +from google.pubsub_v1.services.subscriber.async_client import SubscriberAsyncClient + +from google.pubsub_v1.types.pubsub import AcknowledgeRequest +from google.pubsub_v1.types.pubsub import BigQueryConfig +from google.pubsub_v1.types.pubsub import CreateSnapshotRequest +from google.pubsub_v1.types.pubsub import DeadLetterPolicy +from google.pubsub_v1.types.pubsub import DeleteSnapshotRequest +from google.pubsub_v1.types.pubsub import DeleteSubscriptionRequest +from google.pubsub_v1.types.pubsub import DeleteTopicRequest +from google.pubsub_v1.types.pubsub import DetachSubscriptionRequest +from google.pubsub_v1.types.pubsub import DetachSubscriptionResponse +from google.pubsub_v1.types.pubsub import ExpirationPolicy +from google.pubsub_v1.types.pubsub import GetSnapshotRequest +from google.pubsub_v1.types.pubsub import GetSubscriptionRequest +from google.pubsub_v1.types.pubsub import GetTopicRequest +from google.pubsub_v1.types.pubsub import ListSnapshotsRequest +from google.pubsub_v1.types.pubsub import ListSnapshotsResponse +from google.pubsub_v1.types.pubsub import ListSubscriptionsRequest +from google.pubsub_v1.types.pubsub import ListSubscriptionsResponse +from google.pubsub_v1.types.pubsub import ListTopicSnapshotsRequest +from google.pubsub_v1.types.pubsub import ListTopicSnapshotsResponse +from google.pubsub_v1.types.pubsub import ListTopicsRequest +from google.pubsub_v1.types.pubsub import ListTopicsResponse +from google.pubsub_v1.types.pubsub import ListTopicSubscriptionsRequest +from google.pubsub_v1.types.pubsub import ListTopicSubscriptionsResponse +from google.pubsub_v1.types.pubsub import MessageStoragePolicy +from google.pubsub_v1.types.pubsub import ModifyAckDeadlineRequest +from google.pubsub_v1.types.pubsub import ModifyPushConfigRequest +from google.pubsub_v1.types.pubsub import PublishRequest +from google.pubsub_v1.types.pubsub import PublishResponse +from google.pubsub_v1.types.pubsub import PubsubMessage +from google.pubsub_v1.types.pubsub import PullRequest +from google.pubsub_v1.types.pubsub import PullResponse +from google.pubsub_v1.types.pubsub import PushConfig +from google.pubsub_v1.types.pubsub import ReceivedMessage +from google.pubsub_v1.types.pubsub import RetryPolicy +from google.pubsub_v1.types.pubsub import SchemaSettings +from google.pubsub_v1.types.pubsub import SeekRequest +from google.pubsub_v1.types.pubsub import SeekResponse +from google.pubsub_v1.types.pubsub import Snapshot +from google.pubsub_v1.types.pubsub import StreamingPullRequest +from google.pubsub_v1.types.pubsub import StreamingPullResponse +from google.pubsub_v1.types.pubsub import Subscription +from google.pubsub_v1.types.pubsub import Topic +from google.pubsub_v1.types.pubsub import UpdateSnapshotRequest +from google.pubsub_v1.types.pubsub import UpdateSubscriptionRequest +from google.pubsub_v1.types.pubsub import UpdateTopicRequest +from google.pubsub_v1.types.schema import CreateSchemaRequest +from google.pubsub_v1.types.schema import DeleteSchemaRequest +from google.pubsub_v1.types.schema import GetSchemaRequest +from google.pubsub_v1.types.schema import ListSchemasRequest +from google.pubsub_v1.types.schema import ListSchemasResponse +from google.pubsub_v1.types.schema import Schema +from google.pubsub_v1.types.schema import ValidateMessageRequest +from google.pubsub_v1.types.schema import ValidateMessageResponse +from google.pubsub_v1.types.schema import ValidateSchemaRequest +from google.pubsub_v1.types.schema import ValidateSchemaResponse +from google.pubsub_v1.types.schema import Encoding +from google.pubsub_v1.types.schema import SchemaView + +__all__ = ( + "PublisherClient", + "PublisherAsyncClient", + "SchemaServiceClient", + "SchemaServiceAsyncClient", + "SubscriberClient", + "SubscriberAsyncClient", + "AcknowledgeRequest", + "BigQueryConfig", + "CreateSnapshotRequest", + "DeadLetterPolicy", + "DeleteSnapshotRequest", + "DeleteSubscriptionRequest", + "DeleteTopicRequest", + "DetachSubscriptionRequest", + "DetachSubscriptionResponse", + "ExpirationPolicy", + "GetSnapshotRequest", + "GetSubscriptionRequest", + "GetTopicRequest", + "ListSnapshotsRequest", + "ListSnapshotsResponse", + "ListSubscriptionsRequest", + "ListSubscriptionsResponse", + "ListTopicSnapshotsRequest", + "ListTopicSnapshotsResponse", + "ListTopicsRequest", + "ListTopicsResponse", + "ListTopicSubscriptionsRequest", + "ListTopicSubscriptionsResponse", + "MessageStoragePolicy", + "ModifyAckDeadlineRequest", + "ModifyPushConfigRequest", + "PublishRequest", + "PublishResponse", + "PubsubMessage", + "PullRequest", + "PullResponse", + "PushConfig", + "ReceivedMessage", + "RetryPolicy", + "SchemaSettings", + "SeekRequest", + "SeekResponse", + "Snapshot", + "StreamingPullRequest", + "StreamingPullResponse", + "Subscription", + "Topic", + "UpdateSnapshotRequest", + "UpdateSubscriptionRequest", + "UpdateTopicRequest", + "CreateSchemaRequest", + "DeleteSchemaRequest", + "GetSchemaRequest", + "ListSchemasRequest", + "ListSchemasResponse", + "Schema", + "ValidateMessageRequest", + "ValidateMessageResponse", + "ValidateSchemaRequest", + "ValidateSchemaResponse", + "Encoding", + "SchemaView", +) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub/py.typed b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub/py.typed new file mode 100644 index 000000000000..1cec9a5ba1ab --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub/py.typed @@ -0,0 +1,2 @@ +# Marker file for PEP 561. +# The google-cloud-pubsub package uses inline types. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/__init__.py new file mode 100644 index 000000000000..80fc23d59644 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/__init__.py @@ -0,0 +1,146 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# + +from .services.publisher import PublisherClient +from .services.publisher import PublisherAsyncClient +from .services.schema_service import SchemaServiceClient +from .services.schema_service import SchemaServiceAsyncClient +from .services.subscriber import SubscriberClient +from .services.subscriber import SubscriberAsyncClient + +from .types.pubsub import AcknowledgeRequest +from .types.pubsub import BigQueryConfig +from .types.pubsub import CreateSnapshotRequest +from .types.pubsub import DeadLetterPolicy +from .types.pubsub import DeleteSnapshotRequest +from .types.pubsub import DeleteSubscriptionRequest +from .types.pubsub import DeleteTopicRequest +from .types.pubsub import DetachSubscriptionRequest +from .types.pubsub import DetachSubscriptionResponse +from .types.pubsub import ExpirationPolicy +from .types.pubsub import GetSnapshotRequest +from .types.pubsub import GetSubscriptionRequest +from .types.pubsub import GetTopicRequest +from .types.pubsub import ListSnapshotsRequest +from .types.pubsub import ListSnapshotsResponse +from .types.pubsub import ListSubscriptionsRequest +from .types.pubsub import ListSubscriptionsResponse +from .types.pubsub import ListTopicSnapshotsRequest +from .types.pubsub import ListTopicSnapshotsResponse +from .types.pubsub import ListTopicsRequest +from .types.pubsub import ListTopicsResponse +from .types.pubsub import ListTopicSubscriptionsRequest +from .types.pubsub import ListTopicSubscriptionsResponse +from .types.pubsub import MessageStoragePolicy +from .types.pubsub import ModifyAckDeadlineRequest +from .types.pubsub import ModifyPushConfigRequest +from .types.pubsub import PublishRequest +from .types.pubsub import PublishResponse +from .types.pubsub import PubsubMessage +from .types.pubsub import PullRequest +from .types.pubsub import PullResponse +from .types.pubsub import PushConfig +from .types.pubsub import ReceivedMessage +from .types.pubsub import RetryPolicy +from .types.pubsub import SchemaSettings +from .types.pubsub import SeekRequest +from .types.pubsub import SeekResponse +from .types.pubsub import Snapshot +from .types.pubsub import StreamingPullRequest +from .types.pubsub import StreamingPullResponse +from .types.pubsub import Subscription +from .types.pubsub import Topic +from .types.pubsub import UpdateSnapshotRequest +from .types.pubsub import UpdateSubscriptionRequest +from .types.pubsub import UpdateTopicRequest +from .types.schema import CreateSchemaRequest +from .types.schema import DeleteSchemaRequest +from .types.schema import GetSchemaRequest +from .types.schema import ListSchemasRequest +from .types.schema import ListSchemasResponse +from .types.schema import Schema +from .types.schema import ValidateMessageRequest +from .types.schema import ValidateMessageResponse +from .types.schema import ValidateSchemaRequest +from .types.schema import ValidateSchemaResponse +from .types.schema import Encoding +from .types.schema import SchemaView + +__all__ = ( + "PublisherAsyncClient", + "SchemaServiceAsyncClient", + "SubscriberAsyncClient", + "AcknowledgeRequest", + "BigQueryConfig", + "CreateSchemaRequest", + "CreateSnapshotRequest", + "DeadLetterPolicy", + "DeleteSchemaRequest", + "DeleteSnapshotRequest", + "DeleteSubscriptionRequest", + "DeleteTopicRequest", + "DetachSubscriptionRequest", + "DetachSubscriptionResponse", + "Encoding", + "ExpirationPolicy", + "GetSchemaRequest", + "GetSnapshotRequest", + "GetSubscriptionRequest", + "GetTopicRequest", + "ListSchemasRequest", + "ListSchemasResponse", + "ListSnapshotsRequest", + "ListSnapshotsResponse", + "ListSubscriptionsRequest", + "ListSubscriptionsResponse", + "ListTopicSnapshotsRequest", + "ListTopicSnapshotsResponse", + "ListTopicSubscriptionsRequest", + "ListTopicSubscriptionsResponse", + "ListTopicsRequest", + "ListTopicsResponse", + "MessageStoragePolicy", + "ModifyAckDeadlineRequest", + "ModifyPushConfigRequest", + "PublishRequest", + "PublishResponse", + "PublisherClient", + "PubsubMessage", + "PullRequest", + "PullResponse", + "PushConfig", + "ReceivedMessage", + "RetryPolicy", + "Schema", + "SchemaServiceClient", + "SchemaSettings", + "SchemaView", + "SeekRequest", + "SeekResponse", + "Snapshot", + "StreamingPullRequest", + "StreamingPullResponse", + "SubscriberClient", + "Subscription", + "Topic", + "UpdateSnapshotRequest", + "UpdateSubscriptionRequest", + "UpdateTopicRequest", + "ValidateMessageRequest", + "ValidateMessageResponse", + "ValidateSchemaRequest", + "ValidateSchemaResponse", +) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/gapic_metadata.json b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/gapic_metadata.json new file mode 100644 index 000000000000..4c5b86bd13bc --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/gapic_metadata.json @@ -0,0 +1,361 @@ + { + "comment": "This file maps proto services/RPCs to the corresponding library clients/methods", + "language": "python", + "libraryPackage": "google.pubsub_v1", + "protoPackage": "google.pubsub.v1", + "schema": "1.0", + "services": { + "Publisher": { + "clients": { + "grpc": { + "libraryClient": "PublisherClient", + "rpcs": { + "CreateTopic": { + "methods": [ + "create_topic" + ] + }, + "DeleteTopic": { + "methods": [ + "delete_topic" + ] + }, + "DetachSubscription": { + "methods": [ + "detach_subscription" + ] + }, + "GetTopic": { + "methods": [ + "get_topic" + ] + }, + "ListTopicSnapshots": { + "methods": [ + "list_topic_snapshots" + ] + }, + "ListTopicSubscriptions": { + "methods": [ + "list_topic_subscriptions" + ] + }, + "ListTopics": { + "methods": [ + "list_topics" + ] + }, + "Publish": { + "methods": [ + "publish" + ] + }, + "UpdateTopic": { + "methods": [ + "update_topic" + ] + } + } + }, + "grpc-async": { + "libraryClient": "PublisherAsyncClient", + "rpcs": { + "CreateTopic": { + "methods": [ + "create_topic" + ] + }, + "DeleteTopic": { + "methods": [ + "delete_topic" + ] + }, + "DetachSubscription": { + "methods": [ + "detach_subscription" + ] + }, + "GetTopic": { + "methods": [ + "get_topic" + ] + }, + "ListTopicSnapshots": { + "methods": [ + "list_topic_snapshots" + ] + }, + "ListTopicSubscriptions": { + "methods": [ + "list_topic_subscriptions" + ] + }, + "ListTopics": { + "methods": [ + "list_topics" + ] + }, + "Publish": { + "methods": [ + "publish" + ] + }, + "UpdateTopic": { + "methods": [ + "update_topic" + ] + } + } + } + } + }, + "SchemaService": { + "clients": { + "grpc": { + "libraryClient": "SchemaServiceClient", + "rpcs": { + "CreateSchema": { + "methods": [ + "create_schema" + ] + }, + "DeleteSchema": { + "methods": [ + "delete_schema" + ] + }, + "GetSchema": { + "methods": [ + "get_schema" + ] + }, + "ListSchemas": { + "methods": [ + "list_schemas" + ] + }, + "ValidateMessage": { + "methods": [ + "validate_message" + ] + }, + "ValidateSchema": { + "methods": [ + "validate_schema" + ] + } + } + }, + "grpc-async": { + "libraryClient": "SchemaServiceAsyncClient", + "rpcs": { + "CreateSchema": { + "methods": [ + "create_schema" + ] + }, + "DeleteSchema": { + "methods": [ + "delete_schema" + ] + }, + "GetSchema": { + "methods": [ + "get_schema" + ] + }, + "ListSchemas": { + "methods": [ + "list_schemas" + ] + }, + "ValidateMessage": { + "methods": [ + "validate_message" + ] + }, + "ValidateSchema": { + "methods": [ + "validate_schema" + ] + } + } + } + } + }, + "Subscriber": { + "clients": { + "grpc": { + "libraryClient": "SubscriberClient", + "rpcs": { + "Acknowledge": { + "methods": [ + "acknowledge" + ] + }, + "CreateSnapshot": { + "methods": [ + "create_snapshot" + ] + }, + "CreateSubscription": { + "methods": [ + "create_subscription" + ] + }, + "DeleteSnapshot": { + "methods": [ + "delete_snapshot" + ] + }, + "DeleteSubscription": { + "methods": [ + "delete_subscription" + ] + }, + "GetSnapshot": { + "methods": [ + "get_snapshot" + ] + }, + "GetSubscription": { + "methods": [ + "get_subscription" + ] + }, + "ListSnapshots": { + "methods": [ + "list_snapshots" + ] + }, + "ListSubscriptions": { + "methods": [ + "list_subscriptions" + ] + }, + "ModifyAckDeadline": { + "methods": [ + "modify_ack_deadline" + ] + }, + "ModifyPushConfig": { + "methods": [ + "modify_push_config" + ] + }, + "Pull": { + "methods": [ + "pull" + ] + }, + "Seek": { + "methods": [ + "seek" + ] + }, + "StreamingPull": { + "methods": [ + "streaming_pull" + ] + }, + "UpdateSnapshot": { + "methods": [ + "update_snapshot" + ] + }, + "UpdateSubscription": { + "methods": [ + "update_subscription" + ] + } + } + }, + "grpc-async": { + "libraryClient": "SubscriberAsyncClient", + "rpcs": { + "Acknowledge": { + "methods": [ + "acknowledge" + ] + }, + "CreateSnapshot": { + "methods": [ + "create_snapshot" + ] + }, + "CreateSubscription": { + "methods": [ + "create_subscription" + ] + }, + "DeleteSnapshot": { + "methods": [ + "delete_snapshot" + ] + }, + "DeleteSubscription": { + "methods": [ + "delete_subscription" + ] + }, + "GetSnapshot": { + "methods": [ + "get_snapshot" + ] + }, + "GetSubscription": { + "methods": [ + "get_subscription" + ] + }, + "ListSnapshots": { + "methods": [ + "list_snapshots" + ] + }, + "ListSubscriptions": { + "methods": [ + "list_subscriptions" + ] + }, + "ModifyAckDeadline": { + "methods": [ + "modify_ack_deadline" + ] + }, + "ModifyPushConfig": { + "methods": [ + "modify_push_config" + ] + }, + "Pull": { + "methods": [ + "pull" + ] + }, + "Seek": { + "methods": [ + "seek" + ] + }, + "StreamingPull": { + "methods": [ + "streaming_pull" + ] + }, + "UpdateSnapshot": { + "methods": [ + "update_snapshot" + ] + }, + "UpdateSubscription": { + "methods": [ + "update_subscription" + ] + } + } + } + } + } + } +} diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/py.typed b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/py.typed new file mode 100644 index 000000000000..1cec9a5ba1ab --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/py.typed @@ -0,0 +1,2 @@ +# Marker file for PEP 561. +# The google-cloud-pubsub package uses inline types. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/native/native_foo/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/__init__.py similarity index 76% rename from packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/native/native_foo/__init__.py rename to packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/__init__.py index d5e5048bcc9c..e8e1c3845db5 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/example/nspkg/native/native_foo/__init__.py +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/__init__.py @@ -1,19 +1,15 @@ -# Copyright 2021 Google LLC +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC # # 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 +# 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. - -# coding: utf-8 - -from format.rst.foo import Foo - -__all__ = ['Foo'] \ No newline at end of file +# diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/format/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/__init__.py similarity index 66% rename from packages/gcp-sphinx-docfx-yaml/tests/example/format/__init__.py rename to packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/__init__.py index b7b328fd9f4c..56fb64a17a88 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/example/format/__init__.py +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/__init__.py @@ -1,18 +1,22 @@ -# Copyright 2021 Google LLC +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC # # 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 +# 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. +# +from .client import PublisherClient +from .async_client import PublisherAsyncClient -# coding: utf-8 - -""" Package used to test rst-style, google-style and numpy-style docstrings. -""" \ No newline at end of file +__all__ = ( + "PublisherClient", + "PublisherAsyncClient", +) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/async_client.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/async_client.py new file mode 100644 index 000000000000..dbcd516b2ba9 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/async_client.py @@ -0,0 +1,1561 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +from collections import OrderedDict +import functools +import re +from typing import Dict, Mapping, Optional, Sequence, Tuple, Type, Union +import pkg_resources + +from google.api_core.client_options import ClientOptions +from google.api_core import exceptions as core_exceptions +from google.api_core import gapic_v1 +from google.api_core import retry as retries +from google.api_core import timeout as timeouts # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.oauth2 import service_account # type: ignore + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + +from google.iam.v1 import iam_policy_pb2 # type: ignore +from google.iam.v1 import policy_pb2 # type: ignore +from google.protobuf import duration_pb2 # type: ignore +from google.pubsub_v1.services.publisher import pagers +from google.pubsub_v1.types import pubsub +from google.pubsub_v1.types import TimeoutType +from .transports.base import PublisherTransport, DEFAULT_CLIENT_INFO +from .transports.grpc_asyncio import PublisherGrpcAsyncIOTransport +from .client import PublisherClient + + +class PublisherAsyncClient: + """The service that an application uses to manipulate topics, + and to send messages to a topic. + """ + + _client: PublisherClient + + DEFAULT_ENDPOINT = PublisherClient.DEFAULT_ENDPOINT + DEFAULT_MTLS_ENDPOINT = PublisherClient.DEFAULT_MTLS_ENDPOINT + + schema_path = staticmethod(PublisherClient.schema_path) + parse_schema_path = staticmethod(PublisherClient.parse_schema_path) + subscription_path = staticmethod(PublisherClient.subscription_path) + parse_subscription_path = staticmethod(PublisherClient.parse_subscription_path) + topic_path = staticmethod(PublisherClient.topic_path) + parse_topic_path = staticmethod(PublisherClient.parse_topic_path) + common_billing_account_path = staticmethod( + PublisherClient.common_billing_account_path + ) + parse_common_billing_account_path = staticmethod( + PublisherClient.parse_common_billing_account_path + ) + common_folder_path = staticmethod(PublisherClient.common_folder_path) + parse_common_folder_path = staticmethod(PublisherClient.parse_common_folder_path) + common_organization_path = staticmethod(PublisherClient.common_organization_path) + parse_common_organization_path = staticmethod( + PublisherClient.parse_common_organization_path + ) + common_project_path = staticmethod(PublisherClient.common_project_path) + parse_common_project_path = staticmethod(PublisherClient.parse_common_project_path) + common_location_path = staticmethod(PublisherClient.common_location_path) + parse_common_location_path = staticmethod( + PublisherClient.parse_common_location_path + ) + + @classmethod + def from_service_account_info(cls, info: dict, *args, **kwargs): + """Creates an instance of this client using the provided credentials + info. + + Args: + info (dict): The service account private key info. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + PublisherAsyncClient: The constructed client. + """ + return PublisherClient.from_service_account_info.__func__(PublisherAsyncClient, info, *args, **kwargs) # type: ignore + + @classmethod + def from_service_account_file(cls, filename: str, *args, **kwargs): + """Creates an instance of this client using the provided credentials + file. + + Args: + filename (str): The path to the service account private key json + file. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + PublisherAsyncClient: The constructed client. + """ + return PublisherClient.from_service_account_file.__func__(PublisherAsyncClient, filename, *args, **kwargs) # type: ignore + + from_service_account_json = from_service_account_file + + @classmethod + def get_mtls_endpoint_and_cert_source( + cls, client_options: Optional[ClientOptions] = None + ): + """Return the API endpoint and client cert source for mutual TLS. + + The client cert source is determined in the following order: + (1) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not "true", the + client cert source is None. + (2) if `client_options.client_cert_source` is provided, use the provided one; if the + default client cert source exists, use the default one; otherwise the client cert + source is None. + + The API endpoint is determined in the following order: + (1) if `client_options.api_endpoint` if provided, use the provided one. + (2) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is "always", use the + default mTLS endpoint; if the environment variabel is "never", use the default API + endpoint; otherwise if client cert source exists, use the default mTLS endpoint, otherwise + use the default API endpoint. + + More details can be found at https://google.aip.dev/auth/4114. + + Args: + client_options (google.api_core.client_options.ClientOptions): Custom options for the + client. Only the `api_endpoint` and `client_cert_source` properties may be used + in this method. + + Returns: + Tuple[str, Callable[[], Tuple[bytes, bytes]]]: returns the API endpoint and the + client cert source to use. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If any errors happen. + """ + return PublisherClient.get_mtls_endpoint_and_cert_source(client_options) # type: ignore + + @property + def transport(self) -> PublisherTransport: + """Returns the transport used by the client instance. + + Returns: + PublisherTransport: The transport used by the client instance. + """ + return self._client.transport + + get_transport_class = functools.partial( + type(PublisherClient).get_transport_class, type(PublisherClient) + ) + + def __init__( + self, + *, + credentials: ga_credentials.Credentials = None, + transport: Union[str, PublisherTransport] = "grpc_asyncio", + client_options: ClientOptions = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + ) -> None: + """Instantiates the publisher client. + + Args: + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + transport (Union[str, ~.PublisherTransport]): The + transport to use. If set to None, a transport is chosen + automatically. + client_options (ClientOptions): Custom options for the client. It + won't take effect if a ``transport`` instance is provided. + (1) The ``api_endpoint`` property can be used to override the + default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT + environment variable can also be used to override the endpoint: + "always" (always use the default mTLS endpoint), "never" (always + use the default regular endpoint) and "auto" (auto switch to the + default mTLS endpoint if client certificate is present, this is + the default value). However, the ``api_endpoint`` property takes + precedence if provided. + (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable + is "true", then the ``client_cert_source`` property can be used + to provide client certificate for mutual TLS transport. If + not provided, the default SSL client certificate will be used if + present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not + set, no client certificate will be used. + + Raises: + google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport + creation failed for any reason. + """ + self._client = PublisherClient( + credentials=credentials, + transport=transport, + client_options=client_options, + client_info=client_info, + ) + + async def create_topic( + self, + request: Union[pubsub.Topic, dict] = None, + *, + name: str = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: TimeoutType = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pubsub.Topic: + r"""Creates the given topic with the given name. See the [resource + name rules] + (https://cloud.google.com/pubsub/docs/admin#resource_names). + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + async def sample_create_topic(): + # Create a client + client = pubsub_v1.PublisherAsyncClient() + + # Initialize request argument(s) + request = pubsub_v1.Topic( + name="name_value", + ) + + # Make the request + response = await client.create_topic(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.pubsub_v1.types.Topic, dict]): + The request object. A topic resource. + name (:class:`str`): + Required. The name of the topic. It must have the format + ``"projects/{project}/topics/{topic}"``. ``{topic}`` + must start with a letter, and contain only letters + (``[A-Za-z]``), numbers (``[0-9]``), dashes (``-``), + underscores (``_``), periods (``.``), tildes (``~``), + plus (``+``) or percent signs (``%``). It must be + between 3 and 255 characters in length, and it must not + start with ``"goog"``. + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (TimeoutType): + The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.pubsub_v1.types.Topic: + A topic resource. + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = pubsub.Topic(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.create_topic, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def update_topic( + self, + request: Union[pubsub.UpdateTopicRequest, dict] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: TimeoutType = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pubsub.Topic: + r"""Updates an existing topic. Note that certain + properties of a topic are not modifiable. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + async def sample_update_topic(): + # Create a client + client = pubsub_v1.PublisherAsyncClient() + + # Initialize request argument(s) + topic = pubsub_v1.Topic() + topic.name = "name_value" + + request = pubsub_v1.UpdateTopicRequest( + topic=topic, + ) + + # Make the request + response = await client.update_topic(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.pubsub_v1.types.UpdateTopicRequest, dict]): + The request object. Request for the UpdateTopic method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (TimeoutType): + The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.pubsub_v1.types.Topic: + A topic resource. + """ + # Create or coerce a protobuf request object. + request = pubsub.UpdateTopicRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.update_topic, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("topic.name", request.topic.name),) + ), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def publish( + self, + request: Union[pubsub.PublishRequest, dict] = None, + *, + topic: str = None, + messages: Sequence[pubsub.PubsubMessage] = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: TimeoutType = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pubsub.PublishResponse: + r"""Adds one or more messages to the topic. Returns ``NOT_FOUND`` if + the topic does not exist. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + async def sample_publish(): + # Create a client + client = pubsub_v1.PublisherAsyncClient() + + # Initialize request argument(s) + request = pubsub_v1.PublishRequest( + topic="topic_value", + ) + + # Make the request + response = await client.publish(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.pubsub_v1.types.PublishRequest, dict]): + The request object. Request for the Publish method. + topic (:class:`str`): + Required. The messages in the request will be published + on this topic. Format is + ``projects/{project}/topics/{topic}``. + + This corresponds to the ``topic`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + messages (:class:`Sequence[google.pubsub_v1.types.PubsubMessage]`): + Required. The messages to publish. + This corresponds to the ``messages`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (TimeoutType): + The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.pubsub_v1.types.PublishResponse: + Response for the Publish method. + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([topic, messages]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = pubsub.PublishRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if topic is not None: + request.topic = topic + if messages: + request.messages.extend(messages) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.publish, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.Aborted, + core_exceptions.Cancelled, + core_exceptions.DeadlineExceeded, + core_exceptions.InternalServerError, + core_exceptions.ResourceExhausted, + core_exceptions.ServiceUnavailable, + core_exceptions.Unknown, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("topic", request.topic),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def get_topic( + self, + request: Union[pubsub.GetTopicRequest, dict] = None, + *, + topic: str = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: TimeoutType = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pubsub.Topic: + r"""Gets the configuration of a topic. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + async def sample_get_topic(): + # Create a client + client = pubsub_v1.PublisherAsyncClient() + + # Initialize request argument(s) + request = pubsub_v1.GetTopicRequest( + topic="topic_value", + ) + + # Make the request + response = await client.get_topic(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.pubsub_v1.types.GetTopicRequest, dict]): + The request object. Request for the GetTopic method. + topic (:class:`str`): + Required. The name of the topic to get. Format is + ``projects/{project}/topics/{topic}``. + + This corresponds to the ``topic`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (TimeoutType): + The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.pubsub_v1.types.Topic: + A topic resource. + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([topic]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = pubsub.GetTopicRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if topic is not None: + request.topic = topic + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.get_topic, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.Aborted, + core_exceptions.ServiceUnavailable, + core_exceptions.Unknown, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("topic", request.topic),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def list_topics( + self, + request: Union[pubsub.ListTopicsRequest, dict] = None, + *, + project: str = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: TimeoutType = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListTopicsAsyncPager: + r"""Lists matching topics. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + async def sample_list_topics(): + # Create a client + client = pubsub_v1.PublisherAsyncClient() + + # Initialize request argument(s) + request = pubsub_v1.ListTopicsRequest( + project="project_value", + ) + + # Make the request + page_result = client.list_topics(request=request) + + # Handle the response + async for response in page_result: + print(response) + + Args: + request (Union[google.pubsub_v1.types.ListTopicsRequest, dict]): + The request object. Request for the `ListTopics` method. + project (:class:`str`): + Required. The name of the project in which to list + topics. Format is ``projects/{project-id}``. + + This corresponds to the ``project`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (TimeoutType): + The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.pubsub_v1.services.publisher.pagers.ListTopicsAsyncPager: + Response for the ListTopics method. + + Iterating over this object will yield results and + resolve additional pages automatically. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([project]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = pubsub.ListTopicsRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if project is not None: + request.project = project + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.list_topics, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.Aborted, + core_exceptions.ServiceUnavailable, + core_exceptions.Unknown, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("project", request.project),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # This method is paged; wrap the response in a pager, which provides + # an `__aiter__` convenience method. + response = pagers.ListTopicsAsyncPager( + method=rpc, + request=request, + response=response, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def list_topic_subscriptions( + self, + request: Union[pubsub.ListTopicSubscriptionsRequest, dict] = None, + *, + topic: str = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: TimeoutType = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListTopicSubscriptionsAsyncPager: + r"""Lists the names of the attached subscriptions on this + topic. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + async def sample_list_topic_subscriptions(): + # Create a client + client = pubsub_v1.PublisherAsyncClient() + + # Initialize request argument(s) + request = pubsub_v1.ListTopicSubscriptionsRequest( + topic="topic_value", + ) + + # Make the request + page_result = client.list_topic_subscriptions(request=request) + + # Handle the response + async for response in page_result: + print(response) + + Args: + request (Union[google.pubsub_v1.types.ListTopicSubscriptionsRequest, dict]): + The request object. Request for the + `ListTopicSubscriptions` method. + topic (:class:`str`): + Required. The name of the topic that subscriptions are + attached to. Format is + ``projects/{project}/topics/{topic}``. + + This corresponds to the ``topic`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (TimeoutType): + The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.pubsub_v1.services.publisher.pagers.ListTopicSubscriptionsAsyncPager: + Response for the ListTopicSubscriptions method. + + Iterating over this object will yield results and + resolve additional pages automatically. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([topic]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = pubsub.ListTopicSubscriptionsRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if topic is not None: + request.topic = topic + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.list_topic_subscriptions, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.Aborted, + core_exceptions.ServiceUnavailable, + core_exceptions.Unknown, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("topic", request.topic),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # This method is paged; wrap the response in a pager, which provides + # an `__aiter__` convenience method. + response = pagers.ListTopicSubscriptionsAsyncPager( + method=rpc, + request=request, + response=response, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def list_topic_snapshots( + self, + request: Union[pubsub.ListTopicSnapshotsRequest, dict] = None, + *, + topic: str = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: TimeoutType = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListTopicSnapshotsAsyncPager: + r"""Lists the names of the snapshots on this topic. Snapshots are + used in + `Seek `__ + operations, which allow you to manage message acknowledgments in + bulk. That is, you can set the acknowledgment state of messages + in an existing subscription to the state captured by a snapshot. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + async def sample_list_topic_snapshots(): + # Create a client + client = pubsub_v1.PublisherAsyncClient() + + # Initialize request argument(s) + request = pubsub_v1.ListTopicSnapshotsRequest( + topic="topic_value", + ) + + # Make the request + page_result = client.list_topic_snapshots(request=request) + + # Handle the response + async for response in page_result: + print(response) + + Args: + request (Union[google.pubsub_v1.types.ListTopicSnapshotsRequest, dict]): + The request object. Request for the `ListTopicSnapshots` + method. + topic (:class:`str`): + Required. The name of the topic that snapshots are + attached to. Format is + ``projects/{project}/topics/{topic}``. + + This corresponds to the ``topic`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (TimeoutType): + The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.pubsub_v1.services.publisher.pagers.ListTopicSnapshotsAsyncPager: + Response for the ListTopicSnapshots method. + + Iterating over this object will yield results and + resolve additional pages automatically. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([topic]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = pubsub.ListTopicSnapshotsRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if topic is not None: + request.topic = topic + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.list_topic_snapshots, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.Aborted, + core_exceptions.ServiceUnavailable, + core_exceptions.Unknown, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("topic", request.topic),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # This method is paged; wrap the response in a pager, which provides + # an `__aiter__` convenience method. + response = pagers.ListTopicSnapshotsAsyncPager( + method=rpc, + request=request, + response=response, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def delete_topic( + self, + request: Union[pubsub.DeleteTopicRequest, dict] = None, + *, + topic: str = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: TimeoutType = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + r"""Deletes the topic with the given name. Returns ``NOT_FOUND`` if + the topic does not exist. After a topic is deleted, a new topic + may be created with the same name; this is an entirely new topic + with none of the old configuration or subscriptions. Existing + subscriptions to this topic are not deleted, but their ``topic`` + field is set to ``_deleted-topic_``. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + async def sample_delete_topic(): + # Create a client + client = pubsub_v1.PublisherAsyncClient() + + # Initialize request argument(s) + request = pubsub_v1.DeleteTopicRequest( + topic="topic_value", + ) + + # Make the request + await client.delete_topic(request=request) + + Args: + request (Union[google.pubsub_v1.types.DeleteTopicRequest, dict]): + The request object. Request for the `DeleteTopic` + method. + topic (:class:`str`): + Required. Name of the topic to delete. Format is + ``projects/{project}/topics/{topic}``. + + This corresponds to the ``topic`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (TimeoutType): + The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([topic]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = pubsub.DeleteTopicRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if topic is not None: + request.topic = topic + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.delete_topic, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("topic", request.topic),)), + ) + + # Send the request. + await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + async def detach_subscription( + self, + request: Union[pubsub.DetachSubscriptionRequest, dict] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: TimeoutType = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pubsub.DetachSubscriptionResponse: + r"""Detaches a subscription from this topic. All messages retained + in the subscription are dropped. Subsequent ``Pull`` and + ``StreamingPull`` requests will return FAILED_PRECONDITION. If + the subscription is a push subscription, pushes to the endpoint + will stop. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + async def sample_detach_subscription(): + # Create a client + client = pubsub_v1.PublisherAsyncClient() + + # Initialize request argument(s) + request = pubsub_v1.DetachSubscriptionRequest( + subscription="subscription_value", + ) + + # Make the request + response = await client.detach_subscription(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.pubsub_v1.types.DetachSubscriptionRequest, dict]): + The request object. Request for the DetachSubscription + method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (TimeoutType): + The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.pubsub_v1.types.DetachSubscriptionResponse: + Response for the DetachSubscription + method. Reserved for future use. + + """ + # Create or coerce a protobuf request object. + request = pubsub.DetachSubscriptionRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.detach_subscription, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("subscription", request.subscription),) + ), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def set_iam_policy( + self, + request: iam_policy_pb2.SetIamPolicyRequest = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: TimeoutType = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> policy_pb2.Policy: + r"""Sets the IAM access control policy on the specified function. + + Replaces any existing policy. + + Args: + request (:class:`~.policy_pb2.SetIamPolicyRequest`): + The request object. Request message for `SetIamPolicy` + method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (TimeoutType): + The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~.policy_pb2.Policy: + Defines an Identity and Access Management (IAM) policy. + It is used to specify access control policies for Cloud + Platform resources. + A ``Policy`` is a collection of ``bindings``. A + ``binding`` binds one or more ``members`` to a single + ``role``. Members can be user accounts, service + accounts, Google groups, and domains (such as G Suite). + A ``role`` is a named list of permissions (defined by + IAM or configured by users). A ``binding`` can + optionally specify a ``condition``, which is a logic + expression that further constrains the role binding + based on attributes about the request and/or target + resource. + + **JSON Example** + + :: + { + "bindings": [ + { + "role": "roles/resourcemanager.organizationAdmin", + "members": [ + "user:mike@example.com", + "group:admins@example.com", + "domain:google.com", + "serviceAccount:my-project-id@appspot.gserviceaccount.com" + ] + }, + { + "role": "roles/resourcemanager.organizationViewer", + "members": ["user:eve@example.com"], + "condition": { + "title": "expirable access", + "description": "Does not grant access after Sep 2020", + "expression": "request.time < + timestamp('2020-10-01T00:00:00.000Z')", + } + } + ] + } + + **YAML Example** + + :: + + bindings: + - members: + - user:mike@example.com + - group:admins@example.com + - domain:google.com + - serviceAccount:my-project-id@appspot.gserviceaccount.com + role: roles/resourcemanager.organizationAdmin + - members: + - user:eve@example.com + role: roles/resourcemanager.organizationViewer + condition: + title: expirable access + description: Does not grant access after Sep 2020 + expression: request.time < timestamp('2020-10-01T00:00:00.000Z') + + For a description of IAM and its features, see the `IAM + developer's + guide `__. + """ + # Create or coerce a protobuf request object. + + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = iam_policy_pb2.SetIamPolicyRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.set_iam_policy, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("resource", request.resource),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def get_iam_policy( + self, + request: iam_policy_pb2.GetIamPolicyRequest = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: TimeoutType = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> policy_pb2.Policy: + r"""Gets the IAM access control policy for a function. + + Returns an empty policy if the function exists and does + not have a policy set. + + Args: + request (:class:`~.iam_policy_pb2.GetIamPolicyRequest`): + The request object. Request message for `GetIamPolicy` + method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (TimeoutType): + The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~.policy_pb2.Policy: + Defines an Identity and Access Management (IAM) policy. + It is used to specify access control policies for Cloud + Platform resources. + A ``Policy`` is a collection of ``bindings``. A + ``binding`` binds one or more ``members`` to a single + ``role``. Members can be user accounts, service + accounts, Google groups, and domains (such as G Suite). + A ``role`` is a named list of permissions (defined by + IAM or configured by users). A ``binding`` can + optionally specify a ``condition``, which is a logic + expression that further constrains the role binding + based on attributes about the request and/or target + resource. + + **JSON Example** + + :: + + { + "bindings": [ + { + "role": "roles/resourcemanager.organizationAdmin", + "members": [ + "user:mike@example.com", + "group:admins@example.com", + "domain:google.com", + "serviceAccount:my-project-id@appspot.gserviceaccount.com" + ] + }, + { + "role": "roles/resourcemanager.organizationViewer", + "members": ["user:eve@example.com"], + "condition": { + "title": "expirable access", + "description": "Does not grant access after Sep 2020", + "expression": "request.time < + timestamp('2020-10-01T00:00:00.000Z')", + } + } + ] + } + + **YAML Example** + + :: + + bindings: + - members: + - user:mike@example.com + - group:admins@example.com + - domain:google.com + - serviceAccount:my-project-id@appspot.gserviceaccount.com + role: roles/resourcemanager.organizationAdmin + - members: + - user:eve@example.com + role: roles/resourcemanager.organizationViewer + condition: + title: expirable access + description: Does not grant access after Sep 2020 + expression: request.time < timestamp('2020-10-01T00:00:00.000Z') + + For a description of IAM and its features, see the `IAM + developer's + guide `__. + """ + # Create or coerce a protobuf request object. + + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = iam_policy_pb2.GetIamPolicyRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.get_iam_policy, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("resource", request.resource),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def test_iam_permissions( + self, + request: iam_policy_pb2.TestIamPermissionsRequest = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: TimeoutType = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> iam_policy_pb2.TestIamPermissionsResponse: + r"""Tests the specified permissions against the IAM access control + policy for a function. + + If the function does not exist, this will + return an empty set of permissions, not a NOT_FOUND error. + + Args: + request (:class:`~.iam_policy_pb2.TestIamPermissionsRequest`): + The request object. Request message for + `TestIamPermissions` method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (TimeoutType): + The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~iam_policy_pb2.PolicyTestIamPermissionsResponse: + Response message for ``TestIamPermissions`` method. + """ + # Create or coerce a protobuf request object. + + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = iam_policy_pb2.TestIamPermissionsRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.test_iam_permissions, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("resource", request.resource),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc, tb): + await self.transport.close() + + +try: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + client_library_version=pkg_resources.get_distribution( + "google-cloud-pubsub", + ).version, + ) +except pkg_resources.DistributionNotFound: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() + + +__all__ = ("PublisherAsyncClient",) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py new file mode 100644 index 000000000000..f8a640422f8d --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py @@ -0,0 +1,1754 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +from collections import OrderedDict +import functools +import os +import re +from typing import Dict, Mapping, Optional, Sequence, Tuple, Type, Union +import pkg_resources + +from google.api_core import client_options as client_options_lib +from google.api_core import exceptions as core_exceptions +from google.api_core import gapic_v1 +from google.api_core import retry as retries +from google.api_core import timeout as timeouts # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport import mtls # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.exceptions import MutualTLSChannelError # type: ignore +from google.oauth2 import service_account # type: ignore + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + +from google.iam.v1 import iam_policy_pb2 # type: ignore +from google.iam.v1 import policy_pb2 # type: ignore +from google.protobuf import duration_pb2 # type: ignore +from google.pubsub_v1.services.publisher import pagers +from google.pubsub_v1.types import pubsub +from google.pubsub_v1.types import TimeoutType + +import grpc +from .transports.base import PublisherTransport, DEFAULT_CLIENT_INFO +from .transports.grpc import PublisherGrpcTransport +from .transports.grpc_asyncio import PublisherGrpcAsyncIOTransport + + +class PublisherClientMeta(type): + """Metaclass for the Publisher client. + + This provides class-level methods for building and retrieving + support objects (e.g. transport) without polluting the client instance + objects. + """ + + _transport_registry = OrderedDict() # type: Dict[str, Type[PublisherTransport]] + _transport_registry["grpc"] = PublisherGrpcTransport + _transport_registry["grpc_asyncio"] = PublisherGrpcAsyncIOTransport + + def get_transport_class( + cls, + label: str = None, + ) -> Type[PublisherTransport]: + """Returns an appropriate transport class. + + Args: + label: The name of the desired transport. If none is + provided, then the first transport in the registry is used. + + Returns: + The transport class to use. + """ + # If a specific transport is requested, return that one. + if label: + return cls._transport_registry[label] + + # No transport is requested; return the default (that is, the first one + # in the dictionary). + return next(iter(cls._transport_registry.values())) + + +class PublisherClient(metaclass=PublisherClientMeta): + """The service that an application uses to manipulate topics, + and to send messages to a topic. + """ + + @staticmethod + def _get_default_mtls_endpoint(api_endpoint): + """Converts api endpoint to mTLS endpoint. + + Convert "*.sandbox.googleapis.com" and "*.googleapis.com" to + "*.mtls.sandbox.googleapis.com" and "*.mtls.googleapis.com" respectively. + Args: + api_endpoint (Optional[str]): the api endpoint to convert. + Returns: + str: converted mTLS api endpoint. + """ + if not api_endpoint: + return api_endpoint + + mtls_endpoint_re = re.compile( + r"(?P[^.]+)(?P\.mtls)?(?P\.sandbox)?(?P\.googleapis\.com)?" + ) + + m = mtls_endpoint_re.match(api_endpoint) + name, mtls, sandbox, googledomain = m.groups() + if mtls or not googledomain: + return api_endpoint + + if sandbox: + return api_endpoint.replace( + "sandbox.googleapis.com", "mtls.sandbox.googleapis.com" + ) + + return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com") + + # The scopes needed to make gRPC calls to all of the methods defined in + # this service + _DEFAULT_SCOPES = ( + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/pubsub", + ) + + SERVICE_ADDRESS = "pubsub.googleapis.com:443" + """The default address of the service.""" + + DEFAULT_ENDPOINT = "pubsub.googleapis.com" + DEFAULT_MTLS_ENDPOINT = _get_default_mtls_endpoint.__func__( # type: ignore + DEFAULT_ENDPOINT + ) + + @classmethod + def from_service_account_info(cls, info: dict, *args, **kwargs): + """Creates an instance of this client using the provided credentials + info. + + Args: + info (dict): The service account private key info. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + PublisherClient: The constructed client. + """ + credentials = service_account.Credentials.from_service_account_info(info) + kwargs["credentials"] = credentials + return cls(*args, **kwargs) + + @classmethod + def from_service_account_file(cls, filename: str, *args, **kwargs): + """Creates an instance of this client using the provided credentials + file. + + Args: + filename (str): The path to the service account private key json + file. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + PublisherClient: The constructed client. + """ + credentials = service_account.Credentials.from_service_account_file(filename) + kwargs["credentials"] = credentials + return cls(*args, **kwargs) + + from_service_account_json = from_service_account_file + + @property + def transport(self) -> PublisherTransport: + """Returns the transport used by the client instance. + + Returns: + PublisherTransport: The transport used by the client + instance. + """ + return self._transport + + @staticmethod + def schema_path( + project: str, + schema: str, + ) -> str: + """Returns a fully-qualified schema string.""" + return "projects/{project}/schemas/{schema}".format( + project=project, + schema=schema, + ) + + @staticmethod + def parse_schema_path(path: str) -> Dict[str, str]: + """Parses a schema path into its component segments.""" + m = re.match(r"^projects/(?P.+?)/schemas/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def subscription_path( + project: str, + subscription: str, + ) -> str: + """Returns a fully-qualified subscription string.""" + return "projects/{project}/subscriptions/{subscription}".format( + project=project, + subscription=subscription, + ) + + @staticmethod + def parse_subscription_path(path: str) -> Dict[str, str]: + """Parses a subscription path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/subscriptions/(?P.+?)$", path + ) + return m.groupdict() if m else {} + + @staticmethod + def topic_path( + project: str, + topic: str, + ) -> str: + """Returns a fully-qualified topic string.""" + return "projects/{project}/topics/{topic}".format( + project=project, + topic=topic, + ) + + @staticmethod + def parse_topic_path(path: str) -> Dict[str, str]: + """Parses a topic path into its component segments.""" + m = re.match(r"^projects/(?P.+?)/topics/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_billing_account_path( + billing_account: str, + ) -> str: + """Returns a fully-qualified billing_account string.""" + return "billingAccounts/{billing_account}".format( + billing_account=billing_account, + ) + + @staticmethod + def parse_common_billing_account_path(path: str) -> Dict[str, str]: + """Parse a billing_account path into its component segments.""" + m = re.match(r"^billingAccounts/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_folder_path( + folder: str, + ) -> str: + """Returns a fully-qualified folder string.""" + return "folders/{folder}".format( + folder=folder, + ) + + @staticmethod + def parse_common_folder_path(path: str) -> Dict[str, str]: + """Parse a folder path into its component segments.""" + m = re.match(r"^folders/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_organization_path( + organization: str, + ) -> str: + """Returns a fully-qualified organization string.""" + return "organizations/{organization}".format( + organization=organization, + ) + + @staticmethod + def parse_common_organization_path(path: str) -> Dict[str, str]: + """Parse a organization path into its component segments.""" + m = re.match(r"^organizations/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_project_path( + project: str, + ) -> str: + """Returns a fully-qualified project string.""" + return "projects/{project}".format( + project=project, + ) + + @staticmethod + def parse_common_project_path(path: str) -> Dict[str, str]: + """Parse a project path into its component segments.""" + m = re.match(r"^projects/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_location_path( + project: str, + location: str, + ) -> str: + """Returns a fully-qualified location string.""" + return "projects/{project}/locations/{location}".format( + project=project, + location=location, + ) + + @staticmethod + def parse_common_location_path(path: str) -> Dict[str, str]: + """Parse a location path into its component segments.""" + m = re.match(r"^projects/(?P.+?)/locations/(?P.+?)$", path) + return m.groupdict() if m else {} + + @classmethod + def get_mtls_endpoint_and_cert_source( + cls, client_options: Optional[client_options_lib.ClientOptions] = None + ): + """Return the API endpoint and client cert source for mutual TLS. + + The client cert source is determined in the following order: + (1) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not "true", the + client cert source is None. + (2) if `client_options.client_cert_source` is provided, use the provided one; if the + default client cert source exists, use the default one; otherwise the client cert + source is None. + + The API endpoint is determined in the following order: + (1) if `client_options.api_endpoint` if provided, use the provided one. + (2) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is "always", use the + default mTLS endpoint; if the environment variabel is "never", use the default API + endpoint; otherwise if client cert source exists, use the default mTLS endpoint, otherwise + use the default API endpoint. + + More details can be found at https://google.aip.dev/auth/4114. + + Args: + client_options (google.api_core.client_options.ClientOptions): Custom options for the + client. Only the `api_endpoint` and `client_cert_source` properties may be used + in this method. + + Returns: + Tuple[str, Callable[[], Tuple[bytes, bytes]]]: returns the API endpoint and the + client cert source to use. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If any errors happen. + """ + if client_options is None: + client_options = client_options_lib.ClientOptions() + use_client_cert = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false") + use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto") + if use_client_cert not in ("true", "false"): + raise ValueError( + "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`" + ) + if use_mtls_endpoint not in ("auto", "never", "always"): + raise MutualTLSChannelError( + "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`" + ) + + # Figure out the client cert source to use. + client_cert_source = None + if use_client_cert == "true": + if client_options.client_cert_source: + client_cert_source = client_options.client_cert_source + elif mtls.has_default_client_cert_source(): + client_cert_source = mtls.default_client_cert_source() + + # Figure out which api endpoint to use. + if client_options.api_endpoint is not None: + api_endpoint = client_options.api_endpoint + elif use_mtls_endpoint == "always" or ( + use_mtls_endpoint == "auto" and client_cert_source + ): + api_endpoint = cls.DEFAULT_MTLS_ENDPOINT + else: + api_endpoint = cls.DEFAULT_ENDPOINT + + return api_endpoint, client_cert_source + + def __init__( + self, + *, + credentials: Optional[ga_credentials.Credentials] = None, + transport: Union[str, PublisherTransport, None] = None, + client_options: Optional[client_options_lib.ClientOptions] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + ) -> None: + """Instantiates the publisher client. + + Args: + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + transport (Union[str, PublisherTransport]): The + transport to use. If set to None, a transport is chosen + automatically. + client_options (google.api_core.client_options.ClientOptions): Custom options for the + client. It won't take effect if a ``transport`` instance is provided. + (1) The ``api_endpoint`` property can be used to override the + default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT + environment variable can also be used to override the endpoint: + "always" (always use the default mTLS endpoint), "never" (always + use the default regular endpoint) and "auto" (auto switch to the + default mTLS endpoint if client certificate is present, this is + the default value). However, the ``api_endpoint`` property takes + precedence if provided. + (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable + is "true", then the ``client_cert_source`` property can be used + to provide client certificate for mutual TLS transport. If + not provided, the default SSL client certificate will be used if + present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not + set, no client certificate will be used. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport + creation failed for any reason. + """ + if isinstance(client_options, dict): + client_options = client_options_lib.from_dict(client_options) + if client_options is None: + client_options = client_options_lib.ClientOptions() + + api_endpoint, client_cert_source_func = self.get_mtls_endpoint_and_cert_source( + client_options + ) + + api_key_value = getattr(client_options, "api_key", None) + if api_key_value and credentials: + raise ValueError( + "client_options.api_key and credentials are mutually exclusive" + ) + + # Save or instantiate the transport. + # Ordinarily, we provide the transport, but allowing a custom transport + # instance provides an extensibility point for unusual situations. + if isinstance(transport, PublisherTransport): + # transport is a PublisherTransport instance. + if credentials or client_options.credentials_file or api_key_value: + raise ValueError( + "When providing a transport instance, " + "provide its credentials directly." + ) + if client_options.scopes: + raise ValueError( + "When providing a transport instance, provide its scopes " + "directly." + ) + self._transport = transport + else: + import google.auth._default # type: ignore + + if api_key_value and hasattr( + google.auth._default, "get_api_key_credentials" + ): + credentials = google.auth._default.get_api_key_credentials( + api_key_value + ) + + Transport = type(self).get_transport_class(transport) + + emulator_host = os.environ.get("PUBSUB_EMULATOR_HOST") + if emulator_host: + if issubclass(Transport, type(self)._transport_registry["grpc"]): + channel = grpc.insecure_channel(target=emulator_host) + else: + channel = grpc.aio.insecure_channel(target=emulator_host) + Transport = functools.partial(Transport, channel=channel) + + self._transport = Transport( + credentials=credentials, + credentials_file=client_options.credentials_file, + host=api_endpoint, + scopes=client_options.scopes, + client_cert_source_for_mtls=client_cert_source_func, + quota_project_id=client_options.quota_project_id, + client_info=client_info, + always_use_jwt_access=True, + api_audience=client_options.api_audience, + ) + + def create_topic( + self, + request: Union[pubsub.Topic, dict] = None, + *, + name: str = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: TimeoutType = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pubsub.Topic: + r"""Creates the given topic with the given name. See the [resource + name rules] + (https://cloud.google.com/pubsub/docs/admin#resource_names). + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + def sample_create_topic(): + # Create a client + client = pubsub_v1.PublisherClient() + + # Initialize request argument(s) + request = pubsub_v1.Topic( + name="name_value", + ) + + # Make the request + response = client.create_topic(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.pubsub_v1.types.Topic, dict]): + The request object. A topic resource. + name (str): + Required. The name of the topic. It must have the format + ``"projects/{project}/topics/{topic}"``. ``{topic}`` + must start with a letter, and contain only letters + (``[A-Za-z]``), numbers (``[0-9]``), dashes (``-``), + underscores (``_``), periods (``.``), tildes (``~``), + plus (``+``) or percent signs (``%``). It must be + between 3 and 255 characters in length, and it must not + start with ``"goog"``. + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (TimeoutType): + The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.pubsub_v1.types.Topic: + A topic resource. + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a pubsub.Topic. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, pubsub.Topic): + request = pubsub.Topic(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.create_topic] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def update_topic( + self, + request: Union[pubsub.UpdateTopicRequest, dict] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: TimeoutType = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pubsub.Topic: + r"""Updates an existing topic. Note that certain + properties of a topic are not modifiable. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + def sample_update_topic(): + # Create a client + client = pubsub_v1.PublisherClient() + + # Initialize request argument(s) + topic = pubsub_v1.Topic() + topic.name = "name_value" + + request = pubsub_v1.UpdateTopicRequest( + topic=topic, + ) + + # Make the request + response = client.update_topic(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.pubsub_v1.types.UpdateTopicRequest, dict]): + The request object. Request for the UpdateTopic method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (TimeoutType): + The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.pubsub_v1.types.Topic: + A topic resource. + """ + # Create or coerce a protobuf request object. + # Minor optimization to avoid making a copy if the user passes + # in a pubsub.UpdateTopicRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, pubsub.UpdateTopicRequest): + request = pubsub.UpdateTopicRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.update_topic] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("topic.name", request.topic.name),) + ), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def publish( + self, + request: Union[pubsub.PublishRequest, dict] = None, + *, + topic: str = None, + messages: Sequence[pubsub.PubsubMessage] = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: TimeoutType = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pubsub.PublishResponse: + r"""Adds one or more messages to the topic. Returns ``NOT_FOUND`` if + the topic does not exist. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + def sample_publish(): + # Create a client + client = pubsub_v1.PublisherClient() + + # Initialize request argument(s) + request = pubsub_v1.PublishRequest( + topic="topic_value", + ) + + # Make the request + response = client.publish(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.pubsub_v1.types.PublishRequest, dict]): + The request object. Request for the Publish method. + topic (str): + Required. The messages in the request will be published + on this topic. Format is + ``projects/{project}/topics/{topic}``. + + This corresponds to the ``topic`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + messages (Sequence[google.pubsub_v1.types.PubsubMessage]): + Required. The messages to publish. + This corresponds to the ``messages`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (TimeoutType): + The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.pubsub_v1.types.PublishResponse: + Response for the Publish method. + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([topic, messages]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a pubsub.PublishRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, pubsub.PublishRequest): + request = pubsub.PublishRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if topic is not None: + request.topic = topic + if messages is not None: + request.messages = messages + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.publish] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("topic", request.topic),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def get_topic( + self, + request: Union[pubsub.GetTopicRequest, dict] = None, + *, + topic: str = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: TimeoutType = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pubsub.Topic: + r"""Gets the configuration of a topic. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + def sample_get_topic(): + # Create a client + client = pubsub_v1.PublisherClient() + + # Initialize request argument(s) + request = pubsub_v1.GetTopicRequest( + topic="topic_value", + ) + + # Make the request + response = client.get_topic(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.pubsub_v1.types.GetTopicRequest, dict]): + The request object. Request for the GetTopic method. + topic (str): + Required. The name of the topic to get. Format is + ``projects/{project}/topics/{topic}``. + + This corresponds to the ``topic`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (TimeoutType): + The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.pubsub_v1.types.Topic: + A topic resource. + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([topic]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a pubsub.GetTopicRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, pubsub.GetTopicRequest): + request = pubsub.GetTopicRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if topic is not None: + request.topic = topic + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.get_topic] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("topic", request.topic),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def list_topics( + self, + request: Union[pubsub.ListTopicsRequest, dict] = None, + *, + project: str = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: TimeoutType = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListTopicsPager: + r"""Lists matching topics. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + def sample_list_topics(): + # Create a client + client = pubsub_v1.PublisherClient() + + # Initialize request argument(s) + request = pubsub_v1.ListTopicsRequest( + project="project_value", + ) + + # Make the request + page_result = client.list_topics(request=request) + + # Handle the response + for response in page_result: + print(response) + + Args: + request (Union[google.pubsub_v1.types.ListTopicsRequest, dict]): + The request object. Request for the `ListTopics` method. + project (str): + Required. The name of the project in which to list + topics. Format is ``projects/{project-id}``. + + This corresponds to the ``project`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (TimeoutType): + The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.pubsub_v1.services.publisher.pagers.ListTopicsPager: + Response for the ListTopics method. + + Iterating over this object will yield results and + resolve additional pages automatically. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([project]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a pubsub.ListTopicsRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, pubsub.ListTopicsRequest): + request = pubsub.ListTopicsRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if project is not None: + request.project = project + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.list_topics] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("project", request.project),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # This method is paged; wrap the response in a pager, which provides + # an `__iter__` convenience method. + response = pagers.ListTopicsPager( + method=rpc, + request=request, + response=response, + metadata=metadata, + ) + + # Done; return the response. + return response + + def list_topic_subscriptions( + self, + request: Union[pubsub.ListTopicSubscriptionsRequest, dict] = None, + *, + topic: str = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: TimeoutType = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListTopicSubscriptionsPager: + r"""Lists the names of the attached subscriptions on this + topic. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + def sample_list_topic_subscriptions(): + # Create a client + client = pubsub_v1.PublisherClient() + + # Initialize request argument(s) + request = pubsub_v1.ListTopicSubscriptionsRequest( + topic="topic_value", + ) + + # Make the request + page_result = client.list_topic_subscriptions(request=request) + + # Handle the response + for response in page_result: + print(response) + + Args: + request (Union[google.pubsub_v1.types.ListTopicSubscriptionsRequest, dict]): + The request object. Request for the + `ListTopicSubscriptions` method. + topic (str): + Required. The name of the topic that subscriptions are + attached to. Format is + ``projects/{project}/topics/{topic}``. + + This corresponds to the ``topic`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (TimeoutType): + The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.pubsub_v1.services.publisher.pagers.ListTopicSubscriptionsPager: + Response for the ListTopicSubscriptions method. + + Iterating over this object will yield results and + resolve additional pages automatically. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([topic]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a pubsub.ListTopicSubscriptionsRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, pubsub.ListTopicSubscriptionsRequest): + request = pubsub.ListTopicSubscriptionsRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if topic is not None: + request.topic = topic + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.list_topic_subscriptions] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("topic", request.topic),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # This method is paged; wrap the response in a pager, which provides + # an `__iter__` convenience method. + response = pagers.ListTopicSubscriptionsPager( + method=rpc, + request=request, + response=response, + metadata=metadata, + ) + + # Done; return the response. + return response + + def list_topic_snapshots( + self, + request: Union[pubsub.ListTopicSnapshotsRequest, dict] = None, + *, + topic: str = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: TimeoutType = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListTopicSnapshotsPager: + r"""Lists the names of the snapshots on this topic. Snapshots are + used in + `Seek `__ + operations, which allow you to manage message acknowledgments in + bulk. That is, you can set the acknowledgment state of messages + in an existing subscription to the state captured by a snapshot. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + def sample_list_topic_snapshots(): + # Create a client + client = pubsub_v1.PublisherClient() + + # Initialize request argument(s) + request = pubsub_v1.ListTopicSnapshotsRequest( + topic="topic_value", + ) + + # Make the request + page_result = client.list_topic_snapshots(request=request) + + # Handle the response + for response in page_result: + print(response) + + Args: + request (Union[google.pubsub_v1.types.ListTopicSnapshotsRequest, dict]): + The request object. Request for the `ListTopicSnapshots` + method. + topic (str): + Required. The name of the topic that snapshots are + attached to. Format is + ``projects/{project}/topics/{topic}``. + + This corresponds to the ``topic`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (TimeoutType): + The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.pubsub_v1.services.publisher.pagers.ListTopicSnapshotsPager: + Response for the ListTopicSnapshots method. + + Iterating over this object will yield results and + resolve additional pages automatically. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([topic]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a pubsub.ListTopicSnapshotsRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, pubsub.ListTopicSnapshotsRequest): + request = pubsub.ListTopicSnapshotsRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if topic is not None: + request.topic = topic + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.list_topic_snapshots] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("topic", request.topic),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # This method is paged; wrap the response in a pager, which provides + # an `__iter__` convenience method. + response = pagers.ListTopicSnapshotsPager( + method=rpc, + request=request, + response=response, + metadata=metadata, + ) + + # Done; return the response. + return response + + def delete_topic( + self, + request: Union[pubsub.DeleteTopicRequest, dict] = None, + *, + topic: str = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: TimeoutType = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + r"""Deletes the topic with the given name. Returns ``NOT_FOUND`` if + the topic does not exist. After a topic is deleted, a new topic + may be created with the same name; this is an entirely new topic + with none of the old configuration or subscriptions. Existing + subscriptions to this topic are not deleted, but their ``topic`` + field is set to ``_deleted-topic_``. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + def sample_delete_topic(): + # Create a client + client = pubsub_v1.PublisherClient() + + # Initialize request argument(s) + request = pubsub_v1.DeleteTopicRequest( + topic="topic_value", + ) + + # Make the request + client.delete_topic(request=request) + + Args: + request (Union[google.pubsub_v1.types.DeleteTopicRequest, dict]): + The request object. Request for the `DeleteTopic` + method. + topic (str): + Required. Name of the topic to delete. Format is + ``projects/{project}/topics/{topic}``. + + This corresponds to the ``topic`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (TimeoutType): + The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([topic]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a pubsub.DeleteTopicRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, pubsub.DeleteTopicRequest): + request = pubsub.DeleteTopicRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if topic is not None: + request.topic = topic + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.delete_topic] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("topic", request.topic),)), + ) + + # Send the request. + rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + def detach_subscription( + self, + request: Union[pubsub.DetachSubscriptionRequest, dict] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: TimeoutType = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pubsub.DetachSubscriptionResponse: + r"""Detaches a subscription from this topic. All messages retained + in the subscription are dropped. Subsequent ``Pull`` and + ``StreamingPull`` requests will return FAILED_PRECONDITION. If + the subscription is a push subscription, pushes to the endpoint + will stop. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + def sample_detach_subscription(): + # Create a client + client = pubsub_v1.PublisherClient() + + # Initialize request argument(s) + request = pubsub_v1.DetachSubscriptionRequest( + subscription="subscription_value", + ) + + # Make the request + response = client.detach_subscription(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.pubsub_v1.types.DetachSubscriptionRequest, dict]): + The request object. Request for the DetachSubscription + method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (TimeoutType): + The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.pubsub_v1.types.DetachSubscriptionResponse: + Response for the DetachSubscription + method. Reserved for future use. + + """ + # Create or coerce a protobuf request object. + # Minor optimization to avoid making a copy if the user passes + # in a pubsub.DetachSubscriptionRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, pubsub.DetachSubscriptionRequest): + request = pubsub.DetachSubscriptionRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.detach_subscription] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("subscription", request.subscription),) + ), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def __enter__(self): + return self + + def __exit__(self, type, value, traceback): + """Releases underlying transport's resources. + + .. warning:: + ONLY use as a context manager if the transport is NOT shared + with other clients! Exiting the with block will CLOSE the transport + and may cause errors in other clients! + """ + self.transport.close() + + def set_iam_policy( + self, + request: iam_policy_pb2.SetIamPolicyRequest = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: TimeoutType = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> policy_pb2.Policy: + r"""Sets the IAM access control policy on the specified function. + + Replaces any existing policy. + + Args: + request (:class:`~.iam_policy_pb2.SetIamPolicyRequest`): + The request object. Request message for `SetIamPolicy` + method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (TimeoutType): + The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~.policy_pb2.Policy: + Defines an Identity and Access Management (IAM) policy. + It is used to specify access control policies for Cloud + Platform resources. + A ``Policy`` is a collection of ``bindings``. A + ``binding`` binds one or more ``members`` to a single + ``role``. Members can be user accounts, service + accounts, Google groups, and domains (such as G Suite). + A ``role`` is a named list of permissions (defined by + IAM or configured by users). A ``binding`` can + optionally specify a ``condition``, which is a logic + expression that further constrains the role binding + based on attributes about the request and/or target + resource. + + **JSON Example** + + :: + + { + "bindings": [ + { + "role": "roles/resourcemanager.organizationAdmin", + "members": [ + "user:mike@example.com", + "group:admins@example.com", + "domain:google.com", + "serviceAccount:my-project-id@appspot.gserviceaccount.com" + ] + }, + { + "role": "roles/resourcemanager.organizationViewer", + "members": ["user:eve@example.com"], + "condition": { + "title": "expirable access", + "description": "Does not grant access after Sep 2020", + "expression": "request.time < + timestamp('2020-10-01T00:00:00.000Z')", + } + } + ] + } + + **YAML Example** + + :: + + bindings: + - members: + - user:mike@example.com + - group:admins@example.com + - domain:google.com + - serviceAccount:my-project-id@appspot.gserviceaccount.com + role: roles/resourcemanager.organizationAdmin + - members: + - user:eve@example.com + role: roles/resourcemanager.organizationViewer + condition: + title: expirable access + description: Does not grant access after Sep 2020 + expression: request.time < timestamp('2020-10-01T00:00:00.000Z') + + For a description of IAM and its features, see the `IAM + developer's + guide `__. + """ + # Create or coerce a protobuf request object. + + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = iam_policy_pb2.SetIamPolicyRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._transport.set_iam_policy, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("resource", request.resource),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def get_iam_policy( + self, + request: iam_policy_pb2.GetIamPolicyRequest = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: TimeoutType = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> policy_pb2.Policy: + r"""Gets the IAM access control policy for a function. + + Returns an empty policy if the function exists and does not have a + policy set. + + Args: + request (:class:`~.iam_policy_pb2.GetIamPolicyRequest`): + The request object. Request message for `GetIamPolicy` + method. + retry (google.api_core.retry.Retry): Designation of what errors, if + any, should be retried. + timeout (TimeoutType): + The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~.policy_pb2.Policy: + Defines an Identity and Access Management (IAM) policy. + It is used to specify access control policies for Cloud + Platform resources. + A ``Policy`` is a collection of ``bindings``. A + ``binding`` binds one or more ``members`` to a single + ``role``. Members can be user accounts, service + accounts, Google groups, and domains (such as G Suite). + A ``role`` is a named list of permissions (defined by + IAM or configured by users). A ``binding`` can + optionally specify a ``condition``, which is a logic + expression that further constrains the role binding + based on attributes about the request and/or target + resource. + + **JSON Example** + + :: + + { + "bindings": [ + { + "role": "roles/resourcemanager.organizationAdmin", + "members": [ + "user:mike@example.com", + "group:admins@example.com", + "domain:google.com", + "serviceAccount:my-project-id@appspot.gserviceaccount.com" + ] + }, + { + "role": "roles/resourcemanager.organizationViewer", + "members": ["user:eve@example.com"], + "condition": { + "title": "expirable access", + "description": "Does not grant access after Sep 2020", + "expression": "request.time < + timestamp('2020-10-01T00:00:00.000Z')", + } + } + ] + } + + **YAML Example** + + :: + + bindings: + - members: + - user:mike@example.com + - group:admins@example.com + - domain:google.com + - serviceAccount:my-project-id@appspot.gserviceaccount.com + role: roles/resourcemanager.organizationAdmin + - members: + - user:eve@example.com + role: roles/resourcemanager.organizationViewer + condition: + title: expirable access + description: Does not grant access after Sep 2020 + expression: request.time < timestamp('2020-10-01T00:00:00.000Z') + + For a description of IAM and its features, see the `IAM + developer's + guide `__. + """ + # Create or coerce a protobuf request object. + + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = iam_policy_pb2.GetIamPolicyRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._transport.get_iam_policy, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("resource", request.resource),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def test_iam_permissions( + self, + request: iam_policy_pb2.TestIamPermissionsRequest = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: TimeoutType = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> iam_policy_pb2.TestIamPermissionsResponse: + r"""Tests the specified IAM permissions against the IAM access control + policy for a function. + + If the function does not exist, this will return an empty set + of permissions, not a NOT_FOUND error. + + Args: + request (:class:`~.iam_policy_pb2.TestIamPermissionsRequest`): + The request object. Request message for + `TestIamPermissions` method. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (TimeoutType): + The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~.iam_policy_pb2.TestIamPermissionsResponse: + Response message for ``TestIamPermissions`` method. + """ + # Create or coerce a protobuf request object. + + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = iam_policy_pb2.TestIamPermissionsRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._transport.test_iam_permissions, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("resource", request.resource),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + +try: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + client_library_version=pkg_resources.get_distribution( + "google-cloud-pubsub", + ).version, + ) +except pkg_resources.DistributionNotFound: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() + + +__all__ = ("PublisherClient",) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/pagers.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/pagers.py new file mode 100644 index 000000000000..1e095181f7be --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/pagers.py @@ -0,0 +1,411 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +from typing import ( + Any, + AsyncIterator, + Awaitable, + Callable, + Sequence, + Tuple, + Optional, + Iterator, +) + +from google.pubsub_v1.types import pubsub + + +class ListTopicsPager: + """A pager for iterating through ``list_topics`` requests. + + This class thinly wraps an initial + :class:`google.pubsub_v1.types.ListTopicsResponse` object, and + provides an ``__iter__`` method to iterate through its + ``topics`` field. + + If there are more pages, the ``__iter__`` method will make additional + ``ListTopics`` requests and continue to iterate + through the ``topics`` field on the + corresponding responses. + + All the usual :class:`google.pubsub_v1.types.ListTopicsResponse` + attributes are available on the pager. If multiple requests are made, only + the most recent response is retained, and thus used for attribute lookup. + """ + + def __init__( + self, + method: Callable[..., pubsub.ListTopicsResponse], + request: pubsub.ListTopicsRequest, + response: pubsub.ListTopicsResponse, + *, + metadata: Sequence[Tuple[str, str]] = () + ): + """Instantiate the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.pubsub_v1.types.ListTopicsRequest): + The initial request object. + response (google.pubsub_v1.types.ListTopicsResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = pubsub.ListTopicsRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + def pages(self) -> Iterator[pubsub.ListTopicsResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = self._method(self._request, metadata=self._metadata) + yield self._response + + def __iter__(self) -> Iterator[pubsub.Topic]: + for page in self.pages: + yield from page.topics + + def __repr__(self) -> str: + return "{0}<{1!r}>".format(self.__class__.__name__, self._response) + + +class ListTopicsAsyncPager: + """A pager for iterating through ``list_topics`` requests. + + This class thinly wraps an initial + :class:`google.pubsub_v1.types.ListTopicsResponse` object, and + provides an ``__aiter__`` method to iterate through its + ``topics`` field. + + If there are more pages, the ``__aiter__`` method will make additional + ``ListTopics`` requests and continue to iterate + through the ``topics`` field on the + corresponding responses. + + All the usual :class:`google.pubsub_v1.types.ListTopicsResponse` + attributes are available on the pager. If multiple requests are made, only + the most recent response is retained, and thus used for attribute lookup. + """ + + def __init__( + self, + method: Callable[..., Awaitable[pubsub.ListTopicsResponse]], + request: pubsub.ListTopicsRequest, + response: pubsub.ListTopicsResponse, + *, + metadata: Sequence[Tuple[str, str]] = () + ): + """Instantiates the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.pubsub_v1.types.ListTopicsRequest): + The initial request object. + response (google.pubsub_v1.types.ListTopicsResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = pubsub.ListTopicsRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + async def pages(self) -> AsyncIterator[pubsub.ListTopicsResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = await self._method(self._request, metadata=self._metadata) + yield self._response + + def __aiter__(self) -> AsyncIterator[pubsub.Topic]: + async def async_generator(): + async for page in self.pages: + for response in page.topics: + yield response + + return async_generator() + + def __repr__(self) -> str: + return "{0}<{1!r}>".format(self.__class__.__name__, self._response) + + +class ListTopicSubscriptionsPager: + """A pager for iterating through ``list_topic_subscriptions`` requests. + + This class thinly wraps an initial + :class:`google.pubsub_v1.types.ListTopicSubscriptionsResponse` object, and + provides an ``__iter__`` method to iterate through its + ``subscriptions`` field. + + If there are more pages, the ``__iter__`` method will make additional + ``ListTopicSubscriptions`` requests and continue to iterate + through the ``subscriptions`` field on the + corresponding responses. + + All the usual :class:`google.pubsub_v1.types.ListTopicSubscriptionsResponse` + attributes are available on the pager. If multiple requests are made, only + the most recent response is retained, and thus used for attribute lookup. + """ + + def __init__( + self, + method: Callable[..., pubsub.ListTopicSubscriptionsResponse], + request: pubsub.ListTopicSubscriptionsRequest, + response: pubsub.ListTopicSubscriptionsResponse, + *, + metadata: Sequence[Tuple[str, str]] = () + ): + """Instantiate the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.pubsub_v1.types.ListTopicSubscriptionsRequest): + The initial request object. + response (google.pubsub_v1.types.ListTopicSubscriptionsResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = pubsub.ListTopicSubscriptionsRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + def pages(self) -> Iterator[pubsub.ListTopicSubscriptionsResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = self._method(self._request, metadata=self._metadata) + yield self._response + + def __iter__(self) -> Iterator[str]: + for page in self.pages: + yield from page.subscriptions + + def __repr__(self) -> str: + return "{0}<{1!r}>".format(self.__class__.__name__, self._response) + + +class ListTopicSubscriptionsAsyncPager: + """A pager for iterating through ``list_topic_subscriptions`` requests. + + This class thinly wraps an initial + :class:`google.pubsub_v1.types.ListTopicSubscriptionsResponse` object, and + provides an ``__aiter__`` method to iterate through its + ``subscriptions`` field. + + If there are more pages, the ``__aiter__`` method will make additional + ``ListTopicSubscriptions`` requests and continue to iterate + through the ``subscriptions`` field on the + corresponding responses. + + All the usual :class:`google.pubsub_v1.types.ListTopicSubscriptionsResponse` + attributes are available on the pager. If multiple requests are made, only + the most recent response is retained, and thus used for attribute lookup. + """ + + def __init__( + self, + method: Callable[..., Awaitable[pubsub.ListTopicSubscriptionsResponse]], + request: pubsub.ListTopicSubscriptionsRequest, + response: pubsub.ListTopicSubscriptionsResponse, + *, + metadata: Sequence[Tuple[str, str]] = () + ): + """Instantiates the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.pubsub_v1.types.ListTopicSubscriptionsRequest): + The initial request object. + response (google.pubsub_v1.types.ListTopicSubscriptionsResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = pubsub.ListTopicSubscriptionsRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + async def pages(self) -> AsyncIterator[pubsub.ListTopicSubscriptionsResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = await self._method(self._request, metadata=self._metadata) + yield self._response + + def __aiter__(self) -> AsyncIterator[str]: + async def async_generator(): + async for page in self.pages: + for response in page.subscriptions: + yield response + + return async_generator() + + def __repr__(self) -> str: + return "{0}<{1!r}>".format(self.__class__.__name__, self._response) + + +class ListTopicSnapshotsPager: + """A pager for iterating through ``list_topic_snapshots`` requests. + + This class thinly wraps an initial + :class:`google.pubsub_v1.types.ListTopicSnapshotsResponse` object, and + provides an ``__iter__`` method to iterate through its + ``snapshots`` field. + + If there are more pages, the ``__iter__`` method will make additional + ``ListTopicSnapshots`` requests and continue to iterate + through the ``snapshots`` field on the + corresponding responses. + + All the usual :class:`google.pubsub_v1.types.ListTopicSnapshotsResponse` + attributes are available on the pager. If multiple requests are made, only + the most recent response is retained, and thus used for attribute lookup. + """ + + def __init__( + self, + method: Callable[..., pubsub.ListTopicSnapshotsResponse], + request: pubsub.ListTopicSnapshotsRequest, + response: pubsub.ListTopicSnapshotsResponse, + *, + metadata: Sequence[Tuple[str, str]] = () + ): + """Instantiate the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.pubsub_v1.types.ListTopicSnapshotsRequest): + The initial request object. + response (google.pubsub_v1.types.ListTopicSnapshotsResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = pubsub.ListTopicSnapshotsRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + def pages(self) -> Iterator[pubsub.ListTopicSnapshotsResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = self._method(self._request, metadata=self._metadata) + yield self._response + + def __iter__(self) -> Iterator[str]: + for page in self.pages: + yield from page.snapshots + + def __repr__(self) -> str: + return "{0}<{1!r}>".format(self.__class__.__name__, self._response) + + +class ListTopicSnapshotsAsyncPager: + """A pager for iterating through ``list_topic_snapshots`` requests. + + This class thinly wraps an initial + :class:`google.pubsub_v1.types.ListTopicSnapshotsResponse` object, and + provides an ``__aiter__`` method to iterate through its + ``snapshots`` field. + + If there are more pages, the ``__aiter__`` method will make additional + ``ListTopicSnapshots`` requests and continue to iterate + through the ``snapshots`` field on the + corresponding responses. + + All the usual :class:`google.pubsub_v1.types.ListTopicSnapshotsResponse` + attributes are available on the pager. If multiple requests are made, only + the most recent response is retained, and thus used for attribute lookup. + """ + + def __init__( + self, + method: Callable[..., Awaitable[pubsub.ListTopicSnapshotsResponse]], + request: pubsub.ListTopicSnapshotsRequest, + response: pubsub.ListTopicSnapshotsResponse, + *, + metadata: Sequence[Tuple[str, str]] = () + ): + """Instantiates the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.pubsub_v1.types.ListTopicSnapshotsRequest): + The initial request object. + response (google.pubsub_v1.types.ListTopicSnapshotsResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = pubsub.ListTopicSnapshotsRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + async def pages(self) -> AsyncIterator[pubsub.ListTopicSnapshotsResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = await self._method(self._request, metadata=self._metadata) + yield self._response + + def __aiter__(self) -> AsyncIterator[str]: + async def async_generator(): + async for page in self.pages: + for response in page.snapshots: + yield response + + return async_generator() + + def __repr__(self) -> str: + return "{0}<{1!r}>".format(self.__class__.__name__, self._response) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/transports/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/transports/__init__.py new file mode 100644 index 000000000000..e73fe8901f80 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/transports/__init__.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +from collections import OrderedDict +from typing import Dict, Type + +from .base import PublisherTransport +from .grpc import PublisherGrpcTransport +from .grpc_asyncio import PublisherGrpcAsyncIOTransport + + +# Compile a registry of transports. +_transport_registry = OrderedDict() # type: Dict[str, Type[PublisherTransport]] +_transport_registry["grpc"] = PublisherGrpcTransport +_transport_registry["grpc_asyncio"] = PublisherGrpcAsyncIOTransport + +__all__ = ( + "PublisherTransport", + "PublisherGrpcTransport", + "PublisherGrpcAsyncIOTransport", +) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/transports/base.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/transports/base.py new file mode 100644 index 000000000000..11c085ffa7c0 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/transports/base.py @@ -0,0 +1,406 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +import abc +from typing import Awaitable, Callable, Dict, Optional, Sequence, Union +import pkg_resources + +import google.auth # type: ignore +import google.api_core +from google.api_core import exceptions as core_exceptions +from google.api_core import gapic_v1 +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.oauth2 import service_account # type: ignore + +from google.iam.v1 import iam_policy_pb2 # type: ignore +from google.iam.v1 import policy_pb2 # type: ignore +from google.protobuf import empty_pb2 # type: ignore +from google.pubsub_v1.types import pubsub + +try: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + client_library_version=pkg_resources.get_distribution( + "google-cloud-pubsub", + ).version, + ) +except pkg_resources.DistributionNotFound: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() + + +class PublisherTransport(abc.ABC): + """Abstract transport class for Publisher.""" + + AUTH_SCOPES = ( + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/pubsub", + ) + + DEFAULT_HOST: str = "pubsub.googleapis.com" + + def __init__( + self, + *, + host: str = DEFAULT_HOST, + credentials: ga_credentials.Credentials = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + api_audience: Optional[str] = None, + **kwargs, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is mutually exclusive with credentials. + scopes (Optional[Sequence[str]]): A list of scopes. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + """ + + scopes_kwargs = {"scopes": scopes, "default_scopes": self.AUTH_SCOPES} + + # Save the scopes. + self._scopes = scopes + + # If no credentials are provided, then determine the appropriate + # defaults. + if credentials and credentials_file: + raise core_exceptions.DuplicateCredentialArgs( + "'credentials_file' and 'credentials' are mutually exclusive" + ) + + if credentials_file is not None: + credentials, _ = google.auth.load_credentials_from_file( + credentials_file, **scopes_kwargs, quota_project_id=quota_project_id + ) + elif credentials is None: + credentials, _ = google.auth.default( + **scopes_kwargs, quota_project_id=quota_project_id + ) + # Don't apply audience if the credentials file passed from user. + if hasattr(credentials, "with_gdch_audience"): + credentials = credentials.with_gdch_audience( + api_audience if api_audience else host + ) + + # If the credentials are service account credentials, then always try to use self signed JWT. + if ( + always_use_jwt_access + and isinstance(credentials, service_account.Credentials) + and hasattr(service_account.Credentials, "with_always_use_jwt_access") + ): + credentials = credentials.with_always_use_jwt_access(True) + + # Save the credentials. + self._credentials = credentials + + # Save the hostname. Default to port 443 (HTTPS) if none is specified. + if ":" not in host: + host += ":443" + self._host = host + + def _prep_wrapped_messages(self, client_info): + # Precompute the wrapped methods. + self._wrapped_methods = { + self.create_topic: gapic_v1.method.wrap_method( + self.create_topic, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.ServiceUnavailable, + ), + deadline=600.0, + ), + default_timeout=60.0, + client_info=client_info, + ), + self.update_topic: gapic_v1.method.wrap_method( + self.update_topic, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.ServiceUnavailable, + ), + deadline=600.0, + ), + default_timeout=60.0, + client_info=client_info, + ), + self.publish: gapic_v1.method.wrap_method( + self.publish, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.Aborted, + core_exceptions.Cancelled, + core_exceptions.DeadlineExceeded, + core_exceptions.InternalServerError, + core_exceptions.ResourceExhausted, + core_exceptions.ServiceUnavailable, + core_exceptions.Unknown, + ), + deadline=600.0, + ), + default_timeout=60.0, + client_info=client_info, + ), + self.get_topic: gapic_v1.method.wrap_method( + self.get_topic, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.Aborted, + core_exceptions.ServiceUnavailable, + core_exceptions.Unknown, + ), + deadline=600.0, + ), + default_timeout=60.0, + client_info=client_info, + ), + self.list_topics: gapic_v1.method.wrap_method( + self.list_topics, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.Aborted, + core_exceptions.ServiceUnavailable, + core_exceptions.Unknown, + ), + deadline=600.0, + ), + default_timeout=60.0, + client_info=client_info, + ), + self.list_topic_subscriptions: gapic_v1.method.wrap_method( + self.list_topic_subscriptions, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.Aborted, + core_exceptions.ServiceUnavailable, + core_exceptions.Unknown, + ), + deadline=600.0, + ), + default_timeout=60.0, + client_info=client_info, + ), + self.list_topic_snapshots: gapic_v1.method.wrap_method( + self.list_topic_snapshots, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.Aborted, + core_exceptions.ServiceUnavailable, + core_exceptions.Unknown, + ), + deadline=600.0, + ), + default_timeout=60.0, + client_info=client_info, + ), + self.delete_topic: gapic_v1.method.wrap_method( + self.delete_topic, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.ServiceUnavailable, + ), + deadline=600.0, + ), + default_timeout=60.0, + client_info=client_info, + ), + self.detach_subscription: gapic_v1.method.wrap_method( + self.detach_subscription, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.ServiceUnavailable, + ), + deadline=600.0, + ), + default_timeout=60.0, + client_info=client_info, + ), + } + + def close(self): + """Closes resources associated with the transport. + + .. warning:: + Only call this method if the transport is NOT shared + with other clients - this may cause errors in other clients! + """ + raise NotImplementedError() + + @property + def create_topic( + self, + ) -> Callable[[pubsub.Topic], Union[pubsub.Topic, Awaitable[pubsub.Topic]]]: + raise NotImplementedError() + + @property + def update_topic( + self, + ) -> Callable[ + [pubsub.UpdateTopicRequest], Union[pubsub.Topic, Awaitable[pubsub.Topic]] + ]: + raise NotImplementedError() + + @property + def publish( + self, + ) -> Callable[ + [pubsub.PublishRequest], + Union[pubsub.PublishResponse, Awaitable[pubsub.PublishResponse]], + ]: + raise NotImplementedError() + + @property + def get_topic( + self, + ) -> Callable[ + [pubsub.GetTopicRequest], Union[pubsub.Topic, Awaitable[pubsub.Topic]] + ]: + raise NotImplementedError() + + @property + def list_topics( + self, + ) -> Callable[ + [pubsub.ListTopicsRequest], + Union[pubsub.ListTopicsResponse, Awaitable[pubsub.ListTopicsResponse]], + ]: + raise NotImplementedError() + + @property + def list_topic_subscriptions( + self, + ) -> Callable[ + [pubsub.ListTopicSubscriptionsRequest], + Union[ + pubsub.ListTopicSubscriptionsResponse, + Awaitable[pubsub.ListTopicSubscriptionsResponse], + ], + ]: + raise NotImplementedError() + + @property + def list_topic_snapshots( + self, + ) -> Callable[ + [pubsub.ListTopicSnapshotsRequest], + Union[ + pubsub.ListTopicSnapshotsResponse, + Awaitable[pubsub.ListTopicSnapshotsResponse], + ], + ]: + raise NotImplementedError() + + @property + def delete_topic( + self, + ) -> Callable[ + [pubsub.DeleteTopicRequest], Union[empty_pb2.Empty, Awaitable[empty_pb2.Empty]] + ]: + raise NotImplementedError() + + @property + def detach_subscription( + self, + ) -> Callable[ + [pubsub.DetachSubscriptionRequest], + Union[ + pubsub.DetachSubscriptionResponse, + Awaitable[pubsub.DetachSubscriptionResponse], + ], + ]: + raise NotImplementedError() + + @property + def set_iam_policy( + self, + ) -> Callable[ + [iam_policy_pb2.SetIamPolicyRequest], + Union[policy_pb2.Policy, Awaitable[policy_pb2.Policy]], + ]: + raise NotImplementedError() + + @property + def get_iam_policy( + self, + ) -> Callable[ + [iam_policy_pb2.GetIamPolicyRequest], + Union[policy_pb2.Policy, Awaitable[policy_pb2.Policy]], + ]: + raise NotImplementedError() + + @property + def test_iam_permissions( + self, + ) -> Callable[ + [iam_policy_pb2.TestIamPermissionsRequest], + Union[ + iam_policy_pb2.TestIamPermissionsResponse, + Awaitable[iam_policy_pb2.TestIamPermissionsResponse], + ], + ]: + raise NotImplementedError() + + @property + def kind(self) -> str: + raise NotImplementedError() + + +__all__ = ("PublisherTransport",) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/transports/grpc.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/transports/grpc.py new file mode 100644 index 000000000000..0d41c36f2a13 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/transports/grpc.py @@ -0,0 +1,575 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +import warnings +from typing import Callable, Dict, Optional, Sequence, Tuple, Union + +from google.api_core import grpc_helpers +from google.api_core import gapic_v1 +import google.auth # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore + +import grpc # type: ignore + +from google.iam.v1 import iam_policy_pb2 # type: ignore +from google.iam.v1 import policy_pb2 # type: ignore +from google.protobuf import empty_pb2 # type: ignore +from google.pubsub_v1.types import pubsub +from .base import PublisherTransport, DEFAULT_CLIENT_INFO + + +class PublisherGrpcTransport(PublisherTransport): + """gRPC backend transport for Publisher. + + The service that an application uses to manipulate topics, + and to send messages to a topic. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends protocol buffers over the wire using gRPC (which is built on + top of HTTP/2); the ``grpcio`` package must be installed. + """ + + _stubs: Dict[str, Callable] + + def __init__( + self, + *, + host: str = "pubsub.googleapis.com", + credentials: ga_credentials.Credentials = None, + credentials_file: str = None, + scopes: Sequence[str] = None, + channel: grpc.Channel = None, + api_mtls_endpoint: str = None, + client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, + ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + This argument is ignored if ``channel`` is provided. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + channel (Optional[grpc.Channel]): A ``Channel`` instance through + which to make calls. + api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. + If provided, it overrides the ``host`` argument and tries to create + a mutual TLS channel with client SSL credentials from + ``client_cert_source`` or application default SSL credentials. + client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): + Deprecated. A callback to provide client SSL certificate bytes and + private key bytes, both in PEM format. It is ignored if + ``api_mtls_endpoint`` is None. + ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials + for the grpc channel. It is ignored if ``channel`` is provided. + client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): + A callback to provide client certificate bytes and private key bytes, + both in PEM format. It is used to configure a mutual TLS channel. It is + ignored if ``channel`` or ``ssl_channel_credentials`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport + creation failed for any reason. + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + self._grpc_channel = None + self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} + + if api_mtls_endpoint: + warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning) + if client_cert_source: + warnings.warn("client_cert_source is deprecated", DeprecationWarning) + + if channel: + # Ignore credentials if a channel was passed. + credentials = False + # If a channel was explicitly provided, set it. + self._grpc_channel = channel + self._ssl_channel_credentials = None + + else: + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials + + else: + if client_cert_source_for_mtls and not ssl_channel_credentials: + cert, key = client_cert_source_for_mtls() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + + # The base transport sets the host, credentials and scopes + super().__init__( + host=host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + + if not self._grpc_channel: + self._grpc_channel = type(self).create_channel( + self._host, + # use the credentials which are saved + credentials=self._credentials, + # Set ``credentials_file`` to ``None`` here as + # the credentials that we saved earlier should be used. + credentials_file=None, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, + quota_project_id=quota_project_id, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ("grpc.max_metadata_size", 4 * 1024 * 1024), + ("grpc.keepalive_time_ms", 30000), + ], + ) + + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) + + @classmethod + def create_channel( + cls, + host: str = "pubsub.googleapis.com", + credentials: ga_credentials.Credentials = None, + credentials_file: str = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + **kwargs, + ) -> grpc.Channel: + """Create and return a gRPC channel object. + Args: + host (Optional[str]): The host for the channel to use. + credentials (Optional[~.Credentials]): The + authorization credentials to attach to requests. These + credentials identify this application to the service. If + none are specified, the client will attempt to ascertain + the credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is mutually exclusive with credentials. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + kwargs (Optional[dict]): Keyword arguments, which are passed to the + channel creation. + Returns: + grpc.Channel: A gRPC channel object. + + Raises: + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + + return grpc_helpers.create_channel( + host, + credentials=credentials, + credentials_file=credentials_file, + quota_project_id=quota_project_id, + default_scopes=cls.AUTH_SCOPES, + scopes=scopes, + default_host=cls.DEFAULT_HOST, + **kwargs, + ) + + @property + def grpc_channel(self) -> grpc.Channel: + """Return the channel designed to connect to this service.""" + return self._grpc_channel + + @property + def create_topic(self) -> Callable[[pubsub.Topic], pubsub.Topic]: + r"""Return a callable for the create topic method over gRPC. + + Creates the given topic with the given name. See the [resource + name rules] + (https://cloud.google.com/pubsub/docs/admin#resource_names). + + Returns: + Callable[[~.Topic], + ~.Topic]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "create_topic" not in self._stubs: + self._stubs["create_topic"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Publisher/CreateTopic", + request_serializer=pubsub.Topic.serialize, + response_deserializer=pubsub.Topic.deserialize, + ) + return self._stubs["create_topic"] + + @property + def update_topic(self) -> Callable[[pubsub.UpdateTopicRequest], pubsub.Topic]: + r"""Return a callable for the update topic method over gRPC. + + Updates an existing topic. Note that certain + properties of a topic are not modifiable. + + Returns: + Callable[[~.UpdateTopicRequest], + ~.Topic]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "update_topic" not in self._stubs: + self._stubs["update_topic"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Publisher/UpdateTopic", + request_serializer=pubsub.UpdateTopicRequest.serialize, + response_deserializer=pubsub.Topic.deserialize, + ) + return self._stubs["update_topic"] + + @property + def publish(self) -> Callable[[pubsub.PublishRequest], pubsub.PublishResponse]: + r"""Return a callable for the publish method over gRPC. + + Adds one or more messages to the topic. Returns ``NOT_FOUND`` if + the topic does not exist. + + Returns: + Callable[[~.PublishRequest], + ~.PublishResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "publish" not in self._stubs: + self._stubs["publish"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Publisher/Publish", + request_serializer=pubsub.PublishRequest.serialize, + response_deserializer=pubsub.PublishResponse.deserialize, + ) + return self._stubs["publish"] + + @property + def get_topic(self) -> Callable[[pubsub.GetTopicRequest], pubsub.Topic]: + r"""Return a callable for the get topic method over gRPC. + + Gets the configuration of a topic. + + Returns: + Callable[[~.GetTopicRequest], + ~.Topic]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_topic" not in self._stubs: + self._stubs["get_topic"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Publisher/GetTopic", + request_serializer=pubsub.GetTopicRequest.serialize, + response_deserializer=pubsub.Topic.deserialize, + ) + return self._stubs["get_topic"] + + @property + def list_topics( + self, + ) -> Callable[[pubsub.ListTopicsRequest], pubsub.ListTopicsResponse]: + r"""Return a callable for the list topics method over gRPC. + + Lists matching topics. + + Returns: + Callable[[~.ListTopicsRequest], + ~.ListTopicsResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_topics" not in self._stubs: + self._stubs["list_topics"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Publisher/ListTopics", + request_serializer=pubsub.ListTopicsRequest.serialize, + response_deserializer=pubsub.ListTopicsResponse.deserialize, + ) + return self._stubs["list_topics"] + + @property + def list_topic_subscriptions( + self, + ) -> Callable[ + [pubsub.ListTopicSubscriptionsRequest], pubsub.ListTopicSubscriptionsResponse + ]: + r"""Return a callable for the list topic subscriptions method over gRPC. + + Lists the names of the attached subscriptions on this + topic. + + Returns: + Callable[[~.ListTopicSubscriptionsRequest], + ~.ListTopicSubscriptionsResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_topic_subscriptions" not in self._stubs: + self._stubs["list_topic_subscriptions"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Publisher/ListTopicSubscriptions", + request_serializer=pubsub.ListTopicSubscriptionsRequest.serialize, + response_deserializer=pubsub.ListTopicSubscriptionsResponse.deserialize, + ) + return self._stubs["list_topic_subscriptions"] + + @property + def list_topic_snapshots( + self, + ) -> Callable[ + [pubsub.ListTopicSnapshotsRequest], pubsub.ListTopicSnapshotsResponse + ]: + r"""Return a callable for the list topic snapshots method over gRPC. + + Lists the names of the snapshots on this topic. Snapshots are + used in + `Seek `__ + operations, which allow you to manage message acknowledgments in + bulk. That is, you can set the acknowledgment state of messages + in an existing subscription to the state captured by a snapshot. + + Returns: + Callable[[~.ListTopicSnapshotsRequest], + ~.ListTopicSnapshotsResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_topic_snapshots" not in self._stubs: + self._stubs["list_topic_snapshots"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Publisher/ListTopicSnapshots", + request_serializer=pubsub.ListTopicSnapshotsRequest.serialize, + response_deserializer=pubsub.ListTopicSnapshotsResponse.deserialize, + ) + return self._stubs["list_topic_snapshots"] + + @property + def delete_topic(self) -> Callable[[pubsub.DeleteTopicRequest], empty_pb2.Empty]: + r"""Return a callable for the delete topic method over gRPC. + + Deletes the topic with the given name. Returns ``NOT_FOUND`` if + the topic does not exist. After a topic is deleted, a new topic + may be created with the same name; this is an entirely new topic + with none of the old configuration or subscriptions. Existing + subscriptions to this topic are not deleted, but their ``topic`` + field is set to ``_deleted-topic_``. + + Returns: + Callable[[~.DeleteTopicRequest], + ~.Empty]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "delete_topic" not in self._stubs: + self._stubs["delete_topic"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Publisher/DeleteTopic", + request_serializer=pubsub.DeleteTopicRequest.serialize, + response_deserializer=empty_pb2.Empty.FromString, + ) + return self._stubs["delete_topic"] + + @property + def detach_subscription( + self, + ) -> Callable[ + [pubsub.DetachSubscriptionRequest], pubsub.DetachSubscriptionResponse + ]: + r"""Return a callable for the detach subscription method over gRPC. + + Detaches a subscription from this topic. All messages retained + in the subscription are dropped. Subsequent ``Pull`` and + ``StreamingPull`` requests will return FAILED_PRECONDITION. If + the subscription is a push subscription, pushes to the endpoint + will stop. + + Returns: + Callable[[~.DetachSubscriptionRequest], + ~.DetachSubscriptionResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "detach_subscription" not in self._stubs: + self._stubs["detach_subscription"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Publisher/DetachSubscription", + request_serializer=pubsub.DetachSubscriptionRequest.serialize, + response_deserializer=pubsub.DetachSubscriptionResponse.deserialize, + ) + return self._stubs["detach_subscription"] + + @property + def set_iam_policy( + self, + ) -> Callable[[iam_policy_pb2.SetIamPolicyRequest], policy_pb2.Policy]: + r"""Return a callable for the set iam policy method over gRPC. + Sets the IAM access control policy on the specified + function. Replaces any existing policy. + Returns: + Callable[[~.SetIamPolicyRequest], + ~.Policy]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "set_iam_policy" not in self._stubs: + self._stubs["set_iam_policy"] = self.grpc_channel.unary_unary( + "/google.iam.v1.IAMPolicy/SetIamPolicy", + request_serializer=iam_policy_pb2.SetIamPolicyRequest.SerializeToString, + response_deserializer=policy_pb2.Policy.FromString, + ) + return self._stubs["set_iam_policy"] + + @property + def get_iam_policy( + self, + ) -> Callable[[iam_policy_pb2.GetIamPolicyRequest], policy_pb2.Policy]: + r"""Return a callable for the get iam policy method over gRPC. + Gets the IAM access control policy for a function. + Returns an empty policy if the function exists and does + not have a policy set. + Returns: + Callable[[~.GetIamPolicyRequest], + ~.Policy]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_iam_policy" not in self._stubs: + self._stubs["get_iam_policy"] = self.grpc_channel.unary_unary( + "/google.iam.v1.IAMPolicy/GetIamPolicy", + request_serializer=iam_policy_pb2.GetIamPolicyRequest.SerializeToString, + response_deserializer=policy_pb2.Policy.FromString, + ) + return self._stubs["get_iam_policy"] + + @property + def test_iam_permissions( + self, + ) -> Callable[ + [iam_policy_pb2.TestIamPermissionsRequest], + iam_policy_pb2.TestIamPermissionsResponse, + ]: + r"""Return a callable for the test iam permissions method over gRPC. + Tests the specified permissions against the IAM access control + policy for a function. If the function does not exist, this will + return an empty set of permissions, not a NOT_FOUND error. + Returns: + Callable[[~.TestIamPermissionsRequest], + ~.TestIamPermissionsResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "test_iam_permissions" not in self._stubs: + self._stubs["test_iam_permissions"] = self.grpc_channel.unary_unary( + "/google.iam.v1.IAMPolicy/TestIamPermissions", + request_serializer=iam_policy_pb2.TestIamPermissionsRequest.SerializeToString, + response_deserializer=iam_policy_pb2.TestIamPermissionsResponse.FromString, + ) + return self._stubs["test_iam_permissions"] + + def close(self): + self.grpc_channel.close() + + @property + def kind(self) -> str: + return "grpc" + + +__all__ = ("PublisherGrpcTransport",) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/transports/grpc_asyncio.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/transports/grpc_asyncio.py new file mode 100644 index 000000000000..e236c165cae7 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/transports/grpc_asyncio.py @@ -0,0 +1,581 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +import warnings +from typing import Awaitable, Callable, Dict, Optional, Sequence, Tuple, Union + +from google.api_core import gapic_v1 +from google.api_core import grpc_helpers_async +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore + +import grpc # type: ignore +from grpc.experimental import aio # type: ignore + +from google.iam.v1 import iam_policy_pb2 # type: ignore +from google.iam.v1 import policy_pb2 # type: ignore +from google.protobuf import empty_pb2 # type: ignore +from google.pubsub_v1.types import pubsub +from .base import PublisherTransport, DEFAULT_CLIENT_INFO +from .grpc import PublisherGrpcTransport + + +class PublisherGrpcAsyncIOTransport(PublisherTransport): + """gRPC AsyncIO backend transport for Publisher. + + The service that an application uses to manipulate topics, + and to send messages to a topic. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends protocol buffers over the wire using gRPC (which is built on + top of HTTP/2); the ``grpcio`` package must be installed. + """ + + _grpc_channel: aio.Channel + _stubs: Dict[str, Callable] = {} + + @classmethod + def create_channel( + cls, + host: str = "pubsub.googleapis.com", + credentials: ga_credentials.Credentials = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + **kwargs, + ) -> aio.Channel: + """Create and return a gRPC AsyncIO channel object. + Args: + host (Optional[str]): The host for the channel to use. + credentials (Optional[~.Credentials]): The + authorization credentials to attach to requests. These + credentials identify this application to the service. If + none are specified, the client will attempt to ascertain + the credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + kwargs (Optional[dict]): Keyword arguments, which are passed to the + channel creation. + Returns: + aio.Channel: A gRPC AsyncIO channel object. + """ + + return grpc_helpers_async.create_channel( + host, + credentials=credentials, + credentials_file=credentials_file, + quota_project_id=quota_project_id, + default_scopes=cls.AUTH_SCOPES, + scopes=scopes, + default_host=cls.DEFAULT_HOST, + **kwargs, + ) + + def __init__( + self, + *, + host: str = "pubsub.googleapis.com", + credentials: ga_credentials.Credentials = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + channel: aio.Channel = None, + api_mtls_endpoint: str = None, + client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, + ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, + quota_project_id=None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + This argument is ignored if ``channel`` is provided. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + channel (Optional[aio.Channel]): A ``Channel`` instance through + which to make calls. + api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. + If provided, it overrides the ``host`` argument and tries to create + a mutual TLS channel with client SSL credentials from + ``client_cert_source`` or application default SSL credentials. + client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): + Deprecated. A callback to provide client SSL certificate bytes and + private key bytes, both in PEM format. It is ignored if + ``api_mtls_endpoint`` is None. + ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials + for the grpc channel. It is ignored if ``channel`` is provided. + client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): + A callback to provide client certificate bytes and private key bytes, + both in PEM format. It is used to configure a mutual TLS channel. It is + ignored if ``channel`` or ``ssl_channel_credentials`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + + Raises: + google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport + creation failed for any reason. + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + self._grpc_channel = None + self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} + + if api_mtls_endpoint: + warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning) + if client_cert_source: + warnings.warn("client_cert_source is deprecated", DeprecationWarning) + + if channel: + # Ignore credentials if a channel was passed. + credentials = False + # If a channel was explicitly provided, set it. + self._grpc_channel = channel + self._ssl_channel_credentials = None + else: + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials + + else: + if client_cert_source_for_mtls and not ssl_channel_credentials: + cert, key = client_cert_source_for_mtls() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + + # The base transport sets the host, credentials and scopes + super().__init__( + host=host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + + if not self._grpc_channel: + self._grpc_channel = type(self).create_channel( + self._host, + # use the credentials which are saved + credentials=self._credentials, + # Set ``credentials_file`` to ``None`` here as + # the credentials that we saved earlier should be used. + credentials_file=None, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, + quota_project_id=quota_project_id, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ("grpc.max_metadata_size", 4 * 1024 * 1024), + ("grpc.keepalive_time_ms", 30000), + ], + ) + + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) + + @property + def grpc_channel(self) -> aio.Channel: + """Create the channel designed to connect to this service. + + This property caches on the instance; repeated calls return + the same channel. + """ + # Return the channel from cache. + return self._grpc_channel + + @property + def create_topic(self) -> Callable[[pubsub.Topic], Awaitable[pubsub.Topic]]: + r"""Return a callable for the create topic method over gRPC. + + Creates the given topic with the given name. See the [resource + name rules] + (https://cloud.google.com/pubsub/docs/admin#resource_names). + + Returns: + Callable[[~.Topic], + Awaitable[~.Topic]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "create_topic" not in self._stubs: + self._stubs["create_topic"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Publisher/CreateTopic", + request_serializer=pubsub.Topic.serialize, + response_deserializer=pubsub.Topic.deserialize, + ) + return self._stubs["create_topic"] + + @property + def update_topic( + self, + ) -> Callable[[pubsub.UpdateTopicRequest], Awaitable[pubsub.Topic]]: + r"""Return a callable for the update topic method over gRPC. + + Updates an existing topic. Note that certain + properties of a topic are not modifiable. + + Returns: + Callable[[~.UpdateTopicRequest], + Awaitable[~.Topic]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "update_topic" not in self._stubs: + self._stubs["update_topic"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Publisher/UpdateTopic", + request_serializer=pubsub.UpdateTopicRequest.serialize, + response_deserializer=pubsub.Topic.deserialize, + ) + return self._stubs["update_topic"] + + @property + def publish( + self, + ) -> Callable[[pubsub.PublishRequest], Awaitable[pubsub.PublishResponse]]: + r"""Return a callable for the publish method over gRPC. + + Adds one or more messages to the topic. Returns ``NOT_FOUND`` if + the topic does not exist. + + Returns: + Callable[[~.PublishRequest], + Awaitable[~.PublishResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "publish" not in self._stubs: + self._stubs["publish"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Publisher/Publish", + request_serializer=pubsub.PublishRequest.serialize, + response_deserializer=pubsub.PublishResponse.deserialize, + ) + return self._stubs["publish"] + + @property + def get_topic(self) -> Callable[[pubsub.GetTopicRequest], Awaitable[pubsub.Topic]]: + r"""Return a callable for the get topic method over gRPC. + + Gets the configuration of a topic. + + Returns: + Callable[[~.GetTopicRequest], + Awaitable[~.Topic]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_topic" not in self._stubs: + self._stubs["get_topic"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Publisher/GetTopic", + request_serializer=pubsub.GetTopicRequest.serialize, + response_deserializer=pubsub.Topic.deserialize, + ) + return self._stubs["get_topic"] + + @property + def list_topics( + self, + ) -> Callable[[pubsub.ListTopicsRequest], Awaitable[pubsub.ListTopicsResponse]]: + r"""Return a callable for the list topics method over gRPC. + + Lists matching topics. + + Returns: + Callable[[~.ListTopicsRequest], + Awaitable[~.ListTopicsResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_topics" not in self._stubs: + self._stubs["list_topics"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Publisher/ListTopics", + request_serializer=pubsub.ListTopicsRequest.serialize, + response_deserializer=pubsub.ListTopicsResponse.deserialize, + ) + return self._stubs["list_topics"] + + @property + def list_topic_subscriptions( + self, + ) -> Callable[ + [pubsub.ListTopicSubscriptionsRequest], + Awaitable[pubsub.ListTopicSubscriptionsResponse], + ]: + r"""Return a callable for the list topic subscriptions method over gRPC. + + Lists the names of the attached subscriptions on this + topic. + + Returns: + Callable[[~.ListTopicSubscriptionsRequest], + Awaitable[~.ListTopicSubscriptionsResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_topic_subscriptions" not in self._stubs: + self._stubs["list_topic_subscriptions"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Publisher/ListTopicSubscriptions", + request_serializer=pubsub.ListTopicSubscriptionsRequest.serialize, + response_deserializer=pubsub.ListTopicSubscriptionsResponse.deserialize, + ) + return self._stubs["list_topic_subscriptions"] + + @property + def list_topic_snapshots( + self, + ) -> Callable[ + [pubsub.ListTopicSnapshotsRequest], Awaitable[pubsub.ListTopicSnapshotsResponse] + ]: + r"""Return a callable for the list topic snapshots method over gRPC. + + Lists the names of the snapshots on this topic. Snapshots are + used in + `Seek `__ + operations, which allow you to manage message acknowledgments in + bulk. That is, you can set the acknowledgment state of messages + in an existing subscription to the state captured by a snapshot. + + Returns: + Callable[[~.ListTopicSnapshotsRequest], + Awaitable[~.ListTopicSnapshotsResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_topic_snapshots" not in self._stubs: + self._stubs["list_topic_snapshots"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Publisher/ListTopicSnapshots", + request_serializer=pubsub.ListTopicSnapshotsRequest.serialize, + response_deserializer=pubsub.ListTopicSnapshotsResponse.deserialize, + ) + return self._stubs["list_topic_snapshots"] + + @property + def delete_topic( + self, + ) -> Callable[[pubsub.DeleteTopicRequest], Awaitable[empty_pb2.Empty]]: + r"""Return a callable for the delete topic method over gRPC. + + Deletes the topic with the given name. Returns ``NOT_FOUND`` if + the topic does not exist. After a topic is deleted, a new topic + may be created with the same name; this is an entirely new topic + with none of the old configuration or subscriptions. Existing + subscriptions to this topic are not deleted, but their ``topic`` + field is set to ``_deleted-topic_``. + + Returns: + Callable[[~.DeleteTopicRequest], + Awaitable[~.Empty]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "delete_topic" not in self._stubs: + self._stubs["delete_topic"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Publisher/DeleteTopic", + request_serializer=pubsub.DeleteTopicRequest.serialize, + response_deserializer=empty_pb2.Empty.FromString, + ) + return self._stubs["delete_topic"] + + @property + def detach_subscription( + self, + ) -> Callable[ + [pubsub.DetachSubscriptionRequest], Awaitable[pubsub.DetachSubscriptionResponse] + ]: + r"""Return a callable for the detach subscription method over gRPC. + + Detaches a subscription from this topic. All messages retained + in the subscription are dropped. Subsequent ``Pull`` and + ``StreamingPull`` requests will return FAILED_PRECONDITION. If + the subscription is a push subscription, pushes to the endpoint + will stop. + + Returns: + Callable[[~.DetachSubscriptionRequest], + Awaitable[~.DetachSubscriptionResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "detach_subscription" not in self._stubs: + self._stubs["detach_subscription"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Publisher/DetachSubscription", + request_serializer=pubsub.DetachSubscriptionRequest.serialize, + response_deserializer=pubsub.DetachSubscriptionResponse.deserialize, + ) + return self._stubs["detach_subscription"] + + @property + def set_iam_policy( + self, + ) -> Callable[[iam_policy_pb2.SetIamPolicyRequest], Awaitable[policy_pb2.Policy]]: + r"""Return a callable for the set iam policy method over gRPC. + Sets the IAM access control policy on the specified + function. Replaces any existing policy. + Returns: + Callable[[~.SetIamPolicyRequest], + Awaitable[~.Policy]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "set_iam_policy" not in self._stubs: + self._stubs["set_iam_policy"] = self.grpc_channel.unary_unary( + "/google.iam.v1.IAMPolicy/SetIamPolicy", + request_serializer=iam_policy_pb2.SetIamPolicyRequest.SerializeToString, + response_deserializer=policy_pb2.Policy.FromString, + ) + return self._stubs["set_iam_policy"] + + @property + def get_iam_policy( + self, + ) -> Callable[[iam_policy_pb2.GetIamPolicyRequest], Awaitable[policy_pb2.Policy]]: + r"""Return a callable for the get iam policy method over gRPC. + Gets the IAM access control policy for a function. + Returns an empty policy if the function exists and does + not have a policy set. + Returns: + Callable[[~.GetIamPolicyRequest], + Awaitable[~.Policy]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_iam_policy" not in self._stubs: + self._stubs["get_iam_policy"] = self.grpc_channel.unary_unary( + "/google.iam.v1.IAMPolicy/GetIamPolicy", + request_serializer=iam_policy_pb2.GetIamPolicyRequest.SerializeToString, + response_deserializer=policy_pb2.Policy.FromString, + ) + return self._stubs["get_iam_policy"] + + @property + def test_iam_permissions( + self, + ) -> Callable[ + [iam_policy_pb2.TestIamPermissionsRequest], + Awaitable[iam_policy_pb2.TestIamPermissionsResponse], + ]: + r"""Return a callable for the test iam permissions method over gRPC. + Tests the specified permissions against the IAM access control + policy for a function. If the function does not exist, this will + return an empty set of permissions, not a NOT_FOUND error. + Returns: + Callable[[~.TestIamPermissionsRequest], + Awaitable[~.TestIamPermissionsResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "test_iam_permissions" not in self._stubs: + self._stubs["test_iam_permissions"] = self.grpc_channel.unary_unary( + "/google.iam.v1.IAMPolicy/TestIamPermissions", + request_serializer=iam_policy_pb2.TestIamPermissionsRequest.SerializeToString, + response_deserializer=iam_policy_pb2.TestIamPermissionsResponse.FromString, + ) + return self._stubs["test_iam_permissions"] + + def close(self): + return self.grpc_channel.close() + + +__all__ = ("PublisherGrpcAsyncIOTransport",) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/schema_service/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/schema_service/__init__.py new file mode 100644 index 000000000000..2609e9ecd722 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/schema_service/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +from .client import SchemaServiceClient +from .async_client import SchemaServiceAsyncClient + +__all__ = ( + "SchemaServiceClient", + "SchemaServiceAsyncClient", +) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/schema_service/async_client.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/schema_service/async_client.py new file mode 100644 index 000000000000..f0f158b6fac4 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/schema_service/async_client.py @@ -0,0 +1,1154 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +from collections import OrderedDict +import functools +import re +from typing import Dict, Mapping, Optional, Sequence, Tuple, Type, Union +import pkg_resources + +from google.api_core.client_options import ClientOptions +from google.api_core import exceptions as core_exceptions +from google.api_core import gapic_v1 +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.oauth2 import service_account # type: ignore + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + +from google.iam.v1 import iam_policy_pb2 # type: ignore +from google.iam.v1 import policy_pb2 # type: ignore +from google.pubsub_v1.services.schema_service import pagers +from google.pubsub_v1.types import schema +from google.pubsub_v1.types import schema as gp_schema +from .transports.base import SchemaServiceTransport, DEFAULT_CLIENT_INFO +from .transports.grpc_asyncio import SchemaServiceGrpcAsyncIOTransport +from .client import SchemaServiceClient + + +class SchemaServiceAsyncClient: + """Service for doing schema-related operations.""" + + _client: SchemaServiceClient + + DEFAULT_ENDPOINT = SchemaServiceClient.DEFAULT_ENDPOINT + DEFAULT_MTLS_ENDPOINT = SchemaServiceClient.DEFAULT_MTLS_ENDPOINT + + schema_path = staticmethod(SchemaServiceClient.schema_path) + parse_schema_path = staticmethod(SchemaServiceClient.parse_schema_path) + common_billing_account_path = staticmethod( + SchemaServiceClient.common_billing_account_path + ) + parse_common_billing_account_path = staticmethod( + SchemaServiceClient.parse_common_billing_account_path + ) + common_folder_path = staticmethod(SchemaServiceClient.common_folder_path) + parse_common_folder_path = staticmethod( + SchemaServiceClient.parse_common_folder_path + ) + common_organization_path = staticmethod( + SchemaServiceClient.common_organization_path + ) + parse_common_organization_path = staticmethod( + SchemaServiceClient.parse_common_organization_path + ) + common_project_path = staticmethod(SchemaServiceClient.common_project_path) + parse_common_project_path = staticmethod( + SchemaServiceClient.parse_common_project_path + ) + common_location_path = staticmethod(SchemaServiceClient.common_location_path) + parse_common_location_path = staticmethod( + SchemaServiceClient.parse_common_location_path + ) + + @classmethod + def from_service_account_info(cls, info: dict, *args, **kwargs): + """Creates an instance of this client using the provided credentials + info. + + Args: + info (dict): The service account private key info. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + SchemaServiceAsyncClient: The constructed client. + """ + return SchemaServiceClient.from_service_account_info.__func__(SchemaServiceAsyncClient, info, *args, **kwargs) # type: ignore + + @classmethod + def from_service_account_file(cls, filename: str, *args, **kwargs): + """Creates an instance of this client using the provided credentials + file. + + Args: + filename (str): The path to the service account private key json + file. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + SchemaServiceAsyncClient: The constructed client. + """ + return SchemaServiceClient.from_service_account_file.__func__(SchemaServiceAsyncClient, filename, *args, **kwargs) # type: ignore + + from_service_account_json = from_service_account_file + + @classmethod + def get_mtls_endpoint_and_cert_source( + cls, client_options: Optional[ClientOptions] = None + ): + """Return the API endpoint and client cert source for mutual TLS. + + The client cert source is determined in the following order: + (1) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not "true", the + client cert source is None. + (2) if `client_options.client_cert_source` is provided, use the provided one; if the + default client cert source exists, use the default one; otherwise the client cert + source is None. + + The API endpoint is determined in the following order: + (1) if `client_options.api_endpoint` if provided, use the provided one. + (2) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is "always", use the + default mTLS endpoint; if the environment variabel is "never", use the default API + endpoint; otherwise if client cert source exists, use the default mTLS endpoint, otherwise + use the default API endpoint. + + More details can be found at https://google.aip.dev/auth/4114. + + Args: + client_options (google.api_core.client_options.ClientOptions): Custom options for the + client. Only the `api_endpoint` and `client_cert_source` properties may be used + in this method. + + Returns: + Tuple[str, Callable[[], Tuple[bytes, bytes]]]: returns the API endpoint and the + client cert source to use. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If any errors happen. + """ + return SchemaServiceClient.get_mtls_endpoint_and_cert_source(client_options) # type: ignore + + @property + def transport(self) -> SchemaServiceTransport: + """Returns the transport used by the client instance. + + Returns: + SchemaServiceTransport: The transport used by the client instance. + """ + return self._client.transport + + get_transport_class = functools.partial( + type(SchemaServiceClient).get_transport_class, type(SchemaServiceClient) + ) + + def __init__( + self, + *, + credentials: ga_credentials.Credentials = None, + transport: Union[str, SchemaServiceTransport] = "grpc_asyncio", + client_options: ClientOptions = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + ) -> None: + """Instantiates the schema service client. + + Args: + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + transport (Union[str, ~.SchemaServiceTransport]): The + transport to use. If set to None, a transport is chosen + automatically. + client_options (ClientOptions): Custom options for the client. It + won't take effect if a ``transport`` instance is provided. + (1) The ``api_endpoint`` property can be used to override the + default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT + environment variable can also be used to override the endpoint: + "always" (always use the default mTLS endpoint), "never" (always + use the default regular endpoint) and "auto" (auto switch to the + default mTLS endpoint if client certificate is present, this is + the default value). However, the ``api_endpoint`` property takes + precedence if provided. + (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable + is "true", then the ``client_cert_source`` property can be used + to provide client certificate for mutual TLS transport. If + not provided, the default SSL client certificate will be used if + present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not + set, no client certificate will be used. + + Raises: + google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport + creation failed for any reason. + """ + self._client = SchemaServiceClient( + credentials=credentials, + transport=transport, + client_options=client_options, + client_info=client_info, + ) + + async def create_schema( + self, + request: Union[gp_schema.CreateSchemaRequest, dict] = None, + *, + parent: str = None, + schema: gp_schema.Schema = None, + schema_id: str = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gp_schema.Schema: + r"""Creates a schema. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + async def sample_create_schema(): + # Create a client + client = pubsub_v1.SchemaServiceAsyncClient() + + # Initialize request argument(s) + schema = pubsub_v1.Schema() + schema.name = "name_value" + + request = pubsub_v1.CreateSchemaRequest( + parent="parent_value", + schema=schema, + ) + + # Make the request + response = await client.create_schema(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.pubsub_v1.types.CreateSchemaRequest, dict]): + The request object. Request for the CreateSchema method. + parent (:class:`str`): + Required. The name of the project in which to create the + schema. Format is ``projects/{project-id}``. + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + schema (:class:`google.pubsub_v1.types.Schema`): + Required. The schema object to create. + + This schema's ``name`` parameter is ignored. The schema + object returned by CreateSchema will have a ``name`` + made using the given ``parent`` and ``schema_id``. + + This corresponds to the ``schema`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + schema_id (:class:`str`): + The ID to use for the schema, which will become the + final component of the schema's resource name. + + See + https://cloud.google.com/pubsub/docs/admin#resource_names + for resource name constraints. + + This corresponds to the ``schema_id`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.pubsub_v1.types.Schema: + A schema resource. + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent, schema, schema_id]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = gp_schema.CreateSchemaRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if parent is not None: + request.parent = parent + if schema is not None: + request.schema = schema + if schema_id is not None: + request.schema_id = schema_id + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.create_schema, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def get_schema( + self, + request: Union[schema.GetSchemaRequest, dict] = None, + *, + name: str = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> schema.Schema: + r"""Gets a schema. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + async def sample_get_schema(): + # Create a client + client = pubsub_v1.SchemaServiceAsyncClient() + + # Initialize request argument(s) + request = pubsub_v1.GetSchemaRequest( + name="name_value", + ) + + # Make the request + response = await client.get_schema(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.pubsub_v1.types.GetSchemaRequest, dict]): + The request object. Request for the GetSchema method. + name (:class:`str`): + Required. The name of the schema to get. Format is + ``projects/{project}/schemas/{schema}``. + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.pubsub_v1.types.Schema: + A schema resource. + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = schema.GetSchemaRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.get_schema, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def list_schemas( + self, + request: Union[schema.ListSchemasRequest, dict] = None, + *, + parent: str = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListSchemasAsyncPager: + r"""Lists schemas in a project. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + async def sample_list_schemas(): + # Create a client + client = pubsub_v1.SchemaServiceAsyncClient() + + # Initialize request argument(s) + request = pubsub_v1.ListSchemasRequest( + parent="parent_value", + ) + + # Make the request + page_result = client.list_schemas(request=request) + + # Handle the response + async for response in page_result: + print(response) + + Args: + request (Union[google.pubsub_v1.types.ListSchemasRequest, dict]): + The request object. Request for the `ListSchemas` + method. + parent (:class:`str`): + Required. The name of the project in which to list + schemas. Format is ``projects/{project-id}``. + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.pubsub_v1.services.schema_service.pagers.ListSchemasAsyncPager: + Response for the ListSchemas method. + + Iterating over this object will yield results and + resolve additional pages automatically. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = schema.ListSchemasRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if parent is not None: + request.parent = parent + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.list_schemas, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # This method is paged; wrap the response in a pager, which provides + # an `__aiter__` convenience method. + response = pagers.ListSchemasAsyncPager( + method=rpc, + request=request, + response=response, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def delete_schema( + self, + request: Union[schema.DeleteSchemaRequest, dict] = None, + *, + name: str = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + r"""Deletes a schema. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + async def sample_delete_schema(): + # Create a client + client = pubsub_v1.SchemaServiceAsyncClient() + + # Initialize request argument(s) + request = pubsub_v1.DeleteSchemaRequest( + name="name_value", + ) + + # Make the request + await client.delete_schema(request=request) + + Args: + request (Union[google.pubsub_v1.types.DeleteSchemaRequest, dict]): + The request object. Request for the `DeleteSchema` + method. + name (:class:`str`): + Required. Name of the schema to delete. Format is + ``projects/{project}/schemas/{schema}``. + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = schema.DeleteSchemaRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.delete_schema, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + async def validate_schema( + self, + request: Union[gp_schema.ValidateSchemaRequest, dict] = None, + *, + parent: str = None, + schema: gp_schema.Schema = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gp_schema.ValidateSchemaResponse: + r"""Validates a schema. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + async def sample_validate_schema(): + # Create a client + client = pubsub_v1.SchemaServiceAsyncClient() + + # Initialize request argument(s) + schema = pubsub_v1.Schema() + schema.name = "name_value" + + request = pubsub_v1.ValidateSchemaRequest( + parent="parent_value", + schema=schema, + ) + + # Make the request + response = await client.validate_schema(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.pubsub_v1.types.ValidateSchemaRequest, dict]): + The request object. Request for the `ValidateSchema` + method. + parent (:class:`str`): + Required. The name of the project in which to validate + schemas. Format is ``projects/{project-id}``. + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + schema (:class:`google.pubsub_v1.types.Schema`): + Required. The schema object to + validate. + + This corresponds to the ``schema`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.pubsub_v1.types.ValidateSchemaResponse: + Response for the ValidateSchema method. + Empty for now. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent, schema]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = gp_schema.ValidateSchemaRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if parent is not None: + request.parent = parent + if schema is not None: + request.schema = schema + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.validate_schema, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def validate_message( + self, + request: Union[schema.ValidateMessageRequest, dict] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> schema.ValidateMessageResponse: + r"""Validates a message against a schema. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + async def sample_validate_message(): + # Create a client + client = pubsub_v1.SchemaServiceAsyncClient() + + # Initialize request argument(s) + request = pubsub_v1.ValidateMessageRequest( + name="name_value", + parent="parent_value", + ) + + # Make the request + response = await client.validate_message(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.pubsub_v1.types.ValidateMessageRequest, dict]): + The request object. Request for the `ValidateMessage` + method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.pubsub_v1.types.ValidateMessageResponse: + Response for the ValidateMessage method. + Empty for now. + + """ + # Create or coerce a protobuf request object. + request = schema.ValidateMessageRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.validate_message, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def set_iam_policy( + self, + request: iam_policy_pb2.SetIamPolicyRequest = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> policy_pb2.Policy: + r"""Sets the IAM access control policy on the specified function. + + Replaces any existing policy. + + Args: + request (:class:`~.policy_pb2.SetIamPolicyRequest`): + The request object. Request message for `SetIamPolicy` + method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~.policy_pb2.Policy: + Defines an Identity and Access Management (IAM) policy. + It is used to specify access control policies for Cloud + Platform resources. + A ``Policy`` is a collection of ``bindings``. A + ``binding`` binds one or more ``members`` to a single + ``role``. Members can be user accounts, service + accounts, Google groups, and domains (such as G Suite). + A ``role`` is a named list of permissions (defined by + IAM or configured by users). A ``binding`` can + optionally specify a ``condition``, which is a logic + expression that further constrains the role binding + based on attributes about the request and/or target + resource. + + **JSON Example** + + :: + { + "bindings": [ + { + "role": "roles/resourcemanager.organizationAdmin", + "members": [ + "user:mike@example.com", + "group:admins@example.com", + "domain:google.com", + "serviceAccount:my-project-id@appspot.gserviceaccount.com" + ] + }, + { + "role": "roles/resourcemanager.organizationViewer", + "members": ["user:eve@example.com"], + "condition": { + "title": "expirable access", + "description": "Does not grant access after Sep 2020", + "expression": "request.time < + timestamp('2020-10-01T00:00:00.000Z')", + } + } + ] + } + + **YAML Example** + + :: + + bindings: + - members: + - user:mike@example.com + - group:admins@example.com + - domain:google.com + - serviceAccount:my-project-id@appspot.gserviceaccount.com + role: roles/resourcemanager.organizationAdmin + - members: + - user:eve@example.com + role: roles/resourcemanager.organizationViewer + condition: + title: expirable access + description: Does not grant access after Sep 2020 + expression: request.time < timestamp('2020-10-01T00:00:00.000Z') + + For a description of IAM and its features, see the `IAM + developer's + guide `__. + """ + # Create or coerce a protobuf request object. + + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = iam_policy_pb2.SetIamPolicyRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.set_iam_policy, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("resource", request.resource),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def get_iam_policy( + self, + request: iam_policy_pb2.GetIamPolicyRequest = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> policy_pb2.Policy: + r"""Gets the IAM access control policy for a function. + + Returns an empty policy if the function exists and does + not have a policy set. + + Args: + request (:class:`~.iam_policy_pb2.GetIamPolicyRequest`): + The request object. Request message for `GetIamPolicy` + method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~.policy_pb2.Policy: + Defines an Identity and Access Management (IAM) policy. + It is used to specify access control policies for Cloud + Platform resources. + A ``Policy`` is a collection of ``bindings``. A + ``binding`` binds one or more ``members`` to a single + ``role``. Members can be user accounts, service + accounts, Google groups, and domains (such as G Suite). + A ``role`` is a named list of permissions (defined by + IAM or configured by users). A ``binding`` can + optionally specify a ``condition``, which is a logic + expression that further constrains the role binding + based on attributes about the request and/or target + resource. + + **JSON Example** + + :: + + { + "bindings": [ + { + "role": "roles/resourcemanager.organizationAdmin", + "members": [ + "user:mike@example.com", + "group:admins@example.com", + "domain:google.com", + "serviceAccount:my-project-id@appspot.gserviceaccount.com" + ] + }, + { + "role": "roles/resourcemanager.organizationViewer", + "members": ["user:eve@example.com"], + "condition": { + "title": "expirable access", + "description": "Does not grant access after Sep 2020", + "expression": "request.time < + timestamp('2020-10-01T00:00:00.000Z')", + } + } + ] + } + + **YAML Example** + + :: + + bindings: + - members: + - user:mike@example.com + - group:admins@example.com + - domain:google.com + - serviceAccount:my-project-id@appspot.gserviceaccount.com + role: roles/resourcemanager.organizationAdmin + - members: + - user:eve@example.com + role: roles/resourcemanager.organizationViewer + condition: + title: expirable access + description: Does not grant access after Sep 2020 + expression: request.time < timestamp('2020-10-01T00:00:00.000Z') + + For a description of IAM and its features, see the `IAM + developer's + guide `__. + """ + # Create or coerce a protobuf request object. + + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = iam_policy_pb2.GetIamPolicyRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.get_iam_policy, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("resource", request.resource),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def test_iam_permissions( + self, + request: iam_policy_pb2.TestIamPermissionsRequest = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> iam_policy_pb2.TestIamPermissionsResponse: + r"""Tests the specified permissions against the IAM access control + policy for a function. + + If the function does not exist, this will + return an empty set of permissions, not a NOT_FOUND error. + + Args: + request (:class:`~.iam_policy_pb2.TestIamPermissionsRequest`): + The request object. Request message for + `TestIamPermissions` method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~iam_policy_pb2.PolicyTestIamPermissionsResponse: + Response message for ``TestIamPermissions`` method. + """ + # Create or coerce a protobuf request object. + + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = iam_policy_pb2.TestIamPermissionsRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.test_iam_permissions, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("resource", request.resource),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc, tb): + await self.transport.close() + + +try: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + client_library_version=pkg_resources.get_distribution( + "google-cloud-pubsub", + ).version, + ) +except pkg_resources.DistributionNotFound: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() + + +__all__ = ("SchemaServiceAsyncClient",) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/schema_service/client.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/schema_service/client.py new file mode 100644 index 000000000000..9ecff30f4991 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/schema_service/client.py @@ -0,0 +1,1393 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +from collections import OrderedDict +import functools +import os +import re +from typing import Dict, Mapping, Optional, Sequence, Tuple, Type, Union +import pkg_resources + +from google.api_core import client_options as client_options_lib +from google.api_core import exceptions as core_exceptions +from google.api_core import gapic_v1 +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport import mtls # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.exceptions import MutualTLSChannelError # type: ignore +from google.oauth2 import service_account # type: ignore + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + +from google.iam.v1 import iam_policy_pb2 # type: ignore +from google.iam.v1 import policy_pb2 # type: ignore +from google.pubsub_v1.services.schema_service import pagers +from google.pubsub_v1.types import schema +from google.pubsub_v1.types import schema as gp_schema + +import grpc +from .transports.base import SchemaServiceTransport, DEFAULT_CLIENT_INFO +from .transports.grpc import SchemaServiceGrpcTransport +from .transports.grpc_asyncio import SchemaServiceGrpcAsyncIOTransport + + +class SchemaServiceClientMeta(type): + """Metaclass for the SchemaService client. + + This provides class-level methods for building and retrieving + support objects (e.g. transport) without polluting the client instance + objects. + """ + + _transport_registry = OrderedDict() # type: Dict[str, Type[SchemaServiceTransport]] + _transport_registry["grpc"] = SchemaServiceGrpcTransport + _transport_registry["grpc_asyncio"] = SchemaServiceGrpcAsyncIOTransport + + def get_transport_class( + cls, + label: str = None, + ) -> Type[SchemaServiceTransport]: + """Returns an appropriate transport class. + + Args: + label: The name of the desired transport. If none is + provided, then the first transport in the registry is used. + + Returns: + The transport class to use. + """ + # If a specific transport is requested, return that one. + if label: + return cls._transport_registry[label] + + # No transport is requested; return the default (that is, the first one + # in the dictionary). + return next(iter(cls._transport_registry.values())) + + +class SchemaServiceClient(metaclass=SchemaServiceClientMeta): + """Service for doing schema-related operations.""" + + @staticmethod + def _get_default_mtls_endpoint(api_endpoint): + """Converts api endpoint to mTLS endpoint. + + Convert "*.sandbox.googleapis.com" and "*.googleapis.com" to + "*.mtls.sandbox.googleapis.com" and "*.mtls.googleapis.com" respectively. + Args: + api_endpoint (Optional[str]): the api endpoint to convert. + Returns: + str: converted mTLS api endpoint. + """ + if not api_endpoint: + return api_endpoint + + mtls_endpoint_re = re.compile( + r"(?P[^.]+)(?P\.mtls)?(?P\.sandbox)?(?P\.googleapis\.com)?" + ) + + m = mtls_endpoint_re.match(api_endpoint) + name, mtls, sandbox, googledomain = m.groups() + if mtls or not googledomain: + return api_endpoint + + if sandbox: + return api_endpoint.replace( + "sandbox.googleapis.com", "mtls.sandbox.googleapis.com" + ) + + return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com") + + DEFAULT_ENDPOINT = "pubsub.googleapis.com" + DEFAULT_MTLS_ENDPOINT = _get_default_mtls_endpoint.__func__( # type: ignore + DEFAULT_ENDPOINT + ) + + @classmethod + def from_service_account_info(cls, info: dict, *args, **kwargs): + """Creates an instance of this client using the provided credentials + info. + + Args: + info (dict): The service account private key info. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + SchemaServiceClient: The constructed client. + """ + credentials = service_account.Credentials.from_service_account_info(info) + kwargs["credentials"] = credentials + return cls(*args, **kwargs) + + @classmethod + def from_service_account_file(cls, filename: str, *args, **kwargs): + """Creates an instance of this client using the provided credentials + file. + + Args: + filename (str): The path to the service account private key json + file. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + SchemaServiceClient: The constructed client. + """ + credentials = service_account.Credentials.from_service_account_file(filename) + kwargs["credentials"] = credentials + return cls(*args, **kwargs) + + from_service_account_json = from_service_account_file + + @property + def transport(self) -> SchemaServiceTransport: + """Returns the transport used by the client instance. + + Returns: + SchemaServiceTransport: The transport used by the client + instance. + """ + return self._transport + + @staticmethod + def schema_path( + project: str, + schema: str, + ) -> str: + """Returns a fully-qualified schema string.""" + return "projects/{project}/schemas/{schema}".format( + project=project, + schema=schema, + ) + + @staticmethod + def parse_schema_path(path: str) -> Dict[str, str]: + """Parses a schema path into its component segments.""" + m = re.match(r"^projects/(?P.+?)/schemas/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_billing_account_path( + billing_account: str, + ) -> str: + """Returns a fully-qualified billing_account string.""" + return "billingAccounts/{billing_account}".format( + billing_account=billing_account, + ) + + @staticmethod + def parse_common_billing_account_path(path: str) -> Dict[str, str]: + """Parse a billing_account path into its component segments.""" + m = re.match(r"^billingAccounts/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_folder_path( + folder: str, + ) -> str: + """Returns a fully-qualified folder string.""" + return "folders/{folder}".format( + folder=folder, + ) + + @staticmethod + def parse_common_folder_path(path: str) -> Dict[str, str]: + """Parse a folder path into its component segments.""" + m = re.match(r"^folders/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_organization_path( + organization: str, + ) -> str: + """Returns a fully-qualified organization string.""" + return "organizations/{organization}".format( + organization=organization, + ) + + @staticmethod + def parse_common_organization_path(path: str) -> Dict[str, str]: + """Parse a organization path into its component segments.""" + m = re.match(r"^organizations/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_project_path( + project: str, + ) -> str: + """Returns a fully-qualified project string.""" + return "projects/{project}".format( + project=project, + ) + + @staticmethod + def parse_common_project_path(path: str) -> Dict[str, str]: + """Parse a project path into its component segments.""" + m = re.match(r"^projects/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_location_path( + project: str, + location: str, + ) -> str: + """Returns a fully-qualified location string.""" + return "projects/{project}/locations/{location}".format( + project=project, + location=location, + ) + + @staticmethod + def parse_common_location_path(path: str) -> Dict[str, str]: + """Parse a location path into its component segments.""" + m = re.match(r"^projects/(?P.+?)/locations/(?P.+?)$", path) + return m.groupdict() if m else {} + + @classmethod + def get_mtls_endpoint_and_cert_source( + cls, client_options: Optional[client_options_lib.ClientOptions] = None + ): + """Return the API endpoint and client cert source for mutual TLS. + + The client cert source is determined in the following order: + (1) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not "true", the + client cert source is None. + (2) if `client_options.client_cert_source` is provided, use the provided one; if the + default client cert source exists, use the default one; otherwise the client cert + source is None. + + The API endpoint is determined in the following order: + (1) if `client_options.api_endpoint` if provided, use the provided one. + (2) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is "always", use the + default mTLS endpoint; if the environment variabel is "never", use the default API + endpoint; otherwise if client cert source exists, use the default mTLS endpoint, otherwise + use the default API endpoint. + + More details can be found at https://google.aip.dev/auth/4114. + + Args: + client_options (google.api_core.client_options.ClientOptions): Custom options for the + client. Only the `api_endpoint` and `client_cert_source` properties may be used + in this method. + + Returns: + Tuple[str, Callable[[], Tuple[bytes, bytes]]]: returns the API endpoint and the + client cert source to use. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If any errors happen. + """ + if client_options is None: + client_options = client_options_lib.ClientOptions() + use_client_cert = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false") + use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto") + if use_client_cert not in ("true", "false"): + raise ValueError( + "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`" + ) + if use_mtls_endpoint not in ("auto", "never", "always"): + raise MutualTLSChannelError( + "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`" + ) + + # Figure out the client cert source to use. + client_cert_source = None + if use_client_cert == "true": + if client_options.client_cert_source: + client_cert_source = client_options.client_cert_source + elif mtls.has_default_client_cert_source(): + client_cert_source = mtls.default_client_cert_source() + + # Figure out which api endpoint to use. + if client_options.api_endpoint is not None: + api_endpoint = client_options.api_endpoint + elif use_mtls_endpoint == "always" or ( + use_mtls_endpoint == "auto" and client_cert_source + ): + api_endpoint = cls.DEFAULT_MTLS_ENDPOINT + else: + api_endpoint = cls.DEFAULT_ENDPOINT + + return api_endpoint, client_cert_source + + def __init__( + self, + *, + credentials: Optional[ga_credentials.Credentials] = None, + transport: Union[str, SchemaServiceTransport, None] = None, + client_options: Optional[client_options_lib.ClientOptions] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + ) -> None: + """Instantiates the schema service client. + + Args: + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + transport (Union[str, SchemaServiceTransport]): The + transport to use. If set to None, a transport is chosen + automatically. + client_options (google.api_core.client_options.ClientOptions): Custom options for the + client. It won't take effect if a ``transport`` instance is provided. + (1) The ``api_endpoint`` property can be used to override the + default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT + environment variable can also be used to override the endpoint: + "always" (always use the default mTLS endpoint), "never" (always + use the default regular endpoint) and "auto" (auto switch to the + default mTLS endpoint if client certificate is present, this is + the default value). However, the ``api_endpoint`` property takes + precedence if provided. + (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable + is "true", then the ``client_cert_source`` property can be used + to provide client certificate for mutual TLS transport. If + not provided, the default SSL client certificate will be used if + present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not + set, no client certificate will be used. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport + creation failed for any reason. + """ + if isinstance(client_options, dict): + client_options = client_options_lib.from_dict(client_options) + if client_options is None: + client_options = client_options_lib.ClientOptions() + + api_endpoint, client_cert_source_func = self.get_mtls_endpoint_and_cert_source( + client_options + ) + + api_key_value = getattr(client_options, "api_key", None) + if api_key_value and credentials: + raise ValueError( + "client_options.api_key and credentials are mutually exclusive" + ) + + # Save or instantiate the transport. + # Ordinarily, we provide the transport, but allowing a custom transport + # instance provides an extensibility point for unusual situations. + if isinstance(transport, SchemaServiceTransport): + # transport is a SchemaServiceTransport instance. + if credentials or client_options.credentials_file or api_key_value: + raise ValueError( + "When providing a transport instance, " + "provide its credentials directly." + ) + if client_options.scopes: + raise ValueError( + "When providing a transport instance, provide its scopes " + "directly." + ) + self._transport = transport + else: + import google.auth._default # type: ignore + + if api_key_value and hasattr( + google.auth._default, "get_api_key_credentials" + ): + credentials = google.auth._default.get_api_key_credentials( + api_key_value + ) + + Transport = type(self).get_transport_class(transport) + + emulator_host = os.environ.get("PUBSUB_EMULATOR_HOST") + if emulator_host: + if issubclass(Transport, type(self)._transport_registry["grpc"]): + channel = grpc.insecure_channel(target=emulator_host) + else: + channel = grpc.aio.insecure_channel(target=emulator_host) + Transport = functools.partial(Transport, channel=channel) + + self._transport = Transport( + credentials=credentials, + credentials_file=client_options.credentials_file, + host=api_endpoint, + scopes=client_options.scopes, + client_cert_source_for_mtls=client_cert_source_func, + quota_project_id=client_options.quota_project_id, + client_info=client_info, + always_use_jwt_access=True, + api_audience=client_options.api_audience, + ) + + def create_schema( + self, + request: Union[gp_schema.CreateSchemaRequest, dict] = None, + *, + parent: str = None, + schema: gp_schema.Schema = None, + schema_id: str = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gp_schema.Schema: + r"""Creates a schema. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + def sample_create_schema(): + # Create a client + client = pubsub_v1.SchemaServiceClient() + + # Initialize request argument(s) + schema = pubsub_v1.Schema() + schema.name = "name_value" + + request = pubsub_v1.CreateSchemaRequest( + parent="parent_value", + schema=schema, + ) + + # Make the request + response = client.create_schema(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.pubsub_v1.types.CreateSchemaRequest, dict]): + The request object. Request for the CreateSchema method. + parent (str): + Required. The name of the project in which to create the + schema. Format is ``projects/{project-id}``. + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + schema (google.pubsub_v1.types.Schema): + Required. The schema object to create. + + This schema's ``name`` parameter is ignored. The schema + object returned by CreateSchema will have a ``name`` + made using the given ``parent`` and ``schema_id``. + + This corresponds to the ``schema`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + schema_id (str): + The ID to use for the schema, which will become the + final component of the schema's resource name. + + See + https://cloud.google.com/pubsub/docs/admin#resource_names + for resource name constraints. + + This corresponds to the ``schema_id`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.pubsub_v1.types.Schema: + A schema resource. + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent, schema, schema_id]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a gp_schema.CreateSchemaRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, gp_schema.CreateSchemaRequest): + request = gp_schema.CreateSchemaRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if parent is not None: + request.parent = parent + if schema is not None: + request.schema = schema + if schema_id is not None: + request.schema_id = schema_id + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.create_schema] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def get_schema( + self, + request: Union[schema.GetSchemaRequest, dict] = None, + *, + name: str = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> schema.Schema: + r"""Gets a schema. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + def sample_get_schema(): + # Create a client + client = pubsub_v1.SchemaServiceClient() + + # Initialize request argument(s) + request = pubsub_v1.GetSchemaRequest( + name="name_value", + ) + + # Make the request + response = client.get_schema(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.pubsub_v1.types.GetSchemaRequest, dict]): + The request object. Request for the GetSchema method. + name (str): + Required. The name of the schema to get. Format is + ``projects/{project}/schemas/{schema}``. + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.pubsub_v1.types.Schema: + A schema resource. + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a schema.GetSchemaRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, schema.GetSchemaRequest): + request = schema.GetSchemaRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.get_schema] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def list_schemas( + self, + request: Union[schema.ListSchemasRequest, dict] = None, + *, + parent: str = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListSchemasPager: + r"""Lists schemas in a project. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + def sample_list_schemas(): + # Create a client + client = pubsub_v1.SchemaServiceClient() + + # Initialize request argument(s) + request = pubsub_v1.ListSchemasRequest( + parent="parent_value", + ) + + # Make the request + page_result = client.list_schemas(request=request) + + # Handle the response + for response in page_result: + print(response) + + Args: + request (Union[google.pubsub_v1.types.ListSchemasRequest, dict]): + The request object. Request for the `ListSchemas` + method. + parent (str): + Required. The name of the project in which to list + schemas. Format is ``projects/{project-id}``. + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.pubsub_v1.services.schema_service.pagers.ListSchemasPager: + Response for the ListSchemas method. + + Iterating over this object will yield results and + resolve additional pages automatically. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a schema.ListSchemasRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, schema.ListSchemasRequest): + request = schema.ListSchemasRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if parent is not None: + request.parent = parent + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.list_schemas] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # This method is paged; wrap the response in a pager, which provides + # an `__iter__` convenience method. + response = pagers.ListSchemasPager( + method=rpc, + request=request, + response=response, + metadata=metadata, + ) + + # Done; return the response. + return response + + def delete_schema( + self, + request: Union[schema.DeleteSchemaRequest, dict] = None, + *, + name: str = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + r"""Deletes a schema. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + def sample_delete_schema(): + # Create a client + client = pubsub_v1.SchemaServiceClient() + + # Initialize request argument(s) + request = pubsub_v1.DeleteSchemaRequest( + name="name_value", + ) + + # Make the request + client.delete_schema(request=request) + + Args: + request (Union[google.pubsub_v1.types.DeleteSchemaRequest, dict]): + The request object. Request for the `DeleteSchema` + method. + name (str): + Required. Name of the schema to delete. Format is + ``projects/{project}/schemas/{schema}``. + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a schema.DeleteSchemaRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, schema.DeleteSchemaRequest): + request = schema.DeleteSchemaRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.delete_schema] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + def validate_schema( + self, + request: Union[gp_schema.ValidateSchemaRequest, dict] = None, + *, + parent: str = None, + schema: gp_schema.Schema = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gp_schema.ValidateSchemaResponse: + r"""Validates a schema. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + def sample_validate_schema(): + # Create a client + client = pubsub_v1.SchemaServiceClient() + + # Initialize request argument(s) + schema = pubsub_v1.Schema() + schema.name = "name_value" + + request = pubsub_v1.ValidateSchemaRequest( + parent="parent_value", + schema=schema, + ) + + # Make the request + response = client.validate_schema(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.pubsub_v1.types.ValidateSchemaRequest, dict]): + The request object. Request for the `ValidateSchema` + method. + parent (str): + Required. The name of the project in which to validate + schemas. Format is ``projects/{project-id}``. + + This corresponds to the ``parent`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + schema (google.pubsub_v1.types.Schema): + Required. The schema object to + validate. + + This corresponds to the ``schema`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.pubsub_v1.types.ValidateSchemaResponse: + Response for the ValidateSchema method. + Empty for now. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([parent, schema]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a gp_schema.ValidateSchemaRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, gp_schema.ValidateSchemaRequest): + request = gp_schema.ValidateSchemaRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if parent is not None: + request.parent = parent + if schema is not None: + request.schema = schema + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.validate_schema] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def validate_message( + self, + request: Union[schema.ValidateMessageRequest, dict] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> schema.ValidateMessageResponse: + r"""Validates a message against a schema. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + def sample_validate_message(): + # Create a client + client = pubsub_v1.SchemaServiceClient() + + # Initialize request argument(s) + request = pubsub_v1.ValidateMessageRequest( + name="name_value", + parent="parent_value", + ) + + # Make the request + response = client.validate_message(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.pubsub_v1.types.ValidateMessageRequest, dict]): + The request object. Request for the `ValidateMessage` + method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.pubsub_v1.types.ValidateMessageResponse: + Response for the ValidateMessage method. + Empty for now. + + """ + # Create or coerce a protobuf request object. + # Minor optimization to avoid making a copy if the user passes + # in a schema.ValidateMessageRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, schema.ValidateMessageRequest): + request = schema.ValidateMessageRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.validate_message] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def __enter__(self): + return self + + def __exit__(self, type, value, traceback): + """Releases underlying transport's resources. + + .. warning:: + ONLY use as a context manager if the transport is NOT shared + with other clients! Exiting the with block will CLOSE the transport + and may cause errors in other clients! + """ + self.transport.close() + + def set_iam_policy( + self, + request: iam_policy_pb2.SetIamPolicyRequest = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> policy_pb2.Policy: + r"""Sets the IAM access control policy on the specified function. + + Replaces any existing policy. + + Args: + request (:class:`~.iam_policy_pb2.SetIamPolicyRequest`): + The request object. Request message for `SetIamPolicy` + method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~.policy_pb2.Policy: + Defines an Identity and Access Management (IAM) policy. + It is used to specify access control policies for Cloud + Platform resources. + A ``Policy`` is a collection of ``bindings``. A + ``binding`` binds one or more ``members`` to a single + ``role``. Members can be user accounts, service + accounts, Google groups, and domains (such as G Suite). + A ``role`` is a named list of permissions (defined by + IAM or configured by users). A ``binding`` can + optionally specify a ``condition``, which is a logic + expression that further constrains the role binding + based on attributes about the request and/or target + resource. + + **JSON Example** + + :: + + { + "bindings": [ + { + "role": "roles/resourcemanager.organizationAdmin", + "members": [ + "user:mike@example.com", + "group:admins@example.com", + "domain:google.com", + "serviceAccount:my-project-id@appspot.gserviceaccount.com" + ] + }, + { + "role": "roles/resourcemanager.organizationViewer", + "members": ["user:eve@example.com"], + "condition": { + "title": "expirable access", + "description": "Does not grant access after Sep 2020", + "expression": "request.time < + timestamp('2020-10-01T00:00:00.000Z')", + } + } + ] + } + + **YAML Example** + + :: + + bindings: + - members: + - user:mike@example.com + - group:admins@example.com + - domain:google.com + - serviceAccount:my-project-id@appspot.gserviceaccount.com + role: roles/resourcemanager.organizationAdmin + - members: + - user:eve@example.com + role: roles/resourcemanager.organizationViewer + condition: + title: expirable access + description: Does not grant access after Sep 2020 + expression: request.time < timestamp('2020-10-01T00:00:00.000Z') + + For a description of IAM and its features, see the `IAM + developer's + guide `__. + """ + # Create or coerce a protobuf request object. + + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = iam_policy_pb2.SetIamPolicyRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._transport.set_iam_policy, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("resource", request.resource),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def get_iam_policy( + self, + request: iam_policy_pb2.GetIamPolicyRequest = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> policy_pb2.Policy: + r"""Gets the IAM access control policy for a function. + + Returns an empty policy if the function exists and does not have a + policy set. + + Args: + request (:class:`~.iam_policy_pb2.GetIamPolicyRequest`): + The request object. Request message for `GetIamPolicy` + method. + retry (google.api_core.retry.Retry): Designation of what errors, if + any, should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~.policy_pb2.Policy: + Defines an Identity and Access Management (IAM) policy. + It is used to specify access control policies for Cloud + Platform resources. + A ``Policy`` is a collection of ``bindings``. A + ``binding`` binds one or more ``members`` to a single + ``role``. Members can be user accounts, service + accounts, Google groups, and domains (such as G Suite). + A ``role`` is a named list of permissions (defined by + IAM or configured by users). A ``binding`` can + optionally specify a ``condition``, which is a logic + expression that further constrains the role binding + based on attributes about the request and/or target + resource. + + **JSON Example** + + :: + + { + "bindings": [ + { + "role": "roles/resourcemanager.organizationAdmin", + "members": [ + "user:mike@example.com", + "group:admins@example.com", + "domain:google.com", + "serviceAccount:my-project-id@appspot.gserviceaccount.com" + ] + }, + { + "role": "roles/resourcemanager.organizationViewer", + "members": ["user:eve@example.com"], + "condition": { + "title": "expirable access", + "description": "Does not grant access after Sep 2020", + "expression": "request.time < + timestamp('2020-10-01T00:00:00.000Z')", + } + } + ] + } + + **YAML Example** + + :: + + bindings: + - members: + - user:mike@example.com + - group:admins@example.com + - domain:google.com + - serviceAccount:my-project-id@appspot.gserviceaccount.com + role: roles/resourcemanager.organizationAdmin + - members: + - user:eve@example.com + role: roles/resourcemanager.organizationViewer + condition: + title: expirable access + description: Does not grant access after Sep 2020 + expression: request.time < timestamp('2020-10-01T00:00:00.000Z') + + For a description of IAM and its features, see the `IAM + developer's + guide `__. + """ + # Create or coerce a protobuf request object. + + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = iam_policy_pb2.GetIamPolicyRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._transport.get_iam_policy, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("resource", request.resource),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def test_iam_permissions( + self, + request: iam_policy_pb2.TestIamPermissionsRequest = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> iam_policy_pb2.TestIamPermissionsResponse: + r"""Tests the specified IAM permissions against the IAM access control + policy for a function. + + If the function does not exist, this will return an empty set + of permissions, not a NOT_FOUND error. + + Args: + request (:class:`~.iam_policy_pb2.TestIamPermissionsRequest`): + The request object. Request message for + `TestIamPermissions` method. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~.iam_policy_pb2.TestIamPermissionsResponse: + Response message for ``TestIamPermissions`` method. + """ + # Create or coerce a protobuf request object. + + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = iam_policy_pb2.TestIamPermissionsRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._transport.test_iam_permissions, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("resource", request.resource),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + +try: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + client_library_version=pkg_resources.get_distribution( + "google-cloud-pubsub", + ).version, + ) +except pkg_resources.DistributionNotFound: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() + + +__all__ = ("SchemaServiceClient",) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/schema_service/pagers.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/schema_service/pagers.py new file mode 100644 index 000000000000..965778d459af --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/schema_service/pagers.py @@ -0,0 +1,155 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +from typing import ( + Any, + AsyncIterator, + Awaitable, + Callable, + Sequence, + Tuple, + Optional, + Iterator, +) + +from google.pubsub_v1.types import schema + + +class ListSchemasPager: + """A pager for iterating through ``list_schemas`` requests. + + This class thinly wraps an initial + :class:`google.pubsub_v1.types.ListSchemasResponse` object, and + provides an ``__iter__`` method to iterate through its + ``schemas`` field. + + If there are more pages, the ``__iter__`` method will make additional + ``ListSchemas`` requests and continue to iterate + through the ``schemas`` field on the + corresponding responses. + + All the usual :class:`google.pubsub_v1.types.ListSchemasResponse` + attributes are available on the pager. If multiple requests are made, only + the most recent response is retained, and thus used for attribute lookup. + """ + + def __init__( + self, + method: Callable[..., schema.ListSchemasResponse], + request: schema.ListSchemasRequest, + response: schema.ListSchemasResponse, + *, + metadata: Sequence[Tuple[str, str]] = () + ): + """Instantiate the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.pubsub_v1.types.ListSchemasRequest): + The initial request object. + response (google.pubsub_v1.types.ListSchemasResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = schema.ListSchemasRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + def pages(self) -> Iterator[schema.ListSchemasResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = self._method(self._request, metadata=self._metadata) + yield self._response + + def __iter__(self) -> Iterator[schema.Schema]: + for page in self.pages: + yield from page.schemas + + def __repr__(self) -> str: + return "{0}<{1!r}>".format(self.__class__.__name__, self._response) + + +class ListSchemasAsyncPager: + """A pager for iterating through ``list_schemas`` requests. + + This class thinly wraps an initial + :class:`google.pubsub_v1.types.ListSchemasResponse` object, and + provides an ``__aiter__`` method to iterate through its + ``schemas`` field. + + If there are more pages, the ``__aiter__`` method will make additional + ``ListSchemas`` requests and continue to iterate + through the ``schemas`` field on the + corresponding responses. + + All the usual :class:`google.pubsub_v1.types.ListSchemasResponse` + attributes are available on the pager. If multiple requests are made, only + the most recent response is retained, and thus used for attribute lookup. + """ + + def __init__( + self, + method: Callable[..., Awaitable[schema.ListSchemasResponse]], + request: schema.ListSchemasRequest, + response: schema.ListSchemasResponse, + *, + metadata: Sequence[Tuple[str, str]] = () + ): + """Instantiates the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.pubsub_v1.types.ListSchemasRequest): + The initial request object. + response (google.pubsub_v1.types.ListSchemasResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = schema.ListSchemasRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + async def pages(self) -> AsyncIterator[schema.ListSchemasResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = await self._method(self._request, metadata=self._metadata) + yield self._response + + def __aiter__(self) -> AsyncIterator[schema.Schema]: + async def async_generator(): + async for page in self.pages: + for response in page.schemas: + yield response + + return async_generator() + + def __repr__(self) -> str: + return "{0}<{1!r}>".format(self.__class__.__name__, self._response) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/schema_service/transports/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/schema_service/transports/__init__.py new file mode 100644 index 000000000000..6c2d9460a073 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/schema_service/transports/__init__.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +from collections import OrderedDict +from typing import Dict, Type + +from .base import SchemaServiceTransport +from .grpc import SchemaServiceGrpcTransport +from .grpc_asyncio import SchemaServiceGrpcAsyncIOTransport + + +# Compile a registry of transports. +_transport_registry = OrderedDict() # type: Dict[str, Type[SchemaServiceTransport]] +_transport_registry["grpc"] = SchemaServiceGrpcTransport +_transport_registry["grpc_asyncio"] = SchemaServiceGrpcAsyncIOTransport + +__all__ = ( + "SchemaServiceTransport", + "SchemaServiceGrpcTransport", + "SchemaServiceGrpcAsyncIOTransport", +) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/schema_service/transports/base.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/schema_service/transports/base.py new file mode 100644 index 000000000000..e2b5ad6608d4 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/schema_service/transports/base.py @@ -0,0 +1,270 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +import abc +from typing import Awaitable, Callable, Dict, Optional, Sequence, Union +import pkg_resources + +import google.auth # type: ignore +import google.api_core +from google.api_core import exceptions as core_exceptions +from google.api_core import gapic_v1 +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.oauth2 import service_account # type: ignore + +from google.iam.v1 import iam_policy_pb2 # type: ignore +from google.iam.v1 import policy_pb2 # type: ignore +from google.protobuf import empty_pb2 # type: ignore +from google.pubsub_v1.types import schema +from google.pubsub_v1.types import schema as gp_schema + +try: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + client_library_version=pkg_resources.get_distribution( + "google-cloud-pubsub", + ).version, + ) +except pkg_resources.DistributionNotFound: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() + + +class SchemaServiceTransport(abc.ABC): + """Abstract transport class for SchemaService.""" + + AUTH_SCOPES = ( + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/pubsub", + ) + + DEFAULT_HOST: str = "pubsub.googleapis.com" + + def __init__( + self, + *, + host: str = DEFAULT_HOST, + credentials: ga_credentials.Credentials = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + api_audience: Optional[str] = None, + **kwargs, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is mutually exclusive with credentials. + scopes (Optional[Sequence[str]]): A list of scopes. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + """ + + scopes_kwargs = {"scopes": scopes, "default_scopes": self.AUTH_SCOPES} + + # Save the scopes. + self._scopes = scopes + + # If no credentials are provided, then determine the appropriate + # defaults. + if credentials and credentials_file: + raise core_exceptions.DuplicateCredentialArgs( + "'credentials_file' and 'credentials' are mutually exclusive" + ) + + if credentials_file is not None: + credentials, _ = google.auth.load_credentials_from_file( + credentials_file, **scopes_kwargs, quota_project_id=quota_project_id + ) + elif credentials is None: + credentials, _ = google.auth.default( + **scopes_kwargs, quota_project_id=quota_project_id + ) + # Don't apply audience if the credentials file passed from user. + if hasattr(credentials, "with_gdch_audience"): + credentials = credentials.with_gdch_audience( + api_audience if api_audience else host + ) + + # If the credentials are service account credentials, then always try to use self signed JWT. + if ( + always_use_jwt_access + and isinstance(credentials, service_account.Credentials) + and hasattr(service_account.Credentials, "with_always_use_jwt_access") + ): + credentials = credentials.with_always_use_jwt_access(True) + + # Save the credentials. + self._credentials = credentials + + # Save the hostname. Default to port 443 (HTTPS) if none is specified. + if ":" not in host: + host += ":443" + self._host = host + + def _prep_wrapped_messages(self, client_info): + # Precompute the wrapped methods. + self._wrapped_methods = { + self.create_schema: gapic_v1.method.wrap_method( + self.create_schema, + default_timeout=None, + client_info=client_info, + ), + self.get_schema: gapic_v1.method.wrap_method( + self.get_schema, + default_timeout=None, + client_info=client_info, + ), + self.list_schemas: gapic_v1.method.wrap_method( + self.list_schemas, + default_timeout=None, + client_info=client_info, + ), + self.delete_schema: gapic_v1.method.wrap_method( + self.delete_schema, + default_timeout=None, + client_info=client_info, + ), + self.validate_schema: gapic_v1.method.wrap_method( + self.validate_schema, + default_timeout=None, + client_info=client_info, + ), + self.validate_message: gapic_v1.method.wrap_method( + self.validate_message, + default_timeout=None, + client_info=client_info, + ), + } + + def close(self): + """Closes resources associated with the transport. + + .. warning:: + Only call this method if the transport is NOT shared + with other clients - this may cause errors in other clients! + """ + raise NotImplementedError() + + @property + def create_schema( + self, + ) -> Callable[ + [gp_schema.CreateSchemaRequest], + Union[gp_schema.Schema, Awaitable[gp_schema.Schema]], + ]: + raise NotImplementedError() + + @property + def get_schema( + self, + ) -> Callable[ + [schema.GetSchemaRequest], Union[schema.Schema, Awaitable[schema.Schema]] + ]: + raise NotImplementedError() + + @property + def list_schemas( + self, + ) -> Callable[ + [schema.ListSchemasRequest], + Union[schema.ListSchemasResponse, Awaitable[schema.ListSchemasResponse]], + ]: + raise NotImplementedError() + + @property + def delete_schema( + self, + ) -> Callable[ + [schema.DeleteSchemaRequest], Union[empty_pb2.Empty, Awaitable[empty_pb2.Empty]] + ]: + raise NotImplementedError() + + @property + def validate_schema( + self, + ) -> Callable[ + [gp_schema.ValidateSchemaRequest], + Union[ + gp_schema.ValidateSchemaResponse, + Awaitable[gp_schema.ValidateSchemaResponse], + ], + ]: + raise NotImplementedError() + + @property + def validate_message( + self, + ) -> Callable[ + [schema.ValidateMessageRequest], + Union[ + schema.ValidateMessageResponse, Awaitable[schema.ValidateMessageResponse] + ], + ]: + raise NotImplementedError() + + @property + def set_iam_policy( + self, + ) -> Callable[ + [iam_policy_pb2.SetIamPolicyRequest], + Union[policy_pb2.Policy, Awaitable[policy_pb2.Policy]], + ]: + raise NotImplementedError() + + @property + def get_iam_policy( + self, + ) -> Callable[ + [iam_policy_pb2.GetIamPolicyRequest], + Union[policy_pb2.Policy, Awaitable[policy_pb2.Policy]], + ]: + raise NotImplementedError() + + @property + def test_iam_permissions( + self, + ) -> Callable[ + [iam_policy_pb2.TestIamPermissionsRequest], + Union[ + iam_policy_pb2.TestIamPermissionsResponse, + Awaitable[iam_policy_pb2.TestIamPermissionsResponse], + ], + ]: + raise NotImplementedError() + + @property + def kind(self) -> str: + raise NotImplementedError() + + +__all__ = ("SchemaServiceTransport",) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/schema_service/transports/grpc.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/schema_service/transports/grpc.py new file mode 100644 index 000000000000..3fa0a5b12749 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/schema_service/transports/grpc.py @@ -0,0 +1,478 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +import warnings +from typing import Callable, Dict, Optional, Sequence, Tuple, Union + +from google.api_core import grpc_helpers +from google.api_core import gapic_v1 +import google.auth # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore + +import grpc # type: ignore + +from google.iam.v1 import iam_policy_pb2 # type: ignore +from google.iam.v1 import policy_pb2 # type: ignore +from google.protobuf import empty_pb2 # type: ignore +from google.pubsub_v1.types import schema +from google.pubsub_v1.types import schema as gp_schema +from .base import SchemaServiceTransport, DEFAULT_CLIENT_INFO + + +class SchemaServiceGrpcTransport(SchemaServiceTransport): + """gRPC backend transport for SchemaService. + + Service for doing schema-related operations. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends protocol buffers over the wire using gRPC (which is built on + top of HTTP/2); the ``grpcio`` package must be installed. + """ + + _stubs: Dict[str, Callable] + + def __init__( + self, + *, + host: str = "pubsub.googleapis.com", + credentials: ga_credentials.Credentials = None, + credentials_file: str = None, + scopes: Sequence[str] = None, + channel: grpc.Channel = None, + api_mtls_endpoint: str = None, + client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, + ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + This argument is ignored if ``channel`` is provided. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + channel (Optional[grpc.Channel]): A ``Channel`` instance through + which to make calls. + api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. + If provided, it overrides the ``host`` argument and tries to create + a mutual TLS channel with client SSL credentials from + ``client_cert_source`` or application default SSL credentials. + client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): + Deprecated. A callback to provide client SSL certificate bytes and + private key bytes, both in PEM format. It is ignored if + ``api_mtls_endpoint`` is None. + ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials + for the grpc channel. It is ignored if ``channel`` is provided. + client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): + A callback to provide client certificate bytes and private key bytes, + both in PEM format. It is used to configure a mutual TLS channel. It is + ignored if ``channel`` or ``ssl_channel_credentials`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport + creation failed for any reason. + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + self._grpc_channel = None + self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} + + if api_mtls_endpoint: + warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning) + if client_cert_source: + warnings.warn("client_cert_source is deprecated", DeprecationWarning) + + if channel: + # Ignore credentials if a channel was passed. + credentials = False + # If a channel was explicitly provided, set it. + self._grpc_channel = channel + self._ssl_channel_credentials = None + + else: + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials + + else: + if client_cert_source_for_mtls and not ssl_channel_credentials: + cert, key = client_cert_source_for_mtls() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + + # The base transport sets the host, credentials and scopes + super().__init__( + host=host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + + if not self._grpc_channel: + self._grpc_channel = type(self).create_channel( + self._host, + # use the credentials which are saved + credentials=self._credentials, + # Set ``credentials_file`` to ``None`` here as + # the credentials that we saved earlier should be used. + credentials_file=None, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, + quota_project_id=quota_project_id, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ("grpc.max_metadata_size", 4 * 1024 * 1024), + ("grpc.keepalive_time_ms", 30000), + ], + ) + + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) + + @classmethod + def create_channel( + cls, + host: str = "pubsub.googleapis.com", + credentials: ga_credentials.Credentials = None, + credentials_file: str = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + **kwargs, + ) -> grpc.Channel: + """Create and return a gRPC channel object. + Args: + host (Optional[str]): The host for the channel to use. + credentials (Optional[~.Credentials]): The + authorization credentials to attach to requests. These + credentials identify this application to the service. If + none are specified, the client will attempt to ascertain + the credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is mutually exclusive with credentials. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + kwargs (Optional[dict]): Keyword arguments, which are passed to the + channel creation. + Returns: + grpc.Channel: A gRPC channel object. + + Raises: + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + + return grpc_helpers.create_channel( + host, + credentials=credentials, + credentials_file=credentials_file, + quota_project_id=quota_project_id, + default_scopes=cls.AUTH_SCOPES, + scopes=scopes, + default_host=cls.DEFAULT_HOST, + **kwargs, + ) + + @property + def grpc_channel(self) -> grpc.Channel: + """Return the channel designed to connect to this service.""" + return self._grpc_channel + + @property + def create_schema( + self, + ) -> Callable[[gp_schema.CreateSchemaRequest], gp_schema.Schema]: + r"""Return a callable for the create schema method over gRPC. + + Creates a schema. + + Returns: + Callable[[~.CreateSchemaRequest], + ~.Schema]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "create_schema" not in self._stubs: + self._stubs["create_schema"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.SchemaService/CreateSchema", + request_serializer=gp_schema.CreateSchemaRequest.serialize, + response_deserializer=gp_schema.Schema.deserialize, + ) + return self._stubs["create_schema"] + + @property + def get_schema(self) -> Callable[[schema.GetSchemaRequest], schema.Schema]: + r"""Return a callable for the get schema method over gRPC. + + Gets a schema. + + Returns: + Callable[[~.GetSchemaRequest], + ~.Schema]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_schema" not in self._stubs: + self._stubs["get_schema"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.SchemaService/GetSchema", + request_serializer=schema.GetSchemaRequest.serialize, + response_deserializer=schema.Schema.deserialize, + ) + return self._stubs["get_schema"] + + @property + def list_schemas( + self, + ) -> Callable[[schema.ListSchemasRequest], schema.ListSchemasResponse]: + r"""Return a callable for the list schemas method over gRPC. + + Lists schemas in a project. + + Returns: + Callable[[~.ListSchemasRequest], + ~.ListSchemasResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_schemas" not in self._stubs: + self._stubs["list_schemas"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.SchemaService/ListSchemas", + request_serializer=schema.ListSchemasRequest.serialize, + response_deserializer=schema.ListSchemasResponse.deserialize, + ) + return self._stubs["list_schemas"] + + @property + def delete_schema(self) -> Callable[[schema.DeleteSchemaRequest], empty_pb2.Empty]: + r"""Return a callable for the delete schema method over gRPC. + + Deletes a schema. + + Returns: + Callable[[~.DeleteSchemaRequest], + ~.Empty]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "delete_schema" not in self._stubs: + self._stubs["delete_schema"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.SchemaService/DeleteSchema", + request_serializer=schema.DeleteSchemaRequest.serialize, + response_deserializer=empty_pb2.Empty.FromString, + ) + return self._stubs["delete_schema"] + + @property + def validate_schema( + self, + ) -> Callable[[gp_schema.ValidateSchemaRequest], gp_schema.ValidateSchemaResponse]: + r"""Return a callable for the validate schema method over gRPC. + + Validates a schema. + + Returns: + Callable[[~.ValidateSchemaRequest], + ~.ValidateSchemaResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "validate_schema" not in self._stubs: + self._stubs["validate_schema"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.SchemaService/ValidateSchema", + request_serializer=gp_schema.ValidateSchemaRequest.serialize, + response_deserializer=gp_schema.ValidateSchemaResponse.deserialize, + ) + return self._stubs["validate_schema"] + + @property + def validate_message( + self, + ) -> Callable[[schema.ValidateMessageRequest], schema.ValidateMessageResponse]: + r"""Return a callable for the validate message method over gRPC. + + Validates a message against a schema. + + Returns: + Callable[[~.ValidateMessageRequest], + ~.ValidateMessageResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "validate_message" not in self._stubs: + self._stubs["validate_message"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.SchemaService/ValidateMessage", + request_serializer=schema.ValidateMessageRequest.serialize, + response_deserializer=schema.ValidateMessageResponse.deserialize, + ) + return self._stubs["validate_message"] + + @property + def set_iam_policy( + self, + ) -> Callable[[iam_policy_pb2.SetIamPolicyRequest], policy_pb2.Policy]: + r"""Return a callable for the set iam policy method over gRPC. + Sets the IAM access control policy on the specified + function. Replaces any existing policy. + Returns: + Callable[[~.SetIamPolicyRequest], + ~.Policy]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "set_iam_policy" not in self._stubs: + self._stubs["set_iam_policy"] = self.grpc_channel.unary_unary( + "/google.iam.v1.IAMPolicy/SetIamPolicy", + request_serializer=iam_policy_pb2.SetIamPolicyRequest.SerializeToString, + response_deserializer=policy_pb2.Policy.FromString, + ) + return self._stubs["set_iam_policy"] + + @property + def get_iam_policy( + self, + ) -> Callable[[iam_policy_pb2.GetIamPolicyRequest], policy_pb2.Policy]: + r"""Return a callable for the get iam policy method over gRPC. + Gets the IAM access control policy for a function. + Returns an empty policy if the function exists and does + not have a policy set. + Returns: + Callable[[~.GetIamPolicyRequest], + ~.Policy]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_iam_policy" not in self._stubs: + self._stubs["get_iam_policy"] = self.grpc_channel.unary_unary( + "/google.iam.v1.IAMPolicy/GetIamPolicy", + request_serializer=iam_policy_pb2.GetIamPolicyRequest.SerializeToString, + response_deserializer=policy_pb2.Policy.FromString, + ) + return self._stubs["get_iam_policy"] + + @property + def test_iam_permissions( + self, + ) -> Callable[ + [iam_policy_pb2.TestIamPermissionsRequest], + iam_policy_pb2.TestIamPermissionsResponse, + ]: + r"""Return a callable for the test iam permissions method over gRPC. + Tests the specified permissions against the IAM access control + policy for a function. If the function does not exist, this will + return an empty set of permissions, not a NOT_FOUND error. + Returns: + Callable[[~.TestIamPermissionsRequest], + ~.TestIamPermissionsResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "test_iam_permissions" not in self._stubs: + self._stubs["test_iam_permissions"] = self.grpc_channel.unary_unary( + "/google.iam.v1.IAMPolicy/TestIamPermissions", + request_serializer=iam_policy_pb2.TestIamPermissionsRequest.SerializeToString, + response_deserializer=iam_policy_pb2.TestIamPermissionsResponse.FromString, + ) + return self._stubs["test_iam_permissions"] + + def close(self): + self.grpc_channel.close() + + @property + def kind(self) -> str: + return "grpc" + + +__all__ = ("SchemaServiceGrpcTransport",) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/schema_service/transports/grpc_asyncio.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/schema_service/transports/grpc_asyncio.py new file mode 100644 index 000000000000..fb89c89a2173 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/schema_service/transports/grpc_asyncio.py @@ -0,0 +1,485 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +import warnings +from typing import Awaitable, Callable, Dict, Optional, Sequence, Tuple, Union + +from google.api_core import gapic_v1 +from google.api_core import grpc_helpers_async +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore + +import grpc # type: ignore +from grpc.experimental import aio # type: ignore + +from google.iam.v1 import iam_policy_pb2 # type: ignore +from google.iam.v1 import policy_pb2 # type: ignore +from google.protobuf import empty_pb2 # type: ignore +from google.pubsub_v1.types import schema +from google.pubsub_v1.types import schema as gp_schema +from .base import SchemaServiceTransport, DEFAULT_CLIENT_INFO +from .grpc import SchemaServiceGrpcTransport + + +class SchemaServiceGrpcAsyncIOTransport(SchemaServiceTransport): + """gRPC AsyncIO backend transport for SchemaService. + + Service for doing schema-related operations. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends protocol buffers over the wire using gRPC (which is built on + top of HTTP/2); the ``grpcio`` package must be installed. + """ + + _grpc_channel: aio.Channel + _stubs: Dict[str, Callable] = {} + + @classmethod + def create_channel( + cls, + host: str = "pubsub.googleapis.com", + credentials: ga_credentials.Credentials = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + **kwargs, + ) -> aio.Channel: + """Create and return a gRPC AsyncIO channel object. + Args: + host (Optional[str]): The host for the channel to use. + credentials (Optional[~.Credentials]): The + authorization credentials to attach to requests. These + credentials identify this application to the service. If + none are specified, the client will attempt to ascertain + the credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + kwargs (Optional[dict]): Keyword arguments, which are passed to the + channel creation. + Returns: + aio.Channel: A gRPC AsyncIO channel object. + """ + + return grpc_helpers_async.create_channel( + host, + credentials=credentials, + credentials_file=credentials_file, + quota_project_id=quota_project_id, + default_scopes=cls.AUTH_SCOPES, + scopes=scopes, + default_host=cls.DEFAULT_HOST, + **kwargs, + ) + + def __init__( + self, + *, + host: str = "pubsub.googleapis.com", + credentials: ga_credentials.Credentials = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + channel: aio.Channel = None, + api_mtls_endpoint: str = None, + client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, + ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, + quota_project_id=None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + This argument is ignored if ``channel`` is provided. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + channel (Optional[aio.Channel]): A ``Channel`` instance through + which to make calls. + api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. + If provided, it overrides the ``host`` argument and tries to create + a mutual TLS channel with client SSL credentials from + ``client_cert_source`` or application default SSL credentials. + client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): + Deprecated. A callback to provide client SSL certificate bytes and + private key bytes, both in PEM format. It is ignored if + ``api_mtls_endpoint`` is None. + ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials + for the grpc channel. It is ignored if ``channel`` is provided. + client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): + A callback to provide client certificate bytes and private key bytes, + both in PEM format. It is used to configure a mutual TLS channel. It is + ignored if ``channel`` or ``ssl_channel_credentials`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + + Raises: + google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport + creation failed for any reason. + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + self._grpc_channel = None + self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} + + if api_mtls_endpoint: + warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning) + if client_cert_source: + warnings.warn("client_cert_source is deprecated", DeprecationWarning) + + if channel: + # Ignore credentials if a channel was passed. + credentials = False + # If a channel was explicitly provided, set it. + self._grpc_channel = channel + self._ssl_channel_credentials = None + else: + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials + + else: + if client_cert_source_for_mtls and not ssl_channel_credentials: + cert, key = client_cert_source_for_mtls() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + + # The base transport sets the host, credentials and scopes + super().__init__( + host=host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + + if not self._grpc_channel: + self._grpc_channel = type(self).create_channel( + self._host, + # use the credentials which are saved + credentials=self._credentials, + # Set ``credentials_file`` to ``None`` here as + # the credentials that we saved earlier should be used. + credentials_file=None, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, + quota_project_id=quota_project_id, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ("grpc.max_metadata_size", 4 * 1024 * 1024), + ("grpc.keepalive_time_ms", 30000), + ], + ) + + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) + + @property + def grpc_channel(self) -> aio.Channel: + """Create the channel designed to connect to this service. + + This property caches on the instance; repeated calls return + the same channel. + """ + # Return the channel from cache. + return self._grpc_channel + + @property + def create_schema( + self, + ) -> Callable[[gp_schema.CreateSchemaRequest], Awaitable[gp_schema.Schema]]: + r"""Return a callable for the create schema method over gRPC. + + Creates a schema. + + Returns: + Callable[[~.CreateSchemaRequest], + Awaitable[~.Schema]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "create_schema" not in self._stubs: + self._stubs["create_schema"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.SchemaService/CreateSchema", + request_serializer=gp_schema.CreateSchemaRequest.serialize, + response_deserializer=gp_schema.Schema.deserialize, + ) + return self._stubs["create_schema"] + + @property + def get_schema( + self, + ) -> Callable[[schema.GetSchemaRequest], Awaitable[schema.Schema]]: + r"""Return a callable for the get schema method over gRPC. + + Gets a schema. + + Returns: + Callable[[~.GetSchemaRequest], + Awaitable[~.Schema]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_schema" not in self._stubs: + self._stubs["get_schema"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.SchemaService/GetSchema", + request_serializer=schema.GetSchemaRequest.serialize, + response_deserializer=schema.Schema.deserialize, + ) + return self._stubs["get_schema"] + + @property + def list_schemas( + self, + ) -> Callable[[schema.ListSchemasRequest], Awaitable[schema.ListSchemasResponse]]: + r"""Return a callable for the list schemas method over gRPC. + + Lists schemas in a project. + + Returns: + Callable[[~.ListSchemasRequest], + Awaitable[~.ListSchemasResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_schemas" not in self._stubs: + self._stubs["list_schemas"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.SchemaService/ListSchemas", + request_serializer=schema.ListSchemasRequest.serialize, + response_deserializer=schema.ListSchemasResponse.deserialize, + ) + return self._stubs["list_schemas"] + + @property + def delete_schema( + self, + ) -> Callable[[schema.DeleteSchemaRequest], Awaitable[empty_pb2.Empty]]: + r"""Return a callable for the delete schema method over gRPC. + + Deletes a schema. + + Returns: + Callable[[~.DeleteSchemaRequest], + Awaitable[~.Empty]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "delete_schema" not in self._stubs: + self._stubs["delete_schema"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.SchemaService/DeleteSchema", + request_serializer=schema.DeleteSchemaRequest.serialize, + response_deserializer=empty_pb2.Empty.FromString, + ) + return self._stubs["delete_schema"] + + @property + def validate_schema( + self, + ) -> Callable[ + [gp_schema.ValidateSchemaRequest], Awaitable[gp_schema.ValidateSchemaResponse] + ]: + r"""Return a callable for the validate schema method over gRPC. + + Validates a schema. + + Returns: + Callable[[~.ValidateSchemaRequest], + Awaitable[~.ValidateSchemaResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "validate_schema" not in self._stubs: + self._stubs["validate_schema"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.SchemaService/ValidateSchema", + request_serializer=gp_schema.ValidateSchemaRequest.serialize, + response_deserializer=gp_schema.ValidateSchemaResponse.deserialize, + ) + return self._stubs["validate_schema"] + + @property + def validate_message( + self, + ) -> Callable[ + [schema.ValidateMessageRequest], Awaitable[schema.ValidateMessageResponse] + ]: + r"""Return a callable for the validate message method over gRPC. + + Validates a message against a schema. + + Returns: + Callable[[~.ValidateMessageRequest], + Awaitable[~.ValidateMessageResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "validate_message" not in self._stubs: + self._stubs["validate_message"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.SchemaService/ValidateMessage", + request_serializer=schema.ValidateMessageRequest.serialize, + response_deserializer=schema.ValidateMessageResponse.deserialize, + ) + return self._stubs["validate_message"] + + @property + def set_iam_policy( + self, + ) -> Callable[[iam_policy_pb2.SetIamPolicyRequest], Awaitable[policy_pb2.Policy]]: + r"""Return a callable for the set iam policy method over gRPC. + Sets the IAM access control policy on the specified + function. Replaces any existing policy. + Returns: + Callable[[~.SetIamPolicyRequest], + Awaitable[~.Policy]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "set_iam_policy" not in self._stubs: + self._stubs["set_iam_policy"] = self.grpc_channel.unary_unary( + "/google.iam.v1.IAMPolicy/SetIamPolicy", + request_serializer=iam_policy_pb2.SetIamPolicyRequest.SerializeToString, + response_deserializer=policy_pb2.Policy.FromString, + ) + return self._stubs["set_iam_policy"] + + @property + def get_iam_policy( + self, + ) -> Callable[[iam_policy_pb2.GetIamPolicyRequest], Awaitable[policy_pb2.Policy]]: + r"""Return a callable for the get iam policy method over gRPC. + Gets the IAM access control policy for a function. + Returns an empty policy if the function exists and does + not have a policy set. + Returns: + Callable[[~.GetIamPolicyRequest], + Awaitable[~.Policy]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_iam_policy" not in self._stubs: + self._stubs["get_iam_policy"] = self.grpc_channel.unary_unary( + "/google.iam.v1.IAMPolicy/GetIamPolicy", + request_serializer=iam_policy_pb2.GetIamPolicyRequest.SerializeToString, + response_deserializer=policy_pb2.Policy.FromString, + ) + return self._stubs["get_iam_policy"] + + @property + def test_iam_permissions( + self, + ) -> Callable[ + [iam_policy_pb2.TestIamPermissionsRequest], + Awaitable[iam_policy_pb2.TestIamPermissionsResponse], + ]: + r"""Return a callable for the test iam permissions method over gRPC. + Tests the specified permissions against the IAM access control + policy for a function. If the function does not exist, this will + return an empty set of permissions, not a NOT_FOUND error. + Returns: + Callable[[~.TestIamPermissionsRequest], + Awaitable[~.TestIamPermissionsResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "test_iam_permissions" not in self._stubs: + self._stubs["test_iam_permissions"] = self.grpc_channel.unary_unary( + "/google.iam.v1.IAMPolicy/TestIamPermissions", + request_serializer=iam_policy_pb2.TestIamPermissionsRequest.SerializeToString, + response_deserializer=iam_policy_pb2.TestIamPermissionsResponse.FromString, + ) + return self._stubs["test_iam_permissions"] + + def close(self): + return self.grpc_channel.close() + + +__all__ = ("SchemaServiceGrpcAsyncIOTransport",) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/__init__.py new file mode 100644 index 000000000000..1d7599467227 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +from .client import SubscriberClient +from .async_client import SubscriberAsyncClient + +__all__ = ( + "SubscriberClient", + "SubscriberAsyncClient", +) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/async_client.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/async_client.py new file mode 100644 index 000000000000..902d134c632c --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/async_client.py @@ -0,0 +1,2517 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +from collections import OrderedDict +import functools +import re +from typing import ( + Dict, + Mapping, + Optional, + AsyncIterable, + Awaitable, + AsyncIterator, + Sequence, + Tuple, + Type, + Union, +) +import warnings +import pkg_resources + +from google.api_core.client_options import ClientOptions +from google.api_core import exceptions as core_exceptions +from google.api_core import gapic_v1 +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.oauth2 import service_account # type: ignore + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + +from google.iam.v1 import iam_policy_pb2 # type: ignore +from google.iam.v1 import policy_pb2 # type: ignore +from google.protobuf import duration_pb2 # type: ignore +from google.protobuf import timestamp_pb2 # type: ignore +from google.pubsub_v1.services.subscriber import pagers +from google.pubsub_v1.types import pubsub +from .transports.base import SubscriberTransport, DEFAULT_CLIENT_INFO +from .transports.grpc_asyncio import SubscriberGrpcAsyncIOTransport +from .client import SubscriberClient + + +class SubscriberAsyncClient: + """The service that an application uses to manipulate subscriptions and + to consume messages from a subscription via the ``Pull`` method or + by establishing a bi-directional stream using the ``StreamingPull`` + method. + """ + + _client: SubscriberClient + + DEFAULT_ENDPOINT = SubscriberClient.DEFAULT_ENDPOINT + DEFAULT_MTLS_ENDPOINT = SubscriberClient.DEFAULT_MTLS_ENDPOINT + + snapshot_path = staticmethod(SubscriberClient.snapshot_path) + parse_snapshot_path = staticmethod(SubscriberClient.parse_snapshot_path) + subscription_path = staticmethod(SubscriberClient.subscription_path) + parse_subscription_path = staticmethod(SubscriberClient.parse_subscription_path) + topic_path = staticmethod(SubscriberClient.topic_path) + parse_topic_path = staticmethod(SubscriberClient.parse_topic_path) + common_billing_account_path = staticmethod( + SubscriberClient.common_billing_account_path + ) + parse_common_billing_account_path = staticmethod( + SubscriberClient.parse_common_billing_account_path + ) + common_folder_path = staticmethod(SubscriberClient.common_folder_path) + parse_common_folder_path = staticmethod(SubscriberClient.parse_common_folder_path) + common_organization_path = staticmethod(SubscriberClient.common_organization_path) + parse_common_organization_path = staticmethod( + SubscriberClient.parse_common_organization_path + ) + common_project_path = staticmethod(SubscriberClient.common_project_path) + parse_common_project_path = staticmethod(SubscriberClient.parse_common_project_path) + common_location_path = staticmethod(SubscriberClient.common_location_path) + parse_common_location_path = staticmethod( + SubscriberClient.parse_common_location_path + ) + + @classmethod + def from_service_account_info(cls, info: dict, *args, **kwargs): + """Creates an instance of this client using the provided credentials + info. + + Args: + info (dict): The service account private key info. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + SubscriberAsyncClient: The constructed client. + """ + return SubscriberClient.from_service_account_info.__func__(SubscriberAsyncClient, info, *args, **kwargs) # type: ignore + + @classmethod + def from_service_account_file(cls, filename: str, *args, **kwargs): + """Creates an instance of this client using the provided credentials + file. + + Args: + filename (str): The path to the service account private key json + file. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + SubscriberAsyncClient: The constructed client. + """ + return SubscriberClient.from_service_account_file.__func__(SubscriberAsyncClient, filename, *args, **kwargs) # type: ignore + + from_service_account_json = from_service_account_file + + @classmethod + def get_mtls_endpoint_and_cert_source( + cls, client_options: Optional[ClientOptions] = None + ): + """Return the API endpoint and client cert source for mutual TLS. + + The client cert source is determined in the following order: + (1) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not "true", the + client cert source is None. + (2) if `client_options.client_cert_source` is provided, use the provided one; if the + default client cert source exists, use the default one; otherwise the client cert + source is None. + + The API endpoint is determined in the following order: + (1) if `client_options.api_endpoint` if provided, use the provided one. + (2) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is "always", use the + default mTLS endpoint; if the environment variabel is "never", use the default API + endpoint; otherwise if client cert source exists, use the default mTLS endpoint, otherwise + use the default API endpoint. + + More details can be found at https://google.aip.dev/auth/4114. + + Args: + client_options (google.api_core.client_options.ClientOptions): Custom options for the + client. Only the `api_endpoint` and `client_cert_source` properties may be used + in this method. + + Returns: + Tuple[str, Callable[[], Tuple[bytes, bytes]]]: returns the API endpoint and the + client cert source to use. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If any errors happen. + """ + return SubscriberClient.get_mtls_endpoint_and_cert_source(client_options) # type: ignore + + @property + def transport(self) -> SubscriberTransport: + """Returns the transport used by the client instance. + + Returns: + SubscriberTransport: The transport used by the client instance. + """ + return self._client.transport + + get_transport_class = functools.partial( + type(SubscriberClient).get_transport_class, type(SubscriberClient) + ) + + def __init__( + self, + *, + credentials: ga_credentials.Credentials = None, + transport: Union[str, SubscriberTransport] = "grpc_asyncio", + client_options: ClientOptions = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + ) -> None: + """Instantiates the subscriber client. + + Args: + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + transport (Union[str, ~.SubscriberTransport]): The + transport to use. If set to None, a transport is chosen + automatically. + client_options (ClientOptions): Custom options for the client. It + won't take effect if a ``transport`` instance is provided. + (1) The ``api_endpoint`` property can be used to override the + default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT + environment variable can also be used to override the endpoint: + "always" (always use the default mTLS endpoint), "never" (always + use the default regular endpoint) and "auto" (auto switch to the + default mTLS endpoint if client certificate is present, this is + the default value). However, the ``api_endpoint`` property takes + precedence if provided. + (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable + is "true", then the ``client_cert_source`` property can be used + to provide client certificate for mutual TLS transport. If + not provided, the default SSL client certificate will be used if + present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not + set, no client certificate will be used. + + Raises: + google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport + creation failed for any reason. + """ + self._client = SubscriberClient( + credentials=credentials, + transport=transport, + client_options=client_options, + client_info=client_info, + ) + + async def create_subscription( + self, + request: Union[pubsub.Subscription, dict] = None, + *, + name: str = None, + topic: str = None, + push_config: pubsub.PushConfig = None, + ack_deadline_seconds: int = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pubsub.Subscription: + r"""Creates a subscription to a given topic. See the [resource name + rules] + (https://cloud.google.com/pubsub/docs/admin#resource_names). If + the subscription already exists, returns ``ALREADY_EXISTS``. If + the corresponding topic doesn't exist, returns ``NOT_FOUND``. + + If the name is not provided in the request, the server will + assign a random name for this subscription on the same project + as the topic, conforming to the [resource name format] + (https://cloud.google.com/pubsub/docs/admin#resource_names). The + generated name is populated in the returned Subscription object. + Note that for REST API requests, you must specify a name in the + request. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + async def sample_create_subscription(): + # Create a client + client = pubsub_v1.SubscriberAsyncClient() + + # Initialize request argument(s) + request = pubsub_v1.Subscription( + name="name_value", + topic="topic_value", + ) + + # Make the request + response = await client.create_subscription(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.pubsub_v1.types.Subscription, dict]): + The request object. A subscription resource. + name (:class:`str`): + Required. The name of the subscription. It must have the + format + ``"projects/{project}/subscriptions/{subscription}"``. + ``{subscription}`` must start with a letter, and contain + only letters (``[A-Za-z]``), numbers (``[0-9]``), dashes + (``-``), underscores (``_``), periods (``.``), tildes + (``~``), plus (``+``) or percent signs (``%``). It must + be between 3 and 255 characters in length, and it must + not start with ``"goog"``. + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + topic (:class:`str`): + Required. The name of the topic from which this + subscription is receiving messages. Format is + ``projects/{project}/topics/{topic}``. The value of this + field will be ``_deleted-topic_`` if the topic has been + deleted. + + This corresponds to the ``topic`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + push_config (:class:`google.pubsub_v1.types.PushConfig`): + If push delivery is used with this subscription, this + field is used to configure it. Either ``pushConfig`` or + ``bigQueryConfig`` can be set, but not both. If both are + empty, then the subscriber will pull and ack messages + using API methods. + + This corresponds to the ``push_config`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + ack_deadline_seconds (:class:`int`): + The approximate amount of time (on a best-effort basis) + Pub/Sub waits for the subscriber to acknowledge receipt + before resending the message. In the interval after the + message is delivered and before it is acknowledged, it + is considered to be outstanding. During that time + period, the message will not be redelivered (on a + best-effort basis). + + For pull subscriptions, this value is used as the + initial value for the ack deadline. To override this + value for a given message, call ``ModifyAckDeadline`` + with the corresponding ``ack_id`` if using non-streaming + pull or send the ``ack_id`` in a + ``StreamingModifyAckDeadlineRequest`` if using streaming + pull. The minimum custom deadline you can specify is 10 + seconds. The maximum custom deadline you can specify is + 600 seconds (10 minutes). If this parameter is 0, a + default value of 10 seconds is used. + + For push delivery, this value is also used to set the + request timeout for the call to the push endpoint. + + If the subscriber never acknowledges the message, the + Pub/Sub system will eventually redeliver the message. + + This corresponds to the ``ack_deadline_seconds`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.pubsub_v1.types.Subscription: + A subscription resource. + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name, topic, push_config, ack_deadline_seconds]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = pubsub.Subscription(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if name is not None: + request.name = name + if topic is not None: + request.topic = topic + if push_config is not None: + request.push_config = push_config + if ack_deadline_seconds is not None: + request.ack_deadline_seconds = ack_deadline_seconds + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.create_subscription, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.Aborted, + core_exceptions.ServiceUnavailable, + core_exceptions.Unknown, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def get_subscription( + self, + request: Union[pubsub.GetSubscriptionRequest, dict] = None, + *, + subscription: str = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pubsub.Subscription: + r"""Gets the configuration details of a subscription. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + async def sample_get_subscription(): + # Create a client + client = pubsub_v1.SubscriberAsyncClient() + + # Initialize request argument(s) + request = pubsub_v1.GetSubscriptionRequest( + subscription="subscription_value", + ) + + # Make the request + response = await client.get_subscription(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.pubsub_v1.types.GetSubscriptionRequest, dict]): + The request object. Request for the GetSubscription + method. + subscription (:class:`str`): + Required. The name of the subscription to get. Format is + ``projects/{project}/subscriptions/{sub}``. + + This corresponds to the ``subscription`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.pubsub_v1.types.Subscription: + A subscription resource. + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([subscription]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = pubsub.GetSubscriptionRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if subscription is not None: + request.subscription = subscription + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.get_subscription, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.Aborted, + core_exceptions.ServiceUnavailable, + core_exceptions.Unknown, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("subscription", request.subscription),) + ), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def update_subscription( + self, + request: Union[pubsub.UpdateSubscriptionRequest, dict] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pubsub.Subscription: + r"""Updates an existing subscription. Note that certain + properties of a subscription, such as its topic, are not + modifiable. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + async def sample_update_subscription(): + # Create a client + client = pubsub_v1.SubscriberAsyncClient() + + # Initialize request argument(s) + subscription = pubsub_v1.Subscription() + subscription.name = "name_value" + subscription.topic = "topic_value" + + request = pubsub_v1.UpdateSubscriptionRequest( + subscription=subscription, + ) + + # Make the request + response = await client.update_subscription(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.pubsub_v1.types.UpdateSubscriptionRequest, dict]): + The request object. Request for the UpdateSubscription + method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.pubsub_v1.types.Subscription: + A subscription resource. + """ + # Create or coerce a protobuf request object. + request = pubsub.UpdateSubscriptionRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.update_subscription, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("subscription.name", request.subscription.name),) + ), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def list_subscriptions( + self, + request: Union[pubsub.ListSubscriptionsRequest, dict] = None, + *, + project: str = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListSubscriptionsAsyncPager: + r"""Lists matching subscriptions. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + async def sample_list_subscriptions(): + # Create a client + client = pubsub_v1.SubscriberAsyncClient() + + # Initialize request argument(s) + request = pubsub_v1.ListSubscriptionsRequest( + project="project_value", + ) + + # Make the request + page_result = client.list_subscriptions(request=request) + + # Handle the response + async for response in page_result: + print(response) + + Args: + request (Union[google.pubsub_v1.types.ListSubscriptionsRequest, dict]): + The request object. Request for the `ListSubscriptions` + method. + project (:class:`str`): + Required. The name of the project in which to list + subscriptions. Format is ``projects/{project-id}``. + + This corresponds to the ``project`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.pubsub_v1.services.subscriber.pagers.ListSubscriptionsAsyncPager: + Response for the ListSubscriptions method. + + Iterating over this object will yield results and + resolve additional pages automatically. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([project]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = pubsub.ListSubscriptionsRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if project is not None: + request.project = project + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.list_subscriptions, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.Aborted, + core_exceptions.ServiceUnavailable, + core_exceptions.Unknown, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("project", request.project),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # This method is paged; wrap the response in a pager, which provides + # an `__aiter__` convenience method. + response = pagers.ListSubscriptionsAsyncPager( + method=rpc, + request=request, + response=response, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def delete_subscription( + self, + request: Union[pubsub.DeleteSubscriptionRequest, dict] = None, + *, + subscription: str = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + r"""Deletes an existing subscription. All messages retained in the + subscription are immediately dropped. Calls to ``Pull`` after + deletion will return ``NOT_FOUND``. After a subscription is + deleted, a new one may be created with the same name, but the + new one has no association with the old subscription or its + topic unless the same topic is specified. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + async def sample_delete_subscription(): + # Create a client + client = pubsub_v1.SubscriberAsyncClient() + + # Initialize request argument(s) + request = pubsub_v1.DeleteSubscriptionRequest( + subscription="subscription_value", + ) + + # Make the request + await client.delete_subscription(request=request) + + Args: + request (Union[google.pubsub_v1.types.DeleteSubscriptionRequest, dict]): + The request object. Request for the DeleteSubscription + method. + subscription (:class:`str`): + Required. The subscription to delete. Format is + ``projects/{project}/subscriptions/{sub}``. + + This corresponds to the ``subscription`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([subscription]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = pubsub.DeleteSubscriptionRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if subscription is not None: + request.subscription = subscription + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.delete_subscription, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("subscription", request.subscription),) + ), + ) + + # Send the request. + await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + async def modify_ack_deadline( + self, + request: Union[pubsub.ModifyAckDeadlineRequest, dict] = None, + *, + subscription: str = None, + ack_ids: Sequence[str] = None, + ack_deadline_seconds: int = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + r"""Modifies the ack deadline for a specific message. This method is + useful to indicate that more time is needed to process a message + by the subscriber, or to make the message available for + redelivery if the processing was interrupted. Note that this + does not modify the subscription-level ``ackDeadlineSeconds`` + used for subsequent messages. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + async def sample_modify_ack_deadline(): + # Create a client + client = pubsub_v1.SubscriberAsyncClient() + + # Initialize request argument(s) + request = pubsub_v1.ModifyAckDeadlineRequest( + subscription="subscription_value", + ack_ids=['ack_ids_value1', 'ack_ids_value2'], + ack_deadline_seconds=2066, + ) + + # Make the request + await client.modify_ack_deadline(request=request) + + Args: + request (Union[google.pubsub_v1.types.ModifyAckDeadlineRequest, dict]): + The request object. Request for the ModifyAckDeadline + method. + subscription (:class:`str`): + Required. The name of the subscription. Format is + ``projects/{project}/subscriptions/{sub}``. + + This corresponds to the ``subscription`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + ack_ids (:class:`Sequence[str]`): + Required. List of acknowledgment IDs. + This corresponds to the ``ack_ids`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + ack_deadline_seconds (:class:`int`): + Required. The new ack deadline with respect to the time + this request was sent to the Pub/Sub system. For + example, if the value is 10, the new ack deadline will + expire 10 seconds after the ``ModifyAckDeadline`` call + was made. Specifying zero might immediately make the + message available for delivery to another subscriber + client. This typically results in an increase in the + rate of message redeliveries (that is, duplicates). The + minimum deadline you can specify is 0 seconds. The + maximum deadline you can specify is 600 seconds (10 + minutes). + + This corresponds to the ``ack_deadline_seconds`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([subscription, ack_ids, ack_deadline_seconds]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = pubsub.ModifyAckDeadlineRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if subscription is not None: + request.subscription = subscription + if ack_deadline_seconds is not None: + request.ack_deadline_seconds = ack_deadline_seconds + if ack_ids: + request.ack_ids.extend(ack_ids) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.modify_ack_deadline, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("subscription", request.subscription),) + ), + ) + + # Send the request. + await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + async def acknowledge( + self, + request: Union[pubsub.AcknowledgeRequest, dict] = None, + *, + subscription: str = None, + ack_ids: Sequence[str] = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + r"""Acknowledges the messages associated with the ``ack_ids`` in the + ``AcknowledgeRequest``. The Pub/Sub system can remove the + relevant messages from the subscription. + + Acknowledging a message whose ack deadline has expired may + succeed, but such a message may be redelivered later. + Acknowledging a message more than once will not result in an + error. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + async def sample_acknowledge(): + # Create a client + client = pubsub_v1.SubscriberAsyncClient() + + # Initialize request argument(s) + request = pubsub_v1.AcknowledgeRequest( + subscription="subscription_value", + ack_ids=['ack_ids_value1', 'ack_ids_value2'], + ) + + # Make the request + await client.acknowledge(request=request) + + Args: + request (Union[google.pubsub_v1.types.AcknowledgeRequest, dict]): + The request object. Request for the Acknowledge method. + subscription (:class:`str`): + Required. The subscription whose message is being + acknowledged. Format is + ``projects/{project}/subscriptions/{sub}``. + + This corresponds to the ``subscription`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + ack_ids (:class:`Sequence[str]`): + Required. The acknowledgment ID for the messages being + acknowledged that was returned by the Pub/Sub system in + the ``Pull`` response. Must not be empty. + + This corresponds to the ``ack_ids`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([subscription, ack_ids]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = pubsub.AcknowledgeRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if subscription is not None: + request.subscription = subscription + if ack_ids: + request.ack_ids.extend(ack_ids) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.acknowledge, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("subscription", request.subscription),) + ), + ) + + # Send the request. + await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + async def pull( + self, + request: Union[pubsub.PullRequest, dict] = None, + *, + subscription: str = None, + return_immediately: bool = None, + max_messages: int = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pubsub.PullResponse: + r"""Pulls messages from the server. The server may return + ``UNAVAILABLE`` if there are too many concurrent pull requests + pending for the given subscription. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + async def sample_pull(): + # Create a client + client = pubsub_v1.SubscriberAsyncClient() + + # Initialize request argument(s) + request = pubsub_v1.PullRequest( + subscription="subscription_value", + max_messages=1277, + ) + + # Make the request + response = await client.pull(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.pubsub_v1.types.PullRequest, dict]): + The request object. Request for the `Pull` method. + subscription (:class:`str`): + Required. The subscription from which messages should be + pulled. Format is + ``projects/{project}/subscriptions/{sub}``. + + This corresponds to the ``subscription`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + return_immediately (:class:`bool`): + Optional. If this field set to true, the system will + respond immediately even if it there are no messages + available to return in the ``Pull`` response. Otherwise, + the system may wait (for a bounded amount of time) until + at least one message is available, rather than returning + no messages. Warning: setting this field to ``true`` is + discouraged because it adversely impacts the performance + of ``Pull`` operations. We recommend that users do not + set this field. + + This corresponds to the ``return_immediately`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + max_messages (:class:`int`): + Required. The maximum number of + messages to return for this request. + Must be a positive integer. The Pub/Sub + system may return fewer than the number + specified. + + This corresponds to the ``max_messages`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.pubsub_v1.types.PullResponse: + Response for the Pull method. + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([subscription, return_immediately, max_messages]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = pubsub.PullRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if subscription is not None: + request.subscription = subscription + if return_immediately is not None: + request.return_immediately = return_immediately + if max_messages is not None: + request.max_messages = max_messages + + if request.return_immediately: + warnings.warn( + "The return_immediately flag is deprecated and should be set to False.", + category=DeprecationWarning, + ) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.pull, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.Aborted, + core_exceptions.ServiceUnavailable, + core_exceptions.Unknown, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("subscription", request.subscription),) + ), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def streaming_pull( + self, + requests: AsyncIterator[pubsub.StreamingPullRequest] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> Awaitable[AsyncIterable[pubsub.StreamingPullResponse]]: + r"""Establishes a stream with the server, which sends messages down + to the client. The client streams acknowledgements and ack + deadline modifications back to the server. The server will close + the stream and return the status on any error. The server may + close the stream with status ``UNAVAILABLE`` to reassign + server-side resources, in which case, the client should + re-establish the stream. Flow control can be achieved by + configuring the underlying RPC channel. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + async def sample_streaming_pull(): + # Create a client + client = pubsub_v1.SubscriberAsyncClient() + + # Initialize request argument(s) + request = pubsub_v1.StreamingPullRequest( + subscription="subscription_value", + stream_ack_deadline_seconds=2813, + ) + + # This method expects an iterator which contains + # 'pubsub_v1.StreamingPullRequest' objects + # Here we create a generator that yields a single `request` for + # demonstrative purposes. + requests = [request] + + def request_generator(): + for request in requests: + yield request + + # Make the request + stream = await client.streaming_pull(requests=request_generator()) + + # Handle the response + async for response in stream: + print(response) + + Args: + requests (AsyncIterator[`google.pubsub_v1.types.StreamingPullRequest`]): + The request object AsyncIterator. Request for the `StreamingPull` + streaming RPC method. This request is used to establish + the initial stream as well as to stream acknowledgements + and ack deadline modifications from the client to the + server. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + AsyncIterable[google.pubsub_v1.types.StreamingPullResponse]: + Response for the StreamingPull method. This response is used to stream + messages from the server to the client. + + """ + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.streaming_pull, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.Aborted, + core_exceptions.DeadlineExceeded, + core_exceptions.InternalServerError, + core_exceptions.ResourceExhausted, + core_exceptions.ServiceUnavailable, + ), + deadline=900.0, + ), + default_timeout=900.0, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Send the request. + response = rpc( + requests, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def modify_push_config( + self, + request: Union[pubsub.ModifyPushConfigRequest, dict] = None, + *, + subscription: str = None, + push_config: pubsub.PushConfig = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + r"""Modifies the ``PushConfig`` for a specified subscription. + + This may be used to change a push subscription to a pull one + (signified by an empty ``PushConfig``) or vice versa, or change + the endpoint URL and other attributes of a push subscription. + Messages will accumulate for delivery continuously through the + call regardless of changes to the ``PushConfig``. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + async def sample_modify_push_config(): + # Create a client + client = pubsub_v1.SubscriberAsyncClient() + + # Initialize request argument(s) + request = pubsub_v1.ModifyPushConfigRequest( + subscription="subscription_value", + ) + + # Make the request + await client.modify_push_config(request=request) + + Args: + request (Union[google.pubsub_v1.types.ModifyPushConfigRequest, dict]): + The request object. Request for the ModifyPushConfig + method. + subscription (:class:`str`): + Required. The name of the subscription. Format is + ``projects/{project}/subscriptions/{sub}``. + + This corresponds to the ``subscription`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + push_config (:class:`google.pubsub_v1.types.PushConfig`): + Required. The push configuration for future deliveries. + + An empty ``pushConfig`` indicates that the Pub/Sub + system should stop pushing messages from the given + subscription and allow messages to be pulled and + acknowledged - effectively pausing the subscription if + ``Pull`` or ``StreamingPull`` is not called. + + This corresponds to the ``push_config`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([subscription, push_config]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = pubsub.ModifyPushConfigRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if subscription is not None: + request.subscription = subscription + if push_config is not None: + request.push_config = push_config + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.modify_push_config, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("subscription", request.subscription),) + ), + ) + + # Send the request. + await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + async def get_snapshot( + self, + request: Union[pubsub.GetSnapshotRequest, dict] = None, + *, + snapshot: str = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pubsub.Snapshot: + r"""Gets the configuration details of a snapshot. + Snapshots are used in Seek + operations, which allow you to manage message + acknowledgments in bulk. That is, you can set the + acknowledgment state of messages in an existing + subscription to the state captured by a snapshot. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + async def sample_get_snapshot(): + # Create a client + client = pubsub_v1.SubscriberAsyncClient() + + # Initialize request argument(s) + request = pubsub_v1.GetSnapshotRequest( + snapshot="snapshot_value", + ) + + # Make the request + response = await client.get_snapshot(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.pubsub_v1.types.GetSnapshotRequest, dict]): + The request object. Request for the GetSnapshot method. + snapshot (:class:`str`): + Required. The name of the snapshot to get. Format is + ``projects/{project}/snapshots/{snap}``. + + This corresponds to the ``snapshot`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.pubsub_v1.types.Snapshot: + A snapshot resource. Snapshots are used in + [Seek](https://cloud.google.com/pubsub/docs/replay-overview) + operations, which allow you to manage message + acknowledgments in bulk. That is, you can set the + acknowledgment state of messages in an existing + subscription to the state captured by a snapshot. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([snapshot]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = pubsub.GetSnapshotRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if snapshot is not None: + request.snapshot = snapshot + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.get_snapshot, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.Aborted, + core_exceptions.ServiceUnavailable, + core_exceptions.Unknown, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("snapshot", request.snapshot),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def list_snapshots( + self, + request: Union[pubsub.ListSnapshotsRequest, dict] = None, + *, + project: str = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListSnapshotsAsyncPager: + r"""Lists the existing snapshots. Snapshots are used in + `Seek `__ + operations, which allow you to manage message acknowledgments in + bulk. That is, you can set the acknowledgment state of messages + in an existing subscription to the state captured by a snapshot. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + async def sample_list_snapshots(): + # Create a client + client = pubsub_v1.SubscriberAsyncClient() + + # Initialize request argument(s) + request = pubsub_v1.ListSnapshotsRequest( + project="project_value", + ) + + # Make the request + page_result = client.list_snapshots(request=request) + + # Handle the response + async for response in page_result: + print(response) + + Args: + request (Union[google.pubsub_v1.types.ListSnapshotsRequest, dict]): + The request object. Request for the `ListSnapshots` + method. + project (:class:`str`): + Required. The name of the project in which to list + snapshots. Format is ``projects/{project-id}``. + + This corresponds to the ``project`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.pubsub_v1.services.subscriber.pagers.ListSnapshotsAsyncPager: + Response for the ListSnapshots method. + + Iterating over this object will yield results and + resolve additional pages automatically. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([project]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = pubsub.ListSnapshotsRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if project is not None: + request.project = project + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.list_snapshots, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.Aborted, + core_exceptions.ServiceUnavailable, + core_exceptions.Unknown, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("project", request.project),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # This method is paged; wrap the response in a pager, which provides + # an `__aiter__` convenience method. + response = pagers.ListSnapshotsAsyncPager( + method=rpc, + request=request, + response=response, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def create_snapshot( + self, + request: Union[pubsub.CreateSnapshotRequest, dict] = None, + *, + name: str = None, + subscription: str = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pubsub.Snapshot: + r"""Creates a snapshot from the requested subscription. Snapshots + are used in + `Seek `__ + operations, which allow you to manage message acknowledgments in + bulk. That is, you can set the acknowledgment state of messages + in an existing subscription to the state captured by a snapshot. + If the snapshot already exists, returns ``ALREADY_EXISTS``. If + the requested subscription doesn't exist, returns ``NOT_FOUND``. + If the backlog in the subscription is too old -- and the + resulting snapshot would expire in less than 1 hour -- then + ``FAILED_PRECONDITION`` is returned. See also the + ``Snapshot.expire_time`` field. If the name is not provided in + the request, the server will assign a random name for this + snapshot on the same project as the subscription, conforming to + the [resource name format] + (https://cloud.google.com/pubsub/docs/admin#resource_names). The + generated name is populated in the returned Snapshot object. + Note that for REST API requests, you must specify a name in the + request. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + async def sample_create_snapshot(): + # Create a client + client = pubsub_v1.SubscriberAsyncClient() + + # Initialize request argument(s) + request = pubsub_v1.CreateSnapshotRequest( + name="name_value", + subscription="subscription_value", + ) + + # Make the request + response = await client.create_snapshot(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.pubsub_v1.types.CreateSnapshotRequest, dict]): + The request object. Request for the `CreateSnapshot` + method. + name (:class:`str`): + Required. User-provided name for this snapshot. If the + name is not provided in the request, the server will + assign a random name for this snapshot on the same + project as the subscription. Note that for REST API + requests, you must specify a name. See the resource name + rules. Format is + ``projects/{project}/snapshots/{snap}``. + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + subscription (:class:`str`): + Required. The subscription whose backlog the snapshot + retains. Specifically, the created snapshot is + guaranteed to retain: (a) The existing backlog on the + subscription. More precisely, this is defined as the + messages in the subscription's backlog that are + unacknowledged upon the successful completion of the + ``CreateSnapshot`` request; as well as: (b) Any messages + published to the subscription's topic following the + successful completion of the CreateSnapshot request. + Format is ``projects/{project}/subscriptions/{sub}``. + + This corresponds to the ``subscription`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.pubsub_v1.types.Snapshot: + A snapshot resource. Snapshots are used in + [Seek](https://cloud.google.com/pubsub/docs/replay-overview) + operations, which allow you to manage message + acknowledgments in bulk. That is, you can set the + acknowledgment state of messages in an existing + subscription to the state captured by a snapshot. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name, subscription]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = pubsub.CreateSnapshotRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if name is not None: + request.name = name + if subscription is not None: + request.subscription = subscription + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.create_snapshot, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def update_snapshot( + self, + request: Union[pubsub.UpdateSnapshotRequest, dict] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pubsub.Snapshot: + r"""Updates an existing snapshot. Snapshots are used in + Seek + operations, which allow + you to manage message acknowledgments in bulk. That is, + you can set the acknowledgment state of messages in an + existing subscription to the state captured by a + snapshot. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + async def sample_update_snapshot(): + # Create a client + client = pubsub_v1.SubscriberAsyncClient() + + # Initialize request argument(s) + request = pubsub_v1.UpdateSnapshotRequest( + ) + + # Make the request + response = await client.update_snapshot(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.pubsub_v1.types.UpdateSnapshotRequest, dict]): + The request object. Request for the UpdateSnapshot + method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.pubsub_v1.types.Snapshot: + A snapshot resource. Snapshots are used in + [Seek](https://cloud.google.com/pubsub/docs/replay-overview) + operations, which allow you to manage message + acknowledgments in bulk. That is, you can set the + acknowledgment state of messages in an existing + subscription to the state captured by a snapshot. + + """ + # Create or coerce a protobuf request object. + request = pubsub.UpdateSnapshotRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.update_snapshot, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("snapshot.name", request.snapshot.name),) + ), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def delete_snapshot( + self, + request: Union[pubsub.DeleteSnapshotRequest, dict] = None, + *, + snapshot: str = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + r"""Removes an existing snapshot. Snapshots are used in [Seek] + (https://cloud.google.com/pubsub/docs/replay-overview) + operations, which allow you to manage message acknowledgments in + bulk. That is, you can set the acknowledgment state of messages + in an existing subscription to the state captured by a snapshot. + When the snapshot is deleted, all messages retained in the + snapshot are immediately dropped. After a snapshot is deleted, a + new one may be created with the same name, but the new one has + no association with the old snapshot or its subscription, unless + the same subscription is specified. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + async def sample_delete_snapshot(): + # Create a client + client = pubsub_v1.SubscriberAsyncClient() + + # Initialize request argument(s) + request = pubsub_v1.DeleteSnapshotRequest( + snapshot="snapshot_value", + ) + + # Make the request + await client.delete_snapshot(request=request) + + Args: + request (Union[google.pubsub_v1.types.DeleteSnapshotRequest, dict]): + The request object. Request for the `DeleteSnapshot` + method. + snapshot (:class:`str`): + Required. The name of the snapshot to delete. Format is + ``projects/{project}/snapshots/{snap}``. + + This corresponds to the ``snapshot`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([snapshot]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + request = pubsub.DeleteSnapshotRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if snapshot is not None: + request.snapshot = snapshot + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.delete_snapshot, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("snapshot", request.snapshot),)), + ) + + # Send the request. + await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + async def seek( + self, + request: Union[pubsub.SeekRequest, dict] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pubsub.SeekResponse: + r"""Seeks an existing subscription to a point in time or to a given + snapshot, whichever is provided in the request. Snapshots are + used in [Seek] + (https://cloud.google.com/pubsub/docs/replay-overview) + operations, which allow you to manage message acknowledgments in + bulk. That is, you can set the acknowledgment state of messages + in an existing subscription to the state captured by a snapshot. + Note that both the subscription and the snapshot must be on the + same topic. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + async def sample_seek(): + # Create a client + client = pubsub_v1.SubscriberAsyncClient() + + # Initialize request argument(s) + request = pubsub_v1.SeekRequest( + subscription="subscription_value", + ) + + # Make the request + response = await client.seek(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.pubsub_v1.types.SeekRequest, dict]): + The request object. Request for the `Seek` method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.pubsub_v1.types.SeekResponse: + Response for the Seek method (this response is empty). + """ + # Create or coerce a protobuf request object. + request = pubsub.SeekRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.seek, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.Aborted, + core_exceptions.ServiceUnavailable, + core_exceptions.Unknown, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("subscription", request.subscription),) + ), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def set_iam_policy( + self, + request: iam_policy_pb2.SetIamPolicyRequest = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> policy_pb2.Policy: + r"""Sets the IAM access control policy on the specified function. + + Replaces any existing policy. + + Args: + request (:class:`~.policy_pb2.SetIamPolicyRequest`): + The request object. Request message for `SetIamPolicy` + method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~.policy_pb2.Policy: + Defines an Identity and Access Management (IAM) policy. + It is used to specify access control policies for Cloud + Platform resources. + A ``Policy`` is a collection of ``bindings``. A + ``binding`` binds one or more ``members`` to a single + ``role``. Members can be user accounts, service + accounts, Google groups, and domains (such as G Suite). + A ``role`` is a named list of permissions (defined by + IAM or configured by users). A ``binding`` can + optionally specify a ``condition``, which is a logic + expression that further constrains the role binding + based on attributes about the request and/or target + resource. + + **JSON Example** + + :: + { + "bindings": [ + { + "role": "roles/resourcemanager.organizationAdmin", + "members": [ + "user:mike@example.com", + "group:admins@example.com", + "domain:google.com", + "serviceAccount:my-project-id@appspot.gserviceaccount.com" + ] + }, + { + "role": "roles/resourcemanager.organizationViewer", + "members": ["user:eve@example.com"], + "condition": { + "title": "expirable access", + "description": "Does not grant access after Sep 2020", + "expression": "request.time < + timestamp('2020-10-01T00:00:00.000Z')", + } + } + ] + } + + **YAML Example** + + :: + + bindings: + - members: + - user:mike@example.com + - group:admins@example.com + - domain:google.com + - serviceAccount:my-project-id@appspot.gserviceaccount.com + role: roles/resourcemanager.organizationAdmin + - members: + - user:eve@example.com + role: roles/resourcemanager.organizationViewer + condition: + title: expirable access + description: Does not grant access after Sep 2020 + expression: request.time < timestamp('2020-10-01T00:00:00.000Z') + + For a description of IAM and its features, see the `IAM + developer's + guide `__. + """ + # Create or coerce a protobuf request object. + + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = iam_policy_pb2.SetIamPolicyRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.set_iam_policy, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("resource", request.resource),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def get_iam_policy( + self, + request: iam_policy_pb2.GetIamPolicyRequest = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> policy_pb2.Policy: + r"""Gets the IAM access control policy for a function. + + Returns an empty policy if the function exists and does + not have a policy set. + + Args: + request (:class:`~.iam_policy_pb2.GetIamPolicyRequest`): + The request object. Request message for `GetIamPolicy` + method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~.policy_pb2.Policy: + Defines an Identity and Access Management (IAM) policy. + It is used to specify access control policies for Cloud + Platform resources. + A ``Policy`` is a collection of ``bindings``. A + ``binding`` binds one or more ``members`` to a single + ``role``. Members can be user accounts, service + accounts, Google groups, and domains (such as G Suite). + A ``role`` is a named list of permissions (defined by + IAM or configured by users). A ``binding`` can + optionally specify a ``condition``, which is a logic + expression that further constrains the role binding + based on attributes about the request and/or target + resource. + + **JSON Example** + + :: + + { + "bindings": [ + { + "role": "roles/resourcemanager.organizationAdmin", + "members": [ + "user:mike@example.com", + "group:admins@example.com", + "domain:google.com", + "serviceAccount:my-project-id@appspot.gserviceaccount.com" + ] + }, + { + "role": "roles/resourcemanager.organizationViewer", + "members": ["user:eve@example.com"], + "condition": { + "title": "expirable access", + "description": "Does not grant access after Sep 2020", + "expression": "request.time < + timestamp('2020-10-01T00:00:00.000Z')", + } + } + ] + } + + **YAML Example** + + :: + + bindings: + - members: + - user:mike@example.com + - group:admins@example.com + - domain:google.com + - serviceAccount:my-project-id@appspot.gserviceaccount.com + role: roles/resourcemanager.organizationAdmin + - members: + - user:eve@example.com + role: roles/resourcemanager.organizationViewer + condition: + title: expirable access + description: Does not grant access after Sep 2020 + expression: request.time < timestamp('2020-10-01T00:00:00.000Z') + + For a description of IAM and its features, see the `IAM + developer's + guide `__. + """ + # Create or coerce a protobuf request object. + + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = iam_policy_pb2.GetIamPolicyRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.get_iam_policy, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("resource", request.resource),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def test_iam_permissions( + self, + request: iam_policy_pb2.TestIamPermissionsRequest = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> iam_policy_pb2.TestIamPermissionsResponse: + r"""Tests the specified permissions against the IAM access control + policy for a function. + + If the function does not exist, this will + return an empty set of permissions, not a NOT_FOUND error. + + Args: + request (:class:`~.iam_policy_pb2.TestIamPermissionsRequest`): + The request object. Request message for + `TestIamPermissions` method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~iam_policy_pb2.PolicyTestIamPermissionsResponse: + Response message for ``TestIamPermissions`` method. + """ + # Create or coerce a protobuf request object. + + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = iam_policy_pb2.TestIamPermissionsRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method_async.wrap_method( + self._client._transport.test_iam_permissions, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("resource", request.resource),)), + ) + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc, tb): + await self.transport.close() + + +try: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + client_library_version=pkg_resources.get_distribution( + "google-cloud-pubsub", + ).version, + ) +except pkg_resources.DistributionNotFound: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() + + +__all__ = ("SubscriberAsyncClient",) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py new file mode 100644 index 000000000000..6f08e2792e1a --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py @@ -0,0 +1,2644 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +from collections import OrderedDict +import functools +import os +import re +from typing import ( + Dict, + Mapping, + Optional, + Iterable, + Iterator, + Sequence, + Tuple, + Type, + Union, +) +import warnings +import pkg_resources + +from google.api_core import client_options as client_options_lib +from google.api_core import exceptions as core_exceptions +from google.api_core import gapic_v1 +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport import mtls # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore +from google.auth.exceptions import MutualTLSChannelError # type: ignore +from google.oauth2 import service_account # type: ignore + +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object] # type: ignore + +from google.iam.v1 import iam_policy_pb2 # type: ignore +from google.iam.v1 import policy_pb2 # type: ignore +from google.protobuf import duration_pb2 # type: ignore +from google.protobuf import timestamp_pb2 # type: ignore +from google.pubsub_v1.services.subscriber import pagers +from google.pubsub_v1.types import pubsub + +import grpc +from .transports.base import SubscriberTransport, DEFAULT_CLIENT_INFO +from .transports.grpc import SubscriberGrpcTransport +from .transports.grpc_asyncio import SubscriberGrpcAsyncIOTransport + + +class SubscriberClientMeta(type): + """Metaclass for the Subscriber client. + + This provides class-level methods for building and retrieving + support objects (e.g. transport) without polluting the client instance + objects. + """ + + _transport_registry = OrderedDict() # type: Dict[str, Type[SubscriberTransport]] + _transport_registry["grpc"] = SubscriberGrpcTransport + _transport_registry["grpc_asyncio"] = SubscriberGrpcAsyncIOTransport + + def get_transport_class( + cls, + label: str = None, + ) -> Type[SubscriberTransport]: + """Returns an appropriate transport class. + + Args: + label: The name of the desired transport. If none is + provided, then the first transport in the registry is used. + + Returns: + The transport class to use. + """ + # If a specific transport is requested, return that one. + if label: + return cls._transport_registry[label] + + # No transport is requested; return the default (that is, the first one + # in the dictionary). + return next(iter(cls._transport_registry.values())) + + +class SubscriberClient(metaclass=SubscriberClientMeta): + """The service that an application uses to manipulate subscriptions and + to consume messages from a subscription via the ``Pull`` method or + by establishing a bi-directional stream using the ``StreamingPull`` + method. + """ + + @staticmethod + def _get_default_mtls_endpoint(api_endpoint): + """Converts api endpoint to mTLS endpoint. + + Convert "*.sandbox.googleapis.com" and "*.googleapis.com" to + "*.mtls.sandbox.googleapis.com" and "*.mtls.googleapis.com" respectively. + Args: + api_endpoint (Optional[str]): the api endpoint to convert. + Returns: + str: converted mTLS api endpoint. + """ + if not api_endpoint: + return api_endpoint + + mtls_endpoint_re = re.compile( + r"(?P[^.]+)(?P\.mtls)?(?P\.sandbox)?(?P\.googleapis\.com)?" + ) + + m = mtls_endpoint_re.match(api_endpoint) + name, mtls, sandbox, googledomain = m.groups() + if mtls or not googledomain: + return api_endpoint + + if sandbox: + return api_endpoint.replace( + "sandbox.googleapis.com", "mtls.sandbox.googleapis.com" + ) + + return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com") + + # The scopes needed to make gRPC calls to all of the methods defined in + # this service + _DEFAULT_SCOPES = ( + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/pubsub", + ) + + SERVICE_ADDRESS = "pubsub.googleapis.com:443" + """The default address of the service.""" + + DEFAULT_ENDPOINT = "pubsub.googleapis.com" + DEFAULT_MTLS_ENDPOINT = _get_default_mtls_endpoint.__func__( # type: ignore + DEFAULT_ENDPOINT + ) + + @classmethod + def from_service_account_info(cls, info: dict, *args, **kwargs): + """Creates an instance of this client using the provided credentials + info. + + Args: + info (dict): The service account private key info. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + SubscriberClient: The constructed client. + """ + credentials = service_account.Credentials.from_service_account_info(info) + kwargs["credentials"] = credentials + return cls(*args, **kwargs) + + @classmethod + def from_service_account_file(cls, filename: str, *args, **kwargs): + """Creates an instance of this client using the provided credentials + file. + + Args: + filename (str): The path to the service account private key json + file. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + SubscriberClient: The constructed client. + """ + credentials = service_account.Credentials.from_service_account_file(filename) + kwargs["credentials"] = credentials + return cls(*args, **kwargs) + + from_service_account_json = from_service_account_file + + @property + def transport(self) -> SubscriberTransport: + """Returns the transport used by the client instance. + + Returns: + SubscriberTransport: The transport used by the client + instance. + """ + return self._transport + + @staticmethod + def snapshot_path( + project: str, + snapshot: str, + ) -> str: + """Returns a fully-qualified snapshot string.""" + return "projects/{project}/snapshots/{snapshot}".format( + project=project, + snapshot=snapshot, + ) + + @staticmethod + def parse_snapshot_path(path: str) -> Dict[str, str]: + """Parses a snapshot path into its component segments.""" + m = re.match(r"^projects/(?P.+?)/snapshots/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def subscription_path( + project: str, + subscription: str, + ) -> str: + """Returns a fully-qualified subscription string.""" + return "projects/{project}/subscriptions/{subscription}".format( + project=project, + subscription=subscription, + ) + + @staticmethod + def parse_subscription_path(path: str) -> Dict[str, str]: + """Parses a subscription path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/subscriptions/(?P.+?)$", path + ) + return m.groupdict() if m else {} + + @staticmethod + def topic_path( + project: str, + topic: str, + ) -> str: + """Returns a fully-qualified topic string.""" + return "projects/{project}/topics/{topic}".format( + project=project, + topic=topic, + ) + + @staticmethod + def parse_topic_path(path: str) -> Dict[str, str]: + """Parses a topic path into its component segments.""" + m = re.match(r"^projects/(?P.+?)/topics/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_billing_account_path( + billing_account: str, + ) -> str: + """Returns a fully-qualified billing_account string.""" + return "billingAccounts/{billing_account}".format( + billing_account=billing_account, + ) + + @staticmethod + def parse_common_billing_account_path(path: str) -> Dict[str, str]: + """Parse a billing_account path into its component segments.""" + m = re.match(r"^billingAccounts/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_folder_path( + folder: str, + ) -> str: + """Returns a fully-qualified folder string.""" + return "folders/{folder}".format( + folder=folder, + ) + + @staticmethod + def parse_common_folder_path(path: str) -> Dict[str, str]: + """Parse a folder path into its component segments.""" + m = re.match(r"^folders/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_organization_path( + organization: str, + ) -> str: + """Returns a fully-qualified organization string.""" + return "organizations/{organization}".format( + organization=organization, + ) + + @staticmethod + def parse_common_organization_path(path: str) -> Dict[str, str]: + """Parse a organization path into its component segments.""" + m = re.match(r"^organizations/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_project_path( + project: str, + ) -> str: + """Returns a fully-qualified project string.""" + return "projects/{project}".format( + project=project, + ) + + @staticmethod + def parse_common_project_path(path: str) -> Dict[str, str]: + """Parse a project path into its component segments.""" + m = re.match(r"^projects/(?P.+?)$", path) + return m.groupdict() if m else {} + + @staticmethod + def common_location_path( + project: str, + location: str, + ) -> str: + """Returns a fully-qualified location string.""" + return "projects/{project}/locations/{location}".format( + project=project, + location=location, + ) + + @staticmethod + def parse_common_location_path(path: str) -> Dict[str, str]: + """Parse a location path into its component segments.""" + m = re.match(r"^projects/(?P.+?)/locations/(?P.+?)$", path) + return m.groupdict() if m else {} + + @classmethod + def get_mtls_endpoint_and_cert_source( + cls, client_options: Optional[client_options_lib.ClientOptions] = None + ): + """Return the API endpoint and client cert source for mutual TLS. + + The client cert source is determined in the following order: + (1) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not "true", the + client cert source is None. + (2) if `client_options.client_cert_source` is provided, use the provided one; if the + default client cert source exists, use the default one; otherwise the client cert + source is None. + + The API endpoint is determined in the following order: + (1) if `client_options.api_endpoint` if provided, use the provided one. + (2) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is "always", use the + default mTLS endpoint; if the environment variabel is "never", use the default API + endpoint; otherwise if client cert source exists, use the default mTLS endpoint, otherwise + use the default API endpoint. + + More details can be found at https://google.aip.dev/auth/4114. + + Args: + client_options (google.api_core.client_options.ClientOptions): Custom options for the + client. Only the `api_endpoint` and `client_cert_source` properties may be used + in this method. + + Returns: + Tuple[str, Callable[[], Tuple[bytes, bytes]]]: returns the API endpoint and the + client cert source to use. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If any errors happen. + """ + if client_options is None: + client_options = client_options_lib.ClientOptions() + use_client_cert = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false") + use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto") + if use_client_cert not in ("true", "false"): + raise ValueError( + "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`" + ) + if use_mtls_endpoint not in ("auto", "never", "always"): + raise MutualTLSChannelError( + "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`" + ) + + # Figure out the client cert source to use. + client_cert_source = None + if use_client_cert == "true": + if client_options.client_cert_source: + client_cert_source = client_options.client_cert_source + elif mtls.has_default_client_cert_source(): + client_cert_source = mtls.default_client_cert_source() + + # Figure out which api endpoint to use. + if client_options.api_endpoint is not None: + api_endpoint = client_options.api_endpoint + elif use_mtls_endpoint == "always" or ( + use_mtls_endpoint == "auto" and client_cert_source + ): + api_endpoint = cls.DEFAULT_MTLS_ENDPOINT + else: + api_endpoint = cls.DEFAULT_ENDPOINT + + return api_endpoint, client_cert_source + + def __init__( + self, + *, + credentials: Optional[ga_credentials.Credentials] = None, + transport: Union[str, SubscriberTransport, None] = None, + client_options: Optional[client_options_lib.ClientOptions] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + ) -> None: + """Instantiates the subscriber client. + + Args: + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + transport (Union[str, SubscriberTransport]): The + transport to use. If set to None, a transport is chosen + automatically. + client_options (google.api_core.client_options.ClientOptions): Custom options for the + client. It won't take effect if a ``transport`` instance is provided. + (1) The ``api_endpoint`` property can be used to override the + default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT + environment variable can also be used to override the endpoint: + "always" (always use the default mTLS endpoint), "never" (always + use the default regular endpoint) and "auto" (auto switch to the + default mTLS endpoint if client certificate is present, this is + the default value). However, the ``api_endpoint`` property takes + precedence if provided. + (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable + is "true", then the ``client_cert_source`` property can be used + to provide client certificate for mutual TLS transport. If + not provided, the default SSL client certificate will be used if + present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not + set, no client certificate will be used. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport + creation failed for any reason. + """ + if isinstance(client_options, dict): + client_options = client_options_lib.from_dict(client_options) + if client_options is None: + client_options = client_options_lib.ClientOptions() + + api_endpoint, client_cert_source_func = self.get_mtls_endpoint_and_cert_source( + client_options + ) + + api_key_value = getattr(client_options, "api_key", None) + if api_key_value and credentials: + raise ValueError( + "client_options.api_key and credentials are mutually exclusive" + ) + + # Save or instantiate the transport. + # Ordinarily, we provide the transport, but allowing a custom transport + # instance provides an extensibility point for unusual situations. + if isinstance(transport, SubscriberTransport): + # transport is a SubscriberTransport instance. + if credentials or client_options.credentials_file or api_key_value: + raise ValueError( + "When providing a transport instance, " + "provide its credentials directly." + ) + if client_options.scopes: + raise ValueError( + "When providing a transport instance, provide its scopes " + "directly." + ) + self._transport = transport + else: + import google.auth._default # type: ignore + + if api_key_value and hasattr( + google.auth._default, "get_api_key_credentials" + ): + credentials = google.auth._default.get_api_key_credentials( + api_key_value + ) + + Transport = type(self).get_transport_class(transport) + + emulator_host = os.environ.get("PUBSUB_EMULATOR_HOST") + if emulator_host: + if issubclass(Transport, type(self)._transport_registry["grpc"]): + channel = grpc.insecure_channel(target=emulator_host) + else: + channel = grpc.aio.insecure_channel(target=emulator_host) + Transport = functools.partial(Transport, channel=channel) + + self._transport = Transport( + credentials=credentials, + credentials_file=client_options.credentials_file, + host=api_endpoint, + scopes=client_options.scopes, + client_cert_source_for_mtls=client_cert_source_func, + quota_project_id=client_options.quota_project_id, + client_info=client_info, + always_use_jwt_access=True, + api_audience=client_options.api_audience, + ) + + def create_subscription( + self, + request: Union[pubsub.Subscription, dict] = None, + *, + name: str = None, + topic: str = None, + push_config: pubsub.PushConfig = None, + ack_deadline_seconds: int = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pubsub.Subscription: + r"""Creates a subscription to a given topic. See the [resource name + rules] + (https://cloud.google.com/pubsub/docs/admin#resource_names). If + the subscription already exists, returns ``ALREADY_EXISTS``. If + the corresponding topic doesn't exist, returns ``NOT_FOUND``. + + If the name is not provided in the request, the server will + assign a random name for this subscription on the same project + as the topic, conforming to the [resource name format] + (https://cloud.google.com/pubsub/docs/admin#resource_names). The + generated name is populated in the returned Subscription object. + Note that for REST API requests, you must specify a name in the + request. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + def sample_create_subscription(): + # Create a client + client = pubsub_v1.SubscriberClient() + + # Initialize request argument(s) + request = pubsub_v1.Subscription( + name="name_value", + topic="topic_value", + ) + + # Make the request + response = client.create_subscription(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.pubsub_v1.types.Subscription, dict]): + The request object. A subscription resource. + name (str): + Required. The name of the subscription. It must have the + format + ``"projects/{project}/subscriptions/{subscription}"``. + ``{subscription}`` must start with a letter, and contain + only letters (``[A-Za-z]``), numbers (``[0-9]``), dashes + (``-``), underscores (``_``), periods (``.``), tildes + (``~``), plus (``+``) or percent signs (``%``). It must + be between 3 and 255 characters in length, and it must + not start with ``"goog"``. + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + topic (str): + Required. The name of the topic from which this + subscription is receiving messages. Format is + ``projects/{project}/topics/{topic}``. The value of this + field will be ``_deleted-topic_`` if the topic has been + deleted. + + This corresponds to the ``topic`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + push_config (google.pubsub_v1.types.PushConfig): + If push delivery is used with this subscription, this + field is used to configure it. Either ``pushConfig`` or + ``bigQueryConfig`` can be set, but not both. If both are + empty, then the subscriber will pull and ack messages + using API methods. + + This corresponds to the ``push_config`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + ack_deadline_seconds (int): + The approximate amount of time (on a best-effort basis) + Pub/Sub waits for the subscriber to acknowledge receipt + before resending the message. In the interval after the + message is delivered and before it is acknowledged, it + is considered to be outstanding. During that time + period, the message will not be redelivered (on a + best-effort basis). + + For pull subscriptions, this value is used as the + initial value for the ack deadline. To override this + value for a given message, call ``ModifyAckDeadline`` + with the corresponding ``ack_id`` if using non-streaming + pull or send the ``ack_id`` in a + ``StreamingModifyAckDeadlineRequest`` if using streaming + pull. The minimum custom deadline you can specify is 10 + seconds. The maximum custom deadline you can specify is + 600 seconds (10 minutes). If this parameter is 0, a + default value of 10 seconds is used. + + For push delivery, this value is also used to set the + request timeout for the call to the push endpoint. + + If the subscriber never acknowledges the message, the + Pub/Sub system will eventually redeliver the message. + + This corresponds to the ``ack_deadline_seconds`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.pubsub_v1.types.Subscription: + A subscription resource. + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name, topic, push_config, ack_deadline_seconds]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a pubsub.Subscription. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, pubsub.Subscription): + request = pubsub.Subscription(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if name is not None: + request.name = name + if topic is not None: + request.topic = topic + if push_config is not None: + request.push_config = push_config + if ack_deadline_seconds is not None: + request.ack_deadline_seconds = ack_deadline_seconds + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.create_subscription] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def get_subscription( + self, + request: Union[pubsub.GetSubscriptionRequest, dict] = None, + *, + subscription: str = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pubsub.Subscription: + r"""Gets the configuration details of a subscription. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + def sample_get_subscription(): + # Create a client + client = pubsub_v1.SubscriberClient() + + # Initialize request argument(s) + request = pubsub_v1.GetSubscriptionRequest( + subscription="subscription_value", + ) + + # Make the request + response = client.get_subscription(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.pubsub_v1.types.GetSubscriptionRequest, dict]): + The request object. Request for the GetSubscription + method. + subscription (str): + Required. The name of the subscription to get. Format is + ``projects/{project}/subscriptions/{sub}``. + + This corresponds to the ``subscription`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.pubsub_v1.types.Subscription: + A subscription resource. + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([subscription]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a pubsub.GetSubscriptionRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, pubsub.GetSubscriptionRequest): + request = pubsub.GetSubscriptionRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if subscription is not None: + request.subscription = subscription + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.get_subscription] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("subscription", request.subscription),) + ), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def update_subscription( + self, + request: Union[pubsub.UpdateSubscriptionRequest, dict] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pubsub.Subscription: + r"""Updates an existing subscription. Note that certain + properties of a subscription, such as its topic, are not + modifiable. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + def sample_update_subscription(): + # Create a client + client = pubsub_v1.SubscriberClient() + + # Initialize request argument(s) + subscription = pubsub_v1.Subscription() + subscription.name = "name_value" + subscription.topic = "topic_value" + + request = pubsub_v1.UpdateSubscriptionRequest( + subscription=subscription, + ) + + # Make the request + response = client.update_subscription(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.pubsub_v1.types.UpdateSubscriptionRequest, dict]): + The request object. Request for the UpdateSubscription + method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.pubsub_v1.types.Subscription: + A subscription resource. + """ + # Create or coerce a protobuf request object. + # Minor optimization to avoid making a copy if the user passes + # in a pubsub.UpdateSubscriptionRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, pubsub.UpdateSubscriptionRequest): + request = pubsub.UpdateSubscriptionRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.update_subscription] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("subscription.name", request.subscription.name),) + ), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def list_subscriptions( + self, + request: Union[pubsub.ListSubscriptionsRequest, dict] = None, + *, + project: str = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListSubscriptionsPager: + r"""Lists matching subscriptions. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + def sample_list_subscriptions(): + # Create a client + client = pubsub_v1.SubscriberClient() + + # Initialize request argument(s) + request = pubsub_v1.ListSubscriptionsRequest( + project="project_value", + ) + + # Make the request + page_result = client.list_subscriptions(request=request) + + # Handle the response + for response in page_result: + print(response) + + Args: + request (Union[google.pubsub_v1.types.ListSubscriptionsRequest, dict]): + The request object. Request for the `ListSubscriptions` + method. + project (str): + Required. The name of the project in which to list + subscriptions. Format is ``projects/{project-id}``. + + This corresponds to the ``project`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.pubsub_v1.services.subscriber.pagers.ListSubscriptionsPager: + Response for the ListSubscriptions method. + + Iterating over this object will yield results and + resolve additional pages automatically. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([project]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a pubsub.ListSubscriptionsRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, pubsub.ListSubscriptionsRequest): + request = pubsub.ListSubscriptionsRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if project is not None: + request.project = project + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.list_subscriptions] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("project", request.project),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # This method is paged; wrap the response in a pager, which provides + # an `__iter__` convenience method. + response = pagers.ListSubscriptionsPager( + method=rpc, + request=request, + response=response, + metadata=metadata, + ) + + # Done; return the response. + return response + + def delete_subscription( + self, + request: Union[pubsub.DeleteSubscriptionRequest, dict] = None, + *, + subscription: str = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + r"""Deletes an existing subscription. All messages retained in the + subscription are immediately dropped. Calls to ``Pull`` after + deletion will return ``NOT_FOUND``. After a subscription is + deleted, a new one may be created with the same name, but the + new one has no association with the old subscription or its + topic unless the same topic is specified. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + def sample_delete_subscription(): + # Create a client + client = pubsub_v1.SubscriberClient() + + # Initialize request argument(s) + request = pubsub_v1.DeleteSubscriptionRequest( + subscription="subscription_value", + ) + + # Make the request + client.delete_subscription(request=request) + + Args: + request (Union[google.pubsub_v1.types.DeleteSubscriptionRequest, dict]): + The request object. Request for the DeleteSubscription + method. + subscription (str): + Required. The subscription to delete. Format is + ``projects/{project}/subscriptions/{sub}``. + + This corresponds to the ``subscription`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([subscription]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a pubsub.DeleteSubscriptionRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, pubsub.DeleteSubscriptionRequest): + request = pubsub.DeleteSubscriptionRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if subscription is not None: + request.subscription = subscription + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.delete_subscription] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("subscription", request.subscription),) + ), + ) + + # Send the request. + rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + def modify_ack_deadline( + self, + request: Union[pubsub.ModifyAckDeadlineRequest, dict] = None, + *, + subscription: str = None, + ack_ids: Sequence[str] = None, + ack_deadline_seconds: int = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + r"""Modifies the ack deadline for a specific message. This method is + useful to indicate that more time is needed to process a message + by the subscriber, or to make the message available for + redelivery if the processing was interrupted. Note that this + does not modify the subscription-level ``ackDeadlineSeconds`` + used for subsequent messages. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + def sample_modify_ack_deadline(): + # Create a client + client = pubsub_v1.SubscriberClient() + + # Initialize request argument(s) + request = pubsub_v1.ModifyAckDeadlineRequest( + subscription="subscription_value", + ack_ids=['ack_ids_value1', 'ack_ids_value2'], + ack_deadline_seconds=2066, + ) + + # Make the request + client.modify_ack_deadline(request=request) + + Args: + request (Union[google.pubsub_v1.types.ModifyAckDeadlineRequest, dict]): + The request object. Request for the ModifyAckDeadline + method. + subscription (str): + Required. The name of the subscription. Format is + ``projects/{project}/subscriptions/{sub}``. + + This corresponds to the ``subscription`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + ack_ids (Sequence[str]): + Required. List of acknowledgment IDs. + This corresponds to the ``ack_ids`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + ack_deadline_seconds (int): + Required. The new ack deadline with respect to the time + this request was sent to the Pub/Sub system. For + example, if the value is 10, the new ack deadline will + expire 10 seconds after the ``ModifyAckDeadline`` call + was made. Specifying zero might immediately make the + message available for delivery to another subscriber + client. This typically results in an increase in the + rate of message redeliveries (that is, duplicates). The + minimum deadline you can specify is 0 seconds. The + maximum deadline you can specify is 600 seconds (10 + minutes). + + This corresponds to the ``ack_deadline_seconds`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([subscription, ack_ids, ack_deadline_seconds]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a pubsub.ModifyAckDeadlineRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, pubsub.ModifyAckDeadlineRequest): + request = pubsub.ModifyAckDeadlineRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if subscription is not None: + request.subscription = subscription + if ack_ids is not None: + request.ack_ids = ack_ids + if ack_deadline_seconds is not None: + request.ack_deadline_seconds = ack_deadline_seconds + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.modify_ack_deadline] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("subscription", request.subscription),) + ), + ) + + # Send the request. + rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + def acknowledge( + self, + request: Union[pubsub.AcknowledgeRequest, dict] = None, + *, + subscription: str = None, + ack_ids: Sequence[str] = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + r"""Acknowledges the messages associated with the ``ack_ids`` in the + ``AcknowledgeRequest``. The Pub/Sub system can remove the + relevant messages from the subscription. + + Acknowledging a message whose ack deadline has expired may + succeed, but such a message may be redelivered later. + Acknowledging a message more than once will not result in an + error. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + def sample_acknowledge(): + # Create a client + client = pubsub_v1.SubscriberClient() + + # Initialize request argument(s) + request = pubsub_v1.AcknowledgeRequest( + subscription="subscription_value", + ack_ids=['ack_ids_value1', 'ack_ids_value2'], + ) + + # Make the request + client.acknowledge(request=request) + + Args: + request (Union[google.pubsub_v1.types.AcknowledgeRequest, dict]): + The request object. Request for the Acknowledge method. + subscription (str): + Required. The subscription whose message is being + acknowledged. Format is + ``projects/{project}/subscriptions/{sub}``. + + This corresponds to the ``subscription`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + ack_ids (Sequence[str]): + Required. The acknowledgment ID for the messages being + acknowledged that was returned by the Pub/Sub system in + the ``Pull`` response. Must not be empty. + + This corresponds to the ``ack_ids`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([subscription, ack_ids]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a pubsub.AcknowledgeRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, pubsub.AcknowledgeRequest): + request = pubsub.AcknowledgeRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if subscription is not None: + request.subscription = subscription + if ack_ids is not None: + request.ack_ids = ack_ids + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.acknowledge] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("subscription", request.subscription),) + ), + ) + + # Send the request. + rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + def pull( + self, + request: Union[pubsub.PullRequest, dict] = None, + *, + subscription: str = None, + return_immediately: bool = None, + max_messages: int = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pubsub.PullResponse: + r"""Pulls messages from the server. The server may return + ``UNAVAILABLE`` if there are too many concurrent pull requests + pending for the given subscription. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + def sample_pull(): + # Create a client + client = pubsub_v1.SubscriberClient() + + # Initialize request argument(s) + request = pubsub_v1.PullRequest( + subscription="subscription_value", + max_messages=1277, + ) + + # Make the request + response = client.pull(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.pubsub_v1.types.PullRequest, dict]): + The request object. Request for the `Pull` method. + subscription (str): + Required. The subscription from which messages should be + pulled. Format is + ``projects/{project}/subscriptions/{sub}``. + + This corresponds to the ``subscription`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + return_immediately (bool): + Optional. If this field set to true, the system will + respond immediately even if it there are no messages + available to return in the ``Pull`` response. Otherwise, + the system may wait (for a bounded amount of time) until + at least one message is available, rather than returning + no messages. Warning: setting this field to ``true`` is + discouraged because it adversely impacts the performance + of ``Pull`` operations. We recommend that users do not + set this field. + + This corresponds to the ``return_immediately`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + max_messages (int): + Required. The maximum number of + messages to return for this request. + Must be a positive integer. The Pub/Sub + system may return fewer than the number + specified. + + This corresponds to the ``max_messages`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.pubsub_v1.types.PullResponse: + Response for the Pull method. + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([subscription, return_immediately, max_messages]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a pubsub.PullRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, pubsub.PullRequest): + request = pubsub.PullRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if subscription is not None: + request.subscription = subscription + if return_immediately is not None: + request.return_immediately = return_immediately + if max_messages is not None: + request.max_messages = max_messages + + if request.return_immediately: + warnings.warn( + "The return_immediately flag is deprecated and should be set to False.", + category=DeprecationWarning, + ) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.pull] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("subscription", request.subscription),) + ), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def streaming_pull( + self, + requests: Iterator[pubsub.StreamingPullRequest] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> Iterable[pubsub.StreamingPullResponse]: + r"""Establishes a stream with the server, which sends messages down + to the client. The client streams acknowledgements and ack + deadline modifications back to the server. The server will close + the stream and return the status on any error. The server may + close the stream with status ``UNAVAILABLE`` to reassign + server-side resources, in which case, the client should + re-establish the stream. Flow control can be achieved by + configuring the underlying RPC channel. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + def sample_streaming_pull(): + # Create a client + client = pubsub_v1.SubscriberClient() + + # Initialize request argument(s) + request = pubsub_v1.StreamingPullRequest( + subscription="subscription_value", + stream_ack_deadline_seconds=2813, + ) + + # This method expects an iterator which contains + # 'pubsub_v1.StreamingPullRequest' objects + # Here we create a generator that yields a single `request` for + # demonstrative purposes. + requests = [request] + + def request_generator(): + for request in requests: + yield request + + # Make the request + stream = client.streaming_pull(requests=request_generator()) + + # Handle the response + for response in stream: + print(response) + + Args: + requests (Iterator[google.pubsub_v1.types.StreamingPullRequest]): + The request object iterator. Request for the `StreamingPull` + streaming RPC method. This request is used to establish + the initial stream as well as to stream acknowledgements + and ack deadline modifications from the client to the + server. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + Iterable[google.pubsub_v1.types.StreamingPullResponse]: + Response for the StreamingPull method. This response is used to stream + messages from the server to the client. + + """ + + # Wrappers in api-core should not automatically pre-fetch the first + # stream result, as this breaks the stream when re-opening it. + # https://github.com/googleapis/python-pubsub/issues/93#issuecomment-630762257 + self._transport.streaming_pull._prefetch_first_result_ = False + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.streaming_pull] + + # Send the request. + response = rpc( + requests, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def modify_push_config( + self, + request: Union[pubsub.ModifyPushConfigRequest, dict] = None, + *, + subscription: str = None, + push_config: pubsub.PushConfig = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + r"""Modifies the ``PushConfig`` for a specified subscription. + + This may be used to change a push subscription to a pull one + (signified by an empty ``PushConfig``) or vice versa, or change + the endpoint URL and other attributes of a push subscription. + Messages will accumulate for delivery continuously through the + call regardless of changes to the ``PushConfig``. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + def sample_modify_push_config(): + # Create a client + client = pubsub_v1.SubscriberClient() + + # Initialize request argument(s) + request = pubsub_v1.ModifyPushConfigRequest( + subscription="subscription_value", + ) + + # Make the request + client.modify_push_config(request=request) + + Args: + request (Union[google.pubsub_v1.types.ModifyPushConfigRequest, dict]): + The request object. Request for the ModifyPushConfig + method. + subscription (str): + Required. The name of the subscription. Format is + ``projects/{project}/subscriptions/{sub}``. + + This corresponds to the ``subscription`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + push_config (google.pubsub_v1.types.PushConfig): + Required. The push configuration for future deliveries. + + An empty ``pushConfig`` indicates that the Pub/Sub + system should stop pushing messages from the given + subscription and allow messages to be pulled and + acknowledged - effectively pausing the subscription if + ``Pull`` or ``StreamingPull`` is not called. + + This corresponds to the ``push_config`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([subscription, push_config]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a pubsub.ModifyPushConfigRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, pubsub.ModifyPushConfigRequest): + request = pubsub.ModifyPushConfigRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if subscription is not None: + request.subscription = subscription + if push_config is not None: + request.push_config = push_config + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.modify_push_config] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("subscription", request.subscription),) + ), + ) + + # Send the request. + rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + def get_snapshot( + self, + request: Union[pubsub.GetSnapshotRequest, dict] = None, + *, + snapshot: str = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pubsub.Snapshot: + r"""Gets the configuration details of a snapshot. + Snapshots are used in Seek + operations, which allow you to manage message + acknowledgments in bulk. That is, you can set the + acknowledgment state of messages in an existing + subscription to the state captured by a snapshot. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + def sample_get_snapshot(): + # Create a client + client = pubsub_v1.SubscriberClient() + + # Initialize request argument(s) + request = pubsub_v1.GetSnapshotRequest( + snapshot="snapshot_value", + ) + + # Make the request + response = client.get_snapshot(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.pubsub_v1.types.GetSnapshotRequest, dict]): + The request object. Request for the GetSnapshot method. + snapshot (str): + Required. The name of the snapshot to get. Format is + ``projects/{project}/snapshots/{snap}``. + + This corresponds to the ``snapshot`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.pubsub_v1.types.Snapshot: + A snapshot resource. Snapshots are used in + [Seek](https://cloud.google.com/pubsub/docs/replay-overview) + operations, which allow you to manage message + acknowledgments in bulk. That is, you can set the + acknowledgment state of messages in an existing + subscription to the state captured by a snapshot. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([snapshot]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a pubsub.GetSnapshotRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, pubsub.GetSnapshotRequest): + request = pubsub.GetSnapshotRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if snapshot is not None: + request.snapshot = snapshot + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.get_snapshot] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("snapshot", request.snapshot),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def list_snapshots( + self, + request: Union[pubsub.ListSnapshotsRequest, dict] = None, + *, + project: str = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pagers.ListSnapshotsPager: + r"""Lists the existing snapshots. Snapshots are used in + `Seek `__ + operations, which allow you to manage message acknowledgments in + bulk. That is, you can set the acknowledgment state of messages + in an existing subscription to the state captured by a snapshot. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + def sample_list_snapshots(): + # Create a client + client = pubsub_v1.SubscriberClient() + + # Initialize request argument(s) + request = pubsub_v1.ListSnapshotsRequest( + project="project_value", + ) + + # Make the request + page_result = client.list_snapshots(request=request) + + # Handle the response + for response in page_result: + print(response) + + Args: + request (Union[google.pubsub_v1.types.ListSnapshotsRequest, dict]): + The request object. Request for the `ListSnapshots` + method. + project (str): + Required. The name of the project in which to list + snapshots. Format is ``projects/{project-id}``. + + This corresponds to the ``project`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.pubsub_v1.services.subscriber.pagers.ListSnapshotsPager: + Response for the ListSnapshots method. + + Iterating over this object will yield results and + resolve additional pages automatically. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([project]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a pubsub.ListSnapshotsRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, pubsub.ListSnapshotsRequest): + request = pubsub.ListSnapshotsRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if project is not None: + request.project = project + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.list_snapshots] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("project", request.project),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # This method is paged; wrap the response in a pager, which provides + # an `__iter__` convenience method. + response = pagers.ListSnapshotsPager( + method=rpc, + request=request, + response=response, + metadata=metadata, + ) + + # Done; return the response. + return response + + def create_snapshot( + self, + request: Union[pubsub.CreateSnapshotRequest, dict] = None, + *, + name: str = None, + subscription: str = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pubsub.Snapshot: + r"""Creates a snapshot from the requested subscription. Snapshots + are used in + `Seek `__ + operations, which allow you to manage message acknowledgments in + bulk. That is, you can set the acknowledgment state of messages + in an existing subscription to the state captured by a snapshot. + If the snapshot already exists, returns ``ALREADY_EXISTS``. If + the requested subscription doesn't exist, returns ``NOT_FOUND``. + If the backlog in the subscription is too old -- and the + resulting snapshot would expire in less than 1 hour -- then + ``FAILED_PRECONDITION`` is returned. See also the + ``Snapshot.expire_time`` field. If the name is not provided in + the request, the server will assign a random name for this + snapshot on the same project as the subscription, conforming to + the [resource name format] + (https://cloud.google.com/pubsub/docs/admin#resource_names). The + generated name is populated in the returned Snapshot object. + Note that for REST API requests, you must specify a name in the + request. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + def sample_create_snapshot(): + # Create a client + client = pubsub_v1.SubscriberClient() + + # Initialize request argument(s) + request = pubsub_v1.CreateSnapshotRequest( + name="name_value", + subscription="subscription_value", + ) + + # Make the request + response = client.create_snapshot(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.pubsub_v1.types.CreateSnapshotRequest, dict]): + The request object. Request for the `CreateSnapshot` + method. + name (str): + Required. User-provided name for this snapshot. If the + name is not provided in the request, the server will + assign a random name for this snapshot on the same + project as the subscription. Note that for REST API + requests, you must specify a name. See the resource name + rules. Format is + ``projects/{project}/snapshots/{snap}``. + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + subscription (str): + Required. The subscription whose backlog the snapshot + retains. Specifically, the created snapshot is + guaranteed to retain: (a) The existing backlog on the + subscription. More precisely, this is defined as the + messages in the subscription's backlog that are + unacknowledged upon the successful completion of the + ``CreateSnapshot`` request; as well as: (b) Any messages + published to the subscription's topic following the + successful completion of the CreateSnapshot request. + Format is ``projects/{project}/subscriptions/{sub}``. + + This corresponds to the ``subscription`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.pubsub_v1.types.Snapshot: + A snapshot resource. Snapshots are used in + [Seek](https://cloud.google.com/pubsub/docs/replay-overview) + operations, which allow you to manage message + acknowledgments in bulk. That is, you can set the + acknowledgment state of messages in an existing + subscription to the state captured by a snapshot. + + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name, subscription]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a pubsub.CreateSnapshotRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, pubsub.CreateSnapshotRequest): + request = pubsub.CreateSnapshotRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if name is not None: + request.name = name + if subscription is not None: + request.subscription = subscription + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.create_snapshot] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def update_snapshot( + self, + request: Union[pubsub.UpdateSnapshotRequest, dict] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pubsub.Snapshot: + r"""Updates an existing snapshot. Snapshots are used in + Seek + operations, which allow + you to manage message acknowledgments in bulk. That is, + you can set the acknowledgment state of messages in an + existing subscription to the state captured by a + snapshot. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + def sample_update_snapshot(): + # Create a client + client = pubsub_v1.SubscriberClient() + + # Initialize request argument(s) + request = pubsub_v1.UpdateSnapshotRequest( + ) + + # Make the request + response = client.update_snapshot(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.pubsub_v1.types.UpdateSnapshotRequest, dict]): + The request object. Request for the UpdateSnapshot + method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.pubsub_v1.types.Snapshot: + A snapshot resource. Snapshots are used in + [Seek](https://cloud.google.com/pubsub/docs/replay-overview) + operations, which allow you to manage message + acknowledgments in bulk. That is, you can set the + acknowledgment state of messages in an existing + subscription to the state captured by a snapshot. + + """ + # Create or coerce a protobuf request object. + # Minor optimization to avoid making a copy if the user passes + # in a pubsub.UpdateSnapshotRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, pubsub.UpdateSnapshotRequest): + request = pubsub.UpdateSnapshotRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.update_snapshot] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("snapshot.name", request.snapshot.name),) + ), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def delete_snapshot( + self, + request: Union[pubsub.DeleteSnapshotRequest, dict] = None, + *, + snapshot: str = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> None: + r"""Removes an existing snapshot. Snapshots are used in [Seek] + (https://cloud.google.com/pubsub/docs/replay-overview) + operations, which allow you to manage message acknowledgments in + bulk. That is, you can set the acknowledgment state of messages + in an existing subscription to the state captured by a snapshot. + When the snapshot is deleted, all messages retained in the + snapshot are immediately dropped. After a snapshot is deleted, a + new one may be created with the same name, but the new one has + no association with the old snapshot or its subscription, unless + the same subscription is specified. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + def sample_delete_snapshot(): + # Create a client + client = pubsub_v1.SubscriberClient() + + # Initialize request argument(s) + request = pubsub_v1.DeleteSnapshotRequest( + snapshot="snapshot_value", + ) + + # Make the request + client.delete_snapshot(request=request) + + Args: + request (Union[google.pubsub_v1.types.DeleteSnapshotRequest, dict]): + The request object. Request for the `DeleteSnapshot` + method. + snapshot (str): + Required. The name of the snapshot to delete. Format is + ``projects/{project}/snapshots/{snap}``. + + This corresponds to the ``snapshot`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + # Create or coerce a protobuf request object. + # Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([snapshot]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # Minor optimization to avoid making a copy if the user passes + # in a pubsub.DeleteSnapshotRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, pubsub.DeleteSnapshotRequest): + request = pubsub.DeleteSnapshotRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if snapshot is not None: + request.snapshot = snapshot + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.delete_snapshot] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("snapshot", request.snapshot),)), + ) + + # Send the request. + rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + def seek( + self, + request: Union[pubsub.SeekRequest, dict] = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> pubsub.SeekResponse: + r"""Seeks an existing subscription to a point in time or to a given + snapshot, whichever is provided in the request. Snapshots are + used in [Seek] + (https://cloud.google.com/pubsub/docs/replay-overview) + operations, which allow you to manage message acknowledgments in + bulk. That is, you can set the acknowledgment state of messages + in an existing subscription to the state captured by a snapshot. + Note that both the subscription and the snapshot must be on the + same topic. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google import pubsub_v1 + + def sample_seek(): + # Create a client + client = pubsub_v1.SubscriberClient() + + # Initialize request argument(s) + request = pubsub_v1.SeekRequest( + subscription="subscription_value", + ) + + # Make the request + response = client.seek(request=request) + + # Handle the response + print(response) + + Args: + request (Union[google.pubsub_v1.types.SeekRequest, dict]): + The request object. Request for the `Seek` method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.pubsub_v1.types.SeekResponse: + Response for the Seek method (this response is empty). + """ + # Create or coerce a protobuf request object. + # Minor optimization to avoid making a copy if the user passes + # in a pubsub.SeekRequest. + # There's no risk of modifying the input as we've already verified + # there are no flattened fields. + if not isinstance(request, pubsub.SeekRequest): + request = pubsub.SeekRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.seek] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("subscription", request.subscription),) + ), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def __enter__(self): + return self + + def __exit__(self, type, value, traceback): + """Releases underlying transport's resources. + + .. warning:: + ONLY use as a context manager if the transport is NOT shared + with other clients! Exiting the with block will CLOSE the transport + and may cause errors in other clients! + """ + self.transport.close() + + def set_iam_policy( + self, + request: iam_policy_pb2.SetIamPolicyRequest = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> policy_pb2.Policy: + r"""Sets the IAM access control policy on the specified function. + + Replaces any existing policy. + + Args: + request (:class:`~.iam_policy_pb2.SetIamPolicyRequest`): + The request object. Request message for `SetIamPolicy` + method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~.policy_pb2.Policy: + Defines an Identity and Access Management (IAM) policy. + It is used to specify access control policies for Cloud + Platform resources. + A ``Policy`` is a collection of ``bindings``. A + ``binding`` binds one or more ``members`` to a single + ``role``. Members can be user accounts, service + accounts, Google groups, and domains (such as G Suite). + A ``role`` is a named list of permissions (defined by + IAM or configured by users). A ``binding`` can + optionally specify a ``condition``, which is a logic + expression that further constrains the role binding + based on attributes about the request and/or target + resource. + + **JSON Example** + + :: + + { + "bindings": [ + { + "role": "roles/resourcemanager.organizationAdmin", + "members": [ + "user:mike@example.com", + "group:admins@example.com", + "domain:google.com", + "serviceAccount:my-project-id@appspot.gserviceaccount.com" + ] + }, + { + "role": "roles/resourcemanager.organizationViewer", + "members": ["user:eve@example.com"], + "condition": { + "title": "expirable access", + "description": "Does not grant access after Sep 2020", + "expression": "request.time < + timestamp('2020-10-01T00:00:00.000Z')", + } + } + ] + } + + **YAML Example** + + :: + + bindings: + - members: + - user:mike@example.com + - group:admins@example.com + - domain:google.com + - serviceAccount:my-project-id@appspot.gserviceaccount.com + role: roles/resourcemanager.organizationAdmin + - members: + - user:eve@example.com + role: roles/resourcemanager.organizationViewer + condition: + title: expirable access + description: Does not grant access after Sep 2020 + expression: request.time < timestamp('2020-10-01T00:00:00.000Z') + + For a description of IAM and its features, see the `IAM + developer's + guide `__. + """ + # Create or coerce a protobuf request object. + + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = iam_policy_pb2.SetIamPolicyRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._transport.set_iam_policy, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("resource", request.resource),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def get_iam_policy( + self, + request: iam_policy_pb2.GetIamPolicyRequest = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> policy_pb2.Policy: + r"""Gets the IAM access control policy for a function. + + Returns an empty policy if the function exists and does not have a + policy set. + + Args: + request (:class:`~.iam_policy_pb2.GetIamPolicyRequest`): + The request object. Request message for `GetIamPolicy` + method. + retry (google.api_core.retry.Retry): Designation of what errors, if + any, should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~.policy_pb2.Policy: + Defines an Identity and Access Management (IAM) policy. + It is used to specify access control policies for Cloud + Platform resources. + A ``Policy`` is a collection of ``bindings``. A + ``binding`` binds one or more ``members`` to a single + ``role``. Members can be user accounts, service + accounts, Google groups, and domains (such as G Suite). + A ``role`` is a named list of permissions (defined by + IAM or configured by users). A ``binding`` can + optionally specify a ``condition``, which is a logic + expression that further constrains the role binding + based on attributes about the request and/or target + resource. + + **JSON Example** + + :: + + { + "bindings": [ + { + "role": "roles/resourcemanager.organizationAdmin", + "members": [ + "user:mike@example.com", + "group:admins@example.com", + "domain:google.com", + "serviceAccount:my-project-id@appspot.gserviceaccount.com" + ] + }, + { + "role": "roles/resourcemanager.organizationViewer", + "members": ["user:eve@example.com"], + "condition": { + "title": "expirable access", + "description": "Does not grant access after Sep 2020", + "expression": "request.time < + timestamp('2020-10-01T00:00:00.000Z')", + } + } + ] + } + + **YAML Example** + + :: + + bindings: + - members: + - user:mike@example.com + - group:admins@example.com + - domain:google.com + - serviceAccount:my-project-id@appspot.gserviceaccount.com + role: roles/resourcemanager.organizationAdmin + - members: + - user:eve@example.com + role: roles/resourcemanager.organizationViewer + condition: + title: expirable access + description: Does not grant access after Sep 2020 + expression: request.time < timestamp('2020-10-01T00:00:00.000Z') + + For a description of IAM and its features, see the `IAM + developer's + guide `__. + """ + # Create or coerce a protobuf request object. + + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = iam_policy_pb2.GetIamPolicyRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._transport.get_iam_policy, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("resource", request.resource),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + def test_iam_permissions( + self, + request: iam_policy_pb2.TestIamPermissionsRequest = None, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> iam_policy_pb2.TestIamPermissionsResponse: + r"""Tests the specified IAM permissions against the IAM access control + policy for a function. + + If the function does not exist, this will return an empty set + of permissions, not a NOT_FOUND error. + + Args: + request (:class:`~.iam_policy_pb2.TestIamPermissionsRequest`): + The request object. Request message for + `TestIamPermissions` method. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + Returns: + ~.iam_policy_pb2.TestIamPermissionsResponse: + Response message for ``TestIamPermissions`` method. + """ + # Create or coerce a protobuf request object. + + # The request isn't a proto-plus wrapped type, + # so it must be constructed via keyword expansion. + if isinstance(request, dict): + request = iam_policy_pb2.TestIamPermissionsRequest(**request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._transport.test_iam_permissions, + default_timeout=None, + client_info=DEFAULT_CLIENT_INFO, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("resource", request.resource),)), + ) + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Done; return the response. + return response + + +try: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + client_library_version=pkg_resources.get_distribution( + "google-cloud-pubsub", + ).version, + ) +except pkg_resources.DistributionNotFound: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() + + +__all__ = ("SubscriberClient",) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/pagers.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/pagers.py new file mode 100644 index 000000000000..cb3896bb59fa --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/pagers.py @@ -0,0 +1,283 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +from typing import ( + Any, + AsyncIterator, + Awaitable, + Callable, + Sequence, + Tuple, + Optional, + Iterator, +) + +from google.pubsub_v1.types import pubsub + + +class ListSubscriptionsPager: + """A pager for iterating through ``list_subscriptions`` requests. + + This class thinly wraps an initial + :class:`google.pubsub_v1.types.ListSubscriptionsResponse` object, and + provides an ``__iter__`` method to iterate through its + ``subscriptions`` field. + + If there are more pages, the ``__iter__`` method will make additional + ``ListSubscriptions`` requests and continue to iterate + through the ``subscriptions`` field on the + corresponding responses. + + All the usual :class:`google.pubsub_v1.types.ListSubscriptionsResponse` + attributes are available on the pager. If multiple requests are made, only + the most recent response is retained, and thus used for attribute lookup. + """ + + def __init__( + self, + method: Callable[..., pubsub.ListSubscriptionsResponse], + request: pubsub.ListSubscriptionsRequest, + response: pubsub.ListSubscriptionsResponse, + *, + metadata: Sequence[Tuple[str, str]] = () + ): + """Instantiate the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.pubsub_v1.types.ListSubscriptionsRequest): + The initial request object. + response (google.pubsub_v1.types.ListSubscriptionsResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = pubsub.ListSubscriptionsRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + def pages(self) -> Iterator[pubsub.ListSubscriptionsResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = self._method(self._request, metadata=self._metadata) + yield self._response + + def __iter__(self) -> Iterator[pubsub.Subscription]: + for page in self.pages: + yield from page.subscriptions + + def __repr__(self) -> str: + return "{0}<{1!r}>".format(self.__class__.__name__, self._response) + + +class ListSubscriptionsAsyncPager: + """A pager for iterating through ``list_subscriptions`` requests. + + This class thinly wraps an initial + :class:`google.pubsub_v1.types.ListSubscriptionsResponse` object, and + provides an ``__aiter__`` method to iterate through its + ``subscriptions`` field. + + If there are more pages, the ``__aiter__`` method will make additional + ``ListSubscriptions`` requests and continue to iterate + through the ``subscriptions`` field on the + corresponding responses. + + All the usual :class:`google.pubsub_v1.types.ListSubscriptionsResponse` + attributes are available on the pager. If multiple requests are made, only + the most recent response is retained, and thus used for attribute lookup. + """ + + def __init__( + self, + method: Callable[..., Awaitable[pubsub.ListSubscriptionsResponse]], + request: pubsub.ListSubscriptionsRequest, + response: pubsub.ListSubscriptionsResponse, + *, + metadata: Sequence[Tuple[str, str]] = () + ): + """Instantiates the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.pubsub_v1.types.ListSubscriptionsRequest): + The initial request object. + response (google.pubsub_v1.types.ListSubscriptionsResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = pubsub.ListSubscriptionsRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + async def pages(self) -> AsyncIterator[pubsub.ListSubscriptionsResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = await self._method(self._request, metadata=self._metadata) + yield self._response + + def __aiter__(self) -> AsyncIterator[pubsub.Subscription]: + async def async_generator(): + async for page in self.pages: + for response in page.subscriptions: + yield response + + return async_generator() + + def __repr__(self) -> str: + return "{0}<{1!r}>".format(self.__class__.__name__, self._response) + + +class ListSnapshotsPager: + """A pager for iterating through ``list_snapshots`` requests. + + This class thinly wraps an initial + :class:`google.pubsub_v1.types.ListSnapshotsResponse` object, and + provides an ``__iter__`` method to iterate through its + ``snapshots`` field. + + If there are more pages, the ``__iter__`` method will make additional + ``ListSnapshots`` requests and continue to iterate + through the ``snapshots`` field on the + corresponding responses. + + All the usual :class:`google.pubsub_v1.types.ListSnapshotsResponse` + attributes are available on the pager. If multiple requests are made, only + the most recent response is retained, and thus used for attribute lookup. + """ + + def __init__( + self, + method: Callable[..., pubsub.ListSnapshotsResponse], + request: pubsub.ListSnapshotsRequest, + response: pubsub.ListSnapshotsResponse, + *, + metadata: Sequence[Tuple[str, str]] = () + ): + """Instantiate the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.pubsub_v1.types.ListSnapshotsRequest): + The initial request object. + response (google.pubsub_v1.types.ListSnapshotsResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = pubsub.ListSnapshotsRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + def pages(self) -> Iterator[pubsub.ListSnapshotsResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = self._method(self._request, metadata=self._metadata) + yield self._response + + def __iter__(self) -> Iterator[pubsub.Snapshot]: + for page in self.pages: + yield from page.snapshots + + def __repr__(self) -> str: + return "{0}<{1!r}>".format(self.__class__.__name__, self._response) + + +class ListSnapshotsAsyncPager: + """A pager for iterating through ``list_snapshots`` requests. + + This class thinly wraps an initial + :class:`google.pubsub_v1.types.ListSnapshotsResponse` object, and + provides an ``__aiter__`` method to iterate through its + ``snapshots`` field. + + If there are more pages, the ``__aiter__`` method will make additional + ``ListSnapshots`` requests and continue to iterate + through the ``snapshots`` field on the + corresponding responses. + + All the usual :class:`google.pubsub_v1.types.ListSnapshotsResponse` + attributes are available on the pager. If multiple requests are made, only + the most recent response is retained, and thus used for attribute lookup. + """ + + def __init__( + self, + method: Callable[..., Awaitable[pubsub.ListSnapshotsResponse]], + request: pubsub.ListSnapshotsRequest, + response: pubsub.ListSnapshotsResponse, + *, + metadata: Sequence[Tuple[str, str]] = () + ): + """Instantiates the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (google.pubsub_v1.types.ListSnapshotsRequest): + The initial request object. + response (google.pubsub_v1.types.ListSnapshotsResponse): + The initial response object. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + """ + self._method = method + self._request = pubsub.ListSnapshotsRequest(request) + self._response = response + self._metadata = metadata + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + @property + async def pages(self) -> AsyncIterator[pubsub.ListSnapshotsResponse]: + yield self._response + while self._response.next_page_token: + self._request.page_token = self._response.next_page_token + self._response = await self._method(self._request, metadata=self._metadata) + yield self._response + + def __aiter__(self) -> AsyncIterator[pubsub.Snapshot]: + async def async_generator(): + async for page in self.pages: + for response in page.snapshots: + yield response + + return async_generator() + + def __repr__(self) -> str: + return "{0}<{1!r}>".format(self.__class__.__name__, self._response) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/transports/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/transports/__init__.py new file mode 100644 index 000000000000..f71cdecd4a4c --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/transports/__init__.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +from collections import OrderedDict +from typing import Dict, Type + +from .base import SubscriberTransport +from .grpc import SubscriberGrpcTransport +from .grpc_asyncio import SubscriberGrpcAsyncIOTransport + + +# Compile a registry of transports. +_transport_registry = OrderedDict() # type: Dict[str, Type[SubscriberTransport]] +_transport_registry["grpc"] = SubscriberGrpcTransport +_transport_registry["grpc_asyncio"] = SubscriberGrpcAsyncIOTransport + +__all__ = ( + "SubscriberTransport", + "SubscriberGrpcTransport", + "SubscriberGrpcAsyncIOTransport", +) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/transports/base.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/transports/base.py new file mode 100644 index 000000000000..0d815e06890a --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/transports/base.py @@ -0,0 +1,567 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +import abc +from typing import Awaitable, Callable, Dict, Optional, Sequence, Union +import pkg_resources + +import google.auth # type: ignore +import google.api_core +from google.api_core import exceptions as core_exceptions +from google.api_core import gapic_v1 +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials # type: ignore +from google.oauth2 import service_account # type: ignore + +from google.iam.v1 import iam_policy_pb2 # type: ignore +from google.iam.v1 import policy_pb2 # type: ignore +from google.protobuf import empty_pb2 # type: ignore +from google.pubsub_v1.types import pubsub + +try: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( + client_library_version=pkg_resources.get_distribution( + "google-cloud-pubsub", + ).version, + ) +except pkg_resources.DistributionNotFound: + DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo() + + +class SubscriberTransport(abc.ABC): + """Abstract transport class for Subscriber.""" + + AUTH_SCOPES = ( + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/pubsub", + ) + + DEFAULT_HOST: str = "pubsub.googleapis.com" + + def __init__( + self, + *, + host: str = DEFAULT_HOST, + credentials: ga_credentials.Credentials = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + api_audience: Optional[str] = None, + **kwargs, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is mutually exclusive with credentials. + scopes (Optional[Sequence[str]]): A list of scopes. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + """ + + scopes_kwargs = {"scopes": scopes, "default_scopes": self.AUTH_SCOPES} + + # Save the scopes. + self._scopes = scopes + + # If no credentials are provided, then determine the appropriate + # defaults. + if credentials and credentials_file: + raise core_exceptions.DuplicateCredentialArgs( + "'credentials_file' and 'credentials' are mutually exclusive" + ) + + if credentials_file is not None: + credentials, _ = google.auth.load_credentials_from_file( + credentials_file, **scopes_kwargs, quota_project_id=quota_project_id + ) + elif credentials is None: + credentials, _ = google.auth.default( + **scopes_kwargs, quota_project_id=quota_project_id + ) + # Don't apply audience if the credentials file passed from user. + if hasattr(credentials, "with_gdch_audience"): + credentials = credentials.with_gdch_audience( + api_audience if api_audience else host + ) + + # If the credentials are service account credentials, then always try to use self signed JWT. + if ( + always_use_jwt_access + and isinstance(credentials, service_account.Credentials) + and hasattr(service_account.Credentials, "with_always_use_jwt_access") + ): + credentials = credentials.with_always_use_jwt_access(True) + + # Save the credentials. + self._credentials = credentials + + # Save the hostname. Default to port 443 (HTTPS) if none is specified. + if ":" not in host: + host += ":443" + self._host = host + + def _prep_wrapped_messages(self, client_info): + # Precompute the wrapped methods. + self._wrapped_methods = { + self.create_subscription: gapic_v1.method.wrap_method( + self.create_subscription, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.Aborted, + core_exceptions.ServiceUnavailable, + core_exceptions.Unknown, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=client_info, + ), + self.get_subscription: gapic_v1.method.wrap_method( + self.get_subscription, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.Aborted, + core_exceptions.ServiceUnavailable, + core_exceptions.Unknown, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=client_info, + ), + self.update_subscription: gapic_v1.method.wrap_method( + self.update_subscription, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=client_info, + ), + self.list_subscriptions: gapic_v1.method.wrap_method( + self.list_subscriptions, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.Aborted, + core_exceptions.ServiceUnavailable, + core_exceptions.Unknown, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=client_info, + ), + self.delete_subscription: gapic_v1.method.wrap_method( + self.delete_subscription, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=client_info, + ), + self.modify_ack_deadline: gapic_v1.method.wrap_method( + self.modify_ack_deadline, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=client_info, + ), + self.acknowledge: gapic_v1.method.wrap_method( + self.acknowledge, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=client_info, + ), + self.pull: gapic_v1.method.wrap_method( + self.pull, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.Aborted, + core_exceptions.ServiceUnavailable, + core_exceptions.Unknown, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=client_info, + ), + self.streaming_pull: gapic_v1.method.wrap_method( + self.streaming_pull, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.Aborted, + core_exceptions.DeadlineExceeded, + core_exceptions.InternalServerError, + core_exceptions.ResourceExhausted, + core_exceptions.ServiceUnavailable, + ), + deadline=900.0, + ), + default_timeout=900.0, + client_info=client_info, + ), + self.modify_push_config: gapic_v1.method.wrap_method( + self.modify_push_config, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=client_info, + ), + self.get_snapshot: gapic_v1.method.wrap_method( + self.get_snapshot, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.Aborted, + core_exceptions.ServiceUnavailable, + core_exceptions.Unknown, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=client_info, + ), + self.list_snapshots: gapic_v1.method.wrap_method( + self.list_snapshots, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.Aborted, + core_exceptions.ServiceUnavailable, + core_exceptions.Unknown, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=client_info, + ), + self.create_snapshot: gapic_v1.method.wrap_method( + self.create_snapshot, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=client_info, + ), + self.update_snapshot: gapic_v1.method.wrap_method( + self.update_snapshot, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=client_info, + ), + self.delete_snapshot: gapic_v1.method.wrap_method( + self.delete_snapshot, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=client_info, + ), + self.seek: gapic_v1.method.wrap_method( + self.seek, + default_retry=retries.Retry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.Aborted, + core_exceptions.ServiceUnavailable, + core_exceptions.Unknown, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=client_info, + ), + } + + def close(self): + """Closes resources associated with the transport. + + .. warning:: + Only call this method if the transport is NOT shared + with other clients - this may cause errors in other clients! + """ + raise NotImplementedError() + + @property + def create_subscription( + self, + ) -> Callable[ + [pubsub.Subscription], + Union[pubsub.Subscription, Awaitable[pubsub.Subscription]], + ]: + raise NotImplementedError() + + @property + def get_subscription( + self, + ) -> Callable[ + [pubsub.GetSubscriptionRequest], + Union[pubsub.Subscription, Awaitable[pubsub.Subscription]], + ]: + raise NotImplementedError() + + @property + def update_subscription( + self, + ) -> Callable[ + [pubsub.UpdateSubscriptionRequest], + Union[pubsub.Subscription, Awaitable[pubsub.Subscription]], + ]: + raise NotImplementedError() + + @property + def list_subscriptions( + self, + ) -> Callable[ + [pubsub.ListSubscriptionsRequest], + Union[ + pubsub.ListSubscriptionsResponse, + Awaitable[pubsub.ListSubscriptionsResponse], + ], + ]: + raise NotImplementedError() + + @property + def delete_subscription( + self, + ) -> Callable[ + [pubsub.DeleteSubscriptionRequest], + Union[empty_pb2.Empty, Awaitable[empty_pb2.Empty]], + ]: + raise NotImplementedError() + + @property + def modify_ack_deadline( + self, + ) -> Callable[ + [pubsub.ModifyAckDeadlineRequest], + Union[empty_pb2.Empty, Awaitable[empty_pb2.Empty]], + ]: + raise NotImplementedError() + + @property + def acknowledge( + self, + ) -> Callable[ + [pubsub.AcknowledgeRequest], Union[empty_pb2.Empty, Awaitable[empty_pb2.Empty]] + ]: + raise NotImplementedError() + + @property + def pull( + self, + ) -> Callable[ + [pubsub.PullRequest], Union[pubsub.PullResponse, Awaitable[pubsub.PullResponse]] + ]: + raise NotImplementedError() + + @property + def streaming_pull( + self, + ) -> Callable[ + [pubsub.StreamingPullRequest], + Union[pubsub.StreamingPullResponse, Awaitable[pubsub.StreamingPullResponse]], + ]: + raise NotImplementedError() + + @property + def modify_push_config( + self, + ) -> Callable[ + [pubsub.ModifyPushConfigRequest], + Union[empty_pb2.Empty, Awaitable[empty_pb2.Empty]], + ]: + raise NotImplementedError() + + @property + def get_snapshot( + self, + ) -> Callable[ + [pubsub.GetSnapshotRequest], Union[pubsub.Snapshot, Awaitable[pubsub.Snapshot]] + ]: + raise NotImplementedError() + + @property + def list_snapshots( + self, + ) -> Callable[ + [pubsub.ListSnapshotsRequest], + Union[pubsub.ListSnapshotsResponse, Awaitable[pubsub.ListSnapshotsResponse]], + ]: + raise NotImplementedError() + + @property + def create_snapshot( + self, + ) -> Callable[ + [pubsub.CreateSnapshotRequest], + Union[pubsub.Snapshot, Awaitable[pubsub.Snapshot]], + ]: + raise NotImplementedError() + + @property + def update_snapshot( + self, + ) -> Callable[ + [pubsub.UpdateSnapshotRequest], + Union[pubsub.Snapshot, Awaitable[pubsub.Snapshot]], + ]: + raise NotImplementedError() + + @property + def delete_snapshot( + self, + ) -> Callable[ + [pubsub.DeleteSnapshotRequest], + Union[empty_pb2.Empty, Awaitable[empty_pb2.Empty]], + ]: + raise NotImplementedError() + + @property + def seek( + self, + ) -> Callable[ + [pubsub.SeekRequest], Union[pubsub.SeekResponse, Awaitable[pubsub.SeekResponse]] + ]: + raise NotImplementedError() + + @property + def set_iam_policy( + self, + ) -> Callable[ + [iam_policy_pb2.SetIamPolicyRequest], + Union[policy_pb2.Policy, Awaitable[policy_pb2.Policy]], + ]: + raise NotImplementedError() + + @property + def get_iam_policy( + self, + ) -> Callable[ + [iam_policy_pb2.GetIamPolicyRequest], + Union[policy_pb2.Policy, Awaitable[policy_pb2.Policy]], + ]: + raise NotImplementedError() + + @property + def test_iam_permissions( + self, + ) -> Callable[ + [iam_policy_pb2.TestIamPermissionsRequest], + Union[ + iam_policy_pb2.TestIamPermissionsResponse, + Awaitable[iam_policy_pb2.TestIamPermissionsResponse], + ], + ]: + raise NotImplementedError() + + @property + def kind(self) -> str: + raise NotImplementedError() + + +__all__ = ("SubscriberTransport",) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/transports/grpc.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/transports/grpc.py new file mode 100644 index 000000000000..5954b6403343 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/transports/grpc.py @@ -0,0 +1,834 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +import warnings +from typing import Callable, Dict, Optional, Sequence, Tuple, Union + +from google.api_core import grpc_helpers +from google.api_core import gapic_v1 +import google.auth # type: ignore +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore + +import grpc # type: ignore + +from google.iam.v1 import iam_policy_pb2 # type: ignore +from google.iam.v1 import policy_pb2 # type: ignore +from google.protobuf import empty_pb2 # type: ignore +from google.pubsub_v1.types import pubsub +from .base import SubscriberTransport, DEFAULT_CLIENT_INFO + + +class SubscriberGrpcTransport(SubscriberTransport): + """gRPC backend transport for Subscriber. + + The service that an application uses to manipulate subscriptions and + to consume messages from a subscription via the ``Pull`` method or + by establishing a bi-directional stream using the ``StreamingPull`` + method. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends protocol buffers over the wire using gRPC (which is built on + top of HTTP/2); the ``grpcio`` package must be installed. + """ + + _stubs: Dict[str, Callable] + + def __init__( + self, + *, + host: str = "pubsub.googleapis.com", + credentials: ga_credentials.Credentials = None, + credentials_file: str = None, + scopes: Sequence[str] = None, + channel: grpc.Channel = None, + api_mtls_endpoint: str = None, + client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, + ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, + quota_project_id: Optional[str] = None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + This argument is ignored if ``channel`` is provided. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional(Sequence[str])): A list of scopes. This argument is + ignored if ``channel`` is provided. + channel (Optional[grpc.Channel]): A ``Channel`` instance through + which to make calls. + api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. + If provided, it overrides the ``host`` argument and tries to create + a mutual TLS channel with client SSL credentials from + ``client_cert_source`` or application default SSL credentials. + client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): + Deprecated. A callback to provide client SSL certificate bytes and + private key bytes, both in PEM format. It is ignored if + ``api_mtls_endpoint`` is None. + ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials + for the grpc channel. It is ignored if ``channel`` is provided. + client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): + A callback to provide client certificate bytes and private key bytes, + both in PEM format. It is used to configure a mutual TLS channel. It is + ignored if ``channel`` or ``ssl_channel_credentials`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + + Raises: + google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport + creation failed for any reason. + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + self._grpc_channel = None + self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} + + if api_mtls_endpoint: + warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning) + if client_cert_source: + warnings.warn("client_cert_source is deprecated", DeprecationWarning) + + if channel: + # Ignore credentials if a channel was passed. + credentials = False + # If a channel was explicitly provided, set it. + self._grpc_channel = channel + self._ssl_channel_credentials = None + + else: + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials + + else: + if client_cert_source_for_mtls and not ssl_channel_credentials: + cert, key = client_cert_source_for_mtls() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + + # The base transport sets the host, credentials and scopes + super().__init__( + host=host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + + if not self._grpc_channel: + self._grpc_channel = type(self).create_channel( + self._host, + # use the credentials which are saved + credentials=self._credentials, + # Set ``credentials_file`` to ``None`` here as + # the credentials that we saved earlier should be used. + credentials_file=None, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, + quota_project_id=quota_project_id, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ("grpc.max_metadata_size", 4 * 1024 * 1024), + ("grpc.keepalive_time_ms", 30000), + ], + ) + + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) + + @classmethod + def create_channel( + cls, + host: str = "pubsub.googleapis.com", + credentials: ga_credentials.Credentials = None, + credentials_file: str = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + **kwargs, + ) -> grpc.Channel: + """Create and return a gRPC channel object. + Args: + host (Optional[str]): The host for the channel to use. + credentials (Optional[~.Credentials]): The + authorization credentials to attach to requests. These + credentials identify this application to the service. If + none are specified, the client will attempt to ascertain + the credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is mutually exclusive with credentials. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + kwargs (Optional[dict]): Keyword arguments, which are passed to the + channel creation. + Returns: + grpc.Channel: A gRPC channel object. + + Raises: + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + + return grpc_helpers.create_channel( + host, + credentials=credentials, + credentials_file=credentials_file, + quota_project_id=quota_project_id, + default_scopes=cls.AUTH_SCOPES, + scopes=scopes, + default_host=cls.DEFAULT_HOST, + **kwargs, + ) + + @property + def grpc_channel(self) -> grpc.Channel: + """Return the channel designed to connect to this service.""" + return self._grpc_channel + + @property + def create_subscription( + self, + ) -> Callable[[pubsub.Subscription], pubsub.Subscription]: + r"""Return a callable for the create subscription method over gRPC. + + Creates a subscription to a given topic. See the [resource name + rules] + (https://cloud.google.com/pubsub/docs/admin#resource_names). If + the subscription already exists, returns ``ALREADY_EXISTS``. If + the corresponding topic doesn't exist, returns ``NOT_FOUND``. + + If the name is not provided in the request, the server will + assign a random name for this subscription on the same project + as the topic, conforming to the [resource name format] + (https://cloud.google.com/pubsub/docs/admin#resource_names). The + generated name is populated in the returned Subscription object. + Note that for REST API requests, you must specify a name in the + request. + + Returns: + Callable[[~.Subscription], + ~.Subscription]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "create_subscription" not in self._stubs: + self._stubs["create_subscription"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Subscriber/CreateSubscription", + request_serializer=pubsub.Subscription.serialize, + response_deserializer=pubsub.Subscription.deserialize, + ) + return self._stubs["create_subscription"] + + @property + def get_subscription( + self, + ) -> Callable[[pubsub.GetSubscriptionRequest], pubsub.Subscription]: + r"""Return a callable for the get subscription method over gRPC. + + Gets the configuration details of a subscription. + + Returns: + Callable[[~.GetSubscriptionRequest], + ~.Subscription]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_subscription" not in self._stubs: + self._stubs["get_subscription"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Subscriber/GetSubscription", + request_serializer=pubsub.GetSubscriptionRequest.serialize, + response_deserializer=pubsub.Subscription.deserialize, + ) + return self._stubs["get_subscription"] + + @property + def update_subscription( + self, + ) -> Callable[[pubsub.UpdateSubscriptionRequest], pubsub.Subscription]: + r"""Return a callable for the update subscription method over gRPC. + + Updates an existing subscription. Note that certain + properties of a subscription, such as its topic, are not + modifiable. + + Returns: + Callable[[~.UpdateSubscriptionRequest], + ~.Subscription]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "update_subscription" not in self._stubs: + self._stubs["update_subscription"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Subscriber/UpdateSubscription", + request_serializer=pubsub.UpdateSubscriptionRequest.serialize, + response_deserializer=pubsub.Subscription.deserialize, + ) + return self._stubs["update_subscription"] + + @property + def list_subscriptions( + self, + ) -> Callable[[pubsub.ListSubscriptionsRequest], pubsub.ListSubscriptionsResponse]: + r"""Return a callable for the list subscriptions method over gRPC. + + Lists matching subscriptions. + + Returns: + Callable[[~.ListSubscriptionsRequest], + ~.ListSubscriptionsResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_subscriptions" not in self._stubs: + self._stubs["list_subscriptions"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Subscriber/ListSubscriptions", + request_serializer=pubsub.ListSubscriptionsRequest.serialize, + response_deserializer=pubsub.ListSubscriptionsResponse.deserialize, + ) + return self._stubs["list_subscriptions"] + + @property + def delete_subscription( + self, + ) -> Callable[[pubsub.DeleteSubscriptionRequest], empty_pb2.Empty]: + r"""Return a callable for the delete subscription method over gRPC. + + Deletes an existing subscription. All messages retained in the + subscription are immediately dropped. Calls to ``Pull`` after + deletion will return ``NOT_FOUND``. After a subscription is + deleted, a new one may be created with the same name, but the + new one has no association with the old subscription or its + topic unless the same topic is specified. + + Returns: + Callable[[~.DeleteSubscriptionRequest], + ~.Empty]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "delete_subscription" not in self._stubs: + self._stubs["delete_subscription"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Subscriber/DeleteSubscription", + request_serializer=pubsub.DeleteSubscriptionRequest.serialize, + response_deserializer=empty_pb2.Empty.FromString, + ) + return self._stubs["delete_subscription"] + + @property + def modify_ack_deadline( + self, + ) -> Callable[[pubsub.ModifyAckDeadlineRequest], empty_pb2.Empty]: + r"""Return a callable for the modify ack deadline method over gRPC. + + Modifies the ack deadline for a specific message. This method is + useful to indicate that more time is needed to process a message + by the subscriber, or to make the message available for + redelivery if the processing was interrupted. Note that this + does not modify the subscription-level ``ackDeadlineSeconds`` + used for subsequent messages. + + Returns: + Callable[[~.ModifyAckDeadlineRequest], + ~.Empty]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "modify_ack_deadline" not in self._stubs: + self._stubs["modify_ack_deadline"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Subscriber/ModifyAckDeadline", + request_serializer=pubsub.ModifyAckDeadlineRequest.serialize, + response_deserializer=empty_pb2.Empty.FromString, + ) + return self._stubs["modify_ack_deadline"] + + @property + def acknowledge(self) -> Callable[[pubsub.AcknowledgeRequest], empty_pb2.Empty]: + r"""Return a callable for the acknowledge method over gRPC. + + Acknowledges the messages associated with the ``ack_ids`` in the + ``AcknowledgeRequest``. The Pub/Sub system can remove the + relevant messages from the subscription. + + Acknowledging a message whose ack deadline has expired may + succeed, but such a message may be redelivered later. + Acknowledging a message more than once will not result in an + error. + + Returns: + Callable[[~.AcknowledgeRequest], + ~.Empty]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "acknowledge" not in self._stubs: + self._stubs["acknowledge"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Subscriber/Acknowledge", + request_serializer=pubsub.AcknowledgeRequest.serialize, + response_deserializer=empty_pb2.Empty.FromString, + ) + return self._stubs["acknowledge"] + + @property + def pull(self) -> Callable[[pubsub.PullRequest], pubsub.PullResponse]: + r"""Return a callable for the pull method over gRPC. + + Pulls messages from the server. The server may return + ``UNAVAILABLE`` if there are too many concurrent pull requests + pending for the given subscription. + + Returns: + Callable[[~.PullRequest], + ~.PullResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "pull" not in self._stubs: + self._stubs["pull"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Subscriber/Pull", + request_serializer=pubsub.PullRequest.serialize, + response_deserializer=pubsub.PullResponse.deserialize, + ) + return self._stubs["pull"] + + @property + def streaming_pull( + self, + ) -> Callable[[pubsub.StreamingPullRequest], pubsub.StreamingPullResponse]: + r"""Return a callable for the streaming pull method over gRPC. + + Establishes a stream with the server, which sends messages down + to the client. The client streams acknowledgements and ack + deadline modifications back to the server. The server will close + the stream and return the status on any error. The server may + close the stream with status ``UNAVAILABLE`` to reassign + server-side resources, in which case, the client should + re-establish the stream. Flow control can be achieved by + configuring the underlying RPC channel. + + Returns: + Callable[[~.StreamingPullRequest], + ~.StreamingPullResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "streaming_pull" not in self._stubs: + self._stubs["streaming_pull"] = self.grpc_channel.stream_stream( + "/google.pubsub.v1.Subscriber/StreamingPull", + request_serializer=pubsub.StreamingPullRequest.serialize, + response_deserializer=pubsub.StreamingPullResponse.deserialize, + ) + return self._stubs["streaming_pull"] + + @property + def modify_push_config( + self, + ) -> Callable[[pubsub.ModifyPushConfigRequest], empty_pb2.Empty]: + r"""Return a callable for the modify push config method over gRPC. + + Modifies the ``PushConfig`` for a specified subscription. + + This may be used to change a push subscription to a pull one + (signified by an empty ``PushConfig``) or vice versa, or change + the endpoint URL and other attributes of a push subscription. + Messages will accumulate for delivery continuously through the + call regardless of changes to the ``PushConfig``. + + Returns: + Callable[[~.ModifyPushConfigRequest], + ~.Empty]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "modify_push_config" not in self._stubs: + self._stubs["modify_push_config"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Subscriber/ModifyPushConfig", + request_serializer=pubsub.ModifyPushConfigRequest.serialize, + response_deserializer=empty_pb2.Empty.FromString, + ) + return self._stubs["modify_push_config"] + + @property + def get_snapshot(self) -> Callable[[pubsub.GetSnapshotRequest], pubsub.Snapshot]: + r"""Return a callable for the get snapshot method over gRPC. + + Gets the configuration details of a snapshot. + Snapshots are used in Seek + operations, which allow you to manage message + acknowledgments in bulk. That is, you can set the + acknowledgment state of messages in an existing + subscription to the state captured by a snapshot. + + Returns: + Callable[[~.GetSnapshotRequest], + ~.Snapshot]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_snapshot" not in self._stubs: + self._stubs["get_snapshot"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Subscriber/GetSnapshot", + request_serializer=pubsub.GetSnapshotRequest.serialize, + response_deserializer=pubsub.Snapshot.deserialize, + ) + return self._stubs["get_snapshot"] + + @property + def list_snapshots( + self, + ) -> Callable[[pubsub.ListSnapshotsRequest], pubsub.ListSnapshotsResponse]: + r"""Return a callable for the list snapshots method over gRPC. + + Lists the existing snapshots. Snapshots are used in + `Seek `__ + operations, which allow you to manage message acknowledgments in + bulk. That is, you can set the acknowledgment state of messages + in an existing subscription to the state captured by a snapshot. + + Returns: + Callable[[~.ListSnapshotsRequest], + ~.ListSnapshotsResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_snapshots" not in self._stubs: + self._stubs["list_snapshots"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Subscriber/ListSnapshots", + request_serializer=pubsub.ListSnapshotsRequest.serialize, + response_deserializer=pubsub.ListSnapshotsResponse.deserialize, + ) + return self._stubs["list_snapshots"] + + @property + def create_snapshot( + self, + ) -> Callable[[pubsub.CreateSnapshotRequest], pubsub.Snapshot]: + r"""Return a callable for the create snapshot method over gRPC. + + Creates a snapshot from the requested subscription. Snapshots + are used in + `Seek `__ + operations, which allow you to manage message acknowledgments in + bulk. That is, you can set the acknowledgment state of messages + in an existing subscription to the state captured by a snapshot. + If the snapshot already exists, returns ``ALREADY_EXISTS``. If + the requested subscription doesn't exist, returns ``NOT_FOUND``. + If the backlog in the subscription is too old -- and the + resulting snapshot would expire in less than 1 hour -- then + ``FAILED_PRECONDITION`` is returned. See also the + ``Snapshot.expire_time`` field. If the name is not provided in + the request, the server will assign a random name for this + snapshot on the same project as the subscription, conforming to + the [resource name format] + (https://cloud.google.com/pubsub/docs/admin#resource_names). The + generated name is populated in the returned Snapshot object. + Note that for REST API requests, you must specify a name in the + request. + + Returns: + Callable[[~.CreateSnapshotRequest], + ~.Snapshot]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "create_snapshot" not in self._stubs: + self._stubs["create_snapshot"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Subscriber/CreateSnapshot", + request_serializer=pubsub.CreateSnapshotRequest.serialize, + response_deserializer=pubsub.Snapshot.deserialize, + ) + return self._stubs["create_snapshot"] + + @property + def update_snapshot( + self, + ) -> Callable[[pubsub.UpdateSnapshotRequest], pubsub.Snapshot]: + r"""Return a callable for the update snapshot method over gRPC. + + Updates an existing snapshot. Snapshots are used in + Seek + operations, which allow + you to manage message acknowledgments in bulk. That is, + you can set the acknowledgment state of messages in an + existing subscription to the state captured by a + snapshot. + + Returns: + Callable[[~.UpdateSnapshotRequest], + ~.Snapshot]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "update_snapshot" not in self._stubs: + self._stubs["update_snapshot"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Subscriber/UpdateSnapshot", + request_serializer=pubsub.UpdateSnapshotRequest.serialize, + response_deserializer=pubsub.Snapshot.deserialize, + ) + return self._stubs["update_snapshot"] + + @property + def delete_snapshot( + self, + ) -> Callable[[pubsub.DeleteSnapshotRequest], empty_pb2.Empty]: + r"""Return a callable for the delete snapshot method over gRPC. + + Removes an existing snapshot. Snapshots are used in [Seek] + (https://cloud.google.com/pubsub/docs/replay-overview) + operations, which allow you to manage message acknowledgments in + bulk. That is, you can set the acknowledgment state of messages + in an existing subscription to the state captured by a snapshot. + When the snapshot is deleted, all messages retained in the + snapshot are immediately dropped. After a snapshot is deleted, a + new one may be created with the same name, but the new one has + no association with the old snapshot or its subscription, unless + the same subscription is specified. + + Returns: + Callable[[~.DeleteSnapshotRequest], + ~.Empty]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "delete_snapshot" not in self._stubs: + self._stubs["delete_snapshot"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Subscriber/DeleteSnapshot", + request_serializer=pubsub.DeleteSnapshotRequest.serialize, + response_deserializer=empty_pb2.Empty.FromString, + ) + return self._stubs["delete_snapshot"] + + @property + def seek(self) -> Callable[[pubsub.SeekRequest], pubsub.SeekResponse]: + r"""Return a callable for the seek method over gRPC. + + Seeks an existing subscription to a point in time or to a given + snapshot, whichever is provided in the request. Snapshots are + used in [Seek] + (https://cloud.google.com/pubsub/docs/replay-overview) + operations, which allow you to manage message acknowledgments in + bulk. That is, you can set the acknowledgment state of messages + in an existing subscription to the state captured by a snapshot. + Note that both the subscription and the snapshot must be on the + same topic. + + Returns: + Callable[[~.SeekRequest], + ~.SeekResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "seek" not in self._stubs: + self._stubs["seek"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Subscriber/Seek", + request_serializer=pubsub.SeekRequest.serialize, + response_deserializer=pubsub.SeekResponse.deserialize, + ) + return self._stubs["seek"] + + @property + def set_iam_policy( + self, + ) -> Callable[[iam_policy_pb2.SetIamPolicyRequest], policy_pb2.Policy]: + r"""Return a callable for the set iam policy method over gRPC. + Sets the IAM access control policy on the specified + function. Replaces any existing policy. + Returns: + Callable[[~.SetIamPolicyRequest], + ~.Policy]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "set_iam_policy" not in self._stubs: + self._stubs["set_iam_policy"] = self.grpc_channel.unary_unary( + "/google.iam.v1.IAMPolicy/SetIamPolicy", + request_serializer=iam_policy_pb2.SetIamPolicyRequest.SerializeToString, + response_deserializer=policy_pb2.Policy.FromString, + ) + return self._stubs["set_iam_policy"] + + @property + def get_iam_policy( + self, + ) -> Callable[[iam_policy_pb2.GetIamPolicyRequest], policy_pb2.Policy]: + r"""Return a callable for the get iam policy method over gRPC. + Gets the IAM access control policy for a function. + Returns an empty policy if the function exists and does + not have a policy set. + Returns: + Callable[[~.GetIamPolicyRequest], + ~.Policy]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_iam_policy" not in self._stubs: + self._stubs["get_iam_policy"] = self.grpc_channel.unary_unary( + "/google.iam.v1.IAMPolicy/GetIamPolicy", + request_serializer=iam_policy_pb2.GetIamPolicyRequest.SerializeToString, + response_deserializer=policy_pb2.Policy.FromString, + ) + return self._stubs["get_iam_policy"] + + @property + def test_iam_permissions( + self, + ) -> Callable[ + [iam_policy_pb2.TestIamPermissionsRequest], + iam_policy_pb2.TestIamPermissionsResponse, + ]: + r"""Return a callable for the test iam permissions method over gRPC. + Tests the specified permissions against the IAM access control + policy for a function. If the function does not exist, this will + return an empty set of permissions, not a NOT_FOUND error. + Returns: + Callable[[~.TestIamPermissionsRequest], + ~.TestIamPermissionsResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "test_iam_permissions" not in self._stubs: + self._stubs["test_iam_permissions"] = self.grpc_channel.unary_unary( + "/google.iam.v1.IAMPolicy/TestIamPermissions", + request_serializer=iam_policy_pb2.TestIamPermissionsRequest.SerializeToString, + response_deserializer=iam_policy_pb2.TestIamPermissionsResponse.FromString, + ) + return self._stubs["test_iam_permissions"] + + def close(self): + self.grpc_channel.close() + + @property + def kind(self) -> str: + return "grpc" + + +__all__ = ("SubscriberGrpcTransport",) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/transports/grpc_asyncio.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/transports/grpc_asyncio.py new file mode 100644 index 000000000000..778e49c5dc8e --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/transports/grpc_asyncio.py @@ -0,0 +1,843 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +import warnings +from typing import Awaitable, Callable, Dict, Optional, Sequence, Tuple, Union + +from google.api_core import gapic_v1 +from google.api_core import grpc_helpers_async +from google.auth import credentials as ga_credentials # type: ignore +from google.auth.transport.grpc import SslCredentials # type: ignore + +import grpc # type: ignore +from grpc.experimental import aio # type: ignore + +from google.iam.v1 import iam_policy_pb2 # type: ignore +from google.iam.v1 import policy_pb2 # type: ignore +from google.protobuf import empty_pb2 # type: ignore +from google.pubsub_v1.types import pubsub +from .base import SubscriberTransport, DEFAULT_CLIENT_INFO +from .grpc import SubscriberGrpcTransport + + +class SubscriberGrpcAsyncIOTransport(SubscriberTransport): + """gRPC AsyncIO backend transport for Subscriber. + + The service that an application uses to manipulate subscriptions and + to consume messages from a subscription via the ``Pull`` method or + by establishing a bi-directional stream using the ``StreamingPull`` + method. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends protocol buffers over the wire using gRPC (which is built on + top of HTTP/2); the ``grpcio`` package must be installed. + """ + + _grpc_channel: aio.Channel + _stubs: Dict[str, Callable] = {} + + @classmethod + def create_channel( + cls, + host: str = "pubsub.googleapis.com", + credentials: ga_credentials.Credentials = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + quota_project_id: Optional[str] = None, + **kwargs, + ) -> aio.Channel: + """Create and return a gRPC AsyncIO channel object. + Args: + host (Optional[str]): The host for the channel to use. + credentials (Optional[~.Credentials]): The + authorization credentials to attach to requests. These + credentials identify this application to the service. If + none are specified, the client will attempt to ascertain + the credentials from the environment. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + kwargs (Optional[dict]): Keyword arguments, which are passed to the + channel creation. + Returns: + aio.Channel: A gRPC AsyncIO channel object. + """ + + return grpc_helpers_async.create_channel( + host, + credentials=credentials, + credentials_file=credentials_file, + quota_project_id=quota_project_id, + default_scopes=cls.AUTH_SCOPES, + scopes=scopes, + default_host=cls.DEFAULT_HOST, + **kwargs, + ) + + def __init__( + self, + *, + host: str = "pubsub.googleapis.com", + credentials: ga_credentials.Credentials = None, + credentials_file: Optional[str] = None, + scopes: Optional[Sequence[str]] = None, + channel: aio.Channel = None, + api_mtls_endpoint: str = None, + client_cert_source: Callable[[], Tuple[bytes, bytes]] = None, + ssl_channel_credentials: grpc.ChannelCredentials = None, + client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None, + quota_project_id=None, + client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, + always_use_jwt_access: Optional[bool] = False, + api_audience: Optional[str] = None, + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): + The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + This argument is ignored if ``channel`` is provided. + credentials_file (Optional[str]): A file with credentials that can + be loaded with :func:`google.auth.load_credentials_from_file`. + This argument is ignored if ``channel`` is provided. + scopes (Optional[Sequence[str]]): A optional list of scopes needed for this + service. These are only used when credentials are not specified and + are passed to :func:`google.auth.default`. + channel (Optional[aio.Channel]): A ``Channel`` instance through + which to make calls. + api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. + If provided, it overrides the ``host`` argument and tries to create + a mutual TLS channel with client SSL credentials from + ``client_cert_source`` or application default SSL credentials. + client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): + Deprecated. A callback to provide client SSL certificate bytes and + private key bytes, both in PEM format. It is ignored if + ``api_mtls_endpoint`` is None. + ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials + for the grpc channel. It is ignored if ``channel`` is provided. + client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): + A callback to provide client certificate bytes and private key bytes, + both in PEM format. It is used to configure a mutual TLS channel. It is + ignored if ``channel`` or ``ssl_channel_credentials`` is provided. + quota_project_id (Optional[str]): An optional project to use for billing + and quota. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + always_use_jwt_access (Optional[bool]): Whether self signed JWT should + be used for service account credentials. + + Raises: + google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport + creation failed for any reason. + google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials`` + and ``credentials_file`` are passed. + """ + self._grpc_channel = None + self._ssl_channel_credentials = ssl_channel_credentials + self._stubs: Dict[str, Callable] = {} + + if api_mtls_endpoint: + warnings.warn("api_mtls_endpoint is deprecated", DeprecationWarning) + if client_cert_source: + warnings.warn("client_cert_source is deprecated", DeprecationWarning) + + if channel: + # Ignore credentials if a channel was passed. + credentials = False + # If a channel was explicitly provided, set it. + self._grpc_channel = channel + self._ssl_channel_credentials = None + else: + if api_mtls_endpoint: + host = api_mtls_endpoint + + # Create SSL credentials with client_cert_source or application + # default SSL credentials. + if client_cert_source: + cert, key = client_cert_source() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + else: + self._ssl_channel_credentials = SslCredentials().ssl_credentials + + else: + if client_cert_source_for_mtls and not ssl_channel_credentials: + cert, key = client_cert_source_for_mtls() + self._ssl_channel_credentials = grpc.ssl_channel_credentials( + certificate_chain=cert, private_key=key + ) + + # The base transport sets the host, credentials and scopes + super().__init__( + host=host, + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + quota_project_id=quota_project_id, + client_info=client_info, + always_use_jwt_access=always_use_jwt_access, + api_audience=api_audience, + ) + + if not self._grpc_channel: + self._grpc_channel = type(self).create_channel( + self._host, + # use the credentials which are saved + credentials=self._credentials, + # Set ``credentials_file`` to ``None`` here as + # the credentials that we saved earlier should be used. + credentials_file=None, + scopes=self._scopes, + ssl_credentials=self._ssl_channel_credentials, + quota_project_id=quota_project_id, + options=[ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), + ("grpc.max_metadata_size", 4 * 1024 * 1024), + ("grpc.keepalive_time_ms", 30000), + ], + ) + + # Wrap messages. This must be done after self._grpc_channel exists + self._prep_wrapped_messages(client_info) + + @property + def grpc_channel(self) -> aio.Channel: + """Create the channel designed to connect to this service. + + This property caches on the instance; repeated calls return + the same channel. + """ + # Return the channel from cache. + return self._grpc_channel + + @property + def create_subscription( + self, + ) -> Callable[[pubsub.Subscription], Awaitable[pubsub.Subscription]]: + r"""Return a callable for the create subscription method over gRPC. + + Creates a subscription to a given topic. See the [resource name + rules] + (https://cloud.google.com/pubsub/docs/admin#resource_names). If + the subscription already exists, returns ``ALREADY_EXISTS``. If + the corresponding topic doesn't exist, returns ``NOT_FOUND``. + + If the name is not provided in the request, the server will + assign a random name for this subscription on the same project + as the topic, conforming to the [resource name format] + (https://cloud.google.com/pubsub/docs/admin#resource_names). The + generated name is populated in the returned Subscription object. + Note that for REST API requests, you must specify a name in the + request. + + Returns: + Callable[[~.Subscription], + Awaitable[~.Subscription]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "create_subscription" not in self._stubs: + self._stubs["create_subscription"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Subscriber/CreateSubscription", + request_serializer=pubsub.Subscription.serialize, + response_deserializer=pubsub.Subscription.deserialize, + ) + return self._stubs["create_subscription"] + + @property + def get_subscription( + self, + ) -> Callable[[pubsub.GetSubscriptionRequest], Awaitable[pubsub.Subscription]]: + r"""Return a callable for the get subscription method over gRPC. + + Gets the configuration details of a subscription. + + Returns: + Callable[[~.GetSubscriptionRequest], + Awaitable[~.Subscription]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_subscription" not in self._stubs: + self._stubs["get_subscription"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Subscriber/GetSubscription", + request_serializer=pubsub.GetSubscriptionRequest.serialize, + response_deserializer=pubsub.Subscription.deserialize, + ) + return self._stubs["get_subscription"] + + @property + def update_subscription( + self, + ) -> Callable[[pubsub.UpdateSubscriptionRequest], Awaitable[pubsub.Subscription]]: + r"""Return a callable for the update subscription method over gRPC. + + Updates an existing subscription. Note that certain + properties of a subscription, such as its topic, are not + modifiable. + + Returns: + Callable[[~.UpdateSubscriptionRequest], + Awaitable[~.Subscription]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "update_subscription" not in self._stubs: + self._stubs["update_subscription"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Subscriber/UpdateSubscription", + request_serializer=pubsub.UpdateSubscriptionRequest.serialize, + response_deserializer=pubsub.Subscription.deserialize, + ) + return self._stubs["update_subscription"] + + @property + def list_subscriptions( + self, + ) -> Callable[ + [pubsub.ListSubscriptionsRequest], Awaitable[pubsub.ListSubscriptionsResponse] + ]: + r"""Return a callable for the list subscriptions method over gRPC. + + Lists matching subscriptions. + + Returns: + Callable[[~.ListSubscriptionsRequest], + Awaitable[~.ListSubscriptionsResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_subscriptions" not in self._stubs: + self._stubs["list_subscriptions"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Subscriber/ListSubscriptions", + request_serializer=pubsub.ListSubscriptionsRequest.serialize, + response_deserializer=pubsub.ListSubscriptionsResponse.deserialize, + ) + return self._stubs["list_subscriptions"] + + @property + def delete_subscription( + self, + ) -> Callable[[pubsub.DeleteSubscriptionRequest], Awaitable[empty_pb2.Empty]]: + r"""Return a callable for the delete subscription method over gRPC. + + Deletes an existing subscription. All messages retained in the + subscription are immediately dropped. Calls to ``Pull`` after + deletion will return ``NOT_FOUND``. After a subscription is + deleted, a new one may be created with the same name, but the + new one has no association with the old subscription or its + topic unless the same topic is specified. + + Returns: + Callable[[~.DeleteSubscriptionRequest], + Awaitable[~.Empty]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "delete_subscription" not in self._stubs: + self._stubs["delete_subscription"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Subscriber/DeleteSubscription", + request_serializer=pubsub.DeleteSubscriptionRequest.serialize, + response_deserializer=empty_pb2.Empty.FromString, + ) + return self._stubs["delete_subscription"] + + @property + def modify_ack_deadline( + self, + ) -> Callable[[pubsub.ModifyAckDeadlineRequest], Awaitable[empty_pb2.Empty]]: + r"""Return a callable for the modify ack deadline method over gRPC. + + Modifies the ack deadline for a specific message. This method is + useful to indicate that more time is needed to process a message + by the subscriber, or to make the message available for + redelivery if the processing was interrupted. Note that this + does not modify the subscription-level ``ackDeadlineSeconds`` + used for subsequent messages. + + Returns: + Callable[[~.ModifyAckDeadlineRequest], + Awaitable[~.Empty]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "modify_ack_deadline" not in self._stubs: + self._stubs["modify_ack_deadline"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Subscriber/ModifyAckDeadline", + request_serializer=pubsub.ModifyAckDeadlineRequest.serialize, + response_deserializer=empty_pb2.Empty.FromString, + ) + return self._stubs["modify_ack_deadline"] + + @property + def acknowledge( + self, + ) -> Callable[[pubsub.AcknowledgeRequest], Awaitable[empty_pb2.Empty]]: + r"""Return a callable for the acknowledge method over gRPC. + + Acknowledges the messages associated with the ``ack_ids`` in the + ``AcknowledgeRequest``. The Pub/Sub system can remove the + relevant messages from the subscription. + + Acknowledging a message whose ack deadline has expired may + succeed, but such a message may be redelivered later. + Acknowledging a message more than once will not result in an + error. + + Returns: + Callable[[~.AcknowledgeRequest], + Awaitable[~.Empty]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "acknowledge" not in self._stubs: + self._stubs["acknowledge"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Subscriber/Acknowledge", + request_serializer=pubsub.AcknowledgeRequest.serialize, + response_deserializer=empty_pb2.Empty.FromString, + ) + return self._stubs["acknowledge"] + + @property + def pull(self) -> Callable[[pubsub.PullRequest], Awaitable[pubsub.PullResponse]]: + r"""Return a callable for the pull method over gRPC. + + Pulls messages from the server. The server may return + ``UNAVAILABLE`` if there are too many concurrent pull requests + pending for the given subscription. + + Returns: + Callable[[~.PullRequest], + Awaitable[~.PullResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "pull" not in self._stubs: + self._stubs["pull"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Subscriber/Pull", + request_serializer=pubsub.PullRequest.serialize, + response_deserializer=pubsub.PullResponse.deserialize, + ) + return self._stubs["pull"] + + @property + def streaming_pull( + self, + ) -> Callable[ + [pubsub.StreamingPullRequest], Awaitable[pubsub.StreamingPullResponse] + ]: + r"""Return a callable for the streaming pull method over gRPC. + + Establishes a stream with the server, which sends messages down + to the client. The client streams acknowledgements and ack + deadline modifications back to the server. The server will close + the stream and return the status on any error. The server may + close the stream with status ``UNAVAILABLE`` to reassign + server-side resources, in which case, the client should + re-establish the stream. Flow control can be achieved by + configuring the underlying RPC channel. + + Returns: + Callable[[~.StreamingPullRequest], + Awaitable[~.StreamingPullResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "streaming_pull" not in self._stubs: + self._stubs["streaming_pull"] = self.grpc_channel.stream_stream( + "/google.pubsub.v1.Subscriber/StreamingPull", + request_serializer=pubsub.StreamingPullRequest.serialize, + response_deserializer=pubsub.StreamingPullResponse.deserialize, + ) + return self._stubs["streaming_pull"] + + @property + def modify_push_config( + self, + ) -> Callable[[pubsub.ModifyPushConfigRequest], Awaitable[empty_pb2.Empty]]: + r"""Return a callable for the modify push config method over gRPC. + + Modifies the ``PushConfig`` for a specified subscription. + + This may be used to change a push subscription to a pull one + (signified by an empty ``PushConfig``) or vice versa, or change + the endpoint URL and other attributes of a push subscription. + Messages will accumulate for delivery continuously through the + call regardless of changes to the ``PushConfig``. + + Returns: + Callable[[~.ModifyPushConfigRequest], + Awaitable[~.Empty]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "modify_push_config" not in self._stubs: + self._stubs["modify_push_config"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Subscriber/ModifyPushConfig", + request_serializer=pubsub.ModifyPushConfigRequest.serialize, + response_deserializer=empty_pb2.Empty.FromString, + ) + return self._stubs["modify_push_config"] + + @property + def get_snapshot( + self, + ) -> Callable[[pubsub.GetSnapshotRequest], Awaitable[pubsub.Snapshot]]: + r"""Return a callable for the get snapshot method over gRPC. + + Gets the configuration details of a snapshot. + Snapshots are used in Seek + operations, which allow you to manage message + acknowledgments in bulk. That is, you can set the + acknowledgment state of messages in an existing + subscription to the state captured by a snapshot. + + Returns: + Callable[[~.GetSnapshotRequest], + Awaitable[~.Snapshot]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_snapshot" not in self._stubs: + self._stubs["get_snapshot"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Subscriber/GetSnapshot", + request_serializer=pubsub.GetSnapshotRequest.serialize, + response_deserializer=pubsub.Snapshot.deserialize, + ) + return self._stubs["get_snapshot"] + + @property + def list_snapshots( + self, + ) -> Callable[ + [pubsub.ListSnapshotsRequest], Awaitable[pubsub.ListSnapshotsResponse] + ]: + r"""Return a callable for the list snapshots method over gRPC. + + Lists the existing snapshots. Snapshots are used in + `Seek `__ + operations, which allow you to manage message acknowledgments in + bulk. That is, you can set the acknowledgment state of messages + in an existing subscription to the state captured by a snapshot. + + Returns: + Callable[[~.ListSnapshotsRequest], + Awaitable[~.ListSnapshotsResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_snapshots" not in self._stubs: + self._stubs["list_snapshots"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Subscriber/ListSnapshots", + request_serializer=pubsub.ListSnapshotsRequest.serialize, + response_deserializer=pubsub.ListSnapshotsResponse.deserialize, + ) + return self._stubs["list_snapshots"] + + @property + def create_snapshot( + self, + ) -> Callable[[pubsub.CreateSnapshotRequest], Awaitable[pubsub.Snapshot]]: + r"""Return a callable for the create snapshot method over gRPC. + + Creates a snapshot from the requested subscription. Snapshots + are used in + `Seek `__ + operations, which allow you to manage message acknowledgments in + bulk. That is, you can set the acknowledgment state of messages + in an existing subscription to the state captured by a snapshot. + If the snapshot already exists, returns ``ALREADY_EXISTS``. If + the requested subscription doesn't exist, returns ``NOT_FOUND``. + If the backlog in the subscription is too old -- and the + resulting snapshot would expire in less than 1 hour -- then + ``FAILED_PRECONDITION`` is returned. See also the + ``Snapshot.expire_time`` field. If the name is not provided in + the request, the server will assign a random name for this + snapshot on the same project as the subscription, conforming to + the [resource name format] + (https://cloud.google.com/pubsub/docs/admin#resource_names). The + generated name is populated in the returned Snapshot object. + Note that for REST API requests, you must specify a name in the + request. + + Returns: + Callable[[~.CreateSnapshotRequest], + Awaitable[~.Snapshot]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "create_snapshot" not in self._stubs: + self._stubs["create_snapshot"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Subscriber/CreateSnapshot", + request_serializer=pubsub.CreateSnapshotRequest.serialize, + response_deserializer=pubsub.Snapshot.deserialize, + ) + return self._stubs["create_snapshot"] + + @property + def update_snapshot( + self, + ) -> Callable[[pubsub.UpdateSnapshotRequest], Awaitable[pubsub.Snapshot]]: + r"""Return a callable for the update snapshot method over gRPC. + + Updates an existing snapshot. Snapshots are used in + Seek + operations, which allow + you to manage message acknowledgments in bulk. That is, + you can set the acknowledgment state of messages in an + existing subscription to the state captured by a + snapshot. + + Returns: + Callable[[~.UpdateSnapshotRequest], + Awaitable[~.Snapshot]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "update_snapshot" not in self._stubs: + self._stubs["update_snapshot"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Subscriber/UpdateSnapshot", + request_serializer=pubsub.UpdateSnapshotRequest.serialize, + response_deserializer=pubsub.Snapshot.deserialize, + ) + return self._stubs["update_snapshot"] + + @property + def delete_snapshot( + self, + ) -> Callable[[pubsub.DeleteSnapshotRequest], Awaitable[empty_pb2.Empty]]: + r"""Return a callable for the delete snapshot method over gRPC. + + Removes an existing snapshot. Snapshots are used in [Seek] + (https://cloud.google.com/pubsub/docs/replay-overview) + operations, which allow you to manage message acknowledgments in + bulk. That is, you can set the acknowledgment state of messages + in an existing subscription to the state captured by a snapshot. + When the snapshot is deleted, all messages retained in the + snapshot are immediately dropped. After a snapshot is deleted, a + new one may be created with the same name, but the new one has + no association with the old snapshot or its subscription, unless + the same subscription is specified. + + Returns: + Callable[[~.DeleteSnapshotRequest], + Awaitable[~.Empty]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "delete_snapshot" not in self._stubs: + self._stubs["delete_snapshot"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Subscriber/DeleteSnapshot", + request_serializer=pubsub.DeleteSnapshotRequest.serialize, + response_deserializer=empty_pb2.Empty.FromString, + ) + return self._stubs["delete_snapshot"] + + @property + def seek(self) -> Callable[[pubsub.SeekRequest], Awaitable[pubsub.SeekResponse]]: + r"""Return a callable for the seek method over gRPC. + + Seeks an existing subscription to a point in time or to a given + snapshot, whichever is provided in the request. Snapshots are + used in [Seek] + (https://cloud.google.com/pubsub/docs/replay-overview) + operations, which allow you to manage message acknowledgments in + bulk. That is, you can set the acknowledgment state of messages + in an existing subscription to the state captured by a snapshot. + Note that both the subscription and the snapshot must be on the + same topic. + + Returns: + Callable[[~.SeekRequest], + Awaitable[~.SeekResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "seek" not in self._stubs: + self._stubs["seek"] = self.grpc_channel.unary_unary( + "/google.pubsub.v1.Subscriber/Seek", + request_serializer=pubsub.SeekRequest.serialize, + response_deserializer=pubsub.SeekResponse.deserialize, + ) + return self._stubs["seek"] + + @property + def set_iam_policy( + self, + ) -> Callable[[iam_policy_pb2.SetIamPolicyRequest], Awaitable[policy_pb2.Policy]]: + r"""Return a callable for the set iam policy method over gRPC. + Sets the IAM access control policy on the specified + function. Replaces any existing policy. + Returns: + Callable[[~.SetIamPolicyRequest], + Awaitable[~.Policy]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "set_iam_policy" not in self._stubs: + self._stubs["set_iam_policy"] = self.grpc_channel.unary_unary( + "/google.iam.v1.IAMPolicy/SetIamPolicy", + request_serializer=iam_policy_pb2.SetIamPolicyRequest.SerializeToString, + response_deserializer=policy_pb2.Policy.FromString, + ) + return self._stubs["set_iam_policy"] + + @property + def get_iam_policy( + self, + ) -> Callable[[iam_policy_pb2.GetIamPolicyRequest], Awaitable[policy_pb2.Policy]]: + r"""Return a callable for the get iam policy method over gRPC. + Gets the IAM access control policy for a function. + Returns an empty policy if the function exists and does + not have a policy set. + Returns: + Callable[[~.GetIamPolicyRequest], + Awaitable[~.Policy]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_iam_policy" not in self._stubs: + self._stubs["get_iam_policy"] = self.grpc_channel.unary_unary( + "/google.iam.v1.IAMPolicy/GetIamPolicy", + request_serializer=iam_policy_pb2.GetIamPolicyRequest.SerializeToString, + response_deserializer=policy_pb2.Policy.FromString, + ) + return self._stubs["get_iam_policy"] + + @property + def test_iam_permissions( + self, + ) -> Callable[ + [iam_policy_pb2.TestIamPermissionsRequest], + Awaitable[iam_policy_pb2.TestIamPermissionsResponse], + ]: + r"""Return a callable for the test iam permissions method over gRPC. + Tests the specified permissions against the IAM access control + policy for a function. If the function does not exist, this will + return an empty set of permissions, not a NOT_FOUND error. + Returns: + Callable[[~.TestIamPermissionsRequest], + Awaitable[~.TestIamPermissionsResponse]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "test_iam_permissions" not in self._stubs: + self._stubs["test_iam_permissions"] = self.grpc_channel.unary_unary( + "/google.iam.v1.IAMPolicy/TestIamPermissions", + request_serializer=iam_policy_pb2.TestIamPermissionsRequest.SerializeToString, + response_deserializer=iam_policy_pb2.TestIamPermissionsResponse.FromString, + ) + return self._stubs["test_iam_permissions"] + + def close(self): + return self.grpc_channel.close() + + +__all__ = ("SubscriberGrpcAsyncIOTransport",) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/types/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/types/__init__.py new file mode 100644 index 000000000000..c0d9c4619d75 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/types/__init__.py @@ -0,0 +1,147 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +from typing import Union + +from .pubsub import ( + AcknowledgeRequest, + BigQueryConfig, + CreateSnapshotRequest, + DeadLetterPolicy, + DeleteSnapshotRequest, + DeleteSubscriptionRequest, + DeleteTopicRequest, + DetachSubscriptionRequest, + DetachSubscriptionResponse, + ExpirationPolicy, + GetSnapshotRequest, + GetSubscriptionRequest, + GetTopicRequest, + ListSnapshotsRequest, + ListSnapshotsResponse, + ListSubscriptionsRequest, + ListSubscriptionsResponse, + ListTopicSnapshotsRequest, + ListTopicSnapshotsResponse, + ListTopicsRequest, + ListTopicsResponse, + ListTopicSubscriptionsRequest, + ListTopicSubscriptionsResponse, + MessageStoragePolicy, + ModifyAckDeadlineRequest, + ModifyPushConfigRequest, + PublishRequest, + PublishResponse, + PubsubMessage, + PullRequest, + PullResponse, + PushConfig, + ReceivedMessage, + RetryPolicy, + SchemaSettings, + SeekRequest, + SeekResponse, + Snapshot, + StreamingPullRequest, + StreamingPullResponse, + Subscription, + Topic, + UpdateSnapshotRequest, + UpdateSubscriptionRequest, + UpdateTopicRequest, +) +from .schema import ( + CreateSchemaRequest, + DeleteSchemaRequest, + GetSchemaRequest, + ListSchemasRequest, + ListSchemasResponse, + Schema, + ValidateMessageRequest, + ValidateMessageResponse, + ValidateSchemaRequest, + ValidateSchemaResponse, + Encoding, + SchemaView, +) + +TimeoutType = Union[ + int, + float, + "google.api_core.timeout.ConstantTimeout", + "google.api_core.timeout.ExponentialTimeout", +] +"""The type of the timeout parameter of publisher client methods.""" + +__all__ = ( + "TimeoutType", + "AcknowledgeRequest", + "BigQueryConfig", + "CreateSnapshotRequest", + "DeadLetterPolicy", + "DeleteSnapshotRequest", + "DeleteSubscriptionRequest", + "DeleteTopicRequest", + "DetachSubscriptionRequest", + "DetachSubscriptionResponse", + "ExpirationPolicy", + "GetSnapshotRequest", + "GetSubscriptionRequest", + "GetTopicRequest", + "ListSnapshotsRequest", + "ListSnapshotsResponse", + "ListSubscriptionsRequest", + "ListSubscriptionsResponse", + "ListTopicSnapshotsRequest", + "ListTopicSnapshotsResponse", + "ListTopicsRequest", + "ListTopicsResponse", + "ListTopicSubscriptionsRequest", + "ListTopicSubscriptionsResponse", + "MessageStoragePolicy", + "ModifyAckDeadlineRequest", + "ModifyPushConfigRequest", + "PublishRequest", + "PublishResponse", + "PubsubMessage", + "PullRequest", + "PullResponse", + "PushConfig", + "ReceivedMessage", + "RetryPolicy", + "SchemaSettings", + "SeekRequest", + "SeekResponse", + "Snapshot", + "StreamingPullRequest", + "StreamingPullResponse", + "Subscription", + "Topic", + "UpdateSnapshotRequest", + "UpdateSubscriptionRequest", + "UpdateTopicRequest", + "CreateSchemaRequest", + "DeleteSchemaRequest", + "GetSchemaRequest", + "ListSchemasRequest", + "ListSchemasResponse", + "Schema", + "ValidateMessageRequest", + "ValidateMessageResponse", + "ValidateSchemaRequest", + "ValidateSchemaResponse", + "Encoding", + "SchemaView", +) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/types/pubsub.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/types/pubsub.py new file mode 100644 index 000000000000..73658e9c0989 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/types/pubsub.py @@ -0,0 +1,1867 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +import proto # type: ignore + +from google.protobuf import duration_pb2 # type: ignore +from google.protobuf import field_mask_pb2 # type: ignore +from google.protobuf import timestamp_pb2 # type: ignore +from google.pubsub_v1.types import schema as gp_schema + + +__protobuf__ = proto.module( + package="google.pubsub.v1", + manifest={ + "MessageStoragePolicy", + "SchemaSettings", + "Topic", + "PubsubMessage", + "GetTopicRequest", + "UpdateTopicRequest", + "PublishRequest", + "PublishResponse", + "ListTopicsRequest", + "ListTopicsResponse", + "ListTopicSubscriptionsRequest", + "ListTopicSubscriptionsResponse", + "ListTopicSnapshotsRequest", + "ListTopicSnapshotsResponse", + "DeleteTopicRequest", + "DetachSubscriptionRequest", + "DetachSubscriptionResponse", + "Subscription", + "RetryPolicy", + "DeadLetterPolicy", + "ExpirationPolicy", + "PushConfig", + "BigQueryConfig", + "ReceivedMessage", + "GetSubscriptionRequest", + "UpdateSubscriptionRequest", + "ListSubscriptionsRequest", + "ListSubscriptionsResponse", + "DeleteSubscriptionRequest", + "ModifyPushConfigRequest", + "PullRequest", + "PullResponse", + "ModifyAckDeadlineRequest", + "AcknowledgeRequest", + "StreamingPullRequest", + "StreamingPullResponse", + "CreateSnapshotRequest", + "UpdateSnapshotRequest", + "Snapshot", + "GetSnapshotRequest", + "ListSnapshotsRequest", + "ListSnapshotsResponse", + "DeleteSnapshotRequest", + "SeekRequest", + "SeekResponse", + }, +) + + +class MessageStoragePolicy(proto.Message): + r"""A policy constraining the storage of messages published to + the topic. + + Attributes: + allowed_persistence_regions (Sequence[str]): + A list of IDs of GCP regions where messages + that are published to the topic may be persisted + in storage. Messages published by publishers + running in non-allowed GCP regions (or running + outside of GCP altogether) will be routed for + storage in one of the allowed regions. An empty + list means that no regions are allowed, and is + not a valid configuration. + """ + + allowed_persistence_regions = proto.RepeatedField( + proto.STRING, + number=1, + ) + + +class SchemaSettings(proto.Message): + r"""Settings for validating messages published against a schema. + + Attributes: + schema (str): + Required. The name of the schema that messages published + should be validated against. Format is + ``projects/{project}/schemas/{schema}``. The value of this + field will be ``_deleted-schema_`` if the schema has been + deleted. + encoding (google.pubsub_v1.types.Encoding): + The encoding of messages validated against ``schema``. + """ + + schema = proto.Field( + proto.STRING, + number=1, + ) + encoding = proto.Field( + proto.ENUM, + number=2, + enum=gp_schema.Encoding, + ) + + +class Topic(proto.Message): + r"""A topic resource. + + Attributes: + name (str): + Required. The name of the topic. It must have the format + ``"projects/{project}/topics/{topic}"``. ``{topic}`` must + start with a letter, and contain only letters + (``[A-Za-z]``), numbers (``[0-9]``), dashes (``-``), + underscores (``_``), periods (``.``), tildes (``~``), plus + (``+``) or percent signs (``%``). It must be between 3 and + 255 characters in length, and it must not start with + ``"goog"``. + labels (Mapping[str, str]): + See [Creating and managing labels] + (https://cloud.google.com/pubsub/docs/labels). + message_storage_policy (google.pubsub_v1.types.MessageStoragePolicy): + Policy constraining the set of Google Cloud + Platform regions where messages published to the + topic may be stored. If not present, then no + constraints are in effect. + kms_key_name (str): + The resource name of the Cloud KMS CryptoKey to be used to + protect access to messages published on this topic. + + The expected format is + ``projects/*/locations/*/keyRings/*/cryptoKeys/*``. + schema_settings (google.pubsub_v1.types.SchemaSettings): + Settings for validating messages published + against a schema. + satisfies_pzs (bool): + Reserved for future use. This field is set + only in responses from the server; it is ignored + if it is set in any requests. + message_retention_duration (google.protobuf.duration_pb2.Duration): + Indicates the minimum duration to retain a message after it + is published to the topic. If this field is set, messages + published to the topic in the last + ``message_retention_duration`` are always available to + subscribers. For instance, it allows any attached + subscription to `seek to a + timestamp `__ + that is up to ``message_retention_duration`` in the past. If + this field is not set, message retention is controlled by + settings on individual subscriptions. Cannot be more than 7 + days or less than 10 minutes. + """ + + name = proto.Field( + proto.STRING, + number=1, + ) + labels = proto.MapField( + proto.STRING, + proto.STRING, + number=2, + ) + message_storage_policy = proto.Field( + proto.MESSAGE, + number=3, + message="MessageStoragePolicy", + ) + kms_key_name = proto.Field( + proto.STRING, + number=5, + ) + schema_settings = proto.Field( + proto.MESSAGE, + number=6, + message="SchemaSettings", + ) + satisfies_pzs = proto.Field( + proto.BOOL, + number=7, + ) + message_retention_duration = proto.Field( + proto.MESSAGE, + number=8, + message=duration_pb2.Duration, + ) + + +class PubsubMessage(proto.Message): + r"""A message that is published by publishers and consumed by + subscribers. The message must contain either a non-empty data field + or at least one attribute. Note that client libraries represent this + object differently depending on the language. See the corresponding + `client library + documentation `__ + for more information. See [quotas and limits] + (https://cloud.google.com/pubsub/quotas) for more information about + message limits. + + Attributes: + data (bytes): + The message data field. If this field is + empty, the message must contain at least one + attribute. + attributes (Mapping[str, str]): + Attributes for this message. If this field is + empty, the message must contain non-empty data. + This can be used to filter messages on the + subscription. + message_id (str): + ID of this message, assigned by the server when the message + is published. Guaranteed to be unique within the topic. This + value may be read by a subscriber that receives a + ``PubsubMessage`` via a ``Pull`` call or a push delivery. It + must not be populated by the publisher in a ``Publish`` + call. + publish_time (google.protobuf.timestamp_pb2.Timestamp): + The time at which the message was published, populated by + the server when it receives the ``Publish`` call. It must + not be populated by the publisher in a ``Publish`` call. + ordering_key (str): + If non-empty, identifies related messages for which publish + order should be respected. If a ``Subscription`` has + ``enable_message_ordering`` set to ``true``, messages + published with the same non-empty ``ordering_key`` value + will be delivered to subscribers in the order in which they + are received by the Pub/Sub system. All ``PubsubMessage``\ s + published in a given ``PublishRequest`` must specify the + same ``ordering_key`` value. + """ + + data = proto.Field( + proto.BYTES, + number=1, + ) + attributes = proto.MapField( + proto.STRING, + proto.STRING, + number=2, + ) + message_id = proto.Field( + proto.STRING, + number=3, + ) + publish_time = proto.Field( + proto.MESSAGE, + number=4, + message=timestamp_pb2.Timestamp, + ) + ordering_key = proto.Field( + proto.STRING, + number=5, + ) + + +class GetTopicRequest(proto.Message): + r"""Request for the GetTopic method. + + Attributes: + topic (str): + Required. The name of the topic to get. Format is + ``projects/{project}/topics/{topic}``. + """ + + topic = proto.Field( + proto.STRING, + number=1, + ) + + +class UpdateTopicRequest(proto.Message): + r"""Request for the UpdateTopic method. + + Attributes: + topic (google.pubsub_v1.types.Topic): + Required. The updated topic object. + update_mask (google.protobuf.field_mask_pb2.FieldMask): + Required. Indicates which fields in the provided topic to + update. Must be specified and non-empty. Note that if + ``update_mask`` contains "message_storage_policy" but the + ``message_storage_policy`` is not set in the ``topic`` + provided above, then the updated value is determined by the + policy configured at the project or organization level. + """ + + topic = proto.Field( + proto.MESSAGE, + number=1, + message="Topic", + ) + update_mask = proto.Field( + proto.MESSAGE, + number=2, + message=field_mask_pb2.FieldMask, + ) + + +class PublishRequest(proto.Message): + r"""Request for the Publish method. + + Attributes: + topic (str): + Required. The messages in the request will be published on + this topic. Format is ``projects/{project}/topics/{topic}``. + messages (Sequence[google.pubsub_v1.types.PubsubMessage]): + Required. The messages to publish. + """ + + topic = proto.Field( + proto.STRING, + number=1, + ) + messages = proto.RepeatedField( + proto.MESSAGE, + number=2, + message="PubsubMessage", + ) + + +class PublishResponse(proto.Message): + r"""Response for the ``Publish`` method. + + Attributes: + message_ids (Sequence[str]): + The server-assigned ID of each published + message, in the same order as the messages in + the request. IDs are guaranteed to be unique + within the topic. + """ + + message_ids = proto.RepeatedField( + proto.STRING, + number=1, + ) + + +class ListTopicsRequest(proto.Message): + r"""Request for the ``ListTopics`` method. + + Attributes: + project (str): + Required. The name of the project in which to list topics. + Format is ``projects/{project-id}``. + page_size (int): + Maximum number of topics to return. + page_token (str): + The value returned by the last ``ListTopicsResponse``; + indicates that this is a continuation of a prior + ``ListTopics`` call, and that the system should return the + next page of data. + """ + + project = proto.Field( + proto.STRING, + number=1, + ) + page_size = proto.Field( + proto.INT32, + number=2, + ) + page_token = proto.Field( + proto.STRING, + number=3, + ) + + +class ListTopicsResponse(proto.Message): + r"""Response for the ``ListTopics`` method. + + Attributes: + topics (Sequence[google.pubsub_v1.types.Topic]): + The resulting topics. + next_page_token (str): + If not empty, indicates that there may be more topics that + match the request; this value should be passed in a new + ``ListTopicsRequest``. + """ + + @property + def raw_page(self): + return self + + topics = proto.RepeatedField( + proto.MESSAGE, + number=1, + message="Topic", + ) + next_page_token = proto.Field( + proto.STRING, + number=2, + ) + + +class ListTopicSubscriptionsRequest(proto.Message): + r"""Request for the ``ListTopicSubscriptions`` method. + + Attributes: + topic (str): + Required. The name of the topic that subscriptions are + attached to. Format is + ``projects/{project}/topics/{topic}``. + page_size (int): + Maximum number of subscription names to + return. + page_token (str): + The value returned by the last + ``ListTopicSubscriptionsResponse``; indicates that this is a + continuation of a prior ``ListTopicSubscriptions`` call, and + that the system should return the next page of data. + """ + + topic = proto.Field( + proto.STRING, + number=1, + ) + page_size = proto.Field( + proto.INT32, + number=2, + ) + page_token = proto.Field( + proto.STRING, + number=3, + ) + + +class ListTopicSubscriptionsResponse(proto.Message): + r"""Response for the ``ListTopicSubscriptions`` method. + + Attributes: + subscriptions (Sequence[str]): + The names of subscriptions attached to the + topic specified in the request. + next_page_token (str): + If not empty, indicates that there may be more subscriptions + that match the request; this value should be passed in a new + ``ListTopicSubscriptionsRequest`` to get more subscriptions. + """ + + @property + def raw_page(self): + return self + + subscriptions = proto.RepeatedField( + proto.STRING, + number=1, + ) + next_page_token = proto.Field( + proto.STRING, + number=2, + ) + + +class ListTopicSnapshotsRequest(proto.Message): + r"""Request for the ``ListTopicSnapshots`` method. + + Attributes: + topic (str): + Required. The name of the topic that snapshots are attached + to. Format is ``projects/{project}/topics/{topic}``. + page_size (int): + Maximum number of snapshot names to return. + page_token (str): + The value returned by the last + ``ListTopicSnapshotsResponse``; indicates that this is a + continuation of a prior ``ListTopicSnapshots`` call, and + that the system should return the next page of data. + """ + + topic = proto.Field( + proto.STRING, + number=1, + ) + page_size = proto.Field( + proto.INT32, + number=2, + ) + page_token = proto.Field( + proto.STRING, + number=3, + ) + + +class ListTopicSnapshotsResponse(proto.Message): + r"""Response for the ``ListTopicSnapshots`` method. + + Attributes: + snapshots (Sequence[str]): + The names of the snapshots that match the + request. + next_page_token (str): + If not empty, indicates that there may be more snapshots + that match the request; this value should be passed in a new + ``ListTopicSnapshotsRequest`` to get more snapshots. + """ + + @property + def raw_page(self): + return self + + snapshots = proto.RepeatedField( + proto.STRING, + number=1, + ) + next_page_token = proto.Field( + proto.STRING, + number=2, + ) + + +class DeleteTopicRequest(proto.Message): + r"""Request for the ``DeleteTopic`` method. + + Attributes: + topic (str): + Required. Name of the topic to delete. Format is + ``projects/{project}/topics/{topic}``. + """ + + topic = proto.Field( + proto.STRING, + number=1, + ) + + +class DetachSubscriptionRequest(proto.Message): + r"""Request for the DetachSubscription method. + + Attributes: + subscription (str): + Required. The subscription to detach. Format is + ``projects/{project}/subscriptions/{subscription}``. + """ + + subscription = proto.Field( + proto.STRING, + number=1, + ) + + +class DetachSubscriptionResponse(proto.Message): + r"""Response for the DetachSubscription method. + Reserved for future use. + + """ + + +class Subscription(proto.Message): + r"""A subscription resource. + + Attributes: + name (str): + Required. The name of the subscription. It must have the + format + ``"projects/{project}/subscriptions/{subscription}"``. + ``{subscription}`` must start with a letter, and contain + only letters (``[A-Za-z]``), numbers (``[0-9]``), dashes + (``-``), underscores (``_``), periods (``.``), tildes + (``~``), plus (``+``) or percent signs (``%``). It must be + between 3 and 255 characters in length, and it must not + start with ``"goog"``. + topic (str): + Required. The name of the topic from which this subscription + is receiving messages. Format is + ``projects/{project}/topics/{topic}``. The value of this + field will be ``_deleted-topic_`` if the topic has been + deleted. + push_config (google.pubsub_v1.types.PushConfig): + If push delivery is used with this subscription, this field + is used to configure it. Either ``pushConfig`` or + ``bigQueryConfig`` can be set, but not both. If both are + empty, then the subscriber will pull and ack messages using + API methods. + bigquery_config (google.pubsub_v1.types.BigQueryConfig): + If delivery to BigQuery is used with this subscription, this + field is used to configure it. Either ``pushConfig`` or + ``bigQueryConfig`` can be set, but not both. If both are + empty, then the subscriber will pull and ack messages using + API methods. + ack_deadline_seconds (int): + The approximate amount of time (on a best-effort basis) + Pub/Sub waits for the subscriber to acknowledge receipt + before resending the message. In the interval after the + message is delivered and before it is acknowledged, it is + considered to be outstanding. During that time period, the + message will not be redelivered (on a best-effort basis). + + For pull subscriptions, this value is used as the initial + value for the ack deadline. To override this value for a + given message, call ``ModifyAckDeadline`` with the + corresponding ``ack_id`` if using non-streaming pull or send + the ``ack_id`` in a ``StreamingModifyAckDeadlineRequest`` if + using streaming pull. The minimum custom deadline you can + specify is 10 seconds. The maximum custom deadline you can + specify is 600 seconds (10 minutes). If this parameter is 0, + a default value of 10 seconds is used. + + For push delivery, this value is also used to set the + request timeout for the call to the push endpoint. + + If the subscriber never acknowledges the message, the + Pub/Sub system will eventually redeliver the message. + retain_acked_messages (bool): + Indicates whether to retain acknowledged messages. If true, + then messages are not expunged from the subscription's + backlog, even if they are acknowledged, until they fall out + of the ``message_retention_duration`` window. This must be + true if you would like to [``Seek`` to a timestamp] + (https://cloud.google.com/pubsub/docs/replay-overview#seek_to_a_time) + in the past to replay previously-acknowledged messages. + message_retention_duration (google.protobuf.duration_pb2.Duration): + How long to retain unacknowledged messages in the + subscription's backlog, from the moment a message is + published. If ``retain_acked_messages`` is true, then this + also configures the retention of acknowledged messages, and + thus configures how far back in time a ``Seek`` can be done. + Defaults to 7 days. Cannot be more than 7 days or less than + 10 minutes. + labels (Mapping[str, str]): + See + Creating and managing labels. + enable_message_ordering (bool): + If true, messages published with the same ``ordering_key`` + in ``PubsubMessage`` will be delivered to the subscribers in + the order in which they are received by the Pub/Sub system. + Otherwise, they may be delivered in any order. + expiration_policy (google.pubsub_v1.types.ExpirationPolicy): + A policy that specifies the conditions for this + subscription's expiration. A subscription is considered + active as long as any connected subscriber is successfully + consuming messages from the subscription or is issuing + operations on the subscription. If ``expiration_policy`` is + not set, a *default policy* with ``ttl`` of 31 days will be + used. The minimum allowed value for + ``expiration_policy.ttl`` is 1 day. + filter (str): + An expression written in the Pub/Sub `filter + language `__. + If non-empty, then only ``PubsubMessage``\ s whose + ``attributes`` field matches the filter are delivered on + this subscription. If empty, then no messages are filtered + out. + dead_letter_policy (google.pubsub_v1.types.DeadLetterPolicy): + A policy that specifies the conditions for dead lettering + messages in this subscription. If dead_letter_policy is not + set, dead lettering is disabled. + + The Cloud Pub/Sub service account associated with this + subscriptions's parent project (i.e., + service-{project_number}@gcp-sa-pubsub.iam.gserviceaccount.com) + must have permission to Acknowledge() messages on this + subscription. + retry_policy (google.pubsub_v1.types.RetryPolicy): + A policy that specifies how Pub/Sub retries + message delivery for this subscription. + + If not set, the default retry policy is applied. + This generally implies that messages will be + retried as soon as possible for healthy + subscribers. RetryPolicy will be triggered on + NACKs or acknowledgement deadline exceeded + events for a given message. + detached (bool): + Indicates whether the subscription is detached from its + topic. Detached subscriptions don't receive messages from + their topic and don't retain any backlog. ``Pull`` and + ``StreamingPull`` requests will return FAILED_PRECONDITION. + If the subscription is a push subscription, pushes to the + endpoint will not be made. + enable_exactly_once_delivery (bool): + If true, Pub/Sub provides the following guarantees for the + delivery of a message with a given value of ``message_id`` + on this subscription: + + - The message sent to a subscriber is guaranteed not to be + resent before the message's acknowledgement deadline + expires. + - An acknowledged message will not be resent to a + subscriber. + + Note that subscribers may still receive multiple copies of a + message when ``enable_exactly_once_delivery`` is true if the + message was published multiple times by a publisher client. + These copies are considered distinct by Pub/Sub and have + distinct ``message_id`` values. + topic_message_retention_duration (google.protobuf.duration_pb2.Duration): + Output only. Indicates the minimum duration for which a + message is retained after it is published to the + subscription's topic. If this field is set, messages + published to the subscription's topic in the last + ``topic_message_retention_duration`` are always available to + subscribers. See the ``message_retention_duration`` field in + ``Topic``. This field is set only in responses from the + server; it is ignored if it is set in any requests. + state (google.pubsub_v1.types.Subscription.State): + Output only. An output-only field indicating + whether or not the subscription can receive + messages. + """ + + class State(proto.Enum): + r"""Possible states for a subscription.""" + STATE_UNSPECIFIED = 0 + ACTIVE = 1 + RESOURCE_ERROR = 2 + + name = proto.Field( + proto.STRING, + number=1, + ) + topic = proto.Field( + proto.STRING, + number=2, + ) + push_config = proto.Field( + proto.MESSAGE, + number=4, + message="PushConfig", + ) + bigquery_config = proto.Field( + proto.MESSAGE, + number=18, + message="BigQueryConfig", + ) + ack_deadline_seconds = proto.Field( + proto.INT32, + number=5, + ) + retain_acked_messages = proto.Field( + proto.BOOL, + number=7, + ) + message_retention_duration = proto.Field( + proto.MESSAGE, + number=8, + message=duration_pb2.Duration, + ) + labels = proto.MapField( + proto.STRING, + proto.STRING, + number=9, + ) + enable_message_ordering = proto.Field( + proto.BOOL, + number=10, + ) + expiration_policy = proto.Field( + proto.MESSAGE, + number=11, + message="ExpirationPolicy", + ) + filter = proto.Field( + proto.STRING, + number=12, + ) + dead_letter_policy = proto.Field( + proto.MESSAGE, + number=13, + message="DeadLetterPolicy", + ) + retry_policy = proto.Field( + proto.MESSAGE, + number=14, + message="RetryPolicy", + ) + detached = proto.Field( + proto.BOOL, + number=15, + ) + enable_exactly_once_delivery = proto.Field( + proto.BOOL, + number=16, + ) + topic_message_retention_duration = proto.Field( + proto.MESSAGE, + number=17, + message=duration_pb2.Duration, + ) + state = proto.Field( + proto.ENUM, + number=19, + enum=State, + ) + + +class RetryPolicy(proto.Message): + r"""A policy that specifies how Cloud Pub/Sub retries message delivery. + + Retry delay will be exponential based on provided minimum and + maximum backoffs. https://en.wikipedia.org/wiki/Exponential_backoff. + + RetryPolicy will be triggered on NACKs or acknowledgement deadline + exceeded events for a given message. + + Retry Policy is implemented on a best effort basis. At times, the + delay between consecutive deliveries may not match the + configuration. That is, delay can be more or less than configured + backoff. + + Attributes: + minimum_backoff (google.protobuf.duration_pb2.Duration): + The minimum delay between consecutive + deliveries of a given message. Value should be + between 0 and 600 seconds. Defaults to 10 + seconds. + maximum_backoff (google.protobuf.duration_pb2.Duration): + The maximum delay between consecutive + deliveries of a given message. Value should be + between 0 and 600 seconds. Defaults to 600 + seconds. + """ + + minimum_backoff = proto.Field( + proto.MESSAGE, + number=1, + message=duration_pb2.Duration, + ) + maximum_backoff = proto.Field( + proto.MESSAGE, + number=2, + message=duration_pb2.Duration, + ) + + +class DeadLetterPolicy(proto.Message): + r"""Dead lettering is done on a best effort basis. The same + message might be dead lettered multiple times. + + If validation on any of the fields fails at subscription + creation/updation, the create/update subscription request will + fail. + + Attributes: + dead_letter_topic (str): + The name of the topic to which dead letter messages should + be published. Format is + ``projects/{project}/topics/{topic}``.The Cloud Pub/Sub + service account associated with the enclosing subscription's + parent project (i.e., + service-{project_number}@gcp-sa-pubsub.iam.gserviceaccount.com) + must have permission to Publish() to this topic. + + The operation will fail if the topic does not exist. Users + should ensure that there is a subscription attached to this + topic since messages published to a topic with no + subscriptions are lost. + max_delivery_attempts (int): + The maximum number of delivery attempts for any message. The + value must be between 5 and 100. + + The number of delivery attempts is defined as 1 + (the sum + of number of NACKs and number of times the acknowledgement + deadline has been exceeded for the message). + + A NACK is any call to ModifyAckDeadline with a 0 deadline. + Note that client libraries may automatically extend + ack_deadlines. + + This field will be honored on a best effort basis. + + If this parameter is 0, a default value of 5 is used. + """ + + dead_letter_topic = proto.Field( + proto.STRING, + number=1, + ) + max_delivery_attempts = proto.Field( + proto.INT32, + number=2, + ) + + +class ExpirationPolicy(proto.Message): + r"""A policy that specifies the conditions for resource + expiration (i.e., automatic resource deletion). + + Attributes: + ttl (google.protobuf.duration_pb2.Duration): + Specifies the "time-to-live" duration for an associated + resource. The resource expires if it is not active for a + period of ``ttl``. The definition of "activity" depends on + the type of the associated resource. The minimum and maximum + allowed values for ``ttl`` depend on the type of the + associated resource, as well. If ``ttl`` is not set, the + associated resource never expires. + """ + + ttl = proto.Field( + proto.MESSAGE, + number=1, + message=duration_pb2.Duration, + ) + + +class PushConfig(proto.Message): + r"""Configuration for a push delivery endpoint. + + .. _oneof: https://proto-plus-python.readthedocs.io/en/stable/fields.html#oneofs-mutually-exclusive-fields + + Attributes: + push_endpoint (str): + A URL locating the endpoint to which messages should be + pushed. For example, a Webhook endpoint might use + ``https://example.com/push``. + attributes (Mapping[str, str]): + Endpoint configuration attributes that can be used to + control different aspects of the message delivery. + + The only currently supported attribute is + ``x-goog-version``, which you can use to change the format + of the pushed message. This attribute indicates the version + of the data expected by the endpoint. This controls the + shape of the pushed message (i.e., its fields and metadata). + + If not present during the ``CreateSubscription`` call, it + will default to the version of the Pub/Sub API used to make + such call. If not present in a ``ModifyPushConfig`` call, + its value will not be changed. ``GetSubscription`` calls + will always return a valid version, even if the subscription + was created without this attribute. + + The only supported values for the ``x-goog-version`` + attribute are: + + - ``v1beta1``: uses the push format defined in the v1beta1 + Pub/Sub API. + - ``v1`` or ``v1beta2``: uses the push format defined in + the v1 Pub/Sub API. + + For example: + + .. raw:: html + +
attributes { "x-goog-version": "v1" } 
+ oidc_token (google.pubsub_v1.types.PushConfig.OidcToken): + If specified, Pub/Sub will generate and attach an OIDC JWT + token as an ``Authorization`` header in the HTTP request for + every pushed message. + + This field is a member of `oneof`_ ``authentication_method``. + """ + + class OidcToken(proto.Message): + r"""Contains information needed for generating an `OpenID Connect + token `__. + + Attributes: + service_account_email (str): + `Service account + email `__ + to be used for generating the OIDC token. The caller (for + CreateSubscription, UpdateSubscription, and ModifyPushConfig + RPCs) must have the iam.serviceAccounts.actAs permission for + the service account. + audience (str): + Audience to be used when generating OIDC + token. The audience claim identifies the + recipients that the JWT is intended for. The + audience value is a single case-sensitive + string. Having multiple values (array) for the + audience field is not supported. More info about + the OIDC JWT token audience here: + https://tools.ietf.org/html/rfc7519#section-4.1.3 + Note: if not specified, the Push endpoint URL + will be used. + """ + + service_account_email = proto.Field( + proto.STRING, + number=1, + ) + audience = proto.Field( + proto.STRING, + number=2, + ) + + push_endpoint = proto.Field( + proto.STRING, + number=1, + ) + attributes = proto.MapField( + proto.STRING, + proto.STRING, + number=2, + ) + oidc_token = proto.Field( + proto.MESSAGE, + number=3, + oneof="authentication_method", + message=OidcToken, + ) + + +class BigQueryConfig(proto.Message): + r"""Configuration for a BigQuery subscription. + + Attributes: + table (str): + The name of the table to which to write data, + of the form {projectId}:{datasetId}.{tableId} + use_topic_schema (bool): + When true, use the topic's schema as the + columns to write to in BigQuery, if it exists. + write_metadata (bool): + When true, write the subscription name, message_id, + publish_time, attributes, and ordering_key to additional + columns in the table. The subscription name, message_id, and + publish_time fields are put in their own columns while all + other message properties (other than data) are written to a + JSON object in the attributes column. + drop_unknown_fields (bool): + When true and use_topic_schema is true, any fields that are + a part of the topic schema that are not part of the BigQuery + table schema are dropped when writing to BigQuery. + Otherwise, the schemas must be kept in sync and any messages + with extra fields are not written and remain in the + subscription's backlog. + state (google.pubsub_v1.types.BigQueryConfig.State): + Output only. An output-only field that + indicates whether or not the subscription can + receive messages. + """ + + class State(proto.Enum): + r"""Possible states for a BigQuery subscription.""" + STATE_UNSPECIFIED = 0 + ACTIVE = 1 + PERMISSION_DENIED = 2 + NOT_FOUND = 3 + SCHEMA_MISMATCH = 4 + + table = proto.Field( + proto.STRING, + number=1, + ) + use_topic_schema = proto.Field( + proto.BOOL, + number=2, + ) + write_metadata = proto.Field( + proto.BOOL, + number=3, + ) + drop_unknown_fields = proto.Field( + proto.BOOL, + number=4, + ) + state = proto.Field( + proto.ENUM, + number=5, + enum=State, + ) + + +class ReceivedMessage(proto.Message): + r"""A message and its corresponding acknowledgment ID. + + Attributes: + ack_id (str): + This ID can be used to acknowledge the + received message. + message (google.pubsub_v1.types.PubsubMessage): + The message. + delivery_attempt (int): + The approximate number of times that Cloud Pub/Sub has + attempted to deliver the associated message to a subscriber. + + More precisely, this is 1 + (number of NACKs) + (number of + ack_deadline exceeds) for this message. + + A NACK is any call to ModifyAckDeadline with a 0 deadline. + An ack_deadline exceeds event is whenever a message is not + acknowledged within ack_deadline. Note that ack_deadline is + initially Subscription.ackDeadlineSeconds, but may get + extended automatically by the client library. + + Upon the first delivery of a given message, + ``delivery_attempt`` will have a value of 1. The value is + calculated at best effort and is approximate. + + If a DeadLetterPolicy is not set on the subscription, this + will be 0. + """ + + ack_id = proto.Field( + proto.STRING, + number=1, + ) + message = proto.Field( + proto.MESSAGE, + number=2, + message="PubsubMessage", + ) + delivery_attempt = proto.Field( + proto.INT32, + number=3, + ) + + +class GetSubscriptionRequest(proto.Message): + r"""Request for the GetSubscription method. + + Attributes: + subscription (str): + Required. The name of the subscription to get. Format is + ``projects/{project}/subscriptions/{sub}``. + """ + + subscription = proto.Field( + proto.STRING, + number=1, + ) + + +class UpdateSubscriptionRequest(proto.Message): + r"""Request for the UpdateSubscription method. + + Attributes: + subscription (google.pubsub_v1.types.Subscription): + Required. The updated subscription object. + update_mask (google.protobuf.field_mask_pb2.FieldMask): + Required. Indicates which fields in the + provided subscription to update. Must be + specified and non-empty. + """ + + subscription = proto.Field( + proto.MESSAGE, + number=1, + message="Subscription", + ) + update_mask = proto.Field( + proto.MESSAGE, + number=2, + message=field_mask_pb2.FieldMask, + ) + + +class ListSubscriptionsRequest(proto.Message): + r"""Request for the ``ListSubscriptions`` method. + + Attributes: + project (str): + Required. The name of the project in which to list + subscriptions. Format is ``projects/{project-id}``. + page_size (int): + Maximum number of subscriptions to return. + page_token (str): + The value returned by the last + ``ListSubscriptionsResponse``; indicates that this is a + continuation of a prior ``ListSubscriptions`` call, and that + the system should return the next page of data. + """ + + project = proto.Field( + proto.STRING, + number=1, + ) + page_size = proto.Field( + proto.INT32, + number=2, + ) + page_token = proto.Field( + proto.STRING, + number=3, + ) + + +class ListSubscriptionsResponse(proto.Message): + r"""Response for the ``ListSubscriptions`` method. + + Attributes: + subscriptions (Sequence[google.pubsub_v1.types.Subscription]): + The subscriptions that match the request. + next_page_token (str): + If not empty, indicates that there may be more subscriptions + that match the request; this value should be passed in a new + ``ListSubscriptionsRequest`` to get more subscriptions. + """ + + @property + def raw_page(self): + return self + + subscriptions = proto.RepeatedField( + proto.MESSAGE, + number=1, + message="Subscription", + ) + next_page_token = proto.Field( + proto.STRING, + number=2, + ) + + +class DeleteSubscriptionRequest(proto.Message): + r"""Request for the DeleteSubscription method. + + Attributes: + subscription (str): + Required. The subscription to delete. Format is + ``projects/{project}/subscriptions/{sub}``. + """ + + subscription = proto.Field( + proto.STRING, + number=1, + ) + + +class ModifyPushConfigRequest(proto.Message): + r"""Request for the ModifyPushConfig method. + + Attributes: + subscription (str): + Required. The name of the subscription. Format is + ``projects/{project}/subscriptions/{sub}``. + push_config (google.pubsub_v1.types.PushConfig): + Required. The push configuration for future deliveries. + + An empty ``pushConfig`` indicates that the Pub/Sub system + should stop pushing messages from the given subscription and + allow messages to be pulled and acknowledged - effectively + pausing the subscription if ``Pull`` or ``StreamingPull`` is + not called. + """ + + subscription = proto.Field( + proto.STRING, + number=1, + ) + push_config = proto.Field( + proto.MESSAGE, + number=2, + message="PushConfig", + ) + + +class PullRequest(proto.Message): + r"""Request for the ``Pull`` method. + + Attributes: + subscription (str): + Required. The subscription from which messages should be + pulled. Format is + ``projects/{project}/subscriptions/{sub}``. + return_immediately (bool): + Optional. If this field set to true, the system will respond + immediately even if it there are no messages available to + return in the ``Pull`` response. Otherwise, the system may + wait (for a bounded amount of time) until at least one + message is available, rather than returning no messages. + Warning: setting this field to ``true`` is discouraged + because it adversely impacts the performance of ``Pull`` + operations. We recommend that users do not set this field. + max_messages (int): + Required. The maximum number of messages to + return for this request. Must be a positive + integer. The Pub/Sub system may return fewer + than the number specified. + """ + + subscription = proto.Field( + proto.STRING, + number=1, + ) + return_immediately = proto.Field( + proto.BOOL, + number=2, + ) + max_messages = proto.Field( + proto.INT32, + number=3, + ) + + +class PullResponse(proto.Message): + r"""Response for the ``Pull`` method. + + Attributes: + received_messages (Sequence[google.pubsub_v1.types.ReceivedMessage]): + Received Pub/Sub messages. The list will be empty if there + are no more messages available in the backlog. For JSON, the + response can be entirely empty. The Pub/Sub system may + return fewer than the ``maxMessages`` requested even if + there are more messages available in the backlog. + """ + + received_messages = proto.RepeatedField( + proto.MESSAGE, + number=1, + message="ReceivedMessage", + ) + + +class ModifyAckDeadlineRequest(proto.Message): + r"""Request for the ModifyAckDeadline method. + + Attributes: + subscription (str): + Required. The name of the subscription. Format is + ``projects/{project}/subscriptions/{sub}``. + ack_ids (Sequence[str]): + Required. List of acknowledgment IDs. + ack_deadline_seconds (int): + Required. The new ack deadline with respect to the time this + request was sent to the Pub/Sub system. For example, if the + value is 10, the new ack deadline will expire 10 seconds + after the ``ModifyAckDeadline`` call was made. Specifying + zero might immediately make the message available for + delivery to another subscriber client. This typically + results in an increase in the rate of message redeliveries + (that is, duplicates). The minimum deadline you can specify + is 0 seconds. The maximum deadline you can specify is 600 + seconds (10 minutes). + """ + + subscription = proto.Field( + proto.STRING, + number=1, + ) + ack_ids = proto.RepeatedField( + proto.STRING, + number=4, + ) + ack_deadline_seconds = proto.Field( + proto.INT32, + number=3, + ) + + +class AcknowledgeRequest(proto.Message): + r"""Request for the Acknowledge method. + + Attributes: + subscription (str): + Required. The subscription whose message is being + acknowledged. Format is + ``projects/{project}/subscriptions/{sub}``. + ack_ids (Sequence[str]): + Required. The acknowledgment ID for the messages being + acknowledged that was returned by the Pub/Sub system in the + ``Pull`` response. Must not be empty. + """ + + subscription = proto.Field( + proto.STRING, + number=1, + ) + ack_ids = proto.RepeatedField( + proto.STRING, + number=2, + ) + + +class StreamingPullRequest(proto.Message): + r"""Request for the ``StreamingPull`` streaming RPC method. This request + is used to establish the initial stream as well as to stream + acknowledgements and ack deadline modifications from the client to + the server. + + Attributes: + subscription (str): + Required. The subscription for which to initialize the new + stream. This must be provided in the first request on the + stream, and must not be set in subsequent requests from + client to server. Format is + ``projects/{project}/subscriptions/{sub}``. + ack_ids (Sequence[str]): + List of acknowledgement IDs for acknowledging previously + received messages (received on this stream or a different + stream). If an ack ID has expired, the corresponding message + may be redelivered later. Acknowledging a message more than + once will not result in an error. If the acknowledgement ID + is malformed, the stream will be aborted with status + ``INVALID_ARGUMENT``. + modify_deadline_seconds (Sequence[int]): + The list of new ack deadlines for the IDs listed in + ``modify_deadline_ack_ids``. The size of this list must be + the same as the size of ``modify_deadline_ack_ids``. If it + differs the stream will be aborted with + ``INVALID_ARGUMENT``. Each element in this list is applied + to the element in the same position in + ``modify_deadline_ack_ids``. The new ack deadline is with + respect to the time this request was sent to the Pub/Sub + system. Must be >= 0. For example, if the value is 10, the + new ack deadline will expire 10 seconds after this request + is received. If the value is 0, the message is immediately + made available for another streaming or non-streaming pull + request. If the value is < 0 (an error), the stream will be + aborted with status ``INVALID_ARGUMENT``. + modify_deadline_ack_ids (Sequence[str]): + List of acknowledgement IDs whose deadline will be modified + based on the corresponding element in + ``modify_deadline_seconds``. This field can be used to + indicate that more time is needed to process a message by + the subscriber, or to make the message available for + redelivery if the processing was interrupted. + stream_ack_deadline_seconds (int): + Required. The ack deadline to use for the + stream. This must be provided in the first + request on the stream, but it can also be + updated on subsequent requests from client to + server. The minimum deadline you can specify is + 10 seconds. The maximum deadline you can specify + is 600 seconds (10 minutes). + client_id (str): + A unique identifier that is used to distinguish client + instances from each other. Only needs to be provided on the + initial request. When a stream disconnects and reconnects + for the same stream, the client_id should be set to the same + value so that state associated with the old stream can be + transferred to the new stream. The same client_id should not + be used for different client instances. + max_outstanding_messages (int): + Flow control settings for the maximum number of outstanding + messages. When there are ``max_outstanding_messages`` or + more currently sent to the streaming pull client that have + not yet been acked or nacked, the server stops sending more + messages. The sending of messages resumes once the number of + outstanding messages is less than this value. If the value + is <= 0, there is no limit to the number of outstanding + messages. This property can only be set on the initial + StreamingPullRequest. If it is set on a subsequent request, + the stream will be aborted with status ``INVALID_ARGUMENT``. + max_outstanding_bytes (int): + Flow control settings for the maximum number of outstanding + bytes. When there are ``max_outstanding_bytes`` or more + worth of messages currently sent to the streaming pull + client that have not yet been acked or nacked, the server + will stop sending more messages. The sending of messages + resumes once the number of outstanding bytes is less than + this value. If the value is <= 0, there is no limit to the + number of outstanding bytes. This property can only be set + on the initial StreamingPullRequest. If it is set on a + subsequent request, the stream will be aborted with status + ``INVALID_ARGUMENT``. + """ + + subscription = proto.Field( + proto.STRING, + number=1, + ) + ack_ids = proto.RepeatedField( + proto.STRING, + number=2, + ) + modify_deadline_seconds = proto.RepeatedField( + proto.INT32, + number=3, + ) + modify_deadline_ack_ids = proto.RepeatedField( + proto.STRING, + number=4, + ) + stream_ack_deadline_seconds = proto.Field( + proto.INT32, + number=5, + ) + client_id = proto.Field( + proto.STRING, + number=6, + ) + max_outstanding_messages = proto.Field( + proto.INT64, + number=7, + ) + max_outstanding_bytes = proto.Field( + proto.INT64, + number=8, + ) + + +class StreamingPullResponse(proto.Message): + r"""Response for the ``StreamingPull`` method. This response is used to + stream messages from the server to the client. + + Attributes: + received_messages (Sequence[google.pubsub_v1.types.ReceivedMessage]): + Received Pub/Sub messages. This will not be + empty. + acknowledge_confirmation (google.pubsub_v1.types.StreamingPullResponse.AcknowledgeConfirmation): + This field will only be set if + ``enable_exactly_once_delivery`` is set to ``true``. + modify_ack_deadline_confirmation (google.pubsub_v1.types.StreamingPullResponse.ModifyAckDeadlineConfirmation): + This field will only be set if + ``enable_exactly_once_delivery`` is set to ``true``. + subscription_properties (google.pubsub_v1.types.StreamingPullResponse.SubscriptionProperties): + Properties associated with this subscription. + """ + + class AcknowledgeConfirmation(proto.Message): + r"""Acknowledgement IDs sent in one or more previous requests to + acknowledge a previously received message. + + Attributes: + ack_ids (Sequence[str]): + Successfully processed acknowledgement IDs. + invalid_ack_ids (Sequence[str]): + List of acknowledgement IDs that were + malformed or whose acknowledgement deadline has + expired. + unordered_ack_ids (Sequence[str]): + List of acknowledgement IDs that were out of + order. + """ + + ack_ids = proto.RepeatedField( + proto.STRING, + number=1, + ) + invalid_ack_ids = proto.RepeatedField( + proto.STRING, + number=2, + ) + unordered_ack_ids = proto.RepeatedField( + proto.STRING, + number=3, + ) + + class ModifyAckDeadlineConfirmation(proto.Message): + r"""Acknowledgement IDs sent in one or more previous requests to + modify the deadline for a specific message. + + Attributes: + ack_ids (Sequence[str]): + Successfully processed acknowledgement IDs. + invalid_ack_ids (Sequence[str]): + List of acknowledgement IDs that were + malformed or whose acknowledgement deadline has + expired. + """ + + ack_ids = proto.RepeatedField( + proto.STRING, + number=1, + ) + invalid_ack_ids = proto.RepeatedField( + proto.STRING, + number=2, + ) + + class SubscriptionProperties(proto.Message): + r"""Subscription properties sent as part of the response. + + Attributes: + exactly_once_delivery_enabled (bool): + True iff exactly once delivery is enabled for + this subscription. + message_ordering_enabled (bool): + True iff message ordering is enabled for this + subscription. + """ + + exactly_once_delivery_enabled = proto.Field( + proto.BOOL, + number=1, + ) + message_ordering_enabled = proto.Field( + proto.BOOL, + number=2, + ) + + received_messages = proto.RepeatedField( + proto.MESSAGE, + number=1, + message="ReceivedMessage", + ) + acknowledge_confirmation = proto.Field( + proto.MESSAGE, + number=5, + message=AcknowledgeConfirmation, + ) + modify_ack_deadline_confirmation = proto.Field( + proto.MESSAGE, + number=3, + message=ModifyAckDeadlineConfirmation, + ) + subscription_properties = proto.Field( + proto.MESSAGE, + number=4, + message=SubscriptionProperties, + ) + + +class CreateSnapshotRequest(proto.Message): + r"""Request for the ``CreateSnapshot`` method. + + Attributes: + name (str): + Required. User-provided name for this snapshot. If the name + is not provided in the request, the server will assign a + random name for this snapshot on the same project as the + subscription. Note that for REST API requests, you must + specify a name. See the resource name rules. Format is + ``projects/{project}/snapshots/{snap}``. + subscription (str): + Required. The subscription whose backlog the snapshot + retains. Specifically, the created snapshot is guaranteed to + retain: (a) The existing backlog on the subscription. More + precisely, this is defined as the messages in the + subscription's backlog that are unacknowledged upon the + successful completion of the ``CreateSnapshot`` request; as + well as: (b) Any messages published to the subscription's + topic following the successful completion of the + CreateSnapshot request. Format is + ``projects/{project}/subscriptions/{sub}``. + labels (Mapping[str, str]): + See + Creating and managing labels. + """ + + name = proto.Field( + proto.STRING, + number=1, + ) + subscription = proto.Field( + proto.STRING, + number=2, + ) + labels = proto.MapField( + proto.STRING, + proto.STRING, + number=3, + ) + + +class UpdateSnapshotRequest(proto.Message): + r"""Request for the UpdateSnapshot method. + + Attributes: + snapshot (google.pubsub_v1.types.Snapshot): + Required. The updated snapshot object. + update_mask (google.protobuf.field_mask_pb2.FieldMask): + Required. Indicates which fields in the + provided snapshot to update. Must be specified + and non-empty. + """ + + snapshot = proto.Field( + proto.MESSAGE, + number=1, + message="Snapshot", + ) + update_mask = proto.Field( + proto.MESSAGE, + number=2, + message=field_mask_pb2.FieldMask, + ) + + +class Snapshot(proto.Message): + r"""A snapshot resource. Snapshots are used in + `Seek `__ + operations, which allow you to manage message acknowledgments in + bulk. That is, you can set the acknowledgment state of messages in + an existing subscription to the state captured by a snapshot. + + Attributes: + name (str): + The name of the snapshot. + topic (str): + The name of the topic from which this + snapshot is retaining messages. + expire_time (google.protobuf.timestamp_pb2.Timestamp): + The snapshot is guaranteed to exist up until this time. A + newly-created snapshot expires no later than 7 days from the + time of its creation. Its exact lifetime is determined at + creation by the existing backlog in the source subscription. + Specifically, the lifetime of the snapshot is + ``7 days - (age of oldest unacked message in the subscription)``. + For example, consider a subscription whose oldest unacked + message is 3 days old. If a snapshot is created from this + subscription, the snapshot -- which will always capture this + 3-day-old backlog as long as the snapshot exists -- will + expire in 4 days. The service will refuse to create a + snapshot that would expire in less than 1 hour after + creation. + labels (Mapping[str, str]): + See [Creating and managing labels] + (https://cloud.google.com/pubsub/docs/labels). + """ + + name = proto.Field( + proto.STRING, + number=1, + ) + topic = proto.Field( + proto.STRING, + number=2, + ) + expire_time = proto.Field( + proto.MESSAGE, + number=3, + message=timestamp_pb2.Timestamp, + ) + labels = proto.MapField( + proto.STRING, + proto.STRING, + number=4, + ) + + +class GetSnapshotRequest(proto.Message): + r"""Request for the GetSnapshot method. + + Attributes: + snapshot (str): + Required. The name of the snapshot to get. Format is + ``projects/{project}/snapshots/{snap}``. + """ + + snapshot = proto.Field( + proto.STRING, + number=1, + ) + + +class ListSnapshotsRequest(proto.Message): + r"""Request for the ``ListSnapshots`` method. + + Attributes: + project (str): + Required. The name of the project in which to list + snapshots. Format is ``projects/{project-id}``. + page_size (int): + Maximum number of snapshots to return. + page_token (str): + The value returned by the last ``ListSnapshotsResponse``; + indicates that this is a continuation of a prior + ``ListSnapshots`` call, and that the system should return + the next page of data. + """ + + project = proto.Field( + proto.STRING, + number=1, + ) + page_size = proto.Field( + proto.INT32, + number=2, + ) + page_token = proto.Field( + proto.STRING, + number=3, + ) + + +class ListSnapshotsResponse(proto.Message): + r"""Response for the ``ListSnapshots`` method. + + Attributes: + snapshots (Sequence[google.pubsub_v1.types.Snapshot]): + The resulting snapshots. + next_page_token (str): + If not empty, indicates that there may be more snapshot that + match the request; this value should be passed in a new + ``ListSnapshotsRequest``. + """ + + @property + def raw_page(self): + return self + + snapshots = proto.RepeatedField( + proto.MESSAGE, + number=1, + message="Snapshot", + ) + next_page_token = proto.Field( + proto.STRING, + number=2, + ) + + +class DeleteSnapshotRequest(proto.Message): + r"""Request for the ``DeleteSnapshot`` method. + + Attributes: + snapshot (str): + Required. The name of the snapshot to delete. Format is + ``projects/{project}/snapshots/{snap}``. + """ + + snapshot = proto.Field( + proto.STRING, + number=1, + ) + + +class SeekRequest(proto.Message): + r"""Request for the ``Seek`` method. + + This message has `oneof`_ fields (mutually exclusive fields). + For each oneof, at most one member field can be set at the same time. + Setting any member of the oneof automatically clears all other + members. + + .. _oneof: https://proto-plus-python.readthedocs.io/en/stable/fields.html#oneofs-mutually-exclusive-fields + + Attributes: + subscription (str): + Required. The subscription to affect. + time (google.protobuf.timestamp_pb2.Timestamp): + The time to seek to. Messages retained in the subscription + that were published before this time are marked as + acknowledged, and messages retained in the subscription that + were published after this time are marked as unacknowledged. + Note that this operation affects only those messages + retained in the subscription (configured by the combination + of ``message_retention_duration`` and + ``retain_acked_messages``). For example, if ``time`` + corresponds to a point before the message retention window + (or to a point before the system's notion of the + subscription creation time), only retained messages will be + marked as unacknowledged, and already-expunged messages will + not be restored. + + This field is a member of `oneof`_ ``target``. + snapshot (str): + The snapshot to seek to. The snapshot's topic must be the + same as that of the provided subscription. Format is + ``projects/{project}/snapshots/{snap}``. + + This field is a member of `oneof`_ ``target``. + """ + + subscription = proto.Field( + proto.STRING, + number=1, + ) + time = proto.Field( + proto.MESSAGE, + number=2, + oneof="target", + message=timestamp_pb2.Timestamp, + ) + snapshot = proto.Field( + proto.STRING, + number=3, + oneof="target", + ) + + +class SeekResponse(proto.Message): + r"""Response for the ``Seek`` method (this response is empty).""" + + +__all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/types/schema.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/types/schema.py new file mode 100644 index 000000000000..59fe3aa3e5b8 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/google/pubsub_v1/types/schema.py @@ -0,0 +1,318 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +import proto # type: ignore + + +__protobuf__ = proto.module( + package="google.pubsub.v1", + manifest={ + "SchemaView", + "Encoding", + "Schema", + "CreateSchemaRequest", + "GetSchemaRequest", + "ListSchemasRequest", + "ListSchemasResponse", + "DeleteSchemaRequest", + "ValidateSchemaRequest", + "ValidateSchemaResponse", + "ValidateMessageRequest", + "ValidateMessageResponse", + }, +) + + +class SchemaView(proto.Enum): + r"""View of Schema object fields to be returned by GetSchema and + ListSchemas. + """ + SCHEMA_VIEW_UNSPECIFIED = 0 + BASIC = 1 + FULL = 2 + + +class Encoding(proto.Enum): + r"""Possible encoding types for messages.""" + ENCODING_UNSPECIFIED = 0 + JSON = 1 + BINARY = 2 + + +class Schema(proto.Message): + r"""A schema resource. + + Attributes: + name (str): + Required. Name of the schema. Format is + ``projects/{project}/schemas/{schema}``. + type_ (google.pubsub_v1.types.Schema.Type): + The type of the schema definition. + definition (str): + The definition of the schema. This should contain a string + representing the full definition of the schema that is a + valid schema definition of the type specified in ``type``. + """ + + class Type(proto.Enum): + r"""Possible schema definition types.""" + TYPE_UNSPECIFIED = 0 + PROTOCOL_BUFFER = 1 + AVRO = 2 + + name = proto.Field( + proto.STRING, + number=1, + ) + type_ = proto.Field( + proto.ENUM, + number=2, + enum=Type, + ) + definition = proto.Field( + proto.STRING, + number=3, + ) + + +class CreateSchemaRequest(proto.Message): + r"""Request for the CreateSchema method. + + Attributes: + parent (str): + Required. The name of the project in which to create the + schema. Format is ``projects/{project-id}``. + schema (google.pubsub_v1.types.Schema): + Required. The schema object to create. + + This schema's ``name`` parameter is ignored. The schema + object returned by CreateSchema will have a ``name`` made + using the given ``parent`` and ``schema_id``. + schema_id (str): + The ID to use for the schema, which will become the final + component of the schema's resource name. + + See + https://cloud.google.com/pubsub/docs/admin#resource_names + for resource name constraints. + """ + + parent = proto.Field( + proto.STRING, + number=1, + ) + schema = proto.Field( + proto.MESSAGE, + number=2, + message="Schema", + ) + schema_id = proto.Field( + proto.STRING, + number=3, + ) + + +class GetSchemaRequest(proto.Message): + r"""Request for the GetSchema method. + + Attributes: + name (str): + Required. The name of the schema to get. Format is + ``projects/{project}/schemas/{schema}``. + view (google.pubsub_v1.types.SchemaView): + The set of fields to return in the response. If not set, + returns a Schema with ``name`` and ``type``, but not + ``definition``. Set to ``FULL`` to retrieve all fields. + """ + + name = proto.Field( + proto.STRING, + number=1, + ) + view = proto.Field( + proto.ENUM, + number=2, + enum="SchemaView", + ) + + +class ListSchemasRequest(proto.Message): + r"""Request for the ``ListSchemas`` method. + + Attributes: + parent (str): + Required. The name of the project in which to list schemas. + Format is ``projects/{project-id}``. + view (google.pubsub_v1.types.SchemaView): + The set of Schema fields to return in the response. If not + set, returns Schemas with ``name`` and ``type``, but not + ``definition``. Set to ``FULL`` to retrieve all fields. + page_size (int): + Maximum number of schemas to return. + page_token (str): + The value returned by the last ``ListSchemasResponse``; + indicates that this is a continuation of a prior + ``ListSchemas`` call, and that the system should return the + next page of data. + """ + + parent = proto.Field( + proto.STRING, + number=1, + ) + view = proto.Field( + proto.ENUM, + number=2, + enum="SchemaView", + ) + page_size = proto.Field( + proto.INT32, + number=3, + ) + page_token = proto.Field( + proto.STRING, + number=4, + ) + + +class ListSchemasResponse(proto.Message): + r"""Response for the ``ListSchemas`` method. + + Attributes: + schemas (Sequence[google.pubsub_v1.types.Schema]): + The resulting schemas. + next_page_token (str): + If not empty, indicates that there may be more schemas that + match the request; this value should be passed in a new + ``ListSchemasRequest``. + """ + + @property + def raw_page(self): + return self + + schemas = proto.RepeatedField( + proto.MESSAGE, + number=1, + message="Schema", + ) + next_page_token = proto.Field( + proto.STRING, + number=2, + ) + + +class DeleteSchemaRequest(proto.Message): + r"""Request for the ``DeleteSchema`` method. + + Attributes: + name (str): + Required. Name of the schema to delete. Format is + ``projects/{project}/schemas/{schema}``. + """ + + name = proto.Field( + proto.STRING, + number=1, + ) + + +class ValidateSchemaRequest(proto.Message): + r"""Request for the ``ValidateSchema`` method. + + Attributes: + parent (str): + Required. The name of the project in which to validate + schemas. Format is ``projects/{project-id}``. + schema (google.pubsub_v1.types.Schema): + Required. The schema object to validate. + """ + + parent = proto.Field( + proto.STRING, + number=1, + ) + schema = proto.Field( + proto.MESSAGE, + number=2, + message="Schema", + ) + + +class ValidateSchemaResponse(proto.Message): + r"""Response for the ``ValidateSchema`` method. Empty for now.""" + + +class ValidateMessageRequest(proto.Message): + r"""Request for the ``ValidateMessage`` method. + + This message has `oneof`_ fields (mutually exclusive fields). + For each oneof, at most one member field can be set at the same time. + Setting any member of the oneof automatically clears all other + members. + + .. _oneof: https://proto-plus-python.readthedocs.io/en/stable/fields.html#oneofs-mutually-exclusive-fields + + Attributes: + parent (str): + Required. The name of the project in which to validate + schemas. Format is ``projects/{project-id}``. + name (str): + Name of the schema against which to validate. + + Format is ``projects/{project}/schemas/{schema}``. + + This field is a member of `oneof`_ ``schema_spec``. + schema (google.pubsub_v1.types.Schema): + Ad-hoc schema against which to validate + + This field is a member of `oneof`_ ``schema_spec``. + message (bytes): + Message to validate against the provided ``schema_spec``. + encoding (google.pubsub_v1.types.Encoding): + The encoding expected for messages + """ + + parent = proto.Field( + proto.STRING, + number=1, + ) + name = proto.Field( + proto.STRING, + number=2, + oneof="schema_spec", + ) + schema = proto.Field( + proto.MESSAGE, + number=3, + oneof="schema_spec", + message="Schema", + ) + message = proto.Field( + proto.BYTES, + number=4, + ) + encoding = proto.Field( + proto.ENUM, + number=5, + enum="Encoding", + ) + + +class ValidateMessageResponse(proto.Message): + r"""Response for the ``ValidateMessage`` method. Empty for now.""" + + +__all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/scripts/decrypt-secrets.sh b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/scripts/decrypt-secrets.sh new file mode 100755 index 000000000000..21f6d2a26d90 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/scripts/decrypt-secrets.sh @@ -0,0 +1,46 @@ +#!/bin/bash + +# Copyright 2015 Google Inc. 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. + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +ROOT=$( dirname "$DIR" ) + +# Work from the project root. +cd $ROOT + +# Prevent it from overriding files. +# We recommend that sample authors use their own service account files and cloud project. +# In that case, they are supposed to prepare these files by themselves. +if [[ -f "testing/test-env.sh" ]] || \ + [[ -f "testing/service-account.json" ]] || \ + [[ -f "testing/client-secrets.json" ]]; then + echo "One or more target files exist, aborting." + exit 1 +fi + +# Use SECRET_MANAGER_PROJECT if set, fallback to cloud-devrel-kokoro-resources. +PROJECT_ID="${SECRET_MANAGER_PROJECT:-cloud-devrel-kokoro-resources}" + +gcloud secrets versions access latest --secret="python-docs-samples-test-env" \ + --project="${PROJECT_ID}" \ + > testing/test-env.sh +gcloud secrets versions access latest \ + --secret="python-docs-samples-service-account" \ + --project="${PROJECT_ID}" \ + > testing/service-account.json +gcloud secrets versions access latest \ + --secret="python-docs-samples-client-secrets" \ + --project="${PROJECT_ID}" \ + > testing/client-secrets.json diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/scripts/fixup_pubsub_v1_keywords.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/scripts/fixup_pubsub_v1_keywords.py new file mode 100644 index 000000000000..d1bbcedf98af --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/scripts/fixup_pubsub_v1_keywords.py @@ -0,0 +1,209 @@ +#! /usr/bin/env python3 +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# 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. +# +import argparse +import os +import libcst as cst +import pathlib +import sys +from typing import (Any, Callable, Dict, List, Sequence, Tuple) + + +def partition( + predicate: Callable[[Any], bool], + iterator: Sequence[Any] +) -> Tuple[List[Any], List[Any]]: + """A stable, out-of-place partition.""" + results = ([], []) + + for i in iterator: + results[int(predicate(i))].append(i) + + # Returns trueList, falseList + return results[1], results[0] + + +class pubsubCallTransformer(cst.CSTTransformer): + CTRL_PARAMS: Tuple[str] = ('retry', 'timeout', 'metadata') + METHOD_TO_PARAMS: Dict[str, Tuple[str]] = { + 'acknowledge': ('subscription', 'ack_ids', ), + 'create_schema': ('parent', 'schema', 'schema_id', ), + 'create_snapshot': ('name', 'subscription', 'labels', ), + 'create_subscription': ('name', 'topic', 'push_config', 'bigquery_config', 'ack_deadline_seconds', 'retain_acked_messages', 'message_retention_duration', 'labels', 'enable_message_ordering', 'expiration_policy', 'filter', 'dead_letter_policy', 'retry_policy', 'detached', 'enable_exactly_once_delivery', 'topic_message_retention_duration', 'state', ), + 'create_topic': ('name', 'labels', 'message_storage_policy', 'kms_key_name', 'schema_settings', 'satisfies_pzs', 'message_retention_duration', ), + 'delete_schema': ('name', ), + 'delete_snapshot': ('snapshot', ), + 'delete_subscription': ('subscription', ), + 'delete_topic': ('topic', ), + 'detach_subscription': ('subscription', ), + 'get_schema': ('name', 'view', ), + 'get_snapshot': ('snapshot', ), + 'get_subscription': ('subscription', ), + 'get_topic': ('topic', ), + 'list_schemas': ('parent', 'view', 'page_size', 'page_token', ), + 'list_snapshots': ('project', 'page_size', 'page_token', ), + 'list_subscriptions': ('project', 'page_size', 'page_token', ), + 'list_topics': ('project', 'page_size', 'page_token', ), + 'list_topic_snapshots': ('topic', 'page_size', 'page_token', ), + 'list_topic_subscriptions': ('topic', 'page_size', 'page_token', ), + 'modify_ack_deadline': ('subscription', 'ack_ids', 'ack_deadline_seconds', ), + 'modify_push_config': ('subscription', 'push_config', ), + 'publish': ('topic', 'messages', ), + 'pull': ('subscription', 'max_messages', 'return_immediately', ), + 'seek': ('subscription', 'time', 'snapshot', ), + 'streaming_pull': ('subscription', 'stream_ack_deadline_seconds', 'ack_ids', 'modify_deadline_seconds', 'modify_deadline_ack_ids', 'client_id', 'max_outstanding_messages', 'max_outstanding_bytes', ), + 'update_snapshot': ('snapshot', 'update_mask', ), + 'update_subscription': ('subscription', 'update_mask', ), + 'update_topic': ('topic', 'update_mask', ), + 'validate_message': ('parent', 'name', 'schema', 'message', 'encoding', ), + 'validate_schema': ('parent', 'schema', ), + 'get_iam_policy': ('resource', 'options', ), + 'set_iam_policy': ('resource', 'policy', ), + 'test_iam_permissions': ('resource', 'permissions', ), + } + + def leave_Call(self, original: cst.Call, updated: cst.Call) -> cst.CSTNode: + try: + key = original.func.attr.value + kword_params = self.METHOD_TO_PARAMS[key] + except (AttributeError, KeyError): + # Either not a method from the API or too convoluted to be sure. + return updated + + # If the existing code is valid, keyword args come after positional args. + # Therefore, all positional args must map to the first parameters. + args, kwargs = partition(lambda a: not bool(a.keyword), updated.args) + if any(k.keyword.value == "request" for k in kwargs): + # We've already fixed this file, don't fix it again. + return updated + + kwargs, ctrl_kwargs = partition( + lambda a: a.keyword.value not in self.CTRL_PARAMS, + kwargs + ) + + args, ctrl_args = args[:len(kword_params)], args[len(kword_params):] + ctrl_kwargs.extend(cst.Arg(value=a.value, keyword=cst.Name(value=ctrl)) + for a, ctrl in zip(ctrl_args, self.CTRL_PARAMS)) + + request_arg = cst.Arg( + value=cst.Dict([ + cst.DictElement( + cst.SimpleString("'{}'".format(name)), +cst.Element(value=arg.value) + ) + # Note: the args + kwargs looks silly, but keep in mind that + # the control parameters had to be stripped out, and that + # those could have been passed positionally or by keyword. + for name, arg in zip(kword_params, args + kwargs)]), + keyword=cst.Name("request") + ) + + return updated.with_changes( + args=[request_arg] + ctrl_kwargs + ) + + +def fix_files( + in_dir: pathlib.Path, + out_dir: pathlib.Path, + *, + transformer=pubsubCallTransformer(), +): + """Duplicate the input dir to the output dir, fixing file method calls. + + Preconditions: + * in_dir is a real directory + * out_dir is a real, empty directory + """ + pyfile_gen = ( + pathlib.Path(os.path.join(root, f)) + for root, _, files in os.walk(in_dir) + for f in files if os.path.splitext(f)[1] == ".py" + ) + + for fpath in pyfile_gen: + with open(fpath, 'r') as f: + src = f.read() + + # Parse the code and insert method call fixes. + tree = cst.parse_module(src) + updated = tree.visit(transformer) + + # Create the path and directory structure for the new file. + updated_path = out_dir.joinpath(fpath.relative_to(in_dir)) + updated_path.parent.mkdir(parents=True, exist_ok=True) + + # Generate the updated source file at the corresponding path. + with open(updated_path, 'w') as f: + f.write(updated.code) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser( + description="""Fix up source that uses the pubsub client library. + +The existing sources are NOT overwritten but are copied to output_dir with changes made. + +Note: This tool operates at a best-effort level at converting positional + parameters in client method calls to keyword based parameters. + Cases where it WILL FAIL include + A) * or ** expansion in a method call. + B) Calls via function or method alias (includes free function calls) + C) Indirect or dispatched calls (e.g. the method is looked up dynamically) + + These all constitute false negatives. The tool will also detect false + positives when an API method shares a name with another method. +""") + parser.add_argument( + '-d', + '--input-directory', + required=True, + dest='input_dir', + help='the input directory to walk for python files to fix up', + ) + parser.add_argument( + '-o', + '--output-directory', + required=True, + dest='output_dir', + help='the directory to output files fixed via un-flattening', + ) + args = parser.parse_args() + input_dir = pathlib.Path(args.input_dir) + output_dir = pathlib.Path(args.output_dir) + if not input_dir.is_dir(): + print( + f"input directory '{input_dir}' does not exist or is not a directory", + file=sys.stderr, + ) + sys.exit(-1) + + if not output_dir.is_dir(): + print( + f"output directory '{output_dir}' does not exist or is not a directory", + file=sys.stderr, + ) + sys.exit(-1) + + if os.listdir(output_dir): + print( + f"output directory '{output_dir}' is not empty", + file=sys.stderr, + ) + sys.exit(-1) + + fix_files(input_dir, output_dir) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/scripts/readme-gen/readme_gen.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/scripts/readme-gen/readme_gen.py new file mode 100644 index 000000000000..91b59676bfc7 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/scripts/readme-gen/readme_gen.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python + +# Copyright 2016 Google Inc +# +# 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. + +"""Generates READMEs using configuration defined in yaml.""" + +import argparse +import io +import os +import subprocess + +import jinja2 +import yaml + + +jinja_env = jinja2.Environment( + trim_blocks=True, + loader=jinja2.FileSystemLoader( + os.path.abspath(os.path.join(os.path.dirname(__file__), "templates")) + ), + autoescape=True, +) + +README_TMPL = jinja_env.get_template('README.tmpl.rst') + + +def get_help(file): + return subprocess.check_output(['python', file, '--help']).decode() + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('source') + parser.add_argument('--destination', default='README.rst') + + args = parser.parse_args() + + source = os.path.abspath(args.source) + root = os.path.dirname(source) + destination = os.path.join(root, args.destination) + + jinja_env.globals['get_help'] = get_help + + with io.open(source, 'r') as f: + config = yaml.load(f) + + # This allows get_help to execute in the right directory. + os.chdir(root) + + output = README_TMPL.render(config) + + with io.open(destination, 'w') as f: + f.write(output) + + +if __name__ == '__main__': + main() diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/scripts/readme-gen/templates/README.tmpl.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/scripts/readme-gen/templates/README.tmpl.rst new file mode 100644 index 000000000000..4fd239765b0a --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/scripts/readme-gen/templates/README.tmpl.rst @@ -0,0 +1,87 @@ +{# The following line is a lie. BUT! Once jinja2 is done with it, it will + become truth! #} +.. This file is automatically generated. Do not edit this file directly. + +{{product.name}} Python Samples +=============================================================================== + +.. image:: https://gstatic.com/cloudssh/images/open-btn.png + :target: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor={{folder}}/README.rst + + +This directory contains samples for {{product.name}}. {{product.description}} + +{{description}} + +.. _{{product.name}}: {{product.url}} + +{% if required_api_url %} +To run the sample, you need to enable the API at: {{required_api_url}} +{% endif %} + +{% if required_role %} +To run the sample, you need to have `{{required_role}}` role. +{% endif %} + +{{other_required_steps}} + +{% if setup %} +Setup +------------------------------------------------------------------------------- + +{% for section in setup %} + +{% include section + '.tmpl.rst' %} + +{% endfor %} +{% endif %} + +{% if samples %} +Samples +------------------------------------------------------------------------------- + +{% for sample in samples %} +{{sample.name}} ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +{% if not sample.hide_cloudshell_button %} +.. image:: https://gstatic.com/cloudssh/images/open-btn.png + :target: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor={{folder}}/{{sample.file}},{{folder}}/README.rst +{% endif %} + + +{{sample.description}} + +To run this sample: + +.. code-block:: bash + + $ python {{sample.file}} +{% if sample.show_help %} + + {{get_help(sample.file)|indent}} +{% endif %} + + +{% endfor %} +{% endif %} + +{% if cloud_client_library %} + +The client library +------------------------------------------------------------------------------- + +This sample uses the `Google Cloud Client Library for Python`_. +You can read the documentation for more details on API usage and use GitHub +to `browse the source`_ and `report issues`_. + +.. _Google Cloud Client Library for Python: + https://googlecloudplatform.github.io/google-cloud-python/ +.. _browse the source: + https://github.com/GoogleCloudPlatform/google-cloud-python +.. _report issues: + https://github.com/GoogleCloudPlatform/google-cloud-python/issues + +{% endif %} + +.. _Google Cloud SDK: https://cloud.google.com/sdk/ \ No newline at end of file diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/scripts/readme-gen/templates/auth.tmpl.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/scripts/readme-gen/templates/auth.tmpl.rst new file mode 100644 index 000000000000..1446b94a5e3a --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/scripts/readme-gen/templates/auth.tmpl.rst @@ -0,0 +1,9 @@ +Authentication +++++++++++++++ + +This sample requires you to have authentication setup. Refer to the +`Authentication Getting Started Guide`_ for instructions on setting up +credentials for applications. + +.. _Authentication Getting Started Guide: + https://cloud.google.com/docs/authentication/getting-started diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/scripts/readme-gen/templates/auth_api_key.tmpl.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/scripts/readme-gen/templates/auth_api_key.tmpl.rst new file mode 100644 index 000000000000..11957ce2714a --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/scripts/readme-gen/templates/auth_api_key.tmpl.rst @@ -0,0 +1,14 @@ +Authentication +++++++++++++++ + +Authentication for this service is done via an `API Key`_. To obtain an API +Key: + +1. Open the `Cloud Platform Console`_ +2. Make sure that billing is enabled for your project. +3. From the **Credentials** page, create a new **API Key** or use an existing + one for your project. + +.. _API Key: + https://developers.google.com/api-client-library/python/guide/aaa_apikeys +.. _Cloud Console: https://console.cloud.google.com/project?_ diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/scripts/readme-gen/templates/install_deps.tmpl.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/scripts/readme-gen/templates/install_deps.tmpl.rst new file mode 100644 index 000000000000..6f069c6c87a5 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/scripts/readme-gen/templates/install_deps.tmpl.rst @@ -0,0 +1,29 @@ +Install Dependencies +++++++++++++++++++++ + +#. Clone python-docs-samples and change directory to the sample directory you want to use. + + .. code-block:: bash + + $ git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git + +#. Install `pip`_ and `virtualenv`_ if you do not already have them. You may want to refer to the `Python Development Environment Setup Guide`_ for Google Cloud Platform for instructions. + + .. _Python Development Environment Setup Guide: + https://cloud.google.com/python/setup + +#. Create a virtualenv. Samples are compatible with Python 3.7+. + + .. code-block:: bash + + $ virtualenv env + $ source env/bin/activate + +#. Install the dependencies needed to run the samples. + + .. code-block:: bash + + $ pip install -r requirements.txt + +.. _pip: https://pip.pypa.io/ +.. _virtualenv: https://virtualenv.pypa.io/ diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/scripts/readme-gen/templates/install_portaudio.tmpl.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/scripts/readme-gen/templates/install_portaudio.tmpl.rst new file mode 100644 index 000000000000..5ea33d18c00c --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/scripts/readme-gen/templates/install_portaudio.tmpl.rst @@ -0,0 +1,35 @@ +Install PortAudio ++++++++++++++++++ + +Install `PortAudio`_. This is required by the `PyAudio`_ library to stream +audio from your computer's microphone. PyAudio depends on PortAudio for cross-platform compatibility, and is installed differently depending on the +platform. + +* For Mac OS X, you can use `Homebrew`_:: + + brew install portaudio + + **Note**: if you encounter an error when running `pip install` that indicates + it can't find `portaudio.h`, try running `pip install` with the following + flags:: + + pip install --global-option='build_ext' \ + --global-option='-I/usr/local/include' \ + --global-option='-L/usr/local/lib' \ + pyaudio + +* For Debian / Ubuntu Linux:: + + apt-get install portaudio19-dev python-all-dev + +* Windows may work without having to install PortAudio explicitly (it will get + installed with PyAudio). + +For more details, see the `PyAudio installation`_ page. + + +.. _PyAudio: https://people.csail.mit.edu/hubert/pyaudio/ +.. _PortAudio: http://www.portaudio.com/ +.. _PyAudio installation: + https://people.csail.mit.edu/hubert/pyaudio/#downloads +.. _Homebrew: http://brew.sh diff --git a/packages/gcp-sphinx-docfx-yaml/tests/example/format/google/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/setup.cfg similarity index 74% rename from packages/gcp-sphinx-docfx-yaml/tests/example/format/google/__init__.py rename to packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/setup.cfg index 58f06daa0467..c3a2b39f6528 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/example/format/google/__init__.py +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/setup.cfg @@ -1,10 +1,12 @@ -# Copyright 2021 Google LLC +# -*- coding: utf-8 -*- +# +# Copyright 2020 Google LLC # # 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 +# https://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, @@ -12,5 +14,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -# coding: utf-8 -# This package is used to test google style docstring. +# Generated by synthtool. DO NOT EDIT! +[bdist_wheel] +universal = 1 diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/setup.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/setup.py new file mode 100644 index 000000000000..134b4d30e1c7 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/gapic-combo/setup.py @@ -0,0 +1,95 @@ +# Copyright 2018 Google LLC +# +# 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. + +import io +import os + +import setuptools + + +# Package metadata. + +name = "google-cloud-pubsub" +description = "Google Cloud Pub/Sub API client library" +version = "2.13.10" +# Should be one of: +# 'Development Status :: 3 - Alpha' +# 'Development Status :: 4 - Beta' +# 'Development Status :: 5 - Production/Stable' +release_status = "Development Status :: 5 - Production/Stable" +dependencies = [ + "grpcio >= 1.38.1, < 2.0dev", # https://github.com/googleapis/python-pubsub/issues/414 + "google-api-core[grpc] >= 1.32.0, <3.0.0dev,!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*", + "proto-plus >= 1.22.0, <2.0.0dev", + "protobuf>=3.19.5,<5.0.0dev,!=3.20.0,!=3.20.1,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", + "grpc-google-iam-v1 >=0.12.4, <1.0.0dev", + "grpcio-status >= 1.16.0", +] +extras = {"libcst": "libcst >= 0.3.10"} + + +# Setup boilerplate below this line. + +package_root = os.path.abspath(os.path.dirname(__file__)) + +readme_filename = os.path.join(package_root, "README.rst") +with io.open(readme_filename, encoding="utf-8") as readme_file: + readme = readme_file.read() + +# Only include packages under the 'google' namespace. Do not include tests, +# benchmarks, etc. +packages = [ + package + for package in setuptools.PEP420PackageFinder.find() + if package.startswith("google") +] + +# Determine which namespaces are needed. +namespaces = ["google"] +if "google.cloud" in packages: + namespaces.append("google.cloud") + + +setuptools.setup( + name=name, + version=version, + description=description, + long_description=readme, + author="Google LLC", + author_email="googleapis-packages@google.com", + license="Apache 2.0", + url="https://github.com/googleapis/python-pubsub", + classifiers=[ + release_status, + "Intended Audience :: Developers", + "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Operating System :: OS Independent", + "Topic :: Internet", + ], + platforms="Posix; MacOS X; Windows", + packages=packages, + namespace_packages=namespaces, + install_requires=dependencies, + extras_require=extras, + python_requires=">=3.7", + scripts=["scripts/fixup_pubsub_v1_keywords.py"], + include_package_data=True, + zip_safe=False, +) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/changelog.md b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/changelog.md new file mode 100644 index 000000000000..4019c1309b9c --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/changelog.md @@ -0,0 +1,489 @@ +# Changelog + +[PyPI History](https://pypi.org/project/google-cloud-texttospeech/#history) + +## [2.12.3](https://github.com/googleapis/python-texttospeech/compare/v2.12.2...v2.12.3) (2022-10-07) + +### Bug Fixes + + +* **deps:** Allow protobuf 3.19.5 ([#338](https://github.com/googleapis/python-texttospeech/issues/338)) ([aa92121](https://github.com/googleapis/python-texttospeech/commit/aa921215c05588b6555b7b41381b30f8b0079d54)) + +## [2.12.2](https://github.com/googleapis/python-texttospeech/compare/v2.12.1...v2.12.2) (2022-10-03) + +### Bug Fixes + + +* **deps:** Require protobuf >= 3.20.2 ([#335](https://github.com/googleapis/python-texttospeech/issues/335)) ([50b394d](https://github.com/googleapis/python-texttospeech/commit/50b394dc5684b2df6cf544ba7bb5296d384ee0f8)) + +## [2.12.1](https://github.com/googleapis/python-texttospeech/compare/v2.12.0...v2.12.1) (2022-08-11) + +### Bug Fixes + + +* **deps:** allow protobuf < 5.0.0 ([#316](https://github.com/googleapis/python-texttospeech/issues/316)) ([ec75f1e](https://github.com/googleapis/python-texttospeech/commit/ec75f1e5382bd527d17fb347a7ecc7cd35f57ab0)) + + +* **deps:** require proto-plus >= 1.22.0 ([ec75f1e](https://github.com/googleapis/python-texttospeech/commit/ec75f1e5382bd527d17fb347a7ecc7cd35f57ab0)) + +## [2.12.0](https://github.com/googleapis/python-texttospeech/compare/v2.11.1...v2.12.0) (2022-07-16) + +### Features + + +* add audience parameter ([f450551](https://github.com/googleapis/python-texttospeech/commit/f450551482e52c7f5564bf735b705e22255dc5d8)) + +### Bug Fixes + + +* **deps:** require google-api-core>=1.32.0,>=2.8.0 ([#304](https://github.com/googleapis/python-texttospeech/issues/304)) ([f450551](https://github.com/googleapis/python-texttospeech/commit/f450551482e52c7f5564bf735b705e22255dc5d8)) + + +* require python 3.7+ ([#306](https://github.com/googleapis/python-texttospeech/issues/306)) ([192277b](https://github.com/googleapis/python-texttospeech/commit/192277b9b62338840b55fe8e24be582a19f390cd)) + +## [2.11.1](https://github.com/googleapis/python-texttospeech/compare/v2.11.0...v2.11.1) (2022-06-06) + +### Bug Fixes + + +* **deps:** require protobuf <4.0.0dev ([#293](https://github.com/googleapis/python-texttospeech/issues/293)) ([e5ab0d6](https://github.com/googleapis/python-texttospeech/commit/e5ab0d6b69e008653b1500742ede3ead3a748f58)) + +### Documentation + + +* fix changelog header to consistent size ([#294](https://github.com/googleapis/python-texttospeech/issues/294)) ([8a8b65c](https://github.com/googleapis/python-texttospeech/commit/8a8b65c0e4c39a5671e9998848ebb89ea38d301d)) + +## [2.11.0](https://github.com/googleapis/python-texttospeech/compare/v2.10.2...v2.11.0) (2022-03-10) + +### Features + + +* promote CustomVoiceParams to v1 ([#266](https://github.com/googleapis/python-texttospeech/issues/266)) ([f484e7f](https://github.com/googleapis/python-texttospeech/commit/f484e7fe036fe57a4f432bf30c6421a6541ea486)) + +## [2.10.2](https://github.com/googleapis/python-texttospeech/compare/v2.10.1...v2.10.2) (2022-03-05) + +### Bug Fixes + + +* **deps:** require google-api-core>=1.31.5, >=2.3.2 ([#261](https://github.com/googleapis/python-texttospeech/issues/261)) ([f993058](https://github.com/googleapis/python-texttospeech/commit/f993058b1535e8cc0c71877b8dca9beae3dffb1b)) + + +* **deps:** require proto-plus>=1.15.0 ([f993058](https://github.com/googleapis/python-texttospeech/commit/f993058b1535e8cc0c71877b8dca9beae3dffb1b)) + +## [2.10.1](https://github.com/googleapis/python-texttospeech/compare/v2.10.0...v2.10.1) (2022-02-26) + +### Documentation + + +* add generated snippets ([#249](https://github.com/googleapis/python-texttospeech/issues/249)) ([f918e82](https://github.com/googleapis/python-texttospeech/commit/f918e82df2e0c499356fa1e095b13f7ac2cd3b6b)) + +## [2.10.0](https://github.com/googleapis/python-texttospeech/compare/v2.9.1...v2.10.0) (2022-02-03) + +### Features + + +* add api key support ([#242](https://github.com/googleapis/python-texttospeech/issues/242)) ([3b4f0d0](https://github.com/googleapis/python-texttospeech/commit/3b4f0d0749529b04ed7fedec3c4b06b6d42c12cd)) + +### Bug Fixes + + +* resolve DuplicateCredentialArgs error when using credentials_file ([4c11b12](https://github.com/googleapis/python-texttospeech/commit/4c11b127ece0009082fe91062f3f36c8f18e8ffc)) + +### Documentation + + +* update comments for ListVoicesRequest ([#244](https://github.com/googleapis/python-texttospeech/issues/244)) ([bc5b73f](https://github.com/googleapis/python-texttospeech/commit/bc5b73fbc62900f89a01486c6e8d42d459c34fd6)) + +## [2.9.1](https://www.github.com/googleapis/python-texttospeech/compare/v2.9.0...v2.9.1) (2022-01-08) + +### Documentation + + +* Added virtualenv comment for clarity ([#225](https://www.github.com/googleapis/python-texttospeech/issues/225)) ([61a7fce](https://www.github.com/googleapis/python-texttospeech/commit/61a7fcec0611712cdb1692b830db4aaca4d411b0)) + + +* update comments for ListVoicesRequest ([#229](https://www.github.com/googleapis/python-texttospeech/issues/229)) ([9ea340c](https://www.github.com/googleapis/python-texttospeech/commit/9ea340cee20298630a6a15bed0ed2df9f69b3d13)) + +## [2.9.0](https://www.github.com/googleapis/python-texttospeech/compare/v2.8.0...v2.9.0) (2021-11-16) + +### Features + + +* update v1 proto ([#221](https://www.github.com/googleapis/python-texttospeech/issues/221)) ([e8776d7](https://www.github.com/googleapis/python-texttospeech/commit/e8776d7a482f495ed5ae0e1235609e3e2d3e6067)) + +## [2.8.0](https://www.github.com/googleapis/python-texttospeech/compare/v2.7.1...v2.8.0) (2021-11-13) + +### Features + + +* **v1beta1:** add CustomVoiceParams ([#215](https://www.github.com/googleapis/python-texttospeech/issues/215)) ([6a18d0f](https://www.github.com/googleapis/python-texttospeech/commit/6a18d0f097e992bd4d90eaf5032ce98aa4af004a)) + +### Documentation + + +* fix docstring formatting ([#218](https://www.github.com/googleapis/python-texttospeech/issues/218)) ([2c57f95](https://www.github.com/googleapis/python-texttospeech/commit/2c57f95a1af747b49dac41628bd43d485a68583e)) + +## [2.7.1](https://www.github.com/googleapis/python-texttospeech/compare/v2.7.0...v2.7.1) (2021-11-01) + +### Bug Fixes + + +* **deps:** drop packaging dependency ([99ac70b](https://www.github.com/googleapis/python-texttospeech/commit/99ac70ba45d7c500d0f19a30dead060c0db4453c)) + + +* **deps:** require google-api-core >= 1.28.0 ([99ac70b](https://www.github.com/googleapis/python-texttospeech/commit/99ac70ba45d7c500d0f19a30dead060c0db4453c)) + +### Documentation + + +* list oneofs in docstring ([99ac70b](https://www.github.com/googleapis/python-texttospeech/commit/99ac70ba45d7c500d0f19a30dead060c0db4453c)) + +## [2.7.0](https://www.github.com/googleapis/python-texttospeech/compare/v2.6.0...v2.7.0) (2021-10-18) + +### Features + + +* add support for python 3.10 ([#202](https://www.github.com/googleapis/python-texttospeech/issues/202)) ([2ffa70b](https://www.github.com/googleapis/python-texttospeech/commit/2ffa70b6c35707142d66476b0ef5e3bd8d6d0052)) + +## [2.6.0](https://www.github.com/googleapis/python-texttospeech/compare/v2.5.3...v2.6.0) (2021-10-07) + +### Features + + +* add context manager support in client ([#196](https://www.github.com/googleapis/python-texttospeech/issues/196)) ([73d9290](https://www.github.com/googleapis/python-texttospeech/commit/73d9290cdea69a00ba317ae017a1d07bcf734989)) + +## [2.5.3](https://www.github.com/googleapis/python-texttospeech/compare/v2.5.2...v2.5.3) (2021-09-24) + +### Bug Fixes + + +* add ‘dict’ annotation type to ‘request’ ([e74b994](https://www.github.com/googleapis/python-texttospeech/commit/e74b9942d480bf7e360bc61ff183909873fc20a6)) + +## [2.5.2](https://www.github.com/googleapis/python-texttospeech/compare/v2.5.1...v2.5.2) (2021-07-28) + +### Bug Fixes + + +* enable self signed jwt for grpc ([#171](https://www.github.com/googleapis/python-texttospeech/issues/171)) ([9c1c437](https://www.github.com/googleapis/python-texttospeech/commit/9c1c4371caa712a749b406257c09d98f6b428e7b)) + +### Documentation + + +* add Samples section to CONTRIBUTING.rst ([#166](https://www.github.com/googleapis/python-texttospeech/issues/166)) ([053abe3](https://www.github.com/googleapis/python-texttospeech/commit/053abe3afc1107bdacd164e6ca4cd60b5ca07df7)) + +### Miscellaneous Chores + + +* release as 2.5.2 ([#172](https://www.github.com/googleapis/python-texttospeech/issues/172)) ([3804727](https://www.github.com/googleapis/python-texttospeech/commit/3804727995d0357fa0c4c5c246210768e0ce7124)) + +## [2.5.1](https://www.github.com/googleapis/python-texttospeech/compare/v2.5.0...v2.5.1) (2021-07-20) + +### Bug Fixes + + +* **deps:** pin ‘google-{api,cloud}-core’, ‘google-auth’ to allow 2.x versions ([#165](https://www.github.com/googleapis/python-texttospeech/issues/165)) ([d78b384](https://www.github.com/googleapis/python-texttospeech/commit/d78b384d302a1976682f35875ce2d4f7b60d7a6c)) + +## [2.5.0](https://www.github.com/googleapis/python-texttospeech/compare/v2.4.0...v2.5.0) (2021-07-01) + +### Features + + +* add always_use_jwt_access ([#155](https://www.github.com/googleapis/python-texttospeech/issues/155)) ([cd10c37](https://www.github.com/googleapis/python-texttospeech/commit/cd10c3704db610f2abf65c9142cfdaa867d8490a)) + +### Bug Fixes + + +* disable always_use_jwt_access ([#159](https://www.github.com/googleapis/python-texttospeech/issues/159)) ([d109303](https://www.github.com/googleapis/python-texttospeech/commit/d109303898facc663a6e7fe9212440831c1eeb75)) + +### Documentation + + +* omit mention of Python 2.7 in ‘CONTRIBUTING.rst’ ([#1127](https://www.github.com/googleapis/python-texttospeech/issues/1127)) ([#150](https://www.github.com/googleapis/python-texttospeech/issues/150)) ([d2954ba](https://www.github.com/googleapis/python-texttospeech/commit/d2954ba91385db6d581f75154fb11c969f6ca0e2)), closes [#1126](https://www.github.com/googleapis/python-texttospeech/issues/1126) + +## [2.4.0](https://www.github.com/googleapis/python-texttospeech/compare/v2.3.0...v2.4.0) (2021-05-28) + +### Features + + +* support self-signed JWT flow for service accounts ([8a08836](https://www.github.com/googleapis/python-texttospeech/commit/8a08836487c1b7e4e58d3c07a4e26005d40793f0)) + +### Bug Fixes + + +* add async client to %name_%version/init.py ([8a08836](https://www.github.com/googleapis/python-texttospeech/commit/8a08836487c1b7e4e58d3c07a4e26005d40793f0)) + +## [2.3.0](https://www.github.com/googleapis/python-texttospeech/compare/v2.2.0...v2.3.0) (2021-03-31) + +### Features + + +* add `from_service_account_info` to clients ([139e6e8](https://www.github.com/googleapis/python-texttospeech/commit/139e6e8511cdce4c0be7983520f7efc47092f3b1)) + + +* Add ALAW support on client library and improve the ListVoiceRequest message’s documentation ([#113](https://www.github.com/googleapis/python-texttospeech/issues/113)) ([8bbd380](https://www.github.com/googleapis/python-texttospeech/commit/8bbd38014fe796b30f4b12ae9432d3a05c130063)) + + +* add common resource helper methods ([139e6e8](https://www.github.com/googleapis/python-texttospeech/commit/139e6e8511cdce4c0be7983520f7efc47092f3b1)) + + +* support custom client info ([#82](https://www.github.com/googleapis/python-texttospeech/issues/82)) ([0612793](https://www.github.com/googleapis/python-texttospeech/commit/06127932a920f6318db8f25d6430755b35d09bb5)) + +### Bug Fixes + + +* change default retry and timeout settings ([139e6e8](https://www.github.com/googleapis/python-texttospeech/commit/139e6e8511cdce4c0be7983520f7efc47092f3b1)) + +### Documentation + + +* use sphinx-1.5.5 for sphinx-docfx-yaml ([#89](https://www.github.com/googleapis/python-texttospeech/issues/89)) ([feb04c5](https://www.github.com/googleapis/python-texttospeech/commit/feb04c50b56c2c3359b92d8b5887c8ee50be2b95)) + +## [2.2.0](https://www.github.com/googleapis/python-texttospeech/compare/v2.1.0...v2.2.0) (2020-08-10) + +### Features + + +* incorporate upstream changes ([#73](https://www.github.com/googleapis/python-texttospeech/issues/73)) ([8ee5447](https://www.github.com/googleapis/python-texttospeech/commit/8ee544740f18497d9925bcf77e5ab96695503589)) + + + * support MULAW audio encoding + + + * support MP3_64_KBPS audio encoding + + + * support timepointing via SSML tag + + + * support quota_project_id + +## [2.1.0](https://www.github.com/googleapis/python-texttospeech/compare/v2.0.0...v2.1.0) (2020-06-20) + +### Features + + +* add async client ([#53](https://www.github.com/googleapis/python-texttospeech/issues/53)) ([887d8d5](https://www.github.com/googleapis/python-texttospeech/commit/887d8d501ce9255fee44170b5fc40ebfb1ea953d)) + +### Documentation + + +* change relative URLs to absolute URLs to fix broken links ([#40](https://www.github.com/googleapis/python-texttospeech/issues/40)) ([b68df44](https://www.github.com/googleapis/python-texttospeech/commit/b68df446daa7983cad1d31553ece6df569c932b2)) + +## [2.0.0](https://www.github.com/googleapis/python-texttospeech/compare/v1.0.1...v2.0.0) (2020-06-01) + +### ⚠ BREAKING CHANGES + + +* This release has breaking changes. See the [2.0.0 Migration Guide](https://github.com/googleapis/python-texttospeech/blob/main/UPGRADING.md#200-migration-guide) for details. + +### Features + + +* regenerate with microgenerator ([#30](https://www.github.com/googleapis/python-texttospeech/issues/30)) ([3181b55](https://www.github.com/googleapis/python-texttospeech/commit/3181b55733da7aecde37009a0dd77117434deceb)) + +### Bug Fixes + + +* address PR comments ([65f903b](https://www.github.com/googleapis/python-texttospeech/commit/65f903b00395716fad272ca4fc973755735e1e20)) + +## [1.0.1](https://www.github.com/googleapis/python-texttospeech/compare/v1.0.0...v1.0.1) (2020-02-28) + +### Bug Fixes + + +* update url in setup.py ([#13](https://www.github.com/googleapis/python-texttospeech/issues/13)) ([dc17707](https://www.github.com/googleapis/python-texttospeech/commit/dc17707c41feb885d94f1045ef14e4b9e0898716)) + +## [1.0.0](https://www.github.com/googleapis/python-texttospeech/compare/v0.5.0...v1.0.0) (2020-02-28) + +### Features + + +* bump release status to GA ([#9](https://www.github.com/googleapis/python-texttospeech/issues/9)) ([03a639e](https://www.github.com/googleapis/python-texttospeech/commit/03a639e16256d9211c1fe88991440f2cc22eccd6)) + +## 0.5.0 + +07-24-2019 17:48 PDT + +### Implementation Changes + + +* Allow kwargs to be passed to create_channel (via synth). ([#8407](https://github.com/googleapis/google-cloud-python/pull/8407)) + + +* Reformat protos, update nox session docs (via synth). ([#7941](https://github.com/googleapis/google-cloud-python/pull/7941)) + + +* Remove classifier for Python 3.4 for end-of-life. ([#7535](https://github.com/googleapis/google-cloud-python/pull/7535)) + +### New Features + + +* Add ‘client_options’ support (via synth). ([#8525](https://github.com/googleapis/google-cloud-python/pull/8525)) + +### Dependencies + + +* Bump minimum version for google-api-core to 1.14.0. ([#8709](https://github.com/googleapis/google-cloud-python/pull/8709)) + +### Documentation + + +* Link to googleapis.dev documentation in READMEs. ([#8705](https://github.com/googleapis/google-cloud-python/pull/8705)) + + +* Add compatibility check badges to READMEs. ([#8288](https://github.com/googleapis/google-cloud-python/pull/8288)) + + +* Repair top-level API reference page. ([#8435](https://github.com/googleapis/google-cloud-python/pull/8435)) + + +* Updated client library documentation URLs. ([#7307](https://github.com/googleapis/google-cloud-python/pull/7307)) + +### Internal / Testing Changes + + +* Pin black version (via synth). ([#8599](https://github.com/googleapis/google-cloud-python/pull/8599)) + + +* Add docs job to publish to googleapis.dev. ([#8464](https://github.com/googleapis/google-cloud-python/pull/8464)) + + +* Declare encoding as utf-8 in pb2 files (via synth). ([#8367](https://github.com/googleapis/google-cloud-python/pull/8367)) + + +* Add disclaimer to auto-generated template files (via synth). ([#8331](https://github.com/googleapis/google-cloud-python/pull/8331)) + + +* Blacken (via synth). ([#8281](https://github.com/googleapis/google-cloud-python/pull/8281)) + +## 0.4.0 + +02-07-2019 15:21 PST + +### Implementation Changes + + +* Pick up stub docstring fix in GAPIC generator. ([#6984](https://github.com/googleapis/google-cloud-python/pull/6984)) + +### New Features + + +* Protoc updates to include effects_profile_id. ([#7097](https://github.com/googleapis/google-cloud-python/pull/7097)) + +### Documentation + + +* Fix `Client Library Documentation` link ([#7109](https://github.com/googleapis/google-cloud-python/pull/7109)) + +### Internal / Testing Changes + + +* Copy proto files alongside protoc versions. + + +* Add protos as an artifact to library ([#7205](https://github.com/googleapis/google-cloud-python/pull/7205)) + + +* Update copyright headers and docstring quoting + +## 0.3.0 + +12-18-2018 09:54 PST + +### Implementation Changes + + +* Import `iam.policy` from `google.api_core`. ([#6741](https://github.com/googleapis/google-cloud-python/pull/6741)) + + +* Pick up fixes to GAPIC generator. ([#6510](https://github.com/googleapis/google-cloud-python/pull/6510)) + + +* Fix `client_info` bug, update docstrings. ([#6423](https://github.com/googleapis/google-cloud-python/pull/6423)) + + +* Re-generate library using texttospeech/synth.py ([#5981](https://github.com/googleapis/google-cloud-python/pull/5981)) + + +* Add gRPC Transport layer. ([#5959](https://github.com/googleapis/google-cloud-python/pull/5959)) + +### Dependencies + + +* Bump minimum `api_core` version for all GAPIC libs to 1.4.1. ([#6391](https://github.com/googleapis/google-cloud-python/pull/6391)) + + +* Avoid broken ‘google-common-apis 1.5.4’ release. ([#6355](https://github.com/googleapis/google-cloud-python/pull/6355)) + +### Documentation + + +* Document Python 2 deprecation ([#6910](https://github.com/googleapis/google-cloud-python/pull/6910)) + + +* Docs: normalize use of support level badges ([#6159](https://github.com/googleapis/google-cloud-python/pull/6159)) + + +* Docs: Replace links to `/stable/` with `/latest/`. ([#5901](https://github.com/googleapis/google-cloud-python/pull/5901)) + + +* Fix docs links for TTS. ([#5483](https://github.com/googleapis/google-cloud-python/pull/5483)) + +### Internal / Testing Changes + + +* Add synth.metadata. ([#6870](https://github.com/googleapis/google-cloud-python/pull/6870)) + + +* Update noxfile. + + +* blacken all gen’d libs ([#6792](https://github.com/googleapis/google-cloud-python/pull/6792)) + + +* omit local deps ([#6701](https://github.com/googleapis/google-cloud-python/pull/6701)) + + +* Run black at end of synth.py ([#6698](https://github.com/googleapis/google-cloud-python/pull/6698)) + + +* Run Black on Generated libraries ([#6666](https://github.com/googleapis/google-cloud-python/pull/6666)) + + +* Add templates for flake8, coveragerc, noxfile, and black. ([#6642](https://github.com/googleapis/google-cloud-python/pull/6642)) + + +* Add ‘mock’ to unit test dependencies for autogen libs. ([#6402](https://github.com/googleapis/google-cloud-python/pull/6402)) + + +* Add / fix badges for PyPI / versions. ([#6158](https://github.com/googleapis/google-cloud-python/pull/6158)) + + +* Use new Nox ([#6175](https://github.com/googleapis/google-cloud-python/pull/6175)) + +## 0.2.0 + +### New Features + + +* Add the text-to-speech v1 API surface. (#5468) + + +* Re-generate the text-to-speech v1beta1 API surface. (#5468) + +### Documentation + + +* Rename releases to changelog and include from CHANGELOG.md (#5191) + +### Internal / Testing Changes + + +* Add Test runs for Python 3.7 and remove 3.4 (#5295) + +## 0.1.0 + +### Interface additions + + +* Added text-to-speech v1beta1. (#5049) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.yml new file mode 100644 index 000000000000..f88b9e128547 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.yml @@ -0,0 +1,846 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: [] + children: + - google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + - google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.common_billing_account_path + - google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.common_folder_path + - google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.common_location_path + - google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.common_organization_path + - google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.common_project_path + - google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.from_service_account_file + - google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.from_service_account_info + - google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.from_service_account_json + - google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.get_mtls_endpoint_and_cert_source + - google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.get_transport_class + - google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.list_voices + - google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.model_path + - google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_billing_account_path + - google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_folder_path + - google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_location_path + - google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_organization_path + - google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_project_path + - google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.parse_model_path + - google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.synthesize_speech + - google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.transport + class: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + inheritance: + - type: builtins.object + langs: + - python + module: google.cloud.texttospeech_v1.services.text_to_speech + name: TextToSpeechAsyncClient + source: + id: TextToSpeechAsyncClient + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/async_client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/async_client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 41 + summary: 'Service that implements Google Cloud Text-to-Speech API. + + + ' + syntax: + content: 'TextToSpeechAsyncClient(*, credentials: typing.Optional[google.auth.credentials.Credentials] + = None, transport: typing.Union[str, google.cloud.texttospeech_v1.services.text_to_speech.transports.base.TextToSpeechTransport] + = ''grpc_asyncio'', client_options: typing.Optional[google.api_core.client_options.ClientOptions] + = None, client_info: google.api_core.gapic_v1.client_info.ClientInfo = )' + parameters: [] + type: class + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient +- attributes: [] + class: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + inheritance: + - type: builtins.object + langs: + - python + module: google.cloud.texttospeech_v1.services.text_to_speech + name: TextToSpeechAsyncClient + source: + id: TextToSpeechAsyncClient + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/async_client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/async_client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 41 + summary: 'Instantiates the text to speech client. + + ' + syntax: + content: 'TextToSpeechAsyncClient(*, credentials: typing.Optional[google.auth.credentials.Credentials] + = None, transport: typing.Union[str, google.cloud.texttospeech_v1.services.text_to_speech.transports.base.TextToSpeechTransport] + = ''grpc_asyncio'', client_options: typing.Optional[google.api_core.client_options.ClientOptions] + = None, client_info: google.api_core.gapic_v1.client_info.ClientInfo = )' + exceptions: + - description: If mutual TLS transport creation failed for any reason. + var_type: google.auth.exceptions.MutualTlsChannelError + parameters: + - description: The authorization credentials to attach to requests. These credentials + identify the application to the service; if none are specified, the client + will attempt to ascertain the credentials from the environment. + id: credentials + var_type: Optional[google.auth.credentials.Credentials] + - description: The transport to use. If set to None, a transport is chosen automatically. + id: transport + var_type: Union[str, .TextToSpeechTransport] + - description: 'Custom options for the client. It won''t take effect if a transport + instance is provided. (1) The api_endpoint property can be used + to override the default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT + environment variable can also be used to override the endpoint: "always" (always + use the default mTLS endpoint), "never" (always use the default regular endpoint) + and "auto" (auto switch to the default mTLS endpoint if client certificate + is present, this is the default value). However, the api_endpoint + property takes precedence if provided. (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE + environment variable is "true", then the client_cert_source property + can be used to provide client certificate for mutual TLS transport. If not + provided, the default SSL client certificate will be used if present. If GOOGLE_API_USE_CLIENT_CERTIFICATE + is "false" or not set, no client certificate will be used.' + id: client_options + var_type: ClientOptions + type: method + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient +- attributes: [] + class: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.common_billing_account_path + langs: + - python + module: google.cloud.texttospeech_v1.services.text_to_speech + name: common_billing_account_path + source: + id: common_billing_account_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 185 + summary: 'Returns a fully-qualified billing_account string. + + + ' + syntax: + content: 'common_billing_account_path(billing_account: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.common_billing_account_path +- attributes: [] + class: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.common_folder_path + langs: + - python + module: google.cloud.texttospeech_v1.services.text_to_speech + name: common_folder_path + source: + id: common_folder_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 200 + summary: 'Returns a fully-qualified folder string. + + + ' + syntax: + content: 'common_folder_path(folder: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.common_folder_path +- attributes: [] + class: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.common_location_path + langs: + - python + module: google.cloud.texttospeech_v1.services.text_to_speech + name: common_location_path + source: + id: common_location_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 245 + summary: 'Returns a fully-qualified location string. + + + ' + syntax: + content: 'common_location_path(project: str, location: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.common_location_path +- attributes: [] + class: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.common_organization_path + langs: + - python + module: google.cloud.texttospeech_v1.services.text_to_speech + name: common_organization_path + source: + id: common_organization_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 215 + summary: 'Returns a fully-qualified organization string. + + + ' + syntax: + content: 'common_organization_path(organization: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.common_organization_path +- attributes: [] + class: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.common_project_path + langs: + - python + module: google.cloud.texttospeech_v1.services.text_to_speech + name: common_project_path + source: + id: common_project_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 230 + summary: 'Returns a fully-qualified project string. + + + ' + syntax: + content: 'common_project_path(project: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.common_project_path +- attributes: [] + class: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.from_service_account_file + langs: + - python + module: google.cloud.texttospeech_v1.services.text_to_speech + name: from_service_account_file + source: + id: from_service_account_file + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/async_client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/async_client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 87 + summary: "Creates an instance of this client using the provided credentials\n \ + \ file.\n" + syntax: + content: 'from_service_account_file(filename: str, *args, **kwargs)' + parameters: + - description: The path to the service account private key json file. + id: filename + var_type: str + returns: + - description: The constructed client. + var_type: TextToSpeechAsyncClient + type: method + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.from_service_account_file +- attributes: [] + class: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.from_service_account_info + langs: + - python + module: google.cloud.texttospeech_v1.services.text_to_speech + name: from_service_account_info + source: + id: from_service_account_info + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/async_client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/async_client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 72 + summary: "Creates an instance of this client using the provided credentials\n \ + \ info.\n" + syntax: + content: 'from_service_account_info(info: dict, *args, **kwargs)' + parameters: + - description: The service account private key info. + id: info + var_type: dict + returns: + - description: The constructed client. + var_type: TextToSpeechAsyncClient + type: method + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.from_service_account_info +- attributes: [] + class: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.from_service_account_json + langs: + - python + module: google.cloud.texttospeech_v1.services.text_to_speech + name: from_service_account_json + source: + id: from_service_account_json + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/async_client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/async_client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 87 + summary: "Creates an instance of this client using the provided credentials\n \ + \ file.\n" + syntax: + content: 'from_service_account_json(filename: str, *args, **kwargs)' + parameters: + - description: The path to the service account private key json file. + id: filename + var_type: str + returns: + - description: The constructed client. + var_type: TextToSpeechAsyncClient + type: method + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.from_service_account_json +- attributes: [] + class: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.get_mtls_endpoint_and_cert_source + langs: + - python + module: google.cloud.texttospeech_v1.services.text_to_speech + name: get_mtls_endpoint_and_cert_source + source: + id: get_mtls_endpoint_and_cert_source + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/async_client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/async_client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 105 + summary: 'Return the API endpoint and client cert source for mutual TLS. + + + The client cert source is determined in the following order: + + (1) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not "true", + the + + client cert source is None. + + (2) if `client_options.client_cert_source` is provided, use the provided one; + if the + + default client cert source exists, use the default one; otherwise the client cert + + source is None. + + + The API endpoint is determined in the following order: + + (1) if `client_options.api_endpoint` if provided, use the provided one. + + (2) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is "always", use + the + + default mTLS endpoint; if the environment variabel is "never", use the default + API + + endpoint; otherwise if client cert source exists, use the default mTLS endpoint, + otherwise + + use the default API endpoint. + + + More details can be found at https://google.aip.dev/auth/4114. + + ' + syntax: + content: "get_mtls_endpoint_and_cert_source(\n client_options: typing.Optional[\n\ + \ google.api_core.client_options.ClientOptions\n ] = None,\n)" + exceptions: + - description: If any errors happen. + var_type: google.auth.exceptions.MutualTLSChannelError + parameters: + - defaultValue: None + description: Custom options for the client. Only the api_endpoint + and client_cert_source properties may be used in this method. + id: client_options + var_type: google.api_core.client_options.ClientOptions + returns: + - description: returns the API endpoint and the client cert source to use. + var_type: Tuple[str, Callable[[], Tuple[bytes, bytes]]] + type: method + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.get_mtls_endpoint_and_cert_source +- attributes: [] + class: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.get_transport_class + langs: + - python + module: google.cloud.texttospeech_v1.services.text_to_speech + name: get_transport_class + source: + id: get_transport_class + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Returns an appropriate transport class. + + ' + syntax: + content: get_transport_class() + parameters: [] + type: method + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.get_transport_class +- attributes: [] + class: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.list_voices + langs: + - python + module: google.cloud.texttospeech_v1.services.text_to_speech + name: list_voices + source: + id: list_voices + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/async_client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/async_client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 201 + summary: "Returns a list of Voice supported for synthesis.\n\n```python\n# This\ + \ snippet has been automatically generated and should be regarded as a\n# code\ + \ template only.\n# It will require modifications to work:\n# - It may require\ + \ correct/in-range values for request initialization.\n# - It may require specifying\ + \ regional endpoints when creating the service\n# client as shown in:\n# https://googleapis.dev/python/google-api-core/latest/client_options.html\n\ + from google.cloud import texttospeech_v1\n\nasync def sample_list_voices():\n\ + \ # Create a client\n client = texttospeech_v1.TextToSpeechAsyncClient()\n\ + \n # Initialize request argument(s)\n request = texttospeech_v1.ListVoicesRequest(\n\ + \ )\n\n # Make the request\n response = await client.list_voices(request=request)\n\ + \n # Handle the response\n print(response)\n```\n" + syntax: + content: "list_voices(\n request: typing.Optional[\n typing.Union[\n\ + \ google.cloud.texttospeech_v1.types.cloud_tts.ListVoicesRequest,\ + \ dict\n ]\n ] = None,\n *,\n language_code: typing.Optional[str]\ + \ = None,\n retry: typing.Union[\n google.api_core.retry.Retry, google.api_core.gapic_v1.method._MethodDefault\n\ + \ ] = _MethodDefault._DEFAULT_VALUE,\n timeout: typing.Optional[float]\ + \ = None,\n metadata: typing.Sequence[typing.Tuple[str, str]] = ()\n)" + parameters: + - defaultValue: None + description: The request object. The top-level message sent by the client for + the ListVoices method. + id: request + var_type: Union[google.cloud.texttospeech_v1.types.ListVoicesRequest, + dict] + - description: Optional. Recommended. BCP-47 __ + language tag. If not specified, the API will return all supported voices. + If specified, the ListVoices call will only return voices that can be used + to synthesize this language_code. For example, if you specify "en-NZ", + all "en-NZ" voices will be returned. If you specify "no", + both "no-\*" (Norwegian) and "nb-\*" (Norwegian + Bokmal) voices will be returned. This corresponds to the language_code + field on the request instance; if request is provided, + this should not be set. + id: language_code + var_type: str + - description: Designation of what errors, if any, should be retried. + id: retry + var_type: google.api_core.retry.Retry + - description: The timeout for this request. + id: timeout + var_type: float + - description: Strings which should be sent along with the request as metadata. + id: metadata + var_type: Sequence[Tuple[str, str]] + returns: + - description: The message returned to the client by the ListVoices method. + var_type: google.cloud.texttospeech_v1.types.ListVoicesResponse + type: method + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.list_voices +- attributes: [] + class: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.model_path + langs: + - python + module: google.cloud.texttospeech_v1.services.text_to_speech + name: model_path + source: + id: model_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 163 + summary: 'Returns a fully-qualified model string. + + + ' + syntax: + content: 'model_path(project: str, location: str, model: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.model_path +- attributes: [] + class: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_billing_account_path + langs: + - python + module: google.cloud.texttospeech_v1.services.text_to_speech + name: parse_common_billing_account_path + source: + id: parse_common_billing_account_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 194 + summary: 'Parse a billing_account path into its component segments. + + + ' + syntax: + content: 'parse_common_billing_account_path(path: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_billing_account_path +- attributes: [] + class: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_folder_path + langs: + - python + module: google.cloud.texttospeech_v1.services.text_to_speech + name: parse_common_folder_path + source: + id: parse_common_folder_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 209 + summary: 'Parse a folder path into its component segments. + + + ' + syntax: + content: 'parse_common_folder_path(path: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_folder_path +- attributes: [] + class: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_location_path + langs: + - python + module: google.cloud.texttospeech_v1.services.text_to_speech + name: parse_common_location_path + source: + id: parse_common_location_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 256 + summary: 'Parse a location path into its component segments. + + + ' + syntax: + content: 'parse_common_location_path(path: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_location_path +- attributes: [] + class: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_organization_path + langs: + - python + module: google.cloud.texttospeech_v1.services.text_to_speech + name: parse_common_organization_path + source: + id: parse_common_organization_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 224 + summary: 'Parse a organization path into its component segments. + + + ' + syntax: + content: 'parse_common_organization_path(path: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_organization_path +- attributes: [] + class: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_project_path + langs: + - python + module: google.cloud.texttospeech_v1.services.text_to_speech + name: parse_common_project_path + source: + id: parse_common_project_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 239 + summary: 'Parse a project path into its component segments. + + + ' + syntax: + content: 'parse_common_project_path(path: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_project_path +- attributes: [] + class: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.parse_model_path + langs: + - python + module: google.cloud.texttospeech_v1.services.text_to_speech + name: parse_model_path + source: + id: parse_model_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 176 + summary: 'Parses a model path into its component segments. + + + ' + syntax: + content: 'parse_model_path(path: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.parse_model_path +- attributes: [] + class: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.synthesize_speech + langs: + - python + module: google.cloud.texttospeech_v1.services.text_to_speech + name: synthesize_speech + source: + id: synthesize_speech + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/async_client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/async_client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 303 + summary: "Synthesizes speech synchronously: receive results\nafter all text input\ + \ has been processed.\n\n```python\n# This snippet has been automatically generated\ + \ and should be regarded as a\n# code template only.\n# It will require modifications\ + \ to work:\n# - It may require correct/in-range values for request initialization.\n\ + # - It may require specifying regional endpoints when creating the service\n#\ + \ client as shown in:\n# https://googleapis.dev/python/google-api-core/latest/client_options.html\n\ + from google.cloud import texttospeech_v1\n\nasync def sample_synthesize_speech():\n\ + \ # Create a client\n client = texttospeech_v1.TextToSpeechAsyncClient()\n\ + \n # Initialize request argument(s)\n input = texttospeech_v1.SynthesisInput()\n\ + \ input.text = \"text_value\"\n\n voice = texttospeech_v1.VoiceSelectionParams()\n\ + \ voice.language_code = \"language_code_value\"\n\n audio_config = texttospeech_v1.AudioConfig()\n\ + \ audio_config.audio_encoding = \"ALAW\"\n\n request = texttospeech_v1.SynthesizeSpeechRequest(\n\ + \ input=input,\n voice=voice,\n audio_config=audio_config,\n\ + \ )\n\n # Make the request\n response = await client.synthesize_speech(request=request)\n\ + \n # Handle the response\n print(response)\n```\n" + syntax: + content: "synthesize_speech(\n request: typing.Optional[\n typing.Union[\n\ + \ google.cloud.texttospeech_v1.types.cloud_tts.SynthesizeSpeechRequest,\ + \ dict\n ]\n ] = None,\n *,\n input: typing.Optional[\n \ + \ google.cloud.texttospeech_v1.types.cloud_tts.SynthesisInput\n ] = None,\n\ + \ voice: typing.Optional[\n google.cloud.texttospeech_v1.types.cloud_tts.VoiceSelectionParams\n\ + \ ] = None,\n audio_config: typing.Optional[\n google.cloud.texttospeech_v1.types.cloud_tts.AudioConfig\n\ + \ ] = None,\n retry: typing.Union[\n google.api_core.retry.Retry,\ + \ google.api_core.gapic_v1.method._MethodDefault\n ] = _MethodDefault._DEFAULT_VALUE,\n\ + \ timeout: typing.Optional[float] = None,\n metadata: typing.Sequence[typing.Tuple[str,\ + \ str]] = ()\n)" + parameters: + - defaultValue: None + description: The request object. The top-level message sent by the client for + the SynthesizeSpeech method. + id: request + var_type: Union[google.cloud.texttospeech_v1.types.SynthesizeSpeechRequest, + dict] + - description: Required. The Synthesizer requires either plain text or SSML as + input. This corresponds to the input field on the request + instance; if request is provided, this should not be set. + id: input + var_type: SynthesisInput + - description: Required. The desired voice of the synthesized audio. This corresponds + to the voice field on the request instance; if request + is provided, this should not be set. + id: voice + var_type: VoiceSelectionParams + - description: Required. The configuration of the synthesized audio. This corresponds + to the audio_config field on the request instance; + if request is provided, this should not be set. + id: audio_config + var_type: AudioConfig + - description: Designation of what errors, if any, should be retried. + id: retry + var_type: google.api_core.retry.Retry + - description: The timeout for this request. + id: timeout + var_type: float + - description: Strings which should be sent along with the request as metadata. + id: metadata + var_type: Sequence[Tuple[str, str]] + returns: + - description: The message returned to the client by the SynthesizeSpeech method. + var_type: google.cloud.texttospeech_v1.types.SynthesizeSpeechResponse + type: method + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.synthesize_speech +- &id001 + attributes: [] + class: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.transport + langs: + - python + module: google.cloud.texttospeech_v1.services.text_to_speech + name: transport + source: + id: transport + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Returns the transport used by the client instance. + + ' + syntax: + returns: + - description: The transport used by the client instance. + var_type: TextToSpeechTransport + type: property + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.transport +- *id001 +references: +- fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + isExternal: false + name: TextToSpeechAsyncClient + parent: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient +- fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.common_billing_account_path + isExternal: false + name: common_billing_account_path + parent: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.common_billing_account_path +- fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.common_folder_path + isExternal: false + name: common_folder_path + parent: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.common_folder_path +- fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.common_location_path + isExternal: false + name: common_location_path + parent: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.common_location_path +- fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.common_organization_path + isExternal: false + name: common_organization_path + parent: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.common_organization_path +- fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.common_project_path + isExternal: false + name: common_project_path + parent: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.common_project_path +- fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.from_service_account_file + isExternal: false + name: from_service_account_file + parent: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.from_service_account_file +- fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.from_service_account_info + isExternal: false + name: from_service_account_info + parent: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.from_service_account_info +- fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.from_service_account_json + isExternal: false + name: from_service_account_json + parent: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.from_service_account_json +- fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.get_mtls_endpoint_and_cert_source + isExternal: false + name: get_mtls_endpoint_and_cert_source + parent: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.get_mtls_endpoint_and_cert_source +- fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.get_transport_class + isExternal: false + name: get_transport_class + parent: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.get_transport_class +- fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.list_voices + isExternal: false + name: list_voices + parent: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.list_voices +- fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.model_path + isExternal: false + name: model_path + parent: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.model_path +- fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_billing_account_path + isExternal: false + name: parse_common_billing_account_path + parent: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_billing_account_path +- fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_folder_path + isExternal: false + name: parse_common_folder_path + parent: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_folder_path +- fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_location_path + isExternal: false + name: parse_common_location_path + parent: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_location_path +- fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_organization_path + isExternal: false + name: parse_common_organization_path + parent: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_organization_path +- fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_project_path + isExternal: false + name: parse_common_project_path + parent: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_project_path +- fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.parse_model_path + isExternal: false + name: parse_model_path + parent: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.parse_model_path +- fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.synthesize_speech + isExternal: false + name: synthesize_speech + parent: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.synthesize_speech +- fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.transport + isExternal: false + name: transport + parent: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.transport diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.yml new file mode 100644 index 000000000000..bafb3765cfbf --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.yml @@ -0,0 +1,862 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: [] + children: + - google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + - google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.__exit__ + - google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.common_billing_account_path + - google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.common_folder_path + - google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.common_location_path + - google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.common_organization_path + - google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.common_project_path + - google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.from_service_account_file + - google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.from_service_account_info + - google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.from_service_account_json + - google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.get_mtls_endpoint_and_cert_source + - google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.list_voices + - google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.model_path + - google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.parse_common_billing_account_path + - google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.parse_common_folder_path + - google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.parse_common_location_path + - google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.parse_common_organization_path + - google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.parse_common_project_path + - google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.parse_model_path + - google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.synthesize_speech + - google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.transport + class: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + inheritance: + - type: builtins.object + langs: + - python + module: google.cloud.texttospeech_v1.services.text_to_speech + name: TextToSpeechClient + source: + id: TextToSpeechClient + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 78 + summary: 'Service that implements Google Cloud Text-to-Speech API. + + + ' + syntax: + content: 'TextToSpeechClient(*, credentials: typing.Optional[google.auth.credentials.Credentials] + = None, transport: typing.Optional[typing.Union[str, google.cloud.texttospeech_v1.services.text_to_speech.transports.base.TextToSpeechTransport]] + = None, client_options: typing.Optional[google.api_core.client_options.ClientOptions] + = None, client_info: google.api_core.gapic_v1.client_info.ClientInfo = )' + parameters: [] + type: class + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient +- attributes: [] + class: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + inheritance: + - type: builtins.object + langs: + - python + module: google.cloud.texttospeech_v1.services.text_to_speech + name: TextToSpeechClient + source: + id: TextToSpeechClient + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 78 + summary: 'Instantiates the text to speech client. + + ' + syntax: + content: 'TextToSpeechClient(*, credentials: typing.Optional[google.auth.credentials.Credentials] + = None, transport: typing.Optional[typing.Union[str, google.cloud.texttospeech_v1.services.text_to_speech.transports.base.TextToSpeechTransport]] + = None, client_options: typing.Optional[google.api_core.client_options.ClientOptions] + = None, client_info: google.api_core.gapic_v1.client_info.ClientInfo = )' + exceptions: + - description: If mutual TLS transport creation failed for any reason. + var_type: google.auth.exceptions.MutualTLSChannelError + parameters: + - description: The authorization credentials to attach to requests. These credentials + identify the application to the service; if none are specified, the client + will attempt to ascertain the credentials from the environment. + id: credentials + var_type: Optional[google.auth.credentials.Credentials] + - description: The transport to use. If set to None, a transport is chosen automatically. + id: transport + var_type: Union[str, TextToSpeechTransport] + - description: 'Custom options for the client. It won''t take effect if a transport + instance is provided. (1) The api_endpoint property can be used + to override the default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT + environment variable can also be used to override the endpoint: "always" (always + use the default mTLS endpoint), "never" (always use the default regular endpoint) + and "auto" (auto switch to the default mTLS endpoint if client certificate + is present, this is the default value). However, the api_endpoint + property takes precedence if provided. (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE + environment variable is "true", then the client_cert_source property + can be used to provide client certificate for mutual TLS transport. If not + provided, the default SSL client certificate will be used if present. If GOOGLE_API_USE_CLIENT_CERTIFICATE + is "false" or not set, no client certificate will be used.' + id: client_options + var_type: google.api_core.client_options.ClientOptions + - description: The client info used to send a user-agent string along with API + requests. If None, then default info will be used. Generally, + you only need to set this if you're developing your own client library. + id: client_info + var_type: google.api_core.gapic_v1.client_info.ClientInfo + type: method + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient +- attributes: [] + class: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.__exit__ + langs: + - python + module: google.cloud.texttospeech_v1.services.text_to_speech + name: __exit__ + source: + id: __exit__ + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 661 + summary: 'Releases underlying transport''s resources. + + + ' + syntax: + content: __exit__(type, value, traceback) + parameters: [] + type: method + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.__exit__ +- attributes: [] + class: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.common_billing_account_path + langs: + - python + module: google.cloud.texttospeech_v1.services.text_to_speech + name: common_billing_account_path + source: + id: common_billing_account_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 185 + summary: 'Returns a fully-qualified billing_account string. + + + ' + syntax: + content: 'common_billing_account_path(billing_account: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.common_billing_account_path +- attributes: [] + class: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.common_folder_path + langs: + - python + module: google.cloud.texttospeech_v1.services.text_to_speech + name: common_folder_path + source: + id: common_folder_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 200 + summary: 'Returns a fully-qualified folder string. + + + ' + syntax: + content: 'common_folder_path(folder: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.common_folder_path +- attributes: [] + class: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.common_location_path + langs: + - python + module: google.cloud.texttospeech_v1.services.text_to_speech + name: common_location_path + source: + id: common_location_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 245 + summary: 'Returns a fully-qualified location string. + + + ' + syntax: + content: 'common_location_path(project: str, location: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.common_location_path +- attributes: [] + class: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.common_organization_path + langs: + - python + module: google.cloud.texttospeech_v1.services.text_to_speech + name: common_organization_path + source: + id: common_organization_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 215 + summary: 'Returns a fully-qualified organization string. + + + ' + syntax: + content: 'common_organization_path(organization: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.common_organization_path +- attributes: [] + class: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.common_project_path + langs: + - python + module: google.cloud.texttospeech_v1.services.text_to_speech + name: common_project_path + source: + id: common_project_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 230 + summary: 'Returns a fully-qualified project string. + + + ' + syntax: + content: 'common_project_path(project: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.common_project_path +- attributes: [] + class: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.from_service_account_file + langs: + - python + module: google.cloud.texttospeech_v1.services.text_to_speech + name: from_service_account_file + source: + id: from_service_account_file + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 133 + summary: "Creates an instance of this client using the provided credentials\n \ + \ file.\n" + syntax: + content: 'from_service_account_file(filename: str, *args, **kwargs)' + parameters: + - description: The path to the service account private key json file. + id: filename + var_type: str + returns: + - description: The constructed client. + var_type: TextToSpeechClient + type: method + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.from_service_account_file +- attributes: [] + class: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.from_service_account_info + langs: + - python + module: google.cloud.texttospeech_v1.services.text_to_speech + name: from_service_account_info + source: + id: from_service_account_info + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 116 + summary: "Creates an instance of this client using the provided credentials\n \ + \ info.\n" + syntax: + content: 'from_service_account_info(info: dict, *args, **kwargs)' + parameters: + - description: The service account private key info. + id: info + var_type: dict + returns: + - description: The constructed client. + var_type: TextToSpeechClient + type: method + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.from_service_account_info +- attributes: [] + class: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.from_service_account_json + langs: + - python + module: google.cloud.texttospeech_v1.services.text_to_speech + name: from_service_account_json + source: + id: from_service_account_json + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 133 + summary: "Creates an instance of this client using the provided credentials\n \ + \ file.\n" + syntax: + content: 'from_service_account_json(filename: str, *args, **kwargs)' + parameters: + - description: The path to the service account private key json file. + id: filename + var_type: str + returns: + - description: The constructed client. + var_type: TextToSpeechClient + type: method + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.from_service_account_json +- attributes: [] + class: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.get_mtls_endpoint_and_cert_source + langs: + - python + module: google.cloud.texttospeech_v1.services.text_to_speech + name: get_mtls_endpoint_and_cert_source + source: + id: get_mtls_endpoint_and_cert_source + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 262 + summary: 'Return the API endpoint and client cert source for mutual TLS. + + + The client cert source is determined in the following order: + + (1) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not "true", + the + + client cert source is None. + + (2) if `client_options.client_cert_source` is provided, use the provided one; + if the + + default client cert source exists, use the default one; otherwise the client cert + + source is None. + + + The API endpoint is determined in the following order: + + (1) if `client_options.api_endpoint` if provided, use the provided one. + + (2) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is "always", use + the + + default mTLS endpoint; if the environment variabel is "never", use the default + API + + endpoint; otherwise if client cert source exists, use the default mTLS endpoint, + otherwise + + use the default API endpoint. + + + More details can be found at https://google.aip.dev/auth/4114. + + ' + syntax: + content: "get_mtls_endpoint_and_cert_source(\n client_options: typing.Optional[\n\ + \ google.api_core.client_options.ClientOptions\n ] = None,\n)" + exceptions: + - description: If any errors happen. + var_type: google.auth.exceptions.MutualTLSChannelError + parameters: + - defaultValue: None + description: Custom options for the client. Only the api_endpoint + and client_cert_source properties may be used in this method. + id: client_options + var_type: google.api_core.client_options.ClientOptions + returns: + - description: returns the API endpoint and the client cert source to use. + var_type: Tuple[str, Callable[[], Tuple[bytes, bytes]]] + type: method + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.get_mtls_endpoint_and_cert_source +- attributes: [] + class: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.list_voices + langs: + - python + module: google.cloud.texttospeech_v1.services.text_to_speech + name: list_voices + source: + id: list_voices + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 428 + summary: "Returns a list of Voice supported for synthesis.\n\n```python\n# This\ + \ snippet has been automatically generated and should be regarded as a\n# code\ + \ template only.\n# It will require modifications to work:\n# - It may require\ + \ correct/in-range values for request initialization.\n# - It may require specifying\ + \ regional endpoints when creating the service\n# client as shown in:\n# https://googleapis.dev/python/google-api-core/latest/client_options.html\n\ + from google.cloud import texttospeech_v1\n\ndef sample_list_voices():\n # Create\ + \ a client\n client = texttospeech_v1.TextToSpeechClient()\n\n # Initialize\ + \ request argument(s)\n request = texttospeech_v1.ListVoicesRequest(\n )\n\ + \n # Make the request\n response = client.list_voices(request=request)\n\ + \n # Handle the response\n print(response)\n```\n" + syntax: + content: "list_voices(\n request: typing.Optional[\n typing.Union[\n\ + \ google.cloud.texttospeech_v1.types.cloud_tts.ListVoicesRequest,\ + \ dict\n ]\n ] = None,\n *,\n language_code: typing.Optional[str]\ + \ = None,\n retry: typing.Union[\n google.api_core.retry.Retry, google.api_core.gapic_v1.method._MethodDefault\n\ + \ ] = _MethodDefault._DEFAULT_VALUE,\n timeout: typing.Optional[float]\ + \ = None,\n metadata: typing.Sequence[typing.Tuple[str, str]] = ()\n)" + parameters: + - defaultValue: None + description: The request object. The top-level message sent by the client for + the ListVoices method. + id: request + var_type: Union[google.cloud.texttospeech_v1.types.ListVoicesRequest, + dict] + - description: Optional. Recommended. BCP-47 __ + language tag. If not specified, the API will return all supported voices. + If specified, the ListVoices call will only return voices that can be used + to synthesize this language_code. For example, if you specify "en-NZ", + all "en-NZ" voices will be returned. If you specify "no", + both "no-\*" (Norwegian) and "nb-\*" (Norwegian + Bokmal) voices will be returned. This corresponds to the language_code + field on the request instance; if request is provided, + this should not be set. + id: language_code + var_type: str + - description: Designation of what errors, if any, should be retried. + id: retry + var_type: google.api_core.retry.Retry + - description: The timeout for this request. + id: timeout + var_type: float + - description: Strings which should be sent along with the request as metadata. + id: metadata + var_type: Sequence[Tuple[str, str]] + returns: + - description: The message returned to the client by the ListVoices method. + var_type: google.cloud.texttospeech_v1.types.ListVoicesResponse + type: method + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.list_voices +- attributes: [] + class: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.model_path + langs: + - python + module: google.cloud.texttospeech_v1.services.text_to_speech + name: model_path + source: + id: model_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 163 + summary: 'Returns a fully-qualified model string. + + + ' + syntax: + content: 'model_path(project: str, location: str, model: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.model_path +- attributes: [] + class: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.parse_common_billing_account_path + langs: + - python + module: google.cloud.texttospeech_v1.services.text_to_speech + name: parse_common_billing_account_path + source: + id: parse_common_billing_account_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 194 + summary: 'Parse a billing_account path into its component segments. + + + ' + syntax: + content: 'parse_common_billing_account_path(path: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.parse_common_billing_account_path +- attributes: [] + class: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.parse_common_folder_path + langs: + - python + module: google.cloud.texttospeech_v1.services.text_to_speech + name: parse_common_folder_path + source: + id: parse_common_folder_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 209 + summary: 'Parse a folder path into its component segments. + + + ' + syntax: + content: 'parse_common_folder_path(path: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.parse_common_folder_path +- attributes: [] + class: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.parse_common_location_path + langs: + - python + module: google.cloud.texttospeech_v1.services.text_to_speech + name: parse_common_location_path + source: + id: parse_common_location_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 256 + summary: 'Parse a location path into its component segments. + + + ' + syntax: + content: 'parse_common_location_path(path: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.parse_common_location_path +- attributes: [] + class: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.parse_common_organization_path + langs: + - python + module: google.cloud.texttospeech_v1.services.text_to_speech + name: parse_common_organization_path + source: + id: parse_common_organization_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 224 + summary: 'Parse a organization path into its component segments. + + + ' + syntax: + content: 'parse_common_organization_path(path: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.parse_common_organization_path +- attributes: [] + class: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.parse_common_project_path + langs: + - python + module: google.cloud.texttospeech_v1.services.text_to_speech + name: parse_common_project_path + source: + id: parse_common_project_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 239 + summary: 'Parse a project path into its component segments. + + + ' + syntax: + content: 'parse_common_project_path(path: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.parse_common_project_path +- attributes: [] + class: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.parse_model_path + langs: + - python + module: google.cloud.texttospeech_v1.services.text_to_speech + name: parse_model_path + source: + id: parse_model_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 176 + summary: 'Parses a model path into its component segments. + + + ' + syntax: + content: 'parse_model_path(path: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.parse_model_path +- attributes: [] + class: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.synthesize_speech + langs: + - python + module: google.cloud.texttospeech_v1.services.text_to_speech + name: synthesize_speech + source: + id: synthesize_speech + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 530 + summary: "Synthesizes speech synchronously: receive results\nafter all text input\ + \ has been processed.\n\n```python\n# This snippet has been automatically generated\ + \ and should be regarded as a\n# code template only.\n# It will require modifications\ + \ to work:\n# - It may require correct/in-range values for request initialization.\n\ + # - It may require specifying regional endpoints when creating the service\n#\ + \ client as shown in:\n# https://googleapis.dev/python/google-api-core/latest/client_options.html\n\ + from google.cloud import texttospeech_v1\n\ndef sample_synthesize_speech():\n\ + \ # Create a client\n client = texttospeech_v1.TextToSpeechClient()\n\n\ + \ # Initialize request argument(s)\n input = texttospeech_v1.SynthesisInput()\n\ + \ input.text = \"text_value\"\n\n voice = texttospeech_v1.VoiceSelectionParams()\n\ + \ voice.language_code = \"language_code_value\"\n\n audio_config = texttospeech_v1.AudioConfig()\n\ + \ audio_config.audio_encoding = \"ALAW\"\n\n request = texttospeech_v1.SynthesizeSpeechRequest(\n\ + \ input=input,\n voice=voice,\n audio_config=audio_config,\n\ + \ )\n\n # Make the request\n response = client.synthesize_speech(request=request)\n\ + \n # Handle the response\n print(response)\n```\n" + syntax: + content: "synthesize_speech(\n request: typing.Optional[\n typing.Union[\n\ + \ google.cloud.texttospeech_v1.types.cloud_tts.SynthesizeSpeechRequest,\ + \ dict\n ]\n ] = None,\n *,\n input: typing.Optional[\n \ + \ google.cloud.texttospeech_v1.types.cloud_tts.SynthesisInput\n ] = None,\n\ + \ voice: typing.Optional[\n google.cloud.texttospeech_v1.types.cloud_tts.VoiceSelectionParams\n\ + \ ] = None,\n audio_config: typing.Optional[\n google.cloud.texttospeech_v1.types.cloud_tts.AudioConfig\n\ + \ ] = None,\n retry: typing.Union[\n google.api_core.retry.Retry,\ + \ google.api_core.gapic_v1.method._MethodDefault\n ] = _MethodDefault._DEFAULT_VALUE,\n\ + \ timeout: typing.Optional[float] = None,\n metadata: typing.Sequence[typing.Tuple[str,\ + \ str]] = ()\n)" + parameters: + - defaultValue: None + description: The request object. The top-level message sent by the client for + the SynthesizeSpeech method. + id: request + var_type: Union[google.cloud.texttospeech_v1.types.SynthesizeSpeechRequest, + dict] + - description: Required. The Synthesizer requires either plain text or SSML as + input. This corresponds to the input field on the request + instance; if request is provided, this should not be set. + id: input + var_type: google.cloud.texttospeech_v1.types.SynthesisInput + - description: Required. The desired voice of the synthesized audio. This corresponds + to the voice field on the request instance; if request + is provided, this should not be set. + id: voice + var_type: google.cloud.texttospeech_v1.types.VoiceSelectionParams + - description: Required. The configuration of the synthesized audio. This corresponds + to the audio_config field on the request instance; + if request is provided, this should not be set. + id: audio_config + var_type: google.cloud.texttospeech_v1.types.AudioConfig + - description: Designation of what errors, if any, should be retried. + id: retry + var_type: google.api_core.retry.Retry + - description: The timeout for this request. + id: timeout + var_type: float + - description: Strings which should be sent along with the request as metadata. + id: metadata + var_type: Sequence[Tuple[str, str]] + returns: + - description: The message returned to the client by the SynthesizeSpeech method. + var_type: google.cloud.texttospeech_v1.types.SynthesizeSpeechResponse + type: method + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.synthesize_speech +- &id001 + attributes: [] + class: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.transport + langs: + - python + module: google.cloud.texttospeech_v1.services.text_to_speech + name: transport + source: + id: transport + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Returns the transport used by the client instance. + + ' + syntax: + returns: + - description: The transport used by the client instance. + var_type: TextToSpeechTransport + type: property + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.transport +- *id001 +references: +- fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + isExternal: false + name: TextToSpeechClient + parent: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient +- fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.__exit__ + isExternal: false + name: __exit__ + parent: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.__exit__ +- fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.common_billing_account_path + isExternal: false + name: common_billing_account_path + parent: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.common_billing_account_path +- fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.common_folder_path + isExternal: false + name: common_folder_path + parent: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.common_folder_path +- fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.common_location_path + isExternal: false + name: common_location_path + parent: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.common_location_path +- fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.common_organization_path + isExternal: false + name: common_organization_path + parent: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.common_organization_path +- fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.common_project_path + isExternal: false + name: common_project_path + parent: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.common_project_path +- fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.from_service_account_file + isExternal: false + name: from_service_account_file + parent: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.from_service_account_file +- fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.from_service_account_info + isExternal: false + name: from_service_account_info + parent: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.from_service_account_info +- fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.from_service_account_json + isExternal: false + name: from_service_account_json + parent: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.from_service_account_json +- fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.get_mtls_endpoint_and_cert_source + isExternal: false + name: get_mtls_endpoint_and_cert_source + parent: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.get_mtls_endpoint_and_cert_source +- fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.list_voices + isExternal: false + name: list_voices + parent: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.list_voices +- fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.model_path + isExternal: false + name: model_path + parent: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.model_path +- fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.parse_common_billing_account_path + isExternal: false + name: parse_common_billing_account_path + parent: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.parse_common_billing_account_path +- fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.parse_common_folder_path + isExternal: false + name: parse_common_folder_path + parent: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.parse_common_folder_path +- fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.parse_common_location_path + isExternal: false + name: parse_common_location_path + parent: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.parse_common_location_path +- fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.parse_common_organization_path + isExternal: false + name: parse_common_organization_path + parent: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.parse_common_organization_path +- fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.parse_common_project_path + isExternal: false + name: parse_common_project_path + parent: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.parse_common_project_path +- fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.parse_model_path + isExternal: false + name: parse_model_path + parent: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.parse_model_path +- fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.synthesize_speech + isExternal: false + name: synthesize_speech + parent: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.synthesize_speech +- fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.transport + isExternal: false + name: transport + parent: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.transport diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.services.text_to_speech.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.services.text_to_speech.yml new file mode 100644 index 000000000000..9a054deabc2a --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.services.text_to_speech.yml @@ -0,0 +1,34 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- children: + - google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + - google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + fullName: google.cloud.texttospeech_v1.services.text_to_speech + langs: + - python + module: google.cloud.texttospeech_v1.services.text_to_speech + name: text_to_speech + source: + id: text_to_speech + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/__init__.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/__init__.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 0 + summary: API documentation for `texttospeech_v1.services.text_to_speech` package. + syntax: {} + type: subPackage + uid: google.cloud.texttospeech_v1.services.text_to_speech +references: +- fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + isExternal: false + name: TextToSpeechAsyncClient + parent: google.cloud.texttospeech_v1.services.text_to_speech + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient +- fullName: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + isExternal: false + name: TextToSpeechClient + parent: google.cloud.texttospeech_v1.services.text_to_speech + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.AudioConfig.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.AudioConfig.yml new file mode 100644 index 000000000000..68fd0289c8e5 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.AudioConfig.yml @@ -0,0 +1,73 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: + - description: "Required. The format of the audio byte\n stream." + id: audio_encoding + var_type: google.cloud.texttospeech_v1.types.AudioEncoding + - description: "Optional. Input only. Speaking rate/speed, in the range\n [0.25,\ + \ 4.0]. 1.0 is the normal native speed supported by the\n specific voice.\ + \ 2.0 is twice as fast, and 0.5 is half as\n fast. If unset(0.0), defaults\ + \ to the native 1.0 speed. Any\n other values < 0.25 or > 4.0 will return\ + \ an error." + id: speaking_rate + var_type: float + - description: "Optional. Input only. Speaking pitch, in the range [-20.0,\n 20.0].\ + \ 20 means increase 20 semitones from the original\n pitch. -20 means decrease\ + \ 20 semitones from the original\n pitch." + id: pitch + var_type: float + - description: "Optional. Input only. Volume gain (in dB) of the normal\n native\ + \ volume supported by the specific voice, in the range\n [-96.0, 16.0]. If\ + \ unset, or set to a value of 0.0 (dB), will\n play at normal native signal\ + \ amplitude. A value of -6.0 (dB)\n will play at approximately half the amplitude\ + \ of the normal\n native signal amplitude. A value of +6.0 (dB) will play\ + \ at\n approximately twice the amplitude of the normal native\n signal amplitude.\ + \ Strongly recommend not to exceed +10 (dB)\n as there's usually no effective\ + \ increase in loudness for any\n value greater than that." + id: volume_gain_db + var_type: float + - description: "Optional. The synthesis sample rate (in hertz) for this\n audio.\ + \ When this is specified in SynthesizeSpeechRequest, if\n this is different\ + \ from the voice's natural sample rate, then\n the synthesizer will honor\ + \ this request by converting to the\n desired sample rate (which might result\ + \ in worse audio\n quality), unless the specified sample rate is not supported\n\ + \ for the encoding chosen, in which case it will fail the\n request and\ + \ return [google.rpc.Code.INVALID_ARGUMENT][]." + id: sample_rate_hertz + var_type: int + - description: "Optional. Input only. An identifier which selects 'audio\n effects'\ + \ profiles that are applied on (post synthesized)\n text to speech. Effects\ + \ are applied on top of each other in\n the order they are given. See `audio\n\ + \ profiles `__\n\ + \ for current supported profile ids." + id: effects_profile_id + var_type: Sequence[str] + children: [] + class: google.cloud.texttospeech_v1.types.AudioConfig + fullName: google.cloud.texttospeech_v1.types.AudioConfig + inheritance: + - inheritance: + - type: builtins.object + type: proto.message.Message + langs: + - python + module: google.cloud.texttospeech_v1.types + name: AudioConfig + source: + id: AudioConfig + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 262 + summary: 'Description of audio data to be synthesized. + + ' + syntax: + content: AudioConfig(mapping=None, *, ignore_unknown_fields=False, **kwargs) + parameters: [] + type: class + uid: google.cloud.texttospeech_v1.types.AudioConfig +references: [] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.AudioEncoding.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.AudioEncoding.yml new file mode 100644 index 000000000000..8a5907cca536 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.AudioEncoding.yml @@ -0,0 +1,42 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: [] + children: [] + class: google.cloud.texttospeech_v1.types.AudioEncoding + fullName: google.cloud.texttospeech_v1.types.AudioEncoding + inheritance: + - inheritance: + - inheritance: + - inheritance: + - type: builtins.object + type: builtins.int + - inheritance: + - type: builtins.object + type: enum.Enum + type: enum.IntEnum + type: proto.enums.Enum + langs: + - python + module: google.cloud.texttospeech_v1.types + name: AudioEncoding + source: + id: AudioEncoding + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 46 + summary: 'Configuration to set up audio encoder. The encoding + + determines the output audio format that we''d like. + + + ' + syntax: + content: AudioEncoding(value) + parameters: [] + type: class + uid: google.cloud.texttospeech_v1.types.AudioEncoding +references: [] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.CustomVoiceParams.ReportedUsage.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.CustomVoiceParams.ReportedUsage.yml new file mode 100644 index 000000000000..066f9cea470d --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.CustomVoiceParams.ReportedUsage.yml @@ -0,0 +1,44 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: [] + children: [] + class: google.cloud.texttospeech_v1.types.CustomVoiceParams.ReportedUsage + fullName: google.cloud.texttospeech_v1.types.CustomVoiceParams.ReportedUsage + inheritance: + - inheritance: + - inheritance: + - inheritance: + - type: builtins.object + type: builtins.int + - inheritance: + - type: builtins.object + type: enum.Enum + type: enum.IntEnum + type: proto.enums.Enum + langs: + - python + module: google.cloud.texttospeech_v1.types.CustomVoiceParams + name: ReportedUsage + source: + id: ReportedUsage + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 348 + summary: 'The usage of the synthesized audio. You must report your + + honest and correct usage of the service as it''s regulated by + + contract and will cause significant difference in billing. + + + ' + syntax: + content: ReportedUsage(value) + parameters: [] + type: class + uid: google.cloud.texttospeech_v1.types.CustomVoiceParams.ReportedUsage +references: [] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.CustomVoiceParams.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.CustomVoiceParams.yml new file mode 100644 index 000000000000..76ed7b4ddbb1 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.CustomVoiceParams.yml @@ -0,0 +1,45 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: + - description: "Required. The name of the AutoML model that\n synthesizes the\ + \ custom voice." + id: model + var_type: str + - description: "Optional. The usage of the synthesized audio\n to be reported." + id: reported_usage + var_type: google.cloud.texttospeech_v1.types.CustomVoiceParams.ReportedUsage + children: + - google.cloud.texttospeech_v1.types.CustomVoiceParams.ReportedUsage + class: google.cloud.texttospeech_v1.types.CustomVoiceParams + fullName: google.cloud.texttospeech_v1.types.CustomVoiceParams + inheritance: + - inheritance: + - type: builtins.object + type: proto.message.Message + langs: + - python + module: google.cloud.texttospeech_v1.types + name: CustomVoiceParams + source: + id: CustomVoiceParams + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 336 + summary: 'Description of the custom voice to be synthesized. + + ' + syntax: + content: CustomVoiceParams(mapping=None, *, ignore_unknown_fields=False, **kwargs) + parameters: [] + type: class + uid: google.cloud.texttospeech_v1.types.CustomVoiceParams +references: +- fullName: google.cloud.texttospeech_v1.types.CustomVoiceParams.ReportedUsage + isExternal: false + name: ReportedUsage + parent: google.cloud.texttospeech_v1.types.CustomVoiceParams + uid: google.cloud.texttospeech_v1.types.CustomVoiceParams.ReportedUsage diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.ListVoicesRequest.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.ListVoicesRequest.yml new file mode 100644 index 000000000000..3beda141801f --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.ListVoicesRequest.yml @@ -0,0 +1,43 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: + - description: "Optional. Recommended.\n BCP-47 __\n\ + \ language tag. If not specified, the API will return all\n supported voices.\ + \ If specified, the ListVoices call will\n only return voices that can be\ + \ used to synthesize this\n language_code. For example, if you specify \"\ + en-NZ\", all\n \"en-NZ\" voices will be returned. If you\ + \ specify\n \"no\", both \"no-\\*\" (Norwegian)\ + \ and \"nb-\\*\"\n (Norwegian Bokmal) voices will be returned." + id: language_code + var_type: str + children: [] + class: google.cloud.texttospeech_v1.types.ListVoicesRequest + fullName: google.cloud.texttospeech_v1.types.ListVoicesRequest + inheritance: + - inheritance: + - type: builtins.object + type: proto.message.Message + langs: + - python + module: google.cloud.texttospeech_v1.types + name: ListVoicesRequest + source: + id: ListVoicesRequest + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 58 + summary: 'The top-level message sent by the client for the `ListVoices` + + method. + + ' + syntax: + content: ListVoicesRequest(mapping=None, *, ignore_unknown_fields=False, **kwargs) + parameters: [] + type: class + uid: google.cloud.texttospeech_v1.types.ListVoicesRequest +references: [] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.ListVoicesResponse.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.ListVoicesResponse.yml new file mode 100644 index 000000000000..33beba4488f0 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.ListVoicesResponse.yml @@ -0,0 +1,35 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: + - description: The list of voices. + id: voices + var_type: Sequence[google.cloud.texttospeech_v1.types.Voice] + children: [] + class: google.cloud.texttospeech_v1.types.ListVoicesResponse + fullName: google.cloud.texttospeech_v1.types.ListVoicesResponse + inheritance: + - inheritance: + - type: builtins.object + type: proto.message.Message + langs: + - python + module: google.cloud.texttospeech_v1.types + name: ListVoicesResponse + source: + id: ListVoicesResponse + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 81 + summary: 'The message returned to the client by the `ListVoices` method. + + ' + syntax: + content: ListVoicesResponse(mapping=None, *, ignore_unknown_fields=False, **kwargs) + parameters: [] + type: class + uid: google.cloud.texttospeech_v1.types.ListVoicesResponse +references: [] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.SsmlVoiceGender.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.SsmlVoiceGender.yml new file mode 100644 index 000000000000..d3f57ad70391 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.SsmlVoiceGender.yml @@ -0,0 +1,42 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: [] + children: [] + class: google.cloud.texttospeech_v1.types.SsmlVoiceGender + fullName: google.cloud.texttospeech_v1.types.SsmlVoiceGender + inheritance: + - inheritance: + - inheritance: + - inheritance: + - type: builtins.object + type: builtins.int + - inheritance: + - type: builtins.object + type: enum.Enum + type: enum.IntEnum + type: proto.enums.Enum + langs: + - python + module: google.cloud.texttospeech_v1.types + name: SsmlVoiceGender + source: + id: SsmlVoiceGender + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 36 + summary: 'Gender of the voice as described in `SSML voice + + element `__. + + + ' + syntax: + content: SsmlVoiceGender(value) + parameters: [] + type: class + uid: google.cloud.texttospeech_v1.types.SsmlVoiceGender +references: [] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.SynthesisInput.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.SynthesisInput.yml new file mode 100644 index 000000000000..0c4255ce6485 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.SynthesisInput.yml @@ -0,0 +1,60 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: + - description: "The raw text to be synthesized.\n \n This field is a member\ + \ of oneof_ input_source." + id: text + var_type: str + - description: "The SSML document to be synthesized. The SSML document must\n \ + \ be valid and well-formed. Otherwise the RPC will fail and\n return [google.rpc.Code.INVALID_ARGUMENT][].\ + \ For more\n information, see\n SSML __.\n\ + \ \n This field is a member of oneof_ input_source." + id: ssml + var_type: str + children: [] + class: google.cloud.texttospeech_v1.types.SynthesisInput + fullName: google.cloud.texttospeech_v1.types.SynthesisInput + inheritance: + - inheritance: + - type: builtins.object + type: proto.message.Message + langs: + - python + module: google.cloud.texttospeech_v1.types + name: SynthesisInput + source: + id: SynthesisInput + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 166 + summary: 'Contains text input to be synthesized. Either `text` or `ssml` + + must be supplied. Supplying both or neither returns + + [google.rpc.Code.INVALID_ARGUMENT][]. The input size is limited to + + 5000 characters. + + + This message has `oneof`_ fields (mutually exclusive fields). + + For each oneof, at most one member field can be set at the same time. + + Setting any member of the oneof automatically clears all other + + members. + + + .. _oneof: https://proto-plus-python.readthedocs.io/en/stable/fields.html#oneofs-mutually-exclusive-fields + + ' + syntax: + content: SynthesisInput(mapping=None, *, ignore_unknown_fields=False, **kwargs) + parameters: [] + type: class + uid: google.cloud.texttospeech_v1.types.SynthesisInput +references: [] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.SynthesizeSpeechRequest.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.SynthesizeSpeechRequest.yml new file mode 100644 index 000000000000..10c55f04a6e8 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.SynthesizeSpeechRequest.yml @@ -0,0 +1,45 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: + - description: "Required. The Synthesizer requires either\n plain text or SSML\ + \ as input." + id: input + var_type: google.cloud.texttospeech_v1.types.SynthesisInput + - description: "Required. The desired voice of the\n synthesized audio." + id: voice + var_type: google.cloud.texttospeech_v1.types.VoiceSelectionParams + - description: "Required. The configuration of the\n synthesized audio." + id: audio_config + var_type: google.cloud.texttospeech_v1.types.AudioConfig + children: [] + class: google.cloud.texttospeech_v1.types.SynthesizeSpeechRequest + fullName: google.cloud.texttospeech_v1.types.SynthesizeSpeechRequest + inheritance: + - inheritance: + - type: builtins.object + type: proto.message.Message + langs: + - python + module: google.cloud.texttospeech_v1.types + name: SynthesizeSpeechRequest + source: + id: SynthesizeSpeechRequest + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 133 + summary: 'The top-level message sent by the client for the + + `SynthesizeSpeech` method. + + ' + syntax: + content: SynthesizeSpeechRequest(mapping=None, *, ignore_unknown_fields=False, + **kwargs) + parameters: [] + type: class + uid: google.cloud.texttospeech_v1.types.SynthesizeSpeechRequest +references: [] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.SynthesizeSpeechResponse.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.SynthesizeSpeechResponse.yml new file mode 100644 index 000000000000..5617e3e8dd23 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.SynthesizeSpeechResponse.yml @@ -0,0 +1,42 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: + - description: "The audio data bytes encoded as specified in the request,\n including\ + \ the header for encodings that are wrapped in\n containers (e.g. MP3, OGG_OPUS).\ + \ For LINEAR16 audio, we\n include the WAV header. Note: as with all bytes\ + \ fields,\n protobuffers use a pure binary representation, whereas JSON\n\ + \ representations use base64." + id: audio_content + var_type: bytes + children: [] + class: google.cloud.texttospeech_v1.types.SynthesizeSpeechResponse + fullName: google.cloud.texttospeech_v1.types.SynthesizeSpeechResponse + inheritance: + - inheritance: + - type: builtins.object + type: proto.message.Message + langs: + - python + module: google.cloud.texttospeech_v1.types + name: SynthesizeSpeechResponse + source: + id: SynthesizeSpeechResponse + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 368 + summary: 'The message returned to the client by the `SynthesizeSpeech` + + method. + + ' + syntax: + content: SynthesizeSpeechResponse(mapping=None, *, ignore_unknown_fields=False, + **kwargs) + parameters: [] + type: class + uid: google.cloud.texttospeech_v1.types.SynthesizeSpeechResponse +references: [] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.Voice.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.Voice.yml new file mode 100644 index 000000000000..b359bef43a12 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.Voice.yml @@ -0,0 +1,46 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: + - description: "The languages that this voice supports, expressed as\n BCP-47\ + \ __\n language tags\ + \ (e.g. \"en-US\", \"es-419\", \"cmn-tw\")." + id: language_codes + var_type: Sequence[str] + - description: "The name of this voice. Each distinct voice\n has a unique name." + id: name + var_type: str + - description: The gender of this voice. + id: ssml_gender + var_type: google.cloud.texttospeech_v1.types.SsmlVoiceGender + - description: "The natural sample rate (in hertz) for this\n voice." + id: natural_sample_rate_hertz + var_type: int + children: [] + class: google.cloud.texttospeech_v1.types.Voice + fullName: google.cloud.texttospeech_v1.types.Voice + inheritance: + - inheritance: + - type: builtins.object + type: proto.message.Message + langs: + - python + module: google.cloud.texttospeech_v1.types + name: Voice + source: + id: Voice + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 96 + summary: 'Description of a voice supported by the TTS service. + + ' + syntax: + content: Voice(mapping=None, *, ignore_unknown_fields=False, **kwargs) + parameters: [] + type: class + uid: google.cloud.texttospeech_v1.types.Voice +references: [] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.VoiceSelectionParams.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.VoiceSelectionParams.yml new file mode 100644 index 000000000000..b31c083ea718 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.VoiceSelectionParams.yml @@ -0,0 +1,61 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: + - description: "Required. The language (and potentially also the region) of\n \ + \ the voice expressed as a\n BCP-47 __\n\ + \ language tag, e.g. \"en-US\". This should not include a script\n tag (e.g.\ + \ use \"cmn-cn\" rather than \"cmn-Hant-cn\"), because\n the script will be\ + \ inferred from the input provided in the\n SynthesisInput. The TTS service\ + \ will use this parameter to\n help choose an appropriate voice. Note that\ + \ the TTS service\n may choose a voice with a slightly different language\ + \ code\n than the one selected; it may substitute a different region\n (e.g.\ + \ using en-US rather than en-CA if there isn't a\n Canadian voice available),\ + \ or even a different language,\n e.g. using \"nb\" (Norwegian Bokmal) instead\ + \ of \"no\"\n (Norwegian)\"." + id: language_code + var_type: str + - description: "The name of the voice. If not set, the service will choose a\n \ + \ voice based on the other parameters such as language_code\n and gender." + id: name + var_type: str + - description: "The preferred gender of the voice. If not set, the service\n will\ + \ choose a voice based on the other parameters such as\n language_code and\ + \ name. Note that this is only a preference,\n not requirement; if a voice\ + \ of the appropriate gender is not\n available, the synthesizer should substitute\ + \ a voice with a\n different gender rather than failing the request." + id: ssml_gender + var_type: google.cloud.texttospeech_v1.types.SsmlVoiceGender + - description: "The configuration for a custom voice. If\n [CustomVoiceParams.model]\ + \ is set, the service will choose\n the custom voice matching the specified\ + \ configuration." + id: custom_voice + var_type: google.cloud.texttospeech_v1.types.CustomVoiceParams + children: [] + class: google.cloud.texttospeech_v1.types.VoiceSelectionParams + fullName: google.cloud.texttospeech_v1.types.VoiceSelectionParams + inheritance: + - inheritance: + - type: builtins.object + type: proto.message.Message + langs: + - python + module: google.cloud.texttospeech_v1.types + name: VoiceSelectionParams + source: + id: VoiceSelectionParams + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 206 + summary: 'Description of which voice to use for a synthesis request. + + ' + syntax: + content: VoiceSelectionParams(mapping=None, *, ignore_unknown_fields=False, **kwargs) + parameters: [] + type: class + uid: google.cloud.texttospeech_v1.types.VoiceSelectionParams +references: [] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.yml new file mode 100644 index 000000000000..62e40a3ea2cf --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.yml @@ -0,0 +1,88 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- children: + - google.cloud.texttospeech_v1.types.AudioConfig + - google.cloud.texttospeech_v1.types.AudioEncoding + - google.cloud.texttospeech_v1.types.CustomVoiceParams + - google.cloud.texttospeech_v1.types.ListVoicesRequest + - google.cloud.texttospeech_v1.types.ListVoicesResponse + - google.cloud.texttospeech_v1.types.SsmlVoiceGender + - google.cloud.texttospeech_v1.types.SynthesisInput + - google.cloud.texttospeech_v1.types.SynthesizeSpeechRequest + - google.cloud.texttospeech_v1.types.SynthesizeSpeechResponse + - google.cloud.texttospeech_v1.types.Voice + - google.cloud.texttospeech_v1.types.VoiceSelectionParams + fullName: google.cloud.texttospeech_v1.types + langs: + - python + module: google.cloud.texttospeech_v1.types + name: types + source: + id: types + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/__init__.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/__init__.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 0 + summary: API documentation for `texttospeech_v1.types` package. + syntax: {} + type: subPackage + uid: google.cloud.texttospeech_v1.types +references: +- fullName: google.cloud.texttospeech_v1.types.AudioConfig + isExternal: false + name: AudioConfig + parent: google.cloud.texttospeech_v1.types + uid: google.cloud.texttospeech_v1.types.AudioConfig +- fullName: google.cloud.texttospeech_v1.types.AudioEncoding + isExternal: false + name: AudioEncoding + parent: google.cloud.texttospeech_v1.types + uid: google.cloud.texttospeech_v1.types.AudioEncoding +- fullName: google.cloud.texttospeech_v1.types.CustomVoiceParams + isExternal: false + name: CustomVoiceParams + parent: google.cloud.texttospeech_v1.types + uid: google.cloud.texttospeech_v1.types.CustomVoiceParams +- fullName: google.cloud.texttospeech_v1.types.ListVoicesRequest + isExternal: false + name: ListVoicesRequest + parent: google.cloud.texttospeech_v1.types + uid: google.cloud.texttospeech_v1.types.ListVoicesRequest +- fullName: google.cloud.texttospeech_v1.types.ListVoicesResponse + isExternal: false + name: ListVoicesResponse + parent: google.cloud.texttospeech_v1.types + uid: google.cloud.texttospeech_v1.types.ListVoicesResponse +- fullName: google.cloud.texttospeech_v1.types.SsmlVoiceGender + isExternal: false + name: SsmlVoiceGender + parent: google.cloud.texttospeech_v1.types + uid: google.cloud.texttospeech_v1.types.SsmlVoiceGender +- fullName: google.cloud.texttospeech_v1.types.SynthesisInput + isExternal: false + name: SynthesisInput + parent: google.cloud.texttospeech_v1.types + uid: google.cloud.texttospeech_v1.types.SynthesisInput +- fullName: google.cloud.texttospeech_v1.types.SynthesizeSpeechRequest + isExternal: false + name: SynthesizeSpeechRequest + parent: google.cloud.texttospeech_v1.types + uid: google.cloud.texttospeech_v1.types.SynthesizeSpeechRequest +- fullName: google.cloud.texttospeech_v1.types.SynthesizeSpeechResponse + isExternal: false + name: SynthesizeSpeechResponse + parent: google.cloud.texttospeech_v1.types + uid: google.cloud.texttospeech_v1.types.SynthesizeSpeechResponse +- fullName: google.cloud.texttospeech_v1.types.Voice + isExternal: false + name: Voice + parent: google.cloud.texttospeech_v1.types + uid: google.cloud.texttospeech_v1.types.Voice +- fullName: google.cloud.texttospeech_v1.types.VoiceSelectionParams + isExternal: false + name: VoiceSelectionParams + parent: google.cloud.texttospeech_v1.types + uid: google.cloud.texttospeech_v1.types.VoiceSelectionParams diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.yml new file mode 100644 index 000000000000..9ba4d5d190e0 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.yml @@ -0,0 +1,846 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: [] + children: + - google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + - google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.common_billing_account_path + - google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.common_folder_path + - google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.common_location_path + - google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.common_organization_path + - google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.common_project_path + - google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.from_service_account_file + - google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.from_service_account_info + - google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.from_service_account_json + - google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.get_mtls_endpoint_and_cert_source + - google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.get_transport_class + - google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.list_voices + - google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.model_path + - google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_billing_account_path + - google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_folder_path + - google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_location_path + - google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_organization_path + - google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_project_path + - google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.parse_model_path + - google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.synthesize_speech + - google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.transport + class: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + inheritance: + - type: builtins.object + langs: + - python + module: google.cloud.texttospeech_v1beta1.services.text_to_speech + name: TextToSpeechAsyncClient + source: + id: TextToSpeechAsyncClient + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/async_client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/async_client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 41 + summary: 'Service that implements Google Cloud Text-to-Speech API. + + + ' + syntax: + content: 'TextToSpeechAsyncClient(*, credentials: typing.Optional[google.auth.credentials.Credentials] + = None, transport: typing.Union[str, google.cloud.texttospeech_v1beta1.services.text_to_speech.transports.base.TextToSpeechTransport] + = ''grpc_asyncio'', client_options: typing.Optional[google.api_core.client_options.ClientOptions] + = None, client_info: google.api_core.gapic_v1.client_info.ClientInfo = )' + parameters: [] + type: class + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient +- attributes: [] + class: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + inheritance: + - type: builtins.object + langs: + - python + module: google.cloud.texttospeech_v1beta1.services.text_to_speech + name: TextToSpeechAsyncClient + source: + id: TextToSpeechAsyncClient + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/async_client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/async_client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 41 + summary: 'Instantiates the text to speech client. + + ' + syntax: + content: 'TextToSpeechAsyncClient(*, credentials: typing.Optional[google.auth.credentials.Credentials] + = None, transport: typing.Union[str, google.cloud.texttospeech_v1beta1.services.text_to_speech.transports.base.TextToSpeechTransport] + = ''grpc_asyncio'', client_options: typing.Optional[google.api_core.client_options.ClientOptions] + = None, client_info: google.api_core.gapic_v1.client_info.ClientInfo = )' + exceptions: + - description: If mutual TLS transport creation failed for any reason. + var_type: google.auth.exceptions.MutualTlsChannelError + parameters: + - description: The authorization credentials to attach to requests. These credentials + identify the application to the service; if none are specified, the client + will attempt to ascertain the credentials from the environment. + id: credentials + var_type: Optional[google.auth.credentials.Credentials] + - description: The transport to use. If set to None, a transport is chosen automatically. + id: transport + var_type: Union[str, .TextToSpeechTransport] + - description: 'Custom options for the client. It won''t take effect if a transport + instance is provided. (1) The api_endpoint property can be used + to override the default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT + environment variable can also be used to override the endpoint: "always" (always + use the default mTLS endpoint), "never" (always use the default regular endpoint) + and "auto" (auto switch to the default mTLS endpoint if client certificate + is present, this is the default value). However, the api_endpoint + property takes precedence if provided. (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE + environment variable is "true", then the client_cert_source property + can be used to provide client certificate for mutual TLS transport. If not + provided, the default SSL client certificate will be used if present. If GOOGLE_API_USE_CLIENT_CERTIFICATE + is "false" or not set, no client certificate will be used.' + id: client_options + var_type: ClientOptions + type: method + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient +- attributes: [] + class: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.common_billing_account_path + langs: + - python + module: google.cloud.texttospeech_v1beta1.services.text_to_speech + name: common_billing_account_path + source: + id: common_billing_account_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 185 + summary: 'Returns a fully-qualified billing_account string. + + + ' + syntax: + content: 'common_billing_account_path(billing_account: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.common_billing_account_path +- attributes: [] + class: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.common_folder_path + langs: + - python + module: google.cloud.texttospeech_v1beta1.services.text_to_speech + name: common_folder_path + source: + id: common_folder_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 200 + summary: 'Returns a fully-qualified folder string. + + + ' + syntax: + content: 'common_folder_path(folder: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.common_folder_path +- attributes: [] + class: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.common_location_path + langs: + - python + module: google.cloud.texttospeech_v1beta1.services.text_to_speech + name: common_location_path + source: + id: common_location_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 245 + summary: 'Returns a fully-qualified location string. + + + ' + syntax: + content: 'common_location_path(project: str, location: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.common_location_path +- attributes: [] + class: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.common_organization_path + langs: + - python + module: google.cloud.texttospeech_v1beta1.services.text_to_speech + name: common_organization_path + source: + id: common_organization_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 215 + summary: 'Returns a fully-qualified organization string. + + + ' + syntax: + content: 'common_organization_path(organization: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.common_organization_path +- attributes: [] + class: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.common_project_path + langs: + - python + module: google.cloud.texttospeech_v1beta1.services.text_to_speech + name: common_project_path + source: + id: common_project_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 230 + summary: 'Returns a fully-qualified project string. + + + ' + syntax: + content: 'common_project_path(project: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.common_project_path +- attributes: [] + class: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.from_service_account_file + langs: + - python + module: google.cloud.texttospeech_v1beta1.services.text_to_speech + name: from_service_account_file + source: + id: from_service_account_file + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/async_client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/async_client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 87 + summary: "Creates an instance of this client using the provided credentials\n \ + \ file.\n" + syntax: + content: 'from_service_account_file(filename: str, *args, **kwargs)' + parameters: + - description: The path to the service account private key json file. + id: filename + var_type: str + returns: + - description: The constructed client. + var_type: TextToSpeechAsyncClient + type: method + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.from_service_account_file +- attributes: [] + class: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.from_service_account_info + langs: + - python + module: google.cloud.texttospeech_v1beta1.services.text_to_speech + name: from_service_account_info + source: + id: from_service_account_info + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/async_client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/async_client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 72 + summary: "Creates an instance of this client using the provided credentials\n \ + \ info.\n" + syntax: + content: 'from_service_account_info(info: dict, *args, **kwargs)' + parameters: + - description: The service account private key info. + id: info + var_type: dict + returns: + - description: The constructed client. + var_type: TextToSpeechAsyncClient + type: method + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.from_service_account_info +- attributes: [] + class: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.from_service_account_json + langs: + - python + module: google.cloud.texttospeech_v1beta1.services.text_to_speech + name: from_service_account_json + source: + id: from_service_account_json + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/async_client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/async_client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 87 + summary: "Creates an instance of this client using the provided credentials\n \ + \ file.\n" + syntax: + content: 'from_service_account_json(filename: str, *args, **kwargs)' + parameters: + - description: The path to the service account private key json file. + id: filename + var_type: str + returns: + - description: The constructed client. + var_type: TextToSpeechAsyncClient + type: method + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.from_service_account_json +- attributes: [] + class: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.get_mtls_endpoint_and_cert_source + langs: + - python + module: google.cloud.texttospeech_v1beta1.services.text_to_speech + name: get_mtls_endpoint_and_cert_source + source: + id: get_mtls_endpoint_and_cert_source + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/async_client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/async_client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 105 + summary: 'Return the API endpoint and client cert source for mutual TLS. + + + The client cert source is determined in the following order: + + (1) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not "true", + the + + client cert source is None. + + (2) if `client_options.client_cert_source` is provided, use the provided one; + if the + + default client cert source exists, use the default one; otherwise the client cert + + source is None. + + + The API endpoint is determined in the following order: + + (1) if `client_options.api_endpoint` if provided, use the provided one. + + (2) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is "always", use + the + + default mTLS endpoint; if the environment variabel is "never", use the default + API + + endpoint; otherwise if client cert source exists, use the default mTLS endpoint, + otherwise + + use the default API endpoint. + + + More details can be found at https://google.aip.dev/auth/4114. + + ' + syntax: + content: "get_mtls_endpoint_and_cert_source(\n client_options: typing.Optional[\n\ + \ google.api_core.client_options.ClientOptions\n ] = None,\n)" + exceptions: + - description: If any errors happen. + var_type: google.auth.exceptions.MutualTLSChannelError + parameters: + - defaultValue: None + description: Custom options for the client. Only the api_endpoint + and client_cert_source properties may be used in this method. + id: client_options + var_type: google.api_core.client_options.ClientOptions + returns: + - description: returns the API endpoint and the client cert source to use. + var_type: Tuple[str, Callable[[], Tuple[bytes, bytes]]] + type: method + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.get_mtls_endpoint_and_cert_source +- attributes: [] + class: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.get_transport_class + langs: + - python + module: google.cloud.texttospeech_v1beta1.services.text_to_speech + name: get_transport_class + source: + id: get_transport_class + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Returns an appropriate transport class. + + ' + syntax: + content: get_transport_class() + parameters: [] + type: method + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.get_transport_class +- attributes: [] + class: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.list_voices + langs: + - python + module: google.cloud.texttospeech_v1beta1.services.text_to_speech + name: list_voices + source: + id: list_voices + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/async_client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/async_client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 201 + summary: "Returns a list of Voice supported for synthesis.\n\n```python\n# This\ + \ snippet has been automatically generated and should be regarded as a\n# code\ + \ template only.\n# It will require modifications to work:\n# - It may require\ + \ correct/in-range values for request initialization.\n# - It may require specifying\ + \ regional endpoints when creating the service\n# client as shown in:\n# https://googleapis.dev/python/google-api-core/latest/client_options.html\n\ + from google.cloud import texttospeech_v1beta1\n\nasync def sample_list_voices():\n\ + \ # Create a client\n client = texttospeech_v1beta1.TextToSpeechAsyncClient()\n\ + \n # Initialize request argument(s)\n request = texttospeech_v1beta1.ListVoicesRequest(\n\ + \ )\n\n # Make the request\n response = await client.list_voices(request=request)\n\ + \n # Handle the response\n print(response)\n```\n" + syntax: + content: "list_voices(\n request: typing.Optional[\n typing.Union[\n\ + \ google.cloud.texttospeech_v1beta1.types.cloud_tts.ListVoicesRequest,\ + \ dict\n ]\n ] = None,\n *,\n language_code: typing.Optional[str]\ + \ = None,\n retry: typing.Union[\n google.api_core.retry.Retry, google.api_core.gapic_v1.method._MethodDefault\n\ + \ ] = _MethodDefault._DEFAULT_VALUE,\n timeout: typing.Optional[float]\ + \ = None,\n metadata: typing.Sequence[typing.Tuple[str, str]] = ()\n)" + parameters: + - defaultValue: None + description: The request object. The top-level message sent by the client for + the ListVoices method. + id: request + var_type: Union[google.cloud.texttospeech_v1beta1.types.ListVoicesRequest, + dict] + - description: Optional. Recommended. BCP-47 __ + language tag. If not specified, the API will return all supported voices. + If specified, the ListVoices call will only return voices that can be used + to synthesize this language_code. For example, if you specify "en-NZ", + all "en-NZ" voices will be returned. If you specify "no", + both "no-\*" (Norwegian) and "nb-\*" (Norwegian + Bokmal) voices will be returned. This corresponds to the language_code + field on the request instance; if request is provided, + this should not be set. + id: language_code + var_type: str + - description: Designation of what errors, if any, should be retried. + id: retry + var_type: google.api_core.retry.Retry + - description: The timeout for this request. + id: timeout + var_type: float + - description: Strings which should be sent along with the request as metadata. + id: metadata + var_type: Sequence[Tuple[str, str]] + returns: + - description: The message returned to the client by the ListVoices method. + var_type: google.cloud.texttospeech_v1beta1.types.ListVoicesResponse + type: method + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.list_voices +- attributes: [] + class: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.model_path + langs: + - python + module: google.cloud.texttospeech_v1beta1.services.text_to_speech + name: model_path + source: + id: model_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 163 + summary: 'Returns a fully-qualified model string. + + + ' + syntax: + content: 'model_path(project: str, location: str, model: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.model_path +- attributes: [] + class: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_billing_account_path + langs: + - python + module: google.cloud.texttospeech_v1beta1.services.text_to_speech + name: parse_common_billing_account_path + source: + id: parse_common_billing_account_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 194 + summary: 'Parse a billing_account path into its component segments. + + + ' + syntax: + content: 'parse_common_billing_account_path(path: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_billing_account_path +- attributes: [] + class: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_folder_path + langs: + - python + module: google.cloud.texttospeech_v1beta1.services.text_to_speech + name: parse_common_folder_path + source: + id: parse_common_folder_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 209 + summary: 'Parse a folder path into its component segments. + + + ' + syntax: + content: 'parse_common_folder_path(path: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_folder_path +- attributes: [] + class: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_location_path + langs: + - python + module: google.cloud.texttospeech_v1beta1.services.text_to_speech + name: parse_common_location_path + source: + id: parse_common_location_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 256 + summary: 'Parse a location path into its component segments. + + + ' + syntax: + content: 'parse_common_location_path(path: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_location_path +- attributes: [] + class: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_organization_path + langs: + - python + module: google.cloud.texttospeech_v1beta1.services.text_to_speech + name: parse_common_organization_path + source: + id: parse_common_organization_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 224 + summary: 'Parse a organization path into its component segments. + + + ' + syntax: + content: 'parse_common_organization_path(path: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_organization_path +- attributes: [] + class: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_project_path + langs: + - python + module: google.cloud.texttospeech_v1beta1.services.text_to_speech + name: parse_common_project_path + source: + id: parse_common_project_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 239 + summary: 'Parse a project path into its component segments. + + + ' + syntax: + content: 'parse_common_project_path(path: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_project_path +- attributes: [] + class: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.parse_model_path + langs: + - python + module: google.cloud.texttospeech_v1beta1.services.text_to_speech + name: parse_model_path + source: + id: parse_model_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 176 + summary: 'Parses a model path into its component segments. + + + ' + syntax: + content: 'parse_model_path(path: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.parse_model_path +- attributes: [] + class: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.synthesize_speech + langs: + - python + module: google.cloud.texttospeech_v1beta1.services.text_to_speech + name: synthesize_speech + source: + id: synthesize_speech + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/async_client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/async_client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 303 + summary: "Synthesizes speech synchronously: receive results\nafter all text input\ + \ has been processed.\n\n```python\n# This snippet has been automatically generated\ + \ and should be regarded as a\n# code template only.\n# It will require modifications\ + \ to work:\n# - It may require correct/in-range values for request initialization.\n\ + # - It may require specifying regional endpoints when creating the service\n#\ + \ client as shown in:\n# https://googleapis.dev/python/google-api-core/latest/client_options.html\n\ + from google.cloud import texttospeech_v1beta1\n\nasync def sample_synthesize_speech():\n\ + \ # Create a client\n client = texttospeech_v1beta1.TextToSpeechAsyncClient()\n\ + \n # Initialize request argument(s)\n input = texttospeech_v1beta1.SynthesisInput()\n\ + \ input.text = \"text_value\"\n\n voice = texttospeech_v1beta1.VoiceSelectionParams()\n\ + \ voice.language_code = \"language_code_value\"\n\n audio_config = texttospeech_v1beta1.AudioConfig()\n\ + \ audio_config.audio_encoding = \"ALAW\"\n\n request = texttospeech_v1beta1.SynthesizeSpeechRequest(\n\ + \ input=input,\n voice=voice,\n audio_config=audio_config,\n\ + \ )\n\n # Make the request\n response = await client.synthesize_speech(request=request)\n\ + \n # Handle the response\n print(response)\n```\n" + syntax: + content: "synthesize_speech(\n request: typing.Optional[\n typing.Union[\n\ + \ google.cloud.texttospeech_v1beta1.types.cloud_tts.SynthesizeSpeechRequest,\n\ + \ dict,\n ]\n ] = None,\n *,\n input: typing.Optional[\n\ + \ google.cloud.texttospeech_v1beta1.types.cloud_tts.SynthesisInput\n\ + \ ] = None,\n voice: typing.Optional[\n google.cloud.texttospeech_v1beta1.types.cloud_tts.VoiceSelectionParams\n\ + \ ] = None,\n audio_config: typing.Optional[\n google.cloud.texttospeech_v1beta1.types.cloud_tts.AudioConfig\n\ + \ ] = None,\n retry: typing.Union[\n google.api_core.retry.Retry,\ + \ google.api_core.gapic_v1.method._MethodDefault\n ] = _MethodDefault._DEFAULT_VALUE,\n\ + \ timeout: typing.Optional[float] = None,\n metadata: typing.Sequence[typing.Tuple[str,\ + \ str]] = ()\n)" + parameters: + - defaultValue: None + description: The request object. The top-level message sent by the client for + the SynthesizeSpeech method. + id: request + var_type: Union[google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechRequest, + dict] + - description: Required. The Synthesizer requires either plain text or SSML as + input. This corresponds to the input field on the request + instance; if request is provided, this should not be set. + id: input + var_type: SynthesisInput + - description: Required. The desired voice of the synthesized audio. This corresponds + to the voice field on the request instance; if request + is provided, this should not be set. + id: voice + var_type: VoiceSelectionParams + - description: Required. The configuration of the synthesized audio. This corresponds + to the audio_config field on the request instance; + if request is provided, this should not be set. + id: audio_config + var_type: AudioConfig + - description: Designation of what errors, if any, should be retried. + id: retry + var_type: google.api_core.retry.Retry + - description: The timeout for this request. + id: timeout + var_type: float + - description: Strings which should be sent along with the request as metadata. + id: metadata + var_type: Sequence[Tuple[str, str]] + returns: + - description: The message returned to the client by the SynthesizeSpeech method. + var_type: google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechResponse + type: method + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.synthesize_speech +- &id001 + attributes: [] + class: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.transport + langs: + - python + module: google.cloud.texttospeech_v1beta1.services.text_to_speech + name: transport + source: + id: transport + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Returns the transport used by the client instance. + + ' + syntax: + returns: + - description: The transport used by the client instance. + var_type: TextToSpeechTransport + type: property + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.transport +- *id001 +references: +- fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + isExternal: false + name: TextToSpeechAsyncClient + parent: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient +- fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.common_billing_account_path + isExternal: false + name: common_billing_account_path + parent: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.common_billing_account_path +- fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.common_folder_path + isExternal: false + name: common_folder_path + parent: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.common_folder_path +- fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.common_location_path + isExternal: false + name: common_location_path + parent: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.common_location_path +- fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.common_organization_path + isExternal: false + name: common_organization_path + parent: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.common_organization_path +- fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.common_project_path + isExternal: false + name: common_project_path + parent: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.common_project_path +- fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.from_service_account_file + isExternal: false + name: from_service_account_file + parent: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.from_service_account_file +- fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.from_service_account_info + isExternal: false + name: from_service_account_info + parent: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.from_service_account_info +- fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.from_service_account_json + isExternal: false + name: from_service_account_json + parent: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.from_service_account_json +- fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.get_mtls_endpoint_and_cert_source + isExternal: false + name: get_mtls_endpoint_and_cert_source + parent: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.get_mtls_endpoint_and_cert_source +- fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.get_transport_class + isExternal: false + name: get_transport_class + parent: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.get_transport_class +- fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.list_voices + isExternal: false + name: list_voices + parent: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.list_voices +- fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.model_path + isExternal: false + name: model_path + parent: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.model_path +- fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_billing_account_path + isExternal: false + name: parse_common_billing_account_path + parent: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_billing_account_path +- fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_folder_path + isExternal: false + name: parse_common_folder_path + parent: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_folder_path +- fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_location_path + isExternal: false + name: parse_common_location_path + parent: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_location_path +- fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_organization_path + isExternal: false + name: parse_common_organization_path + parent: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_organization_path +- fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_project_path + isExternal: false + name: parse_common_project_path + parent: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.parse_common_project_path +- fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.parse_model_path + isExternal: false + name: parse_model_path + parent: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.parse_model_path +- fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.synthesize_speech + isExternal: false + name: synthesize_speech + parent: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.synthesize_speech +- fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.transport + isExternal: false + name: transport + parent: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.transport diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.yml new file mode 100644 index 000000000000..9b83f59cd439 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.yml @@ -0,0 +1,862 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: [] + children: + - google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + - google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.__exit__ + - google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.common_billing_account_path + - google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.common_folder_path + - google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.common_location_path + - google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.common_organization_path + - google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.common_project_path + - google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.from_service_account_file + - google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.from_service_account_info + - google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.from_service_account_json + - google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.get_mtls_endpoint_and_cert_source + - google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.list_voices + - google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.model_path + - google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.parse_common_billing_account_path + - google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.parse_common_folder_path + - google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.parse_common_location_path + - google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.parse_common_organization_path + - google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.parse_common_project_path + - google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.parse_model_path + - google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.synthesize_speech + - google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.transport + class: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + inheritance: + - type: builtins.object + langs: + - python + module: google.cloud.texttospeech_v1beta1.services.text_to_speech + name: TextToSpeechClient + source: + id: TextToSpeechClient + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 78 + summary: 'Service that implements Google Cloud Text-to-Speech API. + + + ' + syntax: + content: 'TextToSpeechClient(*, credentials: typing.Optional[google.auth.credentials.Credentials] + = None, transport: typing.Optional[typing.Union[str, google.cloud.texttospeech_v1beta1.services.text_to_speech.transports.base.TextToSpeechTransport]] + = None, client_options: typing.Optional[google.api_core.client_options.ClientOptions] + = None, client_info: google.api_core.gapic_v1.client_info.ClientInfo = )' + parameters: [] + type: class + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient +- attributes: [] + class: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + inheritance: + - type: builtins.object + langs: + - python + module: google.cloud.texttospeech_v1beta1.services.text_to_speech + name: TextToSpeechClient + source: + id: TextToSpeechClient + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 78 + summary: 'Instantiates the text to speech client. + + ' + syntax: + content: 'TextToSpeechClient(*, credentials: typing.Optional[google.auth.credentials.Credentials] + = None, transport: typing.Optional[typing.Union[str, google.cloud.texttospeech_v1beta1.services.text_to_speech.transports.base.TextToSpeechTransport]] + = None, client_options: typing.Optional[google.api_core.client_options.ClientOptions] + = None, client_info: google.api_core.gapic_v1.client_info.ClientInfo = )' + exceptions: + - description: If mutual TLS transport creation failed for any reason. + var_type: google.auth.exceptions.MutualTLSChannelError + parameters: + - description: The authorization credentials to attach to requests. These credentials + identify the application to the service; if none are specified, the client + will attempt to ascertain the credentials from the environment. + id: credentials + var_type: Optional[google.auth.credentials.Credentials] + - description: The transport to use. If set to None, a transport is chosen automatically. + id: transport + var_type: Union[str, TextToSpeechTransport] + - description: 'Custom options for the client. It won''t take effect if a transport + instance is provided. (1) The api_endpoint property can be used + to override the default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT + environment variable can also be used to override the endpoint: "always" (always + use the default mTLS endpoint), "never" (always use the default regular endpoint) + and "auto" (auto switch to the default mTLS endpoint if client certificate + is present, this is the default value). However, the api_endpoint + property takes precedence if provided. (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE + environment variable is "true", then the client_cert_source property + can be used to provide client certificate for mutual TLS transport. If not + provided, the default SSL client certificate will be used if present. If GOOGLE_API_USE_CLIENT_CERTIFICATE + is "false" or not set, no client certificate will be used.' + id: client_options + var_type: google.api_core.client_options.ClientOptions + - description: The client info used to send a user-agent string along with API + requests. If None, then default info will be used. Generally, + you only need to set this if you're developing your own client library. + id: client_info + var_type: google.api_core.gapic_v1.client_info.ClientInfo + type: method + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient +- attributes: [] + class: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.__exit__ + langs: + - python + module: google.cloud.texttospeech_v1beta1.services.text_to_speech + name: __exit__ + source: + id: __exit__ + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 661 + summary: 'Releases underlying transport''s resources. + + + ' + syntax: + content: __exit__(type, value, traceback) + parameters: [] + type: method + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.__exit__ +- attributes: [] + class: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.common_billing_account_path + langs: + - python + module: google.cloud.texttospeech_v1beta1.services.text_to_speech + name: common_billing_account_path + source: + id: common_billing_account_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 185 + summary: 'Returns a fully-qualified billing_account string. + + + ' + syntax: + content: 'common_billing_account_path(billing_account: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.common_billing_account_path +- attributes: [] + class: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.common_folder_path + langs: + - python + module: google.cloud.texttospeech_v1beta1.services.text_to_speech + name: common_folder_path + source: + id: common_folder_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 200 + summary: 'Returns a fully-qualified folder string. + + + ' + syntax: + content: 'common_folder_path(folder: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.common_folder_path +- attributes: [] + class: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.common_location_path + langs: + - python + module: google.cloud.texttospeech_v1beta1.services.text_to_speech + name: common_location_path + source: + id: common_location_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 245 + summary: 'Returns a fully-qualified location string. + + + ' + syntax: + content: 'common_location_path(project: str, location: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.common_location_path +- attributes: [] + class: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.common_organization_path + langs: + - python + module: google.cloud.texttospeech_v1beta1.services.text_to_speech + name: common_organization_path + source: + id: common_organization_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 215 + summary: 'Returns a fully-qualified organization string. + + + ' + syntax: + content: 'common_organization_path(organization: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.common_organization_path +- attributes: [] + class: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.common_project_path + langs: + - python + module: google.cloud.texttospeech_v1beta1.services.text_to_speech + name: common_project_path + source: + id: common_project_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 230 + summary: 'Returns a fully-qualified project string. + + + ' + syntax: + content: 'common_project_path(project: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.common_project_path +- attributes: [] + class: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.from_service_account_file + langs: + - python + module: google.cloud.texttospeech_v1beta1.services.text_to_speech + name: from_service_account_file + source: + id: from_service_account_file + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 133 + summary: "Creates an instance of this client using the provided credentials\n \ + \ file.\n" + syntax: + content: 'from_service_account_file(filename: str, *args, **kwargs)' + parameters: + - description: The path to the service account private key json file. + id: filename + var_type: str + returns: + - description: The constructed client. + var_type: TextToSpeechClient + type: method + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.from_service_account_file +- attributes: [] + class: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.from_service_account_info + langs: + - python + module: google.cloud.texttospeech_v1beta1.services.text_to_speech + name: from_service_account_info + source: + id: from_service_account_info + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 116 + summary: "Creates an instance of this client using the provided credentials\n \ + \ info.\n" + syntax: + content: 'from_service_account_info(info: dict, *args, **kwargs)' + parameters: + - description: The service account private key info. + id: info + var_type: dict + returns: + - description: The constructed client. + var_type: TextToSpeechClient + type: method + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.from_service_account_info +- attributes: [] + class: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.from_service_account_json + langs: + - python + module: google.cloud.texttospeech_v1beta1.services.text_to_speech + name: from_service_account_json + source: + id: from_service_account_json + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 133 + summary: "Creates an instance of this client using the provided credentials\n \ + \ file.\n" + syntax: + content: 'from_service_account_json(filename: str, *args, **kwargs)' + parameters: + - description: The path to the service account private key json file. + id: filename + var_type: str + returns: + - description: The constructed client. + var_type: TextToSpeechClient + type: method + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.from_service_account_json +- attributes: [] + class: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.get_mtls_endpoint_and_cert_source + langs: + - python + module: google.cloud.texttospeech_v1beta1.services.text_to_speech + name: get_mtls_endpoint_and_cert_source + source: + id: get_mtls_endpoint_and_cert_source + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 262 + summary: 'Return the API endpoint and client cert source for mutual TLS. + + + The client cert source is determined in the following order: + + (1) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not "true", + the + + client cert source is None. + + (2) if `client_options.client_cert_source` is provided, use the provided one; + if the + + default client cert source exists, use the default one; otherwise the client cert + + source is None. + + + The API endpoint is determined in the following order: + + (1) if `client_options.api_endpoint` if provided, use the provided one. + + (2) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is "always", use + the + + default mTLS endpoint; if the environment variabel is "never", use the default + API + + endpoint; otherwise if client cert source exists, use the default mTLS endpoint, + otherwise + + use the default API endpoint. + + + More details can be found at https://google.aip.dev/auth/4114. + + ' + syntax: + content: "get_mtls_endpoint_and_cert_source(\n client_options: typing.Optional[\n\ + \ google.api_core.client_options.ClientOptions\n ] = None,\n)" + exceptions: + - description: If any errors happen. + var_type: google.auth.exceptions.MutualTLSChannelError + parameters: + - defaultValue: None + description: Custom options for the client. Only the api_endpoint + and client_cert_source properties may be used in this method. + id: client_options + var_type: google.api_core.client_options.ClientOptions + returns: + - description: returns the API endpoint and the client cert source to use. + var_type: Tuple[str, Callable[[], Tuple[bytes, bytes]]] + type: method + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.get_mtls_endpoint_and_cert_source +- attributes: [] + class: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.list_voices + langs: + - python + module: google.cloud.texttospeech_v1beta1.services.text_to_speech + name: list_voices + source: + id: list_voices + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 428 + summary: "Returns a list of Voice supported for synthesis.\n\n```python\n# This\ + \ snippet has been automatically generated and should be regarded as a\n# code\ + \ template only.\n# It will require modifications to work:\n# - It may require\ + \ correct/in-range values for request initialization.\n# - It may require specifying\ + \ regional endpoints when creating the service\n# client as shown in:\n# https://googleapis.dev/python/google-api-core/latest/client_options.html\n\ + from google.cloud import texttospeech_v1beta1\n\ndef sample_list_voices():\n \ + \ # Create a client\n client = texttospeech_v1beta1.TextToSpeechClient()\n\ + \n # Initialize request argument(s)\n request = texttospeech_v1beta1.ListVoicesRequest(\n\ + \ )\n\n # Make the request\n response = client.list_voices(request=request)\n\ + \n # Handle the response\n print(response)\n```\n" + syntax: + content: "list_voices(\n request: typing.Optional[\n typing.Union[\n\ + \ google.cloud.texttospeech_v1beta1.types.cloud_tts.ListVoicesRequest,\ + \ dict\n ]\n ] = None,\n *,\n language_code: typing.Optional[str]\ + \ = None,\n retry: typing.Union[\n google.api_core.retry.Retry, google.api_core.gapic_v1.method._MethodDefault\n\ + \ ] = _MethodDefault._DEFAULT_VALUE,\n timeout: typing.Optional[float]\ + \ = None,\n metadata: typing.Sequence[typing.Tuple[str, str]] = ()\n)" + parameters: + - defaultValue: None + description: The request object. The top-level message sent by the client for + the ListVoices method. + id: request + var_type: Union[google.cloud.texttospeech_v1beta1.types.ListVoicesRequest, + dict] + - description: Optional. Recommended. BCP-47 __ + language tag. If not specified, the API will return all supported voices. + If specified, the ListVoices call will only return voices that can be used + to synthesize this language_code. For example, if you specify "en-NZ", + all "en-NZ" voices will be returned. If you specify "no", + both "no-\*" (Norwegian) and "nb-\*" (Norwegian + Bokmal) voices will be returned. This corresponds to the language_code + field on the request instance; if request is provided, + this should not be set. + id: language_code + var_type: str + - description: Designation of what errors, if any, should be retried. + id: retry + var_type: google.api_core.retry.Retry + - description: The timeout for this request. + id: timeout + var_type: float + - description: Strings which should be sent along with the request as metadata. + id: metadata + var_type: Sequence[Tuple[str, str]] + returns: + - description: The message returned to the client by the ListVoices method. + var_type: google.cloud.texttospeech_v1beta1.types.ListVoicesResponse + type: method + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.list_voices +- attributes: [] + class: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.model_path + langs: + - python + module: google.cloud.texttospeech_v1beta1.services.text_to_speech + name: model_path + source: + id: model_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 163 + summary: 'Returns a fully-qualified model string. + + + ' + syntax: + content: 'model_path(project: str, location: str, model: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.model_path +- attributes: [] + class: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.parse_common_billing_account_path + langs: + - python + module: google.cloud.texttospeech_v1beta1.services.text_to_speech + name: parse_common_billing_account_path + source: + id: parse_common_billing_account_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 194 + summary: 'Parse a billing_account path into its component segments. + + + ' + syntax: + content: 'parse_common_billing_account_path(path: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.parse_common_billing_account_path +- attributes: [] + class: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.parse_common_folder_path + langs: + - python + module: google.cloud.texttospeech_v1beta1.services.text_to_speech + name: parse_common_folder_path + source: + id: parse_common_folder_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 209 + summary: 'Parse a folder path into its component segments. + + + ' + syntax: + content: 'parse_common_folder_path(path: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.parse_common_folder_path +- attributes: [] + class: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.parse_common_location_path + langs: + - python + module: google.cloud.texttospeech_v1beta1.services.text_to_speech + name: parse_common_location_path + source: + id: parse_common_location_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 256 + summary: 'Parse a location path into its component segments. + + + ' + syntax: + content: 'parse_common_location_path(path: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.parse_common_location_path +- attributes: [] + class: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.parse_common_organization_path + langs: + - python + module: google.cloud.texttospeech_v1beta1.services.text_to_speech + name: parse_common_organization_path + source: + id: parse_common_organization_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 224 + summary: 'Parse a organization path into its component segments. + + + ' + syntax: + content: 'parse_common_organization_path(path: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.parse_common_organization_path +- attributes: [] + class: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.parse_common_project_path + langs: + - python + module: google.cloud.texttospeech_v1beta1.services.text_to_speech + name: parse_common_project_path + source: + id: parse_common_project_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 239 + summary: 'Parse a project path into its component segments. + + + ' + syntax: + content: 'parse_common_project_path(path: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.parse_common_project_path +- attributes: [] + class: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.parse_model_path + langs: + - python + module: google.cloud.texttospeech_v1beta1.services.text_to_speech + name: parse_model_path + source: + id: parse_model_path + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 176 + summary: 'Parses a model path into its component segments. + + + ' + syntax: + content: 'parse_model_path(path: str)' + parameters: [] + type: method + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.parse_model_path +- attributes: [] + class: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.synthesize_speech + langs: + - python + module: google.cloud.texttospeech_v1beta1.services.text_to_speech + name: synthesize_speech + source: + id: synthesize_speech + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 530 + summary: "Synthesizes speech synchronously: receive results\nafter all text input\ + \ has been processed.\n\n```python\n# This snippet has been automatically generated\ + \ and should be regarded as a\n# code template only.\n# It will require modifications\ + \ to work:\n# - It may require correct/in-range values for request initialization.\n\ + # - It may require specifying regional endpoints when creating the service\n#\ + \ client as shown in:\n# https://googleapis.dev/python/google-api-core/latest/client_options.html\n\ + from google.cloud import texttospeech_v1beta1\n\ndef sample_synthesize_speech():\n\ + \ # Create a client\n client = texttospeech_v1beta1.TextToSpeechClient()\n\ + \n # Initialize request argument(s)\n input = texttospeech_v1beta1.SynthesisInput()\n\ + \ input.text = \"text_value\"\n\n voice = texttospeech_v1beta1.VoiceSelectionParams()\n\ + \ voice.language_code = \"language_code_value\"\n\n audio_config = texttospeech_v1beta1.AudioConfig()\n\ + \ audio_config.audio_encoding = \"ALAW\"\n\n request = texttospeech_v1beta1.SynthesizeSpeechRequest(\n\ + \ input=input,\n voice=voice,\n audio_config=audio_config,\n\ + \ )\n\n # Make the request\n response = client.synthesize_speech(request=request)\n\ + \n # Handle the response\n print(response)\n```\n" + syntax: + content: "synthesize_speech(\n request: typing.Optional[\n typing.Union[\n\ + \ google.cloud.texttospeech_v1beta1.types.cloud_tts.SynthesizeSpeechRequest,\n\ + \ dict,\n ]\n ] = None,\n *,\n input: typing.Optional[\n\ + \ google.cloud.texttospeech_v1beta1.types.cloud_tts.SynthesisInput\n\ + \ ] = None,\n voice: typing.Optional[\n google.cloud.texttospeech_v1beta1.types.cloud_tts.VoiceSelectionParams\n\ + \ ] = None,\n audio_config: typing.Optional[\n google.cloud.texttospeech_v1beta1.types.cloud_tts.AudioConfig\n\ + \ ] = None,\n retry: typing.Union[\n google.api_core.retry.Retry,\ + \ google.api_core.gapic_v1.method._MethodDefault\n ] = _MethodDefault._DEFAULT_VALUE,\n\ + \ timeout: typing.Optional[float] = None,\n metadata: typing.Sequence[typing.Tuple[str,\ + \ str]] = ()\n)" + parameters: + - defaultValue: None + description: The request object. The top-level message sent by the client for + the SynthesizeSpeech method. + id: request + var_type: Union[google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechRequest, + dict] + - description: Required. The Synthesizer requires either plain text or SSML as + input. This corresponds to the input field on the request + instance; if request is provided, this should not be set. + id: input + var_type: google.cloud.texttospeech_v1beta1.types.SynthesisInput + - description: Required. The desired voice of the synthesized audio. This corresponds + to the voice field on the request instance; if request + is provided, this should not be set. + id: voice + var_type: google.cloud.texttospeech_v1beta1.types.VoiceSelectionParams + - description: Required. The configuration of the synthesized audio. This corresponds + to the audio_config field on the request instance; + if request is provided, this should not be set. + id: audio_config + var_type: google.cloud.texttospeech_v1beta1.types.AudioConfig + - description: Designation of what errors, if any, should be retried. + id: retry + var_type: google.api_core.retry.Retry + - description: The timeout for this request. + id: timeout + var_type: float + - description: Strings which should be sent along with the request as metadata. + id: metadata + var_type: Sequence[Tuple[str, str]] + returns: + - description: The message returned to the client by the SynthesizeSpeech method. + var_type: google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechResponse + type: method + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.synthesize_speech +- &id001 + attributes: [] + class: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.transport + langs: + - python + module: google.cloud.texttospeech_v1beta1.services.text_to_speech + name: transport + source: + id: transport + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Returns the transport used by the client instance. + + ' + syntax: + returns: + - description: The transport used by the client instance. + var_type: TextToSpeechTransport + type: property + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.transport +- *id001 +references: +- fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + isExternal: false + name: TextToSpeechClient + parent: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient +- fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.__exit__ + isExternal: false + name: __exit__ + parent: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.__exit__ +- fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.common_billing_account_path + isExternal: false + name: common_billing_account_path + parent: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.common_billing_account_path +- fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.common_folder_path + isExternal: false + name: common_folder_path + parent: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.common_folder_path +- fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.common_location_path + isExternal: false + name: common_location_path + parent: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.common_location_path +- fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.common_organization_path + isExternal: false + name: common_organization_path + parent: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.common_organization_path +- fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.common_project_path + isExternal: false + name: common_project_path + parent: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.common_project_path +- fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.from_service_account_file + isExternal: false + name: from_service_account_file + parent: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.from_service_account_file +- fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.from_service_account_info + isExternal: false + name: from_service_account_info + parent: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.from_service_account_info +- fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.from_service_account_json + isExternal: false + name: from_service_account_json + parent: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.from_service_account_json +- fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.get_mtls_endpoint_and_cert_source + isExternal: false + name: get_mtls_endpoint_and_cert_source + parent: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.get_mtls_endpoint_and_cert_source +- fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.list_voices + isExternal: false + name: list_voices + parent: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.list_voices +- fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.model_path + isExternal: false + name: model_path + parent: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.model_path +- fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.parse_common_billing_account_path + isExternal: false + name: parse_common_billing_account_path + parent: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.parse_common_billing_account_path +- fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.parse_common_folder_path + isExternal: false + name: parse_common_folder_path + parent: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.parse_common_folder_path +- fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.parse_common_location_path + isExternal: false + name: parse_common_location_path + parent: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.parse_common_location_path +- fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.parse_common_organization_path + isExternal: false + name: parse_common_organization_path + parent: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.parse_common_organization_path +- fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.parse_common_project_path + isExternal: false + name: parse_common_project_path + parent: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.parse_common_project_path +- fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.parse_model_path + isExternal: false + name: parse_model_path + parent: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.parse_model_path +- fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.synthesize_speech + isExternal: false + name: synthesize_speech + parent: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.synthesize_speech +- fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.transport + isExternal: false + name: transport + parent: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.transport diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.services.text_to_speech.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.services.text_to_speech.yml new file mode 100644 index 000000000000..c58a644d368e --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.services.text_to_speech.yml @@ -0,0 +1,34 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- children: + - google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + - google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech + langs: + - python + module: google.cloud.texttospeech_v1beta1.services.text_to_speech + name: text_to_speech + source: + id: text_to_speech + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/__init__.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/__init__.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 0 + summary: API documentation for `texttospeech_v1beta1.services.text_to_speech` package. + syntax: {} + type: subPackage + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech +references: +- fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + isExternal: false + name: TextToSpeechAsyncClient + parent: google.cloud.texttospeech_v1beta1.services.text_to_speech + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient +- fullName: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + isExternal: false + name: TextToSpeechClient + parent: google.cloud.texttospeech_v1beta1.services.text_to_speech + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.AudioConfig.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.AudioConfig.yml new file mode 100644 index 000000000000..c79100bc5255 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.AudioConfig.yml @@ -0,0 +1,73 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: + - description: "Required. The format of the audio byte\n stream." + id: audio_encoding + var_type: google.cloud.texttospeech_v1beta1.types.AudioEncoding + - description: "Optional. Input only. Speaking rate/speed, in the range\n [0.25,\ + \ 4.0]. 1.0 is the normal native speed supported by the\n specific voice.\ + \ 2.0 is twice as fast, and 0.5 is half as\n fast. If unset(0.0), defaults\ + \ to the native 1.0 speed. Any\n other values < 0.25 or > 4.0 will return\ + \ an error." + id: speaking_rate + var_type: float + - description: "Optional. Input only. Speaking pitch, in the range [-20.0,\n 20.0].\ + \ 20 means increase 20 semitones from the original\n pitch. -20 means decrease\ + \ 20 semitones from the original\n pitch." + id: pitch + var_type: float + - description: "Optional. Input only. Volume gain (in dB) of the normal\n native\ + \ volume supported by the specific voice, in the range\n [-96.0, 16.0]. If\ + \ unset, or set to a value of 0.0 (dB), will\n play at normal native signal\ + \ amplitude. A value of -6.0 (dB)\n will play at approximately half the amplitude\ + \ of the normal\n native signal amplitude. A value of +6.0 (dB) will play\ + \ at\n approximately twice the amplitude of the normal native\n signal amplitude.\ + \ Strongly recommend not to exceed +10 (dB)\n as there's usually no effective\ + \ increase in loudness for any\n value greater than that." + id: volume_gain_db + var_type: float + - description: "Optional. The synthesis sample rate (in hertz) for this\n audio.\ + \ When this is specified in SynthesizeSpeechRequest, if\n this is different\ + \ from the voice's natural sample rate, then\n the synthesizer will honor\ + \ this request by converting to the\n desired sample rate (which might result\ + \ in worse audio\n quality), unless the specified sample rate is not supported\n\ + \ for the encoding chosen, in which case it will fail the\n request and\ + \ return [google.rpc.Code.INVALID_ARGUMENT][]." + id: sample_rate_hertz + var_type: int + - description: "Optional. Input only. An identifier which selects 'audio\n effects'\ + \ profiles that are applied on (post synthesized)\n text to speech. Effects\ + \ are applied on top of each other in\n the order they are given. See `audio\n\ + \ profiles `__\n\ + \ for current supported profile ids." + id: effects_profile_id + var_type: Sequence[str] + children: [] + class: google.cloud.texttospeech_v1beta1.types.AudioConfig + fullName: google.cloud.texttospeech_v1beta1.types.AudioConfig + inheritance: + - inheritance: + - type: builtins.object + type: proto.message.Message + langs: + - python + module: google.cloud.texttospeech_v1beta1.types + name: AudioConfig + source: + id: AudioConfig + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 279 + summary: 'Description of audio data to be synthesized. + + ' + syntax: + content: AudioConfig(mapping=None, *, ignore_unknown_fields=False, **kwargs) + parameters: [] + type: class + uid: google.cloud.texttospeech_v1beta1.types.AudioConfig +references: [] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.AudioEncoding.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.AudioEncoding.yml new file mode 100644 index 000000000000..1c76899c2414 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.AudioEncoding.yml @@ -0,0 +1,42 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: [] + children: [] + class: google.cloud.texttospeech_v1beta1.types.AudioEncoding + fullName: google.cloud.texttospeech_v1beta1.types.AudioEncoding + inheritance: + - inheritance: + - inheritance: + - inheritance: + - type: builtins.object + type: builtins.int + - inheritance: + - type: builtins.object + type: enum.Enum + type: enum.IntEnum + type: proto.enums.Enum + langs: + - python + module: google.cloud.texttospeech_v1beta1.types + name: AudioEncoding + source: + id: AudioEncoding + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 47 + summary: 'Configuration to set up audio encoder. The encoding + + determines the output audio format that we''d like. + + + ' + syntax: + content: AudioEncoding(value) + parameters: [] + type: class + uid: google.cloud.texttospeech_v1beta1.types.AudioEncoding +references: [] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.CustomVoiceParams.ReportedUsage.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.CustomVoiceParams.ReportedUsage.yml new file mode 100644 index 000000000000..14f55e157e32 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.CustomVoiceParams.ReportedUsage.yml @@ -0,0 +1,44 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: [] + children: [] + class: google.cloud.texttospeech_v1beta1.types.CustomVoiceParams.ReportedUsage + fullName: google.cloud.texttospeech_v1beta1.types.CustomVoiceParams.ReportedUsage + inheritance: + - inheritance: + - inheritance: + - inheritance: + - type: builtins.object + type: builtins.int + - inheritance: + - type: builtins.object + type: enum.Enum + type: enum.IntEnum + type: proto.enums.Enum + langs: + - python + module: google.cloud.texttospeech_v1beta1.types.CustomVoiceParams + name: ReportedUsage + source: + id: ReportedUsage + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 365 + summary: 'The usage of the synthesized audio. You must report your + + honest and correct usage of the service as it''s regulated by + + contract and will cause significant difference in billing. + + + ' + syntax: + content: ReportedUsage(value) + parameters: [] + type: class + uid: google.cloud.texttospeech_v1beta1.types.CustomVoiceParams.ReportedUsage +references: [] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.CustomVoiceParams.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.CustomVoiceParams.yml new file mode 100644 index 000000000000..d074295a40fe --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.CustomVoiceParams.yml @@ -0,0 +1,45 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: + - description: "Required. The name of the AutoML model that\n synthesizes the\ + \ custom voice." + id: model + var_type: str + - description: "Optional. The usage of the synthesized audio\n to be reported." + id: reported_usage + var_type: google.cloud.texttospeech_v1beta1.types.CustomVoiceParams.ReportedUsage + children: + - google.cloud.texttospeech_v1beta1.types.CustomVoiceParams.ReportedUsage + class: google.cloud.texttospeech_v1beta1.types.CustomVoiceParams + fullName: google.cloud.texttospeech_v1beta1.types.CustomVoiceParams + inheritance: + - inheritance: + - type: builtins.object + type: proto.message.Message + langs: + - python + module: google.cloud.texttospeech_v1beta1.types + name: CustomVoiceParams + source: + id: CustomVoiceParams + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 353 + summary: 'Description of the custom voice to be synthesized. + + ' + syntax: + content: CustomVoiceParams(mapping=None, *, ignore_unknown_fields=False, **kwargs) + parameters: [] + type: class + uid: google.cloud.texttospeech_v1beta1.types.CustomVoiceParams +references: +- fullName: google.cloud.texttospeech_v1beta1.types.CustomVoiceParams.ReportedUsage + isExternal: false + name: ReportedUsage + parent: google.cloud.texttospeech_v1beta1.types.CustomVoiceParams + uid: google.cloud.texttospeech_v1beta1.types.CustomVoiceParams.ReportedUsage diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.ListVoicesRequest.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.ListVoicesRequest.yml new file mode 100644 index 000000000000..14522408407b --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.ListVoicesRequest.yml @@ -0,0 +1,43 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: + - description: "Optional. Recommended.\n BCP-47 __\n\ + \ language tag. If not specified, the API will return all\n supported voices.\ + \ If specified, the ListVoices call will\n only return voices that can be\ + \ used to synthesize this\n language_code. For example, if you specify \"\ + en-NZ\", all\n \"en-NZ\" voices will be returned. If you\ + \ specify\n \"no\", both \"no-\\*\" (Norwegian)\ + \ and \"nb-\\*\"\n (Norwegian Bokmal) voices will be returned." + id: language_code + var_type: str + children: [] + class: google.cloud.texttospeech_v1beta1.types.ListVoicesRequest + fullName: google.cloud.texttospeech_v1beta1.types.ListVoicesRequest + inheritance: + - inheritance: + - type: builtins.object + type: proto.message.Message + langs: + - python + module: google.cloud.texttospeech_v1beta1.types + name: ListVoicesRequest + source: + id: ListVoicesRequest + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 60 + summary: 'The top-level message sent by the client for the `ListVoices` + + method. + + ' + syntax: + content: ListVoicesRequest(mapping=None, *, ignore_unknown_fields=False, **kwargs) + parameters: [] + type: class + uid: google.cloud.texttospeech_v1beta1.types.ListVoicesRequest +references: [] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.ListVoicesResponse.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.ListVoicesResponse.yml new file mode 100644 index 000000000000..f704a78c7746 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.ListVoicesResponse.yml @@ -0,0 +1,35 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: + - description: The list of voices. + id: voices + var_type: Sequence[google.cloud.texttospeech_v1beta1.types.Voice] + children: [] + class: google.cloud.texttospeech_v1beta1.types.ListVoicesResponse + fullName: google.cloud.texttospeech_v1beta1.types.ListVoicesResponse + inheritance: + - inheritance: + - type: builtins.object + type: proto.message.Message + langs: + - python + module: google.cloud.texttospeech_v1beta1.types + name: ListVoicesResponse + source: + id: ListVoicesResponse + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 83 + summary: 'The message returned to the client by the `ListVoices` method. + + ' + syntax: + content: ListVoicesResponse(mapping=None, *, ignore_unknown_fields=False, **kwargs) + parameters: [] + type: class + uid: google.cloud.texttospeech_v1beta1.types.ListVoicesResponse +references: [] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.SsmlVoiceGender.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.SsmlVoiceGender.yml new file mode 100644 index 000000000000..20fb94711037 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.SsmlVoiceGender.yml @@ -0,0 +1,42 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: [] + children: [] + class: google.cloud.texttospeech_v1beta1.types.SsmlVoiceGender + fullName: google.cloud.texttospeech_v1beta1.types.SsmlVoiceGender + inheritance: + - inheritance: + - inheritance: + - inheritance: + - type: builtins.object + type: builtins.int + - inheritance: + - type: builtins.object + type: enum.Enum + type: enum.IntEnum + type: proto.enums.Enum + langs: + - python + module: google.cloud.texttospeech_v1beta1.types + name: SsmlVoiceGender + source: + id: SsmlVoiceGender + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 37 + summary: 'Gender of the voice as described in `SSML voice + + element `__. + + + ' + syntax: + content: SsmlVoiceGender(value) + parameters: [] + type: class + uid: google.cloud.texttospeech_v1beta1.types.SsmlVoiceGender +references: [] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.SynthesisInput.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.SynthesisInput.yml new file mode 100644 index 000000000000..8ad16edaf9f0 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.SynthesisInput.yml @@ -0,0 +1,60 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: + - description: "The raw text to be synthesized.\n \n This field is a member\ + \ of oneof_ input_source." + id: text + var_type: str + - description: "The SSML document to be synthesized. The SSML document must\n \ + \ be valid and well-formed. Otherwise the RPC will fail and\n return [google.rpc.Code.INVALID_ARGUMENT][].\ + \ For more\n information, see\n SSML __.\n\ + \ \n This field is a member of oneof_ input_source." + id: ssml + var_type: str + children: [] + class: google.cloud.texttospeech_v1beta1.types.SynthesisInput + fullName: google.cloud.texttospeech_v1beta1.types.SynthesisInput + inheritance: + - inheritance: + - type: builtins.object + type: proto.message.Message + langs: + - python + module: google.cloud.texttospeech_v1beta1.types + name: SynthesisInput + source: + id: SynthesisInput + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 183 + summary: 'Contains text input to be synthesized. Either `text` or `ssml` + + must be supplied. Supplying both or neither returns + + [google.rpc.Code.INVALID_ARGUMENT][]. The input size is limited to + + 5000 characters. + + + This message has `oneof`_ fields (mutually exclusive fields). + + For each oneof, at most one member field can be set at the same time. + + Setting any member of the oneof automatically clears all other + + members. + + + .. _oneof: https://proto-plus-python.readthedocs.io/en/stable/fields.html#oneofs-mutually-exclusive-fields + + ' + syntax: + content: SynthesisInput(mapping=None, *, ignore_unknown_fields=False, **kwargs) + parameters: [] + type: class + uid: google.cloud.texttospeech_v1beta1.types.SynthesisInput +references: [] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechRequest.TimepointType.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechRequest.TimepointType.yml new file mode 100644 index 000000000000..22781ee34713 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechRequest.TimepointType.yml @@ -0,0 +1,42 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: [] + children: [] + class: google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechRequest.TimepointType + fullName: google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechRequest.TimepointType + inheritance: + - inheritance: + - inheritance: + - inheritance: + - type: builtins.object + type: builtins.int + - inheritance: + - type: builtins.object + type: enum.Enum + type: enum.IntEnum + type: proto.enums.Enum + langs: + - python + module: google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechRequest + name: TimepointType + source: + id: TimepointType + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 154 + summary: 'The type of timepoint information that is returned in the + + response. + + + ' + syntax: + content: TimepointType(value) + parameters: [] + type: class + uid: google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechRequest.TimepointType +references: [] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechRequest.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechRequest.yml new file mode 100644 index 000000000000..73438340ac3a --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechRequest.yml @@ -0,0 +1,54 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: + - description: "Required. The Synthesizer requires either\n plain text or SSML\ + \ as input." + id: input + var_type: google.cloud.texttospeech_v1beta1.types.SynthesisInput + - description: "Required. The desired voice of the\n synthesized audio." + id: voice + var_type: google.cloud.texttospeech_v1beta1.types.VoiceSelectionParams + - description: "Required. The configuration of the\n synthesized audio." + id: audio_config + var_type: google.cloud.texttospeech_v1beta1.types.AudioConfig + - description: "Whether and what timepoints are returned in\n the response." + id: enable_time_pointing + var_type: Sequence[google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechRequest.TimepointType] + children: + - google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechRequest.TimepointType + class: google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechRequest + fullName: google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechRequest + inheritance: + - inheritance: + - type: builtins.object + type: proto.message.Message + langs: + - python + module: google.cloud.texttospeech_v1beta1.types + name: SynthesizeSpeechRequest + source: + id: SynthesizeSpeechRequest + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 135 + summary: 'The top-level message sent by the client for the + + `SynthesizeSpeech` method. + + ' + syntax: + content: SynthesizeSpeechRequest(mapping=None, *, ignore_unknown_fields=False, + **kwargs) + parameters: [] + type: class + uid: google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechRequest +references: +- fullName: google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechRequest.TimepointType + isExternal: false + name: TimepointType + parent: google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechRequest + uid: google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechRequest.TimepointType diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechResponse.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechResponse.yml new file mode 100644 index 000000000000..43d141da1ef8 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechResponse.yml @@ -0,0 +1,50 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: + - description: "The audio data bytes encoded as specified in the request,\n including\ + \ the header for encodings that are wrapped in\n containers (e.g. MP3, OGG_OPUS).\ + \ For LINEAR16 audio, we\n include the WAV header. Note: as with all bytes\ + \ fields,\n protobuffers use a pure binary representation, whereas JSON\n\ + \ representations use base64." + id: audio_content + var_type: bytes + - description: "A link between a position in the original request input and\n \ + \ a corresponding time in the output audio. It's only\n supported via \ + \ of SSML input." + id: timepoints + var_type: Sequence[google.cloud.texttospeech_v1beta1.types.Timepoint] + - description: The audio metadata of audio_content. + id: audio_config + var_type: google.cloud.texttospeech_v1beta1.types.AudioConfig + children: [] + class: google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechResponse + fullName: google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechResponse + inheritance: + - inheritance: + - type: builtins.object + type: proto.message.Message + langs: + - python + module: google.cloud.texttospeech_v1beta1.types + name: SynthesizeSpeechResponse + source: + id: SynthesizeSpeechResponse + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 385 + summary: 'The message returned to the client by the `SynthesizeSpeech` + + method. + + ' + syntax: + content: SynthesizeSpeechResponse(mapping=None, *, ignore_unknown_fields=False, + **kwargs) + parameters: [] + type: class + uid: google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechResponse +references: [] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.Timepoint.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.Timepoint.yml new file mode 100644 index 000000000000..738d0ed8d745 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.Timepoint.yml @@ -0,0 +1,41 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: + - description: "Timepoint name as received from the client within \n\ + \ tag." + id: mark_name + var_type: str + - description: "Time offset in seconds from the start of the\n synthesized audio." + id: time_seconds + var_type: float + children: [] + class: google.cloud.texttospeech_v1beta1.types.Timepoint + fullName: google.cloud.texttospeech_v1beta1.types.Timepoint + inheritance: + - inheritance: + - type: builtins.object + type: proto.message.Message + langs: + - python + module: google.cloud.texttospeech_v1beta1.types + name: Timepoint + source: + id: Timepoint + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 421 + summary: 'This contains a mapping between a certain point in the input + + text and a corresponding time in the output audio. + + ' + syntax: + content: Timepoint(mapping=None, *, ignore_unknown_fields=False, **kwargs) + parameters: [] + type: class + uid: google.cloud.texttospeech_v1beta1.types.Timepoint +references: [] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.Voice.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.Voice.yml new file mode 100644 index 000000000000..c78224c9a8ec --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.Voice.yml @@ -0,0 +1,46 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: + - description: "The languages that this voice supports, expressed as\n BCP-47\ + \ __\n language tags\ + \ (e.g. \"en-US\", \"es-419\", \"cmn-tw\")." + id: language_codes + var_type: Sequence[str] + - description: "The name of this voice. Each distinct voice\n has a unique name." + id: name + var_type: str + - description: The gender of this voice. + id: ssml_gender + var_type: google.cloud.texttospeech_v1beta1.types.SsmlVoiceGender + - description: "The natural sample rate (in hertz) for this\n voice." + id: natural_sample_rate_hertz + var_type: int + children: [] + class: google.cloud.texttospeech_v1beta1.types.Voice + fullName: google.cloud.texttospeech_v1beta1.types.Voice + inheritance: + - inheritance: + - type: builtins.object + type: proto.message.Message + langs: + - python + module: google.cloud.texttospeech_v1beta1.types + name: Voice + source: + id: Voice + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 98 + summary: 'Description of a voice supported by the TTS service. + + ' + syntax: + content: Voice(mapping=None, *, ignore_unknown_fields=False, **kwargs) + parameters: [] + type: class + uid: google.cloud.texttospeech_v1beta1.types.Voice +references: [] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.VoiceSelectionParams.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.VoiceSelectionParams.yml new file mode 100644 index 000000000000..d9490ca0b491 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.VoiceSelectionParams.yml @@ -0,0 +1,61 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: + - description: "Required. The language (and potentially also the region) of\n \ + \ the voice expressed as a\n BCP-47 __\n\ + \ language tag, e.g. \"en-US\". This should not include a script\n tag (e.g.\ + \ use \"cmn-cn\" rather than \"cmn-Hant-cn\"), because\n the script will be\ + \ inferred from the input provided in the\n SynthesisInput. The TTS service\ + \ will use this parameter to\n help choose an appropriate voice. Note that\ + \ the TTS service\n may choose a voice with a slightly different language\ + \ code\n than the one selected; it may substitute a different region\n (e.g.\ + \ using en-US rather than en-CA if there isn't a\n Canadian voice available),\ + \ or even a different language,\n e.g. using \"nb\" (Norwegian Bokmal) instead\ + \ of \"no\"\n (Norwegian)\"." + id: language_code + var_type: str + - description: "The name of the voice. If not set, the service will choose a\n \ + \ voice based on the other parameters such as language_code\n and gender." + id: name + var_type: str + - description: "The preferred gender of the voice. If not set, the service\n will\ + \ choose a voice based on the other parameters such as\n language_code and\ + \ name. Note that this is only a preference,\n not requirement; if a voice\ + \ of the appropriate gender is not\n available, the synthesizer should substitute\ + \ a voice with a\n different gender rather than failing the request." + id: ssml_gender + var_type: google.cloud.texttospeech_v1beta1.types.SsmlVoiceGender + - description: "The configuration for a custom voice. If\n [CustomVoiceParams.model]\ + \ is set, the service will choose\n the custom voice matching the specified\ + \ configuration." + id: custom_voice + var_type: google.cloud.texttospeech_v1beta1.types.CustomVoiceParams + children: [] + class: google.cloud.texttospeech_v1beta1.types.VoiceSelectionParams + fullName: google.cloud.texttospeech_v1beta1.types.VoiceSelectionParams + inheritance: + - inheritance: + - type: builtins.object + type: proto.message.Message + langs: + - python + module: google.cloud.texttospeech_v1beta1.types + name: VoiceSelectionParams + source: + id: VoiceSelectionParams + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 223 + summary: 'Description of which voice to use for a synthesis request. + + ' + syntax: + content: VoiceSelectionParams(mapping=None, *, ignore_unknown_fields=False, **kwargs) + parameters: [] + type: class + uid: google.cloud.texttospeech_v1beta1.types.VoiceSelectionParams +references: [] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.yml new file mode 100644 index 000000000000..707b6cdc6d3e --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.yml @@ -0,0 +1,94 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- children: + - google.cloud.texttospeech_v1beta1.types.AudioConfig + - google.cloud.texttospeech_v1beta1.types.AudioEncoding + - google.cloud.texttospeech_v1beta1.types.CustomVoiceParams + - google.cloud.texttospeech_v1beta1.types.ListVoicesRequest + - google.cloud.texttospeech_v1beta1.types.ListVoicesResponse + - google.cloud.texttospeech_v1beta1.types.SsmlVoiceGender + - google.cloud.texttospeech_v1beta1.types.SynthesisInput + - google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechRequest + - google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechResponse + - google.cloud.texttospeech_v1beta1.types.Timepoint + - google.cloud.texttospeech_v1beta1.types.Voice + - google.cloud.texttospeech_v1beta1.types.VoiceSelectionParams + fullName: google.cloud.texttospeech_v1beta1.types + langs: + - python + module: google.cloud.texttospeech_v1beta1.types + name: types + source: + id: types + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/__init__.py + remote: + branch: add_goldens + path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/__init__.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 0 + summary: API documentation for `texttospeech_v1beta1.types` package. + syntax: {} + type: subPackage + uid: google.cloud.texttospeech_v1beta1.types +references: +- fullName: google.cloud.texttospeech_v1beta1.types.AudioConfig + isExternal: false + name: AudioConfig + parent: google.cloud.texttospeech_v1beta1.types + uid: google.cloud.texttospeech_v1beta1.types.AudioConfig +- fullName: google.cloud.texttospeech_v1beta1.types.AudioEncoding + isExternal: false + name: AudioEncoding + parent: google.cloud.texttospeech_v1beta1.types + uid: google.cloud.texttospeech_v1beta1.types.AudioEncoding +- fullName: google.cloud.texttospeech_v1beta1.types.CustomVoiceParams + isExternal: false + name: CustomVoiceParams + parent: google.cloud.texttospeech_v1beta1.types + uid: google.cloud.texttospeech_v1beta1.types.CustomVoiceParams +- fullName: google.cloud.texttospeech_v1beta1.types.ListVoicesRequest + isExternal: false + name: ListVoicesRequest + parent: google.cloud.texttospeech_v1beta1.types + uid: google.cloud.texttospeech_v1beta1.types.ListVoicesRequest +- fullName: google.cloud.texttospeech_v1beta1.types.ListVoicesResponse + isExternal: false + name: ListVoicesResponse + parent: google.cloud.texttospeech_v1beta1.types + uid: google.cloud.texttospeech_v1beta1.types.ListVoicesResponse +- fullName: google.cloud.texttospeech_v1beta1.types.SsmlVoiceGender + isExternal: false + name: SsmlVoiceGender + parent: google.cloud.texttospeech_v1beta1.types + uid: google.cloud.texttospeech_v1beta1.types.SsmlVoiceGender +- fullName: google.cloud.texttospeech_v1beta1.types.SynthesisInput + isExternal: false + name: SynthesisInput + parent: google.cloud.texttospeech_v1beta1.types + uid: google.cloud.texttospeech_v1beta1.types.SynthesisInput +- fullName: google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechRequest + isExternal: false + name: SynthesizeSpeechRequest + parent: google.cloud.texttospeech_v1beta1.types + uid: google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechRequest +- fullName: google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechResponse + isExternal: false + name: SynthesizeSpeechResponse + parent: google.cloud.texttospeech_v1beta1.types + uid: google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechResponse +- fullName: google.cloud.texttospeech_v1beta1.types.Timepoint + isExternal: false + name: Timepoint + parent: google.cloud.texttospeech_v1beta1.types + uid: google.cloud.texttospeech_v1beta1.types.Timepoint +- fullName: google.cloud.texttospeech_v1beta1.types.Voice + isExternal: false + name: Voice + parent: google.cloud.texttospeech_v1beta1.types + uid: google.cloud.texttospeech_v1beta1.types.Voice +- fullName: google.cloud.texttospeech_v1beta1.types.VoiceSelectionParams + isExternal: false + name: VoiceSelectionParams + parent: google.cloud.texttospeech_v1beta1.types + uid: google.cloud.texttospeech_v1beta1.types.VoiceSelectionParams diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/index.md b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/index.md new file mode 100644 index 000000000000..4c377712327a --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/index.md @@ -0,0 +1,87 @@ +# Python Client for Google Cloud Text-to-Speech API + +[![image](https://img.shields.io/badge/support-stable-gold.svg)](https://github.com/googleapis/google-cloud-python/blob/main/README.rst#stability-levels) [![image](https://img.shields.io/pypi/v/google-cloud-texttospeech.svg)](https://pypi.org/project/google-cloud-texttospeech/) [![image](https://img.shields.io/pypi/pyversions/google-cloud-texttospeech.svg)](https://pypi.org/project/google-cloud-texttospeech/) + +[Google Cloud Text-to-Speech API](https://cloud.google.com/text-to-speech): enables easy integration of Google text recognition technologies into developer applications. Send text and receive synthesized audio output from the Cloud Text-to-Speech API service. + + +* [Client Library Documentation](https://cloud.google.com/python/docs/reference/texttospeech/latest) + + +* [Product Documentation](https://cloud.google.com/text-to-speech) + +## Quick Start + +In order to use this library, you first need to go through the following steps: + + +1. [Select or create a Cloud Platform project.](https://console.cloud.google.com/project) + + +2. [Enable billing for your project.](https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project) + + +3. [Enable the Google Cloud Text-to-Speech API.](https://cloud.google.com/text-to-speech) + + +4. [Setup Authentication.](https://googleapis.dev/python/google-api-core/latest/auth.html) + +### Installation + +Install this library in a [virtualenv](https://virtualenv.pypa.io/en/latest/) using pip. [virtualenv](https://virtualenv.pypa.io/en/latest/) is a tool to +create isolated Python environments. The basic problem it addresses is one of +dependencies and versions, and indirectly permissions. + +With [virtualenv](https://virtualenv.pypa.io/en/latest/), it’s possible to install this library without needing system +install permissions, and without clashing with the installed system +dependencies. + +### Code samples and snippets + +Code samples and snippets live in the samples/ folder. + +#### Supported Python Versions + +Our client libraries are compatible with all current [active](https://devguide.python.org/devcycle/#in-development-main-branch) and [maintenance](https://devguide.python.org/devcycle/#maintenance-branches) versions of +Python. + +Python >= 3.7 + +#### Unsupported Python Versions + +Python <= 3.6 + +If you are using an [end-of-life](https://devguide.python.org/devcycle/#end-of-life-branches) +version of Python, we recommend that you update as soon as possible to an actively supported version. + +#### Mac/Linux + +```console +pip install virtualenv +virtualenv +source /bin/activate +/bin/pip install google-cloud-texttospeech +``` + +#### Windows + +```console +pip install virtualenv +virtualenv +\Scripts\activate +\Scripts\pip.exe install google-cloud-texttospeech +``` + +### Next Steps + + +* Read the [Client Library Documentation](https://cloud.google.com/python/docs/reference/texttospeech/latest) for Google Cloud Text-to-Speech API +to see other available methods on the client. + + +* Read the [Google Cloud Text-to-Speech API Product documentation](https://cloud.google.com/text-to-speech) to learn +more about the product and see How-to Guides. + + +* View this [README](https://github.com/googleapis/google-cloud-python/blob/main/README.rst) to see the full list of Cloud +APIs that we cover. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/multiprocessing.md b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/multiprocessing.md new file mode 100644 index 000000000000..ac442c0c7185 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/multiprocessing.md @@ -0,0 +1,7 @@ +# Multiprocessing + +**NOTE**: Because this client uses [`grpc`](https://grpc.github.io/grpc/python/grpc.html#module-grpc) library, it is safe to +share instances across threads. In multiprocessing scenarios, the best +practice is to create client instances *after* the invocation of +[`os.fork()`](https://python.readthedocs.io/en/latest/library/os.html#os.fork) by [`multiprocessing.pool.Pool`](https://python.readthedocs.io/en/latest/library/multiprocessing.html#multiprocessing.pool.Pool) or +[`multiprocessing.Process`](https://python.readthedocs.io/en/latest/library/multiprocessing.html#multiprocessing.Process). diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/toc.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/toc.yml new file mode 100644 index 000000000000..8460a986dadb --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/toc.yml @@ -0,0 +1,103 @@ +- items: + - href: index.md + name: Overview + - href: changelog.md + name: Changelog + - href: multiprocessing.md + name: Multiprocessing + - href: upgrading.md + name: 2.0.0 Migration Guide + - items: + - items: + - name: Overview + uid: google.cloud.texttospeech_v1.services.text_to_speech + - name: TextToSpeechAsyncClient + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient + - name: TextToSpeechClient + uid: google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient + name: text_to_speech + uid: google.cloud.texttospeech_v1.services.text_to_speech + - items: + - name: Overview + uid: google.cloud.texttospeech_v1.types + - name: AudioConfig + uid: google.cloud.texttospeech_v1.types.AudioConfig + - name: AudioEncoding + uid: google.cloud.texttospeech_v1.types.AudioEncoding + - items: + - name: Overview + uid: google.cloud.texttospeech_v1.types.CustomVoiceParams + - name: ReportedUsage + uid: google.cloud.texttospeech_v1.types.CustomVoiceParams.ReportedUsage + name: CustomVoiceParams + uid: google.cloud.texttospeech_v1.types.CustomVoiceParams + - name: ListVoicesRequest + uid: google.cloud.texttospeech_v1.types.ListVoicesRequest + - name: ListVoicesResponse + uid: google.cloud.texttospeech_v1.types.ListVoicesResponse + - name: SsmlVoiceGender + uid: google.cloud.texttospeech_v1.types.SsmlVoiceGender + - name: SynthesisInput + uid: google.cloud.texttospeech_v1.types.SynthesisInput + - name: SynthesizeSpeechRequest + uid: google.cloud.texttospeech_v1.types.SynthesizeSpeechRequest + - name: SynthesizeSpeechResponse + uid: google.cloud.texttospeech_v1.types.SynthesizeSpeechResponse + - name: Voice + uid: google.cloud.texttospeech_v1.types.Voice + - name: VoiceSelectionParams + uid: google.cloud.texttospeech_v1.types.VoiceSelectionParams + name: types + uid: google.cloud.texttospeech_v1.types + name: Texttospeech V1 + - items: + - items: + - name: Overview + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech + - name: TextToSpeechAsyncClient + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient + - name: TextToSpeechClient + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient + name: text_to_speech + uid: google.cloud.texttospeech_v1beta1.services.text_to_speech + - items: + - name: Overview + uid: google.cloud.texttospeech_v1beta1.types + - name: AudioConfig + uid: google.cloud.texttospeech_v1beta1.types.AudioConfig + - name: AudioEncoding + uid: google.cloud.texttospeech_v1beta1.types.AudioEncoding + - items: + - name: Overview + uid: google.cloud.texttospeech_v1beta1.types.CustomVoiceParams + - name: ReportedUsage + uid: google.cloud.texttospeech_v1beta1.types.CustomVoiceParams.ReportedUsage + name: CustomVoiceParams + uid: google.cloud.texttospeech_v1beta1.types.CustomVoiceParams + - name: ListVoicesRequest + uid: google.cloud.texttospeech_v1beta1.types.ListVoicesRequest + - name: ListVoicesResponse + uid: google.cloud.texttospeech_v1beta1.types.ListVoicesResponse + - name: SsmlVoiceGender + uid: google.cloud.texttospeech_v1beta1.types.SsmlVoiceGender + - name: SynthesisInput + uid: google.cloud.texttospeech_v1beta1.types.SynthesisInput + - items: + - name: Overview + uid: google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechRequest + - name: TimepointType + uid: google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechRequest.TimepointType + name: SynthesizeSpeechRequest + uid: google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechRequest + - name: SynthesizeSpeechResponse + uid: google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechResponse + - name: Timepoint + uid: google.cloud.texttospeech_v1beta1.types.Timepoint + - name: Voice + uid: google.cloud.texttospeech_v1beta1.types.Voice + - name: VoiceSelectionParams + uid: google.cloud.texttospeech_v1beta1.types.VoiceSelectionParams + name: types + uid: google.cloud.texttospeech_v1beta1.types + name: Texttospeech V1beta1 + name: google-cloud-texttospeech diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/upgrading.md b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/upgrading.md new file mode 100644 index 000000000000..505577990d5c --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/upgrading.md @@ -0,0 +1,151 @@ +# 2.0.0 Migration Guide + +The 2.0 release of the `google-cloud-texttospeech` client is a significant upgrade based on a [next-gen code generator](https://github.com/googleapis/gapic-generator-python), and includes substantial interface changes. Existing code written for earlier versions of this library will likely require updates to use this version. This document describes the changes that have been made, and what you need to do to update your usage. + +If you experience issues or have questions, please file an [issue](https://github.com/googleapis/python-texttospeech/issues). + +## Supported Python Versions + +> **WARNING**: Breaking change + +The 2.0.0 release requires Python 3.6+. + +## Method Calls + +> **WARNING**: Breaking change + +Methods expect request objects. We provide a script that will convert most common use cases. + + +* Install the library and `libcst`. + +```py +python3 -m pip install google-cloud-texttospeech libcst +``` + + +* The script `fixup_keywords.py` is shipped with the library. It expects +an input directory (with the code to convert) and an empty destination directory. + +```sh +$ fixup_keywords.py --input-directory .samples/ --output-directory samples/ +``` + +**Before:** + +```py +from google.cloud import texttospeech + +client = texttospeech.TextToSpeechClient() + +voices = client.list_voices(language_code="no") +``` + +**After:** + +```py +from google.cloud import texttospeech + +client = texttospeech.TextToSpeechClient() + +voices = client.list_voices(request={"language_code": "no"}) +``` + +### More Details + +In `google-cloud-texttospeech<2.0.0`, parameters required by the API were positional parameters and optional parameters were keyword parameters. + +**Before:** + +```py + def synthesize_speech( + self, + input_, + voice, + audio_config, + retry=google.api_core.gapic_v1.method.DEFAULT, + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None, + ): +``` + +In the 2.0.0 release, all methods have a single positional parameter `request`. Method docstrings indicate whether a parameter is required or optional. + +Some methods have additional keyword only parameters. The available parameters depend on the [`google.api.method_signature` annotation](https://github.com/googleapis/googleapis/blob/master/google/cloud/texttospeech/v1/cloud_tts.proto#L53) specified by the API producer. + +**After:** + +```py + def synthesize_speech( + self, + request: cloud_tts.SynthesizeSpeechRequest = None, + *, + input: cloud_tts.SynthesisInput = None, + voice: cloud_tts.VoiceSelectionParams = None, + audio_config: cloud_tts.AudioConfig = None, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> cloud_tts.SynthesizeSpeechResponse: +``` + +> **NOTE:** The `request` parameter and flattened keyword parameters for the API are mutually exclusive. +> Passing both will result in an error. + +Both of these calls are valid: + +```py +response = client.synthesize_speech( + request={ + "input": input_text, + "voice": voice, + "audio_config": audio_config + } +) +``` + +```py +response = client.synthesize_speech( + input=input_text, + voice=voice, + audio_config=audio_config +) +``` + +This call is invalid because it mixes `request` with a keyword argument `audio_config`. Executing this code +will result in an error. + +```py +response = client.synthesize_speech( + request={ + "input": input_text, + "voice": voice, + }, + audio_config=audio_config +) +``` + +## Enums and Types + +> **WARNING**: Breaking change + +The submodules `enums` and `types` have been removed. + +**Before:** + +```py + +from google.cloud import texttospeech + +encoding = texttospeech.enums.AudioEncoding.MP3 +voice = texttospeech.types.VoiceSelectionParams(language_code="en-US") +``` + +**After:** + +```py +from google.cloud import texttospeech + +encoding = texttospeech.AudioEncoding.MP3 +voice = texttospeech.VoiceSelectionParams(language_code="en-US") +``` diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/changelog.md b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/changelog.md new file mode 100644 index 000000000000..d0bb2e310d16 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/changelog.md @@ -0,0 +1,1685 @@ +# Changelog + +[PyPI History](https://pypi.org/project/google-cloud-pubsub/#history) + +## [2.13.10](https://github.com/googleapis/python-pubsub/compare/v2.13.8...v2.13.10) (2022-10-14) + +### Bug Fixes + + +* Batch at most 1,000 ack ids per request ([#802](https://github.com/googleapis/python-pubsub/issues/802)) ([4361e67](https://github.com/googleapis/python-pubsub/commit/4361e6735004a5600ee73979b99e6b9dd587c49b)) + + +* **deps:** Allow protobuf 3.19.5 ([#801](https://github.com/googleapis/python-pubsub/issues/801)) ([fa23503](https://github.com/googleapis/python-pubsub/commit/fa235033481783c2ec378b2a26b223bdff206461)) + + +* Silence invalid_ack_id warnings for receipt modacks ([#798](https://github.com/googleapis/python-pubsub/issues/798)) ([17feea5](https://github.com/googleapis/python-pubsub/commit/17feea5783f3a878b4dcfb3a8570585f7637378f)) + +### Miscellaneous Chores + + +* release as 2.13.10 ([34f022b](https://github.com/googleapis/python-pubsub/commit/34f022b4ee62d53a193bc2babafad508e2f2540b)) + +## [2.13.8](https://github.com/googleapis/python-pubsub/compare/v2.13.7...v2.13.8) (2022-10-03) + +### Bug Fixes + + +* **deps:** Require protobuf >= 3.20.2 ([#792](https://github.com/googleapis/python-pubsub/issues/792)) ([1a54f7c](https://github.com/googleapis/python-pubsub/commit/1a54f7cd3d997270e0a5d70f7caea32d8753be76)) + +## [2.13.7](https://github.com/googleapis/python-pubsub/compare/v2.13.6...v2.13.7) (2022-09-22) + +### Bug Fixes + + +* Remove expired ack_ids ([#787](https://github.com/googleapis/python-pubsub/issues/787)) ([b4b809d](https://github.com/googleapis/python-pubsub/commit/b4b809d616cf93881815d6baadf2dd322ab566d1)) + +## [2.13.6](https://github.com/googleapis/python-pubsub/compare/v2.13.5...v2.13.6) (2022-08-11) + +### Bug Fixes + + +* **deps:** allow protobuf < 5.0.0 ([#762](https://github.com/googleapis/python-pubsub/issues/762)) ([260bd18](https://github.com/googleapis/python-pubsub/commit/260bd183ffe19992be9a1c1d298438c1f44d3fa9)) + + +* **deps:** require proto-plus >= 1.22.0 ([260bd18](https://github.com/googleapis/python-pubsub/commit/260bd183ffe19992be9a1c1d298438c1f44d3fa9)) + + +* set stream_ack_deadline to max_duration_per_lease_extension or 60 s, set ack_deadline to min_duration_per_lease_extension or 10 s ([#760](https://github.com/googleapis/python-pubsub/issues/760)) ([4444129](https://github.com/googleapis/python-pubsub/commit/4444129b28a19296752e865b73827b78e99adea5)) + + +* Update stream_ack_deadline with ack_deadline ([#763](https://github.com/googleapis/python-pubsub/issues/763)) ([e600ad8](https://github.com/googleapis/python-pubsub/commit/e600ad8228930445765ffa0c45500a7779e25817)) + +## [2.13.5](https://github.com/googleapis/python-pubsub/compare/v2.13.4...v2.13.5) (2022-08-10) + +### Documentation + + +* reorganize sphinx structure ([#751](https://github.com/googleapis/python-pubsub/issues/751)) ([b6de574](https://github.com/googleapis/python-pubsub/commit/b6de57458a1976a068dd229208b9b678a9d3f866)) + +## [2.13.4](https://github.com/googleapis/python-pubsub/compare/v2.13.3...v2.13.4) (2022-07-15) + +### Bug Fixes + + +* Remove bidi modacks on StreamingPull initial request ([#738](https://github.com/googleapis/python-pubsub/issues/738)) ([1e7d469](https://github.com/googleapis/python-pubsub/commit/1e7d46901c4472a3534980621e88d81aa2e50760)) + +## [2.13.3](https://github.com/googleapis/python-pubsub/compare/v2.13.2...v2.13.3) (2022-07-13) + +### Bug Fixes + + +* **deps:** require google-api-core>=1.32.0,>=2.8.0 ([#735](https://github.com/googleapis/python-pubsub/issues/735)) ([a5624fb](https://github.com/googleapis/python-pubsub/commit/a5624fbee2951c7f0c3e413d7d399a41fa0aa4bf)) + +## [2.13.2](https://github.com/googleapis/python-pubsub/compare/v2.13.1...v2.13.2) (2022-07-08) + +### Bug Fixes + + +* **deps:** require google-api-core >= 2.8.0 ([#726](https://github.com/googleapis/python-pubsub/issues/726)) ([c80ad41](https://github.com/googleapis/python-pubsub/commit/c80ad41abf36c709f8299a6fa22f3672705b1b6d)) + +## [2.13.1](https://github.com/googleapis/python-pubsub/compare/v2.13.0...v2.13.1) (2022-07-07) + +### Bug Fixes + + +* change info logs to debug ([#693](https://github.com/googleapis/python-pubsub/issues/693)) ([950fbce](https://github.com/googleapis/python-pubsub/commit/950fbce009fd56a55feea971f8e6083fa84d54fc)) + + +* require python 3.7+ ([#730](https://github.com/googleapis/python-pubsub/issues/730)) ([0d949b8](https://github.com/googleapis/python-pubsub/commit/0d949b8da096d1b0a5e26f607b1cd79fb560252a)) + +## [2.13.0](https://github.com/googleapis/python-pubsub/compare/v2.12.1...v2.13.0) (2022-06-06) + +### Features + + +* add BigQuery configuration for subscriptions ([#685](https://github.com/googleapis/python-pubsub/issues/685)) ([6fa03be](https://github.com/googleapis/python-pubsub/commit/6fa03be779d6a7105bb7c029b95d4c357d2a49df)) + +### Bug Fixes + + +* add info log for bidi streaming pull ack_deadline requests ([#692](https://github.com/googleapis/python-pubsub/issues/692)) ([fcb67dd](https://github.com/googleapis/python-pubsub/commit/fcb67dd0d8fff5a583ebe0a3a08d0219601df8e9)) + + +* **deps:** require protobuf <4.0.0dev ([#699](https://github.com/googleapis/python-pubsub/issues/699)) ([dcdf013](https://github.com/googleapis/python-pubsub/commit/dcdf0137905949662ce191adcb6dd588bd74f9fe)) + +### Documentation + + +* fix changelog header to consistent size ([#700](https://github.com/googleapis/python-pubsub/issues/700)) ([93f2b62](https://github.com/googleapis/python-pubsub/commit/93f2b62a18f622d8da71043a6b6d3f53295db308)) + +## [2.12.1](https://github.com/googleapis/python-pubsub/compare/v2.12.0...v2.12.1) (2022-05-11) + +### Bug Fixes + + +* Add emulator support to schema service ([#658](https://github.com/googleapis/python-pubsub/issues/658)) ([1a07d7c](https://github.com/googleapis/python-pubsub/commit/1a07d7ce3b3580191f74b7895dd1b8afb13baccb)) + + +* Handle duplicate acks with streaming pull ([#662](https://github.com/googleapis/python-pubsub/issues/662)) ([219491e](https://github.com/googleapis/python-pubsub/commit/219491ea1e615f33e1955e3afc204a0281c525db)) + + +* set min snooze on lease management to .01 sec ([#678](https://github.com/googleapis/python-pubsub/issues/678)) ([91c6e69](https://github.com/googleapis/python-pubsub/commit/91c6e69e96953919bc86004692edd3a52c7b9796)) + +### Documentation + + +* fix project_path typo in UPGRADING.md ([#660](https://github.com/googleapis/python-pubsub/issues/660)) ([20d661c](https://github.com/googleapis/python-pubsub/commit/20d661c8562cc1f777ac7b3f1ba03dcad7a831c0)) + + +* mark eod as preview ([#657](https://github.com/googleapis/python-pubsub/issues/657)) ([418e1a3](https://github.com/googleapis/python-pubsub/commit/418e1a3783441469713ca8ec8776007ff0fdb15d)) + +## [2.12.0](https://github.com/googleapis/python-pubsub/compare/v2.11.0...v2.12.0) (2022-04-06) + +### Features + + +* increase GRPC max metadata size to 4 MB ([#623](https://github.com/googleapis/python-pubsub/issues/623)) ([54b9e07](https://github.com/googleapis/python-pubsub/commit/54b9e07401b7309f16ecfe2a7afc36ea69f24a9c)) + +### Bug Fixes + + +* mypy errors ([#622](https://github.com/googleapis/python-pubsub/issues/622)) ([dab13d5](https://github.com/googleapis/python-pubsub/commit/dab13d5fb1d723c971cd84ae20f18462e624a26d)) + + +* process ErrorInfo / GRPC errors for ack/modack only when exactly-once delivery is enabled ([#626](https://github.com/googleapis/python-pubsub/issues/626)) ([cc1953b](https://github.com/googleapis/python-pubsub/commit/cc1953bcf942fb394a92ba50ba615adf822bfe7d)) + +## [2.11.0](https://github.com/googleapis/python-pubsub/compare/v2.10.0...v2.11.0) (2022-03-09) + +### Features + + +* retry temporary GRPC statuses for ack/modack/nack when exactly-once delivery is enabled ([#607](https://github.com/googleapis/python-pubsub/issues/607)) ([a91bed8](https://github.com/googleapis/python-pubsub/commit/a91bed829c9040fcc6c1e70b99b66188ac4ded40)) + + +* return singleton success future for exactly-once methods in Message ([#608](https://github.com/googleapis/python-pubsub/issues/608)) ([253ced2](https://github.com/googleapis/python-pubsub/commit/253ced28f308450c7a1a93cc38f6d101ecd7d4c0)) + +### Bug Fixes + + +* **deps:** require google-api-core>=1.31.5, >=2.3.2 ([#600](https://github.com/googleapis/python-pubsub/issues/600)) ([1608b7f](https://github.com/googleapis/python-pubsub/commit/1608b7ffdd5b5db87e1e55fde763440ca9a4086e)) + + +* **deps:** require proto-plus>=1.15.0 ([1608b7f](https://github.com/googleapis/python-pubsub/commit/1608b7ffdd5b5db87e1e55fde763440ca9a4086e)) + +## [2.10.0](https://github.com/googleapis/python-pubsub/compare/v2.9.0...v2.10.0) (2022-03-04) + +### Features + + +* add api key support ([#571](https://github.com/googleapis/python-pubsub/issues/571)) ([cdda762](https://github.com/googleapis/python-pubsub/commit/cdda762f6d15d96f5e2d7fac975f3494dc49eaa9)) + + +* add exactly once delivery flag ([#577](https://github.com/googleapis/python-pubsub/issues/577)) ([d6614e2](https://github.com/googleapis/python-pubsub/commit/d6614e274328c58449e67dfc788e2e7986c0c10b)) + + +* add support for exactly once delivery ([#578](https://github.com/googleapis/python-pubsub/issues/578)) ([95a86fa](https://github.com/googleapis/python-pubsub/commit/95a86fa5f528701b760064f0cece0efa4e60cd44)) + + +* exactly-once delivery support ([#550](https://github.com/googleapis/python-pubsub/issues/550)) ([2fb6e15](https://github.com/googleapis/python-pubsub/commit/2fb6e1533192ae81dceee5c71283169a0a85a015)) + +### Bug Fixes + + +* **deps:** move libcst to extras ([#585](https://github.com/googleapis/python-pubsub/issues/585)) ([0846762](https://github.com/googleapis/python-pubsub/commit/084676243ca4afd54cda601e589b80883f9703a3)) + + +* refactor client classes for safer type checking ([#552](https://github.com/googleapis/python-pubsub/issues/552)) ([7f705be](https://github.com/googleapis/python-pubsub/commit/7f705beb927383f14b9d56f0341ee0de101f7c05)) + + +* resolve DuplicateCredentialArgs error when using credentials_file ([8ca8cf2](https://github.com/googleapis/python-pubsub/commit/8ca8cf27333baf823a1dffd081e63079f1a12625)) + +### Samples + + +* samples: create subscription with filtering enabled [#580](https://github.com/googleapis/python-pubsub/pull/580) + + +* samples: handle empty response in sync pull samples [#586](https://github.com/googleapis/python-pubsub/pull/586) + + +* samples: sample for receiving messages with exactly-once delivery enabled [#588](https://github.com/googleapis/python-pubsub/pull/588) + + +* samples: create subscription with exactly once delivery [#592](https://github.com/googleapis/python-pubsub/pull/592) +(https://github.com/googleapis/python-pubsub/pull/588 + +### Documentation + + +* add autogenerated code snippets ([aa3754c](https://github.com/googleapis/python-pubsub/commit/aa3754cf432bd02be2734a23a32d5b36cd216aee)) + + +* Docs have inconsistent default values for max_latency and max_bytes ([#572](https://github.com/googleapis/python-pubsub/issues/572)) ([d136dfd](https://github.com/googleapis/python-pubsub/commit/d136dfdb69ebeebd1411a1415f863b94d07078f0)) + +## [2.9.0](https://www.github.com/googleapis/python-pubsub/compare/v2.8.0...v2.9.0) (2021-11-10) + +### Features + + +* add context manager support in client ([#516](https://www.github.com/googleapis/python-pubsub/issues/516)) ([51eae67](https://www.github.com/googleapis/python-pubsub/commit/51eae67c47e2ce7d2f7620209e98df4a129801b5)) + + +* add support for Python 3.10 ([#518](https://www.github.com/googleapis/python-pubsub/issues/518)) ([bb25d75](https://www.github.com/googleapis/python-pubsub/commit/bb25d755d70ba19e69d8a281be65f13eb994967d)) + +### Bug Fixes + + +* add ‘dict’ annotation type to ‘request’ ([b72522a](https://www.github.com/googleapis/python-pubsub/commit/b72522a4617c4b2773fb6a5a631038791aa08300)) + + +* **deps:** drop packaging dependency ([290b9c5](https://www.github.com/googleapis/python-pubsub/commit/290b9c5615eaa03674b773a27b756483abd76195)) + + +* **deps:** require google-api-core >= 1.28.0 ([290b9c5](https://www.github.com/googleapis/python-pubsub/commit/290b9c5615eaa03674b773a27b756483abd76195)) + + +* improper types in pagers generation ([2ad639d](https://www.github.com/googleapis/python-pubsub/commit/2ad639d6370c7a085498595d7bd0d7eaadfff3c1)) + +### Documentation + + +* add type annotations to codebase ([#509](https://www.github.com/googleapis/python-pubsub/issues/509)) ([093cabf](https://www.github.com/googleapis/python-pubsub/commit/093cabff9f0464b1dfaa8f373b6fffbc439518de)) + + +* list oneofs in docstring ([290b9c5](https://www.github.com/googleapis/python-pubsub/commit/290b9c5615eaa03674b773a27b756483abd76195)) + +## [2.8.0](https://www.github.com/googleapis/python-pubsub/compare/v2.7.1...v2.8.0) (2021-09-02) + +### Features + + +* closed subscriber as context manager raises ([#488](https://www.github.com/googleapis/python-pubsub/issues/488)) ([a05a3f2](https://www.github.com/googleapis/python-pubsub/commit/a05a3f250cf8567ffe0d2eb3ecc45856a2bcd07c)) + +### Documentation + + +* clarify the types of Message parameters ([#486](https://www.github.com/googleapis/python-pubsub/issues/486)) ([633e91b](https://www.github.com/googleapis/python-pubsub/commit/633e91bbfc0a8f4f484089acff6812b754f40c75)) + +## [2.7.1](https://www.github.com/googleapis/python-pubsub/compare/v2.7.0...v2.7.1) (2021-08-13) + +### Bug Fixes + + +* remove dependency on pytz ([#472](https://www.github.com/googleapis/python-pubsub/issues/472)) ([972cc16](https://www.github.com/googleapis/python-pubsub/commit/972cc163f5a1477b37a5ab7e329faf1468637fa2)) + +## [2.7.0](https://www.github.com/googleapis/python-pubsub/compare/v2.6.1...v2.7.0) (2021-07-24) + +### Features + + +* Add `always_use_jwt_access`. ([1f30ef7](https://www.github.com/googleapis/python-pubsub/commit/1f30ef7f26ae1156751bc42305b1eb156115b5e5)) + + +* Add method signature for `Subscriber.Pull` without the deprecated `return_immediately` field. ([1f30ef7](https://www.github.com/googleapis/python-pubsub/commit/1f30ef7f26ae1156751bc42305b1eb156115b5e5)) + + +* Add Pub/Sub topic retention fields. ([#456](https://www.github.com/googleapis/python-pubsub/issues/456)) ([911829d](https://www.github.com/googleapis/python-pubsub/commit/911829d85c6ec36a87b873cbfe34497b1a493dde)) + + +* Add subscription properties to streaming pull response. ([1f30ef7](https://www.github.com/googleapis/python-pubsub/commit/1f30ef7f26ae1156751bc42305b1eb156115b5e5)) + + +* Support self-signed JWT flow for service accounts. ([1f30ef7](https://www.github.com/googleapis/python-pubsub/commit/1f30ef7f26ae1156751bc42305b1eb156115b5e5)) + +### Bug Fixes + + +* Add async client to `%name_%version/init.py`. ([1f30ef7](https://www.github.com/googleapis/python-pubsub/commit/1f30ef7f26ae1156751bc42305b1eb156115b5e5)) + + +* Disable `always_use_jwt_access`. ([1f30ef7](https://www.github.com/googleapis/python-pubsub/commit/1f30ef7f26ae1156751bc42305b1eb156115b5e5)) + + +* Enable self signed JWT for gRPC. ([#458](https://www.github.com/googleapis/python-pubsub/issues/458)) ([c6e0ff6](https://www.github.com/googleapis/python-pubsub/commit/c6e0ff69faeda614aa6088af59d3420e16720d27)) + +### Dependencies + + +* Add `packaging` requirement. ([1f30ef7](https://www.github.com/googleapis/python-pubsub/commit/1f30ef7f26ae1156751bc42305b1eb156115b5e5)) + + +* Require `google-api-core >= 1.26.0`. ([1f30ef7](https://www.github.com/googleapis/python-pubsub/commit/1f30ef7f26ae1156751bc42305b1eb156115b5e5)) + +## 2.6.1 + +07-05-2021 10:33 PDT + +### Dependencies + + +* Fix possible crash by requiring `grpcio >= 1.38.1`. ([#414](https://github.com/googleapis/python-pubsub/issues/414)) ([7037a28](https://github.com/googleapis/python-pubsub/pull/435/commits/7037a28090aa4efa01808231721716bca80bb0b7)) + +### Documentation + + +* Adjust samples for publishing with error handler and flow control. ([#433](https://github.com/googleapis/python-pubsub/pull/433)) + +### Internal / Testing Changes + + +* Fix flaky sync pull sample test. ([#434](https://github.com/googleapis/python-pubsub/pull/434)) + + +* Mitigate flaky snippets tests. ([#432](https://github.com/googleapis/python-pubsub/pull/432)) + +## [2.6.0](https://www.github.com/googleapis/python-pubsub/compare/v2.5.0...v2.6.0) (2021-06-17) + +### Features + + +* support customizable retry and timeout settings on the publisher client ([#299](https://www.github.com/googleapis/python-pubsub/issues/299)) ([7597604](https://www.github.com/googleapis/python-pubsub/commit/7597604b41fa3a1e9bf34addc35c8647dde007cc)) + +### Bug Fixes + + +* ACK deadline set for received messages can be too low ([#416](https://www.github.com/googleapis/python-pubsub/issues/416)) ([e907f6e](https://www.github.com/googleapis/python-pubsub/commit/e907f6e05f59f64a3b08df3304e92ec960997be6)) + + +* threads can skip the line in publisher flow controller ([#422](https://www.github.com/googleapis/python-pubsub/issues/422)) ([ef89f55](https://www.github.com/googleapis/python-pubsub/commit/ef89f55a41044e9ad26b91132b4b1be9c7b2c127)) + +### Documentation + + +* block until the streaming pull shuts down ([#424](https://www.github.com/googleapis/python-pubsub/issues/424)) ([d0d0b70](https://www.github.com/googleapis/python-pubsub/commit/d0d0b704642df8dee893d3f585aeb666e19696fb)) + + +* explain that future.cancel() is non-blocking ([#420](https://www.github.com/googleapis/python-pubsub/issues/420)) ([c825789](https://www.github.com/googleapis/python-pubsub/commit/c825789bdff310f44cbb132a723e99d1e6331d8f)) + +## [2.5.0](https://www.github.com/googleapis/python-pubsub/compare/v2.4.2...v2.5.0) (2021-05-18) + +### Features + + +* Make publish futures compatible with `concurrent.futures.as_completed()`. ([#397](https://www.github.com/googleapis/python-pubsub/issues/397)) ([e29a2c0](https://www.github.com/googleapis/python-pubsub/commit/e29a2c0ac6c5d2ebf2311646e552a02f184cfedc)) + +### Bug Fixes + + +* Scheduler errors when executor in shutdown. ([#399](https://www.github.com/googleapis/python-pubsub/issues/399)) ([39a83d3](https://www.github.com/googleapis/python-pubsub/commit/39a83d3eef196e88478ad8362201a2ab12e9f681)) + +## 2.4.2 + +05-06-2021 23:50 PDT + +### Implementation Changes + + +* Fix memory leak when publishing messages. ([#406](https://github.com/googleapis/python-pubsub/pull/406)) + + +* Do not crash if distribution cannot be found when extracting semantic version. ([#393](https://github.com/googleapis/python-pubsub/pull/393)) + + +* Emit a warning if `return_immediately` is set with synchronous pull. ([#355](https://github.com/googleapis/python-pubsub/pull/355)) + + +* Regenerate GAPIC layer with latest changes, use explicit default timeouts. ([#345](https://github.com/googleapis/python-pubsub/pull/345)) + +### Documentation + + +* Add additional info on `use_legacy_flow_control` parameter. ([#301](https://github.com/googleapis/python-pubsub/pull/301)) + + +* Remove EXPERIMENTAL tag for ordering keys in `publisher/client.py`. ([#324](https://github.com/googleapis/python-pubsub/pull/324)) + + +* Fix `create_topic()` call in README. ([#360](https://github.com/googleapis/python-pubsub/pull/360)) + + +* Generate PyPI token in secrets manager, fix spacing in docs (via synth). ([#384](https://github.com/googleapis/python-pubsub/pull/384)) + + +* Add `SECURITY.md`. ([#401](https://github.com/googleapis/python-pubsub/pull/401)) + +### Internal / Testing Changes + + +* Require 100% unit test coverage (via synth). ([#359](https://github.com/googleapis/python-pubsub/pull/359)) + + +* Bump test coverage to 100%. ([#364](https://github.com/googleapis/python-pubsub/pull/364)) + + +* Fix streaming pull close unit test flakiness. ([#361](https://github.com/googleapis/python-pubsub/pull/361)) + + +* Pass explicit credentials in all unit tests creating clients. ([#369](https://github.com/googleapis/python-pubsub/pull/369)) + + +* Fix flaky test for blocking pull shutdown. ([#378](https://github.com/googleapis/python-pubsub/pull/378)) + + +* Add missing licence header. ([#377](https://github.com/googleapis/python-pubsub/pull/377)) + +## [2.4.1](https://www.github.com/googleapis/python-pubsub/compare/v2.4.0...v2.4.1) (2021-03-30) + +### Bug Fixes + + +* Move `await_msg_callbacks` flag to `subscribe()` method, fixing a regression in Pub/Sub Lite client. +([#320](https://www.github.com/googleapis/python-pubsub/issues/320)) ([d40d027](https://www.github.com/googleapis/python-pubsub/commit/d40d02713c8c189937ae5c21d099b88a3131a59f)) + + +* SSL error when using the client with the emulator. ([#297](https://www.github.com/googleapis/python-pubsub/issues/297)) ([83db672](https://www.github.com/googleapis/python-pubsub/commit/83db67239d3521457138699109f766d574a0a2c4)) + +### Implementation Changes + + +* (samples) Bump the max_time to 10 minutes for a flaky test. ([#311](https://www.github.com/googleapis/python-pubsub/issues/311)) ([e2678d4](https://www.github.com/googleapis/python-pubsub/commit/e2678d47c08e6b03782d2d744a4e630b933fdd51)), closes [#291](https://www.github.com/googleapis/python-pubsub/issues/291) + + +* (samples) Mark delivery attempts test as flaky. ([#326](https://www.github.com/googleapis/python-pubsub/issues/326)) ([5a97ef1](https://www.github.com/googleapis/python-pubsub/commit/5a97ef1bb7512fe814a8f72a43b3e9698434cd8d)) + + +* (samples) Mitigate flakiness in subscriber_tests. ([#304](https://www.github.com/googleapis/python-pubsub/issues/304)) ([271a385](https://www.github.com/googleapis/python-pubsub/commit/271a3856d835967f18f6becdae5ad53d585d0ccf)) + + +* (samples) Retry `InternalServerError` in dead letter policy test. ([#329](https://www.github.com/googleapis/python-pubsub/issues/329)) ([34c9b11](https://www.github.com/googleapis/python-pubsub/commit/34c9b11ae697c280f32642c3101b7f7da971f589)), closes [#321](https://www.github.com/googleapis/python-pubsub/issues/321) + +### Documentation + + +* Remove EXPERIMENTAL tag for ordering keys in `types.py`. ([#323](https://www.github.com/googleapis/python-pubsub/issues/323)) ([659cd7a](https://www.github.com/googleapis/python-pubsub/commit/659cd7ae2784245d4217fbc722dac04bd3222d32)) + + +* Remove EXPERIMENTAL tag from `Schema` service (via synth). ([#307](https://www.github.com/googleapis/python-pubsub/issues/307)) ([ad85202](https://www.github.com/googleapis/python-pubsub/commit/ad852028836520db779c5cc33689ffd7e5458a7d)) + +## 2.4.0 + +02-22-2021 05:02 PST + +### Implementation Changes + +### New Features + + +* Add graceful streaming pull shutdown. ([#292](https://github.com/googleapis/python-pubsub/pull/292)) + +### Documentation + + +* Update samples with using the subscriber client as a context manager. ([#254](https://github.com/googleapis/python-pubsub/pull/254)) + +## [2.3.0](https://www.github.com/googleapis/python-pubsub/compare/v2.2.0...v2.3.0) (2021-02-08) + +### Features + + +* surface SchemaServiceClient in google.cloud.pubsub ([#281](https://www.github.com/googleapis/python-pubsub/issues/281)) ([8751bcc](https://www.github.com/googleapis/python-pubsub/commit/8751bcc5eb782df55769b48253629a3bde3d4661)) + +### Bug Fixes + + +* client version missing from the user agent header ([#275](https://www.github.com/googleapis/python-pubsub/issues/275)) ([b112f4f](https://www.github.com/googleapis/python-pubsub/commit/b112f4fcbf6f2bce8dcf37871bdc540b11f54fe3)) + + +* Don’t open the google.cloud package by adding pubsub.py ([#269](https://www.github.com/googleapis/python-pubsub/issues/269)) ([542d79d](https://www.github.com/googleapis/python-pubsub/commit/542d79d7c5fb7403016150ba477485756cd4097b)) + + +* flaky samples tests ([#263](https://www.github.com/googleapis/python-pubsub/issues/263)) ([3d6a29d](https://www.github.com/googleapis/python-pubsub/commit/3d6a29de07cc09be663c90a3333f4cd33633994f)) + + +* Modify synth.py to update grpc transport options ([#266](https://www.github.com/googleapis/python-pubsub/issues/266)) ([41dcd30](https://www.github.com/googleapis/python-pubsub/commit/41dcd30636168f3dd1248f1d99170d531fc9bcb8)) + + +* pass anonymous credentials for emulator ([#250](https://www.github.com/googleapis/python-pubsub/issues/250)) ([8eed8e1](https://www.github.com/googleapis/python-pubsub/commit/8eed8e16019510dc8b20fb6b009d61a7ac532d26)) + + +* remove grpc send/recieve limits ([#259](https://www.github.com/googleapis/python-pubsub/issues/259)) ([fd2840c](https://www.github.com/googleapis/python-pubsub/commit/fd2840c10f92b03da7f4b40ac69c602220757c0a)) + +## [2.2.0](https://www.github.com/googleapis/python-pubsub/compare/v2.1.0...v2.2.0) (2020-11-16) + +### Features + + +* Add dead lettering max delivery attempts argument ([#236](https://www.github.com/googleapis/python-pubsub/issues/236)) ([7687ae5](https://www.github.com/googleapis/python-pubsub/commit/7687ae500bdb9c76e3ffb23302b4f32dc9627d81)) + + +* Enable server side flow control by default with the option to turn it off ([#231](https://www.github.com/googleapis/python-pubsub/issues/231)) ([94d738c](https://www.github.com/googleapis/python-pubsub/commit/94d738c07c6404a152c6729f5ba4b106b1fe9355)) + +### Bug Fixes + + +* fix mtls issue in handwritten layer ([#226](https://www.github.com/googleapis/python-pubsub/issues/226)) ([09a409c](https://www.github.com/googleapis/python-pubsub/commit/09a409c6240a74dcb46d8f3f86d4fb95a52274a7)) + + +* make fixup script consistent with migration docs ([#208](https://www.github.com/googleapis/python-pubsub/issues/208)) ([b64e218](https://www.github.com/googleapis/python-pubsub/commit/b64e2187ab0810437575580d6ddb5315ff60e274)) + +### Documentation + + +* document potentially unexpected blocking behavior of publish() method ([#214](https://www.github.com/googleapis/python-pubsub/issues/214)) ([b6d9bd7](https://www.github.com/googleapis/python-pubsub/commit/b6d9bd7c38d4fe597c25b7b5869fd4a1259c7687)) + + +* fix get topic_path in subscriber sample ([#210](https://www.github.com/googleapis/python-pubsub/issues/210)) ([7228f6c](https://www.github.com/googleapis/python-pubsub/commit/7228f6c9a4c050bf22bb4bc3582b89b04eaa8702)) + +## 2.1.0 + +09-21-2020 02:19 PDT + +### Implementation Changes + + +* Convert all RPC error types to exceptions. ([#163](https://github.com/googleapis/python-pubsub/issues/163)) ([#170](https://github.com/googleapis/python-pubsub/pull/170)) + + +* Pass client options to publisher and subscriber clients. ([#166](https://github.com/googleapis/python-pubsub/issues/166)) ([#190](https://github.com/googleapis/python-pubsub/pull/190)) + +### New Features + + +* Regenerate the client lib to pick new mtls env (via synth). ([#197](https://github.com/googleapis/python-pubsub/pull/197)) + +### Documentation + + +* Add subscription detachment sample. ([#152](https://github.com/googleapis/python-pubsub/pull/152)) + + +* Use new call syntax in subscriber docs. ([#198](https://github.com/googleapis/python-pubsub/issues/198)) ([#203](https://github.com/googleapis/python-pubsub/pull/203)) + +### Internal / Testing Changes + + +* Update CODEOWNERS. ([#193](https://github.com/googleapis/python-pubsub/pull/193)) + +## 2.0.0 + +09-11-2020 05:03 PDT + +### Implementation Changes + + +* Transition the library to microgenerator. ([#158](https://github.com/googleapis/python-pubsub/pull/158)) +This is a **breaking change** that introduces several **method signature changes** and **drops support +for Python 2.7 and 3.5**. + +### Documentation + + +* Add samples for using ordering keys. ([#156](https://github.com/googleapis/python-pubsub/pull/156)) + + +* Remove extra white space in delivery attempt sample. ([#159](https://github.com/googleapis/python-pubsub/pull/159)) + +### Internal / Testing Changes + + +* Fix flaky sequencer unit tests. ([#187](https://github.com/googleapis/python-pubsub/pull/187)) + +## [1.7.0](https://www.github.com/googleapis/python-pubsub/compare/v1.6.1...v1.7.0) (2020-07-13) + +This is the last release that supports Python 2.7 and 3.5. + +### New Features + + +* Add support for server-side flow control. ([#143](https://github.com/googleapis/python-pubsub/pull/143)) ([04e261c](https://www.github.com/googleapis/python-pubsub/commit/04e261c602a2919cc75b3efa3dab099fb2cf704c)) + +### Dependencies + + +* Update samples dependency `google-cloud-pubsub` to `v1.6.1`. ([#144](https://github.com/googleapis/python-pubsub/pull/144)) ([1cb6746](https://github.com/googleapis/python-pubsub/commit/1cb6746b00ebb23dbf1663bae301b32c3fc65a88)) + +### Documentation + + +* Add pubsub/cloud-client samples from the common samples repo (with commit history). ([#151](https://github.com/googleapis/python-pubsub/pull/151)) + + +* Add flow control section to publish overview. ([#129](https://github.com/googleapis/python-pubsub/pull/129)) ([acc19eb](https://www.github.com/googleapis/python-pubsub/commit/acc19eb048eef067d9818ef3e310b165d9c6307e)) + + +* Add a link to Pub/Sub filtering language public documentation to `pubsub.proto`. ([#121](https://github.com/googleapis/python-pubsub/pull/121)) ([8802d81](https://www.github.com/googleapis/python-pubsub/commit/8802d8126247f22e26057e68a42f5b5a82dcbf0d)) + +## [1.6.1](https://www.github.com/googleapis/python-pubsub/compare/v1.6.0...v1.6.1) (2020-06-30) + +### Documentation + + +* added Python2 sunset notice (synth) ([#140](https://www.github.com/googleapis/python-pubsub/issues/140)) ([c8f6378](https://www.github.com/googleapis/python-pubsub/commit/c8f63788636c2e3436c8ce6a01ef3b59e3df772a)) + + +* explain how to nack a sync pull message ([#123](https://www.github.com/googleapis/python-pubsub/issues/123)) ([f2eec65](https://www.github.com/googleapis/python-pubsub/commit/f2eec65cec43066ba7a2d1d45efa979e6b7add4f)) + +## [1.6.0](https://www.github.com/googleapis/python-pubsub/compare/v1.5.0...v1.6.0) (2020-06-09) + +### Features + + +* Add flow control for message publishing ([#96](https://www.github.com/googleapis/python-pubsub/issues/96)) ([06085c4](https://www.github.com/googleapis/python-pubsub/commit/06085c4083b9dccdd50383257799904510bbf3a0)) + +### Bug Fixes + + +* Fix PubSub incompatibility with api-core 1.17.0+ ([#103](https://www.github.com/googleapis/python-pubsub/issues/103)) ([c02060f](https://www.github.com/googleapis/python-pubsub/commit/c02060fbbe6e2ca4664bee08d2de10665d41dc0b)) + +### Documentation + + +* Clarify that Schedulers shouldn’t be used with multiple SubscriberClients ([#100](https://github.com/googleapis/python-pubsub/pull/100)) ([cf9e87c](https://github.com/googleapis/python-pubsub/commit/cf9e87c80c0771f3fa6ef784a8d76cb760ad37ef)) + + +* Fix update subscription/snapshot/topic samples ([#113](https://github.com/googleapis/python-pubsub/pull/113)) ([e62c38b](https://github.com/googleapis/python-pubsub/commit/e62c38bb33de2434e32f866979de769382dea34a)) + +### Internal / Testing Changes + + +* Re-generated service implementaton using synth: removed experimental notes from the RetryPolicy and filtering features in anticipation of GA, added DetachSubscription (experimental) ([#114](https://github.com/googleapis/python-pubsub/pull/114)) ([0132a46](https://github.com/googleapis/python-pubsub/commit/0132a4680e0727ce45d5e27d98ffc9f3541a0962)) + + +* Incorporate will_accept() checks into publish() ([#108](https://github.com/googleapis/python-pubsub/pull/108)) ([6c7677e](https://github.com/googleapis/python-pubsub/commit/6c7677ecb259672bbb9b6f7646919e602c698570)) + +## [1.5.0](https://www.github.com/googleapis/python-pubsub/compare/v1.4.3...v1.5.0) (2020-05-04) + +### Features + + +* add methods for listing snapshots (via synth) ([#66](https://www.github.com/googleapis/python-pubsub/issues/66)) ([4ce898e](https://www.github.com/googleapis/python-pubsub/commit/4ce898e80eeb16b18d1ee29c678ade149804d186)) + + +* send client id with StreamingPullRequest ([#58](https://www.github.com/googleapis/python-pubsub/issues/58)) ([9f8acfa](https://www.github.com/googleapis/python-pubsub/commit/9f8acfacfbe93224f59439bb51a17fc28b06c22a)), closes [#62](https://www.github.com/googleapis/python-pubsub/issues/62) + +## [1.4.3](https://www.github.com/googleapis/python-pubsub/compare/v1.4.2...v1.4.3) (2020-04-16) + +### Bug Fixes + + +* fix docs warnings in Sphinx 3.0+ ([#70](https://www.github.com/googleapis/python-pubsub/issues/70)) ([21e761e](https://www.github.com/googleapis/python-pubsub/commit/21e761ee89a4c03e105dc9cddbab0a34be9a9fda)) + + +* restrict api-core dependency to < 1.17.0 ([#76](https://www.github.com/googleapis/python-pubsub/issues/76)) ([191b051](https://www.github.com/googleapis/python-pubsub/commit/191b0516335f5c60828a818ba79e99d6c68aa7bd)) + +## [1.4.2](https://www.github.com/googleapis/python-pubsub/compare/v1.4.1...v1.4.2) (2020-03-25) + +### Bug Fixes + + +* update generated retry timings for publish and pull rpcs via synth ([#43](https://www.github.com/googleapis/python-pubsub/issues/43)) ([4f7fe85](https://www.github.com/googleapis/python-pubsub/commit/4f7fe85618d811fea94cb46b5dc758aa78c328a8)) + + +* use client_options.api_endpoint parameter instead of ignoring it ([#59](https://www.github.com/googleapis/python-pubsub/issues/59)) ([56b8d7b](https://www.github.com/googleapis/python-pubsub/commit/56b8d7b046a495ce2ce59bebdd354385147a5013)), closes [#61](https://www.github.com/googleapis/python-pubsub/issues/61) + +## [1.4.1](https://www.github.com/googleapis/python-pubsub/compare/v1.4.0...v1.4.1) (2020-03-23) + +### Bug Fixes + + +* Don’t assert on unordered publishes after publish error. ([#49](https://www.github.com/googleapis/python-pubsub/issues/49)) ([ea19ce6](https://www.github.com/googleapis/python-pubsub/commit/ea19ce616f6961e8993b72cd2921f7f3e61541f9)) + +## [1.4.0](https://www.github.com/googleapis/python-pubsub/compare/v1.3.1...v1.4.0) (2020-03-06) + +### Features + + +* **pubsub:** implement max_duration_per_lease_extension option ([#38](https://www.github.com/googleapis/python-pubsub/issues/38)) ([d911a2d](https://www.github.com/googleapis/python-pubsub/commit/d911a2dc8edf3c348ad3f128368b30e32dbc449e)) + +## [1.3.1](https://www.github.com/googleapis/python-pubsub/compare/v1.3.0...v1.3.1) (2020-02-28) + +### Bug Fixes + + +* shutdown error on streaming pull callback error ([#40](https://www.github.com/googleapis/python-pubsub/issues/40)) ([552539e](https://www.github.com/googleapis/python-pubsub/commit/552539e7beb30833c39dd29bfcb0183a07895f97)) + +## [1.3.0](https://www.github.com/googleapis/python-pubsub/compare/v1.2.0...v1.3.0) (2020-02-20) + +### Features + + +* **pubsub:** ordering keys ([#26](https://www.github.com/googleapis/python-pubsub/issues/26)) ([cc3093a](https://www.github.com/googleapis/python-pubsub/commit/cc3093a2c0304259bc374bc2eeec9630e4a11a5e)) + + +* add context manager capability to subscriber ([#32](https://www.github.com/googleapis/python-pubsub/issues/32)) ([b58d0d8](https://www.github.com/googleapis/python-pubsub/commit/b58d0d8e404c0a085b89d3407e6640651e81568c)) + +## [1.2.0](https://www.github.com/googleapis/python-pubsub/compare/v1.1.0...v1.2.0) (2020-02-05) + +### Features + + +* **pubsub:** add delivery attempt property to message object received by user code ([#10205](https://www.github.com/googleapis/google-cloud-python/issues/10205)) ([a0937c1](https://www.github.com/googleapis/python-pubsub/commit/a0937c13107b92271913de579b60f24b2aaac177)) + + +* add `StreamingPullRequest.client_id` field (via synth) ([199d56a](https://www.github.com/googleapis/python-pubsub/commit/199d56a939bb6244f67138f843dafdd80721f0d3)) + +### Bug Fixes + + +* **pubsub:** handle None in on response callback ([#9982](https://www.github.com/googleapis/google-cloud-python/issues/9982)) ([6596c4b](https://www.github.com/googleapis/python-pubsub/commit/6596c4bae5526d82f5c1b5e0c243b2883404d51f)) + + +* replace unsafe six.PY3 with PY2 for better future compatibility with Python 4 ([#10081](https://www.github.com/googleapis/google-cloud-python/issues/10081)) ([975c1ac](https://www.github.com/googleapis/python-pubsub/commit/975c1ac2cfdac0ce4403c0b56ad19f2ee7241f1a)) + +## 1.1.0 + +12-09-2019 18:51 PST + +### Implementation Changes + + +* Update client configurations (via synth). ([#9784](https://github.com/googleapis/google-cloud-python/pull/9784)) + + +* Include request overhead when computing publish batch size overflow. ([#9911](https://github.com/googleapis/google-cloud-python/pull/9911)) + + +* Split large (mod)ACK requests into smaller ones. ([#9594](https://github.com/googleapis/google-cloud-python/pull/9594)) + + +* Fix messages delivered multiple times despite a long ACK deadline. ([#9525](https://github.com/googleapis/google-cloud-python/pull/9525)) + + +* Update batching and flow control parameters to be same as the other client libraries. ([#9597](https://github.com/googleapis/google-cloud-python/pull/9597)) + + +* Add `StreamingPullManager._should_terminate`. ([#9335](https://github.com/googleapis/google-cloud-python/pull/9335)) + +### New Features + + +* Add stop method. ([#9365](https://github.com/googleapis/google-cloud-python/pull/9365)) + +### Dependencies + + +* Add Python 2 sunset banner to documentation. ([#9036](https://github.com/googleapis/google-cloud-python/pull/9036)) + +### Documentation + + +* Change spacing in docs templates (via synth). ([#9759](https://github.com/googleapis/google-cloud-python/pull/9759)) + +### Internal / Testing Changes + + +* Refactor fake leaser test helper. ([#9632](https://github.com/googleapis/google-cloud-python/pull/9632)) + + +* Add subscriber role test for streaming. ([#9507](https://github.com/googleapis/google-cloud-python/pull/9507)) + +## 1.0.2 + +09-30-2019 11:57 PDT + +### Implementation Changes + + +* Streaming pull shouldn’t need `subscriptions.get` permission ([#9360](https://github.com/googleapis/google-cloud-python/pull/9360)). + +## 1.0.1 + +09-27-2019 07:01 PDT + +### Implementation Changes + + +* Set default stream ACK deadline to subscriptions’. ([#9268](https://github.com/googleapis/google-cloud-python/pull/9268)) + +### Documentation + + +* Fix intersphinx reference to requests. ([#9294](https://github.com/googleapis/google-cloud-python/pull/9294)) + + +* Link to correct TimeoutError in futures docs. ([#9216](https://github.com/googleapis/google-cloud-python/pull/9216)) + +### Internal / Testing Changes + + +* Adjust messaging RPC timeout settings (via synth). [#9279](https://github.com/googleapis/google-cloud-python/pull/9279) + +## 1.0.0 + +08-29-2019 09:27 PDT + +### Implementation Changes + + +* Add ‘ReceivedMessage.delivery_attempt’ field (via synth). ([#9098](https://github.com/googleapis/google-cloud-python/pull/9098)) + + +* Remove send/recv msg size limit, update docstrings (via synth). ([#8964](https://github.com/googleapis/google-cloud-python/pull/8964)) + +### Documentation + + +* Update docstrings for client kwargs and fix return types uris ([#9037](https://github.com/googleapis/google-cloud-python/pull/9037)) + + +* Remove CI for gh-pages, use googleapis.dev for api_core refs. ([#9085](https://github.com/googleapis/google-cloud-python/pull/9085)) + + +* Remove compatability badges from READMEs. ([#9035](https://github.com/googleapis/google-cloud-python/pull/9035)) + +### Internal / Testing Changes + + +* Add dead-letter-policy field in preparation for its implementation (via synth) ([#9078](https://github.com/googleapis/google-cloud-python/pull/9078)) + +## 0.45.0 + +07-31-2019 02:03 PDT + +### Implementation Changes + + +* Remove deprecated methods and settings ([#8836](https://github.com/googleapis/google-cloud-python/pull/8836)) + +### Documentation + + +* Use double backticks for ReST correctness. ([#8829](https://github.com/googleapis/google-cloud-python/pull/8829)) + + +* Update intersphinx mapping for requests. ([#8805](https://github.com/googleapis/google-cloud-python/pull/8805)) + +## 0.44.0 + +07-29-2019 04:28 PDT + +### Implementation Changes + + +* PubSub: Deprecate several FlowControl settings and things in Message class ([#8796](https://github.com/googleapis/google-cloud-python/pull/8796)) + +### Documentation + + +* Pub/Sub: document regional endpoint ([#8789](https://github.com/googleapis/google-cloud-python/pull/8789)) + +## 0.43.0 + +07-24-2019 17:13 PDT + +### Implementation Changes + + +* Accomodate new location of ‘IAMPolicyStub’ (via synth). ([#8680](https://github.com/googleapis/google-cloud-python/pull/8680)) + + +* Use kwargs in test_subscriber_client ([#8414](https://github.com/googleapis/google-cloud-python/pull/8414)) + +### New Features + + +* Add `options_` argument to clients’ `get_iam_policy`; pin black version (via synth). ([#8657](https://github.com/googleapis/google-cloud-python/pull/8657)) + + +* Add ‘client_options’ support, update list method docstrings (via synth). ([#8518](https://github.com/googleapis/google-cloud-python/pull/8518)) + +### Dependencies + + +* Bump minimum version for google-api-core to 1.14.0. ([#8709](https://github.com/googleapis/google-cloud-python/pull/8709)) + + +* Update pin for ‘grpc-google-iam-v1’ to 0.12.3+. ([#8647](https://github.com/googleapis/google-cloud-python/pull/8647)) + +### Documentation + + +* Link to googleapis.dev documentation in READMEs. ([#8705](https://github.com/googleapis/google-cloud-python/pull/8705)) + + +* Add compatibility check badges to READMEs. ([#8288](https://github.com/googleapis/google-cloud-python/pull/8288)) + + +* Fix typo in publisher index. ([#8619](https://github.com/googleapis/google-cloud-python/pull/8619)) + + +* Document how to choose the PubSub auth method ([#8429](https://github.com/googleapis/google-cloud-python/pull/8429)) + + +* Document different PuSub received message types ([#8468](https://github.com/googleapis/google-cloud-python/pull/8468)) + + +* PubSub: Document batch settings, make synth operations idempotent ([#8448](https://github.com/googleapis/google-cloud-python/pull/8448)) + + +* Add custom docstrings for FlowControl enum and values (via synth). ([#8426](https://github.com/googleapis/google-cloud-python/pull/8426)) + +### Internal / Testing Changes + + +* Add docs job to publish to googleapis.dev. ([#8464](https://github.com/googleapis/google-cloud-python/pull/8464)) + + +* Add system tests for PubSub clients ([#8277](https://github.com/googleapis/google-cloud-python/pull/8277)) + +## 0.42.1 + +06-18-2019 15:14 PDT + +### Implementation Changes + + +* Increase the minimum allowed version for api core. ([#8419](https://github.com/googleapis/google-cloud-python/pull/8419)) + + +* Allow kwargs to be passed to create_channel. ([#8399](https://github.com/googleapis/google-cloud-python/pull/8399)) + +## 0.42.0 + +06-18-2019 11:32 PDT + +### Implementation Changes + + +* Core: Mitigate busy reopen loop in ResumableBidiRpc consuming 100% CPU ([#8193](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/8193)) + + +* Pub/Sub: Increase initial_rpc_timeout for messaging (via synth). ([#8219](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/8219)) + + +* PubSub: Release the state lock before calling the publish api ([#8234](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/8234)) + + +* Pub/Sub: Expose publish retry settings ([#8231](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/8231)) + + +* Prevent unhandled background error on SPM shutdown ([#8111](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/8111)) + + +* Update timeouts, blacken noxfile.py, setup.py (via synth). ([#8128](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/8128)) + + +* PubSub: Fix streaming pull incorrectly handling FlowControl max_messages setting ([#7948](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/7948)) + +### Documentation + + +* Document PubSub FlowControl settings ([#8293](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/8293)) + + +* Replace readthedocs links with links to github docs. ([#8291](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/8291)) + + +* Pub/Sub: surface publish future in documentation ([#8229](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/8229)) + + +* Pubsub: Separate subscriber and publish future documentation. ([#8205](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/8205)) + + +* Drop mention of long-removed ‘policy’ object. ([#8081](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/8081)) + +### Internal / Testing Changes + + +* Pub/Sub: staticmethod check ([#8091](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/8091)) + + +* Add empty lines (via synth). ([#8067](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/8067)) + +## 0.41.0 + +05-15-2019 13:57 PDT + +### New Features + + +* Add `kms_key_name` arg to `create_topic`; remove BETA warnings (via synth). ([#7936](https://github.com/googleapis/google-cloud-python/pull/7936)) + + +* Add message ordering (via synth). ([#7551](https://github.com/googleapis/google-cloud-python/pull/7551)) + +### Implementation Changes + + +* Propagate subscribe callback errors to main thread ([#7954](https://github.com/googleapis/google-cloud-python/pull/7954)) + + +* Fix pubsub Streaming Pull shutdown on RetryError ([#7863](https://github.com/googleapis/google-cloud-python/pull/7863)) + + +* Make PubSub subscriber Scheduler inherit from ABC ([#7690](https://github.com/googleapis/google-cloud-python/pull/7690)) + + +* Add routing header to method metadata (via synth). ([#7623](https://github.com/googleapis/google-cloud-python/pull/7623)) + +### Internal / Testing Changes + + +* Remove classifier for Python 3.4 for end-of-life. ([#7535](https://github.com/googleapis/google-cloud-python/pull/7535)) + + +* Add nox session `docs` (via synth). ([#7778](https://github.com/googleapis/google-cloud-python/pull/7778)) + + +* Pub/Sub (nit): wrong var name in sample ([#7705](https://github.com/googleapis/google-cloud-python/pull/7705)) + +## 0.40.0 + +03-15-2019 14:09 PDT + +### Implementation Changes + + +* Propagate ‘RetryError’ in ‘PublisherClient.publish’. ([#7071](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/7071)) + + +* Protoc-generated serialization update.. ([#7091](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/7091)) + +### New Features + + +* Add ‘authentication_method’ to ‘PushConfig’ (via synth). ([#7512](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/7512)) + + +* Add protos as an artifact to library ([#7205](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/7205)) + + +* Pub/sub: pass transport w/ custom channel to GAPIC API clients. ([#7008](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/7008)) + +### Dependencies + +### Documentation + + +* Updated client library documentation URLs. ([#7307](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/7307)) + + +* Update copyright headers + + +* Fix broken docstring cross-reference links. ([#7132](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/7132)) + + +* Docstring changes from updates to .proto files. ([#7054](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/7054)) + + +* Pick up stub docstring fix in GAPIC generator. ([#6978](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/6978)) + +### Internal / Testing Changes + + +* Copy proto files alongside protoc versions. + +## 0.39.1 + +12-17-2018 16:57 PST + +### Implementation Changes + + +* Initialize `StreamingPullFuture._cancelled` as True. ([#6901](https://github.com/googleapis/google-cloud-python/pull/6901)) + + +* Import `iam.policy` from `google.api_core`. ([#6741](https://github.com/googleapis/google-cloud-python/pull/6741)) + +### Documentation + + +* Document Python 2 deprecation ([#6910](https://github.com/googleapis/google-cloud-python/pull/6910)) + + +* Emphasize that returned futures may differ from stdlib futures. ([#6875](https://github.com/googleapis/google-cloud-python/pull/6875)) + +### Internal / Testing Changes + + +* Add baseline for synth.metadata + + +* Update noxfile. + + +* blacken all gen’d libs ([#6792](https://github.com/googleapis/google-cloud-python/pull/6792)) + + +* omit local deps ([#6701](https://github.com/googleapis/google-cloud-python/pull/6701)) + + +* Run black at end of synth.py ([#6698](https://github.com/googleapis/google-cloud-python/pull/6698)) + + +* Run Black on Generated libraries ([#6666](https://github.com/googleapis/google-cloud-python/pull/6666)) + + +* Add templates for flake8, coveragerc, noxfile, and black. ([#6642](https://github.com/googleapis/google-cloud-python/pull/6642)) + +## 0.39.0 + +11-27-2018 13:32 PST + +### Implementation Changes + + +* Pick up fixes to GAPIC generator. ([#6503](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/6503)) + + +* Override client classmethod factories inherited from GAPIC. ([#6453](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/6453)) + + +* Fix imports for hand-written client docstring examples. ([#6345](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/6345)) + + +* Fix path for patch of ‘bidi’ elements. ([#6243](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/6243)) + + +* Move bidi to api-core. ([#6211](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/6211)) + + +* Re-generate library using pubsub/synth.py ([#6059](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/6059)) + + +* Re-generate library using pubsub/synth.py ([#5978](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/5978)) + +### New Features + + +* Add ‘expiration_policy’ to subscriber client. ([#6223](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/6223)) + +### Dependencies + + +* Bump minimum ‘api_core’ version for all GAPIC libs to 1.4.1. ([#6391](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/6391)) + + +* Update IAM version in dependencies. ([#6362](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/6362)) + + +* Bump minimum ‘api_core’ version to ‘1.4.1’. ([#6134](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/6134)) + +### Documentation + + +* Fix client_info bug, update docstrings. ([#6418](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/6418)) + + +* Fix docstring reference to wrong future class. ([#6382](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/6382)) + + +* Normalize use of support level badges. ([#6159](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/6159)) + + +* Update subscriber example in README to current patterns. ([#6194](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/6194)) + + +* Prep pubsub docs for repo split. ([#6001](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/6001)) + +### Internal / Testing Changes + + +* Fix error from new flake8 version. ([#6346](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/6346)) + + +* Use new Nox. ([#6175](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/6175)) + +## 0.38.0 + +### Implementation Changes + + +* Fix race condition in recv()’s usage of self.call. ([#5935](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/5935)) + + +* Re-generate the underlying library from protos. ([#5953](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/5953)) + + +* Change ‘BatchSettings.max_bytes’ default. ([#5899](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/5899)) + + +* Fix race condition where pending Ack IDs can be modified by another thread. ([#5929](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/5929)) + +### Internal / Testing Changes + + +* Nox: use inplace installs ([#5865](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/5865)) + +## 0.37.2 + +### Implementation Changes + + +* Fix classmethod wrapping (#5826) + +### Documentation + + +* Fix Sphinx rendering for publisher client. (#5822) + +### Internal / Testing Changes + + +* Re-generate library, removing obsolete synth modifications. (#5825) + + +* Add test for testing invoking a wrapped class method on the class itself (#5828) + +## 0.37.1 + +### Implementation Changes + + +* Make get_initial_request more resilient to race conditions. (#5803) + +## 0.37.0 + +### Implementation Changes + + +* Make Publisher batch-related interfaces private (#5784) + +## 0.36.0 + +### Implementation Changes + + +* Pubsub: Make ‘Message.publish_time’ return datetime (#5633) + + +* Ensure SPM methods check that ‘self._consumer’ is not None before use. (#5758) + +### New Features + + +* PubSub: add geo-fencing support (#5769) + + +* Add ‘Message.ack_id’ property. (#5693) + +## 0.35.4 + +### Implementation Changes + + +* Recover streams during the gRPC error callback. (#5446) + + +* Use operational lock when checking for activity on streams. (#5445) + +## 0.35.3 + +### Implementation Changes + + +* Add additional error handling to unary RPCs (#5438) + +## 0.35.2 + +### Implementation Changes + + +* Add heartbeating to the streaming pull manager (#5413) + + +* Fix retrying of bidirectional RPCs and closing the streaming pull manager (#5412) + +## 0.35.1 + +### Implementation Changes + + +* Catch errors when re-retying send() or recv() in addition to open() (#5402) + +## 0.35.0 + +### Implementation Changes + + +* Send requests during streaming pull over a separate unary RPC (#5377) + + +* Initialize references to helper threads before starting them (#5374) + + +* Make leaser exit more quickly (#5373) + + +* Make re-open failures bubble to callbacks (#5372) + + +* Avoid overwriting ‘**module**’ of messages from shared modules. (#5364) + + +* Normalize overflow handling for max count and bytes (#5343) + +### New Features + + +* Restore the synchronous pull method (#5379) + + +* Promote subscribe_experimental() to subscribe(), remove old subscriber implementation. (#5274) + + +* Wire up scheduler argument for subscribe() (#5279) + +### Documentation + + +* Add link to streaming pull behavior documentation (#5378) + + +* Fix example in subscribe’s documentation (#5375) + +### Internal / Testing Changes + + +* Add Test runs for Python 3.7 and remove 3.4 (#5295) + + +* Modify system tests to use prerelease versions of grpcio (#5304) + +## 0.34.0 + +### Implementation Changes + + +* Lower the flow control defaults. (#5248) + +### New Features + + +* A new implementation of the subscriber has been added. This is available as `SubscriberClient.subscribe_experimental`. In the next release, this will be replace the current `subscribe` method. If you use this, please report your findings to us on GitHub. (#5189, #5201, #5210, #5229, #5230, #5237, #5256) + +### Dependencies + + +* Remove psutil dependency. (#5248) + +## 0.33.1 + +### Implementation changes + + +* Surface publish RPC errors back to the publish futures (#5124) + + +* Make the pausable response iterator aware of the RPC state to prevent deadlock (#5108) + + +* Properly handle graceful stop in request generator (#5097) + +## 0.33.0 + +### Implementation changes + + +* Drop leased messages after flow_control.max_lease_duration has passed. (#5020) + + +* Fix mantain leases to not modack messages it just dropped (#5045) + + +* Avoid race condition in maintain_leases by copying leased_messages (#5035) + + +* Retry subscription stream on InternalServerError, Unknown, and GatewayTimeout (#5021) + + +* Use the rpc’s status to determine when to exit the request generator thread (#5054) + + +* Fix missing iter on request stream (#5078) + + +* Nack messages when the subscriber callback errors (#5019) + +### Testing + + +* pubsub nox.py cleanup (#5056) + + +* Fix test that checks for retryable exceptions (#5034) + +## 0.32.1 + +### Dependencies + + +* Update dependency range for api-core to include v1.0.0 releases (#4944) + +### Testing and internal changes + + +* Install local dependencies when running lint (#4936) + + +* Re-enable lint for tests, remove usage of pylint (#4921) + +## 0.32.0 + +### Implementation changes + + +* Added support for streaming pull receipts. (#4878) + +## 0.31.0 + +### New features + + +* Added the ability for subscriber to batch requests. (#4895) + + +* Added pending request backpressure for subscriber. (#4892) + +### Implementation changes + + +* Raise `ValueError` when a message is too large for a batch. (#4872) + + +* Updated the default batch size to 10 MB. (#4857) + + +* Allow a custom `Event` type in Pub / Sub futures. (#4643) + +### Documentation + + +* Clarify that `modify_ack_deadline` resets the deadline. (#4822) + +### Testing + + +* Fix unit test for default `max_bytes` value. (#4860) + +## 0.30.1 + +### Notable Implementation Changes + + +* Moving lock factory used in publisher client to the Batch +implementation (#4628). + + +* Use a UUID (rather than a sentinel object) on `Future` (#4634). + + +* Apply scopes to explicitly provided credentials if needed (#4594). +Fixes #4479. This feature comes as part of `google-api-core==0.1.3`. + +### Dependencies + + +* Upgrading to `google-api-core==0.1.3` which depends on the latest +`grpcio==1.8.2` (#4642). This fixes #4600. For details, see related +gRPC [bug](https://github.com/grpc/grpc/issues/9688) and +[fix](https://github.com/grpc/grpc/pull/13665). + +PyPI: https://pypi.org/project/google-cloud-pubsub/0.30.1/ + +## 0.30.0 + +### Notable Implementation Changes + + +* Dropping redundant `Policy._paused` data member (#4568). + + +* Removing redundant “active” check in policy (#4603). + + +* Adding a `Consumer.active` property (#4604). + + +* Making it impossible to call `Policy.open()` on an already opened +policy (#4606). + + +* **Bug fix** (#4575): Fix bug with async publish for batches. There +were two related bugs. The first: if a batch exceeds the `max_messages` +from the batch settings, then the `commit()` will fail. The second: +when a “monitor” worker calls `commit()` after `max_latency` seconds, +a failure can occur if a new message is added to the batch **during** +the commit. To fix, the following changes were implemented: + + + * Adding a “STARTING” status for `Batch.commit()` (#4614). This +fixes the issue when the batch exceeds `max_messages`. + + + * Adding extra check in `Batch.will_accept` for the number of +messages (#4612). + + + * Moving `will_accept()` check out of `PublisherClient.batch()` +factory (#4613). + + + * Checking `Batch.will_accept` in thread-safe way (#4616). + + +* **Breaking API change**: As part of #4613, changing `PublisherClient.batch()` +to no longer accept a `message` (since the `will_accept` check needs to +happen in a more concurrency friendly way). In addition, changing the +`create` argument so that it means “create even if batch already exists” +rather than “create if missing”. + +### Documentation + + +* Add more explicit documentation for `Message.attributes` (#4601). + + +* Make `Message.__repr__` a bit prettier / more useful (#4602). + +PyPI: https://pypi.org/project/google-cloud-pubsub/0.30.0/ + +## 0.29.4 + +### Notable Implementation Changes + + +* **Bug fix**: Restore previous behavior of the subscription lease +maintenance worker. This was accidentally “stopped” in `0.29.3` +due to a change in implementation that went from an `active` +boolean to an “inactive” / `stopped` boolean, so `True` became +`False` and vice-versa (#4564). + +PyPI: https://pypi.org/project/google-cloud-pubsub/0.29.4/ + +## 0.29.3 + +### Notable Implementation Changes + + +* In subscription consumer thread: Making sure the request generator +attached to an inactive bidirectional streaming pull is stopped before +spawning a new request generator. This way we have a (fairly strong) +guarantee that requests in the queue don’t get sent into an inactive +stream (#4503, #4554). + + +* Adding `pause` / `resume` to subscription consumer thread and using these +methods during flow control. The previous implementation tried to close the +subscription (which involved 3 worker threads and 10 executors in a thread +pool) and then re-open a new subscription. But, this was not entirely +possible to shut down correctly from **within** one of the worker threads. +Instead, we only pause the worker (of the 3) that is pulling new responses +from the bidirectional streaming pull (#4558). + + +* **Bug fix** (#4516): Using `max` where `min` was used by mistake to +ensure the number of bytes tracked for subscription flow control +remained non-negative (#4514). + + +* Raising `TypeError` if `SubscriberClient.subscribe` receives a +non-callable callback (#4497). + + +* Shutting down thread pool executor when closing a subscriber +policy (#4522). + + +* Renaming `Policy.on_callback_request` to `Policy.dispatch_callback` +and making the behavior much less dynamic (#4511). + + +* Make sure subscription consumer thread doesn’t try to join itself +when exiting in error (#4540). + +### Dependencies + + +* Upgrading `google-api-core` dependency to latest revision (`0.1.2`) +since we rely on the latest version of the `concurrent.futures` backport +to provide the `thread_name_prefix` argument for thread pool +executor (#4521, #4559). + +PyPI: https://pypi.org/project/google-cloud-pubsub/0.29.3/ + +## 0.29.2 + +### Notable Implementation Changes + + +* **Bug fix** (#4463): Making a subscription consumer actually stop +running after encountering an exception (#4472, #4498). This bug +is the **only** reason for the `0.29.2` release. + + +* Thread Changes + + + * Added names to all threads created directly by Pub / Sub (#4474, +#4476, #4480). Also removing spaces and colons from thread +names (#4476). + + +* Logging changes + + + * Adding debug logs when lease management exits (#4484) + + + * Adding debug logs when `QueueCallbackThread` exits (#4494). +Instances handle the processing of messages in a +subscription (e.g. to `ack`). + + + * Using a named logger in `publisher.batch.thread` (#4473) + + + * Adding newlines before logging protobuf payloads (#4471) + +PyPI: https://pypi.org/project/google-cloud-pubsub/0.29.2/ + +## 0.29.1 + +### Notable Implementation Changes + + +* **Bug fix** (#4234): Adding retries for connection `UNAVAILABLE`. This +bug made the Pub / Sub client mostly unusable for subscribers to topics +that don’t have a steady stream of messages. After ~2 minutes of inactivity, +the gRPC connection would timeout and raise `UNAVAILABLE` locally, i.e. not +due to a response from the backend. (#4444) + + +* Updating autogenerated packages (#4438) + +### Documentation + + +* Fixing broken examples in quick start (#4398) + + +* Fixing broken example in README (#4402, h/t to @mehmetboraezer) + + +* Updating old/dead link to usage doc in README (#4406, h/t to @mehmetboraezer) + +### Dependencies + + +* Dropping dependency on `google-cloud-core` in exchange for +`google-api-core` (#4438) + +PyPI: https://pypi.org/project/google-cloud-pubsub/0.29.1/ + +## 0.29.0 + +### Notable Implementation Changes + + +* Honor `max_messages` always (#4262) + + +* Add futures for subscriptions (#4265) + + +* Set gRPC message options and keepalive (#4269) + +### Documentation + + +* Added link to “Python Development Environment Setup Guide” in +project README (#4187, h/t to @michaelawyu) + +### Dependencies + + +* Upgrading to `google-cloud-core >= 0.28.0` and adding dependency +on `google-api-core` (#4221, #4280) + + +* Deferring to `google-api-core` for `grpcio` and +`googleapis-common-protos` dependencies (#4096, #4098) + +PyPI: https://pypi.org/project/google-cloud-pubsub/0.29.0/ diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.publisher.client.Client.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.publisher.client.Client.yml new file mode 100644 index 000000000000..e564b88b1af0 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.publisher.client.Client.yml @@ -0,0 +1,1790 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: [] + children: + - google.cloud.pubsub_v1.publisher.client.Client + - google.cloud.pubsub_v1.publisher.client.Client.__exit__ + - google.cloud.pubsub_v1.publisher.client.Client.api + - google.cloud.pubsub_v1.publisher.client.Client.common_billing_account_path + - google.cloud.pubsub_v1.publisher.client.Client.common_folder_path + - google.cloud.pubsub_v1.publisher.client.Client.common_location_path + - google.cloud.pubsub_v1.publisher.client.Client.common_organization_path + - google.cloud.pubsub_v1.publisher.client.Client.common_project_path + - google.cloud.pubsub_v1.publisher.client.Client.create_topic + - google.cloud.pubsub_v1.publisher.client.Client.delete_topic + - google.cloud.pubsub_v1.publisher.client.Client.detach_subscription + - google.cloud.pubsub_v1.publisher.client.Client.ensure_cleanup_and_commit_timer_runs + - google.cloud.pubsub_v1.publisher.client.Client.from_service_account_file + - google.cloud.pubsub_v1.publisher.client.Client.from_service_account_info + - google.cloud.pubsub_v1.publisher.client.Client.from_service_account_json + - google.cloud.pubsub_v1.publisher.client.Client.get_iam_policy + - google.cloud.pubsub_v1.publisher.client.Client.get_mtls_endpoint_and_cert_source + - google.cloud.pubsub_v1.publisher.client.Client.get_topic + - google.cloud.pubsub_v1.publisher.client.Client.list_topic_snapshots + - google.cloud.pubsub_v1.publisher.client.Client.list_topic_subscriptions + - google.cloud.pubsub_v1.publisher.client.Client.list_topics + - google.cloud.pubsub_v1.publisher.client.Client.parse_common_billing_account_path + - google.cloud.pubsub_v1.publisher.client.Client.parse_common_folder_path + - google.cloud.pubsub_v1.publisher.client.Client.parse_common_location_path + - google.cloud.pubsub_v1.publisher.client.Client.parse_common_organization_path + - google.cloud.pubsub_v1.publisher.client.Client.parse_common_project_path + - google.cloud.pubsub_v1.publisher.client.Client.parse_schema_path + - google.cloud.pubsub_v1.publisher.client.Client.parse_subscription_path + - google.cloud.pubsub_v1.publisher.client.Client.parse_topic_path + - google.cloud.pubsub_v1.publisher.client.Client.publish + - google.cloud.pubsub_v1.publisher.client.Client.resume_publish + - google.cloud.pubsub_v1.publisher.client.Client.schema_path + - google.cloud.pubsub_v1.publisher.client.Client.set_iam_policy + - google.cloud.pubsub_v1.publisher.client.Client.stop + - google.cloud.pubsub_v1.publisher.client.Client.subscription_path + - google.cloud.pubsub_v1.publisher.client.Client.target + - google.cloud.pubsub_v1.publisher.client.Client.test_iam_permissions + - google.cloud.pubsub_v1.publisher.client.Client.topic_path + - google.cloud.pubsub_v1.publisher.client.Client.transport + - google.cloud.pubsub_v1.publisher.client.Client.update_topic + class: google.cloud.pubsub_v1.publisher.client.Client + fullName: google.cloud.pubsub_v1.publisher.client.Client + inheritance: + - inheritance: + - type: builtins.object + type: google.pubsub_v1.services.publisher.client.PublisherClient + langs: + - python + module: google.cloud.pubsub_v1.publisher.client + name: Client + source: + id: Client + path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 65 + summary: 'A publisher client for Google Cloud Pub/Sub. + + + This creates an object that is capable of publishing messages. + + Generally, you can instantiate this client with no arguments, and you + + get sensible defaults. + + ' + syntax: + content: "Client(\n batch_settings: typing.Union[\n google.cloud.pubsub_v1.types.BatchSettings,\ + \ typing.Sequence\n ] = (),\n publisher_options: typing.Union[\n \ + \ google.cloud.pubsub_v1.types.PublisherOptions, typing.Sequence\n ] =\ + \ (),\n **kwargs: typing.Any\n)" + parameters: [] + type: class + uid: google.cloud.pubsub_v1.publisher.client.Client +- attributes: [] + class: google.cloud.pubsub_v1.publisher.client.Client + fullName: google.cloud.pubsub_v1.publisher.client.Client + inheritance: + - inheritance: + - type: builtins.object + type: google.pubsub_v1.services.publisher.client.PublisherClient + langs: + - python + module: google.cloud.pubsub_v1.publisher.client + name: Client + source: + id: Client + path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 65 + summary: 'Instantiates the publisher client. + + ' + syntax: + content: "Client(\n batch_settings: typing.Union[\n google.cloud.pubsub_v1.types.BatchSettings,\ + \ typing.Sequence\n ] = (),\n publisher_options: typing.Union[\n \ + \ google.cloud.pubsub_v1.types.PublisherOptions, typing.Sequence\n ] =\ + \ (),\n **kwargs: typing.Any\n)" + exceptions: + - description: If mutual TLS transport creation failed for any reason. + var_type: google.auth.exceptions.MutualTLSChannelError + parameters: + - description: The authorization credentials to attach to requests. These credentials + identify the application to the service; if none are specified, the client + will attempt to ascertain the credentials from the environment. + id: credentials + var_type: Optional[google.auth.credentials.Credentials] + - description: The transport to use. If set to None, a transport is chosen automatically. + id: transport + var_type: Union[str, PublisherTransport] + - description: 'Custom options for the client. It won''t take effect if a transport + instance is provided. (1) The api_endpoint property can be used + to override the default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT + environment variable can also be used to override the endpoint: "always" (always + use the default mTLS endpoint), "never" (always use the default regular endpoint) + and "auto" (auto switch to the default mTLS endpoint if client certificate + is present, this is the default value). However, the api_endpoint + property takes precedence if provided. (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE + environment variable is "true", then the client_cert_source property + can be used to provide client certificate for mutual TLS transport. If not + provided, the default SSL client certificate will be used if present. If GOOGLE_API_USE_CLIENT_CERTIFICATE + is "false" or not set, no client certificate will be used.' + id: client_options + var_type: google.api_core.client_options.ClientOptions + - description: The client info used to send a user-agent string along with API + requests. If None, then default info will be used. Generally, + you only need to set this if you're developing your own client library. + id: client_info + var_type: google.api_core.gapic_v1.client_info.ClientInfo + type: method + uid: google.cloud.pubsub_v1.publisher.client.Client +- attributes: [] + class: google.cloud.pubsub_v1.publisher.client.Client + fullName: google.cloud.pubsub_v1.publisher.client.Client.__exit__ + langs: + - python + module: google.cloud.pubsub_v1.publisher.client + name: __exit__ + source: + id: __exit__ + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 1430 + summary: 'Releases underlying transport''s resources. + + + ' + syntax: + content: __exit__(type, value, traceback) + parameters: [] + type: method + uid: google.cloud.pubsub_v1.publisher.client.Client.__exit__ +- &id001 + attributes: [] + class: google.cloud.pubsub_v1.publisher.client.Client + fullName: google.cloud.pubsub_v1.publisher.client.Client.api + langs: + - python + module: google.cloud.pubsub_v1.publisher.client + name: api + source: + id: api + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: "The underlying gapic API client.\n\n.. versionchanged:: 2.10.0\n Instead\ + \ of a GAPIC `PublisherClient` client instance, this property is a\n proxy\ + \ object to it with the same interface.\n\n" + syntax: {} + type: property + uid: google.cloud.pubsub_v1.publisher.client.Client.api +- *id001 +- attributes: [] + class: google.cloud.pubsub_v1.publisher.client.Client + fullName: google.cloud.pubsub_v1.publisher.client.Client.common_billing_account_path + langs: + - python + module: google.cloud.pubsub_v1.publisher.client + name: common_billing_account_path + source: + id: common_billing_account_path + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 236 + summary: 'Returns a fully-qualified billing_account string. + + + ' + syntax: + content: 'common_billing_account_path(billing_account: str)' + parameters: [] + type: method + uid: google.cloud.pubsub_v1.publisher.client.Client.common_billing_account_path +- attributes: [] + class: google.cloud.pubsub_v1.publisher.client.Client + fullName: google.cloud.pubsub_v1.publisher.client.Client.common_folder_path + langs: + - python + module: google.cloud.pubsub_v1.publisher.client + name: common_folder_path + source: + id: common_folder_path + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 251 + summary: 'Returns a fully-qualified folder string. + + + ' + syntax: + content: 'common_folder_path(folder: str)' + parameters: [] + type: method + uid: google.cloud.pubsub_v1.publisher.client.Client.common_folder_path +- attributes: [] + class: google.cloud.pubsub_v1.publisher.client.Client + fullName: google.cloud.pubsub_v1.publisher.client.Client.common_location_path + langs: + - python + module: google.cloud.pubsub_v1.publisher.client + name: common_location_path + source: + id: common_location_path + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 296 + summary: 'Returns a fully-qualified location string. + + + ' + syntax: + content: 'common_location_path(project: str, location: str)' + parameters: [] + type: method + uid: google.cloud.pubsub_v1.publisher.client.Client.common_location_path +- attributes: [] + class: google.cloud.pubsub_v1.publisher.client.Client + fullName: google.cloud.pubsub_v1.publisher.client.Client.common_organization_path + langs: + - python + module: google.cloud.pubsub_v1.publisher.client + name: common_organization_path + source: + id: common_organization_path + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 266 + summary: 'Returns a fully-qualified organization string. + + + ' + syntax: + content: 'common_organization_path(organization: str)' + parameters: [] + type: method + uid: google.cloud.pubsub_v1.publisher.client.Client.common_organization_path +- attributes: [] + class: google.cloud.pubsub_v1.publisher.client.Client + fullName: google.cloud.pubsub_v1.publisher.client.Client.common_project_path + langs: + - python + module: google.cloud.pubsub_v1.publisher.client + name: common_project_path + source: + id: common_project_path + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 281 + summary: 'Returns a fully-qualified project string. + + + ' + syntax: + content: 'common_project_path(project: str)' + parameters: [] + type: method + uid: google.cloud.pubsub_v1.publisher.client.Client.common_project_path +- attributes: [] + class: google.cloud.pubsub_v1.publisher.client.Client + fullName: google.cloud.pubsub_v1.publisher.client.Client.create_topic + langs: + - python + module: google.cloud.pubsub_v1.publisher.client + name: create_topic + source: + id: create_topic + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 488 + summary: "Creates the given topic with the given name. See the [resource\nname rules]\n\ + (https://cloud.google.com/pubsub/docs/admin#resource_names).\n\n```python\n# This\ + \ snippet has been automatically generated and should be regarded as a\n# code\ + \ template only.\n# It will require modifications to work:\n# - It may require\ + \ correct/in-range values for request initialization.\n# - It may require specifying\ + \ regional endpoints when creating the service\n# client as shown in:\n# https://googleapis.dev/python/google-api-core/latest/client_options.html\n\ + from google import pubsub_v1\n\ndef sample_create_topic():\n # Create a client\n\ + \ client = pubsub_v1.PublisherClient()\n\n # Initialize request argument(s)\n\ + \ request = pubsub_v1.Topic(\n name=\"name_value\",\n )\n\n #\ + \ Make the request\n response = client.create_topic(request=request)\n\n \ + \ # Handle the response\n print(response)\n```\n" + syntax: + content: "create_topic(\n request: typing.Union[google.cloud.pubsub_v1.types.Topic,\ + \ dict] = None,\n *,\n name: str = None,\n retry: typing.Union[\n \ + \ google.api_core.retry.Retry, google.api_core.gapic_v1.method._MethodDefault\n\ + \ ] = _MethodDefault._DEFAULT_VALUE,\n timeout: typing.Union[\n \ + \ int,\n float,\n google.api_core.timeout.ConstantTimeout,\n\ + \ google.api_core.timeout.ExponentialTimeout,\n ] = _MethodDefault._DEFAULT_VALUE,\n\ + \ metadata: typing.Sequence[typing.Tuple[str, str]] = ()\n)" + parameters: + - defaultValue: None + description: The request object. A topic resource. + id: request + var_type: Union[google.pubsub_v1.types.Topic, dict] + - description: Required. The name of the topic. It must have the format "projects/{project}/topics/{topic}". + {topic} must start with a letter, and contain only letters ([A-Za-z]), + numbers ([0-9]), dashes (-), underscores (`_), + periods (.), tildes (
), plus (
+) + or percent signs (%). It must be between 3 and 255 characters + in length, and it must not start with "goog". This corresponds + to the name field on the request instance; if request` + is provided, this should not be set. + id: name + var_type: str + - description: Designation of what errors, if any, should be retried. + id: retry + var_type: google.api_core.retry.Retry + - description: The timeout for this request. + id: timeout + var_type: TimeoutType + - description: Strings which should be sent along with the request as metadata. + id: metadata + var_type: Sequence[Tuple[str, str]] + returns: + - description: A topic resource. + var_type: google.pubsub_v1.types.Topic + type: method + uid: google.cloud.pubsub_v1.publisher.client.Client.create_topic +- attributes: [] + class: google.cloud.pubsub_v1.publisher.client.Client + fullName: google.cloud.pubsub_v1.publisher.client.Client.delete_topic + langs: + - python + module: google.cloud.pubsub_v1.publisher.client + name: delete_topic + source: + id: delete_topic + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 1243 + summary: "Deletes the topic with the given name. Returns `NOT_FOUND` if\nthe topic\ + \ does not exist. After a topic is deleted, a new topic\nmay be created with the\ + \ same name; this is an entirely new topic\nwith none of the old configuration\ + \ or subscriptions. Existing\nsubscriptions to this topic are not deleted, but\ + \ their `topic`\nfield is set to `_deleted-topic_`.\n\n```python\n# This snippet\ + \ has been automatically generated and should be regarded as a\n# code template\ + \ only.\n# It will require modifications to work:\n# - It may require correct/in-range\ + \ values for request initialization.\n# - It may require specifying regional endpoints\ + \ when creating the service\n# client as shown in:\n# https://googleapis.dev/python/google-api-core/latest/client_options.html\n\ + from google import pubsub_v1\n\ndef sample_delete_topic():\n # Create a client\n\ + \ client = pubsub_v1.PublisherClient()\n\n # Initialize request argument(s)\n\ + \ request = pubsub_v1.DeleteTopicRequest(\n topic=\"topic_value\",\n\ + \ )\n\n # Make the request\n client.delete_topic(request=request)\n```\n" + syntax: + content: "delete_topic(\n request: typing.Union[google.cloud.pubsub_v1.types.DeleteTopicRequest,\ + \ dict] = None,\n *,\n topic: str = None,\n retry: typing.Union[\n\ + \ google.api_core.retry.Retry, google.api_core.gapic_v1.method._MethodDefault\n\ + \ ] = _MethodDefault._DEFAULT_VALUE,\n timeout: typing.Union[\n \ + \ int,\n float,\n google.api_core.timeout.ConstantTimeout,\n\ + \ google.api_core.timeout.ExponentialTimeout,\n ] = _MethodDefault._DEFAULT_VALUE,\n\ + \ metadata: typing.Sequence[typing.Tuple[str, str]] = ()\n)" + parameters: + - defaultValue: None + description: The request object. Request for the DeleteTopic method. + id: request + var_type: Union[google.pubsub_v1.types.DeleteTopicRequest, dict] + - description: Required. Name of the topic to delete. Format is projects/{project}/topics/{topic}. + This corresponds to the topic field on the request + instance; if request is provided, this should not be set. + id: topic + var_type: str + - description: Designation of what errors, if any, should be retried. + id: retry + var_type: google.api_core.retry.Retry + - description: The timeout for this request. + id: timeout + var_type: TimeoutType + - description: Strings which should be sent along with the request as metadata. + id: metadata + var_type: Sequence[Tuple[str, str]] + type: method + uid: google.cloud.pubsub_v1.publisher.client.Client.delete_topic +- attributes: [] + class: google.cloud.pubsub_v1.publisher.client.Client + fullName: google.cloud.pubsub_v1.publisher.client.Client.detach_subscription + langs: + - python + module: google.cloud.pubsub_v1.publisher.client + name: detach_subscription + source: + id: detach_subscription + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 1339 + summary: "Detaches a subscription from this topic. All messages retained\nin the\ + \ subscription are dropped. Subsequent `Pull` and\n`StreamingPull` requests will\ + \ return FAILED_PRECONDITION. If\nthe subscription is a push subscription, pushes\ + \ to the endpoint\nwill stop.\n\n```python\n# This snippet has been automatically\ + \ generated and should be regarded as a\n# code template only.\n# It will require\ + \ modifications to work:\n# - It may require correct/in-range values for request\ + \ initialization.\n# - It may require specifying regional endpoints when creating\ + \ the service\n# client as shown in:\n# https://googleapis.dev/python/google-api-core/latest/client_options.html\n\ + from google import pubsub_v1\n\ndef sample_detach_subscription():\n # Create\ + \ a client\n client = pubsub_v1.PublisherClient()\n\n # Initialize request\ + \ argument(s)\n request = pubsub_v1.DetachSubscriptionRequest(\n subscription=\"\ + subscription_value\",\n )\n\n # Make the request\n response = client.detach_subscription(request=request)\n\ + \n # Handle the response\n print(response)\n```\n" + syntax: + content: "detach_subscription(\n request: typing.Union[\n google.cloud.pubsub_v1.types.DetachSubscriptionRequest,\ + \ dict\n ] = None,\n *,\n retry: typing.Union[\n google.api_core.retry.Retry,\ + \ google.api_core.gapic_v1.method._MethodDefault\n ] = _MethodDefault._DEFAULT_VALUE,\n\ + \ timeout: typing.Union[\n int,\n float,\n google.api_core.timeout.ConstantTimeout,\n\ + \ google.api_core.timeout.ExponentialTimeout,\n ] = _MethodDefault._DEFAULT_VALUE,\n\ + \ metadata: typing.Sequence[typing.Tuple[str, str]] = ()\n)" + parameters: + - defaultValue: None + description: The request object. Request for the DetachSubscription method. + id: request + var_type: Union[google.pubsub_v1.types.DetachSubscriptionRequest, dict] + - description: Designation of what errors, if any, should be retried. + id: retry + var_type: google.api_core.retry.Retry + - description: The timeout for this request. + id: timeout + var_type: TimeoutType + - description: Strings which should be sent along with the request as metadata. + id: metadata + var_type: Sequence[Tuple[str, str]] + returns: + - description: Response for the DetachSubscription method. Reserved for future + use. + var_type: google.pubsub_v1.types.DetachSubscriptionResponse + type: method + uid: google.cloud.pubsub_v1.publisher.client.Client.detach_subscription +- attributes: [] + class: google.cloud.pubsub_v1.publisher.client.Client + fullName: google.cloud.pubsub_v1.publisher.client.Client.ensure_cleanup_and_commit_timer_runs + langs: + - python + module: google.cloud.pubsub_v1.publisher.client + name: ensure_cleanup_and_commit_timer_runs + source: + id: ensure_cleanup_and_commit_timer_runs + path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 421 + summary: 'Ensure a cleanup/commit timer thread is running. + + + If a cleanup/commit timer thread is already running, this does nothing. + + + ' + syntax: + content: ensure_cleanup_and_commit_timer_runs() + parameters: [] + type: method + uid: google.cloud.pubsub_v1.publisher.client.Client.ensure_cleanup_and_commit_timer_runs +- attributes: [] + class: google.cloud.pubsub_v1.publisher.client.Client + fullName: google.cloud.pubsub_v1.publisher.client.Client.from_service_account_file + langs: + - python + module: google.cloud.pubsub_v1.publisher.client + name: from_service_account_file + source: + id: from_service_account_file + path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 161 + summary: 'Creates an instance of this client using the provided credentials + + file. + + ' + syntax: + content: "from_service_account_file(\n filename: str,\n batch_settings:\ + \ typing.Union[\n google.cloud.pubsub_v1.types.BatchSettings, typing.Sequence\n\ + \ ] = (),\n **kwargs: typing.Any\n)" + parameters: [] + type: method + uid: google.cloud.pubsub_v1.publisher.client.Client.from_service_account_file +- attributes: [] + class: google.cloud.pubsub_v1.publisher.client.Client + fullName: google.cloud.pubsub_v1.publisher.client.Client.from_service_account_info + langs: + - python + module: google.cloud.pubsub_v1.publisher.client + name: from_service_account_info + source: + id: from_service_account_info + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 136 + summary: "Creates an instance of this client using the provided credentials\n \ + \ info.\n" + syntax: + content: 'from_service_account_info(info: dict, *args, **kwargs)' + parameters: + - description: The service account private key info. + id: info + var_type: dict + returns: + - description: The constructed client. + var_type: PublisherClient + type: method + uid: google.cloud.pubsub_v1.publisher.client.Client.from_service_account_info +- attributes: [] + class: google.cloud.pubsub_v1.publisher.client.Client + fullName: google.cloud.pubsub_v1.publisher.client.Client.from_service_account_json + langs: + - python + module: google.cloud.pubsub_v1.publisher.client + name: from_service_account_json + source: + id: from_service_account_json + path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 161 + summary: 'Creates an instance of this client using the provided credentials + + file. + + ' + syntax: + content: "from_service_account_json(\n filename: str,\n batch_settings:\ + \ typing.Union[\n google.cloud.pubsub_v1.types.BatchSettings, typing.Sequence\n\ + \ ] = (),\n **kwargs: typing.Any\n)" + parameters: [] + type: method + uid: google.cloud.pubsub_v1.publisher.client.Client.from_service_account_json +- attributes: [] + class: google.cloud.pubsub_v1.publisher.client.Client + fullName: google.cloud.pubsub_v1.publisher.client.Client.get_iam_policy + langs: + - python + module: google.cloud.pubsub_v1.publisher.client + name: get_iam_policy + source: + id: get_iam_policy + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 1561 + summary: 'Gets the IAM access control policy for a function. + + + Returns an empty policy if the function exists and does not have a + + policy set. + + ' + syntax: + content: "get_iam_policy(\n request: google.iam.v1.iam_policy_pb2.GetIamPolicyRequest\ + \ = None,\n *,\n retry: typing.Union[\n google.api_core.retry.Retry,\ + \ google.api_core.gapic_v1.method._MethodDefault\n ] = _MethodDefault._DEFAULT_VALUE,\n\ + \ timeout: typing.Union[\n int,\n float,\n google.api_core.timeout.ConstantTimeout,\n\ + \ google.api_core.timeout.ExponentialTimeout,\n ] = _MethodDefault._DEFAULT_VALUE,\n\ + \ metadata: typing.Sequence[typing.Tuple[str, str]] = ()\n)" + parameters: + - defaultValue: None + description: The request object. Request message for GetIamPolicy + method. + id: request + var_type: .iam_policy_pb2.GetIamPolicyRequest + - description: Designation of what errors, if any, should be retried. + id: retry + var_type: google.api_core.retry.Retry + - description: The timeout for this request. + id: timeout + var_type: TimeoutType + - description: Strings which should be sent along with the request as metadata. + id: metadata + var_type: Sequence[Tuple[str, str]] + returns: + - description: 'Defines an Identity and Access Management (IAM) policy. It is + used to specify access control policies for Cloud Platform resources. A Policy + is a collection of bindings. A binding binds one + or more members to a single role. Members can be + user accounts, service accounts, Google groups, and domains (such as G Suite). + A role is a named list of permissions (defined by IAM or configured + by users). A binding can optionally specify a condition, + which is a logic expression that further constrains the role binding based + on attributes about the request and/or target resource. **JSON Example** :: + { "bindings": [ { "role": "roles/resourcemanager.organizationAdmin", "members": + [ "user:mike@example.com", "group:admins@example.com", "domain:google.com", + "serviceAccount:my-project-id@appspot.gserviceaccount.com" ] }, { "role": + "roles/resourcemanager.organizationViewer", "members": ["user:eve@example.com"], + "condition": { "title": "expirable access", "description": "Does not grant + access after Sep 2020", "expression": "request.time < timestamp(''2020-10-01T00:00:00.000Z'')", + } } ] } **YAML Example** :: bindings: - members: - user:mike@example.com - + group:admins@example.com - domain:google.com - serviceAccount:my-project-id@appspot.gserviceaccount.com + role: roles/resourcemanager.organizationAdmin - members: - user:eve@example.com + role: roles/resourcemanager.organizationViewer condition: title: expirable + access description: Does not grant access after Sep 2020 expression: request.time + < timestamp(''2020-10-01T00:00:00.000Z'') For a description of IAM and its + features, see the IAM developer''s guide __.' + var_type: .policy_pb2.Policy + type: method + uid: google.cloud.pubsub_v1.publisher.client.Client.get_iam_policy +- attributes: [] + class: google.cloud.pubsub_v1.publisher.client.Client + fullName: google.cloud.pubsub_v1.publisher.client.Client.get_mtls_endpoint_and_cert_source + langs: + - python + module: google.cloud.pubsub_v1.publisher.client + name: get_mtls_endpoint_and_cert_source + source: + id: get_mtls_endpoint_and_cert_source + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 313 + summary: 'Return the API endpoint and client cert source for mutual TLS. + + + The client cert source is determined in the following order: + + (1) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not "true", + the + + client cert source is None. + + (2) if `client_options.client_cert_source` is provided, use the provided one; + if the + + default client cert source exists, use the default one; otherwise the client cert + + source is None. + + + The API endpoint is determined in the following order: + + (1) if `client_options.api_endpoint` if provided, use the provided one. + + (2) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is "always", use + the + + default mTLS endpoint; if the environment variabel is "never", use the default + API + + endpoint; otherwise if client cert source exists, use the default mTLS endpoint, + otherwise + + use the default API endpoint. + + + More details can be found at https://google.aip.dev/auth/4114. + + ' + syntax: + content: "get_mtls_endpoint_and_cert_source(\n client_options: typing.Optional[\n\ + \ google.api_core.client_options.ClientOptions\n ] = None,\n)" + exceptions: + - description: If any errors happen. + var_type: google.auth.exceptions.MutualTLSChannelError + parameters: + - defaultValue: None + description: Custom options for the client. Only the api_endpoint + and client_cert_source properties may be used in this method. + id: client_options + var_type: google.api_core.client_options.ClientOptions + returns: + - description: returns the API endpoint and the client cert source to use. + var_type: Tuple[str, Callable[[], Tuple[bytes, bytes]]] + type: method + uid: google.cloud.pubsub_v1.publisher.client.Client.get_mtls_endpoint_and_cert_source +- attributes: [] + class: google.cloud.pubsub_v1.publisher.client.Client + fullName: google.cloud.pubsub_v1.publisher.client.Client.get_topic + langs: + - python + module: google.cloud.pubsub_v1.publisher.client + name: get_topic + source: + id: get_topic + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 791 + summary: "Gets the configuration of a topic.\n\n```python\n# This snippet has been\ + \ automatically generated and should be regarded as a\n# code template only.\n\ + # It will require modifications to work:\n# - It may require correct/in-range\ + \ values for request initialization.\n# - It may require specifying regional endpoints\ + \ when creating the service\n# client as shown in:\n# https://googleapis.dev/python/google-api-core/latest/client_options.html\n\ + from google import pubsub_v1\n\ndef sample_get_topic():\n # Create a client\n\ + \ client = pubsub_v1.PublisherClient()\n\n # Initialize request argument(s)\n\ + \ request = pubsub_v1.GetTopicRequest(\n topic=\"topic_value\",\n \ + \ )\n\n # Make the request\n response = client.get_topic(request=request)\n\ + \n # Handle the response\n print(response)\n```\n" + syntax: + content: "get_topic(\n request: typing.Union[google.cloud.pubsub_v1.types.GetTopicRequest,\ + \ dict] = None,\n *,\n topic: str = None,\n retry: typing.Union[\n\ + \ google.api_core.retry.Retry, google.api_core.gapic_v1.method._MethodDefault\n\ + \ ] = _MethodDefault._DEFAULT_VALUE,\n timeout: typing.Union[\n \ + \ int,\n float,\n google.api_core.timeout.ConstantTimeout,\n\ + \ google.api_core.timeout.ExponentialTimeout,\n ] = _MethodDefault._DEFAULT_VALUE,\n\ + \ metadata: typing.Sequence[typing.Tuple[str, str]] = ()\n)" + parameters: + - defaultValue: None + description: The request object. Request for the GetTopic method. + id: request + var_type: Union[google.pubsub_v1.types.GetTopicRequest, dict] + - description: Required. The name of the topic to get. Format is projects/{project}/topics/{topic}. + This corresponds to the topic field on the request + instance; if request is provided, this should not be set. + id: topic + var_type: str + - description: Designation of what errors, if any, should be retried. + id: retry + var_type: google.api_core.retry.Retry + - description: The timeout for this request. + id: timeout + var_type: TimeoutType + - description: Strings which should be sent along with the request as metadata. + id: metadata + var_type: Sequence[Tuple[str, str]] + returns: + - description: A topic resource. + var_type: google.pubsub_v1.types.Topic + type: method + uid: google.cloud.pubsub_v1.publisher.client.Client.get_topic +- attributes: [] + class: google.cloud.pubsub_v1.publisher.client.Client + fullName: google.cloud.pubsub_v1.publisher.client.Client.list_topic_snapshots + langs: + - python + module: google.cloud.pubsub_v1.publisher.client + name: list_topic_snapshots + source: + id: list_topic_snapshots + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 1122 + summary: "Lists the names of the snapshots on this topic. Snapshots are\nused in\n\ + `Seek `__\noperations, which\ + \ allow you to manage message acknowledgments in\nbulk. That is, you can set the\ + \ acknowledgment state of messages\nin an existing subscription to the state captured\ + \ by a snapshot.\n\n```python\n# This snippet has been automatically generated\ + \ and should be regarded as a\n# code template only.\n# It will require modifications\ + \ to work:\n# - It may require correct/in-range values for request initialization.\n\ + # - It may require specifying regional endpoints when creating the service\n#\ + \ client as shown in:\n# https://googleapis.dev/python/google-api-core/latest/client_options.html\n\ + from google import pubsub_v1\n\ndef sample_list_topic_snapshots():\n # Create\ + \ a client\n client = pubsub_v1.PublisherClient()\n\n # Initialize request\ + \ argument(s)\n request = pubsub_v1.ListTopicSnapshotsRequest(\n topic=\"\ + topic_value\",\n )\n\n # Make the request\n page_result = client.list_topic_snapshots(request=request)\n\ + \n # Handle the response\n for response in page_result:\n print(response)\n\ + ```\n" + syntax: + content: "list_topic_snapshots(\n request: typing.Union[\n google.cloud.pubsub_v1.types.ListTopicSnapshotsRequest,\ + \ dict\n ] = None,\n *,\n topic: str = None,\n retry: typing.Union[\n\ + \ google.api_core.retry.Retry, google.api_core.gapic_v1.method._MethodDefault\n\ + \ ] = _MethodDefault._DEFAULT_VALUE,\n timeout: typing.Union[\n \ + \ int,\n float,\n google.api_core.timeout.ConstantTimeout,\n\ + \ google.api_core.timeout.ExponentialTimeout,\n ] = _MethodDefault._DEFAULT_VALUE,\n\ + \ metadata: typing.Sequence[typing.Tuple[str, str]] = ()\n)" + parameters: + - defaultValue: None + description: The request object. Request for the ListTopicSnapshots + method. + id: request + var_type: Union[google.pubsub_v1.types.ListTopicSnapshotsRequest, dict] + - description: Required. The name of the topic that snapshots are attached to. + Format is projects/{project}/topics/{topic}. This corresponds + to the topic field on the request instance; if request + is provided, this should not be set. + id: topic + var_type: str + - description: Designation of what errors, if any, should be retried. + id: retry + var_type: google.api_core.retry.Retry + - description: The timeout for this request. + id: timeout + var_type: TimeoutType + - description: Strings which should be sent along with the request as metadata. + id: metadata + var_type: Sequence[Tuple[str, str]] + returns: + - description: Response for the ListTopicSnapshots method. Iterating over this + object will yield results and resolve additional pages automatically. + var_type: google.pubsub_v1.services.publisher.pagers.ListTopicSnapshotsPager + type: method + uid: google.cloud.pubsub_v1.publisher.client.Client.list_topic_snapshots +- attributes: [] + class: google.cloud.pubsub_v1.publisher.client.Client + fullName: google.cloud.pubsub_v1.publisher.client.Client.list_topic_subscriptions + langs: + - python + module: google.cloud.pubsub_v1.publisher.client + name: list_topic_subscriptions + source: + id: list_topic_subscriptions + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 1005 + summary: "Lists the names of the attached subscriptions on this\ntopic.\n\n```python\n\ + # This snippet has been automatically generated and should be regarded as a\n\ + # code template only.\n# It will require modifications to work:\n# - It may require\ + \ correct/in-range values for request initialization.\n# - It may require specifying\ + \ regional endpoints when creating the service\n# client as shown in:\n# https://googleapis.dev/python/google-api-core/latest/client_options.html\n\ + from google import pubsub_v1\n\ndef sample_list_topic_subscriptions():\n #\ + \ Create a client\n client = pubsub_v1.PublisherClient()\n\n # Initialize\ + \ request argument(s)\n request = pubsub_v1.ListTopicSubscriptionsRequest(\n\ + \ topic=\"topic_value\",\n )\n\n # Make the request\n page_result\ + \ = client.list_topic_subscriptions(request=request)\n\n # Handle the response\n\ + \ for response in page_result:\n print(response)\n```\n" + syntax: + content: "list_topic_subscriptions(\n request: typing.Union[\n google.cloud.pubsub_v1.types.ListTopicSubscriptionsRequest,\ + \ dict\n ] = None,\n *,\n topic: str = None,\n retry: typing.Union[\n\ + \ google.api_core.retry.Retry, google.api_core.gapic_v1.method._MethodDefault\n\ + \ ] = _MethodDefault._DEFAULT_VALUE,\n timeout: typing.Union[\n \ + \ int,\n float,\n google.api_core.timeout.ConstantTimeout,\n\ + \ google.api_core.timeout.ExponentialTimeout,\n ] = _MethodDefault._DEFAULT_VALUE,\n\ + \ metadata: typing.Sequence[typing.Tuple[str, str]] = ()\n)" + parameters: + - defaultValue: None + description: The request object. Request for the ListTopicSubscriptions + method. + id: request + var_type: Union[google.pubsub_v1.types.ListTopicSubscriptionsRequest, dict] + - description: Required. The name of the topic that subscriptions are attached + to. Format is projects/{project}/topics/{topic}. This corresponds + to the topic field on the request instance; if request + is provided, this should not be set. + id: topic + var_type: str + - description: Designation of what errors, if any, should be retried. + id: retry + var_type: google.api_core.retry.Retry + - description: The timeout for this request. + id: timeout + var_type: TimeoutType + - description: Strings which should be sent along with the request as metadata. + id: metadata + var_type: Sequence[Tuple[str, str]] + returns: + - description: Response for the ListTopicSubscriptions method. Iterating over + this object will yield results and resolve additional pages automatically. + var_type: google.pubsub_v1.services.publisher.pagers.ListTopicSubscriptionsPager + type: method + uid: google.cloud.pubsub_v1.publisher.client.Client.list_topic_subscriptions +- attributes: [] + class: google.cloud.pubsub_v1.publisher.client.Client + fullName: google.cloud.pubsub_v1.publisher.client.Client.list_topics + langs: + - python + module: google.cloud.pubsub_v1.publisher.client + name: list_topics + source: + id: list_topics + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 891 + summary: "Lists matching topics.\n\n```python\n# This snippet has been automatically\ + \ generated and should be regarded as a\n# code template only.\n# It will require\ + \ modifications to work:\n# - It may require correct/in-range values for request\ + \ initialization.\n# - It may require specifying regional endpoints when creating\ + \ the service\n# client as shown in:\n# https://googleapis.dev/python/google-api-core/latest/client_options.html\n\ + from google import pubsub_v1\n\ndef sample_list_topics():\n # Create a client\n\ + \ client = pubsub_v1.PublisherClient()\n\n # Initialize request argument(s)\n\ + \ request = pubsub_v1.ListTopicsRequest(\n project=\"project_value\"\ + ,\n )\n\n # Make the request\n page_result = client.list_topics(request=request)\n\ + \n # Handle the response\n for response in page_result:\n print(response)\n\ + ```\n" + syntax: + content: "list_topics(\n request: typing.Union[google.cloud.pubsub_v1.types.ListTopicsRequest,\ + \ dict] = None,\n *,\n project: str = None,\n retry: typing.Union[\n\ + \ google.api_core.retry.Retry, google.api_core.gapic_v1.method._MethodDefault\n\ + \ ] = _MethodDefault._DEFAULT_VALUE,\n timeout: typing.Union[\n \ + \ int,\n float,\n google.api_core.timeout.ConstantTimeout,\n\ + \ google.api_core.timeout.ExponentialTimeout,\n ] = _MethodDefault._DEFAULT_VALUE,\n\ + \ metadata: typing.Sequence[typing.Tuple[str, str]] = ()\n)" + parameters: + - defaultValue: None + description: The request object. Request for the ListTopics method. + id: request + var_type: Union[google.pubsub_v1.types.ListTopicsRequest, dict] + - description: Required. The name of the project in which to list topics. Format + is projects/{project-id}. This corresponds to the project + field on the request instance; if request is provided, + this should not be set. + id: project + var_type: str + - description: Designation of what errors, if any, should be retried. + id: retry + var_type: google.api_core.retry.Retry + - description: The timeout for this request. + id: timeout + var_type: TimeoutType + - description: Strings which should be sent along with the request as metadata. + id: metadata + var_type: Sequence[Tuple[str, str]] + returns: + - description: Response for the ListTopics method. Iterating over this object + will yield results and resolve additional pages automatically. + var_type: google.pubsub_v1.services.publisher.pagers.ListTopicsPager + type: method + uid: google.cloud.pubsub_v1.publisher.client.Client.list_topics +- attributes: [] + class: google.cloud.pubsub_v1.publisher.client.Client + fullName: google.cloud.pubsub_v1.publisher.client.Client.parse_common_billing_account_path + langs: + - python + module: google.cloud.pubsub_v1.publisher.client + name: parse_common_billing_account_path + source: + id: parse_common_billing_account_path + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 245 + summary: 'Parse a billing_account path into its component segments. + + + ' + syntax: + content: 'parse_common_billing_account_path(path: str)' + parameters: [] + type: method + uid: google.cloud.pubsub_v1.publisher.client.Client.parse_common_billing_account_path +- attributes: [] + class: google.cloud.pubsub_v1.publisher.client.Client + fullName: google.cloud.pubsub_v1.publisher.client.Client.parse_common_folder_path + langs: + - python + module: google.cloud.pubsub_v1.publisher.client + name: parse_common_folder_path + source: + id: parse_common_folder_path + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 260 + summary: 'Parse a folder path into its component segments. + + + ' + syntax: + content: 'parse_common_folder_path(path: str)' + parameters: [] + type: method + uid: google.cloud.pubsub_v1.publisher.client.Client.parse_common_folder_path +- attributes: [] + class: google.cloud.pubsub_v1.publisher.client.Client + fullName: google.cloud.pubsub_v1.publisher.client.Client.parse_common_location_path + langs: + - python + module: google.cloud.pubsub_v1.publisher.client + name: parse_common_location_path + source: + id: parse_common_location_path + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 307 + summary: 'Parse a location path into its component segments. + + + ' + syntax: + content: 'parse_common_location_path(path: str)' + parameters: [] + type: method + uid: google.cloud.pubsub_v1.publisher.client.Client.parse_common_location_path +- attributes: [] + class: google.cloud.pubsub_v1.publisher.client.Client + fullName: google.cloud.pubsub_v1.publisher.client.Client.parse_common_organization_path + langs: + - python + module: google.cloud.pubsub_v1.publisher.client + name: parse_common_organization_path + source: + id: parse_common_organization_path + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 275 + summary: 'Parse a organization path into its component segments. + + + ' + syntax: + content: 'parse_common_organization_path(path: str)' + parameters: [] + type: method + uid: google.cloud.pubsub_v1.publisher.client.Client.parse_common_organization_path +- attributes: [] + class: google.cloud.pubsub_v1.publisher.client.Client + fullName: google.cloud.pubsub_v1.publisher.client.Client.parse_common_project_path + langs: + - python + module: google.cloud.pubsub_v1.publisher.client + name: parse_common_project_path + source: + id: parse_common_project_path + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 290 + summary: 'Parse a project path into its component segments. + + + ' + syntax: + content: 'parse_common_project_path(path: str)' + parameters: [] + type: method + uid: google.cloud.pubsub_v1.publisher.client.Client.parse_common_project_path +- attributes: [] + class: google.cloud.pubsub_v1.publisher.client.Client + fullName: google.cloud.pubsub_v1.publisher.client.Client.parse_schema_path + langs: + - python + module: google.cloud.pubsub_v1.publisher.client + name: parse_schema_path + source: + id: parse_schema_path + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 194 + summary: 'Parses a schema path into its component segments. + + + ' + syntax: + content: 'parse_schema_path(path: str)' + parameters: [] + type: method + uid: google.cloud.pubsub_v1.publisher.client.Client.parse_schema_path +- attributes: [] + class: google.cloud.pubsub_v1.publisher.client.Client + fullName: google.cloud.pubsub_v1.publisher.client.Client.parse_subscription_path + langs: + - python + module: google.cloud.pubsub_v1.publisher.client + name: parse_subscription_path + source: + id: parse_subscription_path + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 211 + summary: 'Parses a subscription path into its component segments. + + + ' + syntax: + content: 'parse_subscription_path(path: str)' + parameters: [] + type: method + uid: google.cloud.pubsub_v1.publisher.client.Client.parse_subscription_path +- attributes: [] + class: google.cloud.pubsub_v1.publisher.client.Client + fullName: google.cloud.pubsub_v1.publisher.client.Client.parse_topic_path + langs: + - python + module: google.cloud.pubsub_v1.publisher.client + name: parse_topic_path + source: + id: parse_topic_path + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 230 + summary: 'Parses a topic path into its component segments. + + + ' + syntax: + content: 'parse_topic_path(path: str)' + parameters: [] + type: method + uid: google.cloud.pubsub_v1.publisher.client.Client.parse_topic_path +- attributes: [] + class: google.cloud.pubsub_v1.publisher.client.Client + fullName: google.cloud.pubsub_v1.publisher.client.Client.publish + langs: + - python + module: google.cloud.pubsub_v1.publisher.client + name: publish + source: + id: publish + path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 274 + summary: "Publish a single message.\n\n\n The reason that\ + \ this is so important (and why we do not try to\n coerce for you) is because\ + \ Pub/Sub is also platform independent\n and there is no way to know how to\ + \ decode messages properly on\n the other side; therefore, encoding and decoding\ + \ is a required\n exercise for the developer.\n\nAdd the given message to this\ + \ object; this will cause it to be\npublished once the batch either has enough\ + \ messages or a sufficient\nperiod of time has elapsed.\nThis method may block\ + \ if LimitExceededBehavior.BLOCK is used in the\nflow control settings.\n\n..\ + \ rubric:: Example\n\n>>> from google.cloud import pubsub_v1\n>>> client = pubsub_v1.PublisherClient()\n\ + >>> topic = client.topic_path('[PROJECT]', '[TOPIC]')\n>>> data = b'The rain in\ + \ Wales falls mainly on the snails.'\n>>> response = client.publish(topic, data,\ + \ username='guido')\n" + syntax: + content: "publish(\n topic: str,\n data: bytes,\n ordering_key: str =\ + \ \"\",\n retry: OptionalRetry = _MethodDefault._DEFAULT_VALUE,\n timeout:\ + \ types.OptionalTimeout = _MethodDefault._DEFAULT_VALUE,\n **attrs: typing.Union[bytes,\ + \ str]\n)" + exceptions: + - description: If called after publisher has been stopped by a stop() + method call. + var_type: RuntimeError + - description: If publishing the message would exceed the max size + limit on the backend. + var_type: pubsub_v1.publisher.exceptions.MessageTooLargeError + parameters: [] + type: method + uid: google.cloud.pubsub_v1.publisher.client.Client.publish +- attributes: [] + class: google.cloud.pubsub_v1.publisher.client.Client + fullName: google.cloud.pubsub_v1.publisher.client.Client.resume_publish + langs: + - python + module: google.cloud.pubsub_v1.publisher.client + name: resume_publish + source: + id: resume_publish + path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 234 + summary: 'Resume publish on an ordering key that has had unrecoverable errors. + + ' + syntax: + content: 'resume_publish(topic: str, ordering_key: str)' + exceptions: + - description: If called after publisher has been stopped by a stop() + method call. + var_type: RuntimeError + - description: If the topic/ordering key combination has not been seen before + by this client. + var_type: ValueError + parameters: [] + type: method + uid: google.cloud.pubsub_v1.publisher.client.Client.resume_publish +- attributes: [] + class: google.cloud.pubsub_v1.publisher.client.Client + fullName: google.cloud.pubsub_v1.publisher.client.Client.schema_path + langs: + - python + module: google.cloud.pubsub_v1.publisher.client + name: schema_path + source: + id: schema_path + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 183 + summary: 'Returns a fully-qualified schema string. + + + ' + syntax: + content: 'schema_path(project: str, schema: str)' + parameters: [] + type: method + uid: google.cloud.pubsub_v1.publisher.client.Client.schema_path +- attributes: [] + class: google.cloud.pubsub_v1.publisher.client.Client + fullName: google.cloud.pubsub_v1.publisher.client.Client.set_iam_policy + langs: + - python + module: google.cloud.pubsub_v1.publisher.client + name: set_iam_policy + source: + id: set_iam_policy + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 1440 + summary: 'Sets the IAM access control policy on the specified function. + + + Replaces any existing policy. + + ' + syntax: + content: "set_iam_policy(\n request: google.iam.v1.iam_policy_pb2.SetIamPolicyRequest\ + \ = None,\n *,\n retry: typing.Union[\n google.api_core.retry.Retry,\ + \ google.api_core.gapic_v1.method._MethodDefault\n ] = _MethodDefault._DEFAULT_VALUE,\n\ + \ timeout: typing.Union[\n int,\n float,\n google.api_core.timeout.ConstantTimeout,\n\ + \ google.api_core.timeout.ExponentialTimeout,\n ] = _MethodDefault._DEFAULT_VALUE,\n\ + \ metadata: typing.Sequence[typing.Tuple[str, str]] = ()\n)" + parameters: + - defaultValue: None + description: The request object. Request message for SetIamPolicy + method. + id: request + var_type: .iam_policy_pb2.SetIamPolicyRequest + - description: Designation of what errors, if any, should be retried. + id: retry + var_type: google.api_core.retry.Retry + - description: The timeout for this request. + id: timeout + var_type: TimeoutType + - description: Strings which should be sent along with the request as metadata. + id: metadata + var_type: Sequence[Tuple[str, str]] + returns: + - description: 'Defines an Identity and Access Management (IAM) policy. It is + used to specify access control policies for Cloud Platform resources. A Policy + is a collection of bindings. A binding binds one + or more members to a single role. Members can be + user accounts, service accounts, Google groups, and domains (such as G Suite). + A role is a named list of permissions (defined by IAM or configured + by users). A binding can optionally specify a condition, + which is a logic expression that further constrains the role binding based + on attributes about the request and/or target resource. **JSON Example** :: + { "bindings": [ { "role": "roles/resourcemanager.organizationAdmin", "members": + [ "user:mike@example.com", "group:admins@example.com", "domain:google.com", + "serviceAccount:my-project-id@appspot.gserviceaccount.com" ] }, { "role": + "roles/resourcemanager.organizationViewer", "members": ["user:eve@example.com"], + "condition": { "title": "expirable access", "description": "Does not grant + access after Sep 2020", "expression": "request.time < timestamp(''2020-10-01T00:00:00.000Z'')", + } } ] } **YAML Example** :: bindings: - members: - user:mike@example.com - + group:admins@example.com - domain:google.com - serviceAccount:my-project-id@appspot.gserviceaccount.com + role: roles/resourcemanager.organizationAdmin - members: - user:eve@example.com + role: roles/resourcemanager.organizationViewer condition: title: expirable + access description: Does not grant access after Sep 2020 expression: request.time + < timestamp(''2020-10-01T00:00:00.000Z'') For a description of IAM and its + features, see the IAM developer''s guide __.' + var_type: .policy_pb2.Policy + type: method + uid: google.cloud.pubsub_v1.publisher.client.Client.set_iam_policy +- attributes: [] + class: google.cloud.pubsub_v1.publisher.client.Client + fullName: google.cloud.pubsub_v1.publisher.client.Client.stop + langs: + - python + module: google.cloud.pubsub_v1.publisher.client + name: stop + source: + id: stop + path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 475 + summary: 'Immediately publish all outstanding messages. + + + Asynchronously sends all outstanding messages and + + prevents future calls to `publish()`. Method should + + be invoked prior to deleting this `Client()` object + + in order to ensure that no pending messages are lost. + + + ' + syntax: + content: stop() + exceptions: + - description: If called after publisher has been stopped by a stop() + method call. + var_type: RuntimeError + parameters: [] + type: method + uid: google.cloud.pubsub_v1.publisher.client.Client.stop +- attributes: [] + class: google.cloud.pubsub_v1.publisher.client.Client + fullName: google.cloud.pubsub_v1.publisher.client.Client.subscription_path + langs: + - python + module: google.cloud.pubsub_v1.publisher.client + name: subscription_path + source: + id: subscription_path + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 200 + summary: 'Returns a fully-qualified subscription string. + + + ' + syntax: + content: 'subscription_path(project: str, subscription: str)' + parameters: [] + type: method + uid: google.cloud.pubsub_v1.publisher.client.Client.subscription_path +- &id002 + attributes: [] + class: google.cloud.pubsub_v1.publisher.client.Client + fullName: google.cloud.pubsub_v1.publisher.client.Client.target + langs: + - python + module: google.cloud.pubsub_v1.publisher.client + name: target + source: + id: target + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Return the target (where the API is). + + ' + syntax: {} + type: property + uid: google.cloud.pubsub_v1.publisher.client.Client.target +- *id002 +- attributes: [] + class: google.cloud.pubsub_v1.publisher.client.Client + fullName: google.cloud.pubsub_v1.publisher.client.Client.test_iam_permissions + langs: + - python + module: google.cloud.pubsub_v1.publisher.client + name: test_iam_permissions + source: + id: test_iam_permissions + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 1683 + summary: "Tests the specified IAM permissions against the IAM access control\n \ + \ policy for a function.\n\nIf the function does not exist, this will return\ + \ an empty set\nof permissions, not a NOT_FOUND error.\n" + syntax: + content: "test_iam_permissions(\n request: google.iam.v1.iam_policy_pb2.TestIamPermissionsRequest\ + \ = None,\n *,\n retry: typing.Union[\n google.api_core.retry.Retry,\ + \ google.api_core.gapic_v1.method._MethodDefault\n ] = _MethodDefault._DEFAULT_VALUE,\n\ + \ timeout: typing.Union[\n int,\n float,\n google.api_core.timeout.ConstantTimeout,\n\ + \ google.api_core.timeout.ExponentialTimeout,\n ] = _MethodDefault._DEFAULT_VALUE,\n\ + \ metadata: typing.Sequence[typing.Tuple[str, str]] = ()\n)" + parameters: + - defaultValue: None + description: The request object. Request message for TestIamPermissions + method. + id: request + var_type: .iam_policy_pb2.TestIamPermissionsRequest + - description: Designation of what errors, if any, should be retried. + id: retry + var_type: google.api_core.retry.Retry + - description: The timeout for this request. + id: timeout + var_type: TimeoutType + - description: Strings which should be sent along with the request as metadata. + id: metadata + var_type: Sequence[Tuple[str, str]] + returns: + - description: Response message for TestIamPermissions method. + var_type: .iam_policy_pb2.TestIamPermissionsResponse + type: method + uid: google.cloud.pubsub_v1.publisher.client.Client.test_iam_permissions +- attributes: [] + class: google.cloud.pubsub_v1.publisher.client.Client + fullName: google.cloud.pubsub_v1.publisher.client.Client.topic_path + langs: + - python + module: google.cloud.pubsub_v1.publisher.client + name: topic_path + source: + id: topic_path + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 219 + summary: 'Returns a fully-qualified topic string. + + + ' + syntax: + content: 'topic_path(project: str, topic: str)' + parameters: [] + type: method + uid: google.cloud.pubsub_v1.publisher.client.Client.topic_path +- &id003 + attributes: [] + class: google.cloud.pubsub_v1.publisher.client.Client + fullName: google.cloud.pubsub_v1.publisher.client.Client.transport + langs: + - python + module: google.cloud.pubsub_v1.publisher.client + name: transport + source: + id: transport + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Returns the transport used by the client instance. + + ' + syntax: + returns: + - description: The transport used by the client instance. + var_type: PublisherTransport + type: property + uid: google.cloud.pubsub_v1.publisher.client.Client.transport +- *id003 +- attributes: [] + class: google.cloud.pubsub_v1.publisher.client.Client + fullName: google.cloud.pubsub_v1.publisher.client.Client.update_topic + langs: + - python + module: google.cloud.pubsub_v1.publisher.client + name: update_topic + source: + id: update_topic + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 596 + summary: "Updates an existing topic. Note that certain\nproperties of a topic are\ + \ not modifiable.\n\n```python\n# This snippet has been automatically generated\ + \ and should be regarded as a\n# code template only.\n# It will require modifications\ + \ to work:\n# - It may require correct/in-range values for request initialization.\n\ + # - It may require specifying regional endpoints when creating the service\n#\ + \ client as shown in:\n# https://googleapis.dev/python/google-api-core/latest/client_options.html\n\ + from google import pubsub_v1\n\ndef sample_update_topic():\n # Create a client\n\ + \ client = pubsub_v1.PublisherClient()\n\n # Initialize request argument(s)\n\ + \ topic = pubsub_v1.Topic()\n topic.name = \"name_value\"\n\n request\ + \ = pubsub_v1.UpdateTopicRequest(\n topic=topic,\n )\n\n # Make the\ + \ request\n response = client.update_topic(request=request)\n\n # Handle\ + \ the response\n print(response)\n```\n" + syntax: + content: "update_topic(\n request: typing.Union[google.cloud.pubsub_v1.types.UpdateTopicRequest,\ + \ dict] = None,\n *,\n retry: typing.Union[\n google.api_core.retry.Retry,\ + \ google.api_core.gapic_v1.method._MethodDefault\n ] = _MethodDefault._DEFAULT_VALUE,\n\ + \ timeout: typing.Union[\n int,\n float,\n google.api_core.timeout.ConstantTimeout,\n\ + \ google.api_core.timeout.ExponentialTimeout,\n ] = _MethodDefault._DEFAULT_VALUE,\n\ + \ metadata: typing.Sequence[typing.Tuple[str, str]] = ()\n)" + parameters: + - defaultValue: None + description: The request object. Request for the UpdateTopic method. + id: request + var_type: Union[google.pubsub_v1.types.UpdateTopicRequest, dict] + - description: Designation of what errors, if any, should be retried. + id: retry + var_type: google.api_core.retry.Retry + - description: The timeout for this request. + id: timeout + var_type: TimeoutType + - description: Strings which should be sent along with the request as metadata. + id: metadata + var_type: Sequence[Tuple[str, str]] + returns: + - description: A topic resource. + var_type: google.pubsub_v1.types.Topic + type: method + uid: google.cloud.pubsub_v1.publisher.client.Client.update_topic +references: +- fullName: google.cloud.pubsub_v1.publisher.client.Client + isExternal: false + name: Client + parent: google.cloud.pubsub_v1.publisher.client.Client + uid: google.cloud.pubsub_v1.publisher.client.Client +- fullName: google.cloud.pubsub_v1.publisher.client.Client.__exit__ + isExternal: false + name: __exit__ + parent: google.cloud.pubsub_v1.publisher.client.Client + uid: google.cloud.pubsub_v1.publisher.client.Client.__exit__ +- fullName: google.cloud.pubsub_v1.publisher.client.Client.api + isExternal: false + name: api + parent: google.cloud.pubsub_v1.publisher.client.Client + uid: google.cloud.pubsub_v1.publisher.client.Client.api +- fullName: google.cloud.pubsub_v1.publisher.client.Client.common_billing_account_path + isExternal: false + name: common_billing_account_path + parent: google.cloud.pubsub_v1.publisher.client.Client + uid: google.cloud.pubsub_v1.publisher.client.Client.common_billing_account_path +- fullName: google.cloud.pubsub_v1.publisher.client.Client.common_folder_path + isExternal: false + name: common_folder_path + parent: google.cloud.pubsub_v1.publisher.client.Client + uid: google.cloud.pubsub_v1.publisher.client.Client.common_folder_path +- fullName: google.cloud.pubsub_v1.publisher.client.Client.common_location_path + isExternal: false + name: common_location_path + parent: google.cloud.pubsub_v1.publisher.client.Client + uid: google.cloud.pubsub_v1.publisher.client.Client.common_location_path +- fullName: google.cloud.pubsub_v1.publisher.client.Client.common_organization_path + isExternal: false + name: common_organization_path + parent: google.cloud.pubsub_v1.publisher.client.Client + uid: google.cloud.pubsub_v1.publisher.client.Client.common_organization_path +- fullName: google.cloud.pubsub_v1.publisher.client.Client.common_project_path + isExternal: false + name: common_project_path + parent: google.cloud.pubsub_v1.publisher.client.Client + uid: google.cloud.pubsub_v1.publisher.client.Client.common_project_path +- fullName: google.cloud.pubsub_v1.publisher.client.Client.create_topic + isExternal: false + name: create_topic + parent: google.cloud.pubsub_v1.publisher.client.Client + uid: google.cloud.pubsub_v1.publisher.client.Client.create_topic +- fullName: google.cloud.pubsub_v1.publisher.client.Client.delete_topic + isExternal: false + name: delete_topic + parent: google.cloud.pubsub_v1.publisher.client.Client + uid: google.cloud.pubsub_v1.publisher.client.Client.delete_topic +- fullName: google.cloud.pubsub_v1.publisher.client.Client.detach_subscription + isExternal: false + name: detach_subscription + parent: google.cloud.pubsub_v1.publisher.client.Client + uid: google.cloud.pubsub_v1.publisher.client.Client.detach_subscription +- fullName: google.cloud.pubsub_v1.publisher.client.Client.ensure_cleanup_and_commit_timer_runs + isExternal: false + name: ensure_cleanup_and_commit_timer_runs + parent: google.cloud.pubsub_v1.publisher.client.Client + uid: google.cloud.pubsub_v1.publisher.client.Client.ensure_cleanup_and_commit_timer_runs +- fullName: google.cloud.pubsub_v1.publisher.client.Client.from_service_account_file + isExternal: false + name: from_service_account_file + parent: google.cloud.pubsub_v1.publisher.client.Client + uid: google.cloud.pubsub_v1.publisher.client.Client.from_service_account_file +- fullName: google.cloud.pubsub_v1.publisher.client.Client.from_service_account_info + isExternal: false + name: from_service_account_info + parent: google.cloud.pubsub_v1.publisher.client.Client + uid: google.cloud.pubsub_v1.publisher.client.Client.from_service_account_info +- fullName: google.cloud.pubsub_v1.publisher.client.Client.from_service_account_json + isExternal: false + name: from_service_account_json + parent: google.cloud.pubsub_v1.publisher.client.Client + uid: google.cloud.pubsub_v1.publisher.client.Client.from_service_account_json +- fullName: google.cloud.pubsub_v1.publisher.client.Client.get_iam_policy + isExternal: false + name: get_iam_policy + parent: google.cloud.pubsub_v1.publisher.client.Client + uid: google.cloud.pubsub_v1.publisher.client.Client.get_iam_policy +- fullName: google.cloud.pubsub_v1.publisher.client.Client.get_mtls_endpoint_and_cert_source + isExternal: false + name: get_mtls_endpoint_and_cert_source + parent: google.cloud.pubsub_v1.publisher.client.Client + uid: google.cloud.pubsub_v1.publisher.client.Client.get_mtls_endpoint_and_cert_source +- fullName: google.cloud.pubsub_v1.publisher.client.Client.get_topic + isExternal: false + name: get_topic + parent: google.cloud.pubsub_v1.publisher.client.Client + uid: google.cloud.pubsub_v1.publisher.client.Client.get_topic +- fullName: google.cloud.pubsub_v1.publisher.client.Client.list_topic_snapshots + isExternal: false + name: list_topic_snapshots + parent: google.cloud.pubsub_v1.publisher.client.Client + uid: google.cloud.pubsub_v1.publisher.client.Client.list_topic_snapshots +- fullName: google.cloud.pubsub_v1.publisher.client.Client.list_topic_subscriptions + isExternal: false + name: list_topic_subscriptions + parent: google.cloud.pubsub_v1.publisher.client.Client + uid: google.cloud.pubsub_v1.publisher.client.Client.list_topic_subscriptions +- fullName: google.cloud.pubsub_v1.publisher.client.Client.list_topics + isExternal: false + name: list_topics + parent: google.cloud.pubsub_v1.publisher.client.Client + uid: google.cloud.pubsub_v1.publisher.client.Client.list_topics +- fullName: google.cloud.pubsub_v1.publisher.client.Client.parse_common_billing_account_path + isExternal: false + name: parse_common_billing_account_path + parent: google.cloud.pubsub_v1.publisher.client.Client + uid: google.cloud.pubsub_v1.publisher.client.Client.parse_common_billing_account_path +- fullName: google.cloud.pubsub_v1.publisher.client.Client.parse_common_folder_path + isExternal: false + name: parse_common_folder_path + parent: google.cloud.pubsub_v1.publisher.client.Client + uid: google.cloud.pubsub_v1.publisher.client.Client.parse_common_folder_path +- fullName: google.cloud.pubsub_v1.publisher.client.Client.parse_common_location_path + isExternal: false + name: parse_common_location_path + parent: google.cloud.pubsub_v1.publisher.client.Client + uid: google.cloud.pubsub_v1.publisher.client.Client.parse_common_location_path +- fullName: google.cloud.pubsub_v1.publisher.client.Client.parse_common_organization_path + isExternal: false + name: parse_common_organization_path + parent: google.cloud.pubsub_v1.publisher.client.Client + uid: google.cloud.pubsub_v1.publisher.client.Client.parse_common_organization_path +- fullName: google.cloud.pubsub_v1.publisher.client.Client.parse_common_project_path + isExternal: false + name: parse_common_project_path + parent: google.cloud.pubsub_v1.publisher.client.Client + uid: google.cloud.pubsub_v1.publisher.client.Client.parse_common_project_path +- fullName: google.cloud.pubsub_v1.publisher.client.Client.parse_schema_path + isExternal: false + name: parse_schema_path + parent: google.cloud.pubsub_v1.publisher.client.Client + uid: google.cloud.pubsub_v1.publisher.client.Client.parse_schema_path +- fullName: google.cloud.pubsub_v1.publisher.client.Client.parse_subscription_path + isExternal: false + name: parse_subscription_path + parent: google.cloud.pubsub_v1.publisher.client.Client + uid: google.cloud.pubsub_v1.publisher.client.Client.parse_subscription_path +- fullName: google.cloud.pubsub_v1.publisher.client.Client.parse_topic_path + isExternal: false + name: parse_topic_path + parent: google.cloud.pubsub_v1.publisher.client.Client + uid: google.cloud.pubsub_v1.publisher.client.Client.parse_topic_path +- fullName: google.cloud.pubsub_v1.publisher.client.Client.publish + isExternal: false + name: publish + parent: google.cloud.pubsub_v1.publisher.client.Client + uid: google.cloud.pubsub_v1.publisher.client.Client.publish +- fullName: google.cloud.pubsub_v1.publisher.client.Client.resume_publish + isExternal: false + name: resume_publish + parent: google.cloud.pubsub_v1.publisher.client.Client + uid: google.cloud.pubsub_v1.publisher.client.Client.resume_publish +- fullName: google.cloud.pubsub_v1.publisher.client.Client.schema_path + isExternal: false + name: schema_path + parent: google.cloud.pubsub_v1.publisher.client.Client + uid: google.cloud.pubsub_v1.publisher.client.Client.schema_path +- fullName: google.cloud.pubsub_v1.publisher.client.Client.set_iam_policy + isExternal: false + name: set_iam_policy + parent: google.cloud.pubsub_v1.publisher.client.Client + uid: google.cloud.pubsub_v1.publisher.client.Client.set_iam_policy +- fullName: google.cloud.pubsub_v1.publisher.client.Client.stop + isExternal: false + name: stop + parent: google.cloud.pubsub_v1.publisher.client.Client + uid: google.cloud.pubsub_v1.publisher.client.Client.stop +- fullName: google.cloud.pubsub_v1.publisher.client.Client.subscription_path + isExternal: false + name: subscription_path + parent: google.cloud.pubsub_v1.publisher.client.Client + uid: google.cloud.pubsub_v1.publisher.client.Client.subscription_path +- fullName: google.cloud.pubsub_v1.publisher.client.Client.target + isExternal: false + name: target + parent: google.cloud.pubsub_v1.publisher.client.Client + uid: google.cloud.pubsub_v1.publisher.client.Client.target +- fullName: google.cloud.pubsub_v1.publisher.client.Client.test_iam_permissions + isExternal: false + name: test_iam_permissions + parent: google.cloud.pubsub_v1.publisher.client.Client + uid: google.cloud.pubsub_v1.publisher.client.Client.test_iam_permissions +- fullName: google.cloud.pubsub_v1.publisher.client.Client.topic_path + isExternal: false + name: topic_path + parent: google.cloud.pubsub_v1.publisher.client.Client + uid: google.cloud.pubsub_v1.publisher.client.Client.topic_path +- fullName: google.cloud.pubsub_v1.publisher.client.Client.transport + isExternal: false + name: transport + parent: google.cloud.pubsub_v1.publisher.client.Client + uid: google.cloud.pubsub_v1.publisher.client.Client.transport +- fullName: google.cloud.pubsub_v1.publisher.client.Client.update_topic + isExternal: false + name: update_topic + parent: google.cloud.pubsub_v1.publisher.client.Client + uid: google.cloud.pubsub_v1.publisher.client.Client.update_topic diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.publisher.client.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.publisher.client.yml new file mode 100644 index 000000000000..7677c9ae23ef --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.publisher.client.yml @@ -0,0 +1,28 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- children: + - google.cloud.pubsub_v1.publisher.client.Client + fullName: google.cloud.pubsub_v1.publisher.client + langs: + - python + module: google.cloud.pubsub_v1.publisher.client + name: publisher.client + source: + id: client + path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 0 + summary: API documentation for `pubsub_v1.publisher.client` module. + syntax: {} + type: module + uid: google.cloud.pubsub_v1.publisher.client +references: +- fullName: google.cloud.pubsub_v1.publisher.client.Client + isExternal: false + name: Client + parent: google.cloud.pubsub_v1.publisher.client + uid: google.cloud.pubsub_v1.publisher.client.Client diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.publisher.futures.Future.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.publisher.futures.Future.yml new file mode 100644 index 000000000000..78b6d1ec0e3f --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.publisher.futures.Future.yml @@ -0,0 +1,438 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: [] + children: + - google.cloud.pubsub_v1.publisher.futures.Future + - google.cloud.pubsub_v1.publisher.futures.Future.add_done_callback + - google.cloud.pubsub_v1.publisher.futures.Future.cancel + - google.cloud.pubsub_v1.publisher.futures.Future.cancelled + - google.cloud.pubsub_v1.publisher.futures.Future.done + - google.cloud.pubsub_v1.publisher.futures.Future.exception + - google.cloud.pubsub_v1.publisher.futures.Future.result + - google.cloud.pubsub_v1.publisher.futures.Future.running + - google.cloud.pubsub_v1.publisher.futures.Future.set_exception + - google.cloud.pubsub_v1.publisher.futures.Future.set_result + - google.cloud.pubsub_v1.publisher.futures.Future.set_running_or_notify_cancel + class: google.cloud.pubsub_v1.publisher.futures.Future + fullName: google.cloud.pubsub_v1.publisher.futures.Future + inheritance: + - inheritance: + - inheritance: + - type: builtins.object + type: concurrent.futures._base.Future + - inheritance: + - type: builtins.object + type: google.api_core.future.base.Future + type: google.cloud.pubsub_v1.futures.Future + langs: + - python + module: google.cloud.pubsub_v1.publisher.futures + name: Future + source: + id: Future + path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/futures.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/futures.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 26 + summary: 'This future object is returned from asychronous Pub/Sub publishing + + calls. + + + Calling `result` will resolve the future by returning the message + + ID, unless an error occurs. + + + ' + syntax: + content: Future() + parameters: [] + type: class + uid: google.cloud.pubsub_v1.publisher.futures.Future +- attributes: [] + class: google.cloud.pubsub_v1.publisher.futures.Future + fullName: google.cloud.pubsub_v1.publisher.futures.Future + inheritance: + - inheritance: + - inheritance: + - type: builtins.object + type: concurrent.futures._base.Future + - inheritance: + - type: builtins.object + type: google.api_core.future.base.Future + type: google.cloud.pubsub_v1.futures.Future + langs: + - python + module: google.cloud.pubsub_v1.publisher.futures + name: Future + source: + id: Future + path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/futures.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/futures.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 26 + summary: 'Initializes the future. Should not be called by clients. + + + ' + syntax: + content: Future() + parameters: [] + type: method + uid: google.cloud.pubsub_v1.publisher.futures.Future +- attributes: [] + class: google.cloud.pubsub_v1.publisher.futures.Future + fullName: google.cloud.pubsub_v1.publisher.futures.Future.add_done_callback + langs: + - python + module: google.cloud.pubsub_v1.publisher.futures + name: add_done_callback + source: + id: add_done_callback + path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/futures.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/futures.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 69 + summary: 'Attach a callable that will be called when the future finishes. + + ' + syntax: + content: "add_done_callback(\n callback: typing.Callable[[pubsub_v1.publisher.futures.Future],\ + \ typing.Any]\n)" + parameters: [] + type: method + uid: google.cloud.pubsub_v1.publisher.futures.Future.add_done_callback +- attributes: [] + class: google.cloud.pubsub_v1.publisher.futures.Future + fullName: google.cloud.pubsub_v1.publisher.futures.Future.cancel + langs: + - python + module: google.cloud.pubsub_v1.publisher.futures + name: cancel + source: + id: cancel + path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/futures.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/futures.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 34 + summary: 'Actions in Pub/Sub generally may not be canceled. + + + This method always returns `False`. + + + ' + syntax: + content: cancel() + parameters: [] + type: method + uid: google.cloud.pubsub_v1.publisher.futures.Future.cancel +- attributes: [] + class: google.cloud.pubsub_v1.publisher.futures.Future + fullName: google.cloud.pubsub_v1.publisher.futures.Future.cancelled + langs: + - python + module: google.cloud.pubsub_v1.publisher.futures + name: cancelled + source: + id: cancelled + path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/futures.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/futures.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 41 + summary: 'Actions in Pub/Sub generally may not be canceled. + + + This method always returns `False`. + + + ' + syntax: + content: cancelled() + parameters: [] + type: method + uid: google.cloud.pubsub_v1.publisher.futures.Future.cancelled +- attributes: [] + class: google.cloud.pubsub_v1.publisher.futures.Future + fullName: google.cloud.pubsub_v1.publisher.futures.Future.done + langs: + - python + module: google.cloud.pubsub_v1.publisher.futures + name: done + source: + id: done + path: concurrent/futures/_base.py + remote: + branch: add_goldens + path: concurrent/futures/_base.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 383 + summary: 'Return True if the future was cancelled or finished executing. + + + ' + syntax: + content: done() + parameters: [] + type: method + uid: google.cloud.pubsub_v1.publisher.futures.Future.done +- attributes: [] + class: google.cloud.pubsub_v1.publisher.futures.Future + fullName: google.cloud.pubsub_v1.publisher.futures.Future.exception + langs: + - python + module: google.cloud.pubsub_v1.publisher.futures + name: exception + source: + id: exception + path: concurrent/futures/_base.py + remote: + branch: add_goldens + path: concurrent/futures/_base.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 453 + summary: 'Return the exception raised by the call that the future represents. + + ' + syntax: + content: exception(timeout=None) + exceptions: + - description: If the future was cancelled. + var_type: CancelledError + - description: If the future didn't finish executing before the given timeout. + var_type: TimeoutError + parameters: [] + type: method + uid: google.cloud.pubsub_v1.publisher.futures.Future.exception +- attributes: [] + class: google.cloud.pubsub_v1.publisher.futures.Future + fullName: google.cloud.pubsub_v1.publisher.futures.Future.result + langs: + - python + module: google.cloud.pubsub_v1.publisher.futures + name: result + source: + id: result + path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/futures.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/futures.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 48 + summary: 'Return the message ID or raise an exception. + + + This blocks until the message has been published successfully and + + returns the message ID unless an exception is raised. + + ' + syntax: + content: 'result(timeout: typing.Optional[typing.Union[int, float]] = None)' + exceptions: + - description: If the request times out. + var_type: concurrent.futures.TimeoutError + - description: For undefined exceptions in the underlying call execution. + var_type: Exception + parameters: [] + type: method + uid: google.cloud.pubsub_v1.publisher.futures.Future.result +- attributes: [] + class: google.cloud.pubsub_v1.publisher.futures.Future + fullName: google.cloud.pubsub_v1.publisher.futures.Future.running + langs: + - python + module: google.cloud.pubsub_v1.publisher.futures + name: running + source: + id: running + path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/futures.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/futures.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 33 + summary: 'Return `True` if the associated Pub/Sub action has not yet completed. + + + ' + syntax: + content: running() + parameters: [] + type: method + uid: google.cloud.pubsub_v1.publisher.futures.Future.running +- attributes: [] + class: google.cloud.pubsub_v1.publisher.futures.Future + fullName: google.cloud.pubsub_v1.publisher.futures.Future.set_exception + langs: + - python + module: google.cloud.pubsub_v1.publisher.futures + name: set_exception + source: + id: set_exception + path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/futures.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/futures.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 50 + summary: 'Set the result of the future as being the given exception. + + + Do not use this method, it should only be used internally by the library and its + + unit tests. + + + ' + syntax: + content: 'set_exception(exception: typing.Optional[BaseException])' + parameters: [] + type: method + uid: google.cloud.pubsub_v1.publisher.futures.Future.set_exception +- attributes: [] + class: google.cloud.pubsub_v1.publisher.futures.Future + fullName: google.cloud.pubsub_v1.publisher.futures.Future.set_result + langs: + - python + module: google.cloud.pubsub_v1.publisher.futures + name: set_result + source: + id: set_result + path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/futures.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/futures.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 42 + summary: 'Set the return value of work associated with the future. + + + Do not use this method, it should only be used internally by the library and its + + unit tests. + + + ' + syntax: + content: 'set_result(result: typing.Any)' + parameters: [] + type: method + uid: google.cloud.pubsub_v1.publisher.futures.Future.set_result +- attributes: [] + class: google.cloud.pubsub_v1.publisher.futures.Future + fullName: google.cloud.pubsub_v1.publisher.futures.Future.set_running_or_notify_cancel + langs: + - python + module: google.cloud.pubsub_v1.publisher.futures + name: set_running_or_notify_cancel + source: + id: set_running_or_notify_cancel + path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/futures.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/futures.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 37 + summary: 'Mark the future as running or process any cancel notifications. + + + Should only be used by Executor implementations and unit tests. + + + If the future has been cancelled (cancel() was called and returned + + True) then any threads waiting on the future completing (though calls + + to as_completed() or wait()) are notified and False is returned. + + + If the future was not cancelled then it is put in the running state + + (future calls to running() will return True) and True is returned. + + + This method should be called by Executor implementations before + + executing the work associated with this future. If this method returns + + False then the work should not be executed. + + ' + syntax: + content: set_running_or_notify_cancel() + exceptions: + - description: if this method was already called or if set_result() or set_exception() + was called. + var_type: RuntimeError + parameters: [] + type: method + uid: google.cloud.pubsub_v1.publisher.futures.Future.set_running_or_notify_cancel +references: +- fullName: google.cloud.pubsub_v1.publisher.futures.Future + isExternal: false + name: Future + parent: google.cloud.pubsub_v1.publisher.futures.Future + uid: google.cloud.pubsub_v1.publisher.futures.Future +- fullName: google.cloud.pubsub_v1.publisher.futures.Future.add_done_callback + isExternal: false + name: add_done_callback + parent: google.cloud.pubsub_v1.publisher.futures.Future + uid: google.cloud.pubsub_v1.publisher.futures.Future.add_done_callback +- fullName: google.cloud.pubsub_v1.publisher.futures.Future.cancel + isExternal: false + name: cancel + parent: google.cloud.pubsub_v1.publisher.futures.Future + uid: google.cloud.pubsub_v1.publisher.futures.Future.cancel +- fullName: google.cloud.pubsub_v1.publisher.futures.Future.cancelled + isExternal: false + name: cancelled + parent: google.cloud.pubsub_v1.publisher.futures.Future + uid: google.cloud.pubsub_v1.publisher.futures.Future.cancelled +- fullName: google.cloud.pubsub_v1.publisher.futures.Future.done + isExternal: false + name: done + parent: google.cloud.pubsub_v1.publisher.futures.Future + uid: google.cloud.pubsub_v1.publisher.futures.Future.done +- fullName: google.cloud.pubsub_v1.publisher.futures.Future.exception + isExternal: false + name: exception + parent: google.cloud.pubsub_v1.publisher.futures.Future + uid: google.cloud.pubsub_v1.publisher.futures.Future.exception +- fullName: google.cloud.pubsub_v1.publisher.futures.Future.result + isExternal: false + name: result + parent: google.cloud.pubsub_v1.publisher.futures.Future + uid: google.cloud.pubsub_v1.publisher.futures.Future.result +- fullName: google.cloud.pubsub_v1.publisher.futures.Future.running + isExternal: false + name: running + parent: google.cloud.pubsub_v1.publisher.futures.Future + uid: google.cloud.pubsub_v1.publisher.futures.Future.running +- fullName: google.cloud.pubsub_v1.publisher.futures.Future.set_exception + isExternal: false + name: set_exception + parent: google.cloud.pubsub_v1.publisher.futures.Future + uid: google.cloud.pubsub_v1.publisher.futures.Future.set_exception +- fullName: google.cloud.pubsub_v1.publisher.futures.Future.set_result + isExternal: false + name: set_result + parent: google.cloud.pubsub_v1.publisher.futures.Future + uid: google.cloud.pubsub_v1.publisher.futures.Future.set_result +- fullName: google.cloud.pubsub_v1.publisher.futures.Future.set_running_or_notify_cancel + isExternal: false + name: set_running_or_notify_cancel + parent: google.cloud.pubsub_v1.publisher.futures.Future + uid: google.cloud.pubsub_v1.publisher.futures.Future.set_running_or_notify_cancel diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.publisher.futures.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.publisher.futures.yml new file mode 100644 index 000000000000..4842779f9f69 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.publisher.futures.yml @@ -0,0 +1,28 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- children: + - google.cloud.pubsub_v1.publisher.futures.Future + fullName: google.cloud.pubsub_v1.publisher.futures + langs: + - python + module: google.cloud.pubsub_v1.publisher.futures + name: publisher.futures + source: + id: futures + path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/futures.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/futures.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 0 + summary: API documentation for `pubsub_v1.publisher.futures` module. + syntax: {} + type: module + uid: google.cloud.pubsub_v1.publisher.futures +references: +- fullName: google.cloud.pubsub_v1.publisher.futures.Future + isExternal: false + name: Future + parent: google.cloud.pubsub_v1.publisher.futures + uid: google.cloud.pubsub_v1.publisher.futures.Future diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.subscriber.client.Client.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.subscriber.client.Client.yml new file mode 100644 index 000000000000..5df70984b077 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.subscriber.client.Client.yml @@ -0,0 +1,2339 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: [] + children: + - google.cloud.pubsub_v1.subscriber.client.Client + - google.cloud.pubsub_v1.subscriber.client.Client.acknowledge + - google.cloud.pubsub_v1.subscriber.client.Client.api + - google.cloud.pubsub_v1.subscriber.client.Client.close + - google.cloud.pubsub_v1.subscriber.client.Client.closed + - google.cloud.pubsub_v1.subscriber.client.Client.common_billing_account_path + - google.cloud.pubsub_v1.subscriber.client.Client.common_folder_path + - google.cloud.pubsub_v1.subscriber.client.Client.common_location_path + - google.cloud.pubsub_v1.subscriber.client.Client.common_organization_path + - google.cloud.pubsub_v1.subscriber.client.Client.common_project_path + - google.cloud.pubsub_v1.subscriber.client.Client.create_snapshot + - google.cloud.pubsub_v1.subscriber.client.Client.create_subscription + - google.cloud.pubsub_v1.subscriber.client.Client.delete_snapshot + - google.cloud.pubsub_v1.subscriber.client.Client.delete_subscription + - google.cloud.pubsub_v1.subscriber.client.Client.from_service_account_file + - google.cloud.pubsub_v1.subscriber.client.Client.from_service_account_info + - google.cloud.pubsub_v1.subscriber.client.Client.from_service_account_json + - google.cloud.pubsub_v1.subscriber.client.Client.get_iam_policy + - google.cloud.pubsub_v1.subscriber.client.Client.get_mtls_endpoint_and_cert_source + - google.cloud.pubsub_v1.subscriber.client.Client.get_snapshot + - google.cloud.pubsub_v1.subscriber.client.Client.get_subscription + - google.cloud.pubsub_v1.subscriber.client.Client.list_snapshots + - google.cloud.pubsub_v1.subscriber.client.Client.list_subscriptions + - google.cloud.pubsub_v1.subscriber.client.Client.modify_ack_deadline + - google.cloud.pubsub_v1.subscriber.client.Client.modify_push_config + - google.cloud.pubsub_v1.subscriber.client.Client.parse_common_billing_account_path + - google.cloud.pubsub_v1.subscriber.client.Client.parse_common_folder_path + - google.cloud.pubsub_v1.subscriber.client.Client.parse_common_location_path + - google.cloud.pubsub_v1.subscriber.client.Client.parse_common_organization_path + - google.cloud.pubsub_v1.subscriber.client.Client.parse_common_project_path + - google.cloud.pubsub_v1.subscriber.client.Client.parse_snapshot_path + - google.cloud.pubsub_v1.subscriber.client.Client.parse_subscription_path + - google.cloud.pubsub_v1.subscriber.client.Client.parse_topic_path + - google.cloud.pubsub_v1.subscriber.client.Client.pull + - google.cloud.pubsub_v1.subscriber.client.Client.seek + - google.cloud.pubsub_v1.subscriber.client.Client.set_iam_policy + - google.cloud.pubsub_v1.subscriber.client.Client.snapshot_path + - google.cloud.pubsub_v1.subscriber.client.Client.streaming_pull + - google.cloud.pubsub_v1.subscriber.client.Client.subscribe + - google.cloud.pubsub_v1.subscriber.client.Client.subscription_path + - google.cloud.pubsub_v1.subscriber.client.Client.target + - google.cloud.pubsub_v1.subscriber.client.Client.test_iam_permissions + - google.cloud.pubsub_v1.subscriber.client.Client.topic_path + - google.cloud.pubsub_v1.subscriber.client.Client.transport + - google.cloud.pubsub_v1.subscriber.client.Client.update_snapshot + - google.cloud.pubsub_v1.subscriber.client.Client.update_subscription + class: google.cloud.pubsub_v1.subscriber.client.Client + fullName: google.cloud.pubsub_v1.subscriber.client.Client + inheritance: + - inheritance: + - type: builtins.object + type: google.pubsub_v1.services.subscriber.client.SubscriberClient + langs: + - python + module: google.cloud.pubsub_v1.subscriber.client + name: Client + source: + id: Client + path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 46 + summary: 'A subscriber client for Google Cloud Pub/Sub. + + + This creates an object that is capable of subscribing to messages. + + Generally, you can instantiate this client with no arguments, and you + + get sensible defaults. + + ' + syntax: + content: 'Client(**kwargs: typing.Any)' + parameters: [] + type: class + uid: google.cloud.pubsub_v1.subscriber.client.Client +- attributes: [] + class: google.cloud.pubsub_v1.subscriber.client.Client + fullName: google.cloud.pubsub_v1.subscriber.client.Client + inheritance: + - inheritance: + - type: builtins.object + type: google.pubsub_v1.services.subscriber.client.SubscriberClient + langs: + - python + module: google.cloud.pubsub_v1.subscriber.client + name: Client + source: + id: Client + path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 46 + summary: 'Instantiates the subscriber client. + + ' + syntax: + content: 'Client(**kwargs: typing.Any)' + exceptions: + - description: If mutual TLS transport creation failed for any reason. + var_type: google.auth.exceptions.MutualTLSChannelError + parameters: + - description: The authorization credentials to attach to requests. These credentials + identify the application to the service; if none are specified, the client + will attempt to ascertain the credentials from the environment. + id: credentials + var_type: Optional[google.auth.credentials.Credentials] + - description: The transport to use. If set to None, a transport is chosen automatically. + id: transport + var_type: Union[str, SubscriberTransport] + - description: 'Custom options for the client. It won''t take effect if a transport + instance is provided. (1) The api_endpoint property can be used + to override the default endpoint provided by the client. GOOGLE_API_USE_MTLS_ENDPOINT + environment variable can also be used to override the endpoint: "always" (always + use the default mTLS endpoint), "never" (always use the default regular endpoint) + and "auto" (auto switch to the default mTLS endpoint if client certificate + is present, this is the default value). However, the api_endpoint + property takes precedence if provided. (2) If GOOGLE_API_USE_CLIENT_CERTIFICATE + environment variable is "true", then the client_cert_source property + can be used to provide client certificate for mutual TLS transport. If not + provided, the default SSL client certificate will be used if present. If GOOGLE_API_USE_CLIENT_CERTIFICATE + is "false" or not set, no client certificate will be used.' + id: client_options + var_type: google.api_core.client_options.ClientOptions + - description: The client info used to send a user-agent string along with API + requests. If None, then default info will be used. Generally, + you only need to set this if you're developing your own client library. + id: client_info + var_type: google.api_core.gapic_v1.client_info.ClientInfo + type: method + uid: google.cloud.pubsub_v1.subscriber.client.Client +- attributes: [] + class: google.cloud.pubsub_v1.subscriber.client.Client + fullName: google.cloud.pubsub_v1.subscriber.client.Client.acknowledge + langs: + - python + module: google.cloud.pubsub_v1.subscriber.client + name: acknowledge + source: + id: acknowledge + path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 1203 + summary: "Acknowledges the messages associated with the `ack_ids` in the\n`AcknowledgeRequest`.\ + \ The Pub/Sub system can remove the\nrelevant messages from the subscription.\n\ + \nAcknowledging a message whose ack deadline has expired may\nsucceed, but such\ + \ a message may be redelivered later.\nAcknowledging a message more than once\ + \ will not result in an\nerror.\n\n```python\n# This snippet has been automatically\ + \ generated and should be regarded as a\n# code template only.\n# It will require\ + \ modifications to work:\n# - It may require correct/in-range values for request\ + \ initialization.\n# - It may require specifying regional endpoints when creating\ + \ the service\n# client as shown in:\n# https://googleapis.dev/python/google-api-core/latest/client_options.html\n\ + from google import pubsub_v1\n\ndef sample_acknowledge():\n # Create a client\n\ + \ client = pubsub_v1.SubscriberClient()\n\n # Initialize request argument(s)\n\ + \ request = pubsub_v1.AcknowledgeRequest(\n subscription=\"subscription_value\"\ + ,\n ack_ids=['ack_ids_value1', 'ack_ids_value2'],\n )\n\n # Make\ + \ the request\n client.acknowledge(request=request)\n```\n" + syntax: + content: "acknowledge(\n request: typing.Optional[\n typing.Union[google.cloud.pubsub_v1.types.AcknowledgeRequest,\ + \ dict]\n ] = None,\n *,\n subscription: typing.Optional[str] = None,\n\ + \ ack_ids: typing.Optional[typing.Sequence[str]] = None,\n retry: typing.Union[\n\ + \ google.api_core.retry.Retry, google.api_core.gapic_v1.method._MethodDefault\n\ + \ ] = _MethodDefault._DEFAULT_VALUE,\n timeout: typing.Optional[float]\ + \ = None,\n metadata: typing.Sequence[typing.Tuple[str, str]] = ()\n)" + parameters: + - defaultValue: None + description: The request object. Request for the Acknowledge method. + id: request + var_type: Union[google.pubsub_v1.types.AcknowledgeRequest, dict] + - description: Required. The subscription whose message is being acknowledged. + Format is projects/{project}/subscriptions/{sub}. This corresponds + to the subscription field on the request instance; + if request is provided, this should not be set. + id: subscription + var_type: str + - description: Required. The acknowledgment ID for the messages being acknowledged + that was returned by the Pub/Sub system in the Pull response. + Must not be empty. This corresponds to the ack_ids field on the + request instance; if request is provided, this should + not be set. + id: ack_ids + var_type: Sequence[str] + - description: Designation of what errors, if any, should be retried. + id: retry + var_type: google.api_core.retry.Retry + - description: The timeout for this request. + id: timeout + var_type: float + - description: Strings which should be sent along with the request as metadata. + id: metadata + var_type: Sequence[Tuple[str, str]] + type: method + uid: google.cloud.pubsub_v1.subscriber.client.Client.acknowledge +- &id001 + attributes: [] + class: google.cloud.pubsub_v1.subscriber.client.Client + fullName: google.cloud.pubsub_v1.subscriber.client.Client.api + langs: + - python + module: google.cloud.pubsub_v1.subscriber.client + name: api + source: + id: api + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: "The underlying gapic API client.\n\n.. versionchanged:: 2.10.0\n Instead\ + \ of a GAPIC `SubscriberClient` client instance, this property is a\n proxy\ + \ object to it with the same interface.\n\n" + syntax: {} + type: property + uid: google.cloud.pubsub_v1.subscriber.client.Client.api +- *id001 +- attributes: [] + class: google.cloud.pubsub_v1.subscriber.client.Client + fullName: google.cloud.pubsub_v1.subscriber.client.Client.close + langs: + - python + module: google.cloud.pubsub_v1.subscriber.client + name: close + source: + id: close + path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 271 + summary: 'Close the underlying channel to release socket resources. + + + After a channel has been closed, the client instance cannot be used + + anymore. + + + This method is idempotent. + + + ' + syntax: + content: close() + parameters: [] + type: method + uid: google.cloud.pubsub_v1.subscriber.client.Client.close +- &id002 + attributes: [] + class: google.cloud.pubsub_v1.subscriber.client.Client + fullName: google.cloud.pubsub_v1.subscriber.client.Client.closed + langs: + - python + module: google.cloud.pubsub_v1.subscriber.client + name: closed + source: + id: closed + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Return whether the client has been closed and cannot be used anymore. + + + .. versionadded:: 2.8.0 + + + ' + syntax: {} + type: property + uid: google.cloud.pubsub_v1.subscriber.client.Client.closed +- *id002 +- attributes: [] + class: google.cloud.pubsub_v1.subscriber.client.Client + fullName: google.cloud.pubsub_v1.subscriber.client.Client.common_billing_account_path + langs: + - python + module: google.cloud.pubsub_v1.subscriber.client + name: common_billing_account_path + source: + id: common_billing_account_path + path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 248 + summary: 'Returns a fully-qualified billing_account string. + + + ' + syntax: + content: 'common_billing_account_path(billing_account: str)' + parameters: [] + type: method + uid: google.cloud.pubsub_v1.subscriber.client.Client.common_billing_account_path +- attributes: [] + class: google.cloud.pubsub_v1.subscriber.client.Client + fullName: google.cloud.pubsub_v1.subscriber.client.Client.common_folder_path + langs: + - python + module: google.cloud.pubsub_v1.subscriber.client + name: common_folder_path + source: + id: common_folder_path + path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 263 + summary: 'Returns a fully-qualified folder string. + + + ' + syntax: + content: 'common_folder_path(folder: str)' + parameters: [] + type: method + uid: google.cloud.pubsub_v1.subscriber.client.Client.common_folder_path +- attributes: [] + class: google.cloud.pubsub_v1.subscriber.client.Client + fullName: google.cloud.pubsub_v1.subscriber.client.Client.common_location_path + langs: + - python + module: google.cloud.pubsub_v1.subscriber.client + name: common_location_path + source: + id: common_location_path + path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 308 + summary: 'Returns a fully-qualified location string. + + + ' + syntax: + content: 'common_location_path(project: str, location: str)' + parameters: [] + type: method + uid: google.cloud.pubsub_v1.subscriber.client.Client.common_location_path +- attributes: [] + class: google.cloud.pubsub_v1.subscriber.client.Client + fullName: google.cloud.pubsub_v1.subscriber.client.Client.common_organization_path + langs: + - python + module: google.cloud.pubsub_v1.subscriber.client + name: common_organization_path + source: + id: common_organization_path + path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 278 + summary: 'Returns a fully-qualified organization string. + + + ' + syntax: + content: 'common_organization_path(organization: str)' + parameters: [] + type: method + uid: google.cloud.pubsub_v1.subscriber.client.Client.common_organization_path +- attributes: [] + class: google.cloud.pubsub_v1.subscriber.client.Client + fullName: google.cloud.pubsub_v1.subscriber.client.Client.common_project_path + langs: + - python + module: google.cloud.pubsub_v1.subscriber.client + name: common_project_path + source: + id: common_project_path + path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 293 + summary: 'Returns a fully-qualified project string. + + + ' + syntax: + content: 'common_project_path(project: str)' + parameters: [] + type: method + uid: google.cloud.pubsub_v1.subscriber.client.Client.common_project_path +- attributes: [] + class: google.cloud.pubsub_v1.subscriber.client.Client + fullName: google.cloud.pubsub_v1.subscriber.client.Client.create_snapshot + langs: + - python + module: google.cloud.pubsub_v1.subscriber.client + name: create_snapshot + source: + id: create_snapshot + path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 1892 + summary: "Creates a snapshot from the requested subscription. Snapshots\nare used\ + \ in\n`Seek `__\noperations,\ + \ which allow you to manage message acknowledgments in\nbulk. That is, you can\ + \ set the acknowledgment state of messages\nin an existing subscription to the\ + \ state captured by a snapshot.\nIf the snapshot already exists, returns `ALREADY_EXISTS`.\ + \ If\nthe requested subscription doesn't exist, returns `NOT_FOUND`.\nIf the backlog\ + \ in the subscription is too old -- and the\nresulting snapshot would expire in\ + \ less than 1 hour -- then\n`FAILED_PRECONDITION` is returned. See also the\n\ + `Snapshot.expire_time` field. If the name is not provided in\nthe request, the\ + \ server will assign a random name for this\nsnapshot on the same project as the\ + \ subscription, conforming to\nthe [resource name format]\n(https://cloud.google.com/pubsub/docs/admin#resource_names).\ + \ The\ngenerated name is populated in the returned Snapshot object.\nNote that\ + \ for REST API requests, you must specify a name in the\nrequest.\n\n```python\n\ + # This snippet has been automatically generated and should be regarded as a\n\ + # code template only.\n# It will require modifications to work:\n# - It may require\ + \ correct/in-range values for request initialization.\n# - It may require specifying\ + \ regional endpoints when creating the service\n# client as shown in:\n# https://googleapis.dev/python/google-api-core/latest/client_options.html\n\ + from google import pubsub_v1\n\ndef sample_create_snapshot():\n # Create a\ + \ client\n client = pubsub_v1.SubscriberClient()\n\n # Initialize request\ + \ argument(s)\n request = pubsub_v1.CreateSnapshotRequest(\n name=\"\ + name_value\",\n subscription=\"subscription_value\",\n )\n\n # Make\ + \ the request\n response = client.create_snapshot(request=request)\n\n #\ + \ Handle the response\n print(response)\n```\n" + syntax: + content: "create_snapshot(\n request: typing.Optional[\n typing.Union[google.cloud.pubsub_v1.types.CreateSnapshotRequest,\ + \ dict]\n ] = None,\n *,\n name: typing.Optional[str] = None,\n \ + \ subscription: typing.Optional[str] = None,\n retry: typing.Union[\n \ + \ google.api_core.retry.Retry, google.api_core.gapic_v1.method._MethodDefault\n\ + \ ] = _MethodDefault._DEFAULT_VALUE,\n timeout: typing.Optional[float]\ + \ = None,\n metadata: typing.Sequence[typing.Tuple[str, str]] = ()\n)" + parameters: + - defaultValue: None + description: The request object. Request for the CreateSnapshot + method. + id: request + var_type: Union[google.pubsub_v1.types.CreateSnapshotRequest, dict] + - description: Required. User-provided name for this snapshot. If the name is + not provided in the request, the server will assign a random name for this + snapshot on the same project as the subscription. Note that for REST API requests, + you must specify a name. See the resource name rules. Format is projects/{project}/snapshots/{snap}. + This corresponds to the name field on the request + instance; if request is provided, this should not be set. + id: name + var_type: str + - description: 'Required. The subscription whose backlog the snapshot retains. + Specifically, the created snapshot is guaranteed to retain: (a) The existing + backlog on the subscription. More precisely, this is defined as the messages + in the subscription''s backlog that are unacknowledged upon the successful + completion of the CreateSnapshot request; as well as: (b) Any + messages published to the subscription''s topic following the successful completion + of the CreateSnapshot request. Format is projects/{project}/subscriptions/{sub}. + This corresponds to the subscription field on the request + instance; if request is provided, this should not be set.' + id: subscription + var_type: str + - description: Designation of what errors, if any, should be retried. + id: retry + var_type: google.api_core.retry.Retry + - description: The timeout for this request. + id: timeout + var_type: float + - description: Strings which should be sent along with the request as metadata. + id: metadata + var_type: Sequence[Tuple[str, str]] + returns: + - description: A snapshot resource. Snapshots are used in [Seek](https://cloud.google.com/pubsub/docs/replay-overview) + operations, which allow you to manage message acknowledgments in bulk. That + is, you can set the acknowledgment state of messages in an existing subscription + to the state captured by a snapshot. + var_type: google.pubsub_v1.types.Snapshot + type: method + uid: google.cloud.pubsub_v1.subscriber.client.Client.create_snapshot +- attributes: [] + class: google.cloud.pubsub_v1.subscriber.client.Client + fullName: google.cloud.pubsub_v1.subscriber.client.Client.create_subscription + langs: + - python + module: google.cloud.pubsub_v1.subscriber.client + name: create_subscription + source: + id: create_subscription + path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 500 + summary: "Creates a subscription to a given topic. See the [resource name\nrules]\n\ + (https://cloud.google.com/pubsub/docs/admin#resource_names). If\nthe subscription\ + \ already exists, returns `ALREADY_EXISTS`. If\nthe corresponding topic doesn't\ + \ exist, returns `NOT_FOUND`.\n\nIf the name is not provided in the request, the\ + \ server will\nassign a random name for this subscription on the same project\n\ + as the topic, conforming to the [resource name format]\n(https://cloud.google.com/pubsub/docs/admin#resource_names).\ + \ The\ngenerated name is populated in the returned Subscription object.\nNote\ + \ that for REST API requests, you must specify a name in the\nrequest.\n\n```python\n\ + # This snippet has been automatically generated and should be regarded as a\n\ + # code template only.\n# It will require modifications to work:\n# - It may require\ + \ correct/in-range values for request initialization.\n# - It may require specifying\ + \ regional endpoints when creating the service\n# client as shown in:\n# https://googleapis.dev/python/google-api-core/latest/client_options.html\n\ + from google import pubsub_v1\n\ndef sample_create_subscription():\n # Create\ + \ a client\n client = pubsub_v1.SubscriberClient()\n\n # Initialize request\ + \ argument(s)\n request = pubsub_v1.Subscription(\n name=\"name_value\"\ + ,\n topic=\"topic_value\",\n )\n\n # Make the request\n response\ + \ = client.create_subscription(request=request)\n\n # Handle the response\n\ + \ print(response)\n```\n" + syntax: + content: "create_subscription(\n request: typing.Optional[\n typing.Union[google.cloud.pubsub_v1.types.Subscription,\ + \ dict]\n ] = None,\n *,\n name: typing.Optional[str] = None,\n \ + \ topic: typing.Optional[str] = None,\n push_config: typing.Optional[google.cloud.pubsub_v1.types.PushConfig]\ + \ = None,\n ack_deadline_seconds: typing.Optional[int] = None,\n retry:\ + \ typing.Union[\n google.api_core.retry.Retry, google.api_core.gapic_v1.method._MethodDefault\n\ + \ ] = _MethodDefault._DEFAULT_VALUE,\n timeout: typing.Optional[float]\ + \ = None,\n metadata: typing.Sequence[typing.Tuple[str, str]] = ()\n)" + parameters: + - defaultValue: None + description: The request object. A subscription resource. + id: request + var_type: Union[google.pubsub_v1.types.Subscription, dict] + - description: Required. The name of the subscription. It must have the format + "projects/{project}/subscriptions/{subscription}". {subscription} + must start with a letter, and contain only letters ([A-Za-z]), + numbers ([0-9]), dashes (-), underscores (_), + periods (.), tildes (
), plus (`+)
+        or percent signs (%). It must be between 3 and 255
+        characters in length, and it must not start with "goog". This
+        corresponds to the name field on the request instance;
+        if request` is provided, this should not be set.
+      id: name
+      var_type: str
+    - description: Required. The name of the topic from which this subscription is
+        receiving messages. Format is projects/{project}/topics/{topic}.
+        The value of this field will be _deleted-topic_ if the topic
+        has been deleted. This corresponds to the topic field on the
+        request instance; if request is provided, this should
+        not be set.
+      id: topic
+      var_type: str
+    - description: If push delivery is used with this subscription, this field is
+        used to configure it. Either pushConfig or bigQueryConfig
+        can be set, but not both. If both are empty, then the subscriber will pull
+        and ack messages using API methods. This corresponds to the push_config
+        field on the request instance; if request is provided,
+        this should not be set.
+      id: push_config
+      var_type: google.pubsub_v1.types.PushConfig
+    - description: The approximate amount of time (on a best-effort basis) Pub/Sub
+        waits for the subscriber to acknowledge receipt before resending the message.
+        In the interval after the message is delivered and before it is acknowledged,
+        it is considered to be outstanding. During that time period, the message will
+        not be redelivered (on a best-effort basis). For pull subscriptions, this
+        value is used as the initial value for the ack deadline. To override this
+        value for a given message, call ModifyAckDeadline with the corresponding
+        ack_id if using non-streaming pull or send the ack_id
+        in a StreamingModifyAckDeadlineRequest if using streaming pull.
+        The minimum custom deadline you can specify is 10 seconds. The maximum custom
+        deadline you can specify is 600 seconds (10 minutes). If this parameter is
+        0, a default value of 10 seconds is used. For push delivery, this value is
+        also used to set the request timeout for the call to the push endpoint. If
+        the subscriber never acknowledges the message, the Pub/Sub system will eventually
+        redeliver the message. This corresponds to the ack_deadline_seconds
+        field on the request instance; if request is provided,
+        this should not be set.
+      id: ack_deadline_seconds
+      var_type: int
+    - description: Designation of what errors, if any, should be retried.
+      id: retry
+      var_type: google.api_core.retry.Retry
+    - description: The timeout for this request.
+      id: timeout
+      var_type: float
+    - description: Strings which should be sent along with the request as metadata.
+      id: metadata
+      var_type: Sequence[Tuple[str, str]]
+    returns:
+    - description: A subscription resource.
+      var_type: google.pubsub_v1.types.Subscription
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.create_subscription
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.client.Client
+  fullName: google.cloud.pubsub_v1.subscriber.client.Client.delete_snapshot
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.client
+  name: delete_snapshot
+  source:
+    id: delete_snapshot
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 2133
+  summary: "Removes an existing snapshot. Snapshots are used in [Seek]\n(https://cloud.google.com/pubsub/docs/replay-overview)\n\
+    operations, which allow you to manage message acknowledgments in\nbulk. That is,\
+    \ you can set the acknowledgment state of messages\nin an existing subscription\
+    \ to the state captured by a snapshot.\nWhen the snapshot is deleted, all messages\
+    \ retained in the\nsnapshot are immediately dropped. After a snapshot is deleted,\
+    \ a\nnew one may be created with the same name, but the new one has\nno association\
+    \ with the old snapshot or its subscription, unless\nthe same subscription is\
+    \ specified.\n\n```python\n# This snippet has been automatically generated and\
+    \ should be regarded as a\n# code template only.\n# It will require modifications\
+    \ to work:\n# - It may require correct/in-range values for request initialization.\n\
+    # - It may require specifying regional endpoints when creating the service\n#\
+    \   client as shown in:\n#   https://googleapis.dev/python/google-api-core/latest/client_options.html\n\
+    from google import pubsub_v1\n\ndef sample_delete_snapshot():\n    # Create a\
+    \ client\n    client = pubsub_v1.SubscriberClient()\n\n    # Initialize request\
+    \ argument(s)\n    request = pubsub_v1.DeleteSnapshotRequest(\n        snapshot=\"\
+    snapshot_value\",\n    )\n\n    # Make the request\n    client.delete_snapshot(request=request)\n\
+    ```\n"
+  syntax:
+    content: "delete_snapshot(\n    request: typing.Optional[\n        typing.Union[google.cloud.pubsub_v1.types.DeleteSnapshotRequest,\
+      \ dict]\n    ] = None,\n    *,\n    snapshot: typing.Optional[str] = None,\n\
+      \    retry: typing.Union[\n        google.api_core.retry.Retry, google.api_core.gapic_v1.method._MethodDefault\n\
+      \    ] = _MethodDefault._DEFAULT_VALUE,\n    timeout: typing.Optional[float]\
+      \ = None,\n    metadata: typing.Sequence[typing.Tuple[str, str]] = ()\n)"
+    parameters:
+    - defaultValue: None
+      description: The request object. Request for the DeleteSnapshot
+        method.
+      id: request
+      var_type: Union[google.pubsub_v1.types.DeleteSnapshotRequest, dict]
+    - description: Required. The name of the snapshot to delete. Format is projects/{project}/snapshots/{snap}.
+        This corresponds to the snapshot field on the request
+        instance; if request is provided, this should not be set.
+      id: snapshot
+      var_type: str
+    - description: Designation of what errors, if any, should be retried.
+      id: retry
+      var_type: google.api_core.retry.Retry
+    - description: The timeout for this request.
+      id: timeout
+      var_type: float
+    - description: Strings which should be sent along with the request as metadata.
+      id: metadata
+      var_type: Sequence[Tuple[str, str]]
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.delete_snapshot
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.client.Client
+  fullName: google.cloud.pubsub_v1.subscriber.client.Client.delete_subscription
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.client
+  name: delete_subscription
+  source:
+    id: delete_subscription
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 980
+  summary: "Deletes an existing subscription. All messages retained in the\nsubscription\
+    \ are immediately dropped. Calls to `Pull` after\ndeletion will return `NOT_FOUND`.\
+    \ After a subscription is\ndeleted, a new one may be created with the same name,\
+    \ but the\nnew one has no association with the old subscription or its\ntopic\
+    \ unless the same topic is specified.\n\n```python\n# This snippet has been automatically\
+    \ generated and should be regarded as a\n# code template only.\n# It will require\
+    \ modifications to work:\n# - It may require correct/in-range values for request\
+    \ initialization.\n# - It may require specifying regional endpoints when creating\
+    \ the service\n#   client as shown in:\n#   https://googleapis.dev/python/google-api-core/latest/client_options.html\n\
+    from google import pubsub_v1\n\ndef sample_delete_subscription():\n    # Create\
+    \ a client\n    client = pubsub_v1.SubscriberClient()\n\n    # Initialize request\
+    \ argument(s)\n    request = pubsub_v1.DeleteSubscriptionRequest(\n        subscription=\"\
+    subscription_value\",\n    )\n\n    # Make the request\n    client.delete_subscription(request=request)\n\
+    ```\n"
+  syntax:
+    content: "delete_subscription(\n    request: typing.Optional[\n        typing.Union[google.cloud.pubsub_v1.types.DeleteSubscriptionRequest,\
+      \ dict]\n    ] = None,\n    *,\n    subscription: typing.Optional[str] = None,\n\
+      \    retry: typing.Union[\n        google.api_core.retry.Retry, google.api_core.gapic_v1.method._MethodDefault\n\
+      \    ] = _MethodDefault._DEFAULT_VALUE,\n    timeout: typing.Optional[float]\
+      \ = None,\n    metadata: typing.Sequence[typing.Tuple[str, str]] = ()\n)"
+    parameters:
+    - defaultValue: None
+      description: The request object. Request for the DeleteSubscription method.
+      id: request
+      var_type: Union[google.pubsub_v1.types.DeleteSubscriptionRequest, dict]
+    - description: Required. The subscription to delete. Format is projects/{project}/subscriptions/{sub}.
+        This corresponds to the subscription field on the request
+        instance; if request is provided, this should not be set.
+      id: subscription
+      var_type: str
+    - description: Designation of what errors, if any, should be retried.
+      id: retry
+      var_type: google.api_core.retry.Retry
+    - description: The timeout for this request.
+      id: timeout
+      var_type: float
+    - description: Strings which should be sent along with the request as metadata.
+      id: metadata
+      var_type: Sequence[Tuple[str, str]]
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.delete_subscription
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.client.Client
+  fullName: google.cloud.pubsub_v1.subscriber.client.Client.from_service_account_file
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.client
+  name: from_service_account_file
+  source:
+    id: from_service_account_file
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/client.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/client.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 91
+  summary: 'Creates an instance of this client using the provided credentials
+
+    file.
+
+    '
+  syntax:
+    content: 'from_service_account_file(filename: str, **kwargs: typing.Any)'
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.from_service_account_file
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.client.Client
+  fullName: google.cloud.pubsub_v1.subscriber.client.Client.from_service_account_info
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.client
+  name: from_service_account_info
+  source:
+    id: from_service_account_info
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 148
+  summary: "Creates an instance of this client using the provided credentials\n  \
+    \  info.\n"
+  syntax:
+    content: 'from_service_account_info(info: dict, *args, **kwargs)'
+    parameters:
+    - description: The service account private key info.
+      id: info
+      var_type: dict
+    returns:
+    - description: The constructed client.
+      var_type: SubscriberClient
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.from_service_account_info
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.client.Client
+  fullName: google.cloud.pubsub_v1.subscriber.client.Client.from_service_account_json
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.client
+  name: from_service_account_json
+  source:
+    id: from_service_account_json
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/client.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/client.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 91
+  summary: 'Creates an instance of this client using the provided credentials
+
+    file.
+
+    '
+  syntax:
+    content: 'from_service_account_json(filename: str, **kwargs: typing.Any)'
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.from_service_account_json
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.client.Client
+  fullName: google.cloud.pubsub_v1.subscriber.client.Client.get_iam_policy
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.client
+  name: get_iam_policy
+  source:
+    id: get_iam_policy
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 2453
+  summary: 'Gets the IAM access control policy for a function.
+
+
+    Returns an empty policy if the function exists and does not have a
+
+    policy set.
+
+    '
+  syntax:
+    content: "get_iam_policy(\n    request: typing.Optional[google.iam.v1.iam_policy_pb2.GetIamPolicyRequest]\
+      \ = None,\n    *,\n    retry: typing.Union[\n        google.api_core.retry.Retry,\
+      \ google.api_core.gapic_v1.method._MethodDefault\n    ] = _MethodDefault._DEFAULT_VALUE,\n\
+      \    timeout: typing.Optional[float] = None,\n    metadata: typing.Sequence[typing.Tuple[str,\
+      \ str]] = ()\n)"
+    parameters:
+    - defaultValue: None
+      description: The request object. Request message for GetIamPolicy
+        method.
+      id: request
+      var_type: .iam_policy_pb2.GetIamPolicyRequest
+    - description: Designation of what errors, if any, should be retried.
+      id: retry
+      var_type: google.api_core.retry.Retry
+    - description: The timeout for this request.
+      id: timeout
+      var_type: float
+    - description: Strings which should be sent along with the request as metadata.
+      id: metadata
+      var_type: Sequence[Tuple[str, str]]
+    returns:
+    - description: 'Defines an Identity and Access Management (IAM) policy. It is
+        used to specify access control policies for Cloud Platform resources. A Policy
+        is a collection of bindings. A binding binds one
+        or more members to a single role. Members can be
+        user accounts, service accounts, Google groups, and domains (such as G Suite).
+        A role is a named list of permissions (defined by IAM or configured
+        by users). A binding can optionally specify a condition,
+        which is a logic expression that further constrains the role binding based
+        on attributes about the request and/or target resource. **JSON Example** ::
+        { "bindings": [ { "role": "roles/resourcemanager.organizationAdmin", "members":
+        [ "user:mike@example.com", "group:admins@example.com", "domain:google.com",
+        "serviceAccount:my-project-id@appspot.gserviceaccount.com" ] }, { "role":
+        "roles/resourcemanager.organizationViewer", "members": ["user:eve@example.com"],
+        "condition": { "title": "expirable access", "description": "Does not grant
+        access after Sep 2020", "expression": "request.time < timestamp(''2020-10-01T00:00:00.000Z'')",
+        } } ] } **YAML Example** :: bindings: - members: - user:mike@example.com -
+        group:admins@example.com - domain:google.com - serviceAccount:my-project-id@appspot.gserviceaccount.com
+        role: roles/resourcemanager.organizationAdmin - members: - user:eve@example.com
+        role: roles/resourcemanager.organizationViewer condition: title: expirable
+        access description: Does not grant access after Sep 2020 expression: request.time
+        < timestamp(''2020-10-01T00:00:00.000Z'') For a description of IAM and its
+        features, see the IAM developer''s guide __.'
+      var_type: .policy_pb2.Policy
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.get_iam_policy
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.client.Client
+  fullName: google.cloud.pubsub_v1.subscriber.client.Client.get_mtls_endpoint_and_cert_source
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.client
+  name: get_mtls_endpoint_and_cert_source
+  source:
+    id: get_mtls_endpoint_and_cert_source
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 325
+  summary: 'Return the API endpoint and client cert source for mutual TLS.
+
+
+    The client cert source is determined in the following order:
+
+    (1) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not "true",
+    the
+
+    client cert source is None.
+
+    (2) if `client_options.client_cert_source` is provided, use the provided one;
+    if the
+
+    default client cert source exists, use the default one; otherwise the client cert
+
+    source is None.
+
+
+    The API endpoint is determined in the following order:
+
+    (1) if `client_options.api_endpoint` if provided, use the provided one.
+
+    (2) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is "always", use
+    the
+
+    default mTLS endpoint; if the environment variabel is "never", use the default
+    API
+
+    endpoint; otherwise if client cert source exists, use the default mTLS endpoint,
+    otherwise
+
+    use the default API endpoint.
+
+
+    More details can be found at https://google.aip.dev/auth/4114.
+
+    '
+  syntax:
+    content: "get_mtls_endpoint_and_cert_source(\n    client_options: typing.Optional[\n\
+      \        google.api_core.client_options.ClientOptions\n    ] = None,\n)"
+    exceptions:
+    - description: If any errors happen.
+      var_type: google.auth.exceptions.MutualTLSChannelError
+    parameters:
+    - defaultValue: None
+      description: Custom options for the client. Only the api_endpoint
+        and client_cert_source properties may be used in this method.
+      id: client_options
+      var_type: google.api_core.client_options.ClientOptions
+    returns:
+    - description: returns the API endpoint and the client cert source to use.
+      var_type: Tuple[str, Callable[[], Tuple[bytes, bytes]]]
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.get_mtls_endpoint_and_cert_source
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.client.Client
+  fullName: google.cloud.pubsub_v1.subscriber.client.Client.get_snapshot
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.client
+  name: get_snapshot
+  source:
+    id: get_snapshot
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 1663
+  summary: "Gets the configuration details of a snapshot.\nSnapshots are used in Seek\noperations,\
+    \ which allow you to manage message\nacknowledgments in bulk. That is, you can\
+    \ set the\nacknowledgment state of messages in an existing\nsubscription to the\
+    \ state captured by a snapshot.\n\n```python\n# This snippet has been automatically\
+    \ generated and should be regarded as a\n# code template only.\n# It will require\
+    \ modifications to work:\n# - It may require correct/in-range values for request\
+    \ initialization.\n# - It may require specifying regional endpoints when creating\
+    \ the service\n#   client as shown in:\n#   https://googleapis.dev/python/google-api-core/latest/client_options.html\n\
+    from google import pubsub_v1\n\ndef sample_get_snapshot():\n    # Create a client\n\
+    \    client = pubsub_v1.SubscriberClient()\n\n    # Initialize request argument(s)\n\
+    \    request = pubsub_v1.GetSnapshotRequest(\n        snapshot=\"snapshot_value\"\
+    ,\n    )\n\n    # Make the request\n    response = client.get_snapshot(request=request)\n\
+    \n    # Handle the response\n    print(response)\n```\n"
+  syntax:
+    content: "get_snapshot(\n    request: typing.Optional[\n        typing.Union[google.cloud.pubsub_v1.types.GetSnapshotRequest,\
+      \ dict]\n    ] = None,\n    *,\n    snapshot: typing.Optional[str] = None,\n\
+      \    retry: typing.Union[\n        google.api_core.retry.Retry, google.api_core.gapic_v1.method._MethodDefault\n\
+      \    ] = _MethodDefault._DEFAULT_VALUE,\n    timeout: typing.Optional[float]\
+      \ = None,\n    metadata: typing.Sequence[typing.Tuple[str, str]] = ()\n)"
+    parameters:
+    - defaultValue: None
+      description: The request object. Request for the GetSnapshot method.
+      id: request
+      var_type: Union[google.pubsub_v1.types.GetSnapshotRequest, dict]
+    - description: Required. The name of the snapshot to get. Format is projects/{project}/snapshots/{snap}.
+        This corresponds to the snapshot field on the request
+        instance; if request is provided, this should not be set.
+      id: snapshot
+      var_type: str
+    - description: Designation of what errors, if any, should be retried.
+      id: retry
+      var_type: google.api_core.retry.Retry
+    - description: The timeout for this request.
+      id: timeout
+      var_type: float
+    - description: Strings which should be sent along with the request as metadata.
+      id: metadata
+      var_type: Sequence[Tuple[str, str]]
+    returns:
+    - description: A snapshot resource. Snapshots are used in [Seek](https://cloud.google.com/pubsub/docs/replay-overview)
+        operations, which allow you to manage message acknowledgments in bulk. That
+        is, you can set the acknowledgment state of messages in an existing subscription
+        to the state captured by a snapshot.
+      var_type: google.pubsub_v1.types.Snapshot
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.get_snapshot
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.client.Client
+  fullName: google.cloud.pubsub_v1.subscriber.client.Client.get_subscription
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.client
+  name: get_subscription
+  source:
+    id: get_subscription
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 677
+  summary: "Gets the configuration details of a subscription.\n\n```python\n# This\
+    \ snippet has been automatically generated and should be regarded as a\n# code\
+    \ template only.\n# It will require modifications to work:\n# - It may require\
+    \ correct/in-range values for request initialization.\n# - It may require specifying\
+    \ regional endpoints when creating the service\n#   client as shown in:\n#   https://googleapis.dev/python/google-api-core/latest/client_options.html\n\
+    from google import pubsub_v1\n\ndef sample_get_subscription():\n    # Create a\
+    \ client\n    client = pubsub_v1.SubscriberClient()\n\n    # Initialize request\
+    \ argument(s)\n    request = pubsub_v1.GetSubscriptionRequest(\n        subscription=\"\
+    subscription_value\",\n    )\n\n    # Make the request\n    response = client.get_subscription(request=request)\n\
+    \n    # Handle the response\n    print(response)\n```\n"
+  syntax:
+    content: "get_subscription(\n    request: typing.Optional[\n        typing.Union[google.cloud.pubsub_v1.types.GetSubscriptionRequest,\
+      \ dict]\n    ] = None,\n    *,\n    subscription: typing.Optional[str] = None,\n\
+      \    retry: typing.Union[\n        google.api_core.retry.Retry, google.api_core.gapic_v1.method._MethodDefault\n\
+      \    ] = _MethodDefault._DEFAULT_VALUE,\n    timeout: typing.Optional[float]\
+      \ = None,\n    metadata: typing.Sequence[typing.Tuple[str, str]] = ()\n)"
+    parameters:
+    - defaultValue: None
+      description: The request object. Request for the GetSubscription method.
+      id: request
+      var_type: Union[google.pubsub_v1.types.GetSubscriptionRequest, dict]
+    - description: Required. The name of the subscription to get. Format is projects/{project}/subscriptions/{sub}.
+        This corresponds to the subscription field on the request
+        instance; if request is provided, this should not be set.
+      id: subscription
+      var_type: str
+    - description: Designation of what errors, if any, should be retried.
+      id: retry
+      var_type: google.api_core.retry.Retry
+    - description: The timeout for this request.
+      id: timeout
+      var_type: float
+    - description: Strings which should be sent along with the request as metadata.
+      id: metadata
+      var_type: Sequence[Tuple[str, str]]
+    returns:
+    - description: A subscription resource.
+      var_type: google.pubsub_v1.types.Subscription
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.get_subscription
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.client.Client
+  fullName: google.cloud.pubsub_v1.subscriber.client.Client.list_snapshots
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.client
+  name: list_snapshots
+  source:
+    id: list_snapshots
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 1774
+  summary: "Lists the existing snapshots. Snapshots are used in\n`Seek `__\n\
+    operations, which allow you to manage message acknowledgments in\nbulk. That is,\
+    \ you can set the acknowledgment state of messages\nin an existing subscription\
+    \ to the state captured by a snapshot.\n\n```python\n# This snippet has been automatically\
+    \ generated and should be regarded as a\n# code template only.\n# It will require\
+    \ modifications to work:\n# - It may require correct/in-range values for request\
+    \ initialization.\n# - It may require specifying regional endpoints when creating\
+    \ the service\n#   client as shown in:\n#   https://googleapis.dev/python/google-api-core/latest/client_options.html\n\
+    from google import pubsub_v1\n\ndef sample_list_snapshots():\n    # Create a client\n\
+    \    client = pubsub_v1.SubscriberClient()\n\n    # Initialize request argument(s)\n\
+    \    request = pubsub_v1.ListSnapshotsRequest(\n        project=\"project_value\"\
+    ,\n    )\n\n    # Make the request\n    page_result = client.list_snapshots(request=request)\n\
+    \n    # Handle the response\n    for response in page_result:\n        print(response)\n\
+    ```\n"
+  syntax:
+    content: "list_snapshots(\n    request: typing.Optional[\n        typing.Union[google.cloud.pubsub_v1.types.ListSnapshotsRequest,\
+      \ dict]\n    ] = None,\n    *,\n    project: typing.Optional[str] = None,\n\
+      \    retry: typing.Union[\n        google.api_core.retry.Retry, google.api_core.gapic_v1.method._MethodDefault\n\
+      \    ] = _MethodDefault._DEFAULT_VALUE,\n    timeout: typing.Optional[float]\
+      \ = None,\n    metadata: typing.Sequence[typing.Tuple[str, str]] = ()\n)"
+    parameters:
+    - defaultValue: None
+      description: The request object. Request for the ListSnapshots
+        method.
+      id: request
+      var_type: Union[google.pubsub_v1.types.ListSnapshotsRequest, dict]
+    - description: Required. The name of the project in which to list snapshots. Format
+        is projects/{project-id}. This corresponds to the project
+        field on the request instance; if request is provided,
+        this should not be set.
+      id: project
+      var_type: str
+    - description: Designation of what errors, if any, should be retried.
+      id: retry
+      var_type: google.api_core.retry.Retry
+    - description: The timeout for this request.
+      id: timeout
+      var_type: float
+    - description: Strings which should be sent along with the request as metadata.
+      id: metadata
+      var_type: Sequence[Tuple[str, str]]
+    returns:
+    - description: Response for the ListSnapshots method. Iterating over this object
+        will yield results and resolve additional pages automatically.
+      var_type: google.pubsub_v1.services.subscriber.pagers.ListSnapshotsPager
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.list_snapshots
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.client.Client
+  fullName: google.cloud.pubsub_v1.subscriber.client.Client.list_subscriptions
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.client
+  name: list_subscriptions
+  source:
+    id: list_subscriptions
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 866
+  summary: "Lists matching subscriptions.\n\n```python\n# This snippet has been automatically\
+    \ generated and should be regarded as a\n# code template only.\n# It will require\
+    \ modifications to work:\n# - It may require correct/in-range values for request\
+    \ initialization.\n# - It may require specifying regional endpoints when creating\
+    \ the service\n#   client as shown in:\n#   https://googleapis.dev/python/google-api-core/latest/client_options.html\n\
+    from google import pubsub_v1\n\ndef sample_list_subscriptions():\n    # Create\
+    \ a client\n    client = pubsub_v1.SubscriberClient()\n\n    # Initialize request\
+    \ argument(s)\n    request = pubsub_v1.ListSubscriptionsRequest(\n        project=\"\
+    project_value\",\n    )\n\n    # Make the request\n    page_result = client.list_subscriptions(request=request)\n\
+    \n    # Handle the response\n    for response in page_result:\n        print(response)\n\
+    ```\n"
+  syntax:
+    content: "list_subscriptions(\n    request: typing.Optional[\n        typing.Union[google.cloud.pubsub_v1.types.ListSubscriptionsRequest,\
+      \ dict]\n    ] = None,\n    *,\n    project: typing.Optional[str] = None,\n\
+      \    retry: typing.Union[\n        google.api_core.retry.Retry, google.api_core.gapic_v1.method._MethodDefault\n\
+      \    ] = _MethodDefault._DEFAULT_VALUE,\n    timeout: typing.Optional[float]\
+      \ = None,\n    metadata: typing.Sequence[typing.Tuple[str, str]] = ()\n)"
+    parameters:
+    - defaultValue: None
+      description: The request object. Request for the ListSubscriptions
+        method.
+      id: request
+      var_type: Union[google.pubsub_v1.types.ListSubscriptionsRequest, dict]
+    - description: Required. The name of the project in which to list subscriptions.
+        Format is projects/{project-id}. This corresponds to the project
+        field on the request instance; if request is provided,
+        this should not be set.
+      id: project
+      var_type: str
+    - description: Designation of what errors, if any, should be retried.
+      id: retry
+      var_type: google.api_core.retry.Retry
+    - description: The timeout for this request.
+      id: timeout
+      var_type: float
+    - description: Strings which should be sent along with the request as metadata.
+      id: metadata
+      var_type: Sequence[Tuple[str, str]]
+    returns:
+    - description: Response for the ListSubscriptions method. Iterating over this
+        object will yield results and resolve additional pages automatically.
+      var_type: google.pubsub_v1.services.subscriber.pagers.ListSubscriptionsPager
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.list_subscriptions
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.client.Client
+  fullName: google.cloud.pubsub_v1.subscriber.client.Client.modify_ack_deadline
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.client
+  name: modify_ack_deadline
+  source:
+    id: modify_ack_deadline
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 1077
+  summary: "Modifies the ack deadline for a specific message. This method is\nuseful\
+    \ to indicate that more time is needed to process a message\nby the subscriber,\
+    \ or to make the message available for\nredelivery if the processing was interrupted.\
+    \ Note that this\ndoes not modify the subscription-level `ackDeadlineSeconds`\n\
+    used for subsequent messages.\n\n```python\n# This snippet has been automatically\
+    \ generated and should be regarded as a\n# code template only.\n# It will require\
+    \ modifications to work:\n# - It may require correct/in-range values for request\
+    \ initialization.\n# - It may require specifying regional endpoints when creating\
+    \ the service\n#   client as shown in:\n#   https://googleapis.dev/python/google-api-core/latest/client_options.html\n\
+    from google import pubsub_v1\n\ndef sample_modify_ack_deadline():\n    # Create\
+    \ a client\n    client = pubsub_v1.SubscriberClient()\n\n    # Initialize request\
+    \ argument(s)\n    request = pubsub_v1.ModifyAckDeadlineRequest(\n        subscription=\"\
+    subscription_value\",\n        ack_ids=['ack_ids_value1', 'ack_ids_value2'],\n\
+    \        ack_deadline_seconds=2066,\n    )\n\n    # Make the request\n    client.modify_ack_deadline(request=request)\n\
+    ```\n"
+  syntax:
+    content: "modify_ack_deadline(\n    request: typing.Optional[\n        typing.Union[google.cloud.pubsub_v1.types.ModifyAckDeadlineRequest,\
+      \ dict]\n    ] = None,\n    *,\n    subscription: typing.Optional[str] = None,\n\
+      \    ack_ids: typing.Optional[typing.Sequence[str]] = None,\n    ack_deadline_seconds:\
+      \ typing.Optional[int] = None,\n    retry: typing.Union[\n        google.api_core.retry.Retry,\
+      \ google.api_core.gapic_v1.method._MethodDefault\n    ] = _MethodDefault._DEFAULT_VALUE,\n\
+      \    timeout: typing.Optional[float] = None,\n    metadata: typing.Sequence[typing.Tuple[str,\
+      \ str]] = ()\n)"
+    parameters:
+    - defaultValue: None
+      description: The request object. Request for the ModifyAckDeadline method.
+      id: request
+      var_type: Union[google.pubsub_v1.types.ModifyAckDeadlineRequest, dict]
+    - description: Required. The name of the subscription. Format is projects/{project}/subscriptions/{sub}.
+        This corresponds to the subscription field on the request
+        instance; if request is provided, this should not be set.
+      id: subscription
+      var_type: str
+    - description: Required. List of acknowledgment IDs. This corresponds to the ack_ids
+        field on the request instance; if request is provided,
+        this should not be set.
+      id: ack_ids
+      var_type: Sequence[str]
+    - description: Required. The new ack deadline with respect to the time this request
+        was sent to the Pub/Sub system. For example, if the value is 10, the new ack
+        deadline will expire 10 seconds after the ModifyAckDeadline call
+        was made. Specifying zero might immediately make the message available for
+        delivery to another subscriber client. This typically results in an increase
+        in the rate of message redeliveries (that is, duplicates). The minimum deadline
+        you can specify is 0 seconds. The maximum deadline you can specify is 600
+        seconds (10 minutes). This corresponds to the ack_deadline_seconds
+        field on the request instance; if request is provided,
+        this should not be set.
+      id: ack_deadline_seconds
+      var_type: int
+    - description: Designation of what errors, if any, should be retried.
+      id: retry
+      var_type: google.api_core.retry.Retry
+    - description: The timeout for this request.
+      id: timeout
+      var_type: float
+    - description: Strings which should be sent along with the request as metadata.
+      id: metadata
+      var_type: Sequence[Tuple[str, str]]
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.modify_ack_deadline
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.client.Client
+  fullName: google.cloud.pubsub_v1.subscriber.client.Client.modify_push_config
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.client
+  name: modify_push_config
+  source:
+    id: modify_push_config
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 1550
+  summary: "Modifies the `PushConfig` for a specified subscription.\n\nThis may be\
+    \ used to change a push subscription to a pull one\n(signified by an empty `PushConfig`)\
+    \ or vice versa, or change\nthe endpoint URL and other attributes of a push subscription.\n\
+    Messages will accumulate for delivery continuously through the\ncall regardless\
+    \ of changes to the `PushConfig`.\n\n```python\n# This snippet has been automatically\
+    \ generated and should be regarded as a\n# code template only.\n# It will require\
+    \ modifications to work:\n# - It may require correct/in-range values for request\
+    \ initialization.\n# - It may require specifying regional endpoints when creating\
+    \ the service\n#   client as shown in:\n#   https://googleapis.dev/python/google-api-core/latest/client_options.html\n\
+    from google import pubsub_v1\n\ndef sample_modify_push_config():\n    # Create\
+    \ a client\n    client = pubsub_v1.SubscriberClient()\n\n    # Initialize request\
+    \ argument(s)\n    request = pubsub_v1.ModifyPushConfigRequest(\n        subscription=\"\
+    subscription_value\",\n    )\n\n    # Make the request\n    client.modify_push_config(request=request)\n\
+    ```\n"
+  syntax:
+    content: "modify_push_config(\n    request: typing.Optional[\n        typing.Union[google.cloud.pubsub_v1.types.ModifyPushConfigRequest,\
+      \ dict]\n    ] = None,\n    *,\n    subscription: typing.Optional[str] = None,\n\
+      \    push_config: typing.Optional[google.cloud.pubsub_v1.types.PushConfig] =\
+      \ None,\n    retry: typing.Union[\n        google.api_core.retry.Retry, google.api_core.gapic_v1.method._MethodDefault\n\
+      \    ] = _MethodDefault._DEFAULT_VALUE,\n    timeout: typing.Optional[float]\
+      \ = None,\n    metadata: typing.Sequence[typing.Tuple[str, str]] = ()\n)"
+    parameters:
+    - defaultValue: None
+      description: The request object. Request for the ModifyPushConfig method.
+      id: request
+      var_type: Union[google.pubsub_v1.types.ModifyPushConfigRequest, dict]
+    - description: Required. The name of the subscription. Format is projects/{project}/subscriptions/{sub}.
+        This corresponds to the subscription field on the request
+        instance; if request is provided, this should not be set.
+      id: subscription
+      var_type: str
+    - description: Required. The push configuration for future deliveries. An empty
+        pushConfig indicates that the Pub/Sub system should stop pushing
+        messages from the given subscription and allow messages to be pulled and acknowledged
+        - effectively pausing the subscription if Pull or StreamingPull
+        is not called. This corresponds to the push_config field on the
+        request instance; if request is provided, this should
+        not be set.
+      id: push_config
+      var_type: google.pubsub_v1.types.PushConfig
+    - description: Designation of what errors, if any, should be retried.
+      id: retry
+      var_type: google.api_core.retry.Retry
+    - description: The timeout for this request.
+      id: timeout
+      var_type: float
+    - description: Strings which should be sent along with the request as metadata.
+      id: metadata
+      var_type: Sequence[Tuple[str, str]]
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.modify_push_config
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.client.Client
+  fullName: google.cloud.pubsub_v1.subscriber.client.Client.parse_common_billing_account_path
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.client
+  name: parse_common_billing_account_path
+  source:
+    id: parse_common_billing_account_path
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 257
+  summary: 'Parse a billing_account path into its component segments.
+
+
+    '
+  syntax:
+    content: 'parse_common_billing_account_path(path: str)'
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.parse_common_billing_account_path
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.client.Client
+  fullName: google.cloud.pubsub_v1.subscriber.client.Client.parse_common_folder_path
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.client
+  name: parse_common_folder_path
+  source:
+    id: parse_common_folder_path
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 272
+  summary: 'Parse a folder path into its component segments.
+
+
+    '
+  syntax:
+    content: 'parse_common_folder_path(path: str)'
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.parse_common_folder_path
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.client.Client
+  fullName: google.cloud.pubsub_v1.subscriber.client.Client.parse_common_location_path
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.client
+  name: parse_common_location_path
+  source:
+    id: parse_common_location_path
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 319
+  summary: 'Parse a location path into its component segments.
+
+
+    '
+  syntax:
+    content: 'parse_common_location_path(path: str)'
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.parse_common_location_path
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.client.Client
+  fullName: google.cloud.pubsub_v1.subscriber.client.Client.parse_common_organization_path
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.client
+  name: parse_common_organization_path
+  source:
+    id: parse_common_organization_path
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 287
+  summary: 'Parse a organization path into its component segments.
+
+
+    '
+  syntax:
+    content: 'parse_common_organization_path(path: str)'
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.parse_common_organization_path
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.client.Client
+  fullName: google.cloud.pubsub_v1.subscriber.client.Client.parse_common_project_path
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.client
+  name: parse_common_project_path
+  source:
+    id: parse_common_project_path
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 302
+  summary: 'Parse a project path into its component segments.
+
+
+    '
+  syntax:
+    content: 'parse_common_project_path(path: str)'
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.parse_common_project_path
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.client.Client
+  fullName: google.cloud.pubsub_v1.subscriber.client.Client.parse_snapshot_path
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.client
+  name: parse_snapshot_path
+  source:
+    id: parse_snapshot_path
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 206
+  summary: 'Parses a snapshot path into its component segments.
+
+
+    '
+  syntax:
+    content: 'parse_snapshot_path(path: str)'
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.parse_snapshot_path
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.client.Client
+  fullName: google.cloud.pubsub_v1.subscriber.client.Client.parse_subscription_path
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.client
+  name: parse_subscription_path
+  source:
+    id: parse_subscription_path
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 223
+  summary: 'Parses a subscription path into its component segments.
+
+
+    '
+  syntax:
+    content: 'parse_subscription_path(path: str)'
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.parse_subscription_path
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.client.Client
+  fullName: google.cloud.pubsub_v1.subscriber.client.Client.parse_topic_path
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.client
+  name: parse_topic_path
+  source:
+    id: parse_topic_path
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 242
+  summary: 'Parses a topic path into its component segments.
+
+
+    '
+  syntax:
+    content: 'parse_topic_path(path: str)'
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.parse_topic_path
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.client.Client
+  fullName: google.cloud.pubsub_v1.subscriber.client.Client.pull
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.client
+  name: pull
+  source:
+    id: pull
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 1314
+  summary: "Pulls messages from the server. The server may return\n`UNAVAILABLE` if\
+    \ there are too many concurrent pull requests\npending for the given subscription.\n\
+    \n```python\n# This snippet has been automatically generated and should be regarded\
+    \ as a\n# code template only.\n# It will require modifications to work:\n# - It\
+    \ may require correct/in-range values for request initialization.\n# - It may\
+    \ require specifying regional endpoints when creating the service\n#   client\
+    \ as shown in:\n#   https://googleapis.dev/python/google-api-core/latest/client_options.html\n\
+    from google import pubsub_v1\n\ndef sample_pull():\n    # Create a client\n  \
+    \  client = pubsub_v1.SubscriberClient()\n\n    # Initialize request argument(s)\n\
+    \    request = pubsub_v1.PullRequest(\n        subscription=\"subscription_value\"\
+    ,\n        max_messages=1277,\n    )\n\n    # Make the request\n    response =\
+    \ client.pull(request=request)\n\n    # Handle the response\n    print(response)\n\
+    ```\n"
+  syntax:
+    content: "pull(\n    request: typing.Optional[\n        typing.Union[google.cloud.pubsub_v1.types.PullRequest,\
+      \ dict]\n    ] = None,\n    *,\n    subscription: typing.Optional[str] = None,\n\
+      \    return_immediately: typing.Optional[bool] = None,\n    max_messages: typing.Optional[int]\
+      \ = None,\n    retry: typing.Union[\n        google.api_core.retry.Retry, google.api_core.gapic_v1.method._MethodDefault\n\
+      \    ] = _MethodDefault._DEFAULT_VALUE,\n    timeout: typing.Optional[float]\
+      \ = None,\n    metadata: typing.Sequence[typing.Tuple[str, str]] = ()\n)"
+    parameters:
+    - defaultValue: None
+      description: The request object. Request for the Pull method.
+      id: request
+      var_type: Union[google.pubsub_v1.types.PullRequest, dict]
+    - description: Required. The subscription from which messages should be pulled.
+        Format is projects/{project}/subscriptions/{sub}. This corresponds
+        to the subscription field on the request instance;
+        if request is provided, this should not be set.
+      id: subscription
+      var_type: str
+    - description: 'Optional. If this field set to true, the system will respond immediately
+        even if it there are no messages available to return in the Pull
+        response. Otherwise, the system may wait (for a bounded amount of time) until
+        at least one message is available, rather than returning no messages. Warning:
+        setting this field to true is discouraged because it adversely
+        impacts the performance of Pull operations. We recommend that
+        users do not set this field. This corresponds to the return_immediately
+        field on the request instance; if request is provided,
+        this should not be set.'
+      id: return_immediately
+      var_type: bool
+    - description: Required. The maximum number of messages to return for this request.
+        Must be a positive integer. The Pub/Sub system may return fewer than the number
+        specified. This corresponds to the max_messages field on the
+        request instance; if request is provided, this should
+        not be set.
+      id: max_messages
+      var_type: int
+    - description: Designation of what errors, if any, should be retried.
+      id: retry
+      var_type: google.api_core.retry.Retry
+    - description: The timeout for this request.
+      id: timeout
+      var_type: float
+    - description: Strings which should be sent along with the request as metadata.
+      id: metadata
+      var_type: Sequence[Tuple[str, str]]
+    returns:
+    - description: Response for the Pull method.
+      var_type: google.pubsub_v1.types.PullResponse
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.pull
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.client.Client
+  fullName: google.cloud.pubsub_v1.subscriber.client.Client.seek
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.client
+  name: seek
+  source:
+    id: seek
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 2232
+  summary: "Seeks an existing subscription to a point in time or to a given\nsnapshot,\
+    \ whichever is provided in the request. Snapshots are\nused in [Seek]\n(https://cloud.google.com/pubsub/docs/replay-overview)\n\
+    operations, which allow you to manage message acknowledgments in\nbulk. That is,\
+    \ you can set the acknowledgment state of messages\nin an existing subscription\
+    \ to the state captured by a snapshot.\nNote that both the subscription and the\
+    \ snapshot must be on the\nsame topic.\n\n```python\n# This snippet has been automatically\
+    \ generated and should be regarded as a\n# code template only.\n# It will require\
+    \ modifications to work:\n# - It may require correct/in-range values for request\
+    \ initialization.\n# - It may require specifying regional endpoints when creating\
+    \ the service\n#   client as shown in:\n#   https://googleapis.dev/python/google-api-core/latest/client_options.html\n\
+    from google import pubsub_v1\n\ndef sample_seek():\n    # Create a client\n  \
+    \  client = pubsub_v1.SubscriberClient()\n\n    # Initialize request argument(s)\n\
+    \    request = pubsub_v1.SeekRequest(\n        subscription=\"subscription_value\"\
+    ,\n    )\n\n    # Make the request\n    response = client.seek(request=request)\n\
+    \n    # Handle the response\n    print(response)\n```\n"
+  syntax:
+    content: "seek(\n    request: typing.Optional[\n        typing.Union[google.cloud.pubsub_v1.types.SeekRequest,\
+      \ dict]\n    ] = None,\n    *,\n    retry: typing.Union[\n        google.api_core.retry.Retry,\
+      \ google.api_core.gapic_v1.method._MethodDefault\n    ] = _MethodDefault._DEFAULT_VALUE,\n\
+      \    timeout: typing.Optional[float] = None,\n    metadata: typing.Sequence[typing.Tuple[str,\
+      \ str]] = ()\n)"
+    parameters:
+    - defaultValue: None
+      description: The request object. Request for the Seek method.
+      id: request
+      var_type: Union[google.pubsub_v1.types.SeekRequest, dict]
+    - description: Designation of what errors, if any, should be retried.
+      id: retry
+      var_type: google.api_core.retry.Retry
+    - description: The timeout for this request.
+      id: timeout
+      var_type: float
+    - description: Strings which should be sent along with the request as metadata.
+      id: metadata
+      var_type: Sequence[Tuple[str, str]]
+    returns:
+    - description: Response for the Seek method (this response is empty).
+      var_type: google.pubsub_v1.types.SeekResponse
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.seek
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.client.Client
+  fullName: google.cloud.pubsub_v1.subscriber.client.Client.set_iam_policy
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.client
+  name: set_iam_policy
+  source:
+    id: set_iam_policy
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 2333
+  summary: 'Sets the IAM access control policy on the specified function.
+
+
+    Replaces any existing policy.
+
+    '
+  syntax:
+    content: "set_iam_policy(\n    request: typing.Optional[google.iam.v1.iam_policy_pb2.SetIamPolicyRequest]\
+      \ = None,\n    *,\n    retry: typing.Union[\n        google.api_core.retry.Retry,\
+      \ google.api_core.gapic_v1.method._MethodDefault\n    ] = _MethodDefault._DEFAULT_VALUE,\n\
+      \    timeout: typing.Optional[float] = None,\n    metadata: typing.Sequence[typing.Tuple[str,\
+      \ str]] = ()\n)"
+    parameters:
+    - defaultValue: None
+      description: The request object. Request message for SetIamPolicy
+        method.
+      id: request
+      var_type: .iam_policy_pb2.SetIamPolicyRequest
+    - description: Designation of what errors, if any, should be retried.
+      id: retry
+      var_type: google.api_core.retry.Retry
+    - description: The timeout for this request.
+      id: timeout
+      var_type: float
+    - description: Strings which should be sent along with the request as metadata.
+      id: metadata
+      var_type: Sequence[Tuple[str, str]]
+    returns:
+    - description: 'Defines an Identity and Access Management (IAM) policy. It is
+        used to specify access control policies for Cloud Platform resources. A Policy
+        is a collection of bindings. A binding binds one
+        or more members to a single role. Members can be
+        user accounts, service accounts, Google groups, and domains (such as G Suite).
+        A role is a named list of permissions (defined by IAM or configured
+        by users). A binding can optionally specify a condition,
+        which is a logic expression that further constrains the role binding based
+        on attributes about the request and/or target resource. **JSON Example** ::
+        { "bindings": [ { "role": "roles/resourcemanager.organizationAdmin", "members":
+        [ "user:mike@example.com", "group:admins@example.com", "domain:google.com",
+        "serviceAccount:my-project-id@appspot.gserviceaccount.com" ] }, { "role":
+        "roles/resourcemanager.organizationViewer", "members": ["user:eve@example.com"],
+        "condition": { "title": "expirable access", "description": "Does not grant
+        access after Sep 2020", "expression": "request.time < timestamp(''2020-10-01T00:00:00.000Z'')",
+        } } ] } **YAML Example** :: bindings: - members: - user:mike@example.com -
+        group:admins@example.com - domain:google.com - serviceAccount:my-project-id@appspot.gserviceaccount.com
+        role: roles/resourcemanager.organizationAdmin - members: - user:eve@example.com
+        role: roles/resourcemanager.organizationViewer condition: title: expirable
+        access description: Does not grant access after Sep 2020 expression: request.time
+        < timestamp(''2020-10-01T00:00:00.000Z'') For a description of IAM and its
+        features, see the IAM developer''s guide __.'
+      var_type: .policy_pb2.Policy
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.set_iam_policy
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.client.Client
+  fullName: google.cloud.pubsub_v1.subscriber.client.Client.snapshot_path
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.client
+  name: snapshot_path
+  source:
+    id: snapshot_path
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 195
+  summary: 'Returns a fully-qualified snapshot string.
+
+
+    '
+  syntax:
+    content: 'snapshot_path(project: str, snapshot: str)'
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.snapshot_path
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.client.Client
+  fullName: google.cloud.pubsub_v1.subscriber.client.Client.streaming_pull
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.client
+  name: streaming_pull
+  source:
+    id: streaming_pull
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 1455
+  summary: "Establishes a stream with the server, which sends messages down\nto the\
+    \ client. The client streams acknowledgements and ack\ndeadline modifications\
+    \ back to the server. The server will close\nthe stream and return the status\
+    \ on any error. The server may\nclose the stream with status `UNAVAILABLE` to\
+    \ reassign\nserver-side resources, in which case, the client should\nre-establish\
+    \ the stream. Flow control can be achieved by\nconfiguring the underlying RPC\
+    \ channel.\n\n```python\n# This snippet has been automatically generated and should\
+    \ be regarded as a\n# code template only.\n# It will require modifications to\
+    \ work:\n# - It may require correct/in-range values for request initialization.\n\
+    # - It may require specifying regional endpoints when creating the service\n#\
+    \   client as shown in:\n#   https://googleapis.dev/python/google-api-core/latest/client_options.html\n\
+    from google import pubsub_v1\n\ndef sample_streaming_pull():\n    # Create a client\n\
+    \    client = pubsub_v1.SubscriberClient()\n\n    # Initialize request argument(s)\n\
+    \    request = pubsub_v1.StreamingPullRequest(\n        subscription=\"subscription_value\"\
+    ,\n        stream_ack_deadline_seconds=2813,\n    )\n\n    # This method expects\
+    \ an iterator which contains\n    # 'pubsub_v1.StreamingPullRequest' objects\n\
+    \    # Here we create a generator that yields a single `request` for\n    # demonstrative\
+    \ purposes.\n    requests = [request]\n\n    def request_generator():\n      \
+    \  for request in requests:\n            yield request\n\n    # Make the request\n\
+    \    stream = client.streaming_pull(requests=request_generator())\n\n    # Handle\
+    \ the response\n    for response in stream:\n        print(response)\n```\n"
+  syntax:
+    content: "streaming_pull(\n    requests: typing.Optional[\n        typing.Iterator[google.cloud.pubsub_v1.types.StreamingPullRequest]\n\
+      \    ] = None,\n    *,\n    retry: typing.Union[\n        google.api_core.retry.Retry,\
+      \ google.api_core.gapic_v1.method._MethodDefault\n    ] = _MethodDefault._DEFAULT_VALUE,\n\
+      \    timeout: typing.Optional[float] = None,\n    metadata: typing.Sequence[typing.Tuple[str,\
+      \ str]] = ()\n)"
+    parameters:
+    - defaultValue: None
+      description: The request object iterator. Request for the StreamingPull
+        streaming RPC method. This request is used to establish the initial stream
+        as well as to stream acknowledgements and ack deadline modifications from
+        the client to the server.
+      id: requests
+      var_type: Iterator[google.pubsub_v1.types.StreamingPullRequest]
+    - description: Designation of what errors, if any, should be retried.
+      id: retry
+      var_type: google.api_core.retry.Retry
+    - description: The timeout for this request.
+      id: timeout
+      var_type: float
+    - description: Strings which should be sent along with the request as metadata.
+      id: metadata
+      var_type: Sequence[Tuple[str, str]]
+    returns:
+    - description: Response for the StreamingPull method. This response is used to
+        stream messages from the server to the client.
+      var_type: Iterable[google.pubsub_v1.types.StreamingPullResponse]
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.streaming_pull
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.client.Client
+  fullName: google.cloud.pubsub_v1.subscriber.client.Client.subscribe
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.client
+  name: subscribe
+  source:
+    id: subscribe
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/client.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/client.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 149
+  summary: "Asynchronously start receiving messages on a given subscription.\n\nThis\
+    \ method starts a background thread to begin pulling messages from\na Pub/Sub\
+    \ subscription and scheduling them to be processed using the\nprovided `callback`.\n\
+    \nThe `callback` will be called with an individual\nxref_Message. It is the\n\
+    responsibility of the callback to either call `ack()` or `nack()`\non the message\
+    \ when it finished processing. If an exception occurs in\nthe callback during\
+    \ processing, the exception is logged and the message\nis `nack()` ed.\n\nThe\
+    \ `flow_control` argument can be used to control the rate of at\nwhich messages\
+    \ are pulled. The settings are relatively conservative by\ndefault to prevent\
+    \ \"message hoarding\" - a situation where the client\npulls a large number of\
+    \ messages but can not process them fast enough\nleading it to \"starve\" other\
+    \ clients of messages. Increasing these\nsettings may lead to faster throughput\
+    \ for messages that do not take\na long time to process.\n\nThe `use_legacy_flow_control`\
+    \ argument disables enforcing flow control\nsettings at the Cloud Pub/Sub server,\
+    \ and only the client side flow control\nwill be enforced.\n\nThis method starts\
+    \ the receiver in the background and returns a\n*Future* representing its execution.\
+    \ Waiting on the future (calling\n`result()`) will block forever or until a non-recoverable\
+    \ error\nis encountered (such as loss of network connectivity). Cancelling the\n\
+    future will signal the process to shutdown gracefully and exit.\n\n\n\
+    Example:\n\n```python\nfrom google.cloud import pubsub_v1\n\nsubscriber_client\
+    \ = pubsub_v1.SubscriberClient()\n\n# existing subscription\nsubscription = subscriber_client.subscription_path(\n\
+    \    'my-project-id', 'my-subscription')\n\ndef callback(message):\n    print(message)\n\
+    \    message.ack()\n\nfuture = subscriber_client.subscribe(\n    subscription,\
+    \ callback)\n\ntry:\n    future.result()\nexcept KeyboardInterrupt:\n    future.cancel()\
+    \  # Trigger the shutdown.\n    future.result()  # Block until the shutdown is\
+    \ complete.\n```\n"
+  syntax:
+    content: "subscribe(\n    subscription: str,\n    callback: typing.Callable[[subscriber.message.Message],\
+      \ typing.Any],\n    flow_control: typing.Union[\n        google.cloud.pubsub_v1.types.FlowControl,\
+      \ typing.Sequence\n    ] = (),\n    scheduler: typing.Optional[subscriber.scheduler.ThreadScheduler]\
+      \ = None,\n    use_legacy_flow_control: bool = False,\n    await_callbacks_on_shutdown:\
+      \ bool = False,\n)"
+    parameters:
+    - defaultValue: 'False'
+      description: If set to True, flow control at the Cloud Pub/Sub
+        server is disabled, though client-side flow control is still enabled. If set
+        to False (default), both server-side and client-side flow control
+        are enabled.
+      id: use_legacy_flow_control
+      var_type: bool
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.subscribe
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.client.Client
+  fullName: google.cloud.pubsub_v1.subscriber.client.Client.subscription_path
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.client
+  name: subscription_path
+  source:
+    id: subscription_path
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 212
+  summary: 'Returns a fully-qualified subscription string.
+
+
+    '
+  syntax:
+    content: 'subscription_path(project: str, subscription: str)'
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.subscription_path
+- &id003
+  attributes: []
+  class: google.cloud.pubsub_v1.subscriber.client.Client
+  fullName: google.cloud.pubsub_v1.subscriber.client.Client.target
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.client
+  name: target
+  source:
+    id: target
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Return the target (where the API is).
+
+    '
+  syntax: {}
+  type: property
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.target
+- *id003
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.client.Client
+  fullName: google.cloud.pubsub_v1.subscriber.client.Client.test_iam_permissions
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.client
+  name: test_iam_permissions
+  source:
+    id: test_iam_permissions
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 2574
+  summary: "Tests the specified IAM permissions against the IAM access control\n \
+    \   policy for a function.\n\nIf the function does not exist, this will return\
+    \ an empty set\nof permissions, not a NOT_FOUND error.\n"
+  syntax:
+    content: "test_iam_permissions(\n    request: typing.Optional[\n        google.iam.v1.iam_policy_pb2.TestIamPermissionsRequest\n\
+      \    ] = None,\n    *,\n    retry: typing.Union[\n        google.api_core.retry.Retry,\
+      \ google.api_core.gapic_v1.method._MethodDefault\n    ] = _MethodDefault._DEFAULT_VALUE,\n\
+      \    timeout: typing.Optional[float] = None,\n    metadata: typing.Sequence[typing.Tuple[str,\
+      \ str]] = ()\n)"
+    parameters:
+    - defaultValue: None
+      description: The request object. Request message for TestIamPermissions
+        method.
+      id: request
+      var_type: .iam_policy_pb2.TestIamPermissionsRequest
+    - description: Designation of what errors, if any, should be retried.
+      id: retry
+      var_type: google.api_core.retry.Retry
+    - description: The timeout for this request.
+      id: timeout
+      var_type: float
+    - description: Strings which should be sent along with the request as metadata.
+      id: metadata
+      var_type: Sequence[Tuple[str, str]]
+    returns:
+    - description: Response message for TestIamPermissions method.
+      var_type: .iam_policy_pb2.TestIamPermissionsResponse
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.test_iam_permissions
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.client.Client
+  fullName: google.cloud.pubsub_v1.subscriber.client.Client.topic_path
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.client
+  name: topic_path
+  source:
+    id: topic_path
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 231
+  summary: 'Returns a fully-qualified topic string.
+
+
+    '
+  syntax:
+    content: 'topic_path(project: str, topic: str)'
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.topic_path
+- &id004
+  attributes: []
+  class: google.cloud.pubsub_v1.subscriber.client.Client
+  fullName: google.cloud.pubsub_v1.subscriber.client.Client.transport
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.client
+  name: transport
+  source:
+    id: transport
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Returns the transport used by the client instance.
+
+    '
+  syntax:
+    returns:
+    - description: The transport used by the client instance.
+      var_type: SubscriberTransport
+  type: property
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.transport
+- *id004
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.client.Client
+  fullName: google.cloud.pubsub_v1.subscriber.client.Client.update_snapshot
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.client
+  name: update_snapshot
+  source:
+    id: update_snapshot
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 2040
+  summary: "Updates an existing snapshot. Snapshots are used in\nSeek\noperations, which allow\nyou to manage message acknowledgments in bulk.\
+    \ That is,\nyou can set the acknowledgment state of messages in an\nexisting subscription\
+    \ to the state captured by a\nsnapshot.\n\n```python\n# This snippet has been\
+    \ automatically generated and should be regarded as a\n# code template only.\n\
+    # It will require modifications to work:\n# - It may require correct/in-range\
+    \ values for request initialization.\n# - It may require specifying regional endpoints\
+    \ when creating the service\n#   client as shown in:\n#   https://googleapis.dev/python/google-api-core/latest/client_options.html\n\
+    from google import pubsub_v1\n\ndef sample_update_snapshot():\n    # Create a\
+    \ client\n    client = pubsub_v1.SubscriberClient()\n\n    # Initialize request\
+    \ argument(s)\n    request = pubsub_v1.UpdateSnapshotRequest(\n    )\n\n    #\
+    \ Make the request\n    response = client.update_snapshot(request=request)\n\n\
+    \    # Handle the response\n    print(response)\n```\n"
+  syntax:
+    content: "update_snapshot(\n    request: typing.Optional[\n        typing.Union[google.cloud.pubsub_v1.types.UpdateSnapshotRequest,\
+      \ dict]\n    ] = None,\n    *,\n    retry: typing.Union[\n        google.api_core.retry.Retry,\
+      \ google.api_core.gapic_v1.method._MethodDefault\n    ] = _MethodDefault._DEFAULT_VALUE,\n\
+      \    timeout: typing.Optional[float] = None,\n    metadata: typing.Sequence[typing.Tuple[str,\
+      \ str]] = ()\n)"
+    parameters:
+    - defaultValue: None
+      description: The request object. Request for the UpdateSnapshot method.
+      id: request
+      var_type: Union[google.pubsub_v1.types.UpdateSnapshotRequest, dict]
+    - description: Designation of what errors, if any, should be retried.
+      id: retry
+      var_type: google.api_core.retry.Retry
+    - description: The timeout for this request.
+      id: timeout
+      var_type: float
+    - description: Strings which should be sent along with the request as metadata.
+      id: metadata
+      var_type: Sequence[Tuple[str, str]]
+    returns:
+    - description: A snapshot resource. Snapshots are used in [Seek](https://cloud.google.com/pubsub/docs/replay-overview)
+        operations, which allow you to manage message acknowledgments in bulk. That
+        is, you can set the acknowledgment state of messages in an existing subscription
+        to the state captured by a snapshot.
+      var_type: google.pubsub_v1.types.Snapshot
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.update_snapshot
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.client.Client
+  fullName: google.cloud.pubsub_v1.subscriber.client.Client.update_subscription
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.client
+  name: update_subscription
+  source:
+    id: update_subscription
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/client.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 779
+  summary: "Updates an existing subscription. Note that certain\nproperties of a subscription,\
+    \ such as its topic, are not\nmodifiable.\n\n```python\n# This snippet has been\
+    \ automatically generated and should be regarded as a\n# code template only.\n\
+    # It will require modifications to work:\n# - It may require correct/in-range\
+    \ values for request initialization.\n# - It may require specifying regional endpoints\
+    \ when creating the service\n#   client as shown in:\n#   https://googleapis.dev/python/google-api-core/latest/client_options.html\n\
+    from google import pubsub_v1\n\ndef sample_update_subscription():\n    # Create\
+    \ a client\n    client = pubsub_v1.SubscriberClient()\n\n    # Initialize request\
+    \ argument(s)\n    subscription = pubsub_v1.Subscription()\n    subscription.name\
+    \ = \"name_value\"\n    subscription.topic = \"topic_value\"\n\n    request =\
+    \ pubsub_v1.UpdateSubscriptionRequest(\n        subscription=subscription,\n \
+    \   )\n\n    # Make the request\n    response = client.update_subscription(request=request)\n\
+    \n    # Handle the response\n    print(response)\n```\n"
+  syntax:
+    content: "update_subscription(\n    request: typing.Optional[\n        typing.Union[google.cloud.pubsub_v1.types.UpdateSubscriptionRequest,\
+      \ dict]\n    ] = None,\n    *,\n    retry: typing.Union[\n        google.api_core.retry.Retry,\
+      \ google.api_core.gapic_v1.method._MethodDefault\n    ] = _MethodDefault._DEFAULT_VALUE,\n\
+      \    timeout: typing.Optional[float] = None,\n    metadata: typing.Sequence[typing.Tuple[str,\
+      \ str]] = ()\n)"
+    parameters:
+    - defaultValue: None
+      description: The request object. Request for the UpdateSubscription method.
+      id: request
+      var_type: Union[google.pubsub_v1.types.UpdateSubscriptionRequest, dict]
+    - description: Designation of what errors, if any, should be retried.
+      id: retry
+      var_type: google.api_core.retry.Retry
+    - description: The timeout for this request.
+      id: timeout
+      var_type: float
+    - description: Strings which should be sent along with the request as metadata.
+      id: metadata
+      var_type: Sequence[Tuple[str, str]]
+    returns:
+    - description: A subscription resource.
+      var_type: google.pubsub_v1.types.Subscription
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.update_subscription
+references:
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client
+  isExternal: false
+  name: Client
+  parent: google.cloud.pubsub_v1.subscriber.client.Client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client.acknowledge
+  isExternal: false
+  name: acknowledge
+  parent: google.cloud.pubsub_v1.subscriber.client.Client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.acknowledge
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client.api
+  isExternal: false
+  name: api
+  parent: google.cloud.pubsub_v1.subscriber.client.Client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.api
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client.close
+  isExternal: false
+  name: close
+  parent: google.cloud.pubsub_v1.subscriber.client.Client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.close
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client.closed
+  isExternal: false
+  name: closed
+  parent: google.cloud.pubsub_v1.subscriber.client.Client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.closed
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client.common_billing_account_path
+  isExternal: false
+  name: common_billing_account_path
+  parent: google.cloud.pubsub_v1.subscriber.client.Client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.common_billing_account_path
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client.common_folder_path
+  isExternal: false
+  name: common_folder_path
+  parent: google.cloud.pubsub_v1.subscriber.client.Client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.common_folder_path
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client.common_location_path
+  isExternal: false
+  name: common_location_path
+  parent: google.cloud.pubsub_v1.subscriber.client.Client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.common_location_path
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client.common_organization_path
+  isExternal: false
+  name: common_organization_path
+  parent: google.cloud.pubsub_v1.subscriber.client.Client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.common_organization_path
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client.common_project_path
+  isExternal: false
+  name: common_project_path
+  parent: google.cloud.pubsub_v1.subscriber.client.Client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.common_project_path
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client.create_snapshot
+  isExternal: false
+  name: create_snapshot
+  parent: google.cloud.pubsub_v1.subscriber.client.Client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.create_snapshot
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client.create_subscription
+  isExternal: false
+  name: create_subscription
+  parent: google.cloud.pubsub_v1.subscriber.client.Client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.create_subscription
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client.delete_snapshot
+  isExternal: false
+  name: delete_snapshot
+  parent: google.cloud.pubsub_v1.subscriber.client.Client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.delete_snapshot
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client.delete_subscription
+  isExternal: false
+  name: delete_subscription
+  parent: google.cloud.pubsub_v1.subscriber.client.Client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.delete_subscription
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client.from_service_account_file
+  isExternal: false
+  name: from_service_account_file
+  parent: google.cloud.pubsub_v1.subscriber.client.Client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.from_service_account_file
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client.from_service_account_info
+  isExternal: false
+  name: from_service_account_info
+  parent: google.cloud.pubsub_v1.subscriber.client.Client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.from_service_account_info
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client.from_service_account_json
+  isExternal: false
+  name: from_service_account_json
+  parent: google.cloud.pubsub_v1.subscriber.client.Client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.from_service_account_json
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client.get_iam_policy
+  isExternal: false
+  name: get_iam_policy
+  parent: google.cloud.pubsub_v1.subscriber.client.Client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.get_iam_policy
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client.get_mtls_endpoint_and_cert_source
+  isExternal: false
+  name: get_mtls_endpoint_and_cert_source
+  parent: google.cloud.pubsub_v1.subscriber.client.Client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.get_mtls_endpoint_and_cert_source
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client.get_snapshot
+  isExternal: false
+  name: get_snapshot
+  parent: google.cloud.pubsub_v1.subscriber.client.Client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.get_snapshot
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client.get_subscription
+  isExternal: false
+  name: get_subscription
+  parent: google.cloud.pubsub_v1.subscriber.client.Client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.get_subscription
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client.list_snapshots
+  isExternal: false
+  name: list_snapshots
+  parent: google.cloud.pubsub_v1.subscriber.client.Client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.list_snapshots
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client.list_subscriptions
+  isExternal: false
+  name: list_subscriptions
+  parent: google.cloud.pubsub_v1.subscriber.client.Client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.list_subscriptions
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client.modify_ack_deadline
+  isExternal: false
+  name: modify_ack_deadline
+  parent: google.cloud.pubsub_v1.subscriber.client.Client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.modify_ack_deadline
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client.modify_push_config
+  isExternal: false
+  name: modify_push_config
+  parent: google.cloud.pubsub_v1.subscriber.client.Client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.modify_push_config
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client.parse_common_billing_account_path
+  isExternal: false
+  name: parse_common_billing_account_path
+  parent: google.cloud.pubsub_v1.subscriber.client.Client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.parse_common_billing_account_path
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client.parse_common_folder_path
+  isExternal: false
+  name: parse_common_folder_path
+  parent: google.cloud.pubsub_v1.subscriber.client.Client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.parse_common_folder_path
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client.parse_common_location_path
+  isExternal: false
+  name: parse_common_location_path
+  parent: google.cloud.pubsub_v1.subscriber.client.Client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.parse_common_location_path
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client.parse_common_organization_path
+  isExternal: false
+  name: parse_common_organization_path
+  parent: google.cloud.pubsub_v1.subscriber.client.Client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.parse_common_organization_path
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client.parse_common_project_path
+  isExternal: false
+  name: parse_common_project_path
+  parent: google.cloud.pubsub_v1.subscriber.client.Client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.parse_common_project_path
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client.parse_snapshot_path
+  isExternal: false
+  name: parse_snapshot_path
+  parent: google.cloud.pubsub_v1.subscriber.client.Client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.parse_snapshot_path
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client.parse_subscription_path
+  isExternal: false
+  name: parse_subscription_path
+  parent: google.cloud.pubsub_v1.subscriber.client.Client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.parse_subscription_path
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client.parse_topic_path
+  isExternal: false
+  name: parse_topic_path
+  parent: google.cloud.pubsub_v1.subscriber.client.Client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.parse_topic_path
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client.pull
+  isExternal: false
+  name: pull
+  parent: google.cloud.pubsub_v1.subscriber.client.Client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.pull
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client.seek
+  isExternal: false
+  name: seek
+  parent: google.cloud.pubsub_v1.subscriber.client.Client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.seek
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client.set_iam_policy
+  isExternal: false
+  name: set_iam_policy
+  parent: google.cloud.pubsub_v1.subscriber.client.Client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.set_iam_policy
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client.snapshot_path
+  isExternal: false
+  name: snapshot_path
+  parent: google.cloud.pubsub_v1.subscriber.client.Client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.snapshot_path
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client.streaming_pull
+  isExternal: false
+  name: streaming_pull
+  parent: google.cloud.pubsub_v1.subscriber.client.Client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.streaming_pull
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client.subscribe
+  isExternal: false
+  name: subscribe
+  parent: google.cloud.pubsub_v1.subscriber.client.Client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.subscribe
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client.subscription_path
+  isExternal: false
+  name: subscription_path
+  parent: google.cloud.pubsub_v1.subscriber.client.Client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.subscription_path
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client.target
+  isExternal: false
+  name: target
+  parent: google.cloud.pubsub_v1.subscriber.client.Client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.target
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client.test_iam_permissions
+  isExternal: false
+  name: test_iam_permissions
+  parent: google.cloud.pubsub_v1.subscriber.client.Client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.test_iam_permissions
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client.topic_path
+  isExternal: false
+  name: topic_path
+  parent: google.cloud.pubsub_v1.subscriber.client.Client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.topic_path
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client.transport
+  isExternal: false
+  name: transport
+  parent: google.cloud.pubsub_v1.subscriber.client.Client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.transport
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client.update_snapshot
+  isExternal: false
+  name: update_snapshot
+  parent: google.cloud.pubsub_v1.subscriber.client.Client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.update_snapshot
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client.update_subscription
+  isExternal: false
+  name: update_subscription
+  parent: google.cloud.pubsub_v1.subscriber.client.Client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client.update_subscription
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.subscriber.client.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.subscriber.client.yml
new file mode 100644
index 000000000000..ddfa2e426f6e
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.subscriber.client.yml
@@ -0,0 +1,28 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- children:
+  - google.cloud.pubsub_v1.subscriber.client.Client
+  fullName: google.cloud.pubsub_v1.subscriber.client
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.client
+  name: subscriber.client
+  source:
+    id: client
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/client.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/client.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 0
+  summary: API documentation for `pubsub_v1.subscriber.client` module.
+  syntax: {}
+  type: module
+  uid: google.cloud.pubsub_v1.subscriber.client
+references:
+- fullName: google.cloud.pubsub_v1.subscriber.client.Client
+  isExternal: false
+  name: Client
+  parent: google.cloud.pubsub_v1.subscriber.client
+  uid: google.cloud.pubsub_v1.subscriber.client.Client
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.subscriber.futures.Future.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.subscriber.futures.Future.yml
new file mode 100644
index 000000000000..fe3b386c485f
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.subscriber.futures.Future.yml
@@ -0,0 +1,435 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes: []
+  children:
+  - google.cloud.pubsub_v1.subscriber.futures.Future
+  - google.cloud.pubsub_v1.subscriber.futures.Future.add_done_callback
+  - google.cloud.pubsub_v1.subscriber.futures.Future.cancel
+  - google.cloud.pubsub_v1.subscriber.futures.Future.cancelled
+  - google.cloud.pubsub_v1.subscriber.futures.Future.done
+  - google.cloud.pubsub_v1.subscriber.futures.Future.exception
+  - google.cloud.pubsub_v1.subscriber.futures.Future.result
+  - google.cloud.pubsub_v1.subscriber.futures.Future.running
+  - google.cloud.pubsub_v1.subscriber.futures.Future.set_exception
+  - google.cloud.pubsub_v1.subscriber.futures.Future.set_result
+  - google.cloud.pubsub_v1.subscriber.futures.Future.set_running_or_notify_cancel
+  class: google.cloud.pubsub_v1.subscriber.futures.Future
+  fullName: google.cloud.pubsub_v1.subscriber.futures.Future
+  inheritance:
+  - inheritance:
+    - inheritance:
+      - type: builtins.object
+      type: concurrent.futures._base.Future
+    - inheritance:
+      - type: builtins.object
+      type: google.api_core.future.base.Future
+    type: google.cloud.pubsub_v1.futures.Future
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.futures
+  name: Future
+  source:
+    id: Future
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/futures.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/futures.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 86
+  summary: 'This future object is for subscribe-side calls.
+
+
+    Calling `result` will resolve the future by returning the message
+
+    ID, unless an error occurs.
+
+
+    '
+  syntax:
+    content: Future()
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.subscriber.futures.Future
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.futures.Future
+  fullName: google.cloud.pubsub_v1.subscriber.futures.Future
+  inheritance:
+  - inheritance:
+    - inheritance:
+      - type: builtins.object
+      type: concurrent.futures._base.Future
+    - inheritance:
+      - type: builtins.object
+      type: google.api_core.future.base.Future
+    type: google.cloud.pubsub_v1.futures.Future
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.futures
+  name: Future
+  source:
+    id: Future
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/futures.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/futures.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 86
+  summary: 'Initializes the future. Should not be called by clients.
+
+
+    '
+  syntax:
+    content: Future()
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.futures.Future
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.futures.Future
+  fullName: google.cloud.pubsub_v1.subscriber.futures.Future.add_done_callback
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.futures
+  name: add_done_callback
+  source:
+    id: add_done_callback
+    path: concurrent/futures/_base.py
+    remote:
+      branch: add_goldens
+      path: concurrent/futures/_base.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 398
+  summary: 'Attaches a callable that will be called when the future finishes.
+
+    '
+  syntax:
+    content: add_done_callback(fn)
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.futures.Future.add_done_callback
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.futures.Future
+  fullName: google.cloud.pubsub_v1.subscriber.futures.Future.cancel
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.futures
+  name: cancel
+  source:
+    id: cancel
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/futures.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/futures.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 93
+  summary: 'Actions in Pub/Sub generally may not be canceled.
+
+
+    This method always returns `False`.
+
+
+    '
+  syntax:
+    content: cancel()
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.futures.Future.cancel
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.futures.Future
+  fullName: google.cloud.pubsub_v1.subscriber.futures.Future.cancelled
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.futures
+  name: cancelled
+  source:
+    id: cancelled
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/futures.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/futures.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 100
+  summary: 'Actions in Pub/Sub generally may not be canceled.
+
+
+    This method always returns `False`.
+
+
+    '
+  syntax:
+    content: cancelled()
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.futures.Future.cancelled
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.futures.Future
+  fullName: google.cloud.pubsub_v1.subscriber.futures.Future.done
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.futures
+  name: done
+  source:
+    id: done
+    path: concurrent/futures/_base.py
+    remote:
+      branch: add_goldens
+      path: concurrent/futures/_base.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 383
+  summary: 'Return True if the future was cancelled or finished executing.
+
+
+    '
+  syntax:
+    content: done()
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.futures.Future.done
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.futures.Future
+  fullName: google.cloud.pubsub_v1.subscriber.futures.Future.exception
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.futures
+  name: exception
+  source:
+    id: exception
+    path: concurrent/futures/_base.py
+    remote:
+      branch: add_goldens
+      path: concurrent/futures/_base.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 453
+  summary: 'Return the exception raised by the call that the future represents.
+
+    '
+  syntax:
+    content: exception(timeout=None)
+    exceptions:
+    - description: If the future was cancelled.
+      var_type: CancelledError
+    - description: If the future didn't finish executing before the given timeout.
+      var_type: TimeoutError
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.futures.Future.exception
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.futures.Future
+  fullName: google.cloud.pubsub_v1.subscriber.futures.Future.result
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.futures
+  name: result
+  source:
+    id: result
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/futures.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/futures.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 107
+  summary: 'Return a success code or raise an exception.
+
+
+    This blocks until the operation completes successfully and
+
+    returns the error code unless an exception is raised.
+
+    '
+  syntax:
+    content: 'result(timeout: typing.Optional[typing.Union[int, float]] = None)'
+    exceptions:
+    - description: If the request times out.
+      var_type: concurrent.futures.TimeoutError
+    - description: If the operation did not succeed for another reason.
+      var_type: AcknowledgeError
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.futures.Future.result
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.futures.Future
+  fullName: google.cloud.pubsub_v1.subscriber.futures.Future.running
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.futures
+  name: running
+  source:
+    id: running
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/futures.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/futures.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 33
+  summary: 'Return `True` if the associated Pub/Sub action has not yet completed.
+
+
+    '
+  syntax:
+    content: running()
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.futures.Future.running
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.futures.Future
+  fullName: google.cloud.pubsub_v1.subscriber.futures.Future.set_exception
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.futures
+  name: set_exception
+  source:
+    id: set_exception
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/futures.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/futures.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 50
+  summary: 'Set the result of the future as being the given exception.
+
+
+    Do not use this method, it should only be used internally by the library and its
+
+    unit tests.
+
+
+    '
+  syntax:
+    content: 'set_exception(exception: typing.Optional[BaseException])'
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.futures.Future.set_exception
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.futures.Future
+  fullName: google.cloud.pubsub_v1.subscriber.futures.Future.set_result
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.futures
+  name: set_result
+  source:
+    id: set_result
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/futures.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/futures.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 42
+  summary: 'Set the return value of work associated with the future.
+
+
+    Do not use this method, it should only be used internally by the library and its
+
+    unit tests.
+
+
+    '
+  syntax:
+    content: 'set_result(result: typing.Any)'
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.futures.Future.set_result
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.futures.Future
+  fullName: google.cloud.pubsub_v1.subscriber.futures.Future.set_running_or_notify_cancel
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.futures
+  name: set_running_or_notify_cancel
+  source:
+    id: set_running_or_notify_cancel
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/futures.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/futures.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 37
+  summary: 'Mark the future as running or process any cancel notifications.
+
+
+    Should only be used by Executor implementations and unit tests.
+
+
+    If the future has been cancelled (cancel() was called and returned
+
+    True) then any threads waiting on the future completing (though calls
+
+    to as_completed() or wait()) are notified and False is returned.
+
+
+    If the future was not cancelled then it is put in the running state
+
+    (future calls to running() will return True) and True is returned.
+
+
+    This method should be called by Executor implementations before
+
+    executing the work associated with this future. If this method returns
+
+    False then the work should not be executed.
+
+    '
+  syntax:
+    content: set_running_or_notify_cancel()
+    exceptions:
+    - description: if this method was already called or if set_result() or set_exception()
+        was called.
+      var_type: RuntimeError
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.futures.Future.set_running_or_notify_cancel
+references:
+- fullName: google.cloud.pubsub_v1.subscriber.futures.Future
+  isExternal: false
+  name: Future
+  parent: google.cloud.pubsub_v1.subscriber.futures.Future
+  uid: google.cloud.pubsub_v1.subscriber.futures.Future
+- fullName: google.cloud.pubsub_v1.subscriber.futures.Future.add_done_callback
+  isExternal: false
+  name: add_done_callback
+  parent: google.cloud.pubsub_v1.subscriber.futures.Future
+  uid: google.cloud.pubsub_v1.subscriber.futures.Future.add_done_callback
+- fullName: google.cloud.pubsub_v1.subscriber.futures.Future.cancel
+  isExternal: false
+  name: cancel
+  parent: google.cloud.pubsub_v1.subscriber.futures.Future
+  uid: google.cloud.pubsub_v1.subscriber.futures.Future.cancel
+- fullName: google.cloud.pubsub_v1.subscriber.futures.Future.cancelled
+  isExternal: false
+  name: cancelled
+  parent: google.cloud.pubsub_v1.subscriber.futures.Future
+  uid: google.cloud.pubsub_v1.subscriber.futures.Future.cancelled
+- fullName: google.cloud.pubsub_v1.subscriber.futures.Future.done
+  isExternal: false
+  name: done
+  parent: google.cloud.pubsub_v1.subscriber.futures.Future
+  uid: google.cloud.pubsub_v1.subscriber.futures.Future.done
+- fullName: google.cloud.pubsub_v1.subscriber.futures.Future.exception
+  isExternal: false
+  name: exception
+  parent: google.cloud.pubsub_v1.subscriber.futures.Future
+  uid: google.cloud.pubsub_v1.subscriber.futures.Future.exception
+- fullName: google.cloud.pubsub_v1.subscriber.futures.Future.result
+  isExternal: false
+  name: result
+  parent: google.cloud.pubsub_v1.subscriber.futures.Future
+  uid: google.cloud.pubsub_v1.subscriber.futures.Future.result
+- fullName: google.cloud.pubsub_v1.subscriber.futures.Future.running
+  isExternal: false
+  name: running
+  parent: google.cloud.pubsub_v1.subscriber.futures.Future
+  uid: google.cloud.pubsub_v1.subscriber.futures.Future.running
+- fullName: google.cloud.pubsub_v1.subscriber.futures.Future.set_exception
+  isExternal: false
+  name: set_exception
+  parent: google.cloud.pubsub_v1.subscriber.futures.Future
+  uid: google.cloud.pubsub_v1.subscriber.futures.Future.set_exception
+- fullName: google.cloud.pubsub_v1.subscriber.futures.Future.set_result
+  isExternal: false
+  name: set_result
+  parent: google.cloud.pubsub_v1.subscriber.futures.Future
+  uid: google.cloud.pubsub_v1.subscriber.futures.Future.set_result
+- fullName: google.cloud.pubsub_v1.subscriber.futures.Future.set_running_or_notify_cancel
+  isExternal: false
+  name: set_running_or_notify_cancel
+  parent: google.cloud.pubsub_v1.subscriber.futures.Future
+  uid: google.cloud.pubsub_v1.subscriber.futures.Future.set_running_or_notify_cancel
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.yml
new file mode 100644
index 000000000000..40d4caa3e8a9
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.yml
@@ -0,0 +1,431 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes: []
+  children:
+  - google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture
+  - google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.add_done_callback
+  - google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.cancel
+  - google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.cancelled
+  - google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.done
+  - google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.exception
+  - google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.result
+  - google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.running
+  - google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.set_exception
+  - google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.set_result
+  - google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.set_running_or_notify_cancel
+  class: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture
+  fullName: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture
+  inheritance:
+  - inheritance:
+    - inheritance:
+      - type: builtins.object
+      type: concurrent.futures._base.Future
+    - inheritance:
+      - type: builtins.object
+      type: google.api_core.future.base.Future
+    type: google.cloud.pubsub_v1.futures.Future
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.futures
+  name: StreamingPullFuture
+  source:
+    id: StreamingPullFuture
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/futures.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/futures.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 30
+  summary: 'Represents a process that asynchronously performs streaming pull and
+
+    schedules messages to be processed.
+
+
+    This future is resolved when the process is stopped (via `cancel`) or
+
+    if it encounters an unrecoverable error. Calling `.result()` will cause
+
+    the calling thread to block indefinitely.
+
+
+    '
+  syntax:
+    content: 'StreamingPullFuture(manager: StreamingPullManager)'
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture
+  fullName: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture
+  inheritance:
+  - inheritance:
+    - inheritance:
+      - type: builtins.object
+      type: concurrent.futures._base.Future
+    - inheritance:
+      - type: builtins.object
+      type: google.api_core.future.base.Future
+    type: google.cloud.pubsub_v1.futures.Future
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.futures
+  name: StreamingPullFuture
+  source:
+    id: StreamingPullFuture
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/futures.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/futures.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 30
+  summary: 'Initializes the future. Should not be called by clients.
+
+
+    '
+  syntax:
+    content: 'StreamingPullFuture(manager: StreamingPullManager)'
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture
+  fullName: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.add_done_callback
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.futures
+  name: add_done_callback
+  source:
+    id: add_done_callback
+    path: concurrent/futures/_base.py
+    remote:
+      branch: add_goldens
+      path: concurrent/futures/_base.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 398
+  summary: 'Attaches a callable that will be called when the future finishes.
+
+    '
+  syntax:
+    content: add_done_callback(fn)
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.add_done_callback
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture
+  fullName: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.cancel
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.futures
+  name: cancel
+  source:
+    id: cancel
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/futures.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/futures.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 56
+  summary: "Stops pulling messages and shutdowns the background thread consuming\n\
+    messages.\n\nThe method always returns `True`, as the shutdown is always initiated.\n\
+    However, if the background stream is already being shut down or the shutdown\n\
+    has completed, this method is a no-op.\n\n.. versionchanged:: 2.4.1\n   The method\
+    \ does not block anymore, it just triggers the shutdown and returns\n   immediately.\
+    \ To block until the background stream is terminated, call\n   `result()` after\
+    \ cancelling the future.\n\n.. versionchanged:: 2.10.0\n   The method always returns\
+    \ `True` instead of `None`.\n\n"
+  syntax:
+    content: cancel()
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.cancel
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture
+  fullName: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.cancelled
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.futures
+  name: cancelled
+  source:
+    id: cancelled
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/futures.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/futures.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 78
+  summary: ''
+  syntax:
+    content: cancelled()
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.cancelled
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture
+  fullName: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.done
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.futures
+  name: done
+  source:
+    id: done
+    path: concurrent/futures/_base.py
+    remote:
+      branch: add_goldens
+      path: concurrent/futures/_base.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 383
+  summary: 'Return True if the future was cancelled or finished executing.
+
+
+    '
+  syntax:
+    content: done()
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.done
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture
+  fullName: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.exception
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.futures
+  name: exception
+  source:
+    id: exception
+    path: concurrent/futures/_base.py
+    remote:
+      branch: add_goldens
+      path: concurrent/futures/_base.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 453
+  summary: 'Return the exception raised by the call that the future represents.
+
+    '
+  syntax:
+    content: exception(timeout=None)
+    exceptions:
+    - description: If the future was cancelled.
+      var_type: CancelledError
+    - description: If the future didn't finish executing before the given timeout.
+      var_type: TimeoutError
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.exception
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture
+  fullName: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.result
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.futures
+  name: result
+  source:
+    id: result
+    path: concurrent/futures/_base.py
+    remote:
+      branch: add_goldens
+      path: concurrent/futures/_base.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 418
+  summary: 'Return the result of the call that the future represents.
+
+    '
+  syntax:
+    content: result(timeout=None)
+    exceptions:
+    - description: If the future was cancelled.
+      var_type: CancelledError
+    - description: If the future didn't finish executing before the given timeout.
+      var_type: TimeoutError
+    - description: If the call raised then that exception will be raised.
+      var_type: Exception
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.result
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture
+  fullName: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.running
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.futures
+  name: running
+  source:
+    id: running
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/futures.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/futures.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 33
+  summary: 'Return `True` if the associated Pub/Sub action has not yet completed.
+
+
+    '
+  syntax:
+    content: running()
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.running
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture
+  fullName: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.set_exception
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.futures
+  name: set_exception
+  source:
+    id: set_exception
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/futures.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/futures.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 50
+  summary: 'Set the result of the future as being the given exception.
+
+
+    Do not use this method, it should only be used internally by the library and its
+
+    unit tests.
+
+
+    '
+  syntax:
+    content: 'set_exception(exception: typing.Optional[BaseException])'
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.set_exception
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture
+  fullName: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.set_result
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.futures
+  name: set_result
+  source:
+    id: set_result
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/futures.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/futures.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 42
+  summary: 'Set the return value of work associated with the future.
+
+
+    Do not use this method, it should only be used internally by the library and its
+
+    unit tests.
+
+
+    '
+  syntax:
+    content: 'set_result(result: typing.Any)'
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.set_result
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture
+  fullName: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.set_running_or_notify_cancel
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.futures
+  name: set_running_or_notify_cancel
+  source:
+    id: set_running_or_notify_cancel
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/futures.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/futures.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 37
+  summary: 'Mark the future as running or process any cancel notifications.
+
+
+    Should only be used by Executor implementations and unit tests.
+
+
+    If the future has been cancelled (cancel() was called and returned
+
+    True) then any threads waiting on the future completing (though calls
+
+    to as_completed() or wait()) are notified and False is returned.
+
+
+    If the future was not cancelled then it is put in the running state
+
+    (future calls to running() will return True) and True is returned.
+
+
+    This method should be called by Executor implementations before
+
+    executing the work associated with this future. If this method returns
+
+    False then the work should not be executed.
+
+    '
+  syntax:
+    content: set_running_or_notify_cancel()
+    exceptions:
+    - description: if this method was already called or if set_result() or set_exception()
+        was called.
+      var_type: RuntimeError
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.set_running_or_notify_cancel
+references:
+- fullName: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture
+  isExternal: false
+  name: StreamingPullFuture
+  parent: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture
+  uid: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture
+- fullName: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.add_done_callback
+  isExternal: false
+  name: add_done_callback
+  parent: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture
+  uid: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.add_done_callback
+- fullName: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.cancel
+  isExternal: false
+  name: cancel
+  parent: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture
+  uid: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.cancel
+- fullName: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.cancelled
+  isExternal: false
+  name: cancelled
+  parent: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture
+  uid: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.cancelled
+- fullName: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.done
+  isExternal: false
+  name: done
+  parent: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture
+  uid: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.done
+- fullName: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.exception
+  isExternal: false
+  name: exception
+  parent: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture
+  uid: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.exception
+- fullName: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.result
+  isExternal: false
+  name: result
+  parent: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture
+  uid: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.result
+- fullName: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.running
+  isExternal: false
+  name: running
+  parent: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture
+  uid: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.running
+- fullName: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.set_exception
+  isExternal: false
+  name: set_exception
+  parent: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture
+  uid: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.set_exception
+- fullName: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.set_result
+  isExternal: false
+  name: set_result
+  parent: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture
+  uid: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.set_result
+- fullName: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.set_running_or_notify_cancel
+  isExternal: false
+  name: set_running_or_notify_cancel
+  parent: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture
+  uid: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture.set_running_or_notify_cancel
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.subscriber.futures.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.subscriber.futures.yml
new file mode 100644
index 000000000000..d4c9ffa41978
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.subscriber.futures.yml
@@ -0,0 +1,34 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- children:
+  - google.cloud.pubsub_v1.subscriber.futures.Future
+  - google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture
+  fullName: google.cloud.pubsub_v1.subscriber.futures
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.futures
+  name: subscriber.futures
+  source:
+    id: futures
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/futures.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/futures.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 0
+  summary: API documentation for `pubsub_v1.subscriber.futures` module.
+  syntax: {}
+  type: module
+  uid: google.cloud.pubsub_v1.subscriber.futures
+references:
+- fullName: google.cloud.pubsub_v1.subscriber.futures.Future
+  isExternal: false
+  name: Future
+  parent: google.cloud.pubsub_v1.subscriber.futures
+  uid: google.cloud.pubsub_v1.subscriber.futures.Future
+- fullName: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture
+  isExternal: false
+  name: StreamingPullFuture
+  parent: google.cloud.pubsub_v1.subscriber.futures
+  uid: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.subscriber.message.Message.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.subscriber.message.Message.yml
new file mode 100644
index 000000000000..7a73b35538d7
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.subscriber.message.Message.yml
@@ -0,0 +1,722 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes: []
+  children:
+  - google.cloud.pubsub_v1.subscriber.message.Message
+  - google.cloud.pubsub_v1.subscriber.message.Message.ack
+  - google.cloud.pubsub_v1.subscriber.message.Message.ack_id
+  - google.cloud.pubsub_v1.subscriber.message.Message.ack_with_response
+  - google.cloud.pubsub_v1.subscriber.message.Message.attributes
+  - google.cloud.pubsub_v1.subscriber.message.Message.data
+  - google.cloud.pubsub_v1.subscriber.message.Message.delivery_attempt
+  - google.cloud.pubsub_v1.subscriber.message.Message.drop
+  - google.cloud.pubsub_v1.subscriber.message.Message.modify_ack_deadline
+  - google.cloud.pubsub_v1.subscriber.message.Message.modify_ack_deadline_with_response
+  - google.cloud.pubsub_v1.subscriber.message.Message.nack
+  - google.cloud.pubsub_v1.subscriber.message.Message.nack_with_response
+  - google.cloud.pubsub_v1.subscriber.message.Message.ordering_key
+  - google.cloud.pubsub_v1.subscriber.message.Message.publish_time
+  - google.cloud.pubsub_v1.subscriber.message.Message.size
+  class: google.cloud.pubsub_v1.subscriber.message.Message
+  fullName: google.cloud.pubsub_v1.subscriber.message.Message
+  inheritance:
+  - type: builtins.object
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.message
+  name: Message
+  source:
+    id: Message
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/message.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/message.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 67
+  summary: "A representation of a single Pub/Sub message.\n\nThe common way to interact\
+    \ with\n`.pubsub_v1.subscriber.message.Message` objects is to receive\nthem in\
+    \ callbacks on subscriptions; most users should never have a need\nto instantiate\
+    \ them by hand. (The exception to this is if you are\nimplementing a custom subclass\
+    \ to\n`.pubsub_v1.subscriber._consumer.Consumer`.)\n\n   The data in the message.\
+    \ Note that this will be a `bytes`,\n   not a text string.\n\n   The time that\
+    \ this message was originally published.\n\n"
+  syntax:
+    content: 'Message(message: types.PubsubMessage._meta._pb, ack_id: str, delivery_attempt:
+      int, request_queue: queue.Queue, exactly_once_delivery_enabled_func: typing.Callable[[],
+      bool] = >)'
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.subscriber.message.Message
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.message.Message
+  fullName: google.cloud.pubsub_v1.subscriber.message.Message
+  inheritance:
+  - type: builtins.object
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.message
+  name: Message
+  source:
+    id: Message
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/message.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/message.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 67
+  summary: 'Construct the Message.
+
+
+    '
+  syntax:
+    content: 'Message(message: types.PubsubMessage._meta._pb, ack_id: str, delivery_attempt:
+      int, request_queue: queue.Queue, exactly_once_delivery_enabled_func: typing.Callable[[],
+      bool] = >)'
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.message.Message
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.message.Message
+  fullName: google.cloud.pubsub_v1.subscriber.message.Message.ack
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.message
+  name: ack
+  source:
+    id: ack
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/message.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/message.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 234
+  summary: 'Acknowledge the given message.
+
+
+    Acknowledging a message in Pub/Sub means that you are done
+
+    with it, and it will not be delivered to this subscription again.
+
+    You should avoid acknowledging messages until you have
+
+    *finished* processing them, so that in the event of a failure,
+
+    you receive the message again.
+
+
+    '
+  syntax:
+    content: ack()
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.message.Message.ack
+- &id001
+  attributes: []
+  class: google.cloud.pubsub_v1.subscriber.message.Message
+  fullName: google.cloud.pubsub_v1.subscriber.message.Message.ack_id
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.message
+  name: ack_id
+  source:
+    id: ack_id
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'the ID used to ack the message.
+
+
+    '
+  syntax: {}
+  type: property
+  uid: google.cloud.pubsub_v1.subscriber.message.Message.ack_id
+- *id001
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.message.Message
+  fullName: google.cloud.pubsub_v1.subscriber.message.Message.ack_with_response
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.message
+  name: ack_with_response
+  source:
+    id: ack_with_response
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/message.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/message.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 265
+  summary: 'Acknowledge the given message.
+
+
+    Acknowledging a message in Pub/Sub means that you are done
+
+    with it, and it will not be delivered to this subscription again.
+
+    You should avoid acknowledging messages until you have
+
+    *finished* processing them, so that in the event of a failure,
+
+    you receive the message again.
+
+
+    If exactly-once delivery is NOT enabled on the subscription, the
+
+    future returns immediately with an AcknowledgeStatus.SUCCESS.
+
+    Since acks in Cloud Pub/Sub are best effort when exactly-once
+
+    delivery is disabled, the message may be re-delivered. Because
+
+    re-deliveries are possible, you should ensure that your processing
+
+    code is idempotent, as you may receive any given message more than
+
+    once.
+
+
+    If exactly-once delivery is enabled on the subscription, the
+
+    future returned by this method tracks the state of acknowledgement
+
+    operation. If the future completes successfully, the message is
+
+    guaranteed NOT to be re-delivered. Otherwise, the future will
+
+    contain an exception with more details about the failure and the
+
+    message may be re-delivered.
+
+
+    Exactly once delivery is a preview feature. For more details,
+
+    see https://cloud.google.com/pubsub/docs/exactly-once-delivery."
+
+    '
+  syntax:
+    content: ack_with_response()
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.message.Message.ack_with_response
+- &id002
+  attributes: []
+  class: google.cloud.pubsub_v1.subscriber.message.Message
+  fullName: google.cloud.pubsub_v1.subscriber.message.Message.attributes
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.message
+  name: attributes
+  source:
+    id: attributes
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Return the attributes of the underlying Pub/Sub Message.
+
+
+    '
+  syntax: {}
+  type: property
+  uid: google.cloud.pubsub_v1.subscriber.message.Message.attributes
+- *id002
+- &id003
+  attributes: []
+  class: google.cloud.pubsub_v1.subscriber.message.Message
+  fullName: google.cloud.pubsub_v1.subscriber.message.Message.data
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.message
+  name: data
+  source:
+    id: data
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Return the data for the underlying Pub/Sub Message.
+
+    '
+  syntax: {}
+  type: property
+  uid: google.cloud.pubsub_v1.subscriber.message.Message.data
+- *id003
+- &id004
+  attributes: []
+  class: google.cloud.pubsub_v1.subscriber.message.Message
+  fullName: google.cloud.pubsub_v1.subscriber.message.Message.delivery_attempt
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.message
+  name: delivery_attempt
+  source:
+    id: delivery_attempt
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'The delivery attempt counter is 1 + (the sum of number of NACKs
+
+    and number of ack_deadline exceeds) for this message. It is set to None
+
+    if a DeadLetterPolicy is not set on the subscription.
+
+
+    A NACK is any call to ModifyAckDeadline with a 0 deadline. An ack_deadline
+
+    exceeds event is whenever a message is not acknowledged within
+
+    ack_deadline. Note that ack_deadline is initially
+
+    Subscription.ackDeadlineSeconds, but may get extended automatically by
+
+    the client library.
+
+
+    The first delivery of a given message will have this value as 1. The value
+
+    is calculated at best effort and is approximate.
+
+    '
+  syntax: {}
+  type: property
+  uid: google.cloud.pubsub_v1.subscriber.message.Message.delivery_attempt
+- *id004
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.message.Message
+  fullName: google.cloud.pubsub_v1.subscriber.message.Message.drop
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.message
+  name: drop
+  source:
+    id: drop
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/message.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/message.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 322
+  summary: 'Release the message from lease management.
+
+
+    This informs the policy to no longer hold on to the lease for this
+
+    message. Pub/Sub will re-deliver the message if it is not acknowledged
+
+    before the existing lease expires.
+
+
+    '
+  syntax:
+    content: drop()
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.message.Message.drop
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.message.Message
+  fullName: google.cloud.pubsub_v1.subscriber.message.Message.modify_ack_deadline
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.message
+  name: modify_ack_deadline
+  source:
+    id: modify_ack_deadline
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/message.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/message.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 341
+  summary: 'Resets the deadline for acknowledgement.
+
+
+    New deadline will be the given value of seconds from now.
+
+
+    The default implementation handles automatically modacking received messages for
+    you;
+
+    you should not need to manually deal with setting ack deadlines. The exception
+    case is
+
+    if you are implementing your own custom subclass of
+
+    `.pubsub_v1.subcriber._consumer.Consumer`.
+
+    '
+  syntax:
+    content: 'modify_ack_deadline(seconds: int)'
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.message.Message.modify_ack_deadline
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.message.Message
+  fullName: google.cloud.pubsub_v1.subscriber.message.Message.modify_ack_deadline_with_response
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.message
+  name: modify_ack_deadline_with_response
+  source:
+    id: modify_ack_deadline_with_response
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/message.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/message.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 361
+  summary: 'Resets the deadline for acknowledgement and returns the response
+
+    status via a future.
+
+
+    New deadline will be the given value of seconds from now.
+
+
+    The default implementation handles automatically modacking received messages for
+    you;
+
+    you should not need to manually deal with setting ack deadlines. The exception
+    case is
+
+    if you are implementing your own custom subclass of
+
+    `.pubsub_v1.subcriber._consumer.Consumer`.
+
+
+    If exactly-once delivery is NOT enabled on the subscription, the
+
+    future returns immediately with an AcknowledgeStatus.SUCCESS.
+
+    Since modify-ack-deadline operations in Cloud Pub/Sub are best effort
+
+    when exactly-once delivery is disabled, the message may be re-delivered
+
+    within the set deadline.
+
+
+    If exactly-once delivery is enabled on the subscription, the
+
+    future returned by this method tracks the state of the
+
+    modify-ack-deadline operation. If the future completes successfully,
+
+    the message is guaranteed NOT to be re-delivered within the new deadline.
+
+    Otherwise, the future will contain an exception with more details about
+
+    the failure and the message will be redelivered according to its
+
+    currently-set ack deadline.
+
+
+    Exactly once delivery is a preview feature. For more details,
+
+    see https://cloud.google.com/pubsub/docs/exactly-once-delivery."
+
+    '
+  syntax:
+    content: 'modify_ack_deadline_with_response(seconds: int)'
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.message.Message.modify_ack_deadline_with_response
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.message.Message
+  fullName: google.cloud.pubsub_v1.subscriber.message.Message.nack
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.message
+  name: nack
+  source:
+    id: nack
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/message.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/message.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 422
+  summary: 'Decline to acknowledge the given message.
+
+
+    This will cause the message to be re-delivered to subscribers. Re-deliveries
+
+    may take place immediately or after a delay, and may arrive at this subscriber
+
+    or another.
+
+
+    '
+  syntax:
+    content: nack()
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.message.Message.nack
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.message.Message
+  fullName: google.cloud.pubsub_v1.subscriber.message.Message.nack_with_response
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.message
+  name: nack_with_response
+  source:
+    id: nack_with_response
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/message.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/message.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 438
+  summary: 'Decline to acknowledge the given message, returning the response status
+    via
+
+    a future.
+
+
+    This will cause the message to be re-delivered to subscribers. Re-deliveries
+
+    may take place immediately or after a delay, and may arrive at this subscriber
+
+    or another.
+
+
+    If exactly-once delivery is NOT enabled on the subscription, the
+
+    future returns immediately with an AcknowledgeStatus.SUCCESS.
+
+
+    If exactly-once delivery is enabled on the subscription, the
+
+    future returned by this method tracks the state of the
+
+    nack operation. If the future completes successfully,
+
+    the future''s result will be an AcknowledgeStatus.SUCCESS.
+
+    Otherwise, the future will contain an exception with more details about
+
+    the failure.
+
+
+    Exactly once delivery is a preview feature. For more details,
+
+    see https://cloud.google.com/pubsub/docs/exactly-once-delivery."
+
+    '
+  syntax:
+    content: nack_with_response()
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.message.Message.nack_with_response
+- &id005
+  attributes: []
+  class: google.cloud.pubsub_v1.subscriber.message.Message
+  fullName: google.cloud.pubsub_v1.subscriber.message.Message.ordering_key
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.message
+  name: ordering_key
+  source:
+    id: ordering_key
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'The ordering key used to publish the message.
+
+
+    '
+  syntax: {}
+  type: property
+  uid: google.cloud.pubsub_v1.subscriber.message.Message.ordering_key
+- *id005
+- &id006
+  attributes: []
+  class: google.cloud.pubsub_v1.subscriber.message.Message
+  fullName: google.cloud.pubsub_v1.subscriber.message.Message.publish_time
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.message
+  name: publish_time
+  source:
+    id: publish_time
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Return the time that the message was originally published.
+
+    '
+  syntax: {}
+  type: property
+  uid: google.cloud.pubsub_v1.subscriber.message.Message.publish_time
+- *id006
+- &id007
+  attributes: []
+  class: google.cloud.pubsub_v1.subscriber.message.Message
+  fullName: google.cloud.pubsub_v1.subscriber.message.Message.size
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.message
+  name: size
+  source:
+    id: size
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Return the size of the underlying message, in bytes.
+
+
+    '
+  syntax: {}
+  type: property
+  uid: google.cloud.pubsub_v1.subscriber.message.Message.size
+- *id007
+references:
+- fullName: google.cloud.pubsub_v1.subscriber.message.Message
+  isExternal: false
+  name: Message
+  parent: google.cloud.pubsub_v1.subscriber.message.Message
+  uid: google.cloud.pubsub_v1.subscriber.message.Message
+- fullName: google.cloud.pubsub_v1.subscriber.message.Message.ack
+  isExternal: false
+  name: ack
+  parent: google.cloud.pubsub_v1.subscriber.message.Message
+  uid: google.cloud.pubsub_v1.subscriber.message.Message.ack
+- fullName: google.cloud.pubsub_v1.subscriber.message.Message.ack_id
+  isExternal: false
+  name: ack_id
+  parent: google.cloud.pubsub_v1.subscriber.message.Message
+  uid: google.cloud.pubsub_v1.subscriber.message.Message.ack_id
+- fullName: google.cloud.pubsub_v1.subscriber.message.Message.ack_with_response
+  isExternal: false
+  name: ack_with_response
+  parent: google.cloud.pubsub_v1.subscriber.message.Message
+  uid: google.cloud.pubsub_v1.subscriber.message.Message.ack_with_response
+- fullName: google.cloud.pubsub_v1.subscriber.message.Message.attributes
+  isExternal: false
+  name: attributes
+  parent: google.cloud.pubsub_v1.subscriber.message.Message
+  uid: google.cloud.pubsub_v1.subscriber.message.Message.attributes
+- fullName: google.cloud.pubsub_v1.subscriber.message.Message.data
+  isExternal: false
+  name: data
+  parent: google.cloud.pubsub_v1.subscriber.message.Message
+  uid: google.cloud.pubsub_v1.subscriber.message.Message.data
+- fullName: google.cloud.pubsub_v1.subscriber.message.Message.delivery_attempt
+  isExternal: false
+  name: delivery_attempt
+  parent: google.cloud.pubsub_v1.subscriber.message.Message
+  uid: google.cloud.pubsub_v1.subscriber.message.Message.delivery_attempt
+- fullName: google.cloud.pubsub_v1.subscriber.message.Message.drop
+  isExternal: false
+  name: drop
+  parent: google.cloud.pubsub_v1.subscriber.message.Message
+  uid: google.cloud.pubsub_v1.subscriber.message.Message.drop
+- fullName: google.cloud.pubsub_v1.subscriber.message.Message.modify_ack_deadline
+  isExternal: false
+  name: modify_ack_deadline
+  parent: google.cloud.pubsub_v1.subscriber.message.Message
+  uid: google.cloud.pubsub_v1.subscriber.message.Message.modify_ack_deadline
+- fullName: google.cloud.pubsub_v1.subscriber.message.Message.modify_ack_deadline_with_response
+  isExternal: false
+  name: modify_ack_deadline_with_response
+  parent: google.cloud.pubsub_v1.subscriber.message.Message
+  uid: google.cloud.pubsub_v1.subscriber.message.Message.modify_ack_deadline_with_response
+- fullName: google.cloud.pubsub_v1.subscriber.message.Message.nack
+  isExternal: false
+  name: nack
+  parent: google.cloud.pubsub_v1.subscriber.message.Message
+  uid: google.cloud.pubsub_v1.subscriber.message.Message.nack
+- fullName: google.cloud.pubsub_v1.subscriber.message.Message.nack_with_response
+  isExternal: false
+  name: nack_with_response
+  parent: google.cloud.pubsub_v1.subscriber.message.Message
+  uid: google.cloud.pubsub_v1.subscriber.message.Message.nack_with_response
+- fullName: google.cloud.pubsub_v1.subscriber.message.Message.ordering_key
+  isExternal: false
+  name: ordering_key
+  parent: google.cloud.pubsub_v1.subscriber.message.Message
+  uid: google.cloud.pubsub_v1.subscriber.message.Message.ordering_key
+- fullName: google.cloud.pubsub_v1.subscriber.message.Message.publish_time
+  isExternal: false
+  name: publish_time
+  parent: google.cloud.pubsub_v1.subscriber.message.Message
+  uid: google.cloud.pubsub_v1.subscriber.message.Message.publish_time
+- fullName: google.cloud.pubsub_v1.subscriber.message.Message.size
+  isExternal: false
+  name: size
+  parent: google.cloud.pubsub_v1.subscriber.message.Message
+  uid: google.cloud.pubsub_v1.subscriber.message.Message.size
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.subscriber.scheduler.Scheduler.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.subscriber.scheduler.Scheduler.yml
new file mode 100644
index 000000000000..15e53466098c
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.subscriber.scheduler.Scheduler.yml
@@ -0,0 +1,126 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes: []
+  children:
+  - google.cloud.pubsub_v1.subscriber.scheduler.Scheduler.queue
+  - google.cloud.pubsub_v1.subscriber.scheduler.Scheduler.schedule
+  - google.cloud.pubsub_v1.subscriber.scheduler.Scheduler.shutdown
+  class: google.cloud.pubsub_v1.subscriber.scheduler.Scheduler
+  fullName: google.cloud.pubsub_v1.subscriber.scheduler.Scheduler
+  inheritance:
+  - type: builtins.object
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.scheduler
+  name: Scheduler
+  source:
+    id: Scheduler
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/scheduler.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/scheduler.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 32
+  summary: 'Abstract base class for schedulers.
+
+
+    Schedulers are used to schedule callbacks asynchronously.
+
+
+    '
+  syntax:
+    content: Scheduler()
+  type: class
+  uid: google.cloud.pubsub_v1.subscriber.scheduler.Scheduler
+- &id001
+  attributes: []
+  class: google.cloud.pubsub_v1.subscriber.scheduler.Scheduler
+  fullName: google.cloud.pubsub_v1.subscriber.scheduler.Scheduler.queue
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.scheduler
+  name: queue
+  source:
+    id: queue
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Queue: A concurrency-safe queue specific to the underlying
+
+    concurrency implementation.
+
+
+    This queue is used to send messages *back* to the scheduling actor.
+
+
+    '
+  syntax: {}
+  type: property
+  uid: google.cloud.pubsub_v1.subscriber.scheduler.Scheduler.queue
+- *id001
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.scheduler.Scheduler
+  fullName: google.cloud.pubsub_v1.subscriber.scheduler.Scheduler.schedule
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.scheduler
+  name: schedule
+  source:
+    id: schedule
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/scheduler.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/scheduler.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 48
+  summary: 'Schedule the callback to be called asynchronously.
+
+    '
+  syntax:
+    content: 'schedule(callback: typing.Callable, *args, **kwargs)'
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.scheduler.Scheduler.schedule
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.scheduler.Scheduler
+  fullName: google.cloud.pubsub_v1.subscriber.scheduler.Scheduler.shutdown
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.scheduler
+  name: shutdown
+  source:
+    id: shutdown
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/scheduler.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/scheduler.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 62
+  summary: 'Shuts down the scheduler and immediately end all pending callbacks.
+
+    '
+  syntax:
+    content: 'shutdown(await_msg_callbacks: bool = False)'
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.scheduler.Scheduler.shutdown
+references:
+- fullName: google.cloud.pubsub_v1.subscriber.scheduler.Scheduler.queue
+  isExternal: false
+  name: queue
+  parent: google.cloud.pubsub_v1.subscriber.scheduler.Scheduler
+  uid: google.cloud.pubsub_v1.subscriber.scheduler.Scheduler.queue
+- fullName: google.cloud.pubsub_v1.subscriber.scheduler.Scheduler.schedule
+  isExternal: false
+  name: schedule
+  parent: google.cloud.pubsub_v1.subscriber.scheduler.Scheduler
+  uid: google.cloud.pubsub_v1.subscriber.scheduler.Scheduler.schedule
+- fullName: google.cloud.pubsub_v1.subscriber.scheduler.Scheduler.shutdown
+  isExternal: false
+  name: shutdown
+  parent: google.cloud.pubsub_v1.subscriber.scheduler.Scheduler
+  uid: google.cloud.pubsub_v1.subscriber.scheduler.Scheduler.shutdown
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.subscriber.scheduler.ThreadScheduler.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.subscriber.scheduler.ThreadScheduler.yml
new file mode 100644
index 000000000000..7ebb3151d2cb
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.subscriber.scheduler.ThreadScheduler.yml
@@ -0,0 +1,122 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes: []
+  children:
+  - google.cloud.pubsub_v1.subscriber.scheduler.ThreadScheduler.queue
+  - google.cloud.pubsub_v1.subscriber.scheduler.ThreadScheduler.schedule
+  - google.cloud.pubsub_v1.subscriber.scheduler.ThreadScheduler.shutdown
+  class: google.cloud.pubsub_v1.subscriber.scheduler.ThreadScheduler
+  fullName: google.cloud.pubsub_v1.subscriber.scheduler.ThreadScheduler
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: google.cloud.pubsub_v1.subscriber.scheduler.Scheduler
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.scheduler
+  name: ThreadScheduler
+  source:
+    id: ThreadScheduler
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/scheduler.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/scheduler.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 89
+  summary: "A thread pool-based scheduler. It must not be shared across\n   SubscriberClients.\n\
+    \nThis scheduler is useful in typical I/O-bound message processing.\n"
+  syntax:
+    content: "ThreadScheduler(\n    executor: typing.Optional[concurrent.futures.thread.ThreadPoolExecutor]\
+      \ = None,\n)"
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.subscriber.scheduler.ThreadScheduler
+- &id001
+  attributes: []
+  class: google.cloud.pubsub_v1.subscriber.scheduler.ThreadScheduler
+  fullName: google.cloud.pubsub_v1.subscriber.scheduler.ThreadScheduler.queue
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.scheduler
+  name: queue
+  source:
+    id: queue
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Queue: A thread-safe queue used for communication between callbacks
+
+    and the scheduling thread.
+
+
+    '
+  syntax: {}
+  type: property
+  uid: google.cloud.pubsub_v1.subscriber.scheduler.ThreadScheduler.queue
+- *id001
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.scheduler.ThreadScheduler
+  fullName: google.cloud.pubsub_v1.subscriber.scheduler.ThreadScheduler.schedule
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.scheduler
+  name: schedule
+  source:
+    id: schedule
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/scheduler.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/scheduler.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 116
+  summary: 'Schedule the callback to be called asynchronously in a thread pool.
+
+    '
+  syntax:
+    content: 'schedule(callback: typing.Callable, *args, **kwargs)'
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.scheduler.ThreadScheduler.schedule
+- attributes: []
+  class: google.cloud.pubsub_v1.subscriber.scheduler.ThreadScheduler
+  fullName: google.cloud.pubsub_v1.subscriber.scheduler.ThreadScheduler.shutdown
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.scheduler
+  name: shutdown
+  source:
+    id: shutdown
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/scheduler.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/scheduler.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 136
+  summary: 'Shut down the scheduler and immediately end all pending callbacks.
+
+    '
+  syntax:
+    content: 'shutdown(await_msg_callbacks: bool = False)'
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.subscriber.scheduler.ThreadScheduler.shutdown
+references:
+- fullName: google.cloud.pubsub_v1.subscriber.scheduler.ThreadScheduler.queue
+  isExternal: false
+  name: queue
+  parent: google.cloud.pubsub_v1.subscriber.scheduler.ThreadScheduler
+  uid: google.cloud.pubsub_v1.subscriber.scheduler.ThreadScheduler.queue
+- fullName: google.cloud.pubsub_v1.subscriber.scheduler.ThreadScheduler.schedule
+  isExternal: false
+  name: schedule
+  parent: google.cloud.pubsub_v1.subscriber.scheduler.ThreadScheduler
+  uid: google.cloud.pubsub_v1.subscriber.scheduler.ThreadScheduler.schedule
+- fullName: google.cloud.pubsub_v1.subscriber.scheduler.ThreadScheduler.shutdown
+  isExternal: false
+  name: shutdown
+  parent: google.cloud.pubsub_v1.subscriber.scheduler.ThreadScheduler
+  uid: google.cloud.pubsub_v1.subscriber.scheduler.ThreadScheduler.shutdown
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.subscriber.scheduler.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.subscriber.scheduler.yml
new file mode 100644
index 000000000000..47030a9e8e8b
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.subscriber.scheduler.yml
@@ -0,0 +1,43 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes: []
+  children:
+  - google.cloud.pubsub_v1.subscriber.scheduler.Scheduler
+  - google.cloud.pubsub_v1.subscriber.scheduler.ThreadScheduler
+  fullName: google.cloud.pubsub_v1.subscriber.scheduler
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.subscriber.scheduler
+  name: scheduler
+  source:
+    id: scheduler
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/scheduler.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/subscriber/scheduler.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 0
+  summary: 'Schedulers provide means to *schedule* callbacks asynchronously.
+
+
+    These are used by the subscriber to call the user-provided callback to process
+
+    each message.
+
+
+    '
+  syntax: {}
+  type: module
+  uid: google.cloud.pubsub_v1.subscriber.scheduler
+references:
+- fullName: google.cloud.pubsub_v1.subscriber.scheduler.Scheduler
+  isExternal: false
+  name: Scheduler
+  parent: google.cloud.pubsub_v1.subscriber.scheduler
+  uid: google.cloud.pubsub_v1.subscriber.scheduler.Scheduler
+- fullName: google.cloud.pubsub_v1.subscriber.scheduler.ThreadScheduler
+  isExternal: false
+  name: ThreadScheduler
+  parent: google.cloud.pubsub_v1.subscriber.scheduler
+  uid: google.cloud.pubsub_v1.subscriber.scheduler.ThreadScheduler
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.AcknowledgeRequest.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.AcknowledgeRequest.yml
new file mode 100644
index 000000000000..859b3d7fe606
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.AcknowledgeRequest.yml
@@ -0,0 +1,41 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes:
+  - description: "Required. The subscription whose message is being\n   acknowledged.\
+      \ Format is\n   projects/{project}/subscriptions/{sub}."
+    id: subscription
+    var_type: str
+  - description: "Required. The acknowledgment ID for the messages being\n   acknowledged\
+      \ that was returned by the Pub/Sub system in the\n   Pull response.\
+      \ Must not be empty."
+    id: ack_ids
+    var_type: Sequence[str]
+  children: []
+  class: google.cloud.pubsub_v1.types.AcknowledgeRequest
+  fullName: google.cloud.pubsub_v1.types.AcknowledgeRequest
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: proto.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: AcknowledgeRequest
+  source:
+    id: AcknowledgeRequest
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Request for the Acknowledge method.
+
+    '
+  syntax:
+    content: AcknowledgeRequest(mapping=None, *, ignore_unknown_fields=False, **kwargs)
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.types.AcknowledgeRequest
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.AuditConfig.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.AuditConfig.yml
new file mode 100644
index 000000000000..b9526f2c51c5
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.AuditConfig.yml
@@ -0,0 +1,30 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- children: []
+  class: google.cloud.pubsub_v1.types.AuditConfig
+  fullName: google.cloud.pubsub_v1.types.AuditConfig
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: google._upb._message.Message
+  - inheritance:
+    - type: builtins.object
+    type: google.protobuf.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: AuditConfig
+  source:
+    id: AuditConfig
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: API documentation for `pubsub_v1.types.AuditConfig` class.
+  syntax: {}
+  type: class
+  uid: google.cloud.pubsub_v1.types.AuditConfig
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.AuditConfigDelta.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.AuditConfigDelta.yml
new file mode 100644
index 000000000000..663cfbf77ff5
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.AuditConfigDelta.yml
@@ -0,0 +1,30 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- children: []
+  class: google.cloud.pubsub_v1.types.AuditConfigDelta
+  fullName: google.cloud.pubsub_v1.types.AuditConfigDelta
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: google._upb._message.Message
+  - inheritance:
+    - type: builtins.object
+    type: google.protobuf.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: AuditConfigDelta
+  source:
+    id: AuditConfigDelta
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: API documentation for `pubsub_v1.types.AuditConfigDelta` class.
+  syntax: {}
+  type: class
+  uid: google.cloud.pubsub_v1.types.AuditConfigDelta
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.AuditData.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.AuditData.yml
new file mode 100644
index 000000000000..81cc4c37a0e2
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.AuditData.yml
@@ -0,0 +1,30 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- children: []
+  class: google.cloud.pubsub_v1.types.AuditData
+  fullName: google.cloud.pubsub_v1.types.AuditData
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: google._upb._message.Message
+  - inheritance:
+    - type: builtins.object
+    type: google.protobuf.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: AuditData
+  source:
+    id: AuditData
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: API documentation for `pubsub_v1.types.AuditData` class.
+  syntax: {}
+  type: class
+  uid: google.cloud.pubsub_v1.types.AuditData
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.AuditLogConfig.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.AuditLogConfig.yml
new file mode 100644
index 000000000000..77cdd5b92c98
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.AuditLogConfig.yml
@@ -0,0 +1,30 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- children: []
+  class: google.cloud.pubsub_v1.types.AuditLogConfig
+  fullName: google.cloud.pubsub_v1.types.AuditLogConfig
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: google._upb._message.Message
+  - inheritance:
+    - type: builtins.object
+    type: google.protobuf.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: AuditLogConfig
+  source:
+    id: AuditLogConfig
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: API documentation for `pubsub_v1.types.AuditLogConfig` class.
+  syntax: {}
+  type: class
+  uid: google.cloud.pubsub_v1.types.AuditLogConfig
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.BatchSettings.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.BatchSettings.yml
new file mode 100644
index 000000000000..b2f775ed1a29
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.BatchSettings.yml
@@ -0,0 +1,157 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes: []
+  children:
+  - google.cloud.pubsub_v1.types.BatchSettings
+  - google.cloud.pubsub_v1.types.BatchSettings.max_bytes
+  - google.cloud.pubsub_v1.types.BatchSettings.max_latency
+  - google.cloud.pubsub_v1.types.BatchSettings.max_messages
+  class: google.cloud.pubsub_v1.types.BatchSettings
+  fullName: google.cloud.pubsub_v1.types.BatchSettings
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: builtins.tuple
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: BatchSettings
+  source:
+    id: BatchSettings
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/types.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/types.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 63
+  summary: 'The settings for batch publishing the messages.
+
+
+    '
+  syntax:
+    content: "BatchSettings(\n    max_bytes: int = 1000000, max_latency: float = 0.01,\
+      \ max_messages: int = 100\n)"
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.types.BatchSettings
+- attributes: []
+  class: google.cloud.pubsub_v1.types.BatchSettings
+  fullName: google.cloud.pubsub_v1.types.BatchSettings
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: builtins.tuple
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: BatchSettings
+  source:
+    id: BatchSettings
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/types.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/types.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 63
+  summary: 'Create new instance of BatchSettings(max_bytes, max_latency, max_messages)
+
+
+    '
+  syntax:
+    content: "BatchSettings(\n    max_bytes: int = 1000000, max_latency: float = 0.01,\
+      \ max_messages: int = 100\n)"
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.types.BatchSettings
+- attributes: []
+  class: google.cloud.pubsub_v1.types.BatchSettings
+  fullName: google.cloud.pubsub_v1.types.BatchSettings.max_bytes
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: max_bytes
+  source:
+    id: max_bytes
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'The maximum total size of the messages to collect before automatically
+    publishing the batch, including any byte size overhead of the publish request
+    itself. The maximum value is bound by the server-side limit of 10_000_000 bytes.
+
+
+    '
+  syntax: {}
+  type: attribute
+  uid: google.cloud.pubsub_v1.types.BatchSettings.max_bytes
+- attributes: []
+  class: google.cloud.pubsub_v1.types.BatchSettings
+  fullName: google.cloud.pubsub_v1.types.BatchSettings.max_latency
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: max_latency
+  source:
+    id: max_latency
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'The maximum number of seconds to wait for additional messages before automatically
+    publishing the batch.
+
+
+    '
+  syntax: {}
+  type: attribute
+  uid: google.cloud.pubsub_v1.types.BatchSettings.max_latency
+- attributes: []
+  class: google.cloud.pubsub_v1.types.BatchSettings
+  fullName: google.cloud.pubsub_v1.types.BatchSettings.max_messages
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: max_messages
+  source:
+    id: max_messages
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'The maximum number of messages to collect before automatically publishing
+    the batch.
+
+
+    '
+  syntax: {}
+  type: attribute
+  uid: google.cloud.pubsub_v1.types.BatchSettings.max_messages
+references:
+- fullName: google.cloud.pubsub_v1.types.BatchSettings
+  isExternal: false
+  name: BatchSettings
+  parent: google.cloud.pubsub_v1.types.BatchSettings
+  uid: google.cloud.pubsub_v1.types.BatchSettings
+- fullName: google.cloud.pubsub_v1.types.BatchSettings.max_bytes
+  isExternal: false
+  name: max_bytes
+  parent: google.cloud.pubsub_v1.types.BatchSettings
+  uid: google.cloud.pubsub_v1.types.BatchSettings.max_bytes
+- fullName: google.cloud.pubsub_v1.types.BatchSettings.max_latency
+  isExternal: false
+  name: max_latency
+  parent: google.cloud.pubsub_v1.types.BatchSettings
+  uid: google.cloud.pubsub_v1.types.BatchSettings.max_latency
+- fullName: google.cloud.pubsub_v1.types.BatchSettings.max_messages
+  isExternal: false
+  name: max_messages
+  parent: google.cloud.pubsub_v1.types.BatchSettings
+  uid: google.cloud.pubsub_v1.types.BatchSettings.max_messages
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.BigQueryConfig.State.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.BigQueryConfig.State.yml
new file mode 100644
index 000000000000..bcfe8d21a612
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.BigQueryConfig.State.yml
@@ -0,0 +1,40 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes: []
+  children: []
+  class: google.cloud.pubsub_v1.types.BigQueryConfig.State
+  fullName: google.cloud.pubsub_v1.types.BigQueryConfig.State
+  inheritance:
+  - inheritance:
+    - inheritance:
+      - inheritance:
+        - type: builtins.object
+        type: builtins.int
+      - inheritance:
+        - type: builtins.object
+        type: enum.Enum
+      type: enum.IntEnum
+    type: proto.enums.Enum
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types.BigQueryConfig
+  name: State
+  source:
+    id: State
+    path: tests/testdata/gapic-combo/google/pubsub_v1/types/pubsub.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/types/pubsub.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 1041
+  summary: 'Possible states for a BigQuery subscription.
+
+
+    '
+  syntax:
+    content: State(value)
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.types.BigQueryConfig.State
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.BigQueryConfig.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.BigQueryConfig.yml
new file mode 100644
index 000000000000..3cefa30ffb54
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.BigQueryConfig.yml
@@ -0,0 +1,63 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes:
+  - description: "The name of the table to which to write data,\n   of the form {projectId}:{datasetId}.{tableId}"
+    id: table
+    var_type: str
+  - description: "When true, use the topic's schema as the\n   columns to write to\
+      \ in BigQuery, if it exists."
+    id: use_topic_schema
+    var_type: bool
+  - description: "When true, write the subscription name, message_id,\n   publish_time,\
+      \ attributes, and ordering_key to additional\n   columns in the table. The subscription\
+      \ name, message_id, and\n   publish_time fields are put in their own columns\
+      \ while all\n   other message properties (other than data) are written to a\n\
+      \   JSON object in the attributes column."
+    id: write_metadata
+    var_type: bool
+  - description: "When true and use_topic_schema is true, any fields that are\n  \
+      \ a part of the topic schema that are not part of the BigQuery\n   table schema\
+      \ are dropped when writing to BigQuery.\n   Otherwise, the schemas must be kept\
+      \ in sync and any messages\n   with extra fields are not written and remain\
+      \ in the\n   subscription's backlog."
+    id: drop_unknown_fields
+    var_type: bool
+  - description: "Output only. An output-only field that\n   indicates whether or\
+      \ not the subscription can\n   receive messages."
+    id: state
+    var_type: google.pubsub_v1.types.BigQueryConfig.State
+  children:
+  - google.cloud.pubsub_v1.types.BigQueryConfig.State
+  class: google.cloud.pubsub_v1.types.BigQueryConfig
+  fullName: google.cloud.pubsub_v1.types.BigQueryConfig
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: proto.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: BigQueryConfig
+  source:
+    id: BigQueryConfig
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Configuration for a BigQuery subscription.
+
+    '
+  syntax:
+    content: BigQueryConfig(mapping=None, *, ignore_unknown_fields=False, **kwargs)
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.types.BigQueryConfig
+references:
+- fullName: google.cloud.pubsub_v1.types.BigQueryConfig.State
+  isExternal: false
+  name: State
+  parent: google.cloud.pubsub_v1.types.BigQueryConfig
+  uid: google.cloud.pubsub_v1.types.BigQueryConfig.State
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Binding.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Binding.yml
new file mode 100644
index 000000000000..acf3bac4ca2e
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Binding.yml
@@ -0,0 +1,30 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- children: []
+  class: google.cloud.pubsub_v1.types.Binding
+  fullName: google.cloud.pubsub_v1.types.Binding
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: google._upb._message.Message
+  - inheritance:
+    - type: builtins.object
+    type: google.protobuf.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: Binding
+  source:
+    id: Binding
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: API documentation for `pubsub_v1.types.Binding` class.
+  syntax: {}
+  type: class
+  uid: google.cloud.pubsub_v1.types.Binding
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.BindingDelta.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.BindingDelta.yml
new file mode 100644
index 000000000000..5c82e4627c5e
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.BindingDelta.yml
@@ -0,0 +1,30 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- children: []
+  class: google.cloud.pubsub_v1.types.BindingDelta
+  fullName: google.cloud.pubsub_v1.types.BindingDelta
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: google._upb._message.Message
+  - inheritance:
+    - type: builtins.object
+    type: google.protobuf.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: BindingDelta
+  source:
+    id: BindingDelta
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: API documentation for `pubsub_v1.types.BindingDelta` class.
+  syntax: {}
+  type: class
+  uid: google.cloud.pubsub_v1.types.BindingDelta
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.CreateSnapshotRequest.LabelsEntry.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.CreateSnapshotRequest.LabelsEntry.yml
new file mode 100644
index 000000000000..7a633cdbd632
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.CreateSnapshotRequest.LabelsEntry.yml
@@ -0,0 +1,44 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes: []
+  children: []
+  class: google.cloud.pubsub_v1.types.CreateSnapshotRequest.LabelsEntry
+  fullName: google.cloud.pubsub_v1.types.CreateSnapshotRequest.LabelsEntry
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: proto.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types.CreateSnapshotRequest
+  name: LabelsEntry
+  source:
+    id: LabelsEntry
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'The abstract base class for a message.
+
+    '
+  syntax:
+    content: LabelsEntry(mapping=None, *, ignore_unknown_fields=False, **kwargs)
+    parameters:
+    - defaultValue: None
+      description: Keys and values corresponding to the fields of the message.
+      id: kwargs
+      var_type: dict
+    - description: A dictionary or message to be used to determine the values for
+        this message.
+      id: mapping
+      var_type: Union[dict, .Message]
+    - description: If True, do not raise errors for unknown fields. Only applied if
+        mapping is a mapping type or there are keyword parameters.
+      id: ignore_unknown_fields
+      var_type: Optional(bool)
+  type: class
+  uid: google.cloud.pubsub_v1.types.CreateSnapshotRequest.LabelsEntry
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.CreateSnapshotRequest.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.CreateSnapshotRequest.yml
new file mode 100644
index 000000000000..cd00b403325b
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.CreateSnapshotRequest.yml
@@ -0,0 +1,58 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes:
+  - description: "Required. User-provided name for this snapshot. If the name\n  \
+      \ is not provided in the request, the server will assign a\n   random name for\
+      \ this snapshot on the same project as the\n   subscription. Note that for REST\
+      \ API requests, you must\n   specify a name. See the resource name rules. Format\
+      \ is\n   projects/{project}/snapshots/{snap}."
+    id: name
+    var_type: str
+  - description: "Required. The subscription whose backlog the snapshot\n   retains.\
+      \ Specifically, the created snapshot is guaranteed to\n   retain: (a) The existing\
+      \ backlog on the subscription. More\n   precisely, this is defined as the messages\
+      \ in the\n   subscription's backlog that are unacknowledged upon the\n   successful\
+      \ completion of the CreateSnapshot request; as\n   well as: (b)\
+      \ Any messages published to the subscription's\n   topic following the successful\
+      \ completion of the\n   CreateSnapshot request. Format is\n   projects/{project}/subscriptions/{sub}."
+    id: subscription
+    var_type: str
+  - description: "See \n   Creating and managing labels."
+    id: labels
+    var_type: Mapping[str, str]
+  children:
+  - google.cloud.pubsub_v1.types.CreateSnapshotRequest.LabelsEntry
+  class: google.cloud.pubsub_v1.types.CreateSnapshotRequest
+  fullName: google.cloud.pubsub_v1.types.CreateSnapshotRequest
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: proto.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: CreateSnapshotRequest
+  source:
+    id: CreateSnapshotRequest
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Request for the `CreateSnapshot` method.
+
+    '
+  syntax:
+    content: CreateSnapshotRequest(mapping=None, *, ignore_unknown_fields=False, **kwargs)
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.types.CreateSnapshotRequest
+references:
+- fullName: google.cloud.pubsub_v1.types.CreateSnapshotRequest.LabelsEntry
+  isExternal: false
+  name: LabelsEntry
+  parent: google.cloud.pubsub_v1.types.CreateSnapshotRequest
+  uid: google.cloud.pubsub_v1.types.CreateSnapshotRequest.LabelsEntry
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.CustomHttpPattern.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.CustomHttpPattern.yml
new file mode 100644
index 000000000000..bae8b2530b83
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.CustomHttpPattern.yml
@@ -0,0 +1,30 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- children: []
+  class: google.cloud.pubsub_v1.types.CustomHttpPattern
+  fullName: google.cloud.pubsub_v1.types.CustomHttpPattern
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: google._upb._message.Message
+  - inheritance:
+    - type: builtins.object
+    type: google.protobuf.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: CustomHttpPattern
+  source:
+    id: CustomHttpPattern
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: API documentation for `pubsub_v1.types.CustomHttpPattern` class.
+  syntax: {}
+  type: class
+  uid: google.cloud.pubsub_v1.types.CustomHttpPattern
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.DeadLetterPolicy.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.DeadLetterPolicy.yml
new file mode 100644
index 000000000000..4d311c4aae14
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.DeadLetterPolicy.yml
@@ -0,0 +1,61 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes:
+  - description: "The name of the topic to which dead letter messages should\n   be\
+      \ published. Format is\n   projects/{project}/topics/{topic}.The\
+      \ Cloud Pub/Sub\n   service account associated with the enclosing subscription's\n\
+      \   parent project (i.e.,\n   service-{project_number}@gcp-sa-pubsub.iam.gserviceaccount.com)\n\
+      \   must have permission to Publish() to this topic.\n   \n   The operation\
+      \ will fail if the topic does not exist. Users\n   should ensure that there\
+      \ is a subscription attached to this\n   topic since messages published to a\
+      \ topic with no\n   subscriptions are lost."
+    id: dead_letter_topic
+    var_type: str
+  - description: "The maximum number of delivery attempts for any message. The\n \
+      \  value must be between 5 and 100.\n   \n   The number of delivery attempts\
+      \ is defined as 1 + (the sum\n   of number of NACKs and number of times the\
+      \ acknowledgement\n   deadline has been exceeded for the message).\n   \n  \
+      \ A NACK is any call to ModifyAckDeadline with a 0 deadline.\n   Note that client\
+      \ libraries may automatically extend\n   ack_deadlines.\n   \n   This field\
+      \ will be honored on a best effort basis.\n   \n   If this parameter is 0, a\
+      \ default value of 5 is used."
+    id: max_delivery_attempts
+    var_type: int
+  children: []
+  class: google.cloud.pubsub_v1.types.DeadLetterPolicy
+  fullName: google.cloud.pubsub_v1.types.DeadLetterPolicy
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: proto.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: DeadLetterPolicy
+  source:
+    id: DeadLetterPolicy
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Dead lettering is done on a best effort basis. The same
+
+    message might be dead lettered multiple times.
+
+
+    If validation on any of the fields fails at subscription
+
+    creation/updation, the create/update subscription request will
+
+    fail.
+
+    '
+  syntax:
+    content: DeadLetterPolicy(mapping=None, *, ignore_unknown_fields=False, **kwargs)
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.types.DeadLetterPolicy
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.DeleteSnapshotRequest.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.DeleteSnapshotRequest.yml
new file mode 100644
index 000000000000..352568c3e3b4
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.DeleteSnapshotRequest.yml
@@ -0,0 +1,35 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes:
+  - description: "Required. The name of the snapshot to delete. Format is\n   projects/{project}/snapshots/{snap}."
+    id: snapshot
+    var_type: str
+  children: []
+  class: google.cloud.pubsub_v1.types.DeleteSnapshotRequest
+  fullName: google.cloud.pubsub_v1.types.DeleteSnapshotRequest
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: proto.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: DeleteSnapshotRequest
+  source:
+    id: DeleteSnapshotRequest
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Request for the `DeleteSnapshot` method.
+
+    '
+  syntax:
+    content: DeleteSnapshotRequest(mapping=None, *, ignore_unknown_fields=False, **kwargs)
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.types.DeleteSnapshotRequest
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.DeleteSubscriptionRequest.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.DeleteSubscriptionRequest.yml
new file mode 100644
index 000000000000..66cd0bf712d1
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.DeleteSubscriptionRequest.yml
@@ -0,0 +1,36 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes:
+  - description: "Required. The subscription to delete. Format is\n   projects/{project}/subscriptions/{sub}."
+    id: subscription
+    var_type: str
+  children: []
+  class: google.cloud.pubsub_v1.types.DeleteSubscriptionRequest
+  fullName: google.cloud.pubsub_v1.types.DeleteSubscriptionRequest
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: proto.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: DeleteSubscriptionRequest
+  source:
+    id: DeleteSubscriptionRequest
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Request for the DeleteSubscription method.
+
+    '
+  syntax:
+    content: DeleteSubscriptionRequest(mapping=None, *, ignore_unknown_fields=False,
+      **kwargs)
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.types.DeleteSubscriptionRequest
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.DeleteTopicRequest.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.DeleteTopicRequest.yml
new file mode 100644
index 000000000000..413235b8f69a
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.DeleteTopicRequest.yml
@@ -0,0 +1,35 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes:
+  - description: "Required. Name of the topic to delete. Format is\n   projects/{project}/topics/{topic}."
+    id: topic
+    var_type: str
+  children: []
+  class: google.cloud.pubsub_v1.types.DeleteTopicRequest
+  fullName: google.cloud.pubsub_v1.types.DeleteTopicRequest
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: proto.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: DeleteTopicRequest
+  source:
+    id: DeleteTopicRequest
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Request for the `DeleteTopic` method.
+
+    '
+  syntax:
+    content: DeleteTopicRequest(mapping=None, *, ignore_unknown_fields=False, **kwargs)
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.types.DeleteTopicRequest
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.DescriptorProto.ExtensionRange.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.DescriptorProto.ExtensionRange.yml
new file mode 100644
index 000000000000..e60f2a665997
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.DescriptorProto.ExtensionRange.yml
@@ -0,0 +1,31 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- children: []
+  class: google.cloud.pubsub_v1.types.DescriptorProto.ExtensionRange
+  fullName: google.cloud.pubsub_v1.types.DescriptorProto.ExtensionRange
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: google._upb._message.Message
+  - inheritance:
+    - type: builtins.object
+    type: google.protobuf.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types.DescriptorProto
+  name: ExtensionRange
+  source:
+    id: ExtensionRange
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: API documentation for `pubsub_v1.types.DescriptorProto.ExtensionRange`
+    class.
+  syntax: {}
+  type: class
+  uid: google.cloud.pubsub_v1.types.DescriptorProto.ExtensionRange
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.DescriptorProto.ReservedRange.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.DescriptorProto.ReservedRange.yml
new file mode 100644
index 000000000000..c0b841f99213
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.DescriptorProto.ReservedRange.yml
@@ -0,0 +1,30 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- children: []
+  class: google.cloud.pubsub_v1.types.DescriptorProto.ReservedRange
+  fullName: google.cloud.pubsub_v1.types.DescriptorProto.ReservedRange
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: google._upb._message.Message
+  - inheritance:
+    - type: builtins.object
+    type: google.protobuf.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types.DescriptorProto
+  name: ReservedRange
+  source:
+    id: ReservedRange
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: API documentation for `pubsub_v1.types.DescriptorProto.ReservedRange` class.
+  syntax: {}
+  type: class
+  uid: google.cloud.pubsub_v1.types.DescriptorProto.ReservedRange
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.DescriptorProto.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.DescriptorProto.yml
new file mode 100644
index 000000000000..e071bd4a8a87
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.DescriptorProto.yml
@@ -0,0 +1,42 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- children:
+  - google.cloud.pubsub_v1.types.DescriptorProto.ExtensionRange
+  - google.cloud.pubsub_v1.types.DescriptorProto.ReservedRange
+  class: google.cloud.pubsub_v1.types.DescriptorProto
+  fullName: google.cloud.pubsub_v1.types.DescriptorProto
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: google._upb._message.Message
+  - inheritance:
+    - type: builtins.object
+    type: google.protobuf.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: DescriptorProto
+  source:
+    id: DescriptorProto
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: API documentation for `pubsub_v1.types.DescriptorProto` class.
+  syntax: {}
+  type: class
+  uid: google.cloud.pubsub_v1.types.DescriptorProto
+references:
+- fullName: google.cloud.pubsub_v1.types.DescriptorProto.ExtensionRange
+  isExternal: false
+  name: ExtensionRange
+  parent: google.cloud.pubsub_v1.types.DescriptorProto
+  uid: google.cloud.pubsub_v1.types.DescriptorProto.ExtensionRange
+- fullName: google.cloud.pubsub_v1.types.DescriptorProto.ReservedRange
+  isExternal: false
+  name: ReservedRange
+  parent: google.cloud.pubsub_v1.types.DescriptorProto
+  uid: google.cloud.pubsub_v1.types.DescriptorProto.ReservedRange
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.DetachSubscriptionRequest.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.DetachSubscriptionRequest.yml
new file mode 100644
index 000000000000..069a612ccf3e
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.DetachSubscriptionRequest.yml
@@ -0,0 +1,36 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes:
+  - description: "Required. The subscription to detach. Format is\n   projects/{project}/subscriptions/{subscription}."
+    id: subscription
+    var_type: str
+  children: []
+  class: google.cloud.pubsub_v1.types.DetachSubscriptionRequest
+  fullName: google.cloud.pubsub_v1.types.DetachSubscriptionRequest
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: proto.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: DetachSubscriptionRequest
+  source:
+    id: DetachSubscriptionRequest
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Request for the DetachSubscription method.
+
+    '
+  syntax:
+    content: DetachSubscriptionRequest(mapping=None, *, ignore_unknown_fields=False,
+      **kwargs)
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.types.DetachSubscriptionRequest
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.DetachSubscriptionResponse.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.DetachSubscriptionResponse.yml
new file mode 100644
index 000000000000..1572f20d0700
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.DetachSubscriptionResponse.yml
@@ -0,0 +1,35 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes: []
+  children: []
+  class: google.cloud.pubsub_v1.types.DetachSubscriptionResponse
+  fullName: google.cloud.pubsub_v1.types.DetachSubscriptionResponse
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: proto.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: DetachSubscriptionResponse
+  source:
+    id: DetachSubscriptionResponse
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Response for the DetachSubscription method.
+
+    Reserved for future use.
+
+    '
+  syntax:
+    content: DetachSubscriptionResponse(mapping=None, *, ignore_unknown_fields=False,
+      **kwargs)
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.types.DetachSubscriptionResponse
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Duration.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Duration.yml
new file mode 100644
index 000000000000..0a4691c40214
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Duration.yml
@@ -0,0 +1,33 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- children: []
+  class: google.cloud.pubsub_v1.types.Duration
+  fullName: google.cloud.pubsub_v1.types.Duration
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: google._upb._message.Message
+  - inheritance:
+    - type: builtins.object
+    type: google.protobuf.message.Message
+  - inheritance:
+    - type: builtins.object
+    type: google.protobuf.internal.well_known_types.Duration
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: Duration
+  source:
+    id: Duration
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: API documentation for `pubsub_v1.types.Duration` class.
+  syntax: {}
+  type: class
+  uid: google.cloud.pubsub_v1.types.Duration
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Empty.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Empty.yml
new file mode 100644
index 000000000000..89ffe3c7badb
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Empty.yml
@@ -0,0 +1,30 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- children: []
+  class: google.cloud.pubsub_v1.types.Empty
+  fullName: google.cloud.pubsub_v1.types.Empty
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: google._upb._message.Message
+  - inheritance:
+    - type: builtins.object
+    type: google.protobuf.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: Empty
+  source:
+    id: Empty
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: API documentation for `pubsub_v1.types.Empty` class.
+  syntax: {}
+  type: class
+  uid: google.cloud.pubsub_v1.types.Empty
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.EnumDescriptorProto.EnumReservedRange.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.EnumDescriptorProto.EnumReservedRange.yml
new file mode 100644
index 000000000000..8c0e8096dd2c
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.EnumDescriptorProto.EnumReservedRange.yml
@@ -0,0 +1,31 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- children: []
+  class: google.cloud.pubsub_v1.types.EnumDescriptorProto.EnumReservedRange
+  fullName: google.cloud.pubsub_v1.types.EnumDescriptorProto.EnumReservedRange
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: google._upb._message.Message
+  - inheritance:
+    - type: builtins.object
+    type: google.protobuf.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types.EnumDescriptorProto
+  name: EnumReservedRange
+  source:
+    id: EnumReservedRange
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: API documentation for `pubsub_v1.types.EnumDescriptorProto.EnumReservedRange`
+    class.
+  syntax: {}
+  type: class
+  uid: google.cloud.pubsub_v1.types.EnumDescriptorProto.EnumReservedRange
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.EnumDescriptorProto.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.EnumDescriptorProto.yml
new file mode 100644
index 000000000000..124db4454f65
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.EnumDescriptorProto.yml
@@ -0,0 +1,36 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- children:
+  - google.cloud.pubsub_v1.types.EnumDescriptorProto.EnumReservedRange
+  class: google.cloud.pubsub_v1.types.EnumDescriptorProto
+  fullName: google.cloud.pubsub_v1.types.EnumDescriptorProto
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: google._upb._message.Message
+  - inheritance:
+    - type: builtins.object
+    type: google.protobuf.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: EnumDescriptorProto
+  source:
+    id: EnumDescriptorProto
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: API documentation for `pubsub_v1.types.EnumDescriptorProto` class.
+  syntax: {}
+  type: class
+  uid: google.cloud.pubsub_v1.types.EnumDescriptorProto
+references:
+- fullName: google.cloud.pubsub_v1.types.EnumDescriptorProto.EnumReservedRange
+  isExternal: false
+  name: EnumReservedRange
+  parent: google.cloud.pubsub_v1.types.EnumDescriptorProto
+  uid: google.cloud.pubsub_v1.types.EnumDescriptorProto.EnumReservedRange
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.EnumOptions.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.EnumOptions.yml
new file mode 100644
index 000000000000..90d5e2573cd2
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.EnumOptions.yml
@@ -0,0 +1,30 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- children: []
+  class: google.cloud.pubsub_v1.types.EnumOptions
+  fullName: google.cloud.pubsub_v1.types.EnumOptions
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: google._upb._message.Message
+  - inheritance:
+    - type: builtins.object
+    type: google.protobuf.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: EnumOptions
+  source:
+    id: EnumOptions
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: API documentation for `pubsub_v1.types.EnumOptions` class.
+  syntax: {}
+  type: class
+  uid: google.cloud.pubsub_v1.types.EnumOptions
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.EnumValueDescriptorProto.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.EnumValueDescriptorProto.yml
new file mode 100644
index 000000000000..deed96d2858a
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.EnumValueDescriptorProto.yml
@@ -0,0 +1,30 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- children: []
+  class: google.cloud.pubsub_v1.types.EnumValueDescriptorProto
+  fullName: google.cloud.pubsub_v1.types.EnumValueDescriptorProto
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: google._upb._message.Message
+  - inheritance:
+    - type: builtins.object
+    type: google.protobuf.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: EnumValueDescriptorProto
+  source:
+    id: EnumValueDescriptorProto
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: API documentation for `pubsub_v1.types.EnumValueDescriptorProto` class.
+  syntax: {}
+  type: class
+  uid: google.cloud.pubsub_v1.types.EnumValueDescriptorProto
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.EnumValueOptions.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.EnumValueOptions.yml
new file mode 100644
index 000000000000..816fc976c027
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.EnumValueOptions.yml
@@ -0,0 +1,30 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- children: []
+  class: google.cloud.pubsub_v1.types.EnumValueOptions
+  fullName: google.cloud.pubsub_v1.types.EnumValueOptions
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: google._upb._message.Message
+  - inheritance:
+    - type: builtins.object
+    type: google.protobuf.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: EnumValueOptions
+  source:
+    id: EnumValueOptions
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: API documentation for `pubsub_v1.types.EnumValueOptions` class.
+  syntax: {}
+  type: class
+  uid: google.cloud.pubsub_v1.types.EnumValueOptions
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ExpirationPolicy.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ExpirationPolicy.yml
new file mode 100644
index 000000000000..6164ffdce025
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ExpirationPolicy.yml
@@ -0,0 +1,42 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes:
+  - description: "Specifies the \"time-to-live\" duration for an associated\n   resource.\
+      \ The resource expires if it is not active for a\n   period of ttl.\
+      \ The definition of \"activity\" depends on\n   the type of the associated resource.\
+      \ The minimum and maximum\n   allowed values for ttl depend on\
+      \ the type of the\n   associated resource, as well. If ttl is not\
+      \ set, the\n   associated resource never expires."
+    id: ttl
+    var_type: google.protobuf.duration_pb2.Duration
+  children: []
+  class: google.cloud.pubsub_v1.types.ExpirationPolicy
+  fullName: google.cloud.pubsub_v1.types.ExpirationPolicy
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: proto.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: ExpirationPolicy
+  source:
+    id: ExpirationPolicy
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'A policy that specifies the conditions for resource
+
+    expiration (i.e., automatic resource deletion).
+
+    '
+  syntax:
+    content: ExpirationPolicy(mapping=None, *, ignore_unknown_fields=False, **kwargs)
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.types.ExpirationPolicy
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ExtensionRangeOptions.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ExtensionRangeOptions.yml
new file mode 100644
index 000000000000..ac0652177255
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ExtensionRangeOptions.yml
@@ -0,0 +1,30 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- children: []
+  class: google.cloud.pubsub_v1.types.ExtensionRangeOptions
+  fullName: google.cloud.pubsub_v1.types.ExtensionRangeOptions
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: google._upb._message.Message
+  - inheritance:
+    - type: builtins.object
+    type: google.protobuf.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: ExtensionRangeOptions
+  source:
+    id: ExtensionRangeOptions
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: API documentation for `pubsub_v1.types.ExtensionRangeOptions` class.
+  syntax: {}
+  type: class
+  uid: google.cloud.pubsub_v1.types.ExtensionRangeOptions
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.FieldDescriptorProto.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.FieldDescriptorProto.yml
new file mode 100644
index 000000000000..83a149455276
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.FieldDescriptorProto.yml
@@ -0,0 +1,30 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- children: []
+  class: google.cloud.pubsub_v1.types.FieldDescriptorProto
+  fullName: google.cloud.pubsub_v1.types.FieldDescriptorProto
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: google._upb._message.Message
+  - inheritance:
+    - type: builtins.object
+    type: google.protobuf.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: FieldDescriptorProto
+  source:
+    id: FieldDescriptorProto
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: API documentation for `pubsub_v1.types.FieldDescriptorProto` class.
+  syntax: {}
+  type: class
+  uid: google.cloud.pubsub_v1.types.FieldDescriptorProto
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.FieldMask.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.FieldMask.yml
new file mode 100644
index 000000000000..b8225ff65941
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.FieldMask.yml
@@ -0,0 +1,33 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- children: []
+  class: google.cloud.pubsub_v1.types.FieldMask
+  fullName: google.cloud.pubsub_v1.types.FieldMask
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: google._upb._message.Message
+  - inheritance:
+    - type: builtins.object
+    type: google.protobuf.message.Message
+  - inheritance:
+    - type: builtins.object
+    type: google.protobuf.internal.well_known_types.FieldMask
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: FieldMask
+  source:
+    id: FieldMask
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: API documentation for `pubsub_v1.types.FieldMask` class.
+  syntax: {}
+  type: class
+  uid: google.cloud.pubsub_v1.types.FieldMask
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.FieldOptions.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.FieldOptions.yml
new file mode 100644
index 000000000000..90a82aeb34d1
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.FieldOptions.yml
@@ -0,0 +1,30 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- children: []
+  class: google.cloud.pubsub_v1.types.FieldOptions
+  fullName: google.cloud.pubsub_v1.types.FieldOptions
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: google._upb._message.Message
+  - inheritance:
+    - type: builtins.object
+    type: google.protobuf.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: FieldOptions
+  source:
+    id: FieldOptions
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: API documentation for `pubsub_v1.types.FieldOptions` class.
+  syntax: {}
+  type: class
+  uid: google.cloud.pubsub_v1.types.FieldOptions
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.FileDescriptorProto.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.FileDescriptorProto.yml
new file mode 100644
index 000000000000..218efeb78fe7
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.FileDescriptorProto.yml
@@ -0,0 +1,30 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- children: []
+  class: google.cloud.pubsub_v1.types.FileDescriptorProto
+  fullName: google.cloud.pubsub_v1.types.FileDescriptorProto
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: google._upb._message.Message
+  - inheritance:
+    - type: builtins.object
+    type: google.protobuf.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: FileDescriptorProto
+  source:
+    id: FileDescriptorProto
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: API documentation for `pubsub_v1.types.FileDescriptorProto` class.
+  syntax: {}
+  type: class
+  uid: google.cloud.pubsub_v1.types.FileDescriptorProto
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.FileDescriptorSet.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.FileDescriptorSet.yml
new file mode 100644
index 000000000000..7ec0aa5c8805
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.FileDescriptorSet.yml
@@ -0,0 +1,30 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- children: []
+  class: google.cloud.pubsub_v1.types.FileDescriptorSet
+  fullName: google.cloud.pubsub_v1.types.FileDescriptorSet
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: google._upb._message.Message
+  - inheritance:
+    - type: builtins.object
+    type: google.protobuf.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: FileDescriptorSet
+  source:
+    id: FileDescriptorSet
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: API documentation for `pubsub_v1.types.FileDescriptorSet` class.
+  syntax: {}
+  type: class
+  uid: google.cloud.pubsub_v1.types.FileDescriptorSet
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.FileOptions.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.FileOptions.yml
new file mode 100644
index 000000000000..070a5c383ccc
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.FileOptions.yml
@@ -0,0 +1,30 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- children: []
+  class: google.cloud.pubsub_v1.types.FileOptions
+  fullName: google.cloud.pubsub_v1.types.FileOptions
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: google._upb._message.Message
+  - inheritance:
+    - type: builtins.object
+    type: google.protobuf.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: FileOptions
+  source:
+    id: FileOptions
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: API documentation for `pubsub_v1.types.FileOptions` class.
+  syntax: {}
+  type: class
+  uid: google.cloud.pubsub_v1.types.FileOptions
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.FlowControl.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.FlowControl.yml
new file mode 100644
index 000000000000..97edd40235ae
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.FlowControl.yml
@@ -0,0 +1,221 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes: []
+  children:
+  - google.cloud.pubsub_v1.types.FlowControl
+  - google.cloud.pubsub_v1.types.FlowControl.max_bytes
+  - google.cloud.pubsub_v1.types.FlowControl.max_duration_per_lease_extension
+  - google.cloud.pubsub_v1.types.FlowControl.max_lease_duration
+  - google.cloud.pubsub_v1.types.FlowControl.max_messages
+  - google.cloud.pubsub_v1.types.FlowControl.min_duration_per_lease_extension
+  class: google.cloud.pubsub_v1.types.FlowControl
+  fullName: google.cloud.pubsub_v1.types.FlowControl
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: builtins.tuple
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: FlowControl
+  source:
+    id: FlowControl
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/types.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/types.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 142
+  summary: 'The settings for controlling the rate at which messages are pulled
+
+    with an asynchronous subscription.
+
+
+    '
+  syntax:
+    content: "FlowControl(\n    max_bytes: int = 104857600,\n    max_messages: int\
+      \ = 1000,\n    max_lease_duration: float = 3600,\n    min_duration_per_lease_extension:\
+      \ float = 0,\n    max_duration_per_lease_extension: float = 0,\n)"
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.types.FlowControl
+- attributes: []
+  class: google.cloud.pubsub_v1.types.FlowControl
+  fullName: google.cloud.pubsub_v1.types.FlowControl
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: builtins.tuple
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: FlowControl
+  source:
+    id: FlowControl
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/types.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/types.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 142
+  summary: 'Create new instance of FlowControl(max_bytes, max_messages, max_lease_duration,
+    min_duration_per_lease_extension, max_duration_per_lease_extension)
+
+
+    '
+  syntax:
+    content: "FlowControl(\n    max_bytes: int = 104857600,\n    max_messages: int\
+      \ = 1000,\n    max_lease_duration: float = 3600,\n    min_duration_per_lease_extension:\
+      \ float = 0,\n    max_duration_per_lease_extension: float = 0,\n)"
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.types.FlowControl
+- attributes: []
+  class: google.cloud.pubsub_v1.types.FlowControl
+  fullName: google.cloud.pubsub_v1.types.FlowControl.max_bytes
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: max_bytes
+  source:
+    id: max_bytes
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'The maximum total size of received - but not yet processed - messages
+    before pausing the message stream.
+
+
+    '
+  syntax: {}
+  type: attribute
+  uid: google.cloud.pubsub_v1.types.FlowControl.max_bytes
+- attributes: []
+  class: google.cloud.pubsub_v1.types.FlowControl
+  fullName: google.cloud.pubsub_v1.types.FlowControl.max_duration_per_lease_extension
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: max_duration_per_lease_extension
+  source:
+    id: max_duration_per_lease_extension
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'The max amount of time in seconds for a single lease extension attempt.
+    Bounds the delay before a message redelivery if the subscriber fails to extend
+    the deadline. Must be between 10 and 600 (inclusive). Ignored if set to 0.
+
+
+    '
+  syntax: {}
+  type: attribute
+  uid: google.cloud.pubsub_v1.types.FlowControl.max_duration_per_lease_extension
+- attributes: []
+  class: google.cloud.pubsub_v1.types.FlowControl
+  fullName: google.cloud.pubsub_v1.types.FlowControl.max_lease_duration
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: max_lease_duration
+  source:
+    id: max_lease_duration
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'The maximum amount of time in seconds to hold a lease on a message before
+    dropping it from the lease management.
+
+
+    '
+  syntax: {}
+  type: attribute
+  uid: google.cloud.pubsub_v1.types.FlowControl.max_lease_duration
+- attributes: []
+  class: google.cloud.pubsub_v1.types.FlowControl
+  fullName: google.cloud.pubsub_v1.types.FlowControl.max_messages
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: max_messages
+  source:
+    id: max_messages
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'The maximum number of received - but not yet processed - messages before
+    pausing the message stream.
+
+
+    '
+  syntax: {}
+  type: attribute
+  uid: google.cloud.pubsub_v1.types.FlowControl.max_messages
+- attributes: []
+  class: google.cloud.pubsub_v1.types.FlowControl
+  fullName: google.cloud.pubsub_v1.types.FlowControl.min_duration_per_lease_extension
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: min_duration_per_lease_extension
+  source:
+    id: min_duration_per_lease_extension
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'The min amount of time in seconds for a single lease extension attempt.
+    Must be between 10 and 600 (inclusive). Ignored by default, but set to 60 seconds
+    if the subscription has exactly-once delivery enabled.
+
+
+    '
+  syntax: {}
+  type: attribute
+  uid: google.cloud.pubsub_v1.types.FlowControl.min_duration_per_lease_extension
+references:
+- fullName: google.cloud.pubsub_v1.types.FlowControl
+  isExternal: false
+  name: FlowControl
+  parent: google.cloud.pubsub_v1.types.FlowControl
+  uid: google.cloud.pubsub_v1.types.FlowControl
+- fullName: google.cloud.pubsub_v1.types.FlowControl.max_bytes
+  isExternal: false
+  name: max_bytes
+  parent: google.cloud.pubsub_v1.types.FlowControl
+  uid: google.cloud.pubsub_v1.types.FlowControl.max_bytes
+- fullName: google.cloud.pubsub_v1.types.FlowControl.max_duration_per_lease_extension
+  isExternal: false
+  name: max_duration_per_lease_extension
+  parent: google.cloud.pubsub_v1.types.FlowControl
+  uid: google.cloud.pubsub_v1.types.FlowControl.max_duration_per_lease_extension
+- fullName: google.cloud.pubsub_v1.types.FlowControl.max_lease_duration
+  isExternal: false
+  name: max_lease_duration
+  parent: google.cloud.pubsub_v1.types.FlowControl
+  uid: google.cloud.pubsub_v1.types.FlowControl.max_lease_duration
+- fullName: google.cloud.pubsub_v1.types.FlowControl.max_messages
+  isExternal: false
+  name: max_messages
+  parent: google.cloud.pubsub_v1.types.FlowControl
+  uid: google.cloud.pubsub_v1.types.FlowControl.max_messages
+- fullName: google.cloud.pubsub_v1.types.FlowControl.min_duration_per_lease_extension
+  isExternal: false
+  name: min_duration_per_lease_extension
+  parent: google.cloud.pubsub_v1.types.FlowControl
+  uid: google.cloud.pubsub_v1.types.FlowControl.min_duration_per_lease_extension
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.GeneratedCodeInfo.Annotation.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.GeneratedCodeInfo.Annotation.yml
new file mode 100644
index 000000000000..a3d04d8ce332
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.GeneratedCodeInfo.Annotation.yml
@@ -0,0 +1,30 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- children: []
+  class: google.cloud.pubsub_v1.types.GeneratedCodeInfo.Annotation
+  fullName: google.cloud.pubsub_v1.types.GeneratedCodeInfo.Annotation
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: google._upb._message.Message
+  - inheritance:
+    - type: builtins.object
+    type: google.protobuf.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types.GeneratedCodeInfo
+  name: Annotation
+  source:
+    id: Annotation
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: API documentation for `pubsub_v1.types.GeneratedCodeInfo.Annotation` class.
+  syntax: {}
+  type: class
+  uid: google.cloud.pubsub_v1.types.GeneratedCodeInfo.Annotation
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.GeneratedCodeInfo.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.GeneratedCodeInfo.yml
new file mode 100644
index 000000000000..69e38f7d9f80
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.GeneratedCodeInfo.yml
@@ -0,0 +1,36 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- children:
+  - google.cloud.pubsub_v1.types.GeneratedCodeInfo.Annotation
+  class: google.cloud.pubsub_v1.types.GeneratedCodeInfo
+  fullName: google.cloud.pubsub_v1.types.GeneratedCodeInfo
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: google._upb._message.Message
+  - inheritance:
+    - type: builtins.object
+    type: google.protobuf.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: GeneratedCodeInfo
+  source:
+    id: GeneratedCodeInfo
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: API documentation for `pubsub_v1.types.GeneratedCodeInfo` class.
+  syntax: {}
+  type: class
+  uid: google.cloud.pubsub_v1.types.GeneratedCodeInfo
+references:
+- fullName: google.cloud.pubsub_v1.types.GeneratedCodeInfo.Annotation
+  isExternal: false
+  name: Annotation
+  parent: google.cloud.pubsub_v1.types.GeneratedCodeInfo
+  uid: google.cloud.pubsub_v1.types.GeneratedCodeInfo.Annotation
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.GetIamPolicyRequest.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.GetIamPolicyRequest.yml
new file mode 100644
index 000000000000..e8f3c9218f88
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.GetIamPolicyRequest.yml
@@ -0,0 +1,30 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- children: []
+  class: google.cloud.pubsub_v1.types.GetIamPolicyRequest
+  fullName: google.cloud.pubsub_v1.types.GetIamPolicyRequest
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: google._upb._message.Message
+  - inheritance:
+    - type: builtins.object
+    type: google.protobuf.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: GetIamPolicyRequest
+  source:
+    id: GetIamPolicyRequest
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: API documentation for `pubsub_v1.types.GetIamPolicyRequest` class.
+  syntax: {}
+  type: class
+  uid: google.cloud.pubsub_v1.types.GetIamPolicyRequest
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.GetSnapshotRequest.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.GetSnapshotRequest.yml
new file mode 100644
index 000000000000..aceb22506963
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.GetSnapshotRequest.yml
@@ -0,0 +1,35 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes:
+  - description: "Required. The name of the snapshot to get. Format is\n   projects/{project}/snapshots/{snap}."
+    id: snapshot
+    var_type: str
+  children: []
+  class: google.cloud.pubsub_v1.types.GetSnapshotRequest
+  fullName: google.cloud.pubsub_v1.types.GetSnapshotRequest
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: proto.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: GetSnapshotRequest
+  source:
+    id: GetSnapshotRequest
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Request for the GetSnapshot method.
+
+    '
+  syntax:
+    content: GetSnapshotRequest(mapping=None, *, ignore_unknown_fields=False, **kwargs)
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.types.GetSnapshotRequest
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.GetSubscriptionRequest.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.GetSubscriptionRequest.yml
new file mode 100644
index 000000000000..2d509374737d
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.GetSubscriptionRequest.yml
@@ -0,0 +1,36 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes:
+  - description: "Required. The name of the subscription to get. Format is\n   projects/{project}/subscriptions/{sub}."
+    id: subscription
+    var_type: str
+  children: []
+  class: google.cloud.pubsub_v1.types.GetSubscriptionRequest
+  fullName: google.cloud.pubsub_v1.types.GetSubscriptionRequest
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: proto.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: GetSubscriptionRequest
+  source:
+    id: GetSubscriptionRequest
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Request for the GetSubscription method.
+
+    '
+  syntax:
+    content: GetSubscriptionRequest(mapping=None, *, ignore_unknown_fields=False,
+      **kwargs)
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.types.GetSubscriptionRequest
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.GetTopicRequest.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.GetTopicRequest.yml
new file mode 100644
index 000000000000..4d6611c91bbb
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.GetTopicRequest.yml
@@ -0,0 +1,35 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes:
+  - description: "Required. The name of the topic to get. Format is\n   projects/{project}/topics/{topic}."
+    id: topic
+    var_type: str
+  children: []
+  class: google.cloud.pubsub_v1.types.GetTopicRequest
+  fullName: google.cloud.pubsub_v1.types.GetTopicRequest
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: proto.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: GetTopicRequest
+  source:
+    id: GetTopicRequest
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Request for the GetTopic method.
+
+    '
+  syntax:
+    content: GetTopicRequest(mapping=None, *, ignore_unknown_fields=False, **kwargs)
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.types.GetTopicRequest
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Http.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Http.yml
new file mode 100644
index 000000000000..b519974a34db
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Http.yml
@@ -0,0 +1,30 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- children: []
+  class: google.cloud.pubsub_v1.types.Http
+  fullName: google.cloud.pubsub_v1.types.Http
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: google._upb._message.Message
+  - inheritance:
+    - type: builtins.object
+    type: google.protobuf.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: Http
+  source:
+    id: Http
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: API documentation for `pubsub_v1.types.Http` class.
+  syntax: {}
+  type: class
+  uid: google.cloud.pubsub_v1.types.Http
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.HttpRule.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.HttpRule.yml
new file mode 100644
index 000000000000..77d5468be3f1
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.HttpRule.yml
@@ -0,0 +1,30 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- children: []
+  class: google.cloud.pubsub_v1.types.HttpRule
+  fullName: google.cloud.pubsub_v1.types.HttpRule
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: google._upb._message.Message
+  - inheritance:
+    - type: builtins.object
+    type: google.protobuf.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: HttpRule
+  source:
+    id: HttpRule
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: API documentation for `pubsub_v1.types.HttpRule` class.
+  syntax: {}
+  type: class
+  uid: google.cloud.pubsub_v1.types.HttpRule
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.LimitExceededBehavior.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.LimitExceededBehavior.yml
new file mode 100644
index 000000000000..9d4abfea0ded
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.LimitExceededBehavior.yml
@@ -0,0 +1,36 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes: []
+  children: []
+  class: google.cloud.pubsub_v1.types.LimitExceededBehavior
+  fullName: google.cloud.pubsub_v1.types.LimitExceededBehavior
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: builtins.str
+  - inheritance:
+    - type: builtins.object
+    type: enum.Enum
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: LimitExceededBehavior
+  source:
+    id: LimitExceededBehavior
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/types.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/types.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 87
+  summary: 'The possible actions when exceeding the publish flow control limits.
+
+
+    '
+  syntax:
+    content: LimitExceededBehavior(value)
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.types.LimitExceededBehavior
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ListSnapshotsRequest.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ListSnapshotsRequest.yml
new file mode 100644
index 000000000000..139d88104eb7
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ListSnapshotsRequest.yml
@@ -0,0 +1,44 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes:
+  - description: "Required. The name of the project in which to list\n   snapshots.\
+      \ Format is projects/{project-id}."
+    id: project
+    var_type: str
+  - description: Maximum number of snapshots to return.
+    id: page_size
+    var_type: int
+  - description: "The value returned by the last ListSnapshotsResponse;\n\
+      \   indicates that this is a continuation of a prior\n   ListSnapshots\
+      \ call, and that the system should return\n   the next page of data."
+    id: page_token
+    var_type: str
+  children: []
+  class: google.cloud.pubsub_v1.types.ListSnapshotsRequest
+  fullName: google.cloud.pubsub_v1.types.ListSnapshotsRequest
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: proto.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: ListSnapshotsRequest
+  source:
+    id: ListSnapshotsRequest
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Request for the `ListSnapshots` method.
+
+    '
+  syntax:
+    content: ListSnapshotsRequest(mapping=None, *, ignore_unknown_fields=False, **kwargs)
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.types.ListSnapshotsRequest
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ListSnapshotsResponse.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ListSnapshotsResponse.yml
new file mode 100644
index 000000000000..18ee38025f2b
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ListSnapshotsResponse.yml
@@ -0,0 +1,39 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes:
+  - description: The resulting snapshots.
+    id: snapshots
+    var_type: Sequence[google.pubsub_v1.types.Snapshot]
+  - description: "If not empty, indicates that there may be more snapshot that\n \
+      \  match the request; this value should be passed in a new\n   ListSnapshotsRequest."
+    id: next_page_token
+    var_type: str
+  children: []
+  class: google.cloud.pubsub_v1.types.ListSnapshotsResponse
+  fullName: google.cloud.pubsub_v1.types.ListSnapshotsResponse
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: proto.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: ListSnapshotsResponse
+  source:
+    id: ListSnapshotsResponse
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Response for the `ListSnapshots` method.
+
+    '
+  syntax:
+    content: ListSnapshotsResponse(mapping=None, *, ignore_unknown_fields=False, **kwargs)
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.types.ListSnapshotsResponse
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ListSubscriptionsRequest.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ListSubscriptionsRequest.yml
new file mode 100644
index 000000000000..e6047eddf534
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ListSubscriptionsRequest.yml
@@ -0,0 +1,45 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes:
+  - description: "Required. The name of the project in which to list\n   subscriptions.\
+      \ Format is projects/{project-id}."
+    id: project
+    var_type: str
+  - description: Maximum number of subscriptions to return.
+    id: page_size
+    var_type: int
+  - description: "The value returned by the last\n   ListSubscriptionsResponse;\
+      \ indicates that this is a\n   continuation of a prior ListSubscriptions\
+      \ call, and that\n   the system should return the next page of data."
+    id: page_token
+    var_type: str
+  children: []
+  class: google.cloud.pubsub_v1.types.ListSubscriptionsRequest
+  fullName: google.cloud.pubsub_v1.types.ListSubscriptionsRequest
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: proto.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: ListSubscriptionsRequest
+  source:
+    id: ListSubscriptionsRequest
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Request for the `ListSubscriptions` method.
+
+    '
+  syntax:
+    content: ListSubscriptionsRequest(mapping=None, *, ignore_unknown_fields=False,
+      **kwargs)
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.types.ListSubscriptionsRequest
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ListSubscriptionsResponse.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ListSubscriptionsResponse.yml
new file mode 100644
index 000000000000..838dd4e1799a
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ListSubscriptionsResponse.yml
@@ -0,0 +1,41 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes:
+  - description: The subscriptions that match the request.
+    id: subscriptions
+    var_type: Sequence[google.pubsub_v1.types.Subscription]
+  - description: "If not empty, indicates that there may be more subscriptions\n \
+      \  that match the request; this value should be passed in a new\n   ListSubscriptionsRequest\
+      \ to get more subscriptions."
+    id: next_page_token
+    var_type: str
+  children: []
+  class: google.cloud.pubsub_v1.types.ListSubscriptionsResponse
+  fullName: google.cloud.pubsub_v1.types.ListSubscriptionsResponse
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: proto.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: ListSubscriptionsResponse
+  source:
+    id: ListSubscriptionsResponse
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Response for the `ListSubscriptions` method.
+
+    '
+  syntax:
+    content: ListSubscriptionsResponse(mapping=None, *, ignore_unknown_fields=False,
+      **kwargs)
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.types.ListSubscriptionsResponse
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ListTopicSnapshotsRequest.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ListTopicSnapshotsRequest.yml
new file mode 100644
index 000000000000..b1840c3003bc
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ListTopicSnapshotsRequest.yml
@@ -0,0 +1,45 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes:
+  - description: "Required. The name of the topic that snapshots are attached\n  \
+      \ to. Format is projects/{project}/topics/{topic}."
+    id: topic
+    var_type: str
+  - description: Maximum number of snapshot names to return.
+    id: page_size
+    var_type: int
+  - description: "The value returned by the last\n   ListTopicSnapshotsResponse;\
+      \ indicates that this is a\n   continuation of a prior ListTopicSnapshots\
+      \ call, and\n   that the system should return the next page of data."
+    id: page_token
+    var_type: str
+  children: []
+  class: google.cloud.pubsub_v1.types.ListTopicSnapshotsRequest
+  fullName: google.cloud.pubsub_v1.types.ListTopicSnapshotsRequest
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: proto.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: ListTopicSnapshotsRequest
+  source:
+    id: ListTopicSnapshotsRequest
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Request for the `ListTopicSnapshots` method.
+
+    '
+  syntax:
+    content: ListTopicSnapshotsRequest(mapping=None, *, ignore_unknown_fields=False,
+      **kwargs)
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.types.ListTopicSnapshotsRequest
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ListTopicSnapshotsResponse.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ListTopicSnapshotsResponse.yml
new file mode 100644
index 000000000000..294a3d40d6b5
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ListTopicSnapshotsResponse.yml
@@ -0,0 +1,41 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes:
+  - description: "The names of the snapshots that match the\n   request."
+    id: snapshots
+    var_type: Sequence[str]
+  - description: "If not empty, indicates that there may be more snapshots\n   that\
+      \ match the request; this value should be passed in a new\n   ListTopicSnapshotsRequest\
+      \ to get more snapshots."
+    id: next_page_token
+    var_type: str
+  children: []
+  class: google.cloud.pubsub_v1.types.ListTopicSnapshotsResponse
+  fullName: google.cloud.pubsub_v1.types.ListTopicSnapshotsResponse
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: proto.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: ListTopicSnapshotsResponse
+  source:
+    id: ListTopicSnapshotsResponse
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Response for the `ListTopicSnapshots` method.
+
+    '
+  syntax:
+    content: ListTopicSnapshotsResponse(mapping=None, *, ignore_unknown_fields=False,
+      **kwargs)
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.types.ListTopicSnapshotsResponse
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ListTopicSubscriptionsRequest.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ListTopicSubscriptionsRequest.yml
new file mode 100644
index 000000000000..a5dbb8b424f9
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ListTopicSubscriptionsRequest.yml
@@ -0,0 +1,45 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes:
+  - description: "Required. The name of the topic that subscriptions are\n   attached\
+      \ to. Format is\n   projects/{project}/topics/{topic}."
+    id: topic
+    var_type: str
+  - description: "Maximum number of subscription names to\n   return."
+    id: page_size
+    var_type: int
+  - description: "The value returned by the last\n   ListTopicSubscriptionsResponse;\
+      \ indicates that this is a\n   continuation of a prior ListTopicSubscriptions\
+      \ call, and\n   that the system should return the next page of data."
+    id: page_token
+    var_type: str
+  children: []
+  class: google.cloud.pubsub_v1.types.ListTopicSubscriptionsRequest
+  fullName: google.cloud.pubsub_v1.types.ListTopicSubscriptionsRequest
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: proto.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: ListTopicSubscriptionsRequest
+  source:
+    id: ListTopicSubscriptionsRequest
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Request for the `ListTopicSubscriptions` method.
+
+    '
+  syntax:
+    content: "ListTopicSubscriptionsRequest(\n    mapping=None, *, ignore_unknown_fields=False,\
+      \ **kwargs\n)"
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.types.ListTopicSubscriptionsRequest
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ListTopicSubscriptionsResponse.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ListTopicSubscriptionsResponse.yml
new file mode 100644
index 000000000000..70590db9f2eb
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ListTopicSubscriptionsResponse.yml
@@ -0,0 +1,42 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes:
+  - description: "The names of subscriptions attached to the\n   topic specified in\
+      \ the request."
+    id: subscriptions
+    var_type: Sequence[str]
+  - description: "If not empty, indicates that there may be more subscriptions\n \
+      \  that match the request; this value should be passed in a new\n   ListTopicSubscriptionsRequest\
+      \ to get more subscriptions."
+    id: next_page_token
+    var_type: str
+  children: []
+  class: google.cloud.pubsub_v1.types.ListTopicSubscriptionsResponse
+  fullName: google.cloud.pubsub_v1.types.ListTopicSubscriptionsResponse
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: proto.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: ListTopicSubscriptionsResponse
+  source:
+    id: ListTopicSubscriptionsResponse
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Response for the `ListTopicSubscriptions` method.
+
+    '
+  syntax:
+    content: "ListTopicSubscriptionsResponse(\n    mapping=None, *, ignore_unknown_fields=False,\
+      \ **kwargs\n)"
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.types.ListTopicSubscriptionsResponse
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ListTopicsRequest.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ListTopicsRequest.yml
new file mode 100644
index 000000000000..af11d43d18f0
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ListTopicsRequest.yml
@@ -0,0 +1,44 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes:
+  - description: "Required. The name of the project in which to list topics.\n   Format\
+      \ is projects/{project-id}."
+    id: project
+    var_type: str
+  - description: Maximum number of topics to return.
+    id: page_size
+    var_type: int
+  - description: "The value returned by the last ListTopicsResponse;\n\
+      \   indicates that this is a continuation of a prior\n   ListTopics\
+      \ call, and that the system should return the\n   next page of data."
+    id: page_token
+    var_type: str
+  children: []
+  class: google.cloud.pubsub_v1.types.ListTopicsRequest
+  fullName: google.cloud.pubsub_v1.types.ListTopicsRequest
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: proto.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: ListTopicsRequest
+  source:
+    id: ListTopicsRequest
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Request for the `ListTopics` method.
+
+    '
+  syntax:
+    content: ListTopicsRequest(mapping=None, *, ignore_unknown_fields=False, **kwargs)
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.types.ListTopicsRequest
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ListTopicsResponse.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ListTopicsResponse.yml
new file mode 100644
index 000000000000..497db07dda38
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ListTopicsResponse.yml
@@ -0,0 +1,39 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes:
+  - description: The resulting topics.
+    id: topics
+    var_type: Sequence[google.pubsub_v1.types.Topic]
+  - description: "If not empty, indicates that there may be more topics that\n   match\
+      \ the request; this value should be passed in a new\n   ListTopicsRequest."
+    id: next_page_token
+    var_type: str
+  children: []
+  class: google.cloud.pubsub_v1.types.ListTopicsResponse
+  fullName: google.cloud.pubsub_v1.types.ListTopicsResponse
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: proto.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: ListTopicsResponse
+  source:
+    id: ListTopicsResponse
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Response for the `ListTopics` method.
+
+    '
+  syntax:
+    content: ListTopicsResponse(mapping=None, *, ignore_unknown_fields=False, **kwargs)
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.types.ListTopicsResponse
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.MessageOptions.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.MessageOptions.yml
new file mode 100644
index 000000000000..64b4477da50d
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.MessageOptions.yml
@@ -0,0 +1,30 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- children: []
+  class: google.cloud.pubsub_v1.types.MessageOptions
+  fullName: google.cloud.pubsub_v1.types.MessageOptions
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: google._upb._message.Message
+  - inheritance:
+    - type: builtins.object
+    type: google.protobuf.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: MessageOptions
+  source:
+    id: MessageOptions
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: API documentation for `pubsub_v1.types.MessageOptions` class.
+  syntax: {}
+  type: class
+  uid: google.cloud.pubsub_v1.types.MessageOptions
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.MessageStoragePolicy.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.MessageStoragePolicy.yml
new file mode 100644
index 000000000000..7ba147455b28
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.MessageStoragePolicy.yml
@@ -0,0 +1,41 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes:
+  - description: "A list of IDs of GCP regions where messages\n   that are published\
+      \ to the topic may be persisted\n   in storage. Messages published by publishers\n\
+      \   running in non-allowed GCP regions (or running\n   outside of GCP altogether)\
+      \ will be routed for\n   storage in one of the allowed regions. An empty\n \
+      \  list means that no regions are allowed, and is\n   not a valid configuration."
+    id: allowed_persistence_regions
+    var_type: Sequence[str]
+  children: []
+  class: google.cloud.pubsub_v1.types.MessageStoragePolicy
+  fullName: google.cloud.pubsub_v1.types.MessageStoragePolicy
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: proto.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: MessageStoragePolicy
+  source:
+    id: MessageStoragePolicy
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'A policy constraining the storage of messages published to
+
+    the topic.
+
+    '
+  syntax:
+    content: MessageStoragePolicy(mapping=None, *, ignore_unknown_fields=False, **kwargs)
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.types.MessageStoragePolicy
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.MethodDescriptorProto.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.MethodDescriptorProto.yml
new file mode 100644
index 000000000000..c52288da4348
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.MethodDescriptorProto.yml
@@ -0,0 +1,30 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- children: []
+  class: google.cloud.pubsub_v1.types.MethodDescriptorProto
+  fullName: google.cloud.pubsub_v1.types.MethodDescriptorProto
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: google._upb._message.Message
+  - inheritance:
+    - type: builtins.object
+    type: google.protobuf.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: MethodDescriptorProto
+  source:
+    id: MethodDescriptorProto
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: API documentation for `pubsub_v1.types.MethodDescriptorProto` class.
+  syntax: {}
+  type: class
+  uid: google.cloud.pubsub_v1.types.MethodDescriptorProto
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.MethodOptions.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.MethodOptions.yml
new file mode 100644
index 000000000000..91f1440d48fb
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.MethodOptions.yml
@@ -0,0 +1,30 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- children: []
+  class: google.cloud.pubsub_v1.types.MethodOptions
+  fullName: google.cloud.pubsub_v1.types.MethodOptions
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: google._upb._message.Message
+  - inheritance:
+    - type: builtins.object
+    type: google.protobuf.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: MethodOptions
+  source:
+    id: MethodOptions
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: API documentation for `pubsub_v1.types.MethodOptions` class.
+  syntax: {}
+  type: class
+  uid: google.cloud.pubsub_v1.types.MethodOptions
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ModifyAckDeadlineRequest.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ModifyAckDeadlineRequest.yml
new file mode 100644
index 000000000000..35f91548d391
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ModifyAckDeadlineRequest.yml
@@ -0,0 +1,49 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes:
+  - description: "Required. The name of the subscription. Format is\n   projects/{project}/subscriptions/{sub}."
+    id: subscription
+    var_type: str
+  - description: Required. List of acknowledgment IDs.
+    id: ack_ids
+    var_type: Sequence[str]
+  - description: "Required. The new ack deadline with respect to the time this\n \
+      \  request was sent to the Pub/Sub system. For example, if the\n   value is\
+      \ 10, the new ack deadline will expire 10 seconds\n   after the ModifyAckDeadline\
+      \ call was made. Specifying\n   zero might immediately make the message available\
+      \ for\n   delivery to another subscriber client. This typically\n   results\
+      \ in an increase in the rate of message redeliveries\n   (that is, duplicates).\
+      \ The minimum deadline you can specify\n   is 0 seconds. The maximum deadline\
+      \ you can specify is 600\n   seconds (10 minutes)."
+    id: ack_deadline_seconds
+    var_type: int
+  children: []
+  class: google.cloud.pubsub_v1.types.ModifyAckDeadlineRequest
+  fullName: google.cloud.pubsub_v1.types.ModifyAckDeadlineRequest
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: proto.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: ModifyAckDeadlineRequest
+  source:
+    id: ModifyAckDeadlineRequest
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Request for the ModifyAckDeadline method.
+
+    '
+  syntax:
+    content: ModifyAckDeadlineRequest(mapping=None, *, ignore_unknown_fields=False,
+      **kwargs)
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.types.ModifyAckDeadlineRequest
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ModifyPushConfigRequest.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ModifyPushConfigRequest.yml
new file mode 100644
index 000000000000..ad0c0b2a5abe
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ModifyPushConfigRequest.yml
@@ -0,0 +1,43 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes:
+  - description: "Required. The name of the subscription. Format is\n   projects/{project}/subscriptions/{sub}."
+    id: subscription
+    var_type: str
+  - description: "Required. The push configuration for future deliveries.\n   \n \
+      \  An empty pushConfig indicates that the Pub/Sub system\n   should\
+      \ stop pushing messages from the given subscription and\n   allow messages to\
+      \ be pulled and acknowledged - effectively\n   pausing the subscription if Pull\
+      \ or StreamingPull is\n   not called."
+    id: push_config
+    var_type: google.pubsub_v1.types.PushConfig
+  children: []
+  class: google.cloud.pubsub_v1.types.ModifyPushConfigRequest
+  fullName: google.cloud.pubsub_v1.types.ModifyPushConfigRequest
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: proto.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: ModifyPushConfigRequest
+  source:
+    id: ModifyPushConfigRequest
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Request for the ModifyPushConfig method.
+
+    '
+  syntax:
+    content: ModifyPushConfigRequest(mapping=None, *, ignore_unknown_fields=False,
+      **kwargs)
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.types.ModifyPushConfigRequest
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.OneofDescriptorProto.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.OneofDescriptorProto.yml
new file mode 100644
index 000000000000..292b997aff69
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.OneofDescriptorProto.yml
@@ -0,0 +1,30 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- children: []
+  class: google.cloud.pubsub_v1.types.OneofDescriptorProto
+  fullName: google.cloud.pubsub_v1.types.OneofDescriptorProto
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: google._upb._message.Message
+  - inheritance:
+    - type: builtins.object
+    type: google.protobuf.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: OneofDescriptorProto
+  source:
+    id: OneofDescriptorProto
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: API documentation for `pubsub_v1.types.OneofDescriptorProto` class.
+  syntax: {}
+  type: class
+  uid: google.cloud.pubsub_v1.types.OneofDescriptorProto
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.OneofOptions.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.OneofOptions.yml
new file mode 100644
index 000000000000..735e17df4239
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.OneofOptions.yml
@@ -0,0 +1,30 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- children: []
+  class: google.cloud.pubsub_v1.types.OneofOptions
+  fullName: google.cloud.pubsub_v1.types.OneofOptions
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: google._upb._message.Message
+  - inheritance:
+    - type: builtins.object
+    type: google.protobuf.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: OneofOptions
+  source:
+    id: OneofOptions
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: API documentation for `pubsub_v1.types.OneofOptions` class.
+  syntax: {}
+  type: class
+  uid: google.cloud.pubsub_v1.types.OneofOptions
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Policy.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Policy.yml
new file mode 100644
index 000000000000..1748f7c88e1a
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Policy.yml
@@ -0,0 +1,30 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- children: []
+  class: google.cloud.pubsub_v1.types.Policy
+  fullName: google.cloud.pubsub_v1.types.Policy
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: google._upb._message.Message
+  - inheritance:
+    - type: builtins.object
+    type: google.protobuf.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: Policy
+  source:
+    id: Policy
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: API documentation for `pubsub_v1.types.Policy` class.
+  syntax: {}
+  type: class
+  uid: google.cloud.pubsub_v1.types.Policy
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PolicyDelta.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PolicyDelta.yml
new file mode 100644
index 000000000000..69b984aa7cd6
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PolicyDelta.yml
@@ -0,0 +1,30 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- children: []
+  class: google.cloud.pubsub_v1.types.PolicyDelta
+  fullName: google.cloud.pubsub_v1.types.PolicyDelta
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: google._upb._message.Message
+  - inheritance:
+    - type: builtins.object
+    type: google.protobuf.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: PolicyDelta
+  source:
+    id: PolicyDelta
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: API documentation for `pubsub_v1.types.PolicyDelta` class.
+  syntax: {}
+  type: class
+  uid: google.cloud.pubsub_v1.types.PolicyDelta
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PublishFlowControl.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PublishFlowControl.yml
new file mode 100644
index 000000000000..882542fa95a2
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PublishFlowControl.yml
@@ -0,0 +1,155 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes: []
+  children:
+  - google.cloud.pubsub_v1.types.PublishFlowControl
+  - google.cloud.pubsub_v1.types.PublishFlowControl.byte_limit
+  - google.cloud.pubsub_v1.types.PublishFlowControl.limit_exceeded_behavior
+  - google.cloud.pubsub_v1.types.PublishFlowControl.message_limit
+  class: google.cloud.pubsub_v1.types.PublishFlowControl
+  fullName: google.cloud.pubsub_v1.types.PublishFlowControl
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: builtins.tuple
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: PublishFlowControl
+  source:
+    id: PublishFlowControl
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/types.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/types.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 95
+  summary: 'The client flow control settings for message publishing.
+
+
+    '
+  syntax:
+    content: "PublishFlowControl(\n    message_limit: int = 1000,\n    byte_limit:\
+      \ int = 10000000,\n    limit_exceeded_behavior: google.cloud.pubsub_v1.types.LimitExceededBehavior\
+      \ = LimitExceededBehavior.IGNORE,\n)"
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.types.PublishFlowControl
+- attributes: []
+  class: google.cloud.pubsub_v1.types.PublishFlowControl
+  fullName: google.cloud.pubsub_v1.types.PublishFlowControl
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: builtins.tuple
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: PublishFlowControl
+  source:
+    id: PublishFlowControl
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/types.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/types.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 95
+  summary: 'Create new instance of PublishFlowControl(message_limit, byte_limit, limit_exceeded_behavior)
+
+
+    '
+  syntax:
+    content: "PublishFlowControl(\n    message_limit: int = 1000,\n    byte_limit:\
+      \ int = 10000000,\n    limit_exceeded_behavior: google.cloud.pubsub_v1.types.LimitExceededBehavior\
+      \ = LimitExceededBehavior.IGNORE,\n)"
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.types.PublishFlowControl
+- attributes: []
+  class: google.cloud.pubsub_v1.types.PublishFlowControl
+  fullName: google.cloud.pubsub_v1.types.PublishFlowControl.byte_limit
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: byte_limit
+  source:
+    id: byte_limit
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'The maximum total size of messages awaiting to be published.
+
+
+    '
+  syntax: {}
+  type: attribute
+  uid: google.cloud.pubsub_v1.types.PublishFlowControl.byte_limit
+- attributes: []
+  class: google.cloud.pubsub_v1.types.PublishFlowControl
+  fullName: google.cloud.pubsub_v1.types.PublishFlowControl.limit_exceeded_behavior
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: limit_exceeded_behavior
+  source:
+    id: limit_exceeded_behavior
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'The action to take when publish flow control limits are exceeded.
+
+
+    '
+  syntax: {}
+  type: attribute
+  uid: google.cloud.pubsub_v1.types.PublishFlowControl.limit_exceeded_behavior
+- attributes: []
+  class: google.cloud.pubsub_v1.types.PublishFlowControl
+  fullName: google.cloud.pubsub_v1.types.PublishFlowControl.message_limit
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: message_limit
+  source:
+    id: message_limit
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'The maximum number of messages awaiting to be published.
+
+
+    '
+  syntax: {}
+  type: attribute
+  uid: google.cloud.pubsub_v1.types.PublishFlowControl.message_limit
+references:
+- fullName: google.cloud.pubsub_v1.types.PublishFlowControl
+  isExternal: false
+  name: PublishFlowControl
+  parent: google.cloud.pubsub_v1.types.PublishFlowControl
+  uid: google.cloud.pubsub_v1.types.PublishFlowControl
+- fullName: google.cloud.pubsub_v1.types.PublishFlowControl.byte_limit
+  isExternal: false
+  name: byte_limit
+  parent: google.cloud.pubsub_v1.types.PublishFlowControl
+  uid: google.cloud.pubsub_v1.types.PublishFlowControl.byte_limit
+- fullName: google.cloud.pubsub_v1.types.PublishFlowControl.limit_exceeded_behavior
+  isExternal: false
+  name: limit_exceeded_behavior
+  parent: google.cloud.pubsub_v1.types.PublishFlowControl
+  uid: google.cloud.pubsub_v1.types.PublishFlowControl.limit_exceeded_behavior
+- fullName: google.cloud.pubsub_v1.types.PublishFlowControl.message_limit
+  isExternal: false
+  name: message_limit
+  parent: google.cloud.pubsub_v1.types.PublishFlowControl
+  uid: google.cloud.pubsub_v1.types.PublishFlowControl.message_limit
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PublishRequest.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PublishRequest.yml
new file mode 100644
index 000000000000..b2af8cc3951b
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PublishRequest.yml
@@ -0,0 +1,39 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes:
+  - description: "Required. The messages in the request will be published on\n   this\
+      \ topic. Format is projects/{project}/topics/{topic}."
+    id: topic
+    var_type: str
+  - description: Required. The messages to publish.
+    id: messages
+    var_type: Sequence[google.pubsub_v1.types.PubsubMessage]
+  children: []
+  class: google.cloud.pubsub_v1.types.PublishRequest
+  fullName: google.cloud.pubsub_v1.types.PublishRequest
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: proto.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: PublishRequest
+  source:
+    id: PublishRequest
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Request for the Publish method.
+
+    '
+  syntax:
+    content: PublishRequest(mapping=None, *, ignore_unknown_fields=False, **kwargs)
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.types.PublishRequest
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PublishResponse.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PublishResponse.yml
new file mode 100644
index 000000000000..f7ef4ec7c687
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PublishResponse.yml
@@ -0,0 +1,37 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes:
+  - description: "The server-assigned ID of each published\n   message, in the same\
+      \ order as the messages in\n   the request. IDs are guaranteed to be unique\n\
+      \   within the topic."
+    id: message_ids
+    var_type: Sequence[str]
+  children: []
+  class: google.cloud.pubsub_v1.types.PublishResponse
+  fullName: google.cloud.pubsub_v1.types.PublishResponse
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: proto.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: PublishResponse
+  source:
+    id: PublishResponse
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Response for the `Publish` method.
+
+    '
+  syntax:
+    content: PublishResponse(mapping=None, *, ignore_unknown_fields=False, **kwargs)
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.types.PublishResponse
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PublisherOptions.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PublisherOptions.yml
new file mode 100644
index 000000000000..335e187bb9b0
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PublisherOptions.yml
@@ -0,0 +1,191 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes: []
+  children:
+  - google.cloud.pubsub_v1.types.PublisherOptions
+  - google.cloud.pubsub_v1.types.PublisherOptions.enable_message_ordering
+  - google.cloud.pubsub_v1.types.PublisherOptions.flow_control
+  - google.cloud.pubsub_v1.types.PublisherOptions.retry
+  - google.cloud.pubsub_v1.types.PublisherOptions.timeout
+  class: google.cloud.pubsub_v1.types.PublisherOptions
+  fullName: google.cloud.pubsub_v1.types.PublisherOptions
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: builtins.tuple
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: PublisherOptions
+  source:
+    id: PublisherOptions
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/types.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/types.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 112
+  summary: 'The options for the publisher client.
+
+
+    '
+  syntax:
+    content: 'PublisherOptions(enable_message_ordering: bool = False, flow_control:
+      google.cloud.pubsub_v1.types.PublishFlowControl = PublishFlowControl(message_limit=1000,
+      byte_limit=10000000, limit_exceeded_behavior=), retry: OptionalRetry = _MethodDefault._DEFAULT_VALUE, timeout:
+      OptionalTimeout = _MethodDefault._DEFAULT_VALUE)'
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.types.PublisherOptions
+- attributes: []
+  class: google.cloud.pubsub_v1.types.PublisherOptions
+  fullName: google.cloud.pubsub_v1.types.PublisherOptions
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: builtins.tuple
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: PublisherOptions
+  source:
+    id: PublisherOptions
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/types.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/types.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 112
+  summary: 'Create new instance of PublisherOptions(enable_message_ordering, flow_control,
+    retry, timeout)
+
+
+    '
+  syntax:
+    content: 'PublisherOptions(enable_message_ordering: bool = False, flow_control:
+      google.cloud.pubsub_v1.types.PublishFlowControl = PublishFlowControl(message_limit=1000,
+      byte_limit=10000000, limit_exceeded_behavior=), retry: OptionalRetry = _MethodDefault._DEFAULT_VALUE, timeout:
+      OptionalTimeout = _MethodDefault._DEFAULT_VALUE)'
+    parameters: []
+  type: method
+  uid: google.cloud.pubsub_v1.types.PublisherOptions
+- attributes: []
+  class: google.cloud.pubsub_v1.types.PublisherOptions
+  fullName: google.cloud.pubsub_v1.types.PublisherOptions.enable_message_ordering
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: enable_message_ordering
+  source:
+    id: enable_message_ordering
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Whether to order messages in a batch by a supplied ordering key.
+
+
+    '
+  syntax: {}
+  type: attribute
+  uid: google.cloud.pubsub_v1.types.PublisherOptions.enable_message_ordering
+- attributes: []
+  class: google.cloud.pubsub_v1.types.PublisherOptions
+  fullName: google.cloud.pubsub_v1.types.PublisherOptions.flow_control
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: flow_control
+  source:
+    id: flow_control
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Flow control settings for message publishing by the client. By default
+    the publisher client does not do any throttling.
+
+
+    '
+  syntax: {}
+  type: attribute
+  uid: google.cloud.pubsub_v1.types.PublisherOptions.flow_control
+- attributes: []
+  class: google.cloud.pubsub_v1.types.PublisherOptions
+  fullName: google.cloud.pubsub_v1.types.PublisherOptions.retry
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: retry
+  source:
+    id: retry
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Retry settings for message publishing by the client. This should be an
+    instance of `google.api_core.retry.Retry`.
+
+
+    '
+  syntax: {}
+  type: attribute
+  uid: google.cloud.pubsub_v1.types.PublisherOptions.retry
+- attributes: []
+  class: google.cloud.pubsub_v1.types.PublisherOptions
+  fullName: google.cloud.pubsub_v1.types.PublisherOptions.timeout
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: timeout
+  source:
+    id: timeout
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Timeout settings for message publishing by the client. It should be compatible
+    with `.pubsub_v1.types.TimeoutType`.
+
+
+    '
+  syntax: {}
+  type: attribute
+  uid: google.cloud.pubsub_v1.types.PublisherOptions.timeout
+references:
+- fullName: google.cloud.pubsub_v1.types.PublisherOptions
+  isExternal: false
+  name: PublisherOptions
+  parent: google.cloud.pubsub_v1.types.PublisherOptions
+  uid: google.cloud.pubsub_v1.types.PublisherOptions
+- fullName: google.cloud.pubsub_v1.types.PublisherOptions.enable_message_ordering
+  isExternal: false
+  name: enable_message_ordering
+  parent: google.cloud.pubsub_v1.types.PublisherOptions
+  uid: google.cloud.pubsub_v1.types.PublisherOptions.enable_message_ordering
+- fullName: google.cloud.pubsub_v1.types.PublisherOptions.flow_control
+  isExternal: false
+  name: flow_control
+  parent: google.cloud.pubsub_v1.types.PublisherOptions
+  uid: google.cloud.pubsub_v1.types.PublisherOptions.flow_control
+- fullName: google.cloud.pubsub_v1.types.PublisherOptions.retry
+  isExternal: false
+  name: retry
+  parent: google.cloud.pubsub_v1.types.PublisherOptions
+  uid: google.cloud.pubsub_v1.types.PublisherOptions.retry
+- fullName: google.cloud.pubsub_v1.types.PublisherOptions.timeout
+  isExternal: false
+  name: timeout
+  parent: google.cloud.pubsub_v1.types.PublisherOptions
+  uid: google.cloud.pubsub_v1.types.PublisherOptions.timeout
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PubsubMessage.AttributesEntry.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PubsubMessage.AttributesEntry.yml
new file mode 100644
index 000000000000..23cc5a29055a
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PubsubMessage.AttributesEntry.yml
@@ -0,0 +1,44 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes: []
+  children: []
+  class: google.cloud.pubsub_v1.types.PubsubMessage.AttributesEntry
+  fullName: google.cloud.pubsub_v1.types.PubsubMessage.AttributesEntry
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: proto.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types.PubsubMessage
+  name: AttributesEntry
+  source:
+    id: AttributesEntry
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'The abstract base class for a message.
+
+    '
+  syntax:
+    content: AttributesEntry(mapping=None, *, ignore_unknown_fields=False, **kwargs)
+    parameters:
+    - defaultValue: None
+      description: Keys and values corresponding to the fields of the message.
+      id: kwargs
+      var_type: dict
+    - description: A dictionary or message to be used to determine the values for
+        this message.
+      id: mapping
+      var_type: Union[dict, .Message]
+    - description: If True, do not raise errors for unknown fields. Only applied if
+        mapping is a mapping type or there are keyword parameters.
+      id: ignore_unknown_fields
+      var_type: Optional(bool)
+  type: class
+  uid: google.cloud.pubsub_v1.types.PubsubMessage.AttributesEntry
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PubsubMessage.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PubsubMessage.yml
new file mode 100644
index 000000000000..12da288d32f2
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PubsubMessage.yml
@@ -0,0 +1,84 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes:
+  - description: "The message data field. If this field is\n   empty, the message\
+      \ must contain at least one\n   attribute."
+    id: data
+    var_type: bytes
+  - description: "Attributes for this message. If this field is\n   empty, the message\
+      \ must contain non-empty data.\n   This can be used to filter messages on the\n\
+      \   subscription."
+    id: attributes
+    var_type: Mapping[str, str]
+  - description: "ID of this message, assigned by the server when the message\n  \
+      \ is published. Guaranteed to be unique within the topic. This\n   value may\
+      \ be read by a subscriber that receives a\n   PubsubMessage via\
+      \ a Pull call or a push delivery. It\n   must not be populated\
+      \ by the publisher in a Publish\n   call."
+    id: message_id
+    var_type: str
+  - description: "The time at which the message was published, populated by\n   the\
+      \ server when it receives the Publish call. It must\n   not be\
+      \ populated by the publisher in a Publish call."
+    id: publish_time
+    var_type: google.protobuf.timestamp_pb2.Timestamp
+  - description: "If non-empty, identifies related messages for which publish\n  \
+      \ order should be respected. If a Subscription has\n   enable_message_ordering\
+      \ set to true, messages\n   published with the same non-empty ordering_key\
+      \ value\n   will be delivered to subscribers in the order in which they\n  \
+      \ are received by the Pub/Sub system. All PubsubMessage\\ s\n \
+      \  published in a given PublishRequest must specify the\n   same\
+      \ ordering_key value."
+    id: ordering_key
+    var_type: str
+  children:
+  - google.cloud.pubsub_v1.types.PubsubMessage.AttributesEntry
+  class: google.cloud.pubsub_v1.types.PubsubMessage
+  fullName: google.cloud.pubsub_v1.types.PubsubMessage
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: proto.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: PubsubMessage
+  source:
+    id: PubsubMessage
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'A message that is published by publishers and consumed by
+
+    subscribers. The message must contain either a non-empty data field
+
+    or at least one attribute. Note that client libraries represent this
+
+    object differently depending on the language. See the corresponding
+
+    `client library
+
+    documentation `__
+
+    for more information. See [quotas and limits]
+
+    (https://cloud.google.com/pubsub/quotas) for more information about
+
+    message limits.
+
+    '
+  syntax:
+    content: PubsubMessage(mapping=None, *, ignore_unknown_fields=False, **kwargs)
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.types.PubsubMessage
+references:
+- fullName: google.cloud.pubsub_v1.types.PubsubMessage.AttributesEntry
+  isExternal: false
+  name: AttributesEntry
+  parent: google.cloud.pubsub_v1.types.PubsubMessage
+  uid: google.cloud.pubsub_v1.types.PubsubMessage.AttributesEntry
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PullRequest.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PullRequest.yml
new file mode 100644
index 000000000000..9fd5df3b0e8c
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PullRequest.yml
@@ -0,0 +1,50 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes:
+  - description: "Required. The subscription from which messages should be\n   pulled.\
+      \ Format is\n   projects/{project}/subscriptions/{sub}."
+    id: subscription
+    var_type: str
+  - description: "Optional. If this field set to true, the system will respond\n \
+      \  immediately even if it there are no messages available to\n   return in the\
+      \ Pull response. Otherwise, the system may\n   wait (for a bounded\
+      \ amount of time) until at least one\n   message is available, rather than returning\
+      \ no messages.\n   Warning: setting this field to true is discouraged\n\
+      \   because it adversely impacts the performance of Pull\n   operations.\
+      \ We recommend that users do not set this field."
+    id: return_immediately
+    var_type: bool
+  - description: "Required. The maximum number of messages to\n   return for this\
+      \ request. Must be a positive\n   integer. The Pub/Sub system may return fewer\n\
+      \   than the number specified."
+    id: max_messages
+    var_type: int
+  children: []
+  class: google.cloud.pubsub_v1.types.PullRequest
+  fullName: google.cloud.pubsub_v1.types.PullRequest
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: proto.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: PullRequest
+  source:
+    id: PullRequest
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Request for the `Pull` method.
+
+    '
+  syntax:
+    content: PullRequest(mapping=None, *, ignore_unknown_fields=False, **kwargs)
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.types.PullRequest
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PullResponse.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PullResponse.yml
new file mode 100644
index 000000000000..0bf7a1738a70
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PullResponse.yml
@@ -0,0 +1,38 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes:
+  - description: "Received Pub/Sub messages. The list will be empty if there\n   are\
+      \ no more messages available in the backlog. For JSON, the\n   response can\
+      \ be entirely empty. The Pub/Sub system may\n   return fewer than the maxMessages\
+      \ requested even if\n   there are more messages available in the backlog."
+    id: received_messages
+    var_type: Sequence[google.pubsub_v1.types.ReceivedMessage]
+  children: []
+  class: google.cloud.pubsub_v1.types.PullResponse
+  fullName: google.cloud.pubsub_v1.types.PullResponse
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: proto.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: PullResponse
+  source:
+    id: PullResponse
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Response for the `Pull` method.
+
+    '
+  syntax:
+    content: PullResponse(mapping=None, *, ignore_unknown_fields=False, **kwargs)
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.types.PullResponse
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PushConfig.AttributesEntry.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PushConfig.AttributesEntry.yml
new file mode 100644
index 000000000000..e3dd0d4357cd
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PushConfig.AttributesEntry.yml
@@ -0,0 +1,44 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes: []
+  children: []
+  class: google.cloud.pubsub_v1.types.PushConfig.AttributesEntry
+  fullName: google.cloud.pubsub_v1.types.PushConfig.AttributesEntry
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: proto.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types.PushConfig
+  name: AttributesEntry
+  source:
+    id: AttributesEntry
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'The abstract base class for a message.
+
+    '
+  syntax:
+    content: AttributesEntry(mapping=None, *, ignore_unknown_fields=False, **kwargs)
+    parameters:
+    - defaultValue: None
+      description: Keys and values corresponding to the fields of the message.
+      id: kwargs
+      var_type: dict
+    - description: A dictionary or message to be used to determine the values for
+        this message.
+      id: mapping
+      var_type: Union[dict, .Message]
+    - description: If True, do not raise errors for unknown fields. Only applied if
+        mapping is a mapping type or there are keyword parameters.
+      id: ignore_unknown_fields
+      var_type: Optional(bool)
+  type: class
+  uid: google.cloud.pubsub_v1.types.PushConfig.AttributesEntry
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PushConfig.OidcToken.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PushConfig.OidcToken.yml
new file mode 100644
index 000000000000..ecb5f3d08ff0
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PushConfig.OidcToken.yml
@@ -0,0 +1,48 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes:
+  - description: "`Service account\n   email `__\n\
+      \   to be used for generating the OIDC token. The caller (for\n   CreateSubscription,\
+      \ UpdateSubscription, and ModifyPushConfig\n   RPCs) must have the iam.serviceAccounts.actAs\
+      \ permission for\n   the service account."
+    id: service_account_email
+    var_type: str
+  - description: "Audience to be used when generating OIDC\n   token. The audience\
+      \ claim identifies the\n   recipients that the JWT is intended for. The\n  \
+      \ audience value is a single case-sensitive\n   string. Having multiple values\
+      \ (array) for the\n   audience field is not supported. More info about\n   the\
+      \ OIDC JWT token audience here:\n   https://tools.ietf.org/html/rfc7519#section-4.1.3\n\
+      \   Note: if not specified, the Push endpoint URL\n   will be used."
+    id: audience
+    var_type: str
+  children: []
+  class: google.cloud.pubsub_v1.types.PushConfig.OidcToken
+  fullName: google.cloud.pubsub_v1.types.PushConfig.OidcToken
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: proto.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types.PushConfig
+  name: OidcToken
+  source:
+    id: OidcToken
+    path: tests/testdata/gapic-combo/google/pubsub_v1/types/pubsub.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/types/pubsub.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 960
+  summary: 'Contains information needed for generating an `OpenID Connect
+
+    token `__.
+
+    '
+  syntax:
+    content: OidcToken(mapping=None, *, ignore_unknown_fields=False, **kwargs)
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.types.PushConfig.OidcToken
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PushConfig.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PushConfig.yml
new file mode 100644
index 000000000000..325ef5729e27
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.PushConfig.yml
@@ -0,0 +1,74 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes:
+  - description: "A URL locating the endpoint to which messages should be\n   pushed.\
+      \ For example, a Webhook endpoint might use\n   https://example.com/push."
+    id: push_endpoint
+    var_type: str
+  - description: "Endpoint configuration attributes that can be used to\n   control\
+      \ different aspects of the message delivery.\n   \n   The only currently supported\
+      \ attribute is\n   x-goog-version, which you can use to change\
+      \ the format\n   of the pushed message. This attribute indicates the version\n\
+      \   of the data expected by the endpoint. This controls the\n   shape of the\
+      \ pushed message (i.e., its fields and metadata).\n   \n   If not present during\
+      \ the CreateSubscription call, it\n   will default to the version\
+      \ of the Pub/Sub API used to make\n   such call. If not present in a ModifyPushConfig\
+      \ call,\n   its value will not be changed. GetSubscription calls\n\
+      \   will always return a valid version, even if the subscription\n   was created\
+      \ without this attribute.\n   \n   The only supported values for the x-goog-version\n\
+      \   attribute are:\n   \n   -  v1beta1: uses the push format defined\
+      \ in the v1beta1\n      Pub/Sub API.\n   -  v1 or v1beta2:\
+      \ uses the push format defined in\n      the v1 Pub/Sub API.\n   \n   For example:\n\
+      \   \n   .. raw:: html\n   \n       
attributes { \"x-goog-version\"\
+      : \"v1\" } 
" + id: attributes + var_type: Mapping[str, str] + - description: "If specified, Pub/Sub will generate and attach an OIDC JWT\n token\ + \ as an Authorization header in the HTTP request for\n every\ + \ pushed message.\n \n This field is a member of oneof_ authentication_method." + id: oidc_token + var_type: google.pubsub_v1.types.PushConfig.OidcToken + children: + - google.cloud.pubsub_v1.types.PushConfig.AttributesEntry + - google.cloud.pubsub_v1.types.PushConfig.OidcToken + class: google.cloud.pubsub_v1.types.PushConfig + fullName: google.cloud.pubsub_v1.types.PushConfig + inheritance: + - inheritance: + - type: builtins.object + type: proto.message.Message + langs: + - python + module: google.cloud.pubsub_v1.types + name: PushConfig + source: + id: PushConfig + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Configuration for a push delivery endpoint. + + + .. _oneof: https://proto-plus-python.readthedocs.io/en/stable/fields.html#oneofs-mutually-exclusive-fields + + ' + syntax: + content: PushConfig(mapping=None, *, ignore_unknown_fields=False, **kwargs) + parameters: [] + type: class + uid: google.cloud.pubsub_v1.types.PushConfig +references: +- fullName: google.cloud.pubsub_v1.types.PushConfig.AttributesEntry + isExternal: false + name: AttributesEntry + parent: google.cloud.pubsub_v1.types.PushConfig + uid: google.cloud.pubsub_v1.types.PushConfig.AttributesEntry +- fullName: google.cloud.pubsub_v1.types.PushConfig.OidcToken + isExternal: false + name: OidcToken + parent: google.cloud.pubsub_v1.types.PushConfig + uid: google.cloud.pubsub_v1.types.PushConfig.OidcToken diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ReceivedMessage.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ReceivedMessage.yml new file mode 100644 index 000000000000..244881f16680 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ReceivedMessage.yml @@ -0,0 +1,51 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: + - description: "This ID can be used to acknowledge the\n received message." + id: ack_id + var_type: str + - description: The message. + id: message + var_type: google.pubsub_v1.types.PubsubMessage + - description: "The approximate number of times that Cloud Pub/Sub has\n attempted\ + \ to deliver the associated message to a subscriber.\n \n More precisely,\ + \ this is 1 + (number of NACKs) + (number of\n ack_deadline exceeds) for this\ + \ message.\n \n A NACK is any call to ModifyAckDeadline with a 0 deadline.\n\ + \ An ack_deadline exceeds event is whenever a message is not\n acknowledged\ + \ within ack_deadline. Note that ack_deadline is\n initially Subscription.ackDeadlineSeconds,\ + \ but may get\n extended automatically by the client library.\n \n Upon\ + \ the first delivery of a given message,\n delivery_attempt will\ + \ have a value of 1. The value is\n calculated at best effort and is approximate.\n\ + \ \n If a DeadLetterPolicy is not set on the subscription, this\n will\ + \ be 0." + id: delivery_attempt + var_type: int + children: [] + class: google.cloud.pubsub_v1.types.ReceivedMessage + fullName: google.cloud.pubsub_v1.types.ReceivedMessage + inheritance: + - inheritance: + - type: builtins.object + type: proto.message.Message + langs: + - python + module: google.cloud.pubsub_v1.types + name: ReceivedMessage + source: + id: ReceivedMessage + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'A message and its corresponding acknowledgment ID. + + ' + syntax: + content: ReceivedMessage(mapping=None, *, ignore_unknown_fields=False, **kwargs) + parameters: [] + type: class + uid: google.cloud.pubsub_v1.types.ReceivedMessage +references: [] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.RetryPolicy.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.RetryPolicy.yml new file mode 100644 index 000000000000..db97989e3b2c --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.RetryPolicy.yml @@ -0,0 +1,61 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: + - description: "The minimum delay between consecutive\n deliveries of a given\ + \ message. Value should be\n between 0 and 600 seconds. Defaults to 10\n \ + \ seconds." + id: minimum_backoff + var_type: google.protobuf.duration_pb2.Duration + - description: "The maximum delay between consecutive\n deliveries of a given\ + \ message. Value should be\n between 0 and 600 seconds. Defaults to 600\n\ + \ seconds." + id: maximum_backoff + var_type: google.protobuf.duration_pb2.Duration + children: [] + class: google.cloud.pubsub_v1.types.RetryPolicy + fullName: google.cloud.pubsub_v1.types.RetryPolicy + inheritance: + - inheritance: + - type: builtins.object + type: proto.message.Message + langs: + - python + module: google.cloud.pubsub_v1.types + name: RetryPolicy + source: + id: RetryPolicy + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'A policy that specifies how Cloud Pub/Sub retries message delivery. + + + Retry delay will be exponential based on provided minimum and + + maximum backoffs. https://en.wikipedia.org/wiki/Exponential_backoff. + + + RetryPolicy will be triggered on NACKs or acknowledgement deadline + + exceeded events for a given message. + + + Retry Policy is implemented on a best effort basis. At times, the + + delay between consecutive deliveries may not match the + + configuration. That is, delay can be more or less than configured + + backoff. + + ' + syntax: + content: RetryPolicy(mapping=None, *, ignore_unknown_fields=False, **kwargs) + parameters: [] + type: class + uid: google.cloud.pubsub_v1.types.RetryPolicy +references: [] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.SchemaSettings.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.SchemaSettings.yml new file mode 100644 index 000000000000..dc827bd50216 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.SchemaSettings.yml @@ -0,0 +1,41 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: + - description: "Required. The name of the schema that messages published\n should\ + \ be validated against. Format is\n projects/{project}/schemas/{schema}.\ + \ The value of this\n field will be _deleted-schema_ if the schema\ + \ has been\n deleted." + id: schema + var_type: str + - description: The encoding of messages validated against schema. + id: encoding + var_type: google.pubsub_v1.types.Encoding + children: [] + class: google.cloud.pubsub_v1.types.SchemaSettings + fullName: google.cloud.pubsub_v1.types.SchemaSettings + inheritance: + - inheritance: + - type: builtins.object + type: proto.message.Message + langs: + - python + module: google.cloud.pubsub_v1.types + name: SchemaSettings + source: + id: SchemaSettings + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Settings for validating messages published against a schema. + + ' + syntax: + content: SchemaSettings(mapping=None, *, ignore_unknown_fields=False, **kwargs) + parameters: [] + type: class + uid: google.cloud.pubsub_v1.types.SchemaSettings +references: [] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.SeekRequest.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.SeekRequest.yml new file mode 100644 index 000000000000..0f170078a781 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.SeekRequest.yml @@ -0,0 +1,65 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: + - description: Required. The subscription to affect. + id: subscription + var_type: str + - description: "The time to seek to. Messages retained in the subscription\n that\ + \ were published before this time are marked as\n acknowledged, and messages\ + \ retained in the subscription that\n were published after this time are marked\ + \ as unacknowledged.\n Note that this operation affects only those messages\n\ + \ retained in the subscription (configured by the combination\n of message_retention_duration\ + \ and\n retain_acked_messages). For example, if time\n\ + \ corresponds to a point before the message retention window\n (or to a\ + \ point before the system's notion of the\n subscription creation time), only\ + \ retained messages will be\n marked as unacknowledged, and already-expunged\ + \ messages will\n not be restored.\n \n This field is a member of oneof_\ + \ target." + id: time + var_type: google.protobuf.timestamp_pb2.Timestamp + - description: "The snapshot to seek to. The snapshot's topic must be the\n same\ + \ as that of the provided subscription. Format is\n projects/{project}/snapshots/{snap}.\n\ + \ \n This field is a member of oneof_ target." + id: snapshot + var_type: str + children: [] + class: google.cloud.pubsub_v1.types.SeekRequest + fullName: google.cloud.pubsub_v1.types.SeekRequest + inheritance: + - inheritance: + - type: builtins.object + type: proto.message.Message + langs: + - python + module: google.cloud.pubsub_v1.types + name: SeekRequest + source: + id: SeekRequest + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Request for the `Seek` method. + + + This message has `oneof`_ fields (mutually exclusive fields). + + For each oneof, at most one member field can be set at the same time. + + Setting any member of the oneof automatically clears all other + + members. + + + .. _oneof: https://proto-plus-python.readthedocs.io/en/stable/fields.html#oneofs-mutually-exclusive-fields + + ' + syntax: + content: SeekRequest(mapping=None, *, ignore_unknown_fields=False, **kwargs) + parameters: [] + type: class + uid: google.cloud.pubsub_v1.types.SeekRequest +references: [] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.SeekResponse.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.SeekResponse.yml new file mode 100644 index 000000000000..18a66576006e --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.SeekResponse.yml @@ -0,0 +1,33 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: [] + children: [] + class: google.cloud.pubsub_v1.types.SeekResponse + fullName: google.cloud.pubsub_v1.types.SeekResponse + inheritance: + - inheritance: + - type: builtins.object + type: proto.message.Message + langs: + - python + module: google.cloud.pubsub_v1.types + name: SeekResponse + source: + id: SeekResponse + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Response for the `Seek` method (this response is empty). + + + ' + syntax: + content: SeekResponse(mapping=None, *, ignore_unknown_fields=False, **kwargs) + parameters: [] + type: class + uid: google.cloud.pubsub_v1.types.SeekResponse +references: [] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ServiceDescriptorProto.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ServiceDescriptorProto.yml new file mode 100644 index 000000000000..76dcd33da38a --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ServiceDescriptorProto.yml @@ -0,0 +1,30 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- children: [] + class: google.cloud.pubsub_v1.types.ServiceDescriptorProto + fullName: google.cloud.pubsub_v1.types.ServiceDescriptorProto + inheritance: + - inheritance: + - type: builtins.object + type: google._upb._message.Message + - inheritance: + - type: builtins.object + type: google.protobuf.message.Message + langs: + - python + module: google.cloud.pubsub_v1.types + name: ServiceDescriptorProto + source: + id: ServiceDescriptorProto + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: API documentation for `pubsub_v1.types.ServiceDescriptorProto` class. + syntax: {} + type: class + uid: google.cloud.pubsub_v1.types.ServiceDescriptorProto +references: [] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ServiceOptions.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ServiceOptions.yml new file mode 100644 index 000000000000..169c84b18708 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.ServiceOptions.yml @@ -0,0 +1,30 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- children: [] + class: google.cloud.pubsub_v1.types.ServiceOptions + fullName: google.cloud.pubsub_v1.types.ServiceOptions + inheritance: + - inheritance: + - type: builtins.object + type: google._upb._message.Message + - inheritance: + - type: builtins.object + type: google.protobuf.message.Message + langs: + - python + module: google.cloud.pubsub_v1.types + name: ServiceOptions + source: + id: ServiceOptions + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: API documentation for `pubsub_v1.types.ServiceOptions` class. + syntax: {} + type: class + uid: google.cloud.pubsub_v1.types.ServiceOptions +references: [] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.SetIamPolicyRequest.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.SetIamPolicyRequest.yml new file mode 100644 index 000000000000..2368f5624c99 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.SetIamPolicyRequest.yml @@ -0,0 +1,30 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- children: [] + class: google.cloud.pubsub_v1.types.SetIamPolicyRequest + fullName: google.cloud.pubsub_v1.types.SetIamPolicyRequest + inheritance: + - inheritance: + - type: builtins.object + type: google._upb._message.Message + - inheritance: + - type: builtins.object + type: google.protobuf.message.Message + langs: + - python + module: google.cloud.pubsub_v1.types + name: SetIamPolicyRequest + source: + id: SetIamPolicyRequest + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: API documentation for `pubsub_v1.types.SetIamPolicyRequest` class. + syntax: {} + type: class + uid: google.cloud.pubsub_v1.types.SetIamPolicyRequest +references: [] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Snapshot.LabelsEntry.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Snapshot.LabelsEntry.yml new file mode 100644 index 000000000000..fb3e3cb4443f --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Snapshot.LabelsEntry.yml @@ -0,0 +1,44 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: [] + children: [] + class: google.cloud.pubsub_v1.types.Snapshot.LabelsEntry + fullName: google.cloud.pubsub_v1.types.Snapshot.LabelsEntry + inheritance: + - inheritance: + - type: builtins.object + type: proto.message.Message + langs: + - python + module: google.cloud.pubsub_v1.types.Snapshot + name: LabelsEntry + source: + id: LabelsEntry + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'The abstract base class for a message. + + ' + syntax: + content: LabelsEntry(mapping=None, *, ignore_unknown_fields=False, **kwargs) + parameters: + - defaultValue: None + description: Keys and values corresponding to the fields of the message. + id: kwargs + var_type: dict + - description: A dictionary or message to be used to determine the values for + this message. + id: mapping + var_type: Union[dict, .Message] + - description: If True, do not raise errors for unknown fields. Only applied if + mapping is a mapping type or there are keyword parameters. + id: ignore_unknown_fields + var_type: Optional(bool) + type: class + uid: google.cloud.pubsub_v1.types.Snapshot.LabelsEntry +references: [] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Snapshot.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Snapshot.yml new file mode 100644 index 000000000000..3899ca6c500e --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Snapshot.yml @@ -0,0 +1,68 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: + - description: The name of the snapshot. + id: name + var_type: str + - description: "The name of the topic from which this\n snapshot is retaining\ + \ messages." + id: topic + var_type: str + - description: "The snapshot is guaranteed to exist up until this time. A\n newly-created\ + \ snapshot expires no later than 7 days from the\n time of its creation. Its\ + \ exact lifetime is determined at\n creation by the existing backlog in the\ + \ source subscription.\n Specifically, the lifetime of the snapshot is\n \ + \ 7 days - (age of oldest unacked message in the subscription).\n\ + \ For example, consider a subscription whose oldest unacked\n message is\ + \ 3 days old. If a snapshot is created from this\n subscription, the snapshot\ + \ -- which will always capture this\n 3-day-old backlog as long as the snapshot\ + \ exists -- will\n expire in 4 days. The service will refuse to create a\n\ + \ snapshot that would expire in less than 1 hour after\n creation." + id: expire_time + var_type: google.protobuf.timestamp_pb2.Timestamp + - description: "See [Creating and managing labels]\n (https://cloud.google.com/pubsub/docs/labels)." + id: labels + var_type: Mapping[str, str] + children: + - google.cloud.pubsub_v1.types.Snapshot.LabelsEntry + class: google.cloud.pubsub_v1.types.Snapshot + fullName: google.cloud.pubsub_v1.types.Snapshot + inheritance: + - inheritance: + - type: builtins.object + type: proto.message.Message + langs: + - python + module: google.cloud.pubsub_v1.types + name: Snapshot + source: + id: Snapshot + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'A snapshot resource. Snapshots are used in + + `Seek `__ + + operations, which allow you to manage message acknowledgments in + + bulk. That is, you can set the acknowledgment state of messages in + + an existing subscription to the state captured by a snapshot. + + ' + syntax: + content: Snapshot(mapping=None, *, ignore_unknown_fields=False, **kwargs) + parameters: [] + type: class + uid: google.cloud.pubsub_v1.types.Snapshot +references: +- fullName: google.cloud.pubsub_v1.types.Snapshot.LabelsEntry + isExternal: false + name: LabelsEntry + parent: google.cloud.pubsub_v1.types.Snapshot + uid: google.cloud.pubsub_v1.types.Snapshot.LabelsEntry diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.SourceCodeInfo.Location.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.SourceCodeInfo.Location.yml new file mode 100644 index 000000000000..983a18722314 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.SourceCodeInfo.Location.yml @@ -0,0 +1,30 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- children: [] + class: google.cloud.pubsub_v1.types.SourceCodeInfo.Location + fullName: google.cloud.pubsub_v1.types.SourceCodeInfo.Location + inheritance: + - inheritance: + - type: builtins.object + type: google._upb._message.Message + - inheritance: + - type: builtins.object + type: google.protobuf.message.Message + langs: + - python + module: google.cloud.pubsub_v1.types.SourceCodeInfo + name: Location + source: + id: Location + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: API documentation for `pubsub_v1.types.SourceCodeInfo.Location` class. + syntax: {} + type: class + uid: google.cloud.pubsub_v1.types.SourceCodeInfo.Location +references: [] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.SourceCodeInfo.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.SourceCodeInfo.yml new file mode 100644 index 000000000000..557d71354bf5 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.SourceCodeInfo.yml @@ -0,0 +1,36 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- children: + - google.cloud.pubsub_v1.types.SourceCodeInfo.Location + class: google.cloud.pubsub_v1.types.SourceCodeInfo + fullName: google.cloud.pubsub_v1.types.SourceCodeInfo + inheritance: + - inheritance: + - type: builtins.object + type: google._upb._message.Message + - inheritance: + - type: builtins.object + type: google.protobuf.message.Message + langs: + - python + module: google.cloud.pubsub_v1.types + name: SourceCodeInfo + source: + id: SourceCodeInfo + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: API documentation for `pubsub_v1.types.SourceCodeInfo` class. + syntax: {} + type: class + uid: google.cloud.pubsub_v1.types.SourceCodeInfo +references: +- fullName: google.cloud.pubsub_v1.types.SourceCodeInfo.Location + isExternal: false + name: Location + parent: google.cloud.pubsub_v1.types.SourceCodeInfo + uid: google.cloud.pubsub_v1.types.SourceCodeInfo.Location diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.StreamingPullRequest.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.StreamingPullRequest.yml new file mode 100644 index 000000000000..e6a84ff200aa --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.StreamingPullRequest.yml @@ -0,0 +1,107 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: + - description: "Required. The subscription for which to initialize the new\n stream.\ + \ This must be provided in the first request on the\n stream, and must not\ + \ be set in subsequent requests from\n client to server. Format is\n projects/{project}/subscriptions/{sub}." + id: subscription + var_type: str + - description: "List of acknowledgement IDs for acknowledging previously\n received\ + \ messages (received on this stream or a different\n stream). If an ack ID\ + \ has expired, the corresponding message\n may be redelivered later. Acknowledging\ + \ a message more than\n once will not result in an error. If the acknowledgement\ + \ ID\n is malformed, the stream will be aborted with status\n INVALID_ARGUMENT." + id: ack_ids + var_type: Sequence[str] + - description: "The list of new ack deadlines for the IDs listed in\n modify_deadline_ack_ids.\ + \ The size of this list must be\n the same as the size of modify_deadline_ack_ids.\ + \ If it\n differs the stream will be aborted with\n INVALID_ARGUMENT.\ + \ Each element in this list is applied\n to the element in the same position\ + \ in\n modify_deadline_ack_ids. The new ack deadline is with\n\ + \ respect to the time this request was sent to the Pub/Sub\n system. Must\ + \ be >= 0. For example, if the value is 10, the\n new ack deadline will expire\ + \ 10 seconds after this request\n is received. If the value is 0, the message\ + \ is immediately\n made available for another streaming or non-streaming pull\n\ + \ request. If the value is < 0 (an error), the stream will be\n aborted\ + \ with status INVALID_ARGUMENT." + id: modify_deadline_seconds + var_type: Sequence[int] + - description: "List of acknowledgement IDs whose deadline will be modified\n \ + \ based on the corresponding element in\n modify_deadline_seconds.\ + \ This field can be used to\n indicate that more time is needed to process\ + \ a message by\n the subscriber, or to make the message available for\n \ + \ redelivery if the processing was interrupted." + id: modify_deadline_ack_ids + var_type: Sequence[str] + - description: "Required. The ack deadline to use for the\n stream. This must\ + \ be provided in the first\n request on the stream, but it can also be\n \ + \ updated on subsequent requests from client to\n server. The minimum deadline\ + \ you can specify is\n 10 seconds. The maximum deadline you can specify\n\ + \ is 600 seconds (10 minutes)." + id: stream_ack_deadline_seconds + var_type: int + - description: "A unique identifier that is used to distinguish client\n instances\ + \ from each other. Only needs to be provided on the\n initial request. When\ + \ a stream disconnects and reconnects\n for the same stream, the client_id\ + \ should be set to the same\n value so that state associated with the old\ + \ stream can be\n transferred to the new stream. The same client_id should\ + \ not\n be used for different client instances." + id: client_id + var_type: str + - description: "Flow control settings for the maximum number of outstanding\n \ + \ messages. When there are max_outstanding_messages or\n more\ + \ currently sent to the streaming pull client that have\n not yet been acked\ + \ or nacked, the server stops sending more\n messages. The sending of messages\ + \ resumes once the number of\n outstanding messages is less than this value.\ + \ If the value\n is <= 0, there is no limit to the number of outstanding\n\ + \ messages. This property can only be set on the initial\n StreamingPullRequest.\ + \ If it is set on a subsequent request,\n the stream will be aborted with\ + \ status INVALID_ARGUMENT." + id: max_outstanding_messages + var_type: int + - description: "Flow control settings for the maximum number of outstanding\n \ + \ bytes. When there are max_outstanding_bytes or more\n worth\ + \ of messages currently sent to the streaming pull\n client that have not\ + \ yet been acked or nacked, the server\n will stop sending more messages.\ + \ The sending of messages\n resumes once the number of outstanding bytes is\ + \ less than\n this value. If the value is <= 0, there is no limit to the\n\ + \ number of outstanding bytes. This property can only be set\n on the initial\ + \ StreamingPullRequest. If it is set on a\n subsequent request, the stream\ + \ will be aborted with status\n INVALID_ARGUMENT." + id: max_outstanding_bytes + var_type: int + children: [] + class: google.cloud.pubsub_v1.types.StreamingPullRequest + fullName: google.cloud.pubsub_v1.types.StreamingPullRequest + inheritance: + - inheritance: + - type: builtins.object + type: proto.message.Message + langs: + - python + module: google.cloud.pubsub_v1.types + name: StreamingPullRequest + source: + id: StreamingPullRequest + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Request for the `StreamingPull` streaming RPC method. This request + + is used to establish the initial stream as well as to stream + + acknowledgements and ack deadline modifications from the client to + + the server. + + ' + syntax: + content: StreamingPullRequest(mapping=None, *, ignore_unknown_fields=False, **kwargs) + parameters: [] + type: class + uid: google.cloud.pubsub_v1.types.StreamingPullRequest +references: [] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.StreamingPullResponse.AcknowledgeConfirmation.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.StreamingPullResponse.AcknowledgeConfirmation.yml new file mode 100644 index 000000000000..210182b5c540 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.StreamingPullResponse.AcknowledgeConfirmation.yml @@ -0,0 +1,45 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: + - description: Successfully processed acknowledgement IDs. + id: ack_ids + var_type: Sequence[str] + - description: "List of acknowledgement IDs that were\n malformed or whose acknowledgement\ + \ deadline has\n expired." + id: invalid_ack_ids + var_type: Sequence[str] + - description: "List of acknowledgement IDs that were out of\n order." + id: unordered_ack_ids + var_type: Sequence[str] + children: [] + class: google.cloud.pubsub_v1.types.StreamingPullResponse.AcknowledgeConfirmation + fullName: google.cloud.pubsub_v1.types.StreamingPullResponse.AcknowledgeConfirmation + inheritance: + - inheritance: + - type: builtins.object + type: proto.message.Message + langs: + - python + module: google.cloud.pubsub_v1.types.StreamingPullResponse + name: AcknowledgeConfirmation + source: + id: AcknowledgeConfirmation + path: tests/testdata/gapic-combo/google/pubsub_v1/types/pubsub.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/pubsub_v1/types/pubsub.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 1509 + summary: 'Acknowledgement IDs sent in one or more previous requests to + + acknowledge a previously received message. + + ' + syntax: + content: AcknowledgeConfirmation(mapping=None, *, ignore_unknown_fields=False, + **kwargs) + parameters: [] + type: class + uid: google.cloud.pubsub_v1.types.StreamingPullResponse.AcknowledgeConfirmation +references: [] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.StreamingPullResponse.ModifyAckDeadlineConfirmation.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.StreamingPullResponse.ModifyAckDeadlineConfirmation.yml new file mode 100644 index 000000000000..bd8dcfde294d --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.StreamingPullResponse.ModifyAckDeadlineConfirmation.yml @@ -0,0 +1,42 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: + - description: Successfully processed acknowledgement IDs. + id: ack_ids + var_type: Sequence[str] + - description: "List of acknowledgement IDs that were\n malformed or whose acknowledgement\ + \ deadline has\n expired." + id: invalid_ack_ids + var_type: Sequence[str] + children: [] + class: google.cloud.pubsub_v1.types.StreamingPullResponse.ModifyAckDeadlineConfirmation + fullName: google.cloud.pubsub_v1.types.StreamingPullResponse.ModifyAckDeadlineConfirmation + inheritance: + - inheritance: + - type: builtins.object + type: proto.message.Message + langs: + - python + module: google.cloud.pubsub_v1.types.StreamingPullResponse + name: ModifyAckDeadlineConfirmation + source: + id: ModifyAckDeadlineConfirmation + path: tests/testdata/gapic-combo/google/pubsub_v1/types/pubsub.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/pubsub_v1/types/pubsub.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 1538 + summary: 'Acknowledgement IDs sent in one or more previous requests to + + modify the deadline for a specific message. + + ' + syntax: + content: "ModifyAckDeadlineConfirmation(\n mapping=None, *, ignore_unknown_fields=False,\ + \ **kwargs\n)" + parameters: [] + type: class + uid: google.cloud.pubsub_v1.types.StreamingPullResponse.ModifyAckDeadlineConfirmation +references: [] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.StreamingPullResponse.SubscriptionProperties.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.StreamingPullResponse.SubscriptionProperties.yml new file mode 100644 index 000000000000..b34818032d13 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.StreamingPullResponse.SubscriptionProperties.yml @@ -0,0 +1,39 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: + - description: "True iff exactly once delivery is enabled for\n this subscription." + id: exactly_once_delivery_enabled + var_type: bool + - description: "True iff message ordering is enabled for this\n subscription." + id: message_ordering_enabled + var_type: bool + children: [] + class: google.cloud.pubsub_v1.types.StreamingPullResponse.SubscriptionProperties + fullName: google.cloud.pubsub_v1.types.StreamingPullResponse.SubscriptionProperties + inheritance: + - inheritance: + - type: builtins.object + type: proto.message.Message + langs: + - python + module: google.cloud.pubsub_v1.types.StreamingPullResponse + name: SubscriptionProperties + source: + id: SubscriptionProperties + path: tests/testdata/gapic-combo/google/pubsub_v1/types/pubsub.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/pubsub_v1/types/pubsub.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 1560 + summary: 'Subscription properties sent as part of the response. + + ' + syntax: + content: SubscriptionProperties(mapping=None, *, ignore_unknown_fields=False, + **kwargs) + parameters: [] + type: class + uid: google.cloud.pubsub_v1.types.StreamingPullResponse.SubscriptionProperties +references: [] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.StreamingPullResponse.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.StreamingPullResponse.yml new file mode 100644 index 000000000000..a046c2c73f83 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.StreamingPullResponse.yml @@ -0,0 +1,66 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: + - description: "Received Pub/Sub messages. This will not be\n empty." + id: received_messages + var_type: Sequence[google.pubsub_v1.types.ReceivedMessage] + - description: "This field will only be set if\n enable_exactly_once_delivery\ + \ is set to true." + id: acknowledge_confirmation + var_type: google.pubsub_v1.types.StreamingPullResponse.AcknowledgeConfirmation + - description: "This field will only be set if\n enable_exactly_once_delivery\ + \ is set to true." + id: modify_ack_deadline_confirmation + var_type: google.pubsub_v1.types.StreamingPullResponse.ModifyAckDeadlineConfirmation + - description: Properties associated with this subscription. + id: subscription_properties + var_type: google.pubsub_v1.types.StreamingPullResponse.SubscriptionProperties + children: + - google.cloud.pubsub_v1.types.StreamingPullResponse.AcknowledgeConfirmation + - google.cloud.pubsub_v1.types.StreamingPullResponse.ModifyAckDeadlineConfirmation + - google.cloud.pubsub_v1.types.StreamingPullResponse.SubscriptionProperties + class: google.cloud.pubsub_v1.types.StreamingPullResponse + fullName: google.cloud.pubsub_v1.types.StreamingPullResponse + inheritance: + - inheritance: + - type: builtins.object + type: proto.message.Message + langs: + - python + module: google.cloud.pubsub_v1.types + name: StreamingPullResponse + source: + id: StreamingPullResponse + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Response for the `StreamingPull` method. This response is used to + + stream messages from the server to the client. + + ' + syntax: + content: StreamingPullResponse(mapping=None, *, ignore_unknown_fields=False, **kwargs) + parameters: [] + type: class + uid: google.cloud.pubsub_v1.types.StreamingPullResponse +references: +- fullName: google.cloud.pubsub_v1.types.StreamingPullResponse.AcknowledgeConfirmation + isExternal: false + name: AcknowledgeConfirmation + parent: google.cloud.pubsub_v1.types.StreamingPullResponse + uid: google.cloud.pubsub_v1.types.StreamingPullResponse.AcknowledgeConfirmation +- fullName: google.cloud.pubsub_v1.types.StreamingPullResponse.ModifyAckDeadlineConfirmation + isExternal: false + name: ModifyAckDeadlineConfirmation + parent: google.cloud.pubsub_v1.types.StreamingPullResponse + uid: google.cloud.pubsub_v1.types.StreamingPullResponse.ModifyAckDeadlineConfirmation +- fullName: google.cloud.pubsub_v1.types.StreamingPullResponse.SubscriptionProperties + isExternal: false + name: SubscriptionProperties + parent: google.cloud.pubsub_v1.types.StreamingPullResponse + uid: google.cloud.pubsub_v1.types.StreamingPullResponse.SubscriptionProperties diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Subscription.LabelsEntry.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Subscription.LabelsEntry.yml new file mode 100644 index 000000000000..ffab9fceb32e --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Subscription.LabelsEntry.yml @@ -0,0 +1,44 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: [] + children: [] + class: google.cloud.pubsub_v1.types.Subscription.LabelsEntry + fullName: google.cloud.pubsub_v1.types.Subscription.LabelsEntry + inheritance: + - inheritance: + - type: builtins.object + type: proto.message.Message + langs: + - python + module: google.cloud.pubsub_v1.types.Subscription + name: LabelsEntry + source: + id: LabelsEntry + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'The abstract base class for a message. + + ' + syntax: + content: LabelsEntry(mapping=None, *, ignore_unknown_fields=False, **kwargs) + parameters: + - defaultValue: None + description: Keys and values corresponding to the fields of the message. + id: kwargs + var_type: dict + - description: A dictionary or message to be used to determine the values for + this message. + id: mapping + var_type: Union[dict, .Message] + - description: If True, do not raise errors for unknown fields. Only applied if + mapping is a mapping type or there are keyword parameters. + id: ignore_unknown_fields + var_type: Optional(bool) + type: class + uid: google.cloud.pubsub_v1.types.Subscription.LabelsEntry +references: [] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Subscription.State.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Subscription.State.yml new file mode 100644 index 000000000000..ccd6f69f3eb4 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Subscription.State.yml @@ -0,0 +1,40 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: [] + children: [] + class: google.cloud.pubsub_v1.types.Subscription.State + fullName: google.cloud.pubsub_v1.types.Subscription.State + inheritance: + - inheritance: + - inheritance: + - inheritance: + - type: builtins.object + type: builtins.int + - inheritance: + - type: builtins.object + type: enum.Enum + type: enum.IntEnum + type: proto.enums.Enum + langs: + - python + module: google.cloud.pubsub_v1.types.Subscription + name: State + source: + id: State + path: tests/testdata/gapic-combo/google/pubsub_v1/types/pubsub.py + remote: + branch: add_goldens + path: tests/testdata/gapic-combo/google/pubsub_v1/types/pubsub.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 717 + summary: 'Possible states for a subscription. + + + ' + syntax: + content: State(value) + parameters: [] + type: class + uid: google.cloud.pubsub_v1.types.Subscription.State +references: [] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Subscription.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Subscription.yml new file mode 100644 index 000000000000..5d7643a242c6 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Subscription.yml @@ -0,0 +1,174 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: + - description: "Required. The name of the subscription. It must have the\n format\n\ + \ \"projects/{project}/subscriptions/{subscription}\".\n {subscription}\ + \ must start with a letter, and contain\n only letters ([A-Za-z]),\ + \ numbers ([0-9]), dashes\n (-), underscores (_),\ + \ periods (.), tildes\n (
), plus (`+)\
+      \ or percent signs (%`). It must be\n   between 3 and 255\
+      \ characters in length, and it must not\n   start with \"goog\"."
+    id: name
+    var_type: str
+  - description: "Required. The name of the topic from which this subscription\n \
+      \  is receiving messages. Format is\n   projects/{project}/topics/{topic}.\
+      \ The value of this\n   field will be _deleted-topic_ if the topic\
+      \ has been\n   deleted."
+    id: topic
+    var_type: str
+  - description: "If push delivery is used with this subscription, this field\n  \
+      \ is used to configure it. Either pushConfig or\n   bigQueryConfig\
+      \ can be set, but not both. If both are\n   empty, then the subscriber will\
+      \ pull and ack messages using\n   API methods."
+    id: push_config
+    var_type: google.pubsub_v1.types.PushConfig
+  - description: "If delivery to BigQuery is used with this subscription, this\n \
+      \  field is used to configure it. Either pushConfig or\n   bigQueryConfig\
+      \ can be set, but not both. If both are\n   empty, then the subscriber will\
+      \ pull and ack messages using\n   API methods."
+    id: bigquery_config
+    var_type: google.pubsub_v1.types.BigQueryConfig
+  - description: "The approximate amount of time (on a best-effort basis)\n   Pub/Sub\
+      \ waits for the subscriber to acknowledge receipt\n   before resending the message.\
+      \ In the interval after the\n   message is delivered and before it is acknowledged,\
+      \ it is\n   considered to be outstanding. During that time period, the\n   message\
+      \ will not be redelivered (on a best-effort basis).\n   \n   For pull subscriptions,\
+      \ this value is used as the initial\n   value for the ack deadline. To override\
+      \ this value for a\n   given message, call ModifyAckDeadline with\
+      \ the\n   corresponding ack_id if using non-streaming pull or send\n\
+      \   the ack_id in a StreamingModifyAckDeadlineRequest\
+      \ if\n   using streaming pull. The minimum custom deadline you can\n   specify\
+      \ is 10 seconds. The maximum custom deadline you can\n   specify is 600 seconds\
+      \ (10 minutes). If this parameter is 0,\n   a default value of 10 seconds is\
+      \ used.\n   \n   For push delivery, this value is also used to set the\n   request\
+      \ timeout for the call to the push endpoint.\n   \n   If the subscriber never\
+      \ acknowledges the message, the\n   Pub/Sub system will eventually redeliver\
+      \ the message."
+    id: ack_deadline_seconds
+    var_type: int
+  - description: "Indicates whether to retain acknowledged messages. If true,\n  \
+      \ then messages are not expunged from the subscription's\n   backlog, even if\
+      \ they are acknowledged, until they fall out\n   of the message_retention_duration\
+      \ window. This must be\n   true if you would like to [Seek to a\
+      \ timestamp]\n   (https://cloud.google.com/pubsub/docs/replay-overview#seek_to_a_time)\n\
+      \   in the past to replay previously-acknowledged messages."
+    id: retain_acked_messages
+    var_type: bool
+  - description: "How long to retain unacknowledged messages in the\n   subscription's\
+      \ backlog, from the moment a message is\n   published. If retain_acked_messages\
+      \ is true, then this\n   also configures the retention of acknowledged messages,\
+      \ and\n   thus configures how far back in time a Seek can be done.\n\
+      \   Defaults to 7 days. Cannot be more than 7 days or less than\n   10 minutes."
+    id: message_retention_duration
+    var_type: google.protobuf.duration_pb2.Duration
+  - description: "See \n   Creating and managing labels."
+    id: labels
+    var_type: Mapping[str, str]
+  - description: "If true, messages published with the same ordering_key\n\
+      \   in PubsubMessage will be delivered to the subscribers in\n\
+      \   the order in which they are received by the Pub/Sub system.\n   Otherwise,\
+      \ they may be delivered in any order."
+    id: enable_message_ordering
+    var_type: bool
+  - description: "A policy that specifies the conditions for this\n   subscription's\
+      \ expiration. A subscription is considered\n   active as long as any connected\
+      \ subscriber is successfully\n   consuming messages from the subscription or\
+      \ is issuing\n   operations on the subscription. If expiration_policy\
+      \ is\n   not set, a *default policy* with ttl of 31 days will be\n\
+      \   used. The minimum allowed value for\n   expiration_policy.ttl\
+      \ is 1 day."
+    id: expiration_policy
+    var_type: google.pubsub_v1.types.ExpirationPolicy
+  - description: "An expression written in the Pub/Sub `filter\n   language `__.\n\
+      \   If non-empty, then only PubsubMessage\\ s whose\n   attributes\
+      \ field matches the filter are delivered on\n   this subscription. If empty,\
+      \ then no messages are filtered\n   out."
+    id: filter
+    var_type: str
+  - description: "A policy that specifies the conditions for dead lettering\n   messages\
+      \ in this subscription. If dead_letter_policy is not\n   set, dead lettering\
+      \ is disabled.\n   \n   The Cloud Pub/Sub service account associated with this\n\
+      \   subscriptions's parent project (i.e.,\n   service-{project_number}@gcp-sa-pubsub.iam.gserviceaccount.com)\n\
+      \   must have permission to Acknowledge() messages on this\n   subscription."
+    id: dead_letter_policy
+    var_type: google.pubsub_v1.types.DeadLetterPolicy
+  - description: "A policy that specifies how Pub/Sub retries\n   message delivery\
+      \ for this subscription.\n   \n   If not set, the default retry policy is applied.\n\
+      \   This generally implies that messages will be\n   retried as soon as possible\
+      \ for healthy\n   subscribers. RetryPolicy will be triggered on\n   NACKs or\
+      \ acknowledgement deadline exceeded\n   events for a given message."
+    id: retry_policy
+    var_type: google.pubsub_v1.types.RetryPolicy
+  - description: "Indicates whether the subscription is detached from its\n   topic.\
+      \ Detached subscriptions don't receive messages from\n   their topic and don't\
+      \ retain any backlog. Pull and\n   StreamingPull requests\
+      \ will return FAILED_PRECONDITION.\n   If the subscription is a push subscription,\
+      \ pushes to the\n   endpoint will not be made."
+    id: detached
+    var_type: bool
+  - description: "If true, Pub/Sub provides the following guarantees for the\n   delivery\
+      \ of a message with a given value of message_id\n   on this subscription:\n\
+      \   \n   -  The message sent to a subscriber is guaranteed not to be\n     \
+      \ resent before the message's acknowledgement deadline\n      expires.\n   -\
+      \  An acknowledged message will not be resent to a\n      subscriber.\n   \n\
+      \   Note that subscribers may still receive multiple copies of a\n   message\
+      \ when enable_exactly_once_delivery is true if the\n   message\
+      \ was published multiple times by a publisher client.\n   These copies are considered\
+      \ distinct by Pub/Sub and have\n   distinct message_id values."
+    id: enable_exactly_once_delivery
+    var_type: bool
+  - description: "Output only. Indicates the minimum duration for which a\n   message\
+      \ is retained after it is published to the\n   subscription's topic. If this\
+      \ field is set, messages\n   published to the subscription's topic in the last\n\
+      \   topic_message_retention_duration are always available to\n\
+      \   subscribers. See the message_retention_duration field in\n\
+      \   Topic. This field is set only in responses from the\n   server;\
+      \ it is ignored if it is set in any requests."
+    id: topic_message_retention_duration
+    var_type: google.protobuf.duration_pb2.Duration
+  - description: "Output only. An output-only field indicating\n   whether or not\
+      \ the subscription can receive\n   messages."
+    id: state
+    var_type: google.pubsub_v1.types.Subscription.State
+  children:
+  - google.cloud.pubsub_v1.types.Subscription.LabelsEntry
+  - google.cloud.pubsub_v1.types.Subscription.State
+  class: google.cloud.pubsub_v1.types.Subscription
+  fullName: google.cloud.pubsub_v1.types.Subscription
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: proto.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: Subscription
+  source:
+    id: Subscription
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'A subscription resource.
+
+    '
+  syntax:
+    content: Subscription(mapping=None, *, ignore_unknown_fields=False, **kwargs)
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.types.Subscription
+references:
+- fullName: google.cloud.pubsub_v1.types.Subscription.LabelsEntry
+  isExternal: false
+  name: LabelsEntry
+  parent: google.cloud.pubsub_v1.types.Subscription
+  uid: google.cloud.pubsub_v1.types.Subscription.LabelsEntry
+- fullName: google.cloud.pubsub_v1.types.Subscription.State
+  isExternal: false
+  name: State
+  parent: google.cloud.pubsub_v1.types.Subscription
+  uid: google.cloud.pubsub_v1.types.Subscription.State
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.TestIamPermissionsRequest.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.TestIamPermissionsRequest.yml
new file mode 100644
index 000000000000..545db416adb3
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.TestIamPermissionsRequest.yml
@@ -0,0 +1,30 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- children: []
+  class: google.cloud.pubsub_v1.types.TestIamPermissionsRequest
+  fullName: google.cloud.pubsub_v1.types.TestIamPermissionsRequest
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: google._upb._message.Message
+  - inheritance:
+    - type: builtins.object
+    type: google.protobuf.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: TestIamPermissionsRequest
+  source:
+    id: TestIamPermissionsRequest
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: API documentation for `pubsub_v1.types.TestIamPermissionsRequest` class.
+  syntax: {}
+  type: class
+  uid: google.cloud.pubsub_v1.types.TestIamPermissionsRequest
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.TestIamPermissionsResponse.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.TestIamPermissionsResponse.yml
new file mode 100644
index 000000000000..3ae9281bdde7
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.TestIamPermissionsResponse.yml
@@ -0,0 +1,30 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- children: []
+  class: google.cloud.pubsub_v1.types.TestIamPermissionsResponse
+  fullName: google.cloud.pubsub_v1.types.TestIamPermissionsResponse
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: google._upb._message.Message
+  - inheritance:
+    - type: builtins.object
+    type: google.protobuf.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: TestIamPermissionsResponse
+  source:
+    id: TestIamPermissionsResponse
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: API documentation for `pubsub_v1.types.TestIamPermissionsResponse` class.
+  syntax: {}
+  type: class
+  uid: google.cloud.pubsub_v1.types.TestIamPermissionsResponse
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Timestamp.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Timestamp.yml
new file mode 100644
index 000000000000..09429e088ae0
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Timestamp.yml
@@ -0,0 +1,33 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- children: []
+  class: google.cloud.pubsub_v1.types.Timestamp
+  fullName: google.cloud.pubsub_v1.types.Timestamp
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: google._upb._message.Message
+  - inheritance:
+    - type: builtins.object
+    type: google.protobuf.message.Message
+  - inheritance:
+    - type: builtins.object
+    type: google.protobuf.internal.well_known_types.Timestamp
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: Timestamp
+  source:
+    id: Timestamp
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: API documentation for `pubsub_v1.types.Timestamp` class.
+  syntax: {}
+  type: class
+  uid: google.cloud.pubsub_v1.types.Timestamp
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Topic.LabelsEntry.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Topic.LabelsEntry.yml
new file mode 100644
index 000000000000..ad742e6579de
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Topic.LabelsEntry.yml
@@ -0,0 +1,44 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes: []
+  children: []
+  class: google.cloud.pubsub_v1.types.Topic.LabelsEntry
+  fullName: google.cloud.pubsub_v1.types.Topic.LabelsEntry
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: proto.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types.Topic
+  name: LabelsEntry
+  source:
+    id: LabelsEntry
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'The abstract base class for a message.
+
+    '
+  syntax:
+    content: LabelsEntry(mapping=None, *, ignore_unknown_fields=False, **kwargs)
+    parameters:
+    - defaultValue: None
+      description: Keys and values corresponding to the fields of the message.
+      id: kwargs
+      var_type: dict
+    - description: A dictionary or message to be used to determine the values for
+        this message.
+      id: mapping
+      var_type: Union[dict, .Message]
+    - description: If True, do not raise errors for unknown fields. Only applied if
+        mapping is a mapping type or there are keyword parameters.
+      id: ignore_unknown_fields
+      var_type: Optional(bool)
+  type: class
+  uid: google.cloud.pubsub_v1.types.Topic.LabelsEntry
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Topic.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Topic.yml
new file mode 100644
index 000000000000..750c2aa428a7
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.Topic.yml
@@ -0,0 +1,77 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes:
+  - description: "Required. The name of the topic. It must have the format\n   \"\
+      projects/{project}/topics/{topic}\". {topic} must\n   start\
+      \ with a letter, and contain only letters\n   ([A-Za-z]), numbers\
+      \ ([0-9]), dashes (-),\n   underscores (`_),\
+      \ periods (.`), tildes (
), plus\n   (+)\
+      \ or percent signs (%). It must be between 3 and\n   255 characters\
+      \ in length, and it must not start with\n   \"goog\"."
+    id: name
+    var_type: str
+  - description: "See [Creating and managing labels]\n   (https://cloud.google.com/pubsub/docs/labels)."
+    id: labels
+    var_type: Mapping[str, str]
+  - description: "Policy constraining the set of Google Cloud\n   Platform regions\
+      \ where messages published to the\n   topic may be stored. If not present, then\
+      \ no\n   constraints are in effect."
+    id: message_storage_policy
+    var_type: google.pubsub_v1.types.MessageStoragePolicy
+  - description: "The resource name of the Cloud KMS CryptoKey to be used to\n   protect\
+      \ access to messages published on this topic.\n   \n   The expected format is\n\
+      \   projects/*/locations/*/keyRings/*/cryptoKeys/*."
+    id: kms_key_name
+    var_type: str
+  - description: "Settings for validating messages published\n   against a schema."
+    id: schema_settings
+    var_type: google.pubsub_v1.types.SchemaSettings
+  - description: "Reserved for future use. This field is set\n   only in responses\
+      \ from the server; it is ignored\n   if it is set in any requests."
+    id: satisfies_pzs
+    var_type: bool
+  - description: "Indicates the minimum duration to retain a message after it\n  \
+      \ is published to the topic. If this field is set, messages\n   published to\
+      \ the topic in the last\n   message_retention_duration are always\
+      \ available to\n   subscribers. For instance, it allows any attached\n   subscription\
+      \ to `seek to a\n   timestamp `__\n\
+      \   that is up to message_retention_duration in the past. If\n\
+      \   this field is not set, message retention is controlled by\n   settings on\
+      \ individual subscriptions. Cannot be more than 7\n   days or less than 10 minutes."
+    id: message_retention_duration
+    var_type: google.protobuf.duration_pb2.Duration
+  children:
+  - google.cloud.pubsub_v1.types.Topic.LabelsEntry
+  class: google.cloud.pubsub_v1.types.Topic
+  fullName: google.cloud.pubsub_v1.types.Topic
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: proto.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: Topic
+  source:
+    id: Topic
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'A topic resource.
+
+    '
+  syntax:
+    content: Topic(mapping=None, *, ignore_unknown_fields=False, **kwargs)
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.types.Topic
+references:
+- fullName: google.cloud.pubsub_v1.types.Topic.LabelsEntry
+  isExternal: false
+  name: LabelsEntry
+  parent: google.cloud.pubsub_v1.types.Topic
+  uid: google.cloud.pubsub_v1.types.Topic.LabelsEntry
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.UninterpretedOption.NamePart.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.UninterpretedOption.NamePart.yml
new file mode 100644
index 000000000000..31275427897b
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.UninterpretedOption.NamePart.yml
@@ -0,0 +1,30 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- children: []
+  class: google.cloud.pubsub_v1.types.UninterpretedOption.NamePart
+  fullName: google.cloud.pubsub_v1.types.UninterpretedOption.NamePart
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: google._upb._message.Message
+  - inheritance:
+    - type: builtins.object
+    type: google.protobuf.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types.UninterpretedOption
+  name: NamePart
+  source:
+    id: NamePart
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: API documentation for `pubsub_v1.types.UninterpretedOption.NamePart` class.
+  syntax: {}
+  type: class
+  uid: google.cloud.pubsub_v1.types.UninterpretedOption.NamePart
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.UninterpretedOption.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.UninterpretedOption.yml
new file mode 100644
index 000000000000..83b655a68546
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.UninterpretedOption.yml
@@ -0,0 +1,36 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- children:
+  - google.cloud.pubsub_v1.types.UninterpretedOption.NamePart
+  class: google.cloud.pubsub_v1.types.UninterpretedOption
+  fullName: google.cloud.pubsub_v1.types.UninterpretedOption
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: google._upb._message.Message
+  - inheritance:
+    - type: builtins.object
+    type: google.protobuf.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: UninterpretedOption
+  source:
+    id: UninterpretedOption
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: API documentation for `pubsub_v1.types.UninterpretedOption` class.
+  syntax: {}
+  type: class
+  uid: google.cloud.pubsub_v1.types.UninterpretedOption
+references:
+- fullName: google.cloud.pubsub_v1.types.UninterpretedOption.NamePart
+  isExternal: false
+  name: NamePart
+  parent: google.cloud.pubsub_v1.types.UninterpretedOption
+  uid: google.cloud.pubsub_v1.types.UninterpretedOption.NamePart
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.UpdateSnapshotRequest.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.UpdateSnapshotRequest.yml
new file mode 100644
index 000000000000..e774f1a8a619
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.UpdateSnapshotRequest.yml
@@ -0,0 +1,39 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes:
+  - description: Required. The updated snapshot object.
+    id: snapshot
+    var_type: google.pubsub_v1.types.Snapshot
+  - description: "Required. Indicates which fields in the\n   provided snapshot to\
+      \ update. Must be specified\n   and non-empty."
+    id: update_mask
+    var_type: google.protobuf.field_mask_pb2.FieldMask
+  children: []
+  class: google.cloud.pubsub_v1.types.UpdateSnapshotRequest
+  fullName: google.cloud.pubsub_v1.types.UpdateSnapshotRequest
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: proto.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: UpdateSnapshotRequest
+  source:
+    id: UpdateSnapshotRequest
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Request for the UpdateSnapshot method.
+
+    '
+  syntax:
+    content: UpdateSnapshotRequest(mapping=None, *, ignore_unknown_fields=False, **kwargs)
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.types.UpdateSnapshotRequest
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.UpdateSubscriptionRequest.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.UpdateSubscriptionRequest.yml
new file mode 100644
index 000000000000..1c5faf6fc672
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.UpdateSubscriptionRequest.yml
@@ -0,0 +1,40 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes:
+  - description: Required. The updated subscription object.
+    id: subscription
+    var_type: google.pubsub_v1.types.Subscription
+  - description: "Required. Indicates which fields in the\n   provided subscription\
+      \ to update. Must be\n   specified and non-empty."
+    id: update_mask
+    var_type: google.protobuf.field_mask_pb2.FieldMask
+  children: []
+  class: google.cloud.pubsub_v1.types.UpdateSubscriptionRequest
+  fullName: google.cloud.pubsub_v1.types.UpdateSubscriptionRequest
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: proto.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: UpdateSubscriptionRequest
+  source:
+    id: UpdateSubscriptionRequest
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Request for the UpdateSubscription method.
+
+    '
+  syntax:
+    content: UpdateSubscriptionRequest(mapping=None, *, ignore_unknown_fields=False,
+      **kwargs)
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.types.UpdateSubscriptionRequest
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.UpdateTopicRequest.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.UpdateTopicRequest.yml
new file mode 100644
index 000000000000..baed3fee2bbb
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.UpdateTopicRequest.yml
@@ -0,0 +1,43 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes:
+  - description: Required. The updated topic object.
+    id: topic
+    var_type: google.pubsub_v1.types.Topic
+  - description: "Required. Indicates which fields in the provided topic to\n   update.\
+      \ Must be specified and non-empty. Note that if\n   update_mask\
+      \ contains \"message_storage_policy\" but the\n   message_storage_policy\
+      \ is not set in the topic\n   provided above, then the updated\
+      \ value is determined by the\n   policy configured at the project or organization\
+      \ level."
+    id: update_mask
+    var_type: google.protobuf.field_mask_pb2.FieldMask
+  children: []
+  class: google.cloud.pubsub_v1.types.UpdateTopicRequest
+  fullName: google.cloud.pubsub_v1.types.UpdateTopicRequest
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: proto.message.Message
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: UpdateTopicRequest
+  source:
+    id: UpdateTopicRequest
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Request for the UpdateTopic method.
+
+    '
+  syntax:
+    content: UpdateTopicRequest(mapping=None, *, ignore_unknown_fields=False, **kwargs)
+    parameters: []
+  type: class
+  uid: google.cloud.pubsub_v1.types.UpdateTopicRequest
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.yml
new file mode 100644
index 000000000000..937dc1d67720
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.types.yml
@@ -0,0 +1,562 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- children:
+  - google.cloud.pubsub_v1.types.AcknowledgeRequest
+  - google.cloud.pubsub_v1.types.AuditConfig
+  - google.cloud.pubsub_v1.types.AuditConfigDelta
+  - google.cloud.pubsub_v1.types.AuditData
+  - google.cloud.pubsub_v1.types.AuditLogConfig
+  - google.cloud.pubsub_v1.types.BatchSettings
+  - google.cloud.pubsub_v1.types.BigQueryConfig
+  - google.cloud.pubsub_v1.types.Binding
+  - google.cloud.pubsub_v1.types.BindingDelta
+  - google.cloud.pubsub_v1.types.CreateSnapshotRequest
+  - google.cloud.pubsub_v1.types.CustomHttpPattern
+  - google.cloud.pubsub_v1.types.DeadLetterPolicy
+  - google.cloud.pubsub_v1.types.DeleteSnapshotRequest
+  - google.cloud.pubsub_v1.types.DeleteSubscriptionRequest
+  - google.cloud.pubsub_v1.types.DeleteTopicRequest
+  - google.cloud.pubsub_v1.types.DescriptorProto
+  - google.cloud.pubsub_v1.types.DetachSubscriptionRequest
+  - google.cloud.pubsub_v1.types.DetachSubscriptionResponse
+  - google.cloud.pubsub_v1.types.Duration
+  - google.cloud.pubsub_v1.types.Empty
+  - google.cloud.pubsub_v1.types.EnumDescriptorProto
+  - google.cloud.pubsub_v1.types.EnumOptions
+  - google.cloud.pubsub_v1.types.EnumValueDescriptorProto
+  - google.cloud.pubsub_v1.types.EnumValueOptions
+  - google.cloud.pubsub_v1.types.ExpirationPolicy
+  - google.cloud.pubsub_v1.types.ExtensionRangeOptions
+  - google.cloud.pubsub_v1.types.FieldDescriptorProto
+  - google.cloud.pubsub_v1.types.FieldMask
+  - google.cloud.pubsub_v1.types.FieldOptions
+  - google.cloud.pubsub_v1.types.FileDescriptorProto
+  - google.cloud.pubsub_v1.types.FileDescriptorSet
+  - google.cloud.pubsub_v1.types.FileOptions
+  - google.cloud.pubsub_v1.types.FlowControl
+  - google.cloud.pubsub_v1.types.GeneratedCodeInfo
+  - google.cloud.pubsub_v1.types.GetIamPolicyRequest
+  - google.cloud.pubsub_v1.types.GetSnapshotRequest
+  - google.cloud.pubsub_v1.types.GetSubscriptionRequest
+  - google.cloud.pubsub_v1.types.GetTopicRequest
+  - google.cloud.pubsub_v1.types.Http
+  - google.cloud.pubsub_v1.types.HttpRule
+  - google.cloud.pubsub_v1.types.LimitExceededBehavior
+  - google.cloud.pubsub_v1.types.ListSnapshotsRequest
+  - google.cloud.pubsub_v1.types.ListSnapshotsResponse
+  - google.cloud.pubsub_v1.types.ListSubscriptionsRequest
+  - google.cloud.pubsub_v1.types.ListSubscriptionsResponse
+  - google.cloud.pubsub_v1.types.ListTopicSnapshotsRequest
+  - google.cloud.pubsub_v1.types.ListTopicSnapshotsResponse
+  - google.cloud.pubsub_v1.types.ListTopicSubscriptionsRequest
+  - google.cloud.pubsub_v1.types.ListTopicSubscriptionsResponse
+  - google.cloud.pubsub_v1.types.ListTopicsRequest
+  - google.cloud.pubsub_v1.types.ListTopicsResponse
+  - google.cloud.pubsub_v1.types.MessageOptions
+  - google.cloud.pubsub_v1.types.MessageStoragePolicy
+  - google.cloud.pubsub_v1.types.MethodDescriptorProto
+  - google.cloud.pubsub_v1.types.MethodOptions
+  - google.cloud.pubsub_v1.types.ModifyAckDeadlineRequest
+  - google.cloud.pubsub_v1.types.ModifyPushConfigRequest
+  - google.cloud.pubsub_v1.types.OneofDescriptorProto
+  - google.cloud.pubsub_v1.types.OneofOptions
+  - google.cloud.pubsub_v1.types.Policy
+  - google.cloud.pubsub_v1.types.PolicyDelta
+  - google.cloud.pubsub_v1.types.PublishFlowControl
+  - google.cloud.pubsub_v1.types.PublishRequest
+  - google.cloud.pubsub_v1.types.PublishResponse
+  - google.cloud.pubsub_v1.types.PublisherOptions
+  - google.cloud.pubsub_v1.types.PubsubMessage
+  - google.cloud.pubsub_v1.types.PullRequest
+  - google.cloud.pubsub_v1.types.PullResponse
+  - google.cloud.pubsub_v1.types.PushConfig
+  - google.cloud.pubsub_v1.types.ReceivedMessage
+  - google.cloud.pubsub_v1.types.RetryPolicy
+  - google.cloud.pubsub_v1.types.SchemaSettings
+  - google.cloud.pubsub_v1.types.SeekRequest
+  - google.cloud.pubsub_v1.types.SeekResponse
+  - google.cloud.pubsub_v1.types.ServiceDescriptorProto
+  - google.cloud.pubsub_v1.types.ServiceOptions
+  - google.cloud.pubsub_v1.types.SetIamPolicyRequest
+  - google.cloud.pubsub_v1.types.Snapshot
+  - google.cloud.pubsub_v1.types.SourceCodeInfo
+  - google.cloud.pubsub_v1.types.StreamingPullRequest
+  - google.cloud.pubsub_v1.types.StreamingPullResponse
+  - google.cloud.pubsub_v1.types.Subscription
+  - google.cloud.pubsub_v1.types.TestIamPermissionsRequest
+  - google.cloud.pubsub_v1.types.TestIamPermissionsResponse
+  - google.cloud.pubsub_v1.types.Timestamp
+  - google.cloud.pubsub_v1.types.Topic
+  - google.cloud.pubsub_v1.types.UninterpretedOption
+  - google.cloud.pubsub_v1.types.UpdateSnapshotRequest
+  - google.cloud.pubsub_v1.types.UpdateSubscriptionRequest
+  - google.cloud.pubsub_v1.types.UpdateTopicRequest
+  fullName: google.cloud.pubsub_v1.types
+  langs:
+  - python
+  module: google.cloud.pubsub_v1.types
+  name: types
+  source:
+    id: types
+    path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/types.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/types.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 0
+  summary: API documentation for `pubsub_v1.types` module.
+  syntax: {}
+  type: module
+  uid: google.cloud.pubsub_v1.types
+references:
+- fullName: google.cloud.pubsub_v1.types.AcknowledgeRequest
+  isExternal: false
+  name: AcknowledgeRequest
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.AcknowledgeRequest
+- fullName: google.cloud.pubsub_v1.types.AuditConfig
+  isExternal: false
+  name: AuditConfig
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.AuditConfig
+- fullName: google.cloud.pubsub_v1.types.AuditConfigDelta
+  isExternal: false
+  name: AuditConfigDelta
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.AuditConfigDelta
+- fullName: google.cloud.pubsub_v1.types.AuditData
+  isExternal: false
+  name: AuditData
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.AuditData
+- fullName: google.cloud.pubsub_v1.types.AuditLogConfig
+  isExternal: false
+  name: AuditLogConfig
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.AuditLogConfig
+- fullName: google.cloud.pubsub_v1.types.BatchSettings
+  isExternal: false
+  name: BatchSettings
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.BatchSettings
+- fullName: google.cloud.pubsub_v1.types.BigQueryConfig
+  isExternal: false
+  name: BigQueryConfig
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.BigQueryConfig
+- fullName: google.cloud.pubsub_v1.types.Binding
+  isExternal: false
+  name: Binding
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.Binding
+- fullName: google.cloud.pubsub_v1.types.BindingDelta
+  isExternal: false
+  name: BindingDelta
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.BindingDelta
+- fullName: google.cloud.pubsub_v1.types.CreateSnapshotRequest
+  isExternal: false
+  name: CreateSnapshotRequest
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.CreateSnapshotRequest
+- fullName: google.cloud.pubsub_v1.types.CustomHttpPattern
+  isExternal: false
+  name: CustomHttpPattern
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.CustomHttpPattern
+- fullName: google.cloud.pubsub_v1.types.DeadLetterPolicy
+  isExternal: false
+  name: DeadLetterPolicy
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.DeadLetterPolicy
+- fullName: google.cloud.pubsub_v1.types.DeleteSnapshotRequest
+  isExternal: false
+  name: DeleteSnapshotRequest
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.DeleteSnapshotRequest
+- fullName: google.cloud.pubsub_v1.types.DeleteSubscriptionRequest
+  isExternal: false
+  name: DeleteSubscriptionRequest
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.DeleteSubscriptionRequest
+- fullName: google.cloud.pubsub_v1.types.DeleteTopicRequest
+  isExternal: false
+  name: DeleteTopicRequest
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.DeleteTopicRequest
+- fullName: google.cloud.pubsub_v1.types.DescriptorProto
+  isExternal: false
+  name: DescriptorProto
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.DescriptorProto
+- fullName: google.cloud.pubsub_v1.types.DetachSubscriptionRequest
+  isExternal: false
+  name: DetachSubscriptionRequest
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.DetachSubscriptionRequest
+- fullName: google.cloud.pubsub_v1.types.DetachSubscriptionResponse
+  isExternal: false
+  name: DetachSubscriptionResponse
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.DetachSubscriptionResponse
+- fullName: google.cloud.pubsub_v1.types.Duration
+  isExternal: false
+  name: Duration
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.Duration
+- fullName: google.cloud.pubsub_v1.types.Empty
+  isExternal: false
+  name: Empty
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.Empty
+- fullName: google.cloud.pubsub_v1.types.EnumDescriptorProto
+  isExternal: false
+  name: EnumDescriptorProto
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.EnumDescriptorProto
+- fullName: google.cloud.pubsub_v1.types.EnumOptions
+  isExternal: false
+  name: EnumOptions
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.EnumOptions
+- fullName: google.cloud.pubsub_v1.types.EnumValueDescriptorProto
+  isExternal: false
+  name: EnumValueDescriptorProto
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.EnumValueDescriptorProto
+- fullName: google.cloud.pubsub_v1.types.EnumValueOptions
+  isExternal: false
+  name: EnumValueOptions
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.EnumValueOptions
+- fullName: google.cloud.pubsub_v1.types.ExpirationPolicy
+  isExternal: false
+  name: ExpirationPolicy
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.ExpirationPolicy
+- fullName: google.cloud.pubsub_v1.types.ExtensionRangeOptions
+  isExternal: false
+  name: ExtensionRangeOptions
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.ExtensionRangeOptions
+- fullName: google.cloud.pubsub_v1.types.FieldDescriptorProto
+  isExternal: false
+  name: FieldDescriptorProto
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.FieldDescriptorProto
+- fullName: google.cloud.pubsub_v1.types.FieldMask
+  isExternal: false
+  name: FieldMask
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.FieldMask
+- fullName: google.cloud.pubsub_v1.types.FieldOptions
+  isExternal: false
+  name: FieldOptions
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.FieldOptions
+- fullName: google.cloud.pubsub_v1.types.FileDescriptorProto
+  isExternal: false
+  name: FileDescriptorProto
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.FileDescriptorProto
+- fullName: google.cloud.pubsub_v1.types.FileDescriptorSet
+  isExternal: false
+  name: FileDescriptorSet
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.FileDescriptorSet
+- fullName: google.cloud.pubsub_v1.types.FileOptions
+  isExternal: false
+  name: FileOptions
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.FileOptions
+- fullName: google.cloud.pubsub_v1.types.FlowControl
+  isExternal: false
+  name: FlowControl
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.FlowControl
+- fullName: google.cloud.pubsub_v1.types.GeneratedCodeInfo
+  isExternal: false
+  name: GeneratedCodeInfo
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.GeneratedCodeInfo
+- fullName: google.cloud.pubsub_v1.types.GetIamPolicyRequest
+  isExternal: false
+  name: GetIamPolicyRequest
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.GetIamPolicyRequest
+- fullName: google.cloud.pubsub_v1.types.GetSnapshotRequest
+  isExternal: false
+  name: GetSnapshotRequest
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.GetSnapshotRequest
+- fullName: google.cloud.pubsub_v1.types.GetSubscriptionRequest
+  isExternal: false
+  name: GetSubscriptionRequest
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.GetSubscriptionRequest
+- fullName: google.cloud.pubsub_v1.types.GetTopicRequest
+  isExternal: false
+  name: GetTopicRequest
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.GetTopicRequest
+- fullName: google.cloud.pubsub_v1.types.Http
+  isExternal: false
+  name: Http
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.Http
+- fullName: google.cloud.pubsub_v1.types.HttpRule
+  isExternal: false
+  name: HttpRule
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.HttpRule
+- fullName: google.cloud.pubsub_v1.types.LimitExceededBehavior
+  isExternal: false
+  name: LimitExceededBehavior
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.LimitExceededBehavior
+- fullName: google.cloud.pubsub_v1.types.ListSnapshotsRequest
+  isExternal: false
+  name: ListSnapshotsRequest
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.ListSnapshotsRequest
+- fullName: google.cloud.pubsub_v1.types.ListSnapshotsResponse
+  isExternal: false
+  name: ListSnapshotsResponse
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.ListSnapshotsResponse
+- fullName: google.cloud.pubsub_v1.types.ListSubscriptionsRequest
+  isExternal: false
+  name: ListSubscriptionsRequest
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.ListSubscriptionsRequest
+- fullName: google.cloud.pubsub_v1.types.ListSubscriptionsResponse
+  isExternal: false
+  name: ListSubscriptionsResponse
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.ListSubscriptionsResponse
+- fullName: google.cloud.pubsub_v1.types.ListTopicSnapshotsRequest
+  isExternal: false
+  name: ListTopicSnapshotsRequest
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.ListTopicSnapshotsRequest
+- fullName: google.cloud.pubsub_v1.types.ListTopicSnapshotsResponse
+  isExternal: false
+  name: ListTopicSnapshotsResponse
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.ListTopicSnapshotsResponse
+- fullName: google.cloud.pubsub_v1.types.ListTopicSubscriptionsRequest
+  isExternal: false
+  name: ListTopicSubscriptionsRequest
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.ListTopicSubscriptionsRequest
+- fullName: google.cloud.pubsub_v1.types.ListTopicSubscriptionsResponse
+  isExternal: false
+  name: ListTopicSubscriptionsResponse
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.ListTopicSubscriptionsResponse
+- fullName: google.cloud.pubsub_v1.types.ListTopicsRequest
+  isExternal: false
+  name: ListTopicsRequest
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.ListTopicsRequest
+- fullName: google.cloud.pubsub_v1.types.ListTopicsResponse
+  isExternal: false
+  name: ListTopicsResponse
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.ListTopicsResponse
+- fullName: google.cloud.pubsub_v1.types.MessageOptions
+  isExternal: false
+  name: MessageOptions
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.MessageOptions
+- fullName: google.cloud.pubsub_v1.types.MessageStoragePolicy
+  isExternal: false
+  name: MessageStoragePolicy
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.MessageStoragePolicy
+- fullName: google.cloud.pubsub_v1.types.MethodDescriptorProto
+  isExternal: false
+  name: MethodDescriptorProto
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.MethodDescriptorProto
+- fullName: google.cloud.pubsub_v1.types.MethodOptions
+  isExternal: false
+  name: MethodOptions
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.MethodOptions
+- fullName: google.cloud.pubsub_v1.types.ModifyAckDeadlineRequest
+  isExternal: false
+  name: ModifyAckDeadlineRequest
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.ModifyAckDeadlineRequest
+- fullName: google.cloud.pubsub_v1.types.ModifyPushConfigRequest
+  isExternal: false
+  name: ModifyPushConfigRequest
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.ModifyPushConfigRequest
+- fullName: google.cloud.pubsub_v1.types.OneofDescriptorProto
+  isExternal: false
+  name: OneofDescriptorProto
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.OneofDescriptorProto
+- fullName: google.cloud.pubsub_v1.types.OneofOptions
+  isExternal: false
+  name: OneofOptions
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.OneofOptions
+- fullName: google.cloud.pubsub_v1.types.Policy
+  isExternal: false
+  name: Policy
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.Policy
+- fullName: google.cloud.pubsub_v1.types.PolicyDelta
+  isExternal: false
+  name: PolicyDelta
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.PolicyDelta
+- fullName: google.cloud.pubsub_v1.types.PublishFlowControl
+  isExternal: false
+  name: PublishFlowControl
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.PublishFlowControl
+- fullName: google.cloud.pubsub_v1.types.PublishRequest
+  isExternal: false
+  name: PublishRequest
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.PublishRequest
+- fullName: google.cloud.pubsub_v1.types.PublishResponse
+  isExternal: false
+  name: PublishResponse
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.PublishResponse
+- fullName: google.cloud.pubsub_v1.types.PublisherOptions
+  isExternal: false
+  name: PublisherOptions
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.PublisherOptions
+- fullName: google.cloud.pubsub_v1.types.PubsubMessage
+  isExternal: false
+  name: PubsubMessage
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.PubsubMessage
+- fullName: google.cloud.pubsub_v1.types.PullRequest
+  isExternal: false
+  name: PullRequest
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.PullRequest
+- fullName: google.cloud.pubsub_v1.types.PullResponse
+  isExternal: false
+  name: PullResponse
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.PullResponse
+- fullName: google.cloud.pubsub_v1.types.PushConfig
+  isExternal: false
+  name: PushConfig
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.PushConfig
+- fullName: google.cloud.pubsub_v1.types.ReceivedMessage
+  isExternal: false
+  name: ReceivedMessage
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.ReceivedMessage
+- fullName: google.cloud.pubsub_v1.types.RetryPolicy
+  isExternal: false
+  name: RetryPolicy
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.RetryPolicy
+- fullName: google.cloud.pubsub_v1.types.SchemaSettings
+  isExternal: false
+  name: SchemaSettings
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.SchemaSettings
+- fullName: google.cloud.pubsub_v1.types.SeekRequest
+  isExternal: false
+  name: SeekRequest
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.SeekRequest
+- fullName: google.cloud.pubsub_v1.types.SeekResponse
+  isExternal: false
+  name: SeekResponse
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.SeekResponse
+- fullName: google.cloud.pubsub_v1.types.ServiceDescriptorProto
+  isExternal: false
+  name: ServiceDescriptorProto
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.ServiceDescriptorProto
+- fullName: google.cloud.pubsub_v1.types.ServiceOptions
+  isExternal: false
+  name: ServiceOptions
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.ServiceOptions
+- fullName: google.cloud.pubsub_v1.types.SetIamPolicyRequest
+  isExternal: false
+  name: SetIamPolicyRequest
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.SetIamPolicyRequest
+- fullName: google.cloud.pubsub_v1.types.Snapshot
+  isExternal: false
+  name: Snapshot
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.Snapshot
+- fullName: google.cloud.pubsub_v1.types.SourceCodeInfo
+  isExternal: false
+  name: SourceCodeInfo
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.SourceCodeInfo
+- fullName: google.cloud.pubsub_v1.types.StreamingPullRequest
+  isExternal: false
+  name: StreamingPullRequest
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.StreamingPullRequest
+- fullName: google.cloud.pubsub_v1.types.StreamingPullResponse
+  isExternal: false
+  name: StreamingPullResponse
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.StreamingPullResponse
+- fullName: google.cloud.pubsub_v1.types.Subscription
+  isExternal: false
+  name: Subscription
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.Subscription
+- fullName: google.cloud.pubsub_v1.types.TestIamPermissionsRequest
+  isExternal: false
+  name: TestIamPermissionsRequest
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.TestIamPermissionsRequest
+- fullName: google.cloud.pubsub_v1.types.TestIamPermissionsResponse
+  isExternal: false
+  name: TestIamPermissionsResponse
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.TestIamPermissionsResponse
+- fullName: google.cloud.pubsub_v1.types.Timestamp
+  isExternal: false
+  name: Timestamp
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.Timestamp
+- fullName: google.cloud.pubsub_v1.types.Topic
+  isExternal: false
+  name: Topic
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.Topic
+- fullName: google.cloud.pubsub_v1.types.UninterpretedOption
+  isExternal: false
+  name: UninterpretedOption
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.UninterpretedOption
+- fullName: google.cloud.pubsub_v1.types.UpdateSnapshotRequest
+  isExternal: false
+  name: UpdateSnapshotRequest
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.UpdateSnapshotRequest
+- fullName: google.cloud.pubsub_v1.types.UpdateSubscriptionRequest
+  isExternal: false
+  name: UpdateSubscriptionRequest
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.UpdateSubscriptionRequest
+- fullName: google.cloud.pubsub_v1.types.UpdateTopicRequest
+  isExternal: false
+  name: UpdateTopicRequest
+  parent: google.cloud.pubsub_v1.types
+  uid: google.cloud.pubsub_v1.types.UpdateTopicRequest
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.publisher.pagers.ListTopicSnapshotsAsyncPager.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.publisher.pagers.ListTopicSnapshotsAsyncPager.yml
new file mode 100644
index 000000000000..d64310aa11c6
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.publisher.pagers.ListTopicSnapshotsAsyncPager.yml
@@ -0,0 +1,108 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes: []
+  children:
+  - google.pubsub_v1.services.publisher.pagers.ListTopicSnapshotsAsyncPager
+  class: google.pubsub_v1.services.publisher.pagers.ListTopicSnapshotsAsyncPager
+  fullName: google.pubsub_v1.services.publisher.pagers.ListTopicSnapshotsAsyncPager
+  inheritance:
+  - type: builtins.object
+  langs:
+  - python
+  module: google.pubsub_v1.services.publisher.pagers
+  name: ListTopicSnapshotsAsyncPager
+  source:
+    id: ListTopicSnapshotsAsyncPager
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/pagers.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/pagers.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 348
+  summary: 'A pager for iterating through `list_topic_snapshots` requests.
+
+
+    This class thinly wraps an initial
+
+    `google.pubsub_v1.types.ListTopicSnapshotsResponse` object, and
+
+    provides an `__aiter__` method to iterate through its
+
+    `snapshots` field.
+
+
+    If there are more pages, the `__aiter__` method will make additional
+
+    `ListTopicSnapshots` requests and continue to iterate
+
+    through the `snapshots` field on the
+
+    corresponding responses.
+
+
+    All the usual `google.pubsub_v1.types.ListTopicSnapshotsResponse`
+
+    attributes are available on the pager. If multiple requests are made, only
+
+    the most recent response is retained, and thus used for attribute lookup.
+
+
+    '
+  syntax:
+    content: "ListTopicSnapshotsAsyncPager(\n    method: typing.Callable[\n      \
+      \  [...], typing.Awaitable[google.cloud.pubsub_v1.types.ListTopicSnapshotsResponse]\n\
+      \    ],\n    request: google.cloud.pubsub_v1.types.ListTopicSnapshotsRequest,\n\
+      \    response: google.cloud.pubsub_v1.types.ListTopicSnapshotsResponse,\n  \
+      \  *,\n    metadata: typing.Sequence[typing.Tuple[str, str]] = ()\n)"
+    parameters: []
+  type: class
+  uid: google.pubsub_v1.services.publisher.pagers.ListTopicSnapshotsAsyncPager
+- attributes: []
+  class: google.pubsub_v1.services.publisher.pagers.ListTopicSnapshotsAsyncPager
+  fullName: google.pubsub_v1.services.publisher.pagers.ListTopicSnapshotsAsyncPager
+  inheritance:
+  - type: builtins.object
+  langs:
+  - python
+  module: google.pubsub_v1.services.publisher.pagers
+  name: ListTopicSnapshotsAsyncPager
+  source:
+    id: ListTopicSnapshotsAsyncPager
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/pagers.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/pagers.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 348
+  summary: 'Instantiates the pager.
+
+    '
+  syntax:
+    content: "ListTopicSnapshotsAsyncPager(\n    method: typing.Callable[\n      \
+      \  [...], typing.Awaitable[google.cloud.pubsub_v1.types.ListTopicSnapshotsResponse]\n\
+      \    ],\n    request: google.cloud.pubsub_v1.types.ListTopicSnapshotsRequest,\n\
+      \    response: google.cloud.pubsub_v1.types.ListTopicSnapshotsResponse,\n  \
+      \  *,\n    metadata: typing.Sequence[typing.Tuple[str, str]] = ()\n)"
+    parameters:
+    - description: The method that was originally called, and which instantiated this
+        pager.
+      id: method
+      var_type: Callable
+    - description: The initial request object.
+      id: request
+      var_type: google.pubsub_v1.types.ListTopicSnapshotsRequest
+    - description: The initial response object.
+      id: response
+      var_type: google.pubsub_v1.types.ListTopicSnapshotsResponse
+    - description: Strings which should be sent along with the request as metadata.
+      id: metadata
+      var_type: Sequence[Tuple[str, str]]
+  type: method
+  uid: google.pubsub_v1.services.publisher.pagers.ListTopicSnapshotsAsyncPager
+references:
+- fullName: google.pubsub_v1.services.publisher.pagers.ListTopicSnapshotsAsyncPager
+  isExternal: false
+  name: ListTopicSnapshotsAsyncPager
+  parent: google.pubsub_v1.services.publisher.pagers.ListTopicSnapshotsAsyncPager
+  uid: google.pubsub_v1.services.publisher.pagers.ListTopicSnapshotsAsyncPager
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.publisher.pagers.ListTopicSnapshotsPager.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.publisher.pagers.ListTopicSnapshotsPager.yml
new file mode 100644
index 000000000000..232e8708fe3b
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.publisher.pagers.ListTopicSnapshotsPager.yml
@@ -0,0 +1,106 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes: []
+  children:
+  - google.pubsub_v1.services.publisher.pagers.ListTopicSnapshotsPager
+  class: google.pubsub_v1.services.publisher.pagers.ListTopicSnapshotsPager
+  fullName: google.pubsub_v1.services.publisher.pagers.ListTopicSnapshotsPager
+  inheritance:
+  - type: builtins.object
+  langs:
+  - python
+  module: google.pubsub_v1.services.publisher.pagers
+  name: ListTopicSnapshotsPager
+  source:
+    id: ListTopicSnapshotsPager
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/pagers.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/pagers.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 286
+  summary: 'A pager for iterating through `list_topic_snapshots` requests.
+
+
+    This class thinly wraps an initial
+
+    `google.pubsub_v1.types.ListTopicSnapshotsResponse` object, and
+
+    provides an `__iter__` method to iterate through its
+
+    `snapshots` field.
+
+
+    If there are more pages, the `__iter__` method will make additional
+
+    `ListTopicSnapshots` requests and continue to iterate
+
+    through the `snapshots` field on the
+
+    corresponding responses.
+
+
+    All the usual `google.pubsub_v1.types.ListTopicSnapshotsResponse`
+
+    attributes are available on the pager. If multiple requests are made, only
+
+    the most recent response is retained, and thus used for attribute lookup.
+
+
+    '
+  syntax:
+    content: "ListTopicSnapshotsPager(\n    method: typing.Callable[\n        [...],\
+      \ google.cloud.pubsub_v1.types.ListTopicSnapshotsResponse\n    ],\n    request:\
+      \ google.cloud.pubsub_v1.types.ListTopicSnapshotsRequest,\n    response: google.cloud.pubsub_v1.types.ListTopicSnapshotsResponse,\n\
+      \    *,\n    metadata: typing.Sequence[typing.Tuple[str, str]] = ()\n)"
+    parameters: []
+  type: class
+  uid: google.pubsub_v1.services.publisher.pagers.ListTopicSnapshotsPager
+- attributes: []
+  class: google.pubsub_v1.services.publisher.pagers.ListTopicSnapshotsPager
+  fullName: google.pubsub_v1.services.publisher.pagers.ListTopicSnapshotsPager
+  inheritance:
+  - type: builtins.object
+  langs:
+  - python
+  module: google.pubsub_v1.services.publisher.pagers
+  name: ListTopicSnapshotsPager
+  source:
+    id: ListTopicSnapshotsPager
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/pagers.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/pagers.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 286
+  summary: 'Instantiate the pager.
+
+    '
+  syntax:
+    content: "ListTopicSnapshotsPager(\n    method: typing.Callable[\n        [...],\
+      \ google.cloud.pubsub_v1.types.ListTopicSnapshotsResponse\n    ],\n    request:\
+      \ google.cloud.pubsub_v1.types.ListTopicSnapshotsRequest,\n    response: google.cloud.pubsub_v1.types.ListTopicSnapshotsResponse,\n\
+      \    *,\n    metadata: typing.Sequence[typing.Tuple[str, str]] = ()\n)"
+    parameters:
+    - description: The method that was originally called, and which instantiated this
+        pager.
+      id: method
+      var_type: Callable
+    - description: The initial request object.
+      id: request
+      var_type: google.pubsub_v1.types.ListTopicSnapshotsRequest
+    - description: The initial response object.
+      id: response
+      var_type: google.pubsub_v1.types.ListTopicSnapshotsResponse
+    - description: Strings which should be sent along with the request as metadata.
+      id: metadata
+      var_type: Sequence[Tuple[str, str]]
+  type: method
+  uid: google.pubsub_v1.services.publisher.pagers.ListTopicSnapshotsPager
+references:
+- fullName: google.pubsub_v1.services.publisher.pagers.ListTopicSnapshotsPager
+  isExternal: false
+  name: ListTopicSnapshotsPager
+  parent: google.pubsub_v1.services.publisher.pagers.ListTopicSnapshotsPager
+  uid: google.pubsub_v1.services.publisher.pagers.ListTopicSnapshotsPager
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.publisher.pagers.ListTopicSubscriptionsAsyncPager.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.publisher.pagers.ListTopicSubscriptionsAsyncPager.yml
new file mode 100644
index 000000000000..2fafe23978cf
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.publisher.pagers.ListTopicSubscriptionsAsyncPager.yml
@@ -0,0 +1,108 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes: []
+  children:
+  - google.pubsub_v1.services.publisher.pagers.ListTopicSubscriptionsAsyncPager
+  class: google.pubsub_v1.services.publisher.pagers.ListTopicSubscriptionsAsyncPager
+  fullName: google.pubsub_v1.services.publisher.pagers.ListTopicSubscriptionsAsyncPager
+  inheritance:
+  - type: builtins.object
+  langs:
+  - python
+  module: google.pubsub_v1.services.publisher.pagers
+  name: ListTopicSubscriptionsAsyncPager
+  source:
+    id: ListTopicSubscriptionsAsyncPager
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/pagers.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/pagers.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 220
+  summary: 'A pager for iterating through `list_topic_subscriptions` requests.
+
+
+    This class thinly wraps an initial
+
+    `google.pubsub_v1.types.ListTopicSubscriptionsResponse` object, and
+
+    provides an `__aiter__` method to iterate through its
+
+    `subscriptions` field.
+
+
+    If there are more pages, the `__aiter__` method will make additional
+
+    `ListTopicSubscriptions` requests and continue to iterate
+
+    through the `subscriptions` field on the
+
+    corresponding responses.
+
+
+    All the usual `google.pubsub_v1.types.ListTopicSubscriptionsResponse`
+
+    attributes are available on the pager. If multiple requests are made, only
+
+    the most recent response is retained, and thus used for attribute lookup.
+
+
+    '
+  syntax:
+    content: "ListTopicSubscriptionsAsyncPager(\n    method: typing.Callable[\n  \
+      \      [...],\n        typing.Awaitable[google.cloud.pubsub_v1.types.ListTopicSubscriptionsResponse],\n\
+      \    ],\n    request: google.cloud.pubsub_v1.types.ListTopicSubscriptionsRequest,\n\
+      \    response: google.cloud.pubsub_v1.types.ListTopicSubscriptionsResponse,\n\
+      \    *,\n    metadata: typing.Sequence[typing.Tuple[str, str]] = ()\n)"
+    parameters: []
+  type: class
+  uid: google.pubsub_v1.services.publisher.pagers.ListTopicSubscriptionsAsyncPager
+- attributes: []
+  class: google.pubsub_v1.services.publisher.pagers.ListTopicSubscriptionsAsyncPager
+  fullName: google.pubsub_v1.services.publisher.pagers.ListTopicSubscriptionsAsyncPager
+  inheritance:
+  - type: builtins.object
+  langs:
+  - python
+  module: google.pubsub_v1.services.publisher.pagers
+  name: ListTopicSubscriptionsAsyncPager
+  source:
+    id: ListTopicSubscriptionsAsyncPager
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/pagers.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/pagers.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 220
+  summary: 'Instantiates the pager.
+
+    '
+  syntax:
+    content: "ListTopicSubscriptionsAsyncPager(\n    method: typing.Callable[\n  \
+      \      [...],\n        typing.Awaitable[google.cloud.pubsub_v1.types.ListTopicSubscriptionsResponse],\n\
+      \    ],\n    request: google.cloud.pubsub_v1.types.ListTopicSubscriptionsRequest,\n\
+      \    response: google.cloud.pubsub_v1.types.ListTopicSubscriptionsResponse,\n\
+      \    *,\n    metadata: typing.Sequence[typing.Tuple[str, str]] = ()\n)"
+    parameters:
+    - description: The method that was originally called, and which instantiated this
+        pager.
+      id: method
+      var_type: Callable
+    - description: The initial request object.
+      id: request
+      var_type: google.pubsub_v1.types.ListTopicSubscriptionsRequest
+    - description: The initial response object.
+      id: response
+      var_type: google.pubsub_v1.types.ListTopicSubscriptionsResponse
+    - description: Strings which should be sent along with the request as metadata.
+      id: metadata
+      var_type: Sequence[Tuple[str, str]]
+  type: method
+  uid: google.pubsub_v1.services.publisher.pagers.ListTopicSubscriptionsAsyncPager
+references:
+- fullName: google.pubsub_v1.services.publisher.pagers.ListTopicSubscriptionsAsyncPager
+  isExternal: false
+  name: ListTopicSubscriptionsAsyncPager
+  parent: google.pubsub_v1.services.publisher.pagers.ListTopicSubscriptionsAsyncPager
+  uid: google.pubsub_v1.services.publisher.pagers.ListTopicSubscriptionsAsyncPager
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.publisher.pagers.ListTopicSubscriptionsPager.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.publisher.pagers.ListTopicSubscriptionsPager.yml
new file mode 100644
index 000000000000..12ef825789c4
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.publisher.pagers.ListTopicSubscriptionsPager.yml
@@ -0,0 +1,108 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes: []
+  children:
+  - google.pubsub_v1.services.publisher.pagers.ListTopicSubscriptionsPager
+  class: google.pubsub_v1.services.publisher.pagers.ListTopicSubscriptionsPager
+  fullName: google.pubsub_v1.services.publisher.pagers.ListTopicSubscriptionsPager
+  inheritance:
+  - type: builtins.object
+  langs:
+  - python
+  module: google.pubsub_v1.services.publisher.pagers
+  name: ListTopicSubscriptionsPager
+  source:
+    id: ListTopicSubscriptionsPager
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/pagers.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/pagers.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 158
+  summary: 'A pager for iterating through `list_topic_subscriptions` requests.
+
+
+    This class thinly wraps an initial
+
+    `google.pubsub_v1.types.ListTopicSubscriptionsResponse` object, and
+
+    provides an `__iter__` method to iterate through its
+
+    `subscriptions` field.
+
+
+    If there are more pages, the `__iter__` method will make additional
+
+    `ListTopicSubscriptions` requests and continue to iterate
+
+    through the `subscriptions` field on the
+
+    corresponding responses.
+
+
+    All the usual `google.pubsub_v1.types.ListTopicSubscriptionsResponse`
+
+    attributes are available on the pager. If multiple requests are made, only
+
+    the most recent response is retained, and thus used for attribute lookup.
+
+
+    '
+  syntax:
+    content: "ListTopicSubscriptionsPager(\n    method: typing.Callable[\n       \
+      \ [...], google.cloud.pubsub_v1.types.ListTopicSubscriptionsResponse\n    ],\n\
+      \    request: google.cloud.pubsub_v1.types.ListTopicSubscriptionsRequest,\n\
+      \    response: google.cloud.pubsub_v1.types.ListTopicSubscriptionsResponse,\n\
+      \    *,\n    metadata: typing.Sequence[typing.Tuple[str, str]] = ()\n)"
+    parameters: []
+  type: class
+  uid: google.pubsub_v1.services.publisher.pagers.ListTopicSubscriptionsPager
+- attributes: []
+  class: google.pubsub_v1.services.publisher.pagers.ListTopicSubscriptionsPager
+  fullName: google.pubsub_v1.services.publisher.pagers.ListTopicSubscriptionsPager
+  inheritance:
+  - type: builtins.object
+  langs:
+  - python
+  module: google.pubsub_v1.services.publisher.pagers
+  name: ListTopicSubscriptionsPager
+  source:
+    id: ListTopicSubscriptionsPager
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/pagers.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/pagers.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 158
+  summary: 'Instantiate the pager.
+
+    '
+  syntax:
+    content: "ListTopicSubscriptionsPager(\n    method: typing.Callable[\n       \
+      \ [...], google.cloud.pubsub_v1.types.ListTopicSubscriptionsResponse\n    ],\n\
+      \    request: google.cloud.pubsub_v1.types.ListTopicSubscriptionsRequest,\n\
+      \    response: google.cloud.pubsub_v1.types.ListTopicSubscriptionsResponse,\n\
+      \    *,\n    metadata: typing.Sequence[typing.Tuple[str, str]] = ()\n)"
+    parameters:
+    - description: The method that was originally called, and which instantiated this
+        pager.
+      id: method
+      var_type: Callable
+    - description: The initial request object.
+      id: request
+      var_type: google.pubsub_v1.types.ListTopicSubscriptionsRequest
+    - description: The initial response object.
+      id: response
+      var_type: google.pubsub_v1.types.ListTopicSubscriptionsResponse
+    - description: Strings which should be sent along with the request as metadata.
+      id: metadata
+      var_type: Sequence[Tuple[str, str]]
+  type: method
+  uid: google.pubsub_v1.services.publisher.pagers.ListTopicSubscriptionsPager
+references:
+- fullName: google.pubsub_v1.services.publisher.pagers.ListTopicSubscriptionsPager
+  isExternal: false
+  name: ListTopicSubscriptionsPager
+  parent: google.pubsub_v1.services.publisher.pagers.ListTopicSubscriptionsPager
+  uid: google.pubsub_v1.services.publisher.pagers.ListTopicSubscriptionsPager
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.publisher.pagers.ListTopicsAsyncPager.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.publisher.pagers.ListTopicsAsyncPager.yml
new file mode 100644
index 000000000000..c3497a5adb0b
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.publisher.pagers.ListTopicsAsyncPager.yml
@@ -0,0 +1,108 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes: []
+  children:
+  - google.pubsub_v1.services.publisher.pagers.ListTopicsAsyncPager
+  class: google.pubsub_v1.services.publisher.pagers.ListTopicsAsyncPager
+  fullName: google.pubsub_v1.services.publisher.pagers.ListTopicsAsyncPager
+  inheritance:
+  - type: builtins.object
+  langs:
+  - python
+  module: google.pubsub_v1.services.publisher.pagers
+  name: ListTopicsAsyncPager
+  source:
+    id: ListTopicsAsyncPager
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/pagers.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/pagers.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 92
+  summary: 'A pager for iterating through `list_topics` requests.
+
+
+    This class thinly wraps an initial
+
+    `google.pubsub_v1.types.ListTopicsResponse` object, and
+
+    provides an `__aiter__` method to iterate through its
+
+    `topics` field.
+
+
+    If there are more pages, the `__aiter__` method will make additional
+
+    `ListTopics` requests and continue to iterate
+
+    through the `topics` field on the
+
+    corresponding responses.
+
+
+    All the usual `google.pubsub_v1.types.ListTopicsResponse`
+
+    attributes are available on the pager. If multiple requests are made, only
+
+    the most recent response is retained, and thus used for attribute lookup.
+
+
+    '
+  syntax:
+    content: "ListTopicsAsyncPager(\n    method: typing.Callable[\n        [...],\
+      \ typing.Awaitable[google.cloud.pubsub_v1.types.ListTopicsResponse]\n    ],\n\
+      \    request: google.cloud.pubsub_v1.types.ListTopicsRequest,\n    response:\
+      \ google.cloud.pubsub_v1.types.ListTopicsResponse,\n    *,\n    metadata: typing.Sequence[typing.Tuple[str,\
+      \ str]] = ()\n)"
+    parameters: []
+  type: class
+  uid: google.pubsub_v1.services.publisher.pagers.ListTopicsAsyncPager
+- attributes: []
+  class: google.pubsub_v1.services.publisher.pagers.ListTopicsAsyncPager
+  fullName: google.pubsub_v1.services.publisher.pagers.ListTopicsAsyncPager
+  inheritance:
+  - type: builtins.object
+  langs:
+  - python
+  module: google.pubsub_v1.services.publisher.pagers
+  name: ListTopicsAsyncPager
+  source:
+    id: ListTopicsAsyncPager
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/pagers.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/pagers.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 92
+  summary: 'Instantiates the pager.
+
+    '
+  syntax:
+    content: "ListTopicsAsyncPager(\n    method: typing.Callable[\n        [...],\
+      \ typing.Awaitable[google.cloud.pubsub_v1.types.ListTopicsResponse]\n    ],\n\
+      \    request: google.cloud.pubsub_v1.types.ListTopicsRequest,\n    response:\
+      \ google.cloud.pubsub_v1.types.ListTopicsResponse,\n    *,\n    metadata: typing.Sequence[typing.Tuple[str,\
+      \ str]] = ()\n)"
+    parameters:
+    - description: The method that was originally called, and which instantiated this
+        pager.
+      id: method
+      var_type: Callable
+    - description: The initial request object.
+      id: request
+      var_type: google.pubsub_v1.types.ListTopicsRequest
+    - description: The initial response object.
+      id: response
+      var_type: google.pubsub_v1.types.ListTopicsResponse
+    - description: Strings which should be sent along with the request as metadata.
+      id: metadata
+      var_type: Sequence[Tuple[str, str]]
+  type: method
+  uid: google.pubsub_v1.services.publisher.pagers.ListTopicsAsyncPager
+references:
+- fullName: google.pubsub_v1.services.publisher.pagers.ListTopicsAsyncPager
+  isExternal: false
+  name: ListTopicsAsyncPager
+  parent: google.pubsub_v1.services.publisher.pagers.ListTopicsAsyncPager
+  uid: google.pubsub_v1.services.publisher.pagers.ListTopicsAsyncPager
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.publisher.pagers.ListTopicsPager.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.publisher.pagers.ListTopicsPager.yml
new file mode 100644
index 000000000000..feeb09ce6d1f
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.publisher.pagers.ListTopicsPager.yml
@@ -0,0 +1,106 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes: []
+  children:
+  - google.pubsub_v1.services.publisher.pagers.ListTopicsPager
+  class: google.pubsub_v1.services.publisher.pagers.ListTopicsPager
+  fullName: google.pubsub_v1.services.publisher.pagers.ListTopicsPager
+  inheritance:
+  - type: builtins.object
+  langs:
+  - python
+  module: google.pubsub_v1.services.publisher.pagers
+  name: ListTopicsPager
+  source:
+    id: ListTopicsPager
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/pagers.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/pagers.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 30
+  summary: 'A pager for iterating through `list_topics` requests.
+
+
+    This class thinly wraps an initial
+
+    `google.pubsub_v1.types.ListTopicsResponse` object, and
+
+    provides an `__iter__` method to iterate through its
+
+    `topics` field.
+
+
+    If there are more pages, the `__iter__` method will make additional
+
+    `ListTopics` requests and continue to iterate
+
+    through the `topics` field on the
+
+    corresponding responses.
+
+
+    All the usual `google.pubsub_v1.types.ListTopicsResponse`
+
+    attributes are available on the pager. If multiple requests are made, only
+
+    the most recent response is retained, and thus used for attribute lookup.
+
+
+    '
+  syntax:
+    content: "ListTopicsPager(\n    method: typing.Callable[[...], google.cloud.pubsub_v1.types.ListTopicsResponse],\n\
+      \    request: google.cloud.pubsub_v1.types.ListTopicsRequest,\n    response:\
+      \ google.cloud.pubsub_v1.types.ListTopicsResponse,\n    *,\n    metadata: typing.Sequence[typing.Tuple[str,\
+      \ str]] = ()\n)"
+    parameters: []
+  type: class
+  uid: google.pubsub_v1.services.publisher.pagers.ListTopicsPager
+- attributes: []
+  class: google.pubsub_v1.services.publisher.pagers.ListTopicsPager
+  fullName: google.pubsub_v1.services.publisher.pagers.ListTopicsPager
+  inheritance:
+  - type: builtins.object
+  langs:
+  - python
+  module: google.pubsub_v1.services.publisher.pagers
+  name: ListTopicsPager
+  source:
+    id: ListTopicsPager
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/pagers.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/pagers.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 30
+  summary: 'Instantiate the pager.
+
+    '
+  syntax:
+    content: "ListTopicsPager(\n    method: typing.Callable[[...], google.cloud.pubsub_v1.types.ListTopicsResponse],\n\
+      \    request: google.cloud.pubsub_v1.types.ListTopicsRequest,\n    response:\
+      \ google.cloud.pubsub_v1.types.ListTopicsResponse,\n    *,\n    metadata: typing.Sequence[typing.Tuple[str,\
+      \ str]] = ()\n)"
+    parameters:
+    - description: The method that was originally called, and which instantiated this
+        pager.
+      id: method
+      var_type: Callable
+    - description: The initial request object.
+      id: request
+      var_type: google.pubsub_v1.types.ListTopicsRequest
+    - description: The initial response object.
+      id: response
+      var_type: google.pubsub_v1.types.ListTopicsResponse
+    - description: Strings which should be sent along with the request as metadata.
+      id: metadata
+      var_type: Sequence[Tuple[str, str]]
+  type: method
+  uid: google.pubsub_v1.services.publisher.pagers.ListTopicsPager
+references:
+- fullName: google.pubsub_v1.services.publisher.pagers.ListTopicsPager
+  isExternal: false
+  name: ListTopicsPager
+  parent: google.pubsub_v1.services.publisher.pagers.ListTopicsPager
+  uid: google.pubsub_v1.services.publisher.pagers.ListTopicsPager
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.publisher.pagers.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.publisher.pagers.yml
new file mode 100644
index 000000000000..410278908e37
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.publisher.pagers.yml
@@ -0,0 +1,58 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- children:
+  - google.pubsub_v1.services.publisher.pagers.ListTopicSnapshotsAsyncPager
+  - google.pubsub_v1.services.publisher.pagers.ListTopicSnapshotsPager
+  - google.pubsub_v1.services.publisher.pagers.ListTopicSubscriptionsAsyncPager
+  - google.pubsub_v1.services.publisher.pagers.ListTopicSubscriptionsPager
+  - google.pubsub_v1.services.publisher.pagers.ListTopicsAsyncPager
+  - google.pubsub_v1.services.publisher.pagers.ListTopicsPager
+  fullName: google.pubsub_v1.services.publisher.pagers
+  langs:
+  - python
+  module: google.pubsub_v1.services.publisher.pagers
+  name: publisher.pagers
+  source:
+    id: pagers
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/pagers.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/pagers.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 0
+  summary: API documentation for `pubsub_v1.services.publisher.pagers` module.
+  syntax: {}
+  type: module
+  uid: google.pubsub_v1.services.publisher.pagers
+references:
+- fullName: google.pubsub_v1.services.publisher.pagers.ListTopicSnapshotsAsyncPager
+  isExternal: false
+  name: ListTopicSnapshotsAsyncPager
+  parent: google.pubsub_v1.services.publisher.pagers
+  uid: google.pubsub_v1.services.publisher.pagers.ListTopicSnapshotsAsyncPager
+- fullName: google.pubsub_v1.services.publisher.pagers.ListTopicSnapshotsPager
+  isExternal: false
+  name: ListTopicSnapshotsPager
+  parent: google.pubsub_v1.services.publisher.pagers
+  uid: google.pubsub_v1.services.publisher.pagers.ListTopicSnapshotsPager
+- fullName: google.pubsub_v1.services.publisher.pagers.ListTopicSubscriptionsAsyncPager
+  isExternal: false
+  name: ListTopicSubscriptionsAsyncPager
+  parent: google.pubsub_v1.services.publisher.pagers
+  uid: google.pubsub_v1.services.publisher.pagers.ListTopicSubscriptionsAsyncPager
+- fullName: google.pubsub_v1.services.publisher.pagers.ListTopicSubscriptionsPager
+  isExternal: false
+  name: ListTopicSubscriptionsPager
+  parent: google.pubsub_v1.services.publisher.pagers
+  uid: google.pubsub_v1.services.publisher.pagers.ListTopicSubscriptionsPager
+- fullName: google.pubsub_v1.services.publisher.pagers.ListTopicsAsyncPager
+  isExternal: false
+  name: ListTopicsAsyncPager
+  parent: google.pubsub_v1.services.publisher.pagers
+  uid: google.pubsub_v1.services.publisher.pagers.ListTopicsAsyncPager
+- fullName: google.pubsub_v1.services.publisher.pagers.ListTopicsPager
+  isExternal: false
+  name: ListTopicsPager
+  parent: google.pubsub_v1.services.publisher.pagers
+  uid: google.pubsub_v1.services.publisher.pagers.ListTopicsPager
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.subscriber.pagers.ListSnapshotsAsyncPager.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.subscriber.pagers.ListSnapshotsAsyncPager.yml
new file mode 100644
index 000000000000..85ee86112464
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.subscriber.pagers.ListSnapshotsAsyncPager.yml
@@ -0,0 +1,108 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes: []
+  children:
+  - google.pubsub_v1.services.subscriber.pagers.ListSnapshotsAsyncPager
+  class: google.pubsub_v1.services.subscriber.pagers.ListSnapshotsAsyncPager
+  fullName: google.pubsub_v1.services.subscriber.pagers.ListSnapshotsAsyncPager
+  inheritance:
+  - type: builtins.object
+  langs:
+  - python
+  module: google.pubsub_v1.services.subscriber.pagers
+  name: ListSnapshotsAsyncPager
+  source:
+    id: ListSnapshotsAsyncPager
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/pagers.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/pagers.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 220
+  summary: 'A pager for iterating through `list_snapshots` requests.
+
+
+    This class thinly wraps an initial
+
+    `google.pubsub_v1.types.ListSnapshotsResponse` object, and
+
+    provides an `__aiter__` method to iterate through its
+
+    `snapshots` field.
+
+
+    If there are more pages, the `__aiter__` method will make additional
+
+    `ListSnapshots` requests and continue to iterate
+
+    through the `snapshots` field on the
+
+    corresponding responses.
+
+
+    All the usual `google.pubsub_v1.types.ListSnapshotsResponse`
+
+    attributes are available on the pager. If multiple requests are made, only
+
+    the most recent response is retained, and thus used for attribute lookup.
+
+
+    '
+  syntax:
+    content: "ListSnapshotsAsyncPager(\n    method: typing.Callable[\n        [...],\
+      \ typing.Awaitable[google.cloud.pubsub_v1.types.ListSnapshotsResponse]\n   \
+      \ ],\n    request: google.cloud.pubsub_v1.types.ListSnapshotsRequest,\n    response:\
+      \ google.cloud.pubsub_v1.types.ListSnapshotsResponse,\n    *,\n    metadata:\
+      \ typing.Sequence[typing.Tuple[str, str]] = ()\n)"
+    parameters: []
+  type: class
+  uid: google.pubsub_v1.services.subscriber.pagers.ListSnapshotsAsyncPager
+- attributes: []
+  class: google.pubsub_v1.services.subscriber.pagers.ListSnapshotsAsyncPager
+  fullName: google.pubsub_v1.services.subscriber.pagers.ListSnapshotsAsyncPager
+  inheritance:
+  - type: builtins.object
+  langs:
+  - python
+  module: google.pubsub_v1.services.subscriber.pagers
+  name: ListSnapshotsAsyncPager
+  source:
+    id: ListSnapshotsAsyncPager
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/pagers.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/pagers.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 220
+  summary: 'Instantiates the pager.
+
+    '
+  syntax:
+    content: "ListSnapshotsAsyncPager(\n    method: typing.Callable[\n        [...],\
+      \ typing.Awaitable[google.cloud.pubsub_v1.types.ListSnapshotsResponse]\n   \
+      \ ],\n    request: google.cloud.pubsub_v1.types.ListSnapshotsRequest,\n    response:\
+      \ google.cloud.pubsub_v1.types.ListSnapshotsResponse,\n    *,\n    metadata:\
+      \ typing.Sequence[typing.Tuple[str, str]] = ()\n)"
+    parameters:
+    - description: The method that was originally called, and which instantiated this
+        pager.
+      id: method
+      var_type: Callable
+    - description: The initial request object.
+      id: request
+      var_type: google.pubsub_v1.types.ListSnapshotsRequest
+    - description: The initial response object.
+      id: response
+      var_type: google.pubsub_v1.types.ListSnapshotsResponse
+    - description: Strings which should be sent along with the request as metadata.
+      id: metadata
+      var_type: Sequence[Tuple[str, str]]
+  type: method
+  uid: google.pubsub_v1.services.subscriber.pagers.ListSnapshotsAsyncPager
+references:
+- fullName: google.pubsub_v1.services.subscriber.pagers.ListSnapshotsAsyncPager
+  isExternal: false
+  name: ListSnapshotsAsyncPager
+  parent: google.pubsub_v1.services.subscriber.pagers.ListSnapshotsAsyncPager
+  uid: google.pubsub_v1.services.subscriber.pagers.ListSnapshotsAsyncPager
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.subscriber.pagers.ListSnapshotsPager.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.subscriber.pagers.ListSnapshotsPager.yml
new file mode 100644
index 000000000000..5d5e251b2051
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.subscriber.pagers.ListSnapshotsPager.yml
@@ -0,0 +1,106 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes: []
+  children:
+  - google.pubsub_v1.services.subscriber.pagers.ListSnapshotsPager
+  class: google.pubsub_v1.services.subscriber.pagers.ListSnapshotsPager
+  fullName: google.pubsub_v1.services.subscriber.pagers.ListSnapshotsPager
+  inheritance:
+  - type: builtins.object
+  langs:
+  - python
+  module: google.pubsub_v1.services.subscriber.pagers
+  name: ListSnapshotsPager
+  source:
+    id: ListSnapshotsPager
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/pagers.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/pagers.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 158
+  summary: 'A pager for iterating through `list_snapshots` requests.
+
+
+    This class thinly wraps an initial
+
+    `google.pubsub_v1.types.ListSnapshotsResponse` object, and
+
+    provides an `__iter__` method to iterate through its
+
+    `snapshots` field.
+
+
+    If there are more pages, the `__iter__` method will make additional
+
+    `ListSnapshots` requests and continue to iterate
+
+    through the `snapshots` field on the
+
+    corresponding responses.
+
+
+    All the usual `google.pubsub_v1.types.ListSnapshotsResponse`
+
+    attributes are available on the pager. If multiple requests are made, only
+
+    the most recent response is retained, and thus used for attribute lookup.
+
+
+    '
+  syntax:
+    content: "ListSnapshotsPager(\n    method: typing.Callable[[...], google.cloud.pubsub_v1.types.ListSnapshotsResponse],\n\
+      \    request: google.cloud.pubsub_v1.types.ListSnapshotsRequest,\n    response:\
+      \ google.cloud.pubsub_v1.types.ListSnapshotsResponse,\n    *,\n    metadata:\
+      \ typing.Sequence[typing.Tuple[str, str]] = ()\n)"
+    parameters: []
+  type: class
+  uid: google.pubsub_v1.services.subscriber.pagers.ListSnapshotsPager
+- attributes: []
+  class: google.pubsub_v1.services.subscriber.pagers.ListSnapshotsPager
+  fullName: google.pubsub_v1.services.subscriber.pagers.ListSnapshotsPager
+  inheritance:
+  - type: builtins.object
+  langs:
+  - python
+  module: google.pubsub_v1.services.subscriber.pagers
+  name: ListSnapshotsPager
+  source:
+    id: ListSnapshotsPager
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/pagers.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/pagers.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 158
+  summary: 'Instantiate the pager.
+
+    '
+  syntax:
+    content: "ListSnapshotsPager(\n    method: typing.Callable[[...], google.cloud.pubsub_v1.types.ListSnapshotsResponse],\n\
+      \    request: google.cloud.pubsub_v1.types.ListSnapshotsRequest,\n    response:\
+      \ google.cloud.pubsub_v1.types.ListSnapshotsResponse,\n    *,\n    metadata:\
+      \ typing.Sequence[typing.Tuple[str, str]] = ()\n)"
+    parameters:
+    - description: The method that was originally called, and which instantiated this
+        pager.
+      id: method
+      var_type: Callable
+    - description: The initial request object.
+      id: request
+      var_type: google.pubsub_v1.types.ListSnapshotsRequest
+    - description: The initial response object.
+      id: response
+      var_type: google.pubsub_v1.types.ListSnapshotsResponse
+    - description: Strings which should be sent along with the request as metadata.
+      id: metadata
+      var_type: Sequence[Tuple[str, str]]
+  type: method
+  uid: google.pubsub_v1.services.subscriber.pagers.ListSnapshotsPager
+references:
+- fullName: google.pubsub_v1.services.subscriber.pagers.ListSnapshotsPager
+  isExternal: false
+  name: ListSnapshotsPager
+  parent: google.pubsub_v1.services.subscriber.pagers.ListSnapshotsPager
+  uid: google.pubsub_v1.services.subscriber.pagers.ListSnapshotsPager
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.subscriber.pagers.ListSubscriptionsAsyncPager.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.subscriber.pagers.ListSubscriptionsAsyncPager.yml
new file mode 100644
index 000000000000..bf079291a5bf
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.subscriber.pagers.ListSubscriptionsAsyncPager.yml
@@ -0,0 +1,108 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes: []
+  children:
+  - google.pubsub_v1.services.subscriber.pagers.ListSubscriptionsAsyncPager
+  class: google.pubsub_v1.services.subscriber.pagers.ListSubscriptionsAsyncPager
+  fullName: google.pubsub_v1.services.subscriber.pagers.ListSubscriptionsAsyncPager
+  inheritance:
+  - type: builtins.object
+  langs:
+  - python
+  module: google.pubsub_v1.services.subscriber.pagers
+  name: ListSubscriptionsAsyncPager
+  source:
+    id: ListSubscriptionsAsyncPager
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/pagers.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/pagers.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 92
+  summary: 'A pager for iterating through `list_subscriptions` requests.
+
+
+    This class thinly wraps an initial
+
+    `google.pubsub_v1.types.ListSubscriptionsResponse` object, and
+
+    provides an `__aiter__` method to iterate through its
+
+    `subscriptions` field.
+
+
+    If there are more pages, the `__aiter__` method will make additional
+
+    `ListSubscriptions` requests and continue to iterate
+
+    through the `subscriptions` field on the
+
+    corresponding responses.
+
+
+    All the usual `google.pubsub_v1.types.ListSubscriptionsResponse`
+
+    attributes are available on the pager. If multiple requests are made, only
+
+    the most recent response is retained, and thus used for attribute lookup.
+
+
+    '
+  syntax:
+    content: "ListSubscriptionsAsyncPager(\n    method: typing.Callable[\n       \
+      \ [...], typing.Awaitable[google.cloud.pubsub_v1.types.ListSubscriptionsResponse]\n\
+      \    ],\n    request: google.cloud.pubsub_v1.types.ListSubscriptionsRequest,\n\
+      \    response: google.cloud.pubsub_v1.types.ListSubscriptionsResponse,\n   \
+      \ *,\n    metadata: typing.Sequence[typing.Tuple[str, str]] = ()\n)"
+    parameters: []
+  type: class
+  uid: google.pubsub_v1.services.subscriber.pagers.ListSubscriptionsAsyncPager
+- attributes: []
+  class: google.pubsub_v1.services.subscriber.pagers.ListSubscriptionsAsyncPager
+  fullName: google.pubsub_v1.services.subscriber.pagers.ListSubscriptionsAsyncPager
+  inheritance:
+  - type: builtins.object
+  langs:
+  - python
+  module: google.pubsub_v1.services.subscriber.pagers
+  name: ListSubscriptionsAsyncPager
+  source:
+    id: ListSubscriptionsAsyncPager
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/pagers.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/pagers.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 92
+  summary: 'Instantiates the pager.
+
+    '
+  syntax:
+    content: "ListSubscriptionsAsyncPager(\n    method: typing.Callable[\n       \
+      \ [...], typing.Awaitable[google.cloud.pubsub_v1.types.ListSubscriptionsResponse]\n\
+      \    ],\n    request: google.cloud.pubsub_v1.types.ListSubscriptionsRequest,\n\
+      \    response: google.cloud.pubsub_v1.types.ListSubscriptionsResponse,\n   \
+      \ *,\n    metadata: typing.Sequence[typing.Tuple[str, str]] = ()\n)"
+    parameters:
+    - description: The method that was originally called, and which instantiated this
+        pager.
+      id: method
+      var_type: Callable
+    - description: The initial request object.
+      id: request
+      var_type: google.pubsub_v1.types.ListSubscriptionsRequest
+    - description: The initial response object.
+      id: response
+      var_type: google.pubsub_v1.types.ListSubscriptionsResponse
+    - description: Strings which should be sent along with the request as metadata.
+      id: metadata
+      var_type: Sequence[Tuple[str, str]]
+  type: method
+  uid: google.pubsub_v1.services.subscriber.pagers.ListSubscriptionsAsyncPager
+references:
+- fullName: google.pubsub_v1.services.subscriber.pagers.ListSubscriptionsAsyncPager
+  isExternal: false
+  name: ListSubscriptionsAsyncPager
+  parent: google.pubsub_v1.services.subscriber.pagers.ListSubscriptionsAsyncPager
+  uid: google.pubsub_v1.services.subscriber.pagers.ListSubscriptionsAsyncPager
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.subscriber.pagers.ListSubscriptionsPager.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.subscriber.pagers.ListSubscriptionsPager.yml
new file mode 100644
index 000000000000..7a0ac5aac1c7
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.subscriber.pagers.ListSubscriptionsPager.yml
@@ -0,0 +1,106 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes: []
+  children:
+  - google.pubsub_v1.services.subscriber.pagers.ListSubscriptionsPager
+  class: google.pubsub_v1.services.subscriber.pagers.ListSubscriptionsPager
+  fullName: google.pubsub_v1.services.subscriber.pagers.ListSubscriptionsPager
+  inheritance:
+  - type: builtins.object
+  langs:
+  - python
+  module: google.pubsub_v1.services.subscriber.pagers
+  name: ListSubscriptionsPager
+  source:
+    id: ListSubscriptionsPager
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/pagers.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/pagers.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 30
+  summary: 'A pager for iterating through `list_subscriptions` requests.
+
+
+    This class thinly wraps an initial
+
+    `google.pubsub_v1.types.ListSubscriptionsResponse` object, and
+
+    provides an `__iter__` method to iterate through its
+
+    `subscriptions` field.
+
+
+    If there are more pages, the `__iter__` method will make additional
+
+    `ListSubscriptions` requests and continue to iterate
+
+    through the `subscriptions` field on the
+
+    corresponding responses.
+
+
+    All the usual `google.pubsub_v1.types.ListSubscriptionsResponse`
+
+    attributes are available on the pager. If multiple requests are made, only
+
+    the most recent response is retained, and thus used for attribute lookup.
+
+
+    '
+  syntax:
+    content: "ListSubscriptionsPager(\n    method: typing.Callable[\n        [...],\
+      \ google.cloud.pubsub_v1.types.ListSubscriptionsResponse\n    ],\n    request:\
+      \ google.cloud.pubsub_v1.types.ListSubscriptionsRequest,\n    response: google.cloud.pubsub_v1.types.ListSubscriptionsResponse,\n\
+      \    *,\n    metadata: typing.Sequence[typing.Tuple[str, str]] = ()\n)"
+    parameters: []
+  type: class
+  uid: google.pubsub_v1.services.subscriber.pagers.ListSubscriptionsPager
+- attributes: []
+  class: google.pubsub_v1.services.subscriber.pagers.ListSubscriptionsPager
+  fullName: google.pubsub_v1.services.subscriber.pagers.ListSubscriptionsPager
+  inheritance:
+  - type: builtins.object
+  langs:
+  - python
+  module: google.pubsub_v1.services.subscriber.pagers
+  name: ListSubscriptionsPager
+  source:
+    id: ListSubscriptionsPager
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/pagers.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/pagers.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 30
+  summary: 'Instantiate the pager.
+
+    '
+  syntax:
+    content: "ListSubscriptionsPager(\n    method: typing.Callable[\n        [...],\
+      \ google.cloud.pubsub_v1.types.ListSubscriptionsResponse\n    ],\n    request:\
+      \ google.cloud.pubsub_v1.types.ListSubscriptionsRequest,\n    response: google.cloud.pubsub_v1.types.ListSubscriptionsResponse,\n\
+      \    *,\n    metadata: typing.Sequence[typing.Tuple[str, str]] = ()\n)"
+    parameters:
+    - description: The method that was originally called, and which instantiated this
+        pager.
+      id: method
+      var_type: Callable
+    - description: The initial request object.
+      id: request
+      var_type: google.pubsub_v1.types.ListSubscriptionsRequest
+    - description: The initial response object.
+      id: response
+      var_type: google.pubsub_v1.types.ListSubscriptionsResponse
+    - description: Strings which should be sent along with the request as metadata.
+      id: metadata
+      var_type: Sequence[Tuple[str, str]]
+  type: method
+  uid: google.pubsub_v1.services.subscriber.pagers.ListSubscriptionsPager
+references:
+- fullName: google.pubsub_v1.services.subscriber.pagers.ListSubscriptionsPager
+  isExternal: false
+  name: ListSubscriptionsPager
+  parent: google.pubsub_v1.services.subscriber.pagers.ListSubscriptionsPager
+  uid: google.pubsub_v1.services.subscriber.pagers.ListSubscriptionsPager
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.subscriber.pagers.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.subscriber.pagers.yml
new file mode 100644
index 000000000000..1ae17cc2ff25
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.pubsub_v1.services.subscriber.pagers.yml
@@ -0,0 +1,46 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- children:
+  - google.pubsub_v1.services.subscriber.pagers.ListSnapshotsAsyncPager
+  - google.pubsub_v1.services.subscriber.pagers.ListSnapshotsPager
+  - google.pubsub_v1.services.subscriber.pagers.ListSubscriptionsAsyncPager
+  - google.pubsub_v1.services.subscriber.pagers.ListSubscriptionsPager
+  fullName: google.pubsub_v1.services.subscriber.pagers
+  langs:
+  - python
+  module: google.pubsub_v1.services.subscriber.pagers
+  name: subscriber.pagers
+  source:
+    id: pagers
+    path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/pagers.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/gapic-combo/google/pubsub_v1/services/subscriber/pagers.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 0
+  summary: API documentation for `pubsub_v1.services.subscriber.pagers` module.
+  syntax: {}
+  type: module
+  uid: google.pubsub_v1.services.subscriber.pagers
+references:
+- fullName: google.pubsub_v1.services.subscriber.pagers.ListSnapshotsAsyncPager
+  isExternal: false
+  name: ListSnapshotsAsyncPager
+  parent: google.pubsub_v1.services.subscriber.pagers
+  uid: google.pubsub_v1.services.subscriber.pagers.ListSnapshotsAsyncPager
+- fullName: google.pubsub_v1.services.subscriber.pagers.ListSnapshotsPager
+  isExternal: false
+  name: ListSnapshotsPager
+  parent: google.pubsub_v1.services.subscriber.pagers
+  uid: google.pubsub_v1.services.subscriber.pagers.ListSnapshotsPager
+- fullName: google.pubsub_v1.services.subscriber.pagers.ListSubscriptionsAsyncPager
+  isExternal: false
+  name: ListSubscriptionsAsyncPager
+  parent: google.pubsub_v1.services.subscriber.pagers
+  uid: google.pubsub_v1.services.subscriber.pagers.ListSubscriptionsAsyncPager
+- fullName: google.pubsub_v1.services.subscriber.pagers.ListSubscriptionsPager
+  isExternal: false
+  name: ListSubscriptionsPager
+  parent: google.pubsub_v1.services.subscriber.pagers
+  uid: google.pubsub_v1.services.subscriber.pagers.ListSubscriptionsPager
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/index.md b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/index.md
new file mode 100644
index 000000000000..51b5509c7c61
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/index.md
@@ -0,0 +1,189 @@
+# Python Client for Google Cloud Pub / Sub
+
+[![image](https://img.shields.io/badge/support-GA-gold.svg)](https://github.com/googleapis/google-cloud-python/blob/main/README.rst#general-availability) [![image](https://img.shields.io/pypi/v/google-cloud-pubsub.svg)](https://pypi.org/project/google-cloud-pubsub/) [![image](https://img.shields.io/pypi/pyversions/google-cloud-pubsub.svg)](https://pypi.org/project/google-cloud-pubsub/)
+
+[Google Cloud Pub / Sub](https://cloud.google.com/pubsub/) is a fully-managed real-time messaging service that
+allows you to send and receive messages between independent applications. You
+can leverage Cloud Pub/Sub’s flexibility to decouple systems and components
+hosted on Google Cloud Platform or elsewhere on the Internet. By building on
+the same technology Google uses, Cloud Pub / Sub is designed to provide “at
+least once” delivery at low latency with on-demand scalability to 1 million
+messages per second (and beyond).
+
+Publisher applications can send messages to a `topic` and other applications
+can subscribe to that topic to receive the messages. By decoupling senders and
+receivers, Google Cloud Pub/Sub allows developers to communicate between
+independently written applications.
+
+
+* [Product Documentation](https://cloud.google.com/pubsub/docs)
+
+
+* [Client Library Documentation](https://cloud.google.com/python/docs/reference/pubsub/latest)
+
+## Quick Start
+
+In order to use this library, you first need to go through the following steps:
+
+
+1. [Select or create a Cloud Platform project.](https://console.cloud.google.com/project)
+
+
+2. [Enable billing for your project.](https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project)
+
+
+3. [Enable the Google Cloud Pub / Sub API.](https://cloud.google.com/pubsub)
+
+
+4. [Setup Authentication.](https://googleapis.dev/python/google-api-core/latest/auth.html)
+
+### Installation
+
+Install this library in a [virtualenv](https://virtualenv.pypa.io/en/latest/) using pip. [virtualenv](https://virtualenv.pypa.io/en/latest/) is a tool to
+create isolated Python environments. The basic problem it addresses is one of
+dependencies and versions, and indirectly permissions.
+
+With [virtualenv](https://virtualenv.pypa.io/en/latest/), it’s possible to install this library without needing system
+install permissions, and without clashing with the installed system
+dependencies.
+
+#### Supported Python Versions
+
+Python >= 3.7
+
+#### Deprecated Python Versions
+
+Python <= 3.6.
+
+The last version of this library compatible with Python 2.7 is google-cloud-pubsub==1.7.0.
+
+#### Mac/Linux
+
+```console
+pip install virtualenv
+virtualenv 
+source /bin/activate
+/bin/pip install google-cloud-pubsub
+```
+
+#### Windows
+
+```console
+pip install virtualenv
+virtualenv 
+\Scripts\activate
+\Scripts\pip.exe install google-cloud-pubsub
+```
+
+### Example Usage
+
+#### Publishing
+
+To publish data to Cloud Pub/Sub you must create a topic, and then publish
+messages to it
+
+```python
+import os
+from google.cloud import pubsub_v1
+
+publisher = pubsub_v1.PublisherClient()
+topic_name = 'projects/{project_id}/topics/{topic}'.format(
+    project_id=os.getenv('GOOGLE_CLOUD_PROJECT'),
+    topic='MY_TOPIC_NAME',  # Set this to something appropriate.
+)
+publisher.create_topic(name=topic_name)
+future = publisher.publish(topic_name, b'My first message!', spam='eggs')
+future.result()
+```
+
+To learn more, consult the [publishing documentation](https://cloud.google.com/python/docs/reference/pubsub/latest).
+
+#### Subscribing
+
+To subscribe to data in Cloud Pub/Sub, you create a subscription based on
+the topic, and subscribe to that, passing a callback function.
+
+```python
+import os
+from google.cloud import pubsub_v1
+
+topic_name = 'projects/{project_id}/topics/{topic}'.format(
+    project_id=os.getenv('GOOGLE_CLOUD_PROJECT'),
+    topic='MY_TOPIC_NAME',  # Set this to something appropriate.
+)
+
+subscription_name = 'projects/{project_id}/subscriptions/{sub}'.format(
+    project_id=os.getenv('GOOGLE_CLOUD_PROJECT'),
+    sub='MY_SUBSCRIPTION_NAME',  # Set this to something appropriate.
+)
+
+def callback(message):
+    print(message.data)
+    message.ack()
+
+with pubsub_v1.SubscriberClient() as subscriber:
+    subscriber.create_subscription(
+        name=subscription_name, topic=topic_name)
+    future = subscriber.subscribe(subscription_name, callback)
+```
+
+The future returned by the call to `subscriber.subscribe` can be used to
+block the current thread until a given condition obtains:
+
+```python
+try:
+    future.result()
+except KeyboardInterrupt:
+    future.cancel()
+```
+
+It is also possible to pull messages in a synchronous (blocking) fashion. To
+learn more about subscribing, consult the [subscriber documentation](https://cloud.google.com/python/docs/reference/pubsub/latest).
+
+#### Authentication
+
+It is possible to specify the authentication method to use with the Pub/Sub
+clients. This can be done by providing an explicit [Credentials](https://google-auth.readthedocs.io/en/latest/reference/google.auth.credentials.html#google.auth.credentials.Credentials) instance. Support
+for various authentication methods is available from the [google-auth](https://google-auth.readthedocs.io/en/latest/index.html) library.
+
+For example, to use JSON Web Tokens, provide a [google.auth.jwt.Credentials](https://google-auth.readthedocs.io/en/latest/reference/google.auth.jwt.html#google.auth.jwt.Credentials) instance:
+
+```python
+import json
+from google.auth import jwt
+
+service_account_info = json.load(open("service-account-info.json"))
+audience = "https://pubsub.googleapis.com/google.pubsub.v1.Subscriber"
+
+credentials = jwt.Credentials.from_service_account_info(
+    service_account_info, audience=audience
+)
+
+subscriber = pubsub_v1.SubscriberClient(credentials=credentials)
+
+# The same for the publisher, except that the "audience" claim needs to be adjusted
+publisher_audience = "https://pubsub.googleapis.com/google.pubsub.v1.Publisher"
+credentials_pub = credentials.with_claims(audience=publisher_audience)
+publisher = pubsub_v1.PublisherClient(credentials=credentials_pub)
+```
+
+## Versioning
+
+This library follows [Semantic Versioning](http://semver.org/).
+
+It is currently in major version one (1.y.z), which means that the public API should be considered stable.
+
+## Contributing
+
+Contributions to this library are always welcome and highly encouraged.
+
+See the [CONTRIBUTING doc](https://github.com/googleapis/google-cloud-python/blob/main/CONTRIBUTING.rst) for more information on how to get started.
+
+## Community
+
+Google Cloud Platform Python developers hang out in [Slack](https://googlecloud-community.slack.com) in the `#python`
+channel, click here to [get an invitation](https://gcp-slack.appspot.com/).
+
+## License
+
+Apache 2.0 - See [the LICENSE](https://github.com/googleapis/google-cloud-python/blob/main/LICENSE) for more information.
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/multiprocessing.md b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/multiprocessing.md
new file mode 100644
index 000000000000..ac442c0c7185
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/multiprocessing.md
@@ -0,0 +1,7 @@
+# Multiprocessing
+
+**NOTE**: Because this client uses [`grpc`](https://grpc.github.io/grpc/python/grpc.html#module-grpc) library, it is safe to
+share instances across threads. In multiprocessing scenarios, the best
+practice is to create client instances *after* the invocation of
+[`os.fork()`](https://python.readthedocs.io/en/latest/library/os.html#os.fork) by [`multiprocessing.pool.Pool`](https://python.readthedocs.io/en/latest/library/multiprocessing.html#multiprocessing.pool.Pool) or
+[`multiprocessing.Process`](https://python.readthedocs.io/en/latest/library/multiprocessing.html#multiprocessing.Process).
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/toc.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/toc.yml
new file mode 100644
index 000000000000..04885dc67266
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/toc.yml
@@ -0,0 +1,345 @@
+- items:
+  - href: index.md
+    name: Overview
+  - href: changelog.md
+    name: Changelog
+  - href: multiprocessing.md
+    name: Multiprocessing
+  - href: upgrading.md
+    name: 2.0.0 Migration Guide
+  - items:
+    - items:
+      - name: Overview
+        uid: google.cloud.pubsub_v1.publisher.client
+      - name: Client
+        uid: google.cloud.pubsub_v1.publisher.client.Client
+      name: publisher.client
+      uid: google.cloud.pubsub_v1.publisher.client
+    - items:
+      - name: Overview
+        uid: google.cloud.pubsub_v1.publisher.futures
+      - name: Future
+        uid: google.cloud.pubsub_v1.publisher.futures.Future
+      name: publisher.futures
+      uid: google.cloud.pubsub_v1.publisher.futures
+    - items:
+      - name: Overview
+        uid: google.cloud.pubsub_v1.subscriber.client
+      - name: Client
+        uid: google.cloud.pubsub_v1.subscriber.client.Client
+      name: subscriber.client
+      uid: google.cloud.pubsub_v1.subscriber.client
+    - items:
+      - name: Overview
+        uid: google.cloud.pubsub_v1.subscriber.futures
+      - name: Future
+        uid: google.cloud.pubsub_v1.subscriber.futures.Future
+      - name: StreamingPullFuture
+        uid: google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture
+      name: subscriber.futures
+      uid: google.cloud.pubsub_v1.subscriber.futures
+    - items:
+      - name: Overview
+        uid: google.cloud.pubsub_v1.subscriber.scheduler
+      - name: Scheduler
+        uid: google.cloud.pubsub_v1.subscriber.scheduler.Scheduler
+      - name: ThreadScheduler
+        uid: google.cloud.pubsub_v1.subscriber.scheduler.ThreadScheduler
+      name: scheduler
+      uid: google.cloud.pubsub_v1.subscriber.scheduler
+    - items:
+      - name: Overview
+        uid: google.cloud.pubsub_v1.types
+      - name: AcknowledgeRequest
+        uid: google.cloud.pubsub_v1.types.AcknowledgeRequest
+      - name: AuditConfig
+        uid: google.cloud.pubsub_v1.types.AuditConfig
+      - name: AuditConfigDelta
+        uid: google.cloud.pubsub_v1.types.AuditConfigDelta
+      - name: AuditData
+        uid: google.cloud.pubsub_v1.types.AuditData
+      - name: AuditLogConfig
+        uid: google.cloud.pubsub_v1.types.AuditLogConfig
+      - name: BatchSettings
+        uid: google.cloud.pubsub_v1.types.BatchSettings
+      - items:
+        - name: Overview
+          uid: google.cloud.pubsub_v1.types.BigQueryConfig
+        - name: State
+          uid: google.cloud.pubsub_v1.types.BigQueryConfig.State
+        name: BigQueryConfig
+        uid: google.cloud.pubsub_v1.types.BigQueryConfig
+      - name: Binding
+        uid: google.cloud.pubsub_v1.types.Binding
+      - name: BindingDelta
+        uid: google.cloud.pubsub_v1.types.BindingDelta
+      - items:
+        - name: Overview
+          uid: google.cloud.pubsub_v1.types.CreateSnapshotRequest
+        - name: LabelsEntry
+          uid: google.cloud.pubsub_v1.types.CreateSnapshotRequest.LabelsEntry
+        name: CreateSnapshotRequest
+        uid: google.cloud.pubsub_v1.types.CreateSnapshotRequest
+      - name: CustomHttpPattern
+        uid: google.cloud.pubsub_v1.types.CustomHttpPattern
+      - name: DeadLetterPolicy
+        uid: google.cloud.pubsub_v1.types.DeadLetterPolicy
+      - name: DeleteSnapshotRequest
+        uid: google.cloud.pubsub_v1.types.DeleteSnapshotRequest
+      - name: DeleteSubscriptionRequest
+        uid: google.cloud.pubsub_v1.types.DeleteSubscriptionRequest
+      - name: DeleteTopicRequest
+        uid: google.cloud.pubsub_v1.types.DeleteTopicRequest
+      - items:
+        - name: Overview
+          uid: google.cloud.pubsub_v1.types.DescriptorProto
+        - name: ExtensionRange
+          uid: google.cloud.pubsub_v1.types.DescriptorProto.ExtensionRange
+        - name: ReservedRange
+          uid: google.cloud.pubsub_v1.types.DescriptorProto.ReservedRange
+        name: DescriptorProto
+        uid: google.cloud.pubsub_v1.types.DescriptorProto
+      - name: DetachSubscriptionRequest
+        uid: google.cloud.pubsub_v1.types.DetachSubscriptionRequest
+      - name: DetachSubscriptionResponse
+        uid: google.cloud.pubsub_v1.types.DetachSubscriptionResponse
+      - name: Duration
+        uid: google.cloud.pubsub_v1.types.Duration
+      - name: Empty
+        uid: google.cloud.pubsub_v1.types.Empty
+      - items:
+        - name: Overview
+          uid: google.cloud.pubsub_v1.types.EnumDescriptorProto
+        - name: EnumReservedRange
+          uid: google.cloud.pubsub_v1.types.EnumDescriptorProto.EnumReservedRange
+        name: EnumDescriptorProto
+        uid: google.cloud.pubsub_v1.types.EnumDescriptorProto
+      - name: EnumOptions
+        uid: google.cloud.pubsub_v1.types.EnumOptions
+      - name: EnumValueDescriptorProto
+        uid: google.cloud.pubsub_v1.types.EnumValueDescriptorProto
+      - name: EnumValueOptions
+        uid: google.cloud.pubsub_v1.types.EnumValueOptions
+      - name: ExpirationPolicy
+        uid: google.cloud.pubsub_v1.types.ExpirationPolicy
+      - name: ExtensionRangeOptions
+        uid: google.cloud.pubsub_v1.types.ExtensionRangeOptions
+      - name: FieldDescriptorProto
+        uid: google.cloud.pubsub_v1.types.FieldDescriptorProto
+      - name: FieldMask
+        uid: google.cloud.pubsub_v1.types.FieldMask
+      - name: FieldOptions
+        uid: google.cloud.pubsub_v1.types.FieldOptions
+      - name: FileDescriptorProto
+        uid: google.cloud.pubsub_v1.types.FileDescriptorProto
+      - name: FileDescriptorSet
+        uid: google.cloud.pubsub_v1.types.FileDescriptorSet
+      - name: FileOptions
+        uid: google.cloud.pubsub_v1.types.FileOptions
+      - name: FlowControl
+        uid: google.cloud.pubsub_v1.types.FlowControl
+      - items:
+        - name: Overview
+          uid: google.cloud.pubsub_v1.types.GeneratedCodeInfo
+        - name: Annotation
+          uid: google.cloud.pubsub_v1.types.GeneratedCodeInfo.Annotation
+        name: GeneratedCodeInfo
+        uid: google.cloud.pubsub_v1.types.GeneratedCodeInfo
+      - name: GetIamPolicyRequest
+        uid: google.cloud.pubsub_v1.types.GetIamPolicyRequest
+      - name: GetSnapshotRequest
+        uid: google.cloud.pubsub_v1.types.GetSnapshotRequest
+      - name: GetSubscriptionRequest
+        uid: google.cloud.pubsub_v1.types.GetSubscriptionRequest
+      - name: GetTopicRequest
+        uid: google.cloud.pubsub_v1.types.GetTopicRequest
+      - name: Http
+        uid: google.cloud.pubsub_v1.types.Http
+      - name: HttpRule
+        uid: google.cloud.pubsub_v1.types.HttpRule
+      - name: LimitExceededBehavior
+        uid: google.cloud.pubsub_v1.types.LimitExceededBehavior
+      - name: ListSnapshotsRequest
+        uid: google.cloud.pubsub_v1.types.ListSnapshotsRequest
+      - name: ListSnapshotsResponse
+        uid: google.cloud.pubsub_v1.types.ListSnapshotsResponse
+      - name: ListSubscriptionsRequest
+        uid: google.cloud.pubsub_v1.types.ListSubscriptionsRequest
+      - name: ListSubscriptionsResponse
+        uid: google.cloud.pubsub_v1.types.ListSubscriptionsResponse
+      - name: ListTopicSnapshotsRequest
+        uid: google.cloud.pubsub_v1.types.ListTopicSnapshotsRequest
+      - name: ListTopicSnapshotsResponse
+        uid: google.cloud.pubsub_v1.types.ListTopicSnapshotsResponse
+      - name: ListTopicSubscriptionsRequest
+        uid: google.cloud.pubsub_v1.types.ListTopicSubscriptionsRequest
+      - name: ListTopicSubscriptionsResponse
+        uid: google.cloud.pubsub_v1.types.ListTopicSubscriptionsResponse
+      - name: ListTopicsRequest
+        uid: google.cloud.pubsub_v1.types.ListTopicsRequest
+      - name: ListTopicsResponse
+        uid: google.cloud.pubsub_v1.types.ListTopicsResponse
+      - name: MessageOptions
+        uid: google.cloud.pubsub_v1.types.MessageOptions
+      - name: MessageStoragePolicy
+        uid: google.cloud.pubsub_v1.types.MessageStoragePolicy
+      - name: MethodDescriptorProto
+        uid: google.cloud.pubsub_v1.types.MethodDescriptorProto
+      - name: MethodOptions
+        uid: google.cloud.pubsub_v1.types.MethodOptions
+      - name: ModifyAckDeadlineRequest
+        uid: google.cloud.pubsub_v1.types.ModifyAckDeadlineRequest
+      - name: ModifyPushConfigRequest
+        uid: google.cloud.pubsub_v1.types.ModifyPushConfigRequest
+      - name: OneofDescriptorProto
+        uid: google.cloud.pubsub_v1.types.OneofDescriptorProto
+      - name: OneofOptions
+        uid: google.cloud.pubsub_v1.types.OneofOptions
+      - name: Policy
+        uid: google.cloud.pubsub_v1.types.Policy
+      - name: PolicyDelta
+        uid: google.cloud.pubsub_v1.types.PolicyDelta
+      - name: PublishFlowControl
+        uid: google.cloud.pubsub_v1.types.PublishFlowControl
+      - name: PublishRequest
+        uid: google.cloud.pubsub_v1.types.PublishRequest
+      - name: PublishResponse
+        uid: google.cloud.pubsub_v1.types.PublishResponse
+      - name: PublisherOptions
+        uid: google.cloud.pubsub_v1.types.PublisherOptions
+      - items:
+        - name: Overview
+          uid: google.cloud.pubsub_v1.types.PubsubMessage
+        - name: AttributesEntry
+          uid: google.cloud.pubsub_v1.types.PubsubMessage.AttributesEntry
+        name: PubsubMessage
+        uid: google.cloud.pubsub_v1.types.PubsubMessage
+      - name: PullRequest
+        uid: google.cloud.pubsub_v1.types.PullRequest
+      - name: PullResponse
+        uid: google.cloud.pubsub_v1.types.PullResponse
+      - items:
+        - name: Overview
+          uid: google.cloud.pubsub_v1.types.PushConfig
+        - name: AttributesEntry
+          uid: google.cloud.pubsub_v1.types.PushConfig.AttributesEntry
+        - name: OidcToken
+          uid: google.cloud.pubsub_v1.types.PushConfig.OidcToken
+        name: PushConfig
+        uid: google.cloud.pubsub_v1.types.PushConfig
+      - name: ReceivedMessage
+        uid: google.cloud.pubsub_v1.types.ReceivedMessage
+      - name: RetryPolicy
+        uid: google.cloud.pubsub_v1.types.RetryPolicy
+      - name: SchemaSettings
+        uid: google.cloud.pubsub_v1.types.SchemaSettings
+      - name: SeekRequest
+        uid: google.cloud.pubsub_v1.types.SeekRequest
+      - name: SeekResponse
+        uid: google.cloud.pubsub_v1.types.SeekResponse
+      - name: ServiceDescriptorProto
+        uid: google.cloud.pubsub_v1.types.ServiceDescriptorProto
+      - name: ServiceOptions
+        uid: google.cloud.pubsub_v1.types.ServiceOptions
+      - name: SetIamPolicyRequest
+        uid: google.cloud.pubsub_v1.types.SetIamPolicyRequest
+      - items:
+        - name: Overview
+          uid: google.cloud.pubsub_v1.types.Snapshot
+        - name: LabelsEntry
+          uid: google.cloud.pubsub_v1.types.Snapshot.LabelsEntry
+        name: Snapshot
+        uid: google.cloud.pubsub_v1.types.Snapshot
+      - items:
+        - name: Overview
+          uid: google.cloud.pubsub_v1.types.SourceCodeInfo
+        - name: Location
+          uid: google.cloud.pubsub_v1.types.SourceCodeInfo.Location
+        name: SourceCodeInfo
+        uid: google.cloud.pubsub_v1.types.SourceCodeInfo
+      - name: StreamingPullRequest
+        uid: google.cloud.pubsub_v1.types.StreamingPullRequest
+      - items:
+        - name: Overview
+          uid: google.cloud.pubsub_v1.types.StreamingPullResponse
+        - name: AcknowledgeConfirmation
+          uid: google.cloud.pubsub_v1.types.StreamingPullResponse.AcknowledgeConfirmation
+        - name: ModifyAckDeadlineConfirmation
+          uid: google.cloud.pubsub_v1.types.StreamingPullResponse.ModifyAckDeadlineConfirmation
+        - name: SubscriptionProperties
+          uid: google.cloud.pubsub_v1.types.StreamingPullResponse.SubscriptionProperties
+        name: StreamingPullResponse
+        uid: google.cloud.pubsub_v1.types.StreamingPullResponse
+      - items:
+        - name: Overview
+          uid: google.cloud.pubsub_v1.types.Subscription
+        - name: LabelsEntry
+          uid: google.cloud.pubsub_v1.types.Subscription.LabelsEntry
+        - name: State
+          uid: google.cloud.pubsub_v1.types.Subscription.State
+        name: Subscription
+        uid: google.cloud.pubsub_v1.types.Subscription
+      - name: TestIamPermissionsRequest
+        uid: google.cloud.pubsub_v1.types.TestIamPermissionsRequest
+      - name: TestIamPermissionsResponse
+        uid: google.cloud.pubsub_v1.types.TestIamPermissionsResponse
+      - name: Timestamp
+        uid: google.cloud.pubsub_v1.types.Timestamp
+      - items:
+        - name: Overview
+          uid: google.cloud.pubsub_v1.types.Topic
+        - name: LabelsEntry
+          uid: google.cloud.pubsub_v1.types.Topic.LabelsEntry
+        name: Topic
+        uid: google.cloud.pubsub_v1.types.Topic
+      - items:
+        - name: Overview
+          uid: google.cloud.pubsub_v1.types.UninterpretedOption
+        - name: NamePart
+          uid: google.cloud.pubsub_v1.types.UninterpretedOption.NamePart
+        name: UninterpretedOption
+        uid: google.cloud.pubsub_v1.types.UninterpretedOption
+      - name: UpdateSnapshotRequest
+        uid: google.cloud.pubsub_v1.types.UpdateSnapshotRequest
+      - name: UpdateSubscriptionRequest
+        uid: google.cloud.pubsub_v1.types.UpdateSubscriptionRequest
+      - name: UpdateTopicRequest
+        uid: google.cloud.pubsub_v1.types.UpdateTopicRequest
+      name: types
+      uid: google.cloud.pubsub_v1.types
+    - name: Message
+      uid: google.cloud.pubsub_v1.subscriber.message.Message
+    name: Pubsub V1
+  - items:
+    - items:
+      - name: Overview
+        uid: google.pubsub_v1.services.publisher.pagers
+      - name: ListTopicSnapshotsAsyncPager
+        uid: google.pubsub_v1.services.publisher.pagers.ListTopicSnapshotsAsyncPager
+      - name: ListTopicSnapshotsPager
+        uid: google.pubsub_v1.services.publisher.pagers.ListTopicSnapshotsPager
+      - name: ListTopicSubscriptionsAsyncPager
+        uid: google.pubsub_v1.services.publisher.pagers.ListTopicSubscriptionsAsyncPager
+      - name: ListTopicSubscriptionsPager
+        uid: google.pubsub_v1.services.publisher.pagers.ListTopicSubscriptionsPager
+      - name: ListTopicsAsyncPager
+        uid: google.pubsub_v1.services.publisher.pagers.ListTopicsAsyncPager
+      - name: ListTopicsPager
+        uid: google.pubsub_v1.services.publisher.pagers.ListTopicsPager
+      name: publisher.pagers
+      uid: google.pubsub_v1.services.publisher.pagers
+    - items:
+      - name: Overview
+        uid: google.pubsub_v1.services.subscriber.pagers
+      - name: ListSnapshotsAsyncPager
+        uid: google.pubsub_v1.services.subscriber.pagers.ListSnapshotsAsyncPager
+      - name: ListSnapshotsPager
+        uid: google.pubsub_v1.services.subscriber.pagers.ListSnapshotsPager
+      - name: ListSubscriptionsAsyncPager
+        uid: google.pubsub_v1.services.subscriber.pagers.ListSubscriptionsAsyncPager
+      - name: ListSubscriptionsPager
+        uid: google.pubsub_v1.services.subscriber.pagers.ListSubscriptionsPager
+      name: subscriber.pagers
+      uid: google.pubsub_v1.services.subscriber.pagers
+    name: Services
+  name: google-cloud-pubsub
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/upgrading.md b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/upgrading.md
new file mode 100644
index 000000000000..7d5ca89a6f0e
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/upgrading.md
@@ -0,0 +1,201 @@
+# 2.0.0 Migration Guide
+
+The 2.0 release of the `google-cloud-pubsub` client is a significant upgrade based
+on a [next-gen code generator](https://github.com/googleapis/gapic-generator-python),
+and includes substantial interface changes. Existing code written for earlier versions
+of this library will likely require updates to use this version. This document
+describes the changes that have been made, and what you need to do to update your usage.
+
+If you experience issues or have questions, please file an
+[issue](https://github.com/googleapis/python-pubsub/issues).
+
+## Supported Python Versions
+
+> **WARNING**: Breaking change
+
+The 2.0.0 release requires Python 3.6+.
+
+## Method Calls
+
+> **WARNING**: Breaking change
+
+Almost all methods that send requests to the backend expect request objects. We
+provide a script that will convert most common use cases.
+
+
+* Install the library with the `libcst` extra.
+
+```py
+python3 -m pip install google-cloud-pubsub[libcst]
+```
+
+
+* The script `fixup_pubsub_v1_keywords.py` is shipped with the library. It expects
+an input directory (with the code to convert) and an empty destination directory.
+
+```sh
+$ scripts/fixup_pubsub_v1_keywords.py --input-directory .samples/ --output-directory samples/
+```
+
+**Before:**
+
+```py
+from google.cloud import pubsub
+
+publisher = pubsub.PublisherClient()
+
+project_path = "projects/{}".format(PROJECT_ID)
+topics = publisher.list_topics(project_path)
+```
+
+**After:**
+
+```py
+from google.cloud import pubsub
+
+publisher = pubsub.PublisherClient()
+
+project_path = f"projects/{PROJECT_ID}"
+topics = publisher.list_topics(request={"project": project_path})
+```
+
+### More Details
+
+In `google-cloud-pubsub<2.0.0`, parameters required by the API were positional
+parameters and optional parameters were keyword parameters.
+
+**Before:**
+
+```py
+    def list_topics(
+        self,
+        project,
+        page_size=None,
+        retry=google.api_core.gapic_v1.method.DEFAULT,
+        timeout=google.api_core.gapic_v1.method.DEFAULT,
+        metadata=None,
+    ):
+```
+
+In the 2.0.0 release, almost all methods that interact with the backend have a single
+positional parameter `request`. Method docstrings indicate whether a parameter is
+required or optional.
+
+> **NOTE:** The exception are hand written methods such as `publisher.publish()` and
+> `subscriber.subscribe()` that implement additional logic (e.g. request batching) and
+> sit on top of the API methods from the generated parts of the library. The signatures
+> of these methods have in large part been preserved.
+
+Some methods have additional keyword only parameters. The available parameters depend
+on the [`google.api.method_signature` annotation](https://github.com/googleapis/python-pubsub/blob/main/google/cloud/pubsub_v1/proto/pubsub.proto#L88)
+specified by the API producer.
+
+**After:**
+
+```py
+    def list_topics(
+        self,
+        request: pubsub.ListTopicsRequest = None,
+        *,
+        project: str = None,
+        retry: retries.Retry = gapic_v1.method.DEFAULT,
+        timeout: google.pubsub_v1.types.TimeoutType = gapic_v1.method.DEFAULT,
+        metadata: Sequence[Tuple[str, str]] = (),
+    ) -> pagers.ListTopicsPager:
+```
+
+> **NOTE:** The `request` parameter and flattened keyword parameters for the API are
+> mutually exclusive. Passing both will result in an error.
+
+Both of these calls are valid:
+
+```py
+response = client.list_topics(
+    request={
+        "project": project_path,
+        "metadata": [("foo", "bar"), ("baz", "quux")],
+    }
+)
+```
+
+```py
+response = client.list_topics(
+    project=project_path,
+    metadata=[("foo", "bar"), ("baz", "quux")],
+)
+```
+
+This call is invalid because it mixes `request` with a keyword argument `metadata`.
+Executing this code will result in an error:
+
+```py
+response = client.synthesize_speech(
+    request={"project": project_path},
+    metadata=[("foo", "bar"), ("baz", "quux")],
+)
+```
+
+> **NOTE:** The `request` parameter of some methods can also contain a more rich set of
+> options that are otherwise not available as explicit keyword only parameters, thus
+> these *must* be passed through `request`.
+
+## Removed Utility Methods
+
+> **WARNING**: Breaking change
+
+Some utility methods such as publisher client’s `subscription_path()` have been removed
+and now only exist in the relevant client, e.g. `subscriber.subscription_path()`.
+
+The `project_path()` method has been removed from both the publisher and subscriber
+client, this path must now be constructed manually:
+
+```py
+project_path = f"projects/{PROJECT_ID}"
+```
+
+## Removed `client_config` Parameter
+
+The publisher and subscriber clients cannot be constructed with `client_config`
+argument anymore. If you want to customize retry and timeout settings for a particular
+method, you need to do it upon method invocation by passing the custom `timeout` and
+`retry` arguments, respectively.
+
+## Custom Retry and Timeout settings for Publisher Client
+
+The `publisher_options` parameter to the Publisher Client, as well as all of the
+client’s methods, now accept custom retry and timeout settings:
+
+```py
+custom_retry = api_core.retry.Retry(
+    initial=0.250,  # seconds (default: 0.1)
+    maximum=90.0,  # seconds (default: 60.0)
+    multiplier=1.45,  # default: 1.3
+    deadline=300.0,  # seconds (default: 60.0)
+    predicate=api_core.retry.if_exception_type(
+        api_core.exceptions.Aborted,
+        api_core.exceptions.DeadlineExceeded,
+        api_core.exceptions.InternalServerError,
+        api_core.exceptions.ResourceExhausted,
+        api_core.exceptions.ServiceUnavailable,
+        api_core.exceptions.Unknown,
+        api_core.exceptions.Cancelled,
+    ),
+)
+
+custom_timeout=api_core.timeout.ExponentialTimeout(
+    initial=1.0,  
+    maximum=10.0,  
+    multiplier=1.0,  
+    deadline=300.0,  
+)
+
+publisher = pubsub_v1.PublisherClient(
+    publisher_options = pubsub_v1.types.PublisherOptions(
+        retry=custom_retry,
+        timeout=custom_timeout,
+    ),
+)
+```
+
+The timeout can be either an instance of `google.api_core.timeout.ConstantTimeout`,
+or an instance of `google.api_core.timeout.ExponentialTimeout`, as in the example.
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/changelog.md b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/changelog.md
new file mode 100644
index 000000000000..9153439e436d
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/changelog.md
@@ -0,0 +1,1377 @@
+# Changelog
+
+[PyPI History](https://pypi.org/project/google-cloud-storage/#history)
+
+## [2.5.0](https://github.com/googleapis/python-storage/compare/v2.4.0...v2.5.0) (2022-07-24)
+
+### Features
+
+
+* Custom Placement Config Dual Region Support ([#819](https://github.com/googleapis/python-storage/issues/819)) ([febece7](https://github.com/googleapis/python-storage/commit/febece76802252278bb7626d931973a76561382a))
+
+### Documentation
+
+
+* open file-like objects in byte mode for uploads ([#824](https://github.com/googleapis/python-storage/issues/824)) ([4bd3d1d](https://github.com/googleapis/python-storage/commit/4bd3d1ddf21196b075bbd84cdcb553c5d7355b93))
+
+## [2.4.0](https://github.com/googleapis/python-storage/compare/v2.3.0...v2.4.0) (2022-06-07)
+
+### Features
+
+
+* add AbortIncompleteMultipartUpload lifecycle rule ([#765](https://github.com/googleapis/python-storage/issues/765)) ([b2e5150](https://github.com/googleapis/python-storage/commit/b2e5150f191c04acb47ad98cef88512451aff81d))
+
+
+* support OLM Prefix/Suffix ([#773](https://github.com/googleapis/python-storage/issues/773)) ([187cf50](https://github.com/googleapis/python-storage/commit/187cf503194cf636640ca8ba787f9e8c216ea763))
+
+### Bug Fixes
+
+
+* fix rewrite object in CMEK enabled bucket ([#807](https://github.com/googleapis/python-storage/issues/807)) ([9b3cbf3](https://github.com/googleapis/python-storage/commit/9b3cbf3789c21462eac3c776cd29df12701e792f))
+
+### Documentation
+
+
+* fix changelog header to consistent size ([#802](https://github.com/googleapis/python-storage/issues/802)) ([4dd0907](https://github.com/googleapis/python-storage/commit/4dd0907b68e20d1ffcd0fe350831867197917e0d))
+
+
+* **samples:** Update the Recovery Point Objective (RPO) sample output ([#725](https://github.com/googleapis/python-storage/issues/725)) ([b0bf411](https://github.com/googleapis/python-storage/commit/b0bf411f8fec8712b3eeb99a2dd33de6d82312f8))
+
+
+* Update generation_metageneration.rst with a missing space ([#798](https://github.com/googleapis/python-storage/issues/798)) ([1e7cdb6](https://github.com/googleapis/python-storage/commit/1e7cdb655beb2a61a0d1b984c4d0468ec31bf463))
+
+
+* update retry docs ([#808](https://github.com/googleapis/python-storage/issues/808)) ([c365d5b](https://github.com/googleapis/python-storage/commit/c365d5bbd78292adb6861da3cdfae9ab7b39b844))
+
+## [2.3.0](https://github.com/googleapis/python-storage/compare/v2.2.1...v2.3.0) (2022-04-12)
+
+### Features
+
+
+* add dual region bucket support and sample ([#748](https://github.com/googleapis/python-storage/issues/748)) ([752e8ab](https://github.com/googleapis/python-storage/commit/752e8ab42d23afd68738e4d7ca6cdeee416dfd50))
+
+
+* track invocation id for retry metrics ([#741](https://github.com/googleapis/python-storage/issues/741)) ([bd56931](https://github.com/googleapis/python-storage/commit/bd5693164e7331df5f14186fd002e72e5203d7ee))
+
+### Bug Fixes
+
+
+* **deps:** drop pkg_resources ([#744](https://github.com/googleapis/python-storage/issues/744)) ([e963f33](https://github.com/googleapis/python-storage/commit/e963f33ced2852b64d721d69928b54443461ec9c))
+
+### Documentation
+
+
+* fix links in blob module ([#759](https://github.com/googleapis/python-storage/issues/759)) ([9b29314](https://github.com/googleapis/python-storage/commit/9b2931430b0796ffb23ec4efacd82dacad36f40f))
+
+## [2.2.1](https://github.com/googleapis/python-storage/compare/v2.2.0...v2.2.1) (2022-03-15)
+
+### Bug Fixes
+
+
+* remove py.typed marker file for PEP 561 ([#735](https://github.com/googleapis/python-storage/issues/735)) ([f77d2f7](https://github.com/googleapis/python-storage/commit/f77d2f787f435f2f898e9babcdab81225672ad4f)), closes [#734](https://github.com/googleapis/python-storage/issues/734)
+
+## [2.2.0](https://github.com/googleapis/python-storage/compare/v2.1.0...v2.2.0) (2022-03-14)
+
+### Features
+
+
+* allow no project in client methods using storage emulator ([#703](https://github.com/googleapis/python-storage/issues/703)) ([bcde0ec](https://github.com/googleapis/python-storage/commit/bcde0ec619d7d303892bcc0863b7f977c79f7649))
+
+### Bug Fixes
+
+
+* add user agent in python-storage when calling resumable media ([c7bf615](https://github.com/googleapis/python-storage/commit/c7bf615909a04f3bab3efb1047a9f4ba659bba19))
+
+
+* **deps:** require google-api-core>=1.31.5, >=2.3.2 ([#722](https://github.com/googleapis/python-storage/issues/722)) ([e9aab38](https://github.com/googleapis/python-storage/commit/e9aab389f868799d4425133954bad4f1cbb85786))
+
+
+* Fix BlobReader handling of interleaved reads and seeks ([#721](https://github.com/googleapis/python-storage/issues/721)) ([5d1cfd2](https://github.com/googleapis/python-storage/commit/5d1cfd2050321481a3bc4acbe80537ea666506fa))
+
+
+* retry client side requests timeout ([#727](https://github.com/googleapis/python-storage/issues/727)) ([e0b3b35](https://github.com/googleapis/python-storage/commit/e0b3b354d51e4be7c563d7f2f628a7139df842c0))
+
+### Documentation
+
+
+* fixed download_blob_to_file example ([#704](https://github.com/googleapis/python-storage/issues/704)) ([2c94d98](https://github.com/googleapis/python-storage/commit/2c94d98ed21cc768cfa54fac3d734254fc4d8480))
+
+## [2.1.0](https://github.com/googleapis/python-storage/compare/v2.0.0...v2.1.0) (2022-01-19)
+
+### Features
+
+
+* add turbo replication support and samples ([#622](https://github.com/googleapis/python-storage/issues/622)) ([4dafc81](https://github.com/googleapis/python-storage/commit/4dafc815470480ce9de7f0357e331d3fbd0ae9b7))
+
+
+* avoid authentication with storage emulator ([#679](https://github.com/googleapis/python-storage/issues/679)) ([8789afa](https://github.com/googleapis/python-storage/commit/8789afaaa1b2bd6f03fae72e3d87ce004ec10129))
+
+
+* remove python 3.6 support ([#689](https://github.com/googleapis/python-storage/issues/689)) ([8aa4130](https://github.com/googleapis/python-storage/commit/8aa4130ee068a1922161c8ca54a53a4a51d65ce0))
+
+## [2.0.0](https://github.com/googleapis/python-storage/compare/v1.44.0...v2.0.0) (2022-01-12)
+
+### ⚠ BREAKING CHANGES
+
+
+* Remove Python 2 support (#657)
+
+### Features
+
+
+* Remove Python 2 support ([#657](https://github.com/googleapis/python-storage/issues/657)) ([b611670](https://github.com/googleapis/python-storage/commit/b6116700a4a32d28404c39018138e545f3f7910e))
+
+## [1.44.0](https://www.github.com/googleapis/python-storage/compare/v1.43.0...v1.44.0) (2022-01-05)
+
+### Features
+
+
+* add raw_download kwarg to BlobReader ([#668](https://www.github.com/googleapis/python-storage/issues/668)) ([10cdad6](https://www.github.com/googleapis/python-storage/commit/10cdad630739a324ae0b16a3d14a67ca4c8a23c2))
+
+### Documentation
+
+
+* Describe code sample more specifically ([#660](https://www.github.com/googleapis/python-storage/issues/660)) ([0459cb4](https://www.github.com/googleapis/python-storage/commit/0459cb4e866696c46385a5ad72e2a85db810a36b))
+
+
+* refresh readme instructions ([#667](https://www.github.com/googleapis/python-storage/issues/667)) ([ceb9314](https://www.github.com/googleapis/python-storage/commit/ceb931403a755f2a0bdc20144287dbc4700c3360))
+
+
+* This is just a simple PR to better describe what the code is doing in the comments. ([0459cb4](https://www.github.com/googleapis/python-storage/commit/0459cb4e866696c46385a5ad72e2a85db810a36b))
+
+
+* use writeable streamin example for ‘download_blob_to_file’ ([#676](https://www.github.com/googleapis/python-storage/issues/676)) ([96092d4](https://www.github.com/googleapis/python-storage/commit/96092d4be36be478f9671e8940de4fd09cc6f7f0))
+
+## [1.43.0](https://www.github.com/googleapis/python-storage/compare/v1.42.3...v1.43.0) (2021-11-15)
+
+### Features
+
+
+* add ignore_flush parameter to BlobWriter ([#644](https://www.github.com/googleapis/python-storage/issues/644)) ([af9c9dc](https://www.github.com/googleapis/python-storage/commit/af9c9dc83d8582167b74105167af17c9809455de))
+
+
+* add support for Python 3.10 ([#615](https://www.github.com/googleapis/python-storage/issues/615)) ([f81a2d0](https://www.github.com/googleapis/python-storage/commit/f81a2d054616c1ca1734997a16a8f47f98ab346b))
+
+### Bug Fixes
+
+
+* raise a ValueError in BucketNotification.create() if a topic name is not set ([#617](https://www.github.com/googleapis/python-storage/issues/617)) ([9dd78df](https://www.github.com/googleapis/python-storage/commit/9dd78df444d21af51af7858e8958b505a26c0b79))
+
+### Documentation
+
+
+* add contributing and authoring guides under samples/ ([#633](https://www.github.com/googleapis/python-storage/issues/633)) ([420591a](https://www.github.com/googleapis/python-storage/commit/420591a2b71f823dbe80f4a4405d8a514f87e0fb))
+
+
+* add links to samples and how to guides ([#641](https://www.github.com/googleapis/python-storage/issues/641)) ([49f78b0](https://www.github.com/googleapis/python-storage/commit/49f78b09fed6d9f486639fd0a72542c30a0df084))
+
+
+* add README to samples subdirectory ([#639](https://www.github.com/googleapis/python-storage/issues/639)) ([58af882](https://www.github.com/googleapis/python-storage/commit/58af882c047c31f59486513c568737082bca6350))
+
+
+* update samples readme with cli args ([#651](https://www.github.com/googleapis/python-storage/issues/651)) ([75dda81](https://www.github.com/googleapis/python-storage/commit/75dda810e808074d18dfe7915f1403ad01bf2f02))
+
+## [1.42.3](https://www.github.com/googleapis/python-storage/compare/v1.42.2...v1.42.3) (2021-09-30)
+
+### Bug Fixes
+
+
+* changeover unspecified to inherited ([#603](https://www.github.com/googleapis/python-storage/issues/603)) ([283a419](https://www.github.com/googleapis/python-storage/commit/283a4196865d9b5275e87f54737d1faee40cc946))
+
+
+* check response code in batch.finish ([#609](https://www.github.com/googleapis/python-storage/issues/609)) ([318a286](https://www.github.com/googleapis/python-storage/commit/318a286d709427bfe9f3a37e933c255ac51b3033))
+
+
+* skip tests that use unspecified pap until we get the change in ([#600](https://www.github.com/googleapis/python-storage/issues/600)) ([38b9b55](https://www.github.com/googleapis/python-storage/commit/38b9b5582e2c6bbd1acab2b49410084170466fad))
+
+## [1.42.2](https://www.github.com/googleapis/python-storage/compare/v1.42.1...v1.42.2) (2021-09-16)
+
+### Bug Fixes
+
+
+* add preconditions and retry config support to ACL patch operationss ([#586](https://www.github.com/googleapis/python-storage/issues/586)) ([4333caf](https://www.github.com/googleapis/python-storage/commit/4333caf3674d78b3dfbc161a796abac604d57953))
+
+
+* add unpinned protobuf for python3 ([#592](https://www.github.com/googleapis/python-storage/issues/592)) ([53f7ad0](https://www.github.com/googleapis/python-storage/commit/53f7ad0204ad425011da9162d1a78f8276c837eb))
+
+
+* pin six as a required dependency ([#589](https://www.github.com/googleapis/python-storage/issues/589)) ([9ca97bf](https://www.github.com/googleapis/python-storage/commit/9ca97bf9139c71cd033c78af73da904b27d8ff50))
+
+## [1.42.1](https://www.github.com/googleapis/python-storage/compare/v1.42.0...v1.42.1) (2021-09-07)
+
+### Bug Fixes
+
+
+* do not append duplicates to user agent string ([#570](https://www.github.com/googleapis/python-storage/issues/570)) ([57cf3a1](https://www.github.com/googleapis/python-storage/commit/57cf3a1f27292939ed097ef8afa3f4392c4b83e0))
+
+### Documentation
+
+
+* pass explicit ‘client’ in ‘{Blob.Bucket}.from_string’ examples ([#545](https://www.github.com/googleapis/python-storage/issues/545)) ([6eff22d](https://www.github.com/googleapis/python-storage/commit/6eff22db0e8c8689208ee52fa815f3ea00675094))
+
+## [1.42.0](https://www.github.com/googleapis/python-storage/compare/v1.41.1...v1.42.0) (2021-08-05)
+
+### Features
+
+
+* add ‘page_size’ parameter to ‘Bucket.list_blobs, list_buckets ([#520](https://www.github.com/googleapis/python-storage/issues/520)) ([c5f4ad8](https://www.github.com/googleapis/python-storage/commit/c5f4ad8fddd1849a4229b0126c4c022bccb90128))
+
+### Bug Fixes
+
+
+* **deps:** add explicit ranges for ‘google-api-core’ and ‘google-auth’ ([#530](https://www.github.com/googleapis/python-storage/issues/530)) ([310f207](https://www.github.com/googleapis/python-storage/commit/310f207411da0382af310172344f19c644c14e6a))
+
+
+* downloading no longer marks metadata fields as ‘changed’ ([#523](https://www.github.com/googleapis/python-storage/issues/523)) ([160d1ec](https://www.github.com/googleapis/python-storage/commit/160d1ecb41f1f269b25cb68b2d2f7daf418bf01c))
+
+
+* make ‘requests.exceptions.ChunkedEncodingError retryable by default ([#526](https://www.github.com/googleapis/python-storage/issues/526)) ([4abb403](https://www.github.com/googleapis/python-storage/commit/4abb40310eca7ec45afc4bc5e4dfafbe083e74d2))
+
+### Documentation
+
+
+* update supported / removed Python versions in README ([#519](https://www.github.com/googleapis/python-storage/issues/519)) ([1f1b138](https://www.github.com/googleapis/python-storage/commit/1f1b138865fb171535ee0cf768aff1987ed58914))
+
+## [1.41.1](https://www.github.com/googleapis/python-storage/compare/v1.41.0...v1.41.1) (2021-07-20)
+
+### Bug Fixes
+
+
+* **deps:** pin `{api,cloud}-core`, `auth` to allow 2.x versions on Python 3 ([#512](https://www.github.com/googleapis/python-storage/issues/512)) ([4d7500e](https://www.github.com/googleapis/python-storage/commit/4d7500e39c51efd817b8363b69c88be040f3edb8))
+
+
+* remove trailing commas from error message constants ([#505](https://www.github.com/googleapis/python-storage/issues/505)) ([d4a86ce](https://www.github.com/googleapis/python-storage/commit/d4a86ceb7a7c5e00ba7bae37c7078d52478040ff)), closes [#501](https://www.github.com/googleapis/python-storage/issues/501)
+
+### Documentation
+
+
+* replace usage of deprecated function `download_as_string` in docs ([#508](https://www.github.com/googleapis/python-storage/issues/508)) ([8dfa4d4](https://www.github.com/googleapis/python-storage/commit/8dfa4d429dce94b671dc3e3755e52ab82733f61a))
+
+## [1.41.0](https://www.github.com/googleapis/python-storage/compare/v1.40.0...v1.41.0) (2021-07-13)
+
+### Features
+
+
+* add support for Etag headers on reads ([#489](https://www.github.com/googleapis/python-storage/issues/489)) ([741d3fd](https://www.github.com/googleapis/python-storage/commit/741d3fda4e4280022cede29ebeb7c2ea09e73b6f))
+
+### Bug Fixes
+
+
+* **deps:** update minimum dependency versions to pick up bugfixes ([#496](https://www.github.com/googleapis/python-storage/issues/496)) ([92251a5](https://www.github.com/googleapis/python-storage/commit/92251a5c8ea4d663773506eb1c630201a657aa69)), closes [#494](https://www.github.com/googleapis/python-storage/issues/494)
+
+
+* populate etag / generation / metageneration properties during download ([#488](https://www.github.com/googleapis/python-storage/issues/488)) ([49ba14c](https://www.github.com/googleapis/python-storage/commit/49ba14c9c47dbe6bc2bb45d53bbe5621c131fbcb))
+
+
+* revise and rename is_etag_in_json(data) ([#483](https://www.github.com/googleapis/python-storage/issues/483)) ([0a52546](https://www.github.com/googleapis/python-storage/commit/0a5254647bf1155874fe48f3891bcc34a76b0b81))
+
+## [1.40.0](https://www.github.com/googleapis/python-storage/compare/v1.39.0...v1.40.0) (2021-06-30)
+
+### Features
+
+
+* add preconditions and retry configuration to blob.create_resumable_upload_session ([#484](https://www.github.com/googleapis/python-storage/issues/484)) ([0ae35ee](https://www.github.com/googleapis/python-storage/commit/0ae35eef0fe82fe60bc095c4b183102bb1dabeeb))
+
+
+* add public access prevention to bucket IAM configuration ([#304](https://www.github.com/googleapis/python-storage/issues/304)) ([e3e57a9](https://www.github.com/googleapis/python-storage/commit/e3e57a9c779d6b87852063787f19e27c76b1bb14))
+
+### Bug Fixes
+
+
+* replace default retry for upload operations ([#480](https://www.github.com/googleapis/python-storage/issues/480)) ([c027ccf](https://www.github.com/googleapis/python-storage/commit/c027ccf4279fb05e041754294f10744b7d81beea))
+
+## [1.39.0](https://www.github.com/googleapis/python-storage/compare/v1.38.0...v1.39.0) (2021-06-21)
+
+### Features
+
+
+* media operation retries can be configured using the same interface as with non-media operation ([#447](https://www.github.com/googleapis/python-storage/issues/447)) ([0dbbb8a](https://www.github.com/googleapis/python-storage/commit/0dbbb8ac17a4b632707485ee6c7cc15e4670efaa))
+
+### Bug Fixes
+
+
+* add ConnectionError to default retry ([#445](https://www.github.com/googleapis/python-storage/issues/445)) ([8344253](https://www.github.com/googleapis/python-storage/commit/8344253a1969b9d04b81f87a6d7bddd3ddb55006))
+
+
+* apply idempotency policies for ACLs ([#458](https://www.github.com/googleapis/python-storage/issues/458)) ([2232f38](https://www.github.com/googleapis/python-storage/commit/2232f38933dbdfeb4f6585291794d332771ffdf2))
+
+
+* replace python lifecycle action parsing ValueError with warning ([#437](https://www.github.com/googleapis/python-storage/issues/437)) ([2532d50](https://www.github.com/googleapis/python-storage/commit/2532d506b44fc1ef0fa0a996822d29e7459c465a))
+
+
+* revise blob.compose query parameters `if_generation_match` ([#454](https://www.github.com/googleapis/python-storage/issues/454)) ([70d19e7](https://www.github.com/googleapis/python-storage/commit/70d19e72831dee112bb07f38b50beef4890c1155))
+
+### Documentation
+
+
+* streamline ‘timeout’ / ‘retry’ docs in docstrings ([#461](https://www.github.com/googleapis/python-storage/issues/461)) ([78b2eba](https://www.github.com/googleapis/python-storage/commit/78b2eba81003b437cd24f2b8d269ea2455682507))
+
+
+* streamline docstrings for conditional parmas ([#464](https://www.github.com/googleapis/python-storage/issues/464)) ([6999370](https://www.github.com/googleapis/python-storage/commit/69993702390322df07cc2e818003186a47524c2b))
+
+## [1.38.0](https://www.github.com/googleapis/python-storage/compare/v1.37.1...v1.38.0) (2021-04-26)
+
+### Features
+
+
+* add getters and setters for encryption_key and kms_key_name ([#409](https://www.github.com/googleapis/python-storage/issues/409)) ([2adfb59](https://www.github.com/googleapis/python-storage/commit/2adfb593d5ad19320affe480455568c1410b9d93))
+
+### Bug Fixes
+
+
+* retry auth.TransportError errors ([#418](https://www.github.com/googleapis/python-storage/issues/418)) ([23a8db8](https://www.github.com/googleapis/python-storage/commit/23a8db839909a0781343cb18edffaea06a0b7092))
+
+### Documentation
+
+
+* revise docstrings for generate_signed_url ([#408](https://www.github.com/googleapis/python-storage/issues/408)) ([f090548](https://www.github.com/googleapis/python-storage/commit/f090548437142b635191e90dcee1acd4c38e565c))
+
+## [1.37.1](https://www.github.com/googleapis/python-storage/compare/v1.37.0...v1.37.1) (2021-04-02)
+
+### Bug Fixes
+
+
+* Ensure consistency check in test runs even if expected error occurs ([#402](https://www.github.com/googleapis/python-storage/issues/402)) ([416bcd4](https://www.github.com/googleapis/python-storage/commit/416bcd42406ec57e51f04e5d9b0c58509f80520c))
+
+
+* silence expected errors for routine operations on BlobReader ([#400](https://www.github.com/googleapis/python-storage/issues/400)) ([d52853b](https://www.github.com/googleapis/python-storage/commit/d52853b420f50012e02c395f5407e3018922c048))
+
+## [1.37.0](https://www.github.com/googleapis/python-storage/compare/v1.36.2...v1.37.0) (2021-03-24)
+
+### Features
+
+
+* add blob.open() for file-like I/O ([#385](https://www.github.com/googleapis/python-storage/issues/385)) ([440a0a4](https://www.github.com/googleapis/python-storage/commit/440a0a4ffe00b1f7c562b0e9c1e47dbadeca33e1)), closes [#29](https://www.github.com/googleapis/python-storage/issues/29)
+
+### Bug Fixes
+
+
+* update user_project usage and documentation in bucket/client class methods ([#396](https://www.github.com/googleapis/python-storage/issues/396)) ([1a2734b](https://www.github.com/googleapis/python-storage/commit/1a2734ba6d316ce51e4e141571331e86196462b9))
+
+## [1.36.2](https://www.github.com/googleapis/python-storage/compare/v1.36.1...v1.36.2) (2021-03-09)
+
+### Bug Fixes
+
+
+* update batch connection to request api endpoint info from client ([#392](https://www.github.com/googleapis/python-storage/issues/392)) ([91fc6d9](https://www.github.com/googleapis/python-storage/commit/91fc6d9870a36308b15a827ed6a691e5b4669b62))
+
+## [1.36.1](https://www.github.com/googleapis/python-storage/compare/v1.36.0...v1.36.1) (2021-02-19)
+
+### Bug Fixes
+
+
+* allow metadata keys to be cleared ([#383](https://www.github.com/googleapis/python-storage/issues/383)) ([79d27da](https://www.github.com/googleapis/python-storage/commit/79d27da9fe842e44a9091076ea0ef52c5ef5ff72)), closes [#381](https://www.github.com/googleapis/python-storage/issues/381)
+
+
+* allow signed url version v4 without signed credentials ([#356](https://www.github.com/googleapis/python-storage/issues/356)) ([3e69bf9](https://www.github.com/googleapis/python-storage/commit/3e69bf92496616c5de28094dd42260b35c3bf982))
+
+
+* correctly encode bytes for V2 signature ([#382](https://www.github.com/googleapis/python-storage/issues/382)) ([f44212b](https://www.github.com/googleapis/python-storage/commit/f44212b7b91a67ca661898400fe632f9fb3ec8f6))
+
+## [1.36.0](https://www.github.com/googleapis/python-storage/compare/v1.35.1...v1.36.0) (2021-02-10)
+
+### Features
+
+
+* add mtls support ([#367](https://www.github.com/googleapis/python-storage/issues/367)) ([d35ab35](https://www.github.com/googleapis/python-storage/commit/d35ab3537d1828505f614d32b79b67173c9438c0))
+
+### Bug Fixes
+
+
+* correctly decode times without microseconds ([#375](https://www.github.com/googleapis/python-storage/issues/375)) ([37a1eb5](https://www.github.com/googleapis/python-storage/commit/37a1eb54095b4f857771784007dd049ffafbc11d)), closes [#363](https://www.github.com/googleapis/python-storage/issues/363)
+
+
+* expose num_retries parameter for blob upload methods ([#353](https://www.github.com/googleapis/python-storage/issues/353)) ([fdabd6a](https://www.github.com/googleapis/python-storage/commit/fdabd6af74da4b15fbb5d40fb8f80a9b478b9607)), closes [#352](https://www.github.com/googleapis/python-storage/issues/352)
+
+
+* pass the unused parameter ([#349](https://www.github.com/googleapis/python-storage/issues/349)) ([5c60d24](https://www.github.com/googleapis/python-storage/commit/5c60d240aa98d2a1dcc6933d6da2ce60ea1b7559))
+
+
+* set custom_time on uploads ([#374](https://www.github.com/googleapis/python-storage/issues/374)) ([f048be1](https://www.github.com/googleapis/python-storage/commit/f048be10416f51cea4e6c8c5b805df7b5d9c4d32)), closes [#372](https://www.github.com/googleapis/python-storage/issues/372)
+
+## [1.35.1](https://www.github.com/googleapis/python-storage/compare/v1.35.0...v1.35.1) (2021-01-28)
+
+### Bug Fixes
+
+
+* address incorrect usage of request preconditions ([#366](https://www.github.com/googleapis/python-storage/issues/366)) ([321658c](https://www.github.com/googleapis/python-storage/commit/321658c3b9ccaf22d08dd881c93206590f8275b7))
+
+
+* Amend default retry behavior for bucket operations on client ([#358](https://www.github.com/googleapis/python-storage/issues/358)) ([b91e57d](https://www.github.com/googleapis/python-storage/commit/b91e57d6ca314ac4feaec30bf355fcf7ac4468c0))
+
+## [1.35.0](https://www.github.com/googleapis/python-storage/compare/v1.34.0...v1.35.0) (2020-12-14)
+
+### Features
+
+
+* support ConnectionError retries for media operations ([#342](https://www.github.com/googleapis/python-storage/issues/342)) ([e55b25b](https://www.github.com/googleapis/python-storage/commit/e55b25be1e32f17b17bffe1da99fca5062f180cb))
+
+## [1.34.0](https://www.github.com/googleapis/python-storage/compare/v1.33.0...v1.34.0) (2020-12-11)
+
+### Features
+
+
+* make retry parameter public and added in other methods ([#331](https://www.github.com/googleapis/python-storage/issues/331)) ([910e34c](https://www.github.com/googleapis/python-storage/commit/910e34c57de5823bc3a04adbd87cbfe27fb41882))
+
+### Bug Fixes
+
+
+* avoid triggering global logging config ([#333](https://www.github.com/googleapis/python-storage/issues/333)) ([602108a](https://www.github.com/googleapis/python-storage/commit/602108a976503271fe0d85c8d7891ce8083aca89)), closes [#332](https://www.github.com/googleapis/python-storage/issues/332)
+
+
+* fall back to ‘charset’ of ‘content_type’ in ‘download_as_text’  ([#326](https://www.github.com/googleapis/python-storage/issues/326)) ([63ff233](https://www.github.com/googleapis/python-storage/commit/63ff23387f5873c609490be8e58d69ba34a10a5e)), closes [#319](https://www.github.com/googleapis/python-storage/issues/319)
+
+
+* fix conditional retry handling of camelCase query params ([#340](https://www.github.com/googleapis/python-storage/issues/340)) ([4ff6141](https://www.github.com/googleapis/python-storage/commit/4ff614161f6a2654a59706f4f72b5fbb614e70ec))
+
+
+* retry uploads only conditionally ([#316](https://www.github.com/googleapis/python-storage/issues/316)) ([547740c](https://www.github.com/googleapis/python-storage/commit/547740c0a898492e76ce5e60dd20c7ddb8a53d1f))
+
+
+* update ‘custom_time’ setter to record change ([#323](https://www.github.com/googleapis/python-storage/issues/323)) ([5174154](https://www.github.com/googleapis/python-storage/commit/5174154fe73bb6581efc3cd32ebe12014ceab306)), closes [#322](https://www.github.com/googleapis/python-storage/issues/322)
+
+## [1.33.0](https://www.github.com/googleapis/python-storage/compare/v1.32.0...v1.33.0) (2020-11-16)
+
+### Features
+
+
+* add classifiers for python3.9 and remove for python3.5 ([#295](https://www.github.com/googleapis/python-storage/issues/295)) ([f072825](https://www.github.com/googleapis/python-storage/commit/f072825ce03d774fd95d9fe3db95a8c7130b0e8a))
+
+
+* add testing support for Python 3.9, drop Python 3.5 ([#313](https://www.github.com/googleapis/python-storage/issues/313)) ([fa14009](https://www.github.com/googleapis/python-storage/commit/fa140092877a277abbb23785657590a274a86d61))
+
+### Bug Fixes
+
+
+* use passed-in `client` within `Blob.from_string` and helpers ([#290](https://www.github.com/googleapis/python-storage/issues/290)) ([d457ce3](https://www.github.com/googleapis/python-storage/commit/d457ce3e161555c9117ae288ec0c9cd5f8d5fe3a)), closes [#286](https://www.github.com/googleapis/python-storage/issues/286)
+
+
+* preserve `metadata` value when uploading new file content ([#298](https://www.github.com/googleapis/python-storage/issues/298)) ([5ab6b0d](https://www.github.com/googleapis/python-storage/commit/5ab6b0d9a2b27ae830740a7a0226fc1e241e9ec4)), closes [#293](https://www.github.com/googleapis/python-storage/issues/293)
+
+## [1.32.0](https://www.github.com/googleapis/python-storage/compare/v1.31.2...v1.32.0) (2020-10-16)
+
+### Features
+
+
+* retry API calls with exponential backoff ([#287](https://www.github.com/googleapis/python-storage/issues/287)) ([fbe5d9c](https://www.github.com/googleapis/python-storage/commit/fbe5d9ca8684c6a992dcdee977fc8dd012a96a5c))
+
+### Bug Fixes
+
+
+* field policy return string ([#282](https://www.github.com/googleapis/python-storage/issues/282)) ([c356b84](https://www.github.com/googleapis/python-storage/commit/c356b8484a758548d5f4823a495ab70c798cfaaf))
+
+
+* self-upload files for Unicode system test ([#296](https://www.github.com/googleapis/python-storage/issues/296)) ([6f865d9](https://www.github.com/googleapis/python-storage/commit/6f865d97a19278884356055dfeeaae92f7c63cc1))
+
+
+* use version.py for versioning, avoid issues with discovering version via get_distribution ([#288](https://www.github.com/googleapis/python-storage/issues/288)) ([fcd1c4f](https://www.github.com/googleapis/python-storage/commit/fcd1c4f7c947eb95d6937783fd69670a570f145e))
+
+## [1.31.2](https://www.github.com/googleapis/python-storage/compare/v1.31.1...v1.31.2) (2020-09-23)
+
+### Documentation
+
+
+* fix docstring example for ‘blob.generate_signed_url’ ([#278](https://www.github.com/googleapis/python-storage/issues/278)) ([2dc91c9](https://www.github.com/googleapis/python-storage/commit/2dc91c947e3693023b4478a15c460693808ea2d9))
+
+## [1.31.1](https://www.github.com/googleapis/python-storage/compare/v1.31.0...v1.31.1) (2020-09-16)
+
+### Bug Fixes
+
+
+* add requests as a dependency ([#271](https://www.github.com/googleapis/python-storage/issues/271)) ([ec52b38](https://www.github.com/googleapis/python-storage/commit/ec52b38df211fad18a86d7e16d83db79de59d5f5))
+
+
+* preserve existing blob hashes when ‘X-Goog-Hash header’ is not present ([#267](https://www.github.com/googleapis/python-storage/issues/267)) ([277afb8](https://www.github.com/googleapis/python-storage/commit/277afb83f464d77b163f2722272092df4180411e))
+
+
+* **blob:** base64 includes additional characters ([#258](https://www.github.com/googleapis/python-storage/issues/258)) ([cf0774a](https://www.github.com/googleapis/python-storage/commit/cf0774aa8ffd45d340aff9a7d2236d8d65c8ae93))
+
+### Documentation
+
+
+* add docs signed_url expiration take default utc ([#250](https://www.github.com/googleapis/python-storage/issues/250)) ([944ab18](https://www.github.com/googleapis/python-storage/commit/944ab1827b3ca0bd1d3aafc2829245290e9bde59))
+
+## [1.31.0](https://www.github.com/googleapis/python-storage/compare/v1.30.0...v1.31.0) (2020-08-26)
+
+### Features
+
+
+* add configurable checksumming for blob uploads and downloads ([#246](https://www.github.com/googleapis/python-storage/issues/246)) ([23b7d1c](https://www.github.com/googleapis/python-storage/commit/23b7d1c3155deae3c804c510dee3a7cec97cd46c))
+
+
+* add support for ‘Blob.custom_time’ and lifecycle rules ([#199](https://www.github.com/googleapis/python-storage/issues/199)) ([180873d](https://www.github.com/googleapis/python-storage/commit/180873de139f7f8e00b7bef423bc15760cf68cc2))
+
+
+* error message return from api ([#235](https://www.github.com/googleapis/python-storage/issues/235)) ([a8de586](https://www.github.com/googleapis/python-storage/commit/a8de5868f32b45868f178f420138fcd2fe42f5fd))
+
+
+* **storage:** add support of daysSinceNoncurrentTime and noncurrentTimeBefore ([#162](https://www.github.com/googleapis/python-storage/issues/162)) ([136c097](https://www.github.com/googleapis/python-storage/commit/136c0970f8ef7ad4751104e3b8b7dd3204220a67))
+
+
+* pass ‘client_options’ to base class ctor ([#225](https://www.github.com/googleapis/python-storage/issues/225)) ([e1f91fc](https://www.github.com/googleapis/python-storage/commit/e1f91fcca6c001bc3b0c5f759a7a003fcf60c0a6)), closes [#210](https://www.github.com/googleapis/python-storage/issues/210)
+
+
+* rename ‘Blob.download_as_{string,bytes}’, add ‘Blob.download_as_text’ ([#182](https://www.github.com/googleapis/python-storage/issues/182)) ([73107c3](https://www.github.com/googleapis/python-storage/commit/73107c35f23c4a358e957c2b8188300a7fa958fe))
+
+### Bug Fixes
+
+
+* change datetime.now to utcnow ([#251](https://www.github.com/googleapis/python-storage/issues/251)) ([3465d08](https://www.github.com/googleapis/python-storage/commit/3465d08e098edb250dee5e97d1fb9ded8bae5700)), closes [#228](https://www.github.com/googleapis/python-storage/issues/228)
+
+
+* extract hashes correctly during download ([#238](https://www.github.com/googleapis/python-storage/issues/238)) ([23cfb65](https://www.github.com/googleapis/python-storage/commit/23cfb65c3a3b10759c67846e162e4ed77a3f5307))
+
+
+* repair mal-formed docstring ([#255](https://www.github.com/googleapis/python-storage/issues/255)) ([e722376](https://www.github.com/googleapis/python-storage/commit/e722376371cb8a3acc46d6c84fb41f4e874f41aa))
+
+### Documentation
+
+
+* update docs build (via synth) ([#222](https://www.github.com/googleapis/python-storage/issues/222)) ([4c5adfa](https://www.github.com/googleapis/python-storage/commit/4c5adfa6e05bf018d72ee1a7e99679fd55f2c662))
+
+## [1.30.0](https://www.github.com/googleapis/python-storage/compare/v1.29.0...v1.30.0) (2020-07-24)
+
+### Features
+
+
+* add timeouts to Blob methods where missing ([#185](https://www.github.com/googleapis/python-storage/issues/185)) ([6eeb855](https://www.github.com/googleapis/python-storage/commit/6eeb855aa0e6a7835d1d4f6e72951e43af22ab57))
+
+
+* auto-populate standard headers for non-chunked downloads ([#204](https://www.github.com/googleapis/python-storage/issues/204)) ([d8432cd](https://www.github.com/googleapis/python-storage/commit/d8432cd65a4e9b38eebd1ade2ff00f2f44bb0ef6)), closes [#24](https://www.github.com/googleapis/python-storage/issues/24)
+
+
+* migrate to Service Account Credentials API ([#189](https://www.github.com/googleapis/python-storage/issues/189)) ([e4990d0](https://www.github.com/googleapis/python-storage/commit/e4990d06043dbd8d1a417f3a1a67fe8746071f1c))
+
+### Bug Fixes
+
+
+* add multiprocessing.rst to synthool excludes ([#186](https://www.github.com/googleapis/python-storage/issues/186)) ([4d76e38](https://www.github.com/googleapis/python-storage/commit/4d76e3882210ed2818a43256265f6df31348d410))
+
+### Documentation
+
+
+* fix indent in code blocks ([#171](https://www.github.com/googleapis/python-storage/issues/171)) ([62d1543](https://www.github.com/googleapis/python-storage/commit/62d1543e18040b286b23464562aa6eb998074c54)), closes [#170](https://www.github.com/googleapis/python-storage/issues/170)
+
+
+* remove doubled word in docstring ([#209](https://www.github.com/googleapis/python-storage/issues/209)) ([7a4e7a5](https://www.github.com/googleapis/python-storage/commit/7a4e7a5974abedb0b7b2e110cacbfcd0a40346b6))
+
+### Documentation
+
+
+* fix indent in code blocks ([#171](https://www.github.com/googleapis/python-storage/issues/171)) ([62d1543](https://www.github.com/googleapis/python-storage/commit/62d1543e18040b286b23464562aa6eb998074c54)), closes [#170](https://www.github.com/googleapis/python-storage/issues/170)
+
+
+* remove doubled word in docstring ([#209](https://www.github.com/googleapis/python-storage/issues/209)) ([7a4e7a5](https://www.github.com/googleapis/python-storage/commit/7a4e7a5974abedb0b7b2e110cacbfcd0a40346b6))
+
+### Dependencies
+
+
+* prep for grmp-1.0.0 release ([#211](https://www.github.com/googleapis/python-storage/issues/211)) ([55bae9a](https://www.github.com/googleapis/python-storage/commit/55bae9a0e7c0db512c10c6b3b621cd2ef05c9729))
+
+## [1.29.0](https://www.github.com/googleapis/python-storage/compare/v1.28.1...v1.29.0) (2020-06-09)
+
+### Features
+
+
+* add *generation*match args into Blob.compose() ([#122](https://www.github.com/googleapis/python-storage/issues/122)) ([dc01c59](https://www.github.com/googleapis/python-storage/commit/dc01c59e036164326aeeea164098cf2e6e0dc12c))
+
+
+* add Bucket.reload() and Bucket.update() wrappers to restrict generation match args ([#153](https://www.github.com/googleapis/python-storage/issues/153)) ([76dd9ac](https://www.github.com/googleapis/python-storage/commit/76dd9ac7e8b7765defc5b521cfe059e08e33c65c)), closes [#127](https://www.github.com/googleapis/python-storage/issues/127)
+
+
+* add helper for bucket bound hostname URLs ([#137](https://www.github.com/googleapis/python-storage/issues/137)) ([b26f9fa](https://www.github.com/googleapis/python-storage/commit/b26f9fa8a767b7d5affea8d2c4b87163ce979fd2)), closes [#121](https://www.github.com/googleapis/python-storage/issues/121)
+
+
+* add if*generation*match support for Bucket.rename_blob() ([#141](https://www.github.com/googleapis/python-storage/issues/141)) ([f52efc8](https://www.github.com/googleapis/python-storage/commit/f52efc807355c82aa3ea621cdadcc316175f0abf))
+
+
+* add if*generation*Match support, pt1 ([#123](https://www.github.com/googleapis/python-storage/issues/123)) ([0944442](https://www.github.com/googleapis/python-storage/commit/094444280dd7b7735e24071e5381508cbd392260))
+
+
+* add offset and includeTrailingPrefix options to list_blobs ([#125](https://www.github.com/googleapis/python-storage/issues/125)) ([d84c0dd](https://www.github.com/googleapis/python-storage/commit/d84c0ddfd00fa731acfe9899c668041456b08ab7))
+
+
+* Create CODEOWNERS ([#135](https://www.github.com/googleapis/python-storage/issues/135)) ([32a8d55](https://www.github.com/googleapis/python-storage/commit/32a8d55b6ec56a9f7c0a3502fbe23c1ba1cc8ad2))
+
+### Bug Fixes
+
+
+* add documentaion of list_blobs with user project ([#147](https://www.github.com/googleapis/python-storage/issues/147)) ([792b21f](https://www.github.com/googleapis/python-storage/commit/792b21fd2263b518d56f79cab6a4a1bb06c6e4e7))
+
+
+* add projection parameter to blob.reload method ([#146](https://www.github.com/googleapis/python-storage/issues/146)) ([ddad20b](https://www.github.com/googleapis/python-storage/commit/ddad20b3c3d2e6bf482e34dad85fa4b0ff90e1b1))
+
+
+* add unused variables to method generation match ([#152](https://www.github.com/googleapis/python-storage/issues/152)) ([f6574bb](https://www.github.com/googleapis/python-storage/commit/f6574bb84c60c30989d05dba97b423579360cdb2))
+
+
+* change the method names in snippets file ([#161](https://www.github.com/googleapis/python-storage/issues/161)) ([e516ed9](https://www.github.com/googleapis/python-storage/commit/e516ed9be518e30df4e201d3242f979c0b081086))
+
+
+* fix upload object with bucket cmek enabled ([#158](https://www.github.com/googleapis/python-storage/issues/158)) ([5f27ffa](https://www.github.com/googleapis/python-storage/commit/5f27ffa3b1b55681453b594a0ef9e2811fc5f0c8))
+
+
+* set default POST policy scheme to “http” ([#172](https://www.github.com/googleapis/python-storage/issues/172)) ([90c020d](https://www.github.com/googleapis/python-storage/commit/90c020d69a69ebc396416e4086a2e0838932130c))
+
+## [1.28.1](https://www.github.com/googleapis/python-storage/compare/v1.28.0...v1.28.1) (2020-04-28)
+
+### Bug Fixes
+
+
+* anonymous credentials for private bucket ([#107](https://www.github.com/googleapis/python-storage/issues/107)) ([6152ab4](https://www.github.com/googleapis/python-storage/commit/6152ab4067d39ba824f9b6a17b83859dd7236cec))
+
+
+* add bucket name into POST policy conditions ([#118](https://www.github.com/googleapis/python-storage/issues/118)) ([311ecab](https://www.github.com/googleapis/python-storage/commit/311ecabf8acc3018cef0697dd29483693f7722b9))
+
+## [1.28.0](https://www.github.com/googleapis/python-storage/compare/v1.27.0...v1.28.0) (2020-04-22)
+
+### Features
+
+
+* add arguments for \*GenerationMatch uploading options ([#111](https://www.github.com/googleapis/python-storage/issues/111)) ([b11aa5f](https://www.github.com/googleapis/python-storage/commit/b11aa5f00753b094580847bc62c154ae0e584dbc))
+
+### Bug Fixes
+
+
+* fix incorrect mtime by UTC offset ([#42](https://www.github.com/googleapis/python-storage/issues/42)) ([76bd652](https://www.github.com/googleapis/python-storage/commit/76bd652a3078d94e03e566b6a387fc488ab26910))
+
+
+* remove expiration strict conversion ([#106](https://www.github.com/googleapis/python-storage/issues/106)) ([9550dad](https://www.github.com/googleapis/python-storage/commit/9550dad6e63e249110fc9dcda245061b76dacdcf)), closes [#105](https://www.github.com/googleapis/python-storage/issues/105)
+
+## [1.27.0](https://www.github.com/googleapis/python-storage/compare/v1.26.0...v1.27.0) (2020-04-01)
+
+### Features
+
+
+* generate signed URLs for blobs/buckets using virtual hostname ([#58](https://www.github.com/googleapis/python-storage/issues/58)) ([23df542](https://www.github.com/googleapis/python-storage/commit/23df542d0669852b05139023d5ef1ae14a09f4c7))
+
+
+* Add cname support for V4 signature ([#72](https://www.github.com/googleapis/python-storage/issues/72)) ([cc853af](https://www.github.com/googleapis/python-storage/commit/cc853af6bf8e44e5b16e8cdfb3a275629ffb1f27))
+
+
+* add conformance tests for virtual hosted style signed URLs ([#83](https://www.github.com/googleapis/python-storage/issues/83)) ([5adc8b0](https://www.github.com/googleapis/python-storage/commit/5adc8b0e6ffe28185a4085cd1fc8c1b4998094aa))
+
+
+* add get notification method ([#77](https://www.github.com/googleapis/python-storage/issues/77)) ([f602252](https://www.github.com/googleapis/python-storage/commit/f6022521bee0824e1b291211703afc5eae6c6891))
+
+
+* improve v4 signature query parameters encoding ([#48](https://www.github.com/googleapis/python-storage/issues/48)) ([8df0b55](https://www.github.com/googleapis/python-storage/commit/8df0b554a1904787889309707f08c6b8683cad44))
+
+### Bug Fixes
+
+
+* fix blob metadata to None regression ([#60](https://www.github.com/googleapis/python-storage/issues/60)) ([a834d1b](https://www.github.com/googleapis/python-storage/commit/a834d1b54aa96152ced4d841c4e0c241acd2d8d8))
+
+
+* add classifer for Python 3.8 ([#63](https://www.github.com/googleapis/python-storage/issues/63)) ([1b9b6bc](https://www.github.com/googleapis/python-storage/commit/1b9b6bc2601ee336a8399266852fb850e368b30a))
+
+
+* make v4 signing formatting consistent w/ spec ([#56](https://www.github.com/googleapis/python-storage/issues/56)) ([8712da8](https://www.github.com/googleapis/python-storage/commit/8712da84c93600a736e72a097c42a49b4724347d))
+
+
+* use correct IAM object admin role ([#71](https://www.github.com/googleapis/python-storage/issues/71)) ([2e27edd](https://www.github.com/googleapis/python-storage/commit/2e27edd3fe65cd5e17c12bf11f2b58f611937d61))
+
+
+* remove docstring of retrun in reload method ([#78](https://www.github.com/googleapis/python-storage/issues/78)) ([4abeb1c](https://www.github.com/googleapis/python-storage/commit/4abeb1c0810c4e5d716758536da9fc204fa4c2a9))
+
+
+* use OrderedDict while encoding POST policy ([#95](https://www.github.com/googleapis/python-storage/issues/95)) ([df560e1](https://www.github.com/googleapis/python-storage/commit/df560e178369a6d03140e412a25af6ec7444f5a1))
+
+## [1.26.0](https://www.github.com/googleapis/python-storage/compare/v1.25.0...v1.26.0) (2020-02-12)
+
+### Features
+
+
+* add support for signing URLs using token ([#9889](https://www.github.com/googleapis/google-cloud-python/issues/9889)) ([ad280bf](https://www.github.com/googleapis/python-storage/commit/ad280bf506d3d7a37c402d06eac07422a5fe80af))
+
+
+* add timeout parameter to public methods ([#44](https://www.github.com/googleapis/python-storage/issues/44)) ([63abf07](https://www.github.com/googleapis/python-storage/commit/63abf0778686df1caa001270dd22f9df0daf0c78))
+
+### Bug Fixes
+
+
+* fix documentation of max_result parameter in list_blob ([#43](https://www.github.com/googleapis/python-storage/issues/43)) ([ff15f19](https://www.github.com/googleapis/python-storage/commit/ff15f19d3a5830acdd540181dc6e9d07ca7d88ee))
+
+
+* fix system test and change scope for iam access token ([#47](https://www.github.com/googleapis/python-storage/issues/47)) ([bc5375f](https://www.github.com/googleapis/python-storage/commit/bc5375f4c88f7e6ad1afbe7667c49d9a846e9757))
+
+
+* remove low version error assertion from iam conditions system tests ([#53](https://www.github.com/googleapis/python-storage/issues/53)) ([8904aee](https://www.github.com/googleapis/python-storage/commit/8904aee9ad5dc01ab83e1460b6f186a739668eb7))
+
+## 1.25.0
+
+01-16-2020 11:00 PST
+
+### Implementation Changes
+
+
+* fix: replace unsafe six.PY3 with PY2 for better future compatibility with Python 4 ([#10081](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/10081))
+
+
+* fix(storage): fix document of delete blob ([#10015](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/10015))
+
+### New Features
+
+
+* feat(storage): support optionsRequestedPolicyVersion ([#9989](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/9989))
+
+### Dependencies
+
+
+* chore(storage): bump core dependency to 1.2.0 ([#10160](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/10160))
+
+## 1.24.1
+
+01-02-2020 13:20 PST
+
+### Implementation Changes
+
+
+* Add ‘ARCHIVE’ storage class ([#9533](https://github.com/googleapis/google-cloud-python/pull/9533))
+
+## 1.24.0
+
+01-02-2020 10:39 PST
+
+### Implementation Changes
+
+-str() metadata for for blob ([#9796](https://github.com/googleapis/google-cloud-python/pull/9796))
+
+### New Features
+
+
+* Add timeout parameter to Batch interface to match google-cloud-core ([#10010](https://github.com/googleapis/google-cloud-python/pull/10010))
+
+## 1.23.0
+
+11-12-2019 12:57 PST
+
+### Implementation Changes
+
+
+* Move `create_bucket` implementation from `Bucket` to `Client`. ([#8604](https://github.com/googleapis/google-cloud-python/pull/8604))
+
+### New Features
+
+
+* Add opt-in raw download support. ([#9572](https://github.com/googleapis/google-cloud-python/pull/9572))
+
+### Dependencies
+
+
+* Pin `google-resumable-media >= 0.5.0, < 0.6dev`. ([#9572](https://github.com/googleapis/google-cloud-python/pull/9572))
+
+### Documentation
+
+
+* Add python 2 sunset banner to documentation. ([#9036](https://github.com/googleapis/google-cloud-python/pull/9036))
+
+### Internal / Testing Changes
+
+
+* Fix query-string order dependent assert. ([#9728](https://github.com/googleapis/google-cloud-python/pull/9728))
+
+
+* Normalize VPCSC configuration in system tests. ([#9616](https://github.com/googleapis/google-cloud-python/pull/9616))
+
+## 1.22.0
+
+11-05-2019 10:22 PST
+
+### New Features
+
+
+* Add UBLA attrs to IAMConfiguration. ([#9475](https://github.com/googleapis/google-cloud-python/pull/9475))
+
+## 1.21.0
+
+10-28-2019 21:52 PDT
+
+### Implementation Changes
+
+
+* Add gcloud-python header to user agent ([#9551](https://github.com/googleapis/google-cloud-python/pull/9551))
+
+
+* Don’t report a gapic version for storage ([#9549](https://github.com/googleapis/google-cloud-python/pull/9549))
+
+
+* Update storage endpoint from www.googleapis.com to storage.googleapis.com ([#9543](https://github.com/googleapis/google-cloud-python/pull/9543))
+
+
+* Call anonymous client method to remove dependency of google application credentials ([#9455](https://github.com/googleapis/google-cloud-python/pull/9455))
+
+
+* Enable CSEK w/ V4 signed URLs ([#9450](https://github.com/googleapis/google-cloud-python/pull/9450))
+
+### New Features
+
+
+* Support predefined ACLs in `Bucket.create` ([#9334](https://github.com/googleapis/google-cloud-python/pull/9334))
+
+### Documentation
+
+
+* Add `hmac_key` and notification documentation rst files ([#9529](https://github.com/googleapis/google-cloud-python/pull/9529))
+
+
+* Remove references to the old authentication credentials ([#9456](https://github.com/googleapis/google-cloud-python/pull/9456))
+
+
+* Clarify docstring for `Blob.download_as_string` ([#9332](https://github.com/googleapis/google-cloud-python/pull/9332))
+
+## 1.20.0
+
+09-26-2019 06:45 PDT
+
+### New Features
+
+
+* Add `user_project` param to HMAC-related methods. ([#9237](https://github.com/googleapis/google-cloud-python/pull/9237))
+
+
+* Add `Blob.from_string` and `Bucket.from_string` factories. ([#9143](https://github.com/googleapis/google-cloud-python/pull/9143))
+
+### Documentation
+
+
+* Fix intersphinx reference to `requests`. ([#9294](https://github.com/googleapis/google-cloud-python/pull/9294))
+
+
+* Fix deep / broken URL for service account setup. ([#9164](https://github.com/googleapis/google-cloud-python/pull/9164))
+
+### Internal / Testing Changes
+
+
+* Fix typo in `_helpers.py`. ([#9239](https://github.com/googleapis/google-cloud-python/pull/9239))
+
+
+* In systests, retry bucket creation on 503. ([#9248](https://github.com/googleapis/google-cloud-python/pull/9248))
+
+
+* Avoid using `REGIONAL` / `MULTI_REGIONAL` in examples, tests. ([#9205](https://github.com/googleapis/google-cloud-python/pull/9205))
+
+
+* Move `benchwrapper` into `tests/perf`. ([#9246](https://github.com/googleapis/google-cloud-python/pull/9246))
+
+
+* Add support for `STORAGE_EMULATOR_HOST`; add `benchwrapper` script. ([#9219](https://github.com/googleapis/google-cloud-python/pull/9219))
+
+## 1.19.0
+
+08-28-2019 09:45 PDT
+
+### Implementation Changes
+
+
+* Expose ‘HMACKeyMetadata.id’ field. ([#9115](https://github.com/googleapis/google-cloud-python/pull/9115))
+
+
+* Make ‘Blob.bucket’ a readonly property. ([#9113](https://github.com/googleapis/google-cloud-python/pull/9113))
+
+
+* Clarify ‘response_type’ for signed_url methods. ([#8942](https://github.com/googleapis/google-cloud-python/pull/8942))
+
+### New Features
+
+
+* Add `client_options` to constructors for manual clients. ([#9054](https://github.com/googleapis/google-cloud-python/pull/9054))
+
+### Documentation
+
+
+* Remove compatability badges from READMEs. ([#9035](https://github.com/googleapis/google-cloud-python/pull/9035))
+
+### Internal / Testing Changes
+
+
+* Remove CI for gh-pages, use googleapis.dev for api_core refs. ([#9085](https://github.com/googleapis/google-cloud-python/pull/9085))
+
+
+* Fix tests broken by yesterday’s google-resumable-media release. ([#9119](https://github.com/googleapis/google-cloud-python/pull/9119))
+
+
+* Harden ‘test_access_to_public_bucket’ systest against 429 / 503 errors. ([#8997](https://github.com/googleapis/google-cloud-python/pull/8997))
+
+## 1.18.0
+
+08-07-2019 00:37 PDT
+
+### New Features
+
+
+* Add HMAC key support. ([#8430](https://github.com/googleapis/google-cloud-python/pull/8430))
+
+### Documentation
+
+
+* Mark old storage classes as legacy, not deprecated. ([#8887](https://github.com/googleapis/google-cloud-python/pull/8887))
+
+### Internal / Testing Changes
+
+
+* Normalize ‘lint’ / ‘blacken’ support under nox. ([#8831](https://github.com/googleapis/google-cloud-python/pull/8831))
+
+
+* Update intersphinx mapping for requests. ([#8805](https://github.com/googleapis/google-cloud-python/pull/8805))
+
+## 1.17.0
+
+07-24-2019 12:37 PDT
+
+### New Features
+
+
+* Add `Bucket.location_type` property. ([#8570](https://github.com/googleapis/google-cloud-python/pull/8570))
+
+
+* Add `Client.list_blobs(bucket_or_name)`. ([#8375](https://github.com/googleapis/google-cloud-python/pull/8375))
+
+### Implementation Changes
+
+
+* Retry bucket creation in signing setup. ([#8620](https://github.com/googleapis/google-cloud-python/pull/8620))
+
+
+* Fix URI -> blob name conversion in `Client download_blob_to_file`. ([#8440](https://github.com/googleapis/google-cloud-python/pull/8440))
+
+
+* Avoid escaping tilde in blob public / signed URLs. ([#8434](https://github.com/googleapis/google-cloud-python/pull/8434))
+
+
+* Add generation to ‘Blob.**repr**’. ([#8423](https://github.com/googleapis/google-cloud-python/pull/8423))
+
+### Documentation
+
+
+* Link to googleapis.dev documentation in READMEs. ([#8705](https://github.com/googleapis/google-cloud-python/pull/8705))
+
+
+* Add compatibility check badges to READMEs. ([#8288](https://github.com/googleapis/google-cloud-python/pull/8288))
+
+
+* Fix example in `Client.download_blob_to_file` docstring. ([#8629](https://github.com/googleapis/google-cloud-python/pull/8629))
+
+
+* Remove typing information for kwargs to not conflict with type checkers ([#8546](https://github.com/googleapis/google-cloud-python/pull/8546))
+
+### Internal / Testing Changes
+
+
+* Skip failing `test_bpo_set_unset_preserves_acls` systest. ([#8617](https://github.com/googleapis/google-cloud-python/pull/8617))
+
+
+* Add nox session ‘docs’. ([#8478](https://github.com/googleapis/google-cloud-python/pull/8478))
+
+
+* Add docs job to publish to googleapis.dev. ([#8464](https://github.com/googleapis/google-cloud-python/pull/8464))
+
+## 1.16.1
+
+06-04-2019 11:09 PDT
+
+### Dependencies
+
+
+* Don’t pin `google-api-core` in libs using `google-cloud-core`. ([#8213](https://github.com/googleapis/google-cloud-python/pull/8213))
+
+### Documentation
+
+
+* Fix example in `download_blob_to_file` docstring. ([#8201](https://github.com/googleapis/google-cloud-python/pull/8201))
+
+
+* Tweak `fields` docstring further. ([#8040](https://github.com/googleapis/google-cloud-python/pull/8040))
+
+
+* Improve docs for `fields` argument to `Bucket.list_blobs`. ([#8023](https://github.com/googleapis/google-cloud-python/pull/8023))
+
+
+* Fix docs typo. ([#8027](https://github.com/googleapis/google-cloud-python/pull/8027))
+
+### Internal / Testing Changes
+
+
+* Retry harder in face of 409/429 during module teardown. ([#8113](https://github.com/googleapis/google-cloud-python/pull/8113))
+
+
+* Add more retries for 429s during teardown operations. ([#8112](https://github.com/googleapis/google-cloud-python/pull/8112))
+
+## 1.16.0
+
+05-16-2019 12:55 PDT
+
+### New Features
+
+
+* Update `Client.create_bucket` to take a Bucket object or string. ([#7820](https://github.com/googleapis/google-cloud-python/pull/7820))
+
+
+* Update `Client.get_bucket` to take a `Bucket` object or string. ([#7856](https://github.com/googleapis/google-cloud-python/pull/7856))
+
+
+* Add `Client.download_blob_to_file` method. ([#7949](https://github.com/googleapis/google-cloud-python/pull/7949))
+
+
+* Add `client_info` support to client / connection. ([#7872](https://github.com/googleapis/google-cloud-python/pull/7872))
+
+### Dependencies
+
+
+* Pin `google-cloud-core >= 1.0.0, < 2.0dev`. ([#7993](https://github.com/googleapis/google-cloud-python/pull/7993))
+
+
+* Pin `google-auth >= 1.2.0`. ([#7798](https://github.com/googleapis/google-cloud-python/pull/7798))
+
+## 1.15.0
+
+04-17-2019 15:37 PDT
+
+### New Features
+
+
+* Add support for V4 signed URLs ([#7460](https://github.com/googleapis/google-cloud-python/pull/7460))
+
+
+* Add generation arguments to bucket / blob methods. ([#7444](https://github.com/googleapis/google-cloud-python/pull/7444))
+
+### Implementation Changes
+
+
+* Remove classifier for Python 3.4 for end-of-life. ([#7535](https://github.com/googleapis/google-cloud-python/pull/7535))
+
+
+* Ensure that ‘Blob.reload’ passes encryption headers. ([#7441](https://github.com/googleapis/google-cloud-python/pull/7441))
+
+### Documentation
+
+
+* Update client library documentation URLs. ([#7307](https://github.com/googleapis/google-cloud-python/pull/7307))
+
+### Internal / Testing Changes
+
+
+* Fix failing system tests ([#7714](https://github.com/googleapis/google-cloud-python/pull/7714))
+
+
+* Increase number of retries for 429 errors. ([#7484](https://github.com/googleapis/google-cloud-python/pull/7484))
+
+
+* Un-flake KMS integration tests expecting empty bucket. ([#7479](https://github.com/googleapis/google-cloud-python/pull/7479))
+
+## 1.14.0
+
+02-06-2019 12:49 PST
+
+### New Features
+
+
+* Add ‘Bucket.iam_configuration’ property, enabling Bucket-Policy-Only. ([#7066](https://github.com/googleapis/google-cloud-python/pull/7066))
+
+### Documentation
+
+
+* Improve docs for ‘generate_signed_url’. ([#7201](https://github.com/googleapis/google-cloud-python/pull/7201))
+
+## 1.13.2
+
+12-17-2018 17:02 PST
+
+### Implementation Changes
+
+
+* Update `Blob.update_storage_class` to support rewrite tokens. ([#6527](https://github.com/googleapis/google-cloud-python/pull/6527))
+
+### Internal / Testing Changes
+
+
+* Skip signing tests for insufficient credentials ([#6917](https://github.com/googleapis/google-cloud-python/pull/6917))
+
+
+* Document Python 2 deprecation ([#6910](https://github.com/googleapis/google-cloud-python/pull/6910))
+
+
+* Normalize docs for `page_size` / `max_results` / `page_token`. ([#6842](https://github.com/googleapis/google-cloud-python/pull/6842))
+
+## 1.13.1
+
+12-10-2018 13:31 PST
+
+### Implementation Changes
+
+
+* Import `iam.policy` from `google.api_core`. ([#6741](https://github.com/googleapis/google-cloud-python/pull/6741))
+
+
+* Accomodate new back-end restriction on retention period. ([#6388](https://github.com/googleapis/google-cloud-python/pull/6388))
+
+
+* Avoid deleting a blob renamed to itself ([#6365](https://github.com/googleapis/google-cloud-python/pull/6365))
+
+### Dependencies
+
+
+* Update dependency to google-cloud-core ([#6835](https://github.com/googleapis/google-cloud-python/pull/6835))
+
+
+* Bump minimum `api_core` version for all GAPIC libs to 1.4.1. ([#6391](https://github.com/googleapis/google-cloud-python/pull/6391))
+
+### Documentation
+
+
+* Normalize use of support level badges ([#6159](https://github.com/googleapis/google-cloud-python/pull/6159))
+
+### Internal / Testing Changes
+
+
+* Blacken libraries ([#6794](https://github.com/googleapis/google-cloud-python/pull/6794))
+
+
+* Add templates for flake8, coveragerc, noxfile, and black. ([#6642](https://github.com/googleapis/google-cloud-python/pull/6642))
+
+
+* Harden teardown in system tests. ([#6444](https://github.com/googleapis/google-cloud-python/pull/6444))
+
+
+* Harden `create_bucket` call in systests vs. 429 TooManyRequests. ([#6401](https://github.com/googleapis/google-cloud-python/pull/6401))
+
+
+* Skip public bucket test in VPC Service Controls  ([#6230](https://github.com/googleapis/google-cloud-python/pull/6230))
+
+
+* Fix lint failure. ([#6219](https://github.com/googleapis/google-cloud-python/pull/6219))
+
+
+* Disable test running in VPC Service Controls  restricted environment ([#6215](https://github.com/googleapis/google-cloud-python/pull/6215))
+
+
+* Use new Nox ([#6175](https://github.com/googleapis/google-cloud-python/pull/6175))
+
+## 1.13.0
+
+### New Features
+
+
+* Add support for bucket retention policies ([#5534](https://github.com/googleapis/google-cloud-python/pull/5534))
+
+
+* Allow `destination.content_type` to be None in `Blob.compose`. ([#6031](https://github.com/googleapis/google-cloud-python/pull/6031))
+
+### Implementation Changes
+
+
+* Ensure that `method` for `Blob.generate_signed_url` is uppercase. ([#6110](https://github.com/googleapis/google-cloud-python/pull/6110))
+
+### Documentation
+
+
+* Clarify GCS URL signing limitations on GCE ([#6104](https://github.com/googleapis/google-cloud-python/pull/6104))
+
+
+* Redirect renamed ‘usage.html’/’client.html’ -> ‘index.html’. ([#5996](https://github.com/googleapis/google-cloud-python/pull/5996))
+
+## 1.12.0
+
+### New Features
+
+
+* Add support for Python 3.7, drop support for Python 3.4. ([#5942](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/5942))
+
+
+* Add lifecycle rules helpers to bucket. ([#5877](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/5877))
+
+### Implementation Changes
+
+
+* Add ‘stacklevel=2’ to deprecation warnings. ([#5897](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/5897))
+
+### Documentation
+
+
+* Storage docs: fix typos. ([#5933](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/5933))
+
+
+* Prep storage docs for repo split. ([#5923](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/5923))
+
+### Internal / Testing Changes
+
+
+* Harden systest teardown further. ([#5900](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/5900))
+
+
+* Nox: use inplace installs ([#5865](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/5865))
+
+## 1.11.0
+
+### Implementation Changes
+
+
+* Preserve message / args from an `InvalidResponse`. (#5492)
+
+
+* Fix generating signed urls for blobs with non-ascii names. (#5625)
+
+
+* Move bucket location specification to `Bucket.create`; deprecate `Bucket.location` setter (#5808)
+
+### New Features
+
+
+* Add `Client.get_service_account_email`. (#5765)
+
+### Documentation
+
+
+* Clarify `None` values for resource-backed properties. (#5509)
+
+
+* Elaborate docs for `{Bucket,Blob}.make_{public,private}`; note how to enable anonymous accesss to `Blob.public_url`. (#5767)
+
+### Internal / Testing Changes
+
+
+* Harden `create_bucket` systest against 429 responses. (#5535)
+
+
+* Add system test: signed URLs w/ non-ASCII blob name. (#5626)
+
+
+* Harden `tearDownModule` against 429 TooManyRequests. (#5701)
+
+
+* Retry `notification.create()` on `503 ServiceUnavailable`. (#5741)
+
+
+* Fix failing KMS system tests. (#5832, #5837, #5860)
+
+## 1.10.0
+
+### New Features
+
+
+* Add support for KMS keys (#5259)
+
+
+* Add `{Blob,Bucket}make_private` method (#5336)
+
+### Internal / Testing Changes
+
+
+* Modify system tests to use prerelease versions of grpcio (#5304)
+
+## 1.9.0
+
+### Implementation Changes
+
+
+* Change GCS batch endpoint from `/batch` to `/batch/storage/v1` (#5040)
+
+### New Features
+
+
+* Allow uploading files larger than 2GB by using Resumable Media Requests (#5187)
+
+
+* Add range downloads (#5081)
+
+### Documentation
+
+
+* Update docstring to reflect correct units (#5277)
+
+
+* Replace link to 404 object IAM docs with a note on limited utility. (#5181)
+
+
+* Update doc reference in GCS client documentation (#5084)
+
+
+* Add see also for `Bucket.create` method call for `Client.create_bucket()` documentation. (#5073)
+
+
+* Link out to requester pays docs. (#5065)
+
+### Internal / Testing Changes
+
+
+* Add testing support for Python 3.7; remove testing support for Python 3.4. (#5295)
+
+
+* Fix bad trove classifier
+
+
+* Remove unused var (flake8 warning) (#5280)
+
+
+* Fix unit test moving batch to batch/storage/v1 (#5082)
+
+## 1.8.0
+
+### New features
+
+
+* Implement predefined acl (#4757)
+
+
+* Add support for resumable signed url generation (#4789)
+
+### Implementation changes
+
+
+* Do not quote embedded slashes for public / signed URLs (#4716)
+
+### Dependencies
+
+
+* Update dependency range for api-core to include v1.0.0 releases (#4944)
+
+### Documentation
+
+
+* Missing word in docstring (#4763)
+
+### Testing and internal changes
+
+
+* Install local dependencies when running lint (#4936)
+
+
+* Re-enable lint for tests, remove usage of pylint (#4921)
+
+
+* Normalize all setup.py files (#4909)
+
+## 1.7.0
+
+### Features
+
+
+* Enable anonymous access to blobs in public buckets (#4315)
+
+
+* Make project optional / overridable for storage client (#4381)
+
+
+* Relax regex used to test for valid project IDs (#4543)
+
+
+* Add support for `source_generation` parameter to `Bucket.copy_blob` (#4546)
+
+## 1.6.0
+
+### Documentation
+
+
+* Added link to “Python Development Environment Setup Guide” in
+project README (#4187, h/t to @michaelawyu)
+
+### Dependencies
+
+
+* Upgrading to `google-cloud-core >= 0.28.0` and adding dependency
+on `google-api-core` (#4221, #4280)
+
+
+* Requiring `google-resumable-media >= 0.3.1` (#4244)
+
+PyPI: https://pypi.org/project/google-cloud-storage/1.6.0/
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.acl.ACL.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.acl.ACL.yml
new file mode 100644
index 000000000000..1737527146d1
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.acl.ACL.yml
@@ -0,0 +1,786 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes: []
+  children:
+  - google.cloud.storage.acl.ACL.PREDEFINED_JSON_ACLS
+  - google.cloud.storage.acl.ACL.add_entity
+  - google.cloud.storage.acl.ACL.all
+  - google.cloud.storage.acl.ACL.all_authenticated
+  - google.cloud.storage.acl.ACL.clear
+  - google.cloud.storage.acl.ACL.client
+  - google.cloud.storage.acl.ACL.domain
+  - google.cloud.storage.acl.ACL.entity
+  - google.cloud.storage.acl.ACL.entity_from_dict
+  - google.cloud.storage.acl.ACL.get_entities
+  - google.cloud.storage.acl.ACL.get_entity
+  - google.cloud.storage.acl.ACL.group
+  - google.cloud.storage.acl.ACL.has_entity
+  - google.cloud.storage.acl.ACL.reload
+  - google.cloud.storage.acl.ACL.reset
+  - google.cloud.storage.acl.ACL.save
+  - google.cloud.storage.acl.ACL.save_predefined
+  - google.cloud.storage.acl.ACL.user
+  - google.cloud.storage.acl.ACL.validate_predefined
+  class: google.cloud.storage.acl.ACL
+  fullName: google.cloud.storage.acl.ACL
+  inheritance:
+  - type: builtins.object
+  langs:
+  - python
+  module: google.cloud.storage.acl
+  name: ACL
+  source:
+    id: ACL
+    path: tests/testdata/handwritten/google/cloud/storage/acl.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/handwritten/google/cloud/storage/acl.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 105
+  summary: 'Container class representing a list of access controls.
+
+
+    '
+  syntax:
+    content: ACL()
+    parameters: []
+  type: class
+  uid: google.cloud.storage.acl.ACL
+- attributes: []
+  class: google.cloud.storage.acl.ACL
+  fullName: google.cloud.storage.acl.ACL.PREDEFINED_JSON_ACLS
+  langs:
+  - python
+  module: google.cloud.storage.acl
+  name: PREDEFINED_JSON_ACLS
+  source:
+    id: PREDEFINED_JSON_ACLS
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'See
+
+    https://cloud.google.com/storage/docs/access-control/lists#predefined-acl
+
+
+    '
+  syntax: {}
+  type: attribute
+  uid: google.cloud.storage.acl.ACL.PREDEFINED_JSON_ACLS
+- attributes: []
+  class: google.cloud.storage.acl.ACL
+  fullName: google.cloud.storage.acl.ACL.add_entity
+  langs:
+  - python
+  module: google.cloud.storage.acl
+  name: add_entity
+  source:
+    id: add_entity
+    path: tests/testdata/handwritten/google/cloud/storage/acl.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/handwritten/google/cloud/storage/acl.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 250
+  summary: 'Add an entity to the ACL.
+
+    '
+  syntax:
+    content: add_entity(entity)
+    parameters:
+    - description: The entity to add to this ACL.
+      id: entity
+      var_type: _ACLEntity
+  type: method
+  uid: google.cloud.storage.acl.ACL.add_entity
+- attributes: []
+  class: google.cloud.storage.acl.ACL
+  fullName: google.cloud.storage.acl.ACL.all
+  langs:
+  - python
+  module: google.cloud.storage.acl
+  name: all
+  source:
+    id: all
+    path: tests/testdata/handwritten/google/cloud/storage/acl.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/handwritten/google/cloud/storage/acl.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 318
+  summary: 'Factory method for an Entity representing all users.
+
+    '
+  syntax:
+    content: all()
+    parameters: []
+    returns:
+    - description: An entity representing all users.
+      var_type: _ACLEntity
+  type: method
+  uid: google.cloud.storage.acl.ACL.all
+- attributes: []
+  class: google.cloud.storage.acl.ACL
+  fullName: google.cloud.storage.acl.ACL.all_authenticated
+  langs:
+  - python
+  module: google.cloud.storage.acl
+  name: all_authenticated
+  source:
+    id: all_authenticated
+    path: tests/testdata/handwritten/google/cloud/storage/acl.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/handwritten/google/cloud/storage/acl.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 326
+  summary: 'Factory method for an Entity representing all authenticated users.
+
+    '
+  syntax:
+    content: all_authenticated()
+    parameters: []
+    returns:
+    - description: An entity representing all authenticated users.
+      var_type: _ACLEntity
+  type: method
+  uid: google.cloud.storage.acl.ACL.all_authenticated
+- attributes: []
+  class: google.cloud.storage.acl.ACL
+  fullName: google.cloud.storage.acl.ACL.clear
+  langs:
+  - python
+  module: google.cloud.storage.acl
+  name: clear
+  source:
+    id: clear
+    path: tests/testdata/handwritten/google/cloud/storage/acl.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/handwritten/google/cloud/storage/acl.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 621
+  summary: 'Remove all ACL entries.
+
+
+    If `user_project` is set, bills the API request to that project.
+
+
+    Note that this won''t actually remove *ALL* the rules, but it
+
+    will remove all the non-default rules.  In short, you''ll still
+
+    have access to a bucket that you created even after you clear
+
+    ACL rules with this method.
+
+    '
+  syntax:
+    content: clear(client=None, if_generation_match=None, if_generation_not_match=None,
+      if_metageneration_match=None, if_metageneration_not_match=None, timeout=60,
+      retry=)
+    parameters:
+    - description: (Optional) The client to use. If not passed, falls back to the
+        client stored on the ACL's parent.
+      id: client
+      var_type: Client or NoneType
+    - description: (Optional) See :ref:using-if-generation-match
+      id: if_generation_match
+      var_type: long
+    - description: (Optional) See :ref:using-if-generation-not-match
+      id: if_generation_not_match
+      var_type: long
+    - description: (Optional) See :ref:using-if-metageneration-match
+      id: if_metageneration_match
+      var_type: long
+    - description: (Optional) See :ref:using-if-metageneration-not-match
+      id: if_metageneration_not_match
+      var_type: long
+    - description: '(Optional) The amount of time, in seconds, to wait for the server
+        response. See: configuring_timeouts'
+      id: timeout
+      var_type: float or tuple
+    - description: '(Optional) How to retry the RPC. See: configuring_retries'
+      id: retry
+      var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy
+  type: method
+  uid: google.cloud.storage.acl.ACL.clear
+- &id001
+  attributes: []
+  class: google.cloud.storage.acl.ACL
+  fullName: google.cloud.storage.acl.ACL.client
+  langs:
+  - python
+  module: google.cloud.storage.acl
+  name: client
+  source:
+    id: client
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Abstract getter for the object client.
+
+
+    '
+  syntax: {}
+  type: property
+  uid: google.cloud.storage.acl.ACL.client
+- *id001
+- attributes: []
+  class: google.cloud.storage.acl.ACL
+  fullName: google.cloud.storage.acl.ACL.domain
+  langs:
+  - python
+  module: google.cloud.storage.acl
+  name: domain
+  source:
+    id: domain
+    path: tests/testdata/handwritten/google/cloud/storage/acl.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/handwritten/google/cloud/storage/acl.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 307
+  summary: 'Factory method for a domain Entity.
+
+    '
+  syntax:
+    content: domain(domain)
+    parameters:
+    - description: The domain for this entity.
+      id: domain
+      var_type: str
+    returns:
+    - description: An entity corresponding to this domain.
+      var_type: _ACLEntity
+  type: method
+  uid: google.cloud.storage.acl.ACL.domain
+- attributes: []
+  class: google.cloud.storage.acl.ACL
+  fullName: google.cloud.storage.acl.ACL.entity
+  langs:
+  - python
+  module: google.cloud.storage.acl
+  name: entity
+  source:
+    id: entity
+    path: tests/testdata/handwritten/google/cloud/storage/acl.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/handwritten/google/cloud/storage/acl.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 259
+  summary: 'Factory method for creating an Entity.
+
+
+    If an entity with the same type and identifier already exists,
+
+    this will return a reference to that entity.  If not, it will
+
+    create a new one and add it to the list of known entities for
+
+    this ACL.
+
+    '
+  syntax:
+    content: entity(entity_type, identifier=None)
+    parameters:
+    - description: The type of entity to create (ie, user, group,
+        etc)
+      id: entity_type
+      var_type: str
+    - description: The ID of the entity (if applicable). This can be either an ID
+        or an e-mail address.
+      id: identifier
+      var_type: str
+    returns:
+    - description: A new Entity or a reference to an existing identical entity.
+      var_type: _ACLEntity
+  type: method
+  uid: google.cloud.storage.acl.ACL.entity
+- attributes: []
+  class: google.cloud.storage.acl.ACL
+  fullName: google.cloud.storage.acl.ACL.entity_from_dict
+  langs:
+  - python
+  module: google.cloud.storage.acl
+  name: entity_from_dict
+  source:
+    id: entity_from_dict
+    path: tests/testdata/handwritten/google/cloud/storage/acl.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/handwritten/google/cloud/storage/acl.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 189
+  summary: 'Build an _ACLEntity object from a dictionary of data.
+
+
+    An entity is a mutable object that represents a list of roles
+
+    belonging to either a user or group or the special types for all
+
+    users and all authenticated users.
+
+    '
+  syntax:
+    content: entity_from_dict(entity_dict)
+    parameters:
+    - description: Dictionary full of data from an ACL lookup.
+      id: entity_dict
+      var_type: dict
+    returns:
+    - description: An Entity constructed from the dictionary.
+      var_type: _ACLEntity
+  type: method
+  uid: google.cloud.storage.acl.ACL.entity_from_dict
+- attributes: []
+  class: google.cloud.storage.acl.ACL
+  fullName: google.cloud.storage.acl.ACL.get_entities
+  langs:
+  - python
+  module: google.cloud.storage.acl
+  name: get_entities
+  source:
+    id: get_entities
+    path: tests/testdata/handwritten/google/cloud/storage/acl.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/handwritten/google/cloud/storage/acl.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 334
+  summary: 'Get a list of all Entity objects.
+
+    '
+  syntax:
+    content: get_entities()
+    parameters: []
+    returns:
+    - description: A list of all Entity objects.
+      var_type: list of _ACLEntity objects
+  type: method
+  uid: google.cloud.storage.acl.ACL.get_entities
+- attributes: []
+  class: google.cloud.storage.acl.ACL
+  fullName: google.cloud.storage.acl.ACL.get_entity
+  langs:
+  - python
+  module: google.cloud.storage.acl
+  name: get_entity
+  source:
+    id: get_entity
+    path: tests/testdata/handwritten/google/cloud/storage/acl.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/handwritten/google/cloud/storage/acl.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 233
+  summary: 'Gets an entity object from the ACL.
+
+    '
+  syntax:
+    content: get_entity(entity, default=None)
+    parameters:
+    - description: The entity to get lookup in the ACL.
+      id: entity
+      var_type: _ACLEntity or string
+    - description: This value will be returned if the entity doesn't exist.
+      id: default
+      var_type: anything
+    returns:
+    - description: The corresponding entity or the value provided to default.
+      var_type: _ACLEntity
+  type: method
+  uid: google.cloud.storage.acl.ACL.get_entity
+- attributes: []
+  class: google.cloud.storage.acl.ACL
+  fullName: google.cloud.storage.acl.ACL.group
+  langs:
+  - python
+  module: google.cloud.storage.acl
+  name: group
+  source:
+    id: group
+    path: tests/testdata/handwritten/google/cloud/storage/acl.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/handwritten/google/cloud/storage/acl.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 296
+  summary: 'Factory method for a group Entity.
+
+    '
+  syntax:
+    content: group(identifier)
+    parameters:
+    - description: An id or e-mail for this particular group.
+      id: identifier
+      var_type: str
+    returns:
+    - description: An Entity corresponding to this group.
+      var_type: _ACLEntity
+  type: method
+  uid: google.cloud.storage.acl.ACL.group
+- attributes: []
+  class: google.cloud.storage.acl.ACL
+  fullName: google.cloud.storage.acl.ACL.has_entity
+  langs:
+  - python
+  module: google.cloud.storage.acl
+  name: has_entity
+  source:
+    id: has_entity
+    path: tests/testdata/handwritten/google/cloud/storage/acl.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/handwritten/google/cloud/storage/acl.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 221
+  summary: 'Returns whether or not this ACL has any entries for an entity.
+
+    '
+  syntax:
+    content: has_entity(entity)
+    parameters:
+    - description: The entity to check for existence in this ACL.
+      id: entity
+      var_type: _ACLEntity
+    returns:
+    - description: True of the entity exists in the ACL.
+      var_type: bool
+  type: method
+  uid: google.cloud.storage.acl.ACL.has_entity
+- attributes: []
+  class: google.cloud.storage.acl.ACL
+  fullName: google.cloud.storage.acl.ACL.reload
+  langs:
+  - python
+  module: google.cloud.storage.acl
+  name: reload
+  source:
+    id: reload
+    path: tests/testdata/handwritten/google/cloud/storage/acl.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/handwritten/google/cloud/storage/acl.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 363
+  summary: 'Reload the ACL data from Cloud Storage.
+
+
+    If `user_project` is set, bills the API request to that project.
+
+    '
+  syntax:
+    content: reload(client=None, timeout=60, retry=)
+    parameters:
+    - description: (Optional) The client to use. If not passed, falls back to the
+        client stored on the ACL's parent.
+      id: client
+      var_type: Client or NoneType
+    - description: '(Optional) The amount of time, in seconds, to wait for the server
+        response. See: configuring_timeouts'
+      id: timeout
+      var_type: float or tuple
+    - description: '(Optional) How to retry the RPC. See: configuring_retries'
+      id: retry
+      var_type: google.api_core.retry.Retry
+  type: method
+  uid: google.cloud.storage.acl.ACL.reload
+- attributes: []
+  class: google.cloud.storage.acl.ACL
+  fullName: google.cloud.storage.acl.ACL.reset
+  langs:
+  - python
+  module: google.cloud.storage.acl
+  name: reset
+  source:
+    id: reset
+    path: tests/testdata/handwritten/google/cloud/storage/acl.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/handwritten/google/cloud/storage/acl.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 176
+  summary: 'Remove all entities from the ACL, and clear the `loaded` flag.
+
+
+    '
+  syntax:
+    content: reset()
+    parameters: []
+  type: method
+  uid: google.cloud.storage.acl.ACL.reset
+- attributes: []
+  class: google.cloud.storage.acl.ACL
+  fullName: google.cloud.storage.acl.ACL.save
+  langs:
+  - python
+  module: google.cloud.storage.acl
+  name: save
+  source:
+    id: save
+    path: tests/testdata/handwritten/google/cloud/storage/acl.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/handwritten/google/cloud/storage/acl.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 488
+  summary: 'Save this ACL for the current bucket.
+
+
+    If `user_project` is set, bills the API request to that project.
+
+    '
+  syntax:
+    content: save(acl=None, client=None, if_generation_match=None, if_generation_not_match=None,
+      if_metageneration_match=None, if_metageneration_not_match=None, timeout=60,
+      retry=)
+    parameters:
+    - description: The ACL object to save. If left blank, this will save current entries.
+      id: acl
+      var_type: ACL, or a compatible
+        list.
+    - description: (Optional) The client to use. If not passed, falls back to the
+        client stored on the ACL's parent.
+      id: client
+      var_type: Client or NoneType
+    - description: (Optional) See :ref:using-if-generation-match
+      id: if_generation_match
+      var_type: long
+    - description: (Optional) See :ref:using-if-generation-not-match
+      id: if_generation_not_match
+      var_type: long
+    - description: (Optional) See :ref:using-if-metageneration-match
+      id: if_metageneration_match
+      var_type: long
+    - description: (Optional) See :ref:using-if-metageneration-not-match
+      id: if_metageneration_not_match
+      var_type: long
+    - description: '(Optional) The amount of time, in seconds, to wait for the server
+        response. See: configuring_timeouts'
+      id: timeout
+      var_type: float or tuple
+    - description: '(Optional) How to retry the RPC. See: configuring_retries'
+      id: retry
+      var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy
+  type: method
+  uid: google.cloud.storage.acl.ACL.save
+- attributes: []
+  class: google.cloud.storage.acl.ACL
+  fullName: google.cloud.storage.acl.ACL.save_predefined
+  langs:
+  - python
+  module: google.cloud.storage.acl
+  name: save_predefined
+  source:
+    id: save_predefined
+    path: tests/testdata/handwritten/google/cloud/storage/acl.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/handwritten/google/cloud/storage/acl.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 556
+  summary: 'Save this ACL for the current bucket using a predefined ACL.
+
+
+    If `user_project` is set, bills the API request to that project.
+
+    '
+  syntax:
+    content: save_predefined(predefined, client=None, if_generation_match=None, if_generation_not_match=None,
+      if_metageneration_match=None, if_metageneration_not_match=None, timeout=60,
+      retry=)
+    parameters:
+    - description: An identifier for a predefined ACL. Must be one of the keys in
+        PREDEFINED_JSON_ACLS or PREDEFINED_XML_ACLS (which
+        will be aliased to the corresponding JSON name). If passed, acl
+        must be None.
+      id: predefined
+      var_type: str
+    - description: (Optional) The client to use. If not passed, falls back to the
+        client stored on the ACL's parent.
+      id: client
+      var_type: Client or NoneType
+    - description: (Optional) See :ref:using-if-generation-match
+      id: if_generation_match
+      var_type: long
+    - description: (Optional) See :ref:using-if-generation-not-match
+      id: if_generation_not_match
+      var_type: long
+    - description: (Optional) See :ref:using-if-metageneration-match
+      id: if_metageneration_match
+      var_type: long
+    - description: (Optional) See :ref:using-if-metageneration-not-match
+      id: if_metageneration_not_match
+      var_type: long
+    - description: '(Optional) The amount of time, in seconds, to wait for the server
+        response. See: configuring_timeouts'
+      id: timeout
+      var_type: float or tuple
+    - description: '(Optional) How to retry the RPC. See: configuring_retries'
+      id: retry
+      var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy
+  type: method
+  uid: google.cloud.storage.acl.ACL.save_predefined
+- attributes: []
+  class: google.cloud.storage.acl.ACL
+  fullName: google.cloud.storage.acl.ACL.user
+  langs:
+  - python
+  module: google.cloud.storage.acl
+  name: user
+  source:
+    id: user
+    path: tests/testdata/handwritten/google/cloud/storage/acl.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/handwritten/google/cloud/storage/acl.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 285
+  summary: 'Factory method for a user Entity.
+
+    '
+  syntax:
+    content: user(identifier)
+    parameters:
+    - description: An id or e-mail for this particular user.
+      id: identifier
+      var_type: str
+    returns:
+    - description: An Entity corresponding to this user.
+      var_type: _ACLEntity
+  type: method
+  uid: google.cloud.storage.acl.ACL.user
+- attributes: []
+  class: google.cloud.storage.acl.ACL
+  fullName: google.cloud.storage.acl.ACL.validate_predefined
+  langs:
+  - python
+  module: google.cloud.storage.acl
+  name: validate_predefined
+  source:
+    id: validate_predefined
+    path: tests/testdata/handwritten/google/cloud/storage/acl.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/handwritten/google/cloud/storage/acl.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 159
+  summary: 'Ensures predefined is in list of predefined json values
+
+    '
+  syntax:
+    content: validate_predefined(predefined)
+    exceptions:
+    - description: 'ValueError: If predefined is not a valid acl'
+      var_type: :exc
+    parameters:
+    - description: validated JSON name of predefined acl
+      id: predefined
+      var_type: str
+  type: method
+  uid: google.cloud.storage.acl.ACL.validate_predefined
+references:
+- fullName: google.cloud.storage.acl.ACL.PREDEFINED_JSON_ACLS
+  isExternal: false
+  name: PREDEFINED_JSON_ACLS
+  parent: google.cloud.storage.acl.ACL
+  uid: google.cloud.storage.acl.ACL.PREDEFINED_JSON_ACLS
+- fullName: google.cloud.storage.acl.ACL.add_entity
+  isExternal: false
+  name: add_entity
+  parent: google.cloud.storage.acl.ACL
+  uid: google.cloud.storage.acl.ACL.add_entity
+- fullName: google.cloud.storage.acl.ACL.all
+  isExternal: false
+  name: all
+  parent: google.cloud.storage.acl.ACL
+  uid: google.cloud.storage.acl.ACL.all
+- fullName: google.cloud.storage.acl.ACL.all_authenticated
+  isExternal: false
+  name: all_authenticated
+  parent: google.cloud.storage.acl.ACL
+  uid: google.cloud.storage.acl.ACL.all_authenticated
+- fullName: google.cloud.storage.acl.ACL.clear
+  isExternal: false
+  name: clear
+  parent: google.cloud.storage.acl.ACL
+  uid: google.cloud.storage.acl.ACL.clear
+- fullName: google.cloud.storage.acl.ACL.client
+  isExternal: false
+  name: client
+  parent: google.cloud.storage.acl.ACL
+  uid: google.cloud.storage.acl.ACL.client
+- fullName: google.cloud.storage.acl.ACL.domain
+  isExternal: false
+  name: domain
+  parent: google.cloud.storage.acl.ACL
+  uid: google.cloud.storage.acl.ACL.domain
+- fullName: google.cloud.storage.acl.ACL.entity
+  isExternal: false
+  name: entity
+  parent: google.cloud.storage.acl.ACL
+  uid: google.cloud.storage.acl.ACL.entity
+- fullName: google.cloud.storage.acl.ACL.entity_from_dict
+  isExternal: false
+  name: entity_from_dict
+  parent: google.cloud.storage.acl.ACL
+  uid: google.cloud.storage.acl.ACL.entity_from_dict
+- fullName: google.cloud.storage.acl.ACL.get_entities
+  isExternal: false
+  name: get_entities
+  parent: google.cloud.storage.acl.ACL
+  uid: google.cloud.storage.acl.ACL.get_entities
+- fullName: google.cloud.storage.acl.ACL.get_entity
+  isExternal: false
+  name: get_entity
+  parent: google.cloud.storage.acl.ACL
+  uid: google.cloud.storage.acl.ACL.get_entity
+- fullName: google.cloud.storage.acl.ACL.group
+  isExternal: false
+  name: group
+  parent: google.cloud.storage.acl.ACL
+  uid: google.cloud.storage.acl.ACL.group
+- fullName: google.cloud.storage.acl.ACL.has_entity
+  isExternal: false
+  name: has_entity
+  parent: google.cloud.storage.acl.ACL
+  uid: google.cloud.storage.acl.ACL.has_entity
+- fullName: google.cloud.storage.acl.ACL.reload
+  isExternal: false
+  name: reload
+  parent: google.cloud.storage.acl.ACL
+  uid: google.cloud.storage.acl.ACL.reload
+- fullName: google.cloud.storage.acl.ACL.reset
+  isExternal: false
+  name: reset
+  parent: google.cloud.storage.acl.ACL
+  uid: google.cloud.storage.acl.ACL.reset
+- fullName: google.cloud.storage.acl.ACL.save
+  isExternal: false
+  name: save
+  parent: google.cloud.storage.acl.ACL
+  uid: google.cloud.storage.acl.ACL.save
+- fullName: google.cloud.storage.acl.ACL.save_predefined
+  isExternal: false
+  name: save_predefined
+  parent: google.cloud.storage.acl.ACL
+  uid: google.cloud.storage.acl.ACL.save_predefined
+- fullName: google.cloud.storage.acl.ACL.user
+  isExternal: false
+  name: user
+  parent: google.cloud.storage.acl.ACL
+  uid: google.cloud.storage.acl.ACL.user
+- fullName: google.cloud.storage.acl.ACL.validate_predefined
+  isExternal: false
+  name: validate_predefined
+  parent: google.cloud.storage.acl.ACL
+  uid: google.cloud.storage.acl.ACL.validate_predefined
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.acl.BucketACL.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.acl.BucketACL.yml
new file mode 100644
index 000000000000..dc17576dbfee
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.acl.BucketACL.yml
@@ -0,0 +1,155 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes: []
+  children:
+  - google.cloud.storage.acl.BucketACL.client
+  - google.cloud.storage.acl.BucketACL.reload_path
+  - google.cloud.storage.acl.BucketACL.save_path
+  - google.cloud.storage.acl.BucketACL.user_project
+  class: google.cloud.storage.acl.BucketACL
+  fullName: google.cloud.storage.acl.BucketACL
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: google.cloud.storage.acl.ACL
+  langs:
+  - python
+  module: google.cloud.storage.acl
+  name: BucketACL
+  source:
+    id: BucketACL
+    path: tests/testdata/handwritten/google/cloud/storage/acl.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/handwritten/google/cloud/storage/acl.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 682
+  summary: 'An ACL specifically for a bucket.
+
+    '
+  syntax:
+    content: BucketACL(bucket)
+    parameters:
+    - description: The bucket to which this ACL relates.
+      id: bucket
+      var_type: Bucket
+  type: class
+  uid: google.cloud.storage.acl.BucketACL
+- &id001
+  attributes: []
+  class: google.cloud.storage.acl.BucketACL
+  fullName: google.cloud.storage.acl.BucketACL.client
+  langs:
+  - python
+  module: google.cloud.storage.acl
+  name: client
+  source:
+    id: client
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'The client bound to this ACL''s bucket.
+
+
+    '
+  syntax: {}
+  type: property
+  uid: google.cloud.storage.acl.BucketACL.client
+- *id001
+- &id002
+  attributes: []
+  class: google.cloud.storage.acl.BucketACL
+  fullName: google.cloud.storage.acl.BucketACL.reload_path
+  langs:
+  - python
+  module: google.cloud.storage.acl
+  name: reload_path
+  source:
+    id: reload_path
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Compute the path for GET API requests for this ACL.
+
+
+    '
+  syntax: {}
+  type: property
+  uid: google.cloud.storage.acl.BucketACL.reload_path
+- *id002
+- &id003
+  attributes: []
+  class: google.cloud.storage.acl.BucketACL
+  fullName: google.cloud.storage.acl.BucketACL.save_path
+  langs:
+  - python
+  module: google.cloud.storage.acl
+  name: save_path
+  source:
+    id: save_path
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Compute the path for PATCH API requests for this ACL.
+
+
+    '
+  syntax: {}
+  type: property
+  uid: google.cloud.storage.acl.BucketACL.save_path
+- *id003
+- &id004
+  attributes: []
+  class: google.cloud.storage.acl.BucketACL
+  fullName: google.cloud.storage.acl.BucketACL.user_project
+  langs:
+  - python
+  module: google.cloud.storage.acl
+  name: user_project
+  source:
+    id: user_project
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Compute the user project charged for API requests for this ACL.
+
+
+    '
+  syntax: {}
+  type: property
+  uid: google.cloud.storage.acl.BucketACL.user_project
+- *id004
+references:
+- fullName: google.cloud.storage.acl.BucketACL.client
+  isExternal: false
+  name: client
+  parent: google.cloud.storage.acl.BucketACL
+  uid: google.cloud.storage.acl.BucketACL.client
+- fullName: google.cloud.storage.acl.BucketACL.reload_path
+  isExternal: false
+  name: reload_path
+  parent: google.cloud.storage.acl.BucketACL
+  uid: google.cloud.storage.acl.BucketACL.reload_path
+- fullName: google.cloud.storage.acl.BucketACL.save_path
+  isExternal: false
+  name: save_path
+  parent: google.cloud.storage.acl.BucketACL
+  uid: google.cloud.storage.acl.BucketACL.save_path
+- fullName: google.cloud.storage.acl.BucketACL.user_project
+  isExternal: false
+  name: user_project
+  parent: google.cloud.storage.acl.BucketACL
+  uid: google.cloud.storage.acl.BucketACL.user_project
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.acl.DefaultObjectACL.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.acl.DefaultObjectACL.yml
new file mode 100644
index 000000000000..9e835857c26f
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.acl.DefaultObjectACL.yml
@@ -0,0 +1,35 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes: []
+  children: []
+  class: google.cloud.storage.acl.DefaultObjectACL
+  fullName: google.cloud.storage.acl.DefaultObjectACL
+  inheritance:
+  - inheritance:
+    - inheritance:
+      - type: builtins.object
+      type: google.cloud.storage.acl.ACL
+    type: google.cloud.storage.acl.BucketACL
+  langs:
+  - python
+  module: google.cloud.storage.acl
+  name: DefaultObjectACL
+  source:
+    id: DefaultObjectACL
+    path: tests/testdata/handwritten/google/cloud/storage/acl.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/handwritten/google/cloud/storage/acl.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 714
+  summary: 'A class representing the default object ACL for a bucket.
+
+
+    '
+  syntax:
+    content: DefaultObjectACL(bucket)
+    parameters: []
+  type: class
+  uid: google.cloud.storage.acl.DefaultObjectACL
+references: []
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.acl.ObjectACL.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.acl.ObjectACL.yml
new file mode 100644
index 000000000000..49eb0e1afce4
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.acl.ObjectACL.yml
@@ -0,0 +1,155 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes: []
+  children:
+  - google.cloud.storage.acl.ObjectACL.client
+  - google.cloud.storage.acl.ObjectACL.reload_path
+  - google.cloud.storage.acl.ObjectACL.save_path
+  - google.cloud.storage.acl.ObjectACL.user_project
+  class: google.cloud.storage.acl.ObjectACL
+  fullName: google.cloud.storage.acl.ObjectACL
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: google.cloud.storage.acl.ACL
+  langs:
+  - python
+  module: google.cloud.storage.acl
+  name: ObjectACL
+  source:
+    id: ObjectACL
+    path: tests/testdata/handwritten/google/cloud/storage/acl.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/handwritten/google/cloud/storage/acl.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 721
+  summary: 'An ACL specifically for a Cloud Storage object / blob.
+
+    '
+  syntax:
+    content: ObjectACL(blob)
+    parameters:
+    - description: The blob that this ACL corresponds to.
+      id: blob
+      var_type: Blob
+  type: class
+  uid: google.cloud.storage.acl.ObjectACL
+- &id001
+  attributes: []
+  class: google.cloud.storage.acl.ObjectACL
+  fullName: google.cloud.storage.acl.ObjectACL.client
+  langs:
+  - python
+  module: google.cloud.storage.acl
+  name: client
+  source:
+    id: client
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'The client bound to this ACL''s blob.
+
+
+    '
+  syntax: {}
+  type: property
+  uid: google.cloud.storage.acl.ObjectACL.client
+- *id001
+- &id002
+  attributes: []
+  class: google.cloud.storage.acl.ObjectACL
+  fullName: google.cloud.storage.acl.ObjectACL.reload_path
+  langs:
+  - python
+  module: google.cloud.storage.acl
+  name: reload_path
+  source:
+    id: reload_path
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Compute the path for GET API requests for this ACL.
+
+
+    '
+  syntax: {}
+  type: property
+  uid: google.cloud.storage.acl.ObjectACL.reload_path
+- *id002
+- &id003
+  attributes: []
+  class: google.cloud.storage.acl.ObjectACL
+  fullName: google.cloud.storage.acl.ObjectACL.save_path
+  langs:
+  - python
+  module: google.cloud.storage.acl
+  name: save_path
+  source:
+    id: save_path
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Compute the path for PATCH API requests for this ACL.
+
+
+    '
+  syntax: {}
+  type: property
+  uid: google.cloud.storage.acl.ObjectACL.save_path
+- *id003
+- &id004
+  attributes: []
+  class: google.cloud.storage.acl.ObjectACL
+  fullName: google.cloud.storage.acl.ObjectACL.user_project
+  langs:
+  - python
+  module: google.cloud.storage.acl
+  name: user_project
+  source:
+    id: user_project
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Compute the user project charged for API requests for this ACL.
+
+
+    '
+  syntax: {}
+  type: property
+  uid: google.cloud.storage.acl.ObjectACL.user_project
+- *id004
+references:
+- fullName: google.cloud.storage.acl.ObjectACL.client
+  isExternal: false
+  name: client
+  parent: google.cloud.storage.acl.ObjectACL
+  uid: google.cloud.storage.acl.ObjectACL.client
+- fullName: google.cloud.storage.acl.ObjectACL.reload_path
+  isExternal: false
+  name: reload_path
+  parent: google.cloud.storage.acl.ObjectACL
+  uid: google.cloud.storage.acl.ObjectACL.reload_path
+- fullName: google.cloud.storage.acl.ObjectACL.save_path
+  isExternal: false
+  name: save_path
+  parent: google.cloud.storage.acl.ObjectACL
+  uid: google.cloud.storage.acl.ObjectACL.save_path
+- fullName: google.cloud.storage.acl.ObjectACL.user_project
+  isExternal: false
+  name: user_project
+  parent: google.cloud.storage.acl.ObjectACL
+  uid: google.cloud.storage.acl.ObjectACL.user_project
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.acl.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.acl.yml
new file mode 100644
index 000000000000..ecf608c5f5d6
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.acl.yml
@@ -0,0 +1,50 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes: []
+  children:
+  - google.cloud.storage.acl.ACL
+  - google.cloud.storage.acl.BucketACL
+  - google.cloud.storage.acl.DefaultObjectACL
+  - google.cloud.storage.acl.ObjectACL
+  fullName: google.cloud.storage.acl
+  langs:
+  - python
+  module: google.cloud.storage.acl
+  name: acl
+  source:
+    id: acl
+    path: tests/testdata/handwritten/google/cloud/storage/acl.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/handwritten/google/cloud/storage/acl.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 0
+  summary: 'Manage access to objects and buckets.
+
+
+    '
+  syntax: {}
+  type: module
+  uid: google.cloud.storage.acl
+references:
+- fullName: google.cloud.storage.acl.ACL
+  isExternal: false
+  name: ACL
+  parent: google.cloud.storage.acl
+  uid: google.cloud.storage.acl.ACL
+- fullName: google.cloud.storage.acl.BucketACL
+  isExternal: false
+  name: BucketACL
+  parent: google.cloud.storage.acl
+  uid: google.cloud.storage.acl.BucketACL
+- fullName: google.cloud.storage.acl.DefaultObjectACL
+  isExternal: false
+  name: DefaultObjectACL
+  parent: google.cloud.storage.acl
+  uid: google.cloud.storage.acl.DefaultObjectACL
+- fullName: google.cloud.storage.acl.ObjectACL
+  isExternal: false
+  name: ObjectACL
+  parent: google.cloud.storage.acl
+  uid: google.cloud.storage.acl.ObjectACL
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.batch.Batch.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.batch.Batch.yml
new file mode 100644
index 000000000000..e0fecf6f2b8c
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.batch.Batch.yml
@@ -0,0 +1,101 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes: []
+  children:
+  - google.cloud.storage.batch.Batch.current
+  - google.cloud.storage.batch.Batch.finish
+  class: google.cloud.storage.batch.Batch
+  fullName: google.cloud.storage.batch.Batch
+  inheritance:
+  - inheritance:
+    - inheritance:
+      - inheritance:
+        - type: builtins.object
+        type: google.cloud._http.Connection
+      type: google.cloud._http.JSONConnection
+    type: google.cloud.storage._http.Connection
+  langs:
+  - python
+  module: google.cloud.storage.batch
+  name: Batch
+  source:
+    id: Batch
+    path: tests/testdata/handwritten/google/cloud/storage/batch.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/handwritten/google/cloud/storage/batch.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 131
+  summary: 'Proxy an underlying connection, batching up change operations.
+
+    '
+  syntax:
+    content: Batch(client)
+    parameters:
+    - description: The client to use for making connections.
+      id: client
+      var_type: Client
+  type: class
+  uid: google.cloud.storage.batch.Batch
+- attributes: []
+  class: google.cloud.storage.batch.Batch
+  fullName: google.cloud.storage.batch.Batch.current
+  langs:
+  - python
+  module: google.cloud.storage.batch
+  name: current
+  source:
+    id: current
+    path: tests/testdata/handwritten/google/cloud/storage/batch.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/handwritten/google/cloud/storage/batch.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 275
+  summary: 'Return the topmost batch, or None.
+
+
+    '
+  syntax:
+    content: current()
+    parameters: []
+  type: method
+  uid: google.cloud.storage.batch.Batch.current
+- attributes: []
+  class: google.cloud.storage.batch.Batch
+  fullName: google.cloud.storage.batch.Batch.finish
+  langs:
+  - python
+  module: google.cloud.storage.batch
+  name: finish
+  source:
+    id: finish
+    path: tests/testdata/handwritten/google/cloud/storage/batch.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/handwritten/google/cloud/storage/batch.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 250
+  summary: 'Submit a single `multipart/mixed` request with deferred requests.
+
+    '
+  syntax:
+    content: finish()
+    parameters: []
+    returns:
+    - description: one (headers, payload) tuple per deferred request.
+      var_type: list of tuples
+  type: method
+  uid: google.cloud.storage.batch.Batch.finish
+references:
+- fullName: google.cloud.storage.batch.Batch.current
+  isExternal: false
+  name: current
+  parent: google.cloud.storage.batch.Batch
+  uid: google.cloud.storage.batch.Batch.current
+- fullName: google.cloud.storage.batch.Batch.finish
+  isExternal: false
+  name: finish
+  parent: google.cloud.storage.batch.Batch
+  uid: google.cloud.storage.batch.Batch.finish
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.batch.MIMEApplicationHTTP.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.batch.MIMEApplicationHTTP.yml
new file mode 100644
index 000000000000..ee56b019d523
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.batch.MIMEApplicationHTTP.yml
@@ -0,0 +1,113 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes: []
+  children:
+  - google.cloud.storage.batch.MIMEApplicationHTTP
+  class: google.cloud.storage.batch.MIMEApplicationHTTP
+  fullName: google.cloud.storage.batch.MIMEApplicationHTTP
+  inheritance:
+  - inheritance:
+    - inheritance:
+      - inheritance:
+        - inheritance:
+          - type: builtins.object
+          type: email.message.Message
+        type: email.mime.base.MIMEBase
+      type: email.mime.nonmultipart.MIMENonMultipart
+    type: email.mime.application.MIMEApplication
+  langs:
+  - python
+  module: google.cloud.storage.batch
+  name: MIMEApplicationHTTP
+  source:
+    id: MIMEApplicationHTTP
+    path: tests/testdata/handwritten/google/cloud/storage/batch.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/handwritten/google/cloud/storage/batch.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 34
+  summary: 'MIME type for `application/http`.
+
+
+    Constructs payload from headers and body
+
+    '
+  syntax:
+    content: MIMEApplicationHTTP(method, uri, headers, body)
+    parameters:
+    - description: HTTP method
+      id: method
+      var_type: str
+    - description: URI for HTTP request
+      id: uri
+      var_type: str
+    - description: HTTP headers
+      id: headers
+      var_type: dict
+    - description: (Optional) HTTP payload
+      id: body
+      var_type: str
+  type: class
+  uid: google.cloud.storage.batch.MIMEApplicationHTTP
+- attributes: []
+  class: google.cloud.storage.batch.MIMEApplicationHTTP
+  fullName: google.cloud.storage.batch.MIMEApplicationHTTP
+  inheritance:
+  - inheritance:
+    - inheritance:
+      - inheritance:
+        - inheritance:
+          - type: builtins.object
+          type: email.message.Message
+        type: email.mime.base.MIMEBase
+      type: email.mime.nonmultipart.MIMENonMultipart
+    type: email.mime.application.MIMEApplication
+  langs:
+  - python
+  module: google.cloud.storage.batch
+  name: MIMEApplicationHTTP
+  source:
+    id: MIMEApplicationHTTP
+    path: tests/testdata/handwritten/google/cloud/storage/batch.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/handwritten/google/cloud/storage/batch.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 34
+  summary: 'Create an application/* type MIME document.
+
+
+    _data is a string containing the raw application data.
+
+
+    _subtype is the MIME content type subtype, defaulting to
+
+    ''octet-stream''.
+
+
+    _encoder is a function which will perform the actual encoding for
+
+    transport of the application data, defaulting to base64 encoding.
+
+
+    Any additional keyword arguments are passed to the base class
+
+    constructor, which turns them into parameters on the Content-Type
+
+    header.
+
+
+    '
+  syntax:
+    content: MIMEApplicationHTTP(method, uri, headers, body)
+    parameters: []
+  type: method
+  uid: google.cloud.storage.batch.MIMEApplicationHTTP
+references:
+- fullName: google.cloud.storage.batch.MIMEApplicationHTTP
+  isExternal: false
+  name: MIMEApplicationHTTP
+  parent: google.cloud.storage.batch.MIMEApplicationHTTP
+  uid: google.cloud.storage.batch.MIMEApplicationHTTP
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.batch.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.batch.yml
new file mode 100644
index 000000000000..e40e57d84b03
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.batch.yml
@@ -0,0 +1,41 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes: []
+  children:
+  - google.cloud.storage.batch.Batch
+  - google.cloud.storage.batch.MIMEApplicationHTTP
+  fullName: google.cloud.storage.batch
+  langs:
+  - python
+  module: google.cloud.storage.batch
+  name: batch
+  source:
+    id: batch
+    path: tests/testdata/handwritten/google/cloud/storage/batch.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/handwritten/google/cloud/storage/batch.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 0
+  summary: 'Batch updates / deletes of storage buckets / blobs.
+
+
+    See https://cloud.google.com/storage/docs/json_api/v1/how-tos/batch
+
+
+    '
+  syntax: {}
+  type: module
+  uid: google.cloud.storage.batch
+references:
+- fullName: google.cloud.storage.batch.Batch
+  isExternal: false
+  name: Batch
+  parent: google.cloud.storage.batch
+  uid: google.cloud.storage.batch.Batch
+- fullName: google.cloud.storage.batch.MIMEApplicationHTTP
+  isExternal: false
+  name: MIMEApplicationHTTP
+  parent: google.cloud.storage.batch
+  uid: google.cloud.storage.batch.MIMEApplicationHTTP
diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.blob.Blob.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.blob.Blob.yml
new file mode 100644
index 000000000000..1aeaeba053d3
--- /dev/null
+++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.blob.Blob.yml
@@ -0,0 +1,3527 @@
+### YamlMime:UniversalReference
+api_name: []
+items:
+- attributes: []
+  children:
+  - google.cloud.storage.blob.Blob
+  - google.cloud.storage.blob.Blob.STORAGE_CLASSES
+  - google.cloud.storage.blob.Blob.acl
+  - google.cloud.storage.blob.Blob.bucket
+  - google.cloud.storage.blob.Blob.cache_control
+  - google.cloud.storage.blob.Blob.chunk_size
+  - google.cloud.storage.blob.Blob.client
+  - google.cloud.storage.blob.Blob.component_count
+  - google.cloud.storage.blob.Blob.compose
+  - google.cloud.storage.blob.Blob.content_disposition
+  - google.cloud.storage.blob.Blob.content_encoding
+  - google.cloud.storage.blob.Blob.content_language
+  - google.cloud.storage.blob.Blob.content_type
+  - google.cloud.storage.blob.Blob.crc32c
+  - google.cloud.storage.blob.Blob.create_resumable_upload_session
+  - google.cloud.storage.blob.Blob.custom_time
+  - google.cloud.storage.blob.Blob.delete
+  - google.cloud.storage.blob.Blob.download_as_bytes
+  - google.cloud.storage.blob.Blob.download_as_string
+  - google.cloud.storage.blob.Blob.download_as_text
+  - google.cloud.storage.blob.Blob.download_to_file
+  - google.cloud.storage.blob.Blob.download_to_filename
+  - google.cloud.storage.blob.Blob.encryption_key
+  - google.cloud.storage.blob.Blob.etag
+  - google.cloud.storage.blob.Blob.event_based_hold
+  - google.cloud.storage.blob.Blob.exists
+  - google.cloud.storage.blob.Blob.from_string
+  - google.cloud.storage.blob.Blob.generate_signed_url
+  - google.cloud.storage.blob.Blob.generation
+  - google.cloud.storage.blob.Blob.get_iam_policy
+  - google.cloud.storage.blob.Blob.id
+  - google.cloud.storage.blob.Blob.kms_key_name
+  - google.cloud.storage.blob.Blob.make_private
+  - google.cloud.storage.blob.Blob.make_public
+  - google.cloud.storage.blob.Blob.md5_hash
+  - google.cloud.storage.blob.Blob.media_link
+  - google.cloud.storage.blob.Blob.metadata
+  - google.cloud.storage.blob.Blob.metageneration
+  - google.cloud.storage.blob.Blob.open
+  - google.cloud.storage.blob.Blob.owner
+  - google.cloud.storage.blob.Blob.patch
+  - google.cloud.storage.blob.Blob.path
+  - google.cloud.storage.blob.Blob.path_helper
+  - google.cloud.storage.blob.Blob.public_url
+  - google.cloud.storage.blob.Blob.reload
+  - google.cloud.storage.blob.Blob.retention_expiration_time
+  - google.cloud.storage.blob.Blob.rewrite
+  - google.cloud.storage.blob.Blob.self_link
+  - google.cloud.storage.blob.Blob.set_iam_policy
+  - google.cloud.storage.blob.Blob.size
+  - google.cloud.storage.blob.Blob.storage_class
+  - google.cloud.storage.blob.Blob.temporary_hold
+  - google.cloud.storage.blob.Blob.test_iam_permissions
+  - google.cloud.storage.blob.Blob.time_created
+  - google.cloud.storage.blob.Blob.time_deleted
+  - google.cloud.storage.blob.Blob.update
+  - google.cloud.storage.blob.Blob.update_storage_class
+  - google.cloud.storage.blob.Blob.updated
+  - google.cloud.storage.blob.Blob.upload_from_file
+  - google.cloud.storage.blob.Blob.upload_from_filename
+  - google.cloud.storage.blob.Blob.upload_from_string
+  - google.cloud.storage.blob.Blob.user_project
+  class: google.cloud.storage.blob.Blob
+  fullName: google.cloud.storage.blob.Blob
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: google.cloud.storage._helpers._PropertyMixin
+  langs:
+  - python
+  module: google.cloud.storage.blob
+  name: Blob
+  source:
+    id: Blob
+    path: tests/testdata/handwritten/google/cloud/storage/blob.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/handwritten/google/cloud/storage/blob.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 145
+  summary: 'A wrapper around Cloud Storage''s concept of an `Object`.
+
+    '
+  syntax:
+    content: "Blob(\n    name,\n    bucket,\n    chunk_size=None,\n    encryption_key=None,\n\
+      \    kms_key_name=None,\n    generation=None,\n)"
+    parameters:
+    - description: The name of the blob. This corresponds to the unique path of the
+        object in the bucket. If bytes, will be converted to a unicode object. Blob
+        / object names can contain any sequence of valid unicode characters, of length
+        1-1024 bytes when UTF-8 encoded.
+      id: name
+      var_type: str
+    - description: The bucket to which this blob belongs.
+      id: bucket
+      var_type: Bucket
+    - description: (Optional) The size of a chunk of data whenever iterating (in bytes).
+        This must be a multiple of 256 KB per the API specification. If not specified,
+        the chunk_size of the blob itself is used. If that is not specified, a default
+        value of 40 MB is used.
+      id: chunk_size
+      var_type: int
+    - description: (Optional) 32 byte encryption key for customer-supplied encryption.
+        See https://cloud.google.com/storage/docs/encryption#customer-supplied.
+      id: encryption_key
+      var_type: bytes
+    - description: (Optional) Resource name of Cloud KMS key used to encrypt the blob's
+        contents.
+      id: kms_key_name
+      var_type: str
+    - description: (Optional) If present, selects a specific revision of this object.
+      id: generation
+      var_type: long
+  type: class
+  uid: google.cloud.storage.blob.Blob
+- attributes: []
+  class: google.cloud.storage.blob.Blob
+  fullName: google.cloud.storage.blob.Blob
+  inheritance:
+  - inheritance:
+    - type: builtins.object
+    type: google.cloud.storage._helpers._PropertyMixin
+  langs:
+  - python
+  module: google.cloud.storage.blob
+  name: Blob
+  source:
+    id: Blob
+    path: tests/testdata/handwritten/google/cloud/storage/blob.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/handwritten/google/cloud/storage/blob.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 145
+  summary: "property `name`\n    Get the blob's name.\n\n"
+  syntax:
+    content: "Blob(\n    name,\n    bucket,\n    chunk_size=None,\n    encryption_key=None,\n\
+      \    kms_key_name=None,\n    generation=None,\n)"
+    parameters: []
+  type: method
+  uid: google.cloud.storage.blob.Blob
+- attributes: []
+  class: google.cloud.storage.blob.Blob
+  fullName: google.cloud.storage.blob.Blob.STORAGE_CLASSES
+  langs:
+  - python
+  module: google.cloud.storage.blob
+  name: STORAGE_CLASSES
+  source:
+    id: STORAGE_CLASSES
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Allowed values for `storage_class`.
+
+
+    See
+
+    https://cloud.google.com/storage/docs/json_api/v1/objects#storageClass
+
+    https://cloud.google.com/storage/docs/per-object-storage-class
+
+
+    '
+  syntax: {}
+  type: attribute
+  uid: google.cloud.storage.blob.Blob.STORAGE_CLASSES
+- &id001
+  attributes: []
+  class: google.cloud.storage.blob.Blob
+  fullName: google.cloud.storage.blob.Blob.acl
+  langs:
+  - python
+  module: google.cloud.storage.blob
+  name: acl
+  source:
+    id: acl
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Create our ACL on demand.
+
+
+    '
+  syntax: {}
+  type: property
+  uid: google.cloud.storage.blob.Blob.acl
+- *id001
+- &id002
+  attributes: []
+  class: google.cloud.storage.blob.Blob
+  fullName: google.cloud.storage.blob.Blob.bucket
+  langs:
+  - python
+  module: google.cloud.storage.blob
+  name: bucket
+  source:
+    id: bucket
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Bucket which contains the object.
+
+    '
+  syntax:
+    returns:
+    - description: The object's bucket.
+      var_type: Bucket
+  type: property
+  uid: google.cloud.storage.blob.Blob.bucket
+- *id002
+- &id003
+  attributes: []
+  class: google.cloud.storage.blob.Blob
+  fullName: google.cloud.storage.blob.Blob.cache_control
+  langs:
+  - python
+  module: google.cloud.storage.blob
+  name: cache_control
+  source:
+    id: cache_control
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Scalar property getter.
+
+
+    '
+  syntax: {}
+  type: property
+  uid: google.cloud.storage.blob.Blob.cache_control
+- *id003
+- &id004
+  attributes: []
+  class: google.cloud.storage.blob.Blob
+  fullName: google.cloud.storage.blob.Blob.chunk_size
+  langs:
+  - python
+  module: google.cloud.storage.blob
+  name: chunk_size
+  source:
+    id: chunk_size
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Get the blob''s default chunk size.
+
+    '
+  syntax:
+    returns:
+    - description: The current blob's chunk size, if it is set.
+      var_type: int or NoneType
+  type: property
+  uid: google.cloud.storage.blob.Blob.chunk_size
+- *id004
+- &id005
+  attributes: []
+  class: google.cloud.storage.blob.Blob
+  fullName: google.cloud.storage.blob.Blob.client
+  langs:
+  - python
+  module: google.cloud.storage.blob
+  name: client
+  source:
+    id: client
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'The client bound to this blob.
+
+
+    '
+  syntax: {}
+  type: property
+  uid: google.cloud.storage.blob.Blob.client
+- *id005
+- &id006
+  attributes: []
+  class: google.cloud.storage.blob.Blob
+  fullName: google.cloud.storage.blob.Blob.component_count
+  langs:
+  - python
+  module: google.cloud.storage.blob
+  name: component_count
+  source:
+    id: component_count
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Number of underlying components that make up this object.
+
+
+    See https://cloud.google.com/storage/docs/json_api/v1/objects
+
+    '
+  syntax:
+    returns:
+    - description: The component count (in case of a composed object) or None
+        if the blob's resource has not been loaded from the server. This property
+        will not be set on objects not created via compose.
+      var_type: int or NoneType
+  type: property
+  uid: google.cloud.storage.blob.Blob.component_count
+- *id006
+- attributes: []
+  class: google.cloud.storage.blob.Blob
+  fullName: google.cloud.storage.blob.Blob.compose
+  langs:
+  - python
+  module: google.cloud.storage.blob
+  name: compose
+  source:
+    id: compose
+    path: tests/testdata/handwritten/google/cloud/storage/blob.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/handwritten/google/cloud/storage/blob.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 3298
+  summary: 'Concatenate source blobs into this one.
+
+
+    If `user_project` is set on the bucket, bills the API request
+
+    to that project.
+
+
+    See [API reference docs](https://cloud.google.com/storage/docs/json_api/v1/objects/compose)
+
+    and a [code sample](https://cloud.google.com/storage/docs/samples/storage-compose-file#storage_compose_file-python).
+
+    '
+  syntax:
+    content: compose(sources, client=None, timeout=60, if_generation_match=None, if_metageneration_match=None,
+      if_source_generation_match=None, retry=)
+    parameters:
+    - description: Blobs whose contents will be composed into this blob.
+      id: sources
+      var_type: list of Blob
+    - description: (Optional) The client to use. If not passed, falls back to the
+        client stored on the blob's bucket.
+      id: client
+      var_type: Client
+    - description: '(Optional) The amount of time, in seconds, to wait for the server
+        response. See: configuring_timeouts'
+      id: timeout
+      var_type: float or tuple
+    - description: '(Optional) Makes the operation conditional on whether the destination
+        object''s current generation matches the given value. Setting to 0 makes the
+        operation succeed only if there are no live versions of the object. Note:
+        In a previous version, this argument worked identically to the if_source_generation_match
+        argument. For backwards-compatibility reasons, if a list is passed in, this
+        argument will behave like if_source_generation_match and also
+        issue a DeprecationWarning.'
+      id: if_generation_match
+      var_type: long
+    - description: '(Optional) Makes the operation conditional on whether the destination
+        object''s current metageneration matches the given value. If a list of long
+        is passed in, no match operation will be performed. (Deprecated: type(list
+        of long) is supported for backwards-compatability reasons only.)'
+      id: if_metageneration_match
+      var_type: long
+    - description: (Optional) Makes the operation conditional on whether the current
+        generation of each source blob matches the corresponding generation. The list
+        must match sources item-to-item.
+      id: if_source_generation_match
+      var_type: list of long
+    - description: '(Optional) How to retry the RPC. See: configuring_retries'
+      id: retry
+      var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy
+  type: method
+  uid: google.cloud.storage.blob.Blob.compose
+- &id007
+  attributes: []
+  class: google.cloud.storage.blob.Blob
+  fullName: google.cloud.storage.blob.Blob.content_disposition
+  langs:
+  - python
+  module: google.cloud.storage.blob
+  name: content_disposition
+  source:
+    id: content_disposition
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Scalar property getter.
+
+
+    '
+  syntax: {}
+  type: property
+  uid: google.cloud.storage.blob.Blob.content_disposition
+- *id007
+- &id008
+  attributes: []
+  class: google.cloud.storage.blob.Blob
+  fullName: google.cloud.storage.blob.Blob.content_encoding
+  langs:
+  - python
+  module: google.cloud.storage.blob
+  name: content_encoding
+  source:
+    id: content_encoding
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Scalar property getter.
+
+
+    '
+  syntax: {}
+  type: property
+  uid: google.cloud.storage.blob.Blob.content_encoding
+- *id008
+- &id009
+  attributes: []
+  class: google.cloud.storage.blob.Blob
+  fullName: google.cloud.storage.blob.Blob.content_language
+  langs:
+  - python
+  module: google.cloud.storage.blob
+  name: content_language
+  source:
+    id: content_language
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Scalar property getter.
+
+
+    '
+  syntax: {}
+  type: property
+  uid: google.cloud.storage.blob.Blob.content_language
+- *id009
+- &id010
+  attributes: []
+  class: google.cloud.storage.blob.Blob
+  fullName: google.cloud.storage.blob.Blob.content_type
+  langs:
+  - python
+  module: google.cloud.storage.blob
+  name: content_type
+  source:
+    id: content_type
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Scalar property getter.
+
+
+    '
+  syntax: {}
+  type: property
+  uid: google.cloud.storage.blob.Blob.content_type
+- *id010
+- &id011
+  attributes: []
+  class: google.cloud.storage.blob.Blob
+  fullName: google.cloud.storage.blob.Blob.crc32c
+  langs:
+  - python
+  module: google.cloud.storage.blob
+  name: crc32c
+  source:
+    id: crc32c
+    path: null
+    remote:
+      branch: add_goldens
+      path: null
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: null
+  summary: 'Scalar property getter.
+
+
+    '
+  syntax: {}
+  type: property
+  uid: google.cloud.storage.blob.Blob.crc32c
+- *id011
+- attributes: []
+  class: google.cloud.storage.blob.Blob
+  fullName: google.cloud.storage.blob.Blob.create_resumable_upload_session
+  langs:
+  - python
+  module: google.cloud.storage.blob
+  name: create_resumable_upload_session
+  source:
+    id: create_resumable_upload_session
+    path: tests/testdata/handwritten/google/cloud/storage/blob.py
+    remote:
+      branch: add_goldens
+      path: tests/testdata/handwritten/google/cloud/storage/blob.py
+      repo: https://github.com/googleapis/sphinx-docfx-yaml
+    startLine: 2830
+  summary: "Create a resumable upload session.\n\nResumable upload sessions allow\
+    \ you to start an upload session from\none client and complete the session in\
+    \ another. This method is called\nby the initiator to set the metadata and limits.\
+    \ The initiator then\npasses the session URL to the client that will upload the\
+    \ binary data.\nThe client performs a PUT request on the session URL to complete\
+    \ the\nupload. This process allows untrusted clients to upload to an\naccess-controlled\
+    \ bucket.\n\nFor more details, see the\ndocumentation on [`signed URLs`](https://cloud.google.com/storage/docs/access-control/signed-urls#signing-resumable).\n\
+    \nThe content type of the upload will be determined in order\nof precedence:\n\
+    \n- The value passed in to this method (if not :data:`None`)\n- The value stored\
+    \ on the current blob\n- The default value ('application/octet-stream')\n\n\nNote:\nThe effect of uploading to an existing blob depends\
+    \ on the\n\"versioning\" and \"lifecycle\" policies defined on the blob's\nbucket.\
+    \  In the absence of those policies, upload will\noverwrite any existing contents.\n\
+    \n   See the [`object versioning`](https://cloud.google.com/storage/docs/object-versioning)\n\
+    \   and [`lifecycle`](https://cloud.google.com/storage/docs/lifecycle)\n   API\
+    \ documents for details.\n\nIf `encryption_key` is set, the blob will be encrypted\
+    \ with\na [`customer-supplied`](https://cloud.google.com/storage/docs/encryption#customer-supplied)\n\
+    encryption key.\n\nIf `user_project` is set on the bucket, bills the API request\n\
+    to that project.\n"
+  syntax:
+    content: create_resumable_upload_session(content_type=None, size=None, origin=None,
+      client=None, timeout=60, checksum=None, predefined_acl=None, if_generation_match=None,
+      if_generation_not_match=None, if_metageneration_match=None, if_metageneration_not_match=None,
+      retry=)
+    exceptions:
+    - description: if the session creation response returns an error status.
+      var_type: GoogleCloudErrorclient
stored on the blob's bucket. + id: client + var_type: Client + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: (Optional) The type of checksum to compute to verify the integrity + of the object. After the upload is complete, the server-computed checksum + of the resulting object will be checked and google.resumable_media.common.DataCorruption + will be raised on a mismatch. On a validation failure, the client will attempt + to delete the uploaded object automatically. Supported values are "md5", "crc32c" + and None. The default is None. + id: checksum + var_type: str + - description: (Optional) Predefined access control list + id: predefined_acl + var_type: str + - description: (Optional) See :ref:using-if-generation-match + id: if_generation_match + var_type: long + - description: (Optional) See :ref:using-if-generation-not-match + id: if_generation_not_match + var_type: long + - description: (Optional) See :ref:using-if-metageneration-match + id: if_metageneration_match + var_type: long + - description: (Optional) See :ref:using-if-metageneration-not-match + id: if_metageneration_not_match + var_type: long + - description: (Optional) How to retry the RPC. A None value will disable retries. + A google.api_core.retry.Retry value will enable retries, and the object will + define retriable response codes and errors and configure backoff and timeout + options. A google.cloud.storage.retry.ConditionalRetryPolicy + value wraps a Retry object and activates it only if certain conditions are + met. This class exists to provide safe defaults for RPC calls that are not + technically safe to retry normally (due to potential data duplication or other + side-effects) but become safe to retry if a condition such as if_generation_match + is set. See the retry.py source code and docstrings in this package (google.cloud.storage.retry) for information + on retry types and how to configure them. Media operations (downloads and + uploads) do not support non-default predicates in a Retry object. The default + will always be used. Other configuration changes for Retry objects such as + delays and deadlines are respected. + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + returns: + - description: The resumable upload session URL. The upload can be completed by + making an HTTP PUT request with the file's contents. + var_type: str + type: method + uid: google.cloud.storage.blob.Blob.create_resumable_upload_session +- &id012 + attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.custom_time + langs: + - python + module: google.cloud.storage.blob + name: custom_time + source: + id: custom_time + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Retrieve the custom time for the object. + + + See https://cloud.google.com/storage/docs/json_api/v1/objects + + ' + syntax: + returns: + - description: Datetime object parsed from RFC3339 valid timestamp, or None + if the blob's resource has not been loaded from the server (see reload). + var_type: datetime.datetime or NoneType + type: property + uid: google.cloud.storage.blob.Blob.custom_time +- *id012 +- attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.delete + langs: + - python + module: google.cloud.storage.blob + name: delete + source: + id: delete + path: tests/testdata/handwritten/google/cloud/storage/blob.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/blob.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 714 + summary: 'Deletes a blob from Cloud Storage. + + + If `user_project` is set on the bucket, bills the API request + + to that project. + + ' + syntax: + content: delete(client=None, if_generation_match=None, if_generation_not_match=None, + if_metageneration_match=None, if_metageneration_not_match=None, timeout=60, + retry=) + exceptions: + - description: (propagated from delete_blob). + var_type: NotFoundclient
stored on the blob's bucket. + id: client + var_type: Client + - description: (Optional) See :ref:using-if-generation-match + id: if_generation_match + var_type: long + - description: (Optional) See :ref:using-if-generation-not-match + id: if_generation_not_match + var_type: long + - description: (Optional) See :ref:using-if-metageneration-match + id: if_metageneration_match + var_type: long + - description: (Optional) See :ref:using-if-metageneration-not-match + id: if_metageneration_not_match + var_type: long + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: '(Optional) How to retry the RPC. See: configuring_retries' + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + type: method + uid: google.cloud.storage.blob.Blob.delete +- attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.download_as_bytes + langs: + - python + module: google.cloud.storage.blob + name: download_as_bytes + source: + id: download_as_bytes + path: tests/testdata/handwritten/google/cloud/storage/blob.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/blob.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 1282 + summary: 'Download the contents of this blob as a bytes object. + + + If `user_project` is set on the bucket, bills the API request + + to that project. + + ' + syntax: + content: download_as_bytes(client=None, start=None, end=None, raw_download=False, + if_etag_match=None, if_etag_not_match=None, if_generation_match=None, if_generation_not_match=None, + if_metageneration_match=None, if_metageneration_not_match=None, timeout=60, + checksum='md5', retry=) + exceptions: + - description: '' + var_type: NotFoundclient stored on the blob's bucket. + id: client + var_type: Client + - description: (Optional) The first byte in a range to be downloaded. + id: start + var_type: int + - description: (Optional) The last byte in a range to be downloaded. + id: end + var_type: int + - description: (Optional) If true, download the object without any expansion. + id: raw_download + var_type: bool + - description: (Optional) See :ref:using-if-etag-match + id: if_etag_match + var_type: Union[str, Set[str]] + - description: (Optional) See :ref:using-if-etag-not-match + id: if_etag_not_match + var_type: Union[str, Set[str]] + - description: (Optional) See :ref:using-if-generation-match + id: if_generation_match + var_type: long + - description: (Optional) See :ref:using-if-generation-not-match + id: if_generation_not_match + var_type: long + - description: (Optional) See :ref:using-if-metageneration-match + id: if_metageneration_match + var_type: long + - description: (Optional) See :ref:using-if-metageneration-not-match + id: if_metageneration_not_match + var_type: long + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: (Optional) The type of checksum to compute to verify the integrity + of the object. The response headers must contain a checksum of the requested + type. If the headers lack an appropriate checksum (for instance in the case + of transcoded or ranged downloads where the remote service does not know the + correct checksum, including downloads where chunk_size is set) an INFO-level + log will be emitted. Supported values are "md5", "crc32c" and None. The default + is "md5". + id: checksum + var_type: str + - description: (Optional) How to retry the RPC. A None value will disable retries. + A google.api_core.retry.Retry value will enable retries, and the object will + define retriable response codes and errors and configure backoff and timeout + options. A google.cloud.storage.retry.ConditionalRetryPolicy + value wraps a Retry object and activates it only if certain conditions are + met. This class exists to provide safe defaults for RPC calls that are not + technically safe to retry normally (due to potential data duplication or other + side-effects) but become safe to retry if a condition such as if_metageneration_match + is set. See the retry.py source code and docstrings in this package (google.cloud.storage.retry) for information + on retry types and how to configure them. Media operations (downloads and + uploads) do not support non-default predicates in a Retry object. The default + will always be used. Other configuration changes for Retry objects such as + delays and deadlines are respected. + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + returns: + - description: The data stored in this blob. + var_type: bytes + type: method + uid: google.cloud.storage.blob.Blob.download_as_bytes +- attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.download_as_string + langs: + - python + module: google.cloud.storage.blob + name: download_as_string + source: + id: download_as_string + path: tests/testdata/handwritten/google/cloud/storage/blob.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/blob.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 1405 + summary: '(Deprecated) Download the contents of this blob as a bytes object. + + + If `user_project` is set on the bucket, bills the API request + + to that project. + + + ' + syntax: + content: download_as_string(client=None, start=None, end=None, raw_download=False, + if_etag_match=None, if_etag_not_match=None, if_generation_match=None, if_generation_not_match=None, + if_metageneration_match=None, if_metageneration_not_match=None, timeout=60, + retry=) + exceptions: + - description: '' + var_type: NotFoundclient stored on the blob's bucket. + id: client + var_type: Client + - description: (Optional) The first byte in a range to be downloaded. + id: start + var_type: int + - description: (Optional) The last byte in a range to be downloaded. + id: end + var_type: int + - description: (Optional) If true, download the object without any expansion. + id: raw_download + var_type: bool + - description: (Optional) See :ref:using-if-etag-match + id: if_etag_match + var_type: Union[str, Set[str]] + - description: (Optional) See :ref:using-if-etag-not-match + id: if_etag_not_match + var_type: Union[str, Set[str]] + - description: (Optional) See :ref:using-if-generation-match + id: if_generation_match + var_type: long + - description: (Optional) See :ref:using-if-generation-not-match + id: if_generation_not_match + var_type: long + - description: (Optional) See :ref:using-if-metageneration-match + id: if_metageneration_match + var_type: long + - description: (Optional) See :ref:using-if-metageneration-not-match + id: if_metageneration_not_match + var_type: long + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: (Optional) How to retry the RPC. A None value will disable retries. + A google.api_core.retry.Retry value will enable retries, and the object will + define retriable response codes and errors and configure backoff and timeout + options. A google.cloud.storage.retry.ConditionalRetryPolicy + value wraps a Retry object and activates it only if certain conditions are + met. This class exists to provide safe defaults for RPC calls that are not + technically safe to retry normally (due to potential data duplication or other + side-effects) but become safe to retry if a condition such as if_metageneration_match + is set. See the retry.py source code and docstrings in this package (google.cloud.storage.retry) for information + on retry types and how to configure them. Media operations (downloads and + uploads) do not support non-default predicates in a Retry object. The default + will always be used. Other configuration changes for Retry objects such as + delays and deadlines are respected. + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + returns: + - description: The data stored in this blob. + var_type: bytes + type: method + uid: google.cloud.storage.blob.Blob.download_as_string +- attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.download_as_text + langs: + - python + module: google.cloud.storage.blob + name: download_as_text + source: + id: download_as_text + path: tests/testdata/handwritten/google/cloud/storage/blob.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/blob.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 1517 + summary: 'Download the contents of this blob as text (*not* bytes). + + + If `user_project` is set on the bucket, bills the API request + + to that project. + + ' + syntax: + content: download_as_text(client=None, start=None, end=None, raw_download=False, + encoding=None, if_etag_match=None, if_etag_not_match=None, if_generation_match=None, + if_generation_not_match=None, if_metageneration_match=None, if_metageneration_not_match=None, + timeout=60, retry=) + parameters: + - description: (Optional) The client to use. If not passed, falls back to the + client stored on the blob's bucket. + id: client + var_type: Client + - description: (Optional) The first byte in a range to be downloaded. + id: start + var_type: int + - description: (Optional) The last byte in a range to be downloaded. + id: end + var_type: int + - description: (Optional) If true, download the object without any expansion. + id: raw_download + var_type: bool + - description: (Optional) encoding to be used to decode the downloaded bytes. + Defaults to the charset param of attr:content_type, + or else to "utf-8". + id: encoding + var_type: str + - description: (Optional) See :ref:using-if-etag-match + id: if_etag_match + var_type: Union[str, Set[str]] + - description: (Optional) See :ref:using-if-etag-not-match + id: if_etag_not_match + var_type: Union[str, Set[str]] + - description: (Optional) See :ref:using-if-generation-match + id: if_generation_match + var_type: long + - description: (Optional) See :ref:using-if-generation-not-match + id: if_generation_not_match + var_type: long + - description: (Optional) See :ref:using-if-metageneration-match + id: if_metageneration_match + var_type: long + - description: (Optional) See :ref:using-if-metageneration-not-match + id: if_metageneration_not_match + var_type: long + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: (Optional) How to retry the RPC. A None value will disable retries. + A google.api_core.retry.Retry value will enable retries, and the object will + define retriable response codes and errors and configure backoff and timeout + options. A google.cloud.storage.retry.ConditionalRetryPolicy + value wraps a Retry object and activates it only if certain conditions are + met. This class exists to provide safe defaults for RPC calls that are not + technically safe to retry normally (due to potential data duplication or other + side-effects) but become safe to retry if a condition such as if_metageneration_match + is set. See the retry.py source code and docstrings in this package (google.cloud.storage.retry) for information + on retry types and how to configure them. Media operations (downloads and + uploads) do not support non-default predicates in a Retry object. The default + will always be used. Other configuration changes for Retry objects such as + delays and deadlines are respected. + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + returns: + - description: The data stored in this blob, decoded to text. + var_type: text + type: method + uid: google.cloud.storage.blob.Blob.download_as_text +- attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.download_to_file + langs: + - python + module: google.cloud.storage.blob + name: download_to_file + source: + id: download_to_file + path: tests/testdata/handwritten/google/cloud/storage/blob.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/blob.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 1010 + summary: 'DEPRECATED. Download the contents of this blob into a file-like object. + + + + + For more fine-grained control over the download process, check out + + [`google-resumable-media`](https://googleapis.dev/python/google-resumable-media/latest/index.html). + + For example, this library allows downloading **parts** of a blob rather than the + whole thing. + + + If `user_project` is set on the bucket, bills the API request + + to that project. + + ' + syntax: + content: download_to_file(file_obj, client=None, start=None, end=None, raw_download=False, + if_etag_match=None, if_etag_not_match=None, if_generation_match=None, if_generation_not_match=None, + if_metageneration_match=None, if_metageneration_not_match=None, timeout=60, + checksum='md5', retry=) + exceptions: + - description: '' + var_type: NotFoundclient stored on the blob's bucket. + id: client + var_type: Client + - description: (Optional) The first byte in a range to be downloaded. + id: start + var_type: int + - description: (Optional) The last byte in a range to be downloaded. + id: end + var_type: int + - description: (Optional) If true, download the object without any expansion. + id: raw_download + var_type: bool + - description: (Optional) See :ref:using-if-etag-match + id: if_etag_match + var_type: Union[str, Set[str]] + - description: (Optional) See :ref:using-if-etag-not-match + id: if_etag_not_match + var_type: Union[str, Set[str]] + - description: (Optional) See :ref:using-if-generation-match + id: if_generation_match + var_type: long + - description: (Optional) See :ref:using-if-generation-not-match + id: if_generation_not_match + var_type: long + - description: (Optional) See :ref:using-if-metageneration-match + id: if_metageneration_match + var_type: long + - description: (Optional) See :ref:using-if-metageneration-not-match + id: if_metageneration_not_match + var_type: long + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: (Optional) The type of checksum to compute to verify the integrity + of the object. The response headers must contain a checksum of the requested + type. If the headers lack an appropriate checksum (for instance in the case + of transcoded or ranged downloads where the remote service does not know the + correct checksum, including downloads where chunk_size is set) an INFO-level + log will be emitted. Supported values are "md5", "crc32c" and None. The default + is "md5". + id: checksum + var_type: str + - description: (Optional) How to retry the RPC. A None value will disable retries. + A google.api_core.retry.Retry value will enable retries, and the object will + define retriable response codes and errors and configure backoff and timeout + options. A google.cloud.storage.retry.ConditionalRetryPolicy + value wraps a Retry object and activates it only if certain conditions are + met. This class exists to provide safe defaults for RPC calls that are not + technically safe to retry normally (due to potential data duplication or other + side-effects) but become safe to retry if a condition such as if_metageneration_match + is set. See the retry.py source code and docstrings in this package (google.cloud.storage.retry) for information + on retry types and how to configure them. Media operations (downloads and + uploads) do not support non-default predicates in a Retry object. The default + will always be used. Other configuration changes for Retry objects such as + delays and deadlines are respected. + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + type: method + uid: google.cloud.storage.blob.Blob.download_to_file +- attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.download_to_filename + langs: + - python + module: google.cloud.storage.blob + name: download_to_filename + source: + id: download_to_filename + path: tests/testdata/handwritten/google/cloud/storage/blob.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/blob.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 1146 + summary: 'Download the contents of this blob into a named file. + + + If `user_project` is set on the bucket, bills the API request + + to that project. + + + See a [code sample](https://cloud.google.com/storage/docs/samples/storage-download-encrypted-file#storage_download_encrypted_file-python) + + to download a file with a [`customer-supplied encryption key`](https://cloud.google.com/storage/docs/encryption#customer-supplied). + + ' + syntax: + content: download_to_filename(filename, client=None, start=None, end=None, raw_download=False, + if_etag_match=None, if_etag_not_match=None, if_generation_match=None, if_generation_not_match=None, + if_metageneration_match=None, if_metageneration_not_match=None, timeout=60, + checksum='md5', retry=) + exceptions: + - description: '' + var_type: NotFoundopen. + id: filename + var_type: str + - description: (Optional) The client to use. If not passed, falls back to the + client stored on the blob's bucket. + id: client + var_type: Client + - description: (Optional) The first byte in a range to be downloaded. + id: start + var_type: int + - description: (Optional) The last byte in a range to be downloaded. + id: end + var_type: int + - description: (Optional) If true, download the object without any expansion. + id: raw_download + var_type: bool + - description: (Optional) See :ref:using-if-etag-match + id: if_etag_match + var_type: Union[str, Set[str]] + - description: (Optional) See :ref:using-if-etag-not-match + id: if_etag_not_match + var_type: Union[str, Set[str]] + - description: (Optional) See :ref:using-if-generation-match + id: if_generation_match + var_type: long + - description: (Optional) See :ref:using-if-generation-not-match + id: if_generation_not_match + var_type: long + - description: (Optional) See :ref:using-if-metageneration-match + id: if_metageneration_match + var_type: long + - description: (Optional) See :ref:using-if-metageneration-not-match + id: if_metageneration_not_match + var_type: long + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: (Optional) The type of checksum to compute to verify the integrity + of the object. The response headers must contain a checksum of the requested + type. If the headers lack an appropriate checksum (for instance in the case + of transcoded or ranged downloads where the remote service does not know the + correct checksum, including downloads where chunk_size is set) an INFO-level + log will be emitted. Supported values are "md5", "crc32c" and None. The default + is "md5". + id: checksum + var_type: str + - description: (Optional) How to retry the RPC. A None value will disable retries. + A google.api_core.retry.Retry value will enable retries, and the object will + define retriable response codes and errors and configure backoff and timeout + options. A google.cloud.storage.retry.ConditionalRetryPolicy + value wraps a Retry object and activates it only if certain conditions are + met. This class exists to provide safe defaults for RPC calls that are not + technically safe to retry normally (due to potential data duplication or other + side-effects) but become safe to retry if a condition such as if_metageneration_match + is set. See the retry.py source code and docstrings in this package (google.cloud.storage.retry) for information + on retry types and how to configure them. Media operations (downloads and + uploads) do not support non-default predicates in a Retry object. The default + will always be used. Other configuration changes for Retry objects such as + delays and deadlines are respected. + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + type: method + uid: google.cloud.storage.blob.Blob.download_to_filename +- &id013 + attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.encryption_key + langs: + - python + module: google.cloud.storage.blob + name: encryption_key + source: + id: encryption_key + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Retrieve the customer-supplied encryption key for the object. + + ' + syntax: + returns: + - description: The encryption key or None if no customer-supplied + encryption key was used, or the blob's resource has not been loaded from the + server. + var_type: bytes or NoneType + type: property + uid: google.cloud.storage.blob.Blob.encryption_key +- *id013 +- &id014 + attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.etag + langs: + - python + module: google.cloud.storage.blob + name: etag + source: + id: etag + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Retrieve the ETag for the object. + + + See [`RFC 2616 (etags)`](https://tools.ietf.org/html/rfc2616#section-3.11) and + + [`API reference docs`](https://cloud.google.com/storage/docs/json_api/v1/objects). + + ' + syntax: + returns: + - description: The blob etag or None if the blob's resource has not + been loaded from the server. + var_type: str or NoneType + type: property + uid: google.cloud.storage.blob.Blob.etag +- *id014 +- &id015 + attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.event_based_hold + langs: + - python + module: google.cloud.storage.blob + name: event_based_hold + source: + id: event_based_hold + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Scalar property getter. + + + ' + syntax: {} + type: property + uid: google.cloud.storage.blob.Blob.event_based_hold +- *id015 +- attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.exists + langs: + - python + module: google.cloud.storage.blob + name: exists + source: + id: exists + path: tests/testdata/handwritten/google/cloud/storage/blob.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/blob.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 619 + summary: 'Determines whether or not this blob exists. + + + If `user_project` is set on the bucket, bills the API request + + to that project. + + ' + syntax: + content: exists(client=None, if_etag_match=None, if_etag_not_match=None, if_generation_match=None, + if_generation_not_match=None, if_metageneration_match=None, if_metageneration_not_match=None, + timeout=60, retry=) + parameters: + - description: (Optional) The client to use. If not passed, falls back to the + client stored on the blob's bucket. + id: client + var_type: Client + - description: (Optional) See :ref:using-if-etag-match + id: if_etag_match + var_type: Union[str, Set[str]] + - description: (Optional) See :ref:using-if-etag-not-match + id: if_etag_not_match + var_type: Union[str, Set[str]] + - description: (Optional) See :ref:using-if-generation-match + id: if_generation_match + var_type: long + - description: (Optional) See :ref:using-if-generation-not-match + id: if_generation_not_match + var_type: long + - description: (Optional) See :ref:using-if-metageneration-match + id: if_metageneration_match + var_type: long + - description: (Optional) See :ref:using-if-metageneration-not-match + id: if_metageneration_not_match + var_type: long + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: '(Optional) How to retry the RPC. See: configuring_retries' + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + returns: + - description: True if the blob exists in Cloud Storage. + var_type: bool + type: method + uid: google.cloud.storage.blob.Blob.exists +- attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.from_string + langs: + - python + module: google.cloud.storage.blob + name: from_string + source: + id: from_string + path: tests/testdata/handwritten/google/cloud/storage/blob.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/blob.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 382 + summary: 'Get a constructor for blob object by URI. + + + ```python + + from google.cloud import storage + + from google.cloud.storage.blob import Blob + + client = storage.Client() + + blob = Blob.from_string("gs://bucket/object", client=client) + + ``` + + ' + syntax: + content: from_string(uri, client=None) + parameters: + - description: The blob uri pass to get blob object. + id: uri + var_type: str + - description: (Optional) The client to use. Application code should *always* + pass client. + id: client + var_type: Client + returns: + - description: The blob object created. + var_type: Blob + type: method + uid: google.cloud.storage.blob.Blob.from_string +- attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.generate_signed_url + langs: + - python + module: google.cloud.storage.blob + name: generate_signed_url + source: + id: generate_signed_url + path: tests/testdata/handwritten/google/cloud/storage/blob.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/blob.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 413 + summary: 'Generates a signed URL for this blob. + + + + + See a [code sample](https://cloud.google.com/storage/docs/samples/storage-generate-signed-url-v4#storage_generate_signed_url_v4-python). + + + This is particularly useful if you don''t want publicly + + accessible blobs, but don''t want to require users to explicitly + + log in. + + + If `bucket_bound_hostname` is set as an argument of `api_access_endpoint`, + + `https` works only if using a `CDN`. + + ' + syntax: + content: "generate_signed_url(\n expiration=None,\n api_access_endpoint=\"\ + https://storage.googleapis.com\",\n method=\"GET\",\n content_md5=None,\n\ + \ content_type=None,\n response_disposition=None,\n response_type=None,\n\ + \ generation=None,\n headers=None,\n query_parameters=None,\n client=None,\n\ + \ credentials=None,\n version=None,\n service_account_email=None,\n\ + \ access_token=None,\n virtual_hosted_style=False,\n bucket_bound_hostname=None,\n\ + \ scheme=\"http\",\n)" + exceptions: + - description: when version is invalid. + var_type: '`ValueError' + - description: when expiration is not a valid type. + var_type: '`TypeError' + - description: if credentials is not an instance of google.auth.credentials.Signing. + var_type: '`AttributeError' + parameters: + - description: Point in time when the signed URL should expire. If a datetime + instance is passed without an explicit tzinfo set, it will be + assumed to be UTC. + id: expiration + var_type: Union[Integer, datetime.datetime, datetime.timedelta] + - description: (Optional) URI base. + id: api_access_endpoint + var_type: str + - description: The HTTP verb that will be used when requesting the URL. + id: method + var_type: str + - description: (Optional) The MD5 hash of the object referenced by resource. + id: content_md5 + var_type: str + - description: (Optional) The content type of the object referenced by resource. + id: content_type + var_type: str + - description: (Optional) Content disposition of responses to requests for the + signed URL. For example, to enable the signed URL to initiate a file of blog.png, + use the value 'attachment; filename=blob.png'. + id: response_disposition + var_type: str + - description: (Optional) Content type of responses to requests for the signed + URL. Ignored if content_type is set on object/blob metadata. + id: response_type + var_type: str + - description: (Optional) A value that indicates which generation of the resource + to fetch. + id: generation + var_type: str + - description: '(Optional) Additional HTTP headers to be included as part of the + signed URLs. See: https://cloud.google.com/storage/docs/xml-api/reference-headers + Requests using the signed URL *must* pass the specified header (name and value) + with each request for the URL.' + id: headers + var_type: dict + - description: '(Optional) Additional query parameters to be included as part + of the signed URLs. See: https://cloud.google.com/storage/docs/xml-api/reference-headers#query' + id: query_parameters + var_type: dict + - description: (Optional) The client to use. If not passed, falls back to the + client stored on the blob's bucket. + id: client + var_type: Client + - description: (Optional) The authorization credentials to attach to requests. + These credentials identify this application to the service. If none are specified, + the client will attempt to ascertain the credentials from the environment. + id: credentials + var_type: google.auth.credentials.Credentials + - description: (Optional) The version of signed credential to create. Must be + one of 'v2' 'v4'. + id: version + var_type: str + - description: (Optional) E-mail address of the service account. + id: service_account_email + var_type: str + - description: (Optional) Access token for a service account. + id: access_token + var_type: str + - description: (Optional) If true, then construct the URL relative the bucket's + virtual hostname, e.g., '.storage.googleapis.com'. + id: virtual_hosted_style + var_type: bool + - description: '(Optional) If passed, then construct the URL relative to the bucket-bound + hostname. Value can be a bare or with scheme, e.g., ''example.com'' or ''http://example.com''. + See: https://cloud.google.com/storage/docs/request-endpoints#cname' + id: bucket_bound_hostname + var_type: str + - description: (Optional) If bucket_bound_hostname is passed as a + bare hostname, use this value as the scheme. https will work + only when using a CDN. Defaults to "http". + id: scheme + var_type: str + returns: + - description: A signed URL you can use to access the resource until expiration. + var_type: str + type: method + uid: google.cloud.storage.blob.Blob.generate_signed_url +- &id016 + attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.generation + langs: + - python + module: google.cloud.storage.blob + name: generation + source: + id: generation + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Retrieve the generation for the object. + + + See https://cloud.google.com/storage/docs/json_api/v1/objects + + ' + syntax: + returns: + - description: The generation of the blob or None if the blob's resource + has not been loaded from the server. + var_type: int or NoneType + type: property + uid: google.cloud.storage.blob.Blob.generation +- *id016 +- attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.get_iam_policy + langs: + - python + module: google.cloud.storage.blob + name: get_iam_policy + source: + id: get_iam_policy + path: tests/testdata/handwritten/google/cloud/storage/blob.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/blob.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 3009 + summary: 'Retrieve the IAM policy for the object. + + + ' + syntax: + content: get_iam_policy(client=None, requested_policy_version=None, timeout=60, + retry=) + parameters: + - description: (Optional) The client to use. If not passed, falls back to the + client stored on the current object's bucket. + id: client + var_type: Client + - description: (Optional) The version of IAM policies to request. If a policy + with a condition is requested without setting this, the server will return + an error. This must be set to a value of 3 to retrieve IAM policies containing + conditions. This is to prevent client code that isn't aware of IAM conditions + from interpreting and modifying policies incorrectly. The service might return + a policy with version lower than the one that was requested, based on the + feature syntax in the policy fetched. + id: requested_policy_version + var_type: int or NoneType + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: '(Optional) How to retry the RPC. See: configuring_retries' + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + returns: + - description: the policy instance, based on the resource returned from the getIamPolicy + API request. + var_type: google.api_core.iam.Policy + type: method + uid: google.cloud.storage.blob.Blob.get_iam_policy +- &id017 + attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.id + langs: + - python + module: google.cloud.storage.blob + name: id + source: + id: id + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Retrieve the ID for the object. + + + See https://cloud.google.com/storage/docs/json_api/v1/objects + + + The ID consists of the bucket name, object name, and generation number. + + ' + syntax: + returns: + - description: The ID of the blob or None if the blob's resource + has not been loaded from the server. + var_type: str or NoneType + type: property + uid: google.cloud.storage.blob.Blob.id +- *id017 +- &id018 + attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.kms_key_name + langs: + - python + module: google.cloud.storage.blob + name: kms_key_name + source: + id: kms_key_name + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Resource name of Cloud KMS key used to encrypt the blob''s contents. + + ' + syntax: + returns: + - description: The resource name or None if no Cloud KMS key was + used, or the blob's resource has not been loaded from the server. + var_type: str or NoneType + type: property + uid: google.cloud.storage.blob.Blob.kms_key_name +- *id018 +- attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.make_private + langs: + - python + module: google.cloud.storage.blob + name: make_private + source: + id: make_private + path: tests/testdata/handwritten/google/cloud/storage/blob.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/blob.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 3245 + summary: 'Update blob''s ACL, revoking read access for anonymous users. + + ' + syntax: + content: make_private(client=None, timeout=60, if_generation_match=None, if_generation_not_match=None, + if_metageneration_match=None, if_metageneration_not_match=None, retry=) + parameters: + - description: (Optional) The client to use. If not passed, falls back to the + client stored on the blob's bucket. + id: client + var_type: Client or NoneType + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: (Optional) See :ref:using-if-generation-match + id: if_generation_match + var_type: long + - description: (Optional) See :ref:using-if-generation-not-match + id: if_generation_not_match + var_type: long + - description: (Optional) See :ref:using-if-metageneration-match + id: if_metageneration_match + var_type: long + - description: (Optional) See :ref:using-if-metageneration-not-match + id: if_metageneration_not_match + var_type: long + - description: '(Optional) How to retry the RPC. See: configuring_retries' + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + type: method + uid: google.cloud.storage.blob.Blob.make_private +- attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.make_public + langs: + - python + module: google.cloud.storage.blob + name: make_public + source: + id: make_public + path: tests/testdata/handwritten/google/cloud/storage/blob.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/blob.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 3192 + summary: 'Update blob''s ACL, granting read access to anonymous users. + + ' + syntax: + content: make_public(client=None, timeout=60, if_generation_match=None, if_generation_not_match=None, + if_metageneration_match=None, if_metageneration_not_match=None, retry=) + parameters: + - description: (Optional) The client to use. If not passed, falls back to the + client stored on the blob's bucket. + id: client + var_type: Client or NoneType + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: (Optional) See :ref:using-if-generation-match + id: if_generation_match + var_type: long + - description: (Optional) See :ref:using-if-generation-not-match + id: if_generation_not_match + var_type: long + - description: (Optional) See :ref:using-if-metageneration-match + id: if_metageneration_match + var_type: long + - description: (Optional) See :ref:using-if-metageneration-not-match + id: if_metageneration_not_match + var_type: long + - description: '(Optional) How to retry the RPC. See: configuring_retries' + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + type: method + uid: google.cloud.storage.blob.Blob.make_public +- &id019 + attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.md5_hash + langs: + - python + module: google.cloud.storage.blob + name: md5_hash + source: + id: md5_hash + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Scalar property getter. + + + ' + syntax: {} + type: property + uid: google.cloud.storage.blob.Blob.md5_hash +- *id019 +- &id020 + attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.media_link + langs: + - python + module: google.cloud.storage.blob + name: media_link + source: + id: media_link + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Retrieve the media download URI for the object. + + + See https://cloud.google.com/storage/docs/json_api/v1/objects + + ' + syntax: + returns: + - description: The media link for the blob or None if the blob's + resource has not been loaded from the server. + var_type: str or NoneType + type: property + uid: google.cloud.storage.blob.Blob.media_link +- *id020 +- &id021 + attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.metadata + langs: + - python + module: google.cloud.storage.blob + name: metadata + source: + id: metadata + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: "Retrieve arbitrary/application specific metadata for the object.\n\nSee\ + \ https://cloud.google.com/storage/docs/json_api/v1/objects\n\n:setter: Update\ + \ arbitrary/application specific metadata for the\n object.\n:getter:\ + \ Retrieve arbitrary/application specific metadata for\n the object.\n" + syntax: + returns: + - description: The metadata associated with the blob or None if the + property is not set. + var_type: dict or NoneType + type: property + uid: google.cloud.storage.blob.Blob.metadata +- *id021 +- &id022 + attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.metageneration + langs: + - python + module: google.cloud.storage.blob + name: metageneration + source: + id: metageneration + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Retrieve the metageneration for the object. + + + See https://cloud.google.com/storage/docs/json_api/v1/objects + + ' + syntax: + returns: + - description: The metageneration of the blob or None if the blob's + resource has not been loaded from the server. + var_type: int or NoneType + type: property + uid: google.cloud.storage.blob.Blob.metageneration +- *id022 +- attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.open + langs: + - python + module: google.cloud.storage.blob + name: open + source: + id: open + path: tests/testdata/handwritten/google/cloud/storage/blob.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/blob.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 3712 + summary: 'Create a file handler for file-like I/O to or from this blob. + + + This method can be used as a context manager, just like Python''s + + built-in ''open()'' function. + + + While reading, as with other read methods, if blob.generation is not set + + the most recent blob generation will be used. Because the file-like IO + + reader downloads progressively in chunks, this could result in data from + + multiple versions being mixed together. If this is a concern, use + + either bucket.get_blob(), or blob.reload(), which will download the + + latest generation number and set it; or, if the generation is known, set + + it manually, for instance with bucket.blob(generation=123456). + + + Checksumming (hashing) to verify data integrity is disabled for reads + + using this feature because reads are implemented using request ranges, + + which do not provide checksums to validate. See + + https://cloud.google.com/storage/docs/hashes-etags for details. + + + See a [code sample](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_fileio_write_read.py). + + + Keyword arguments to pass to the underlying API calls. + + For both uploads and downloads, the following arguments are + + supported: + + + - `if_generation_match` + + - `if_generation_not_match` + + - `if_metageneration_match` + + - `if_metageneration_not_match` + + - `timeout` + + - `retry` + + + For downloads only, the following additional arguments are supported: + + + - `raw_download` + + + For uploads only, the following additional arguments are supported: + + + - `content_type` + + - `num_retries` + + - `predefined_acl` + + - `checksum` + + + ' + syntax: + content: "open(\n mode=\"r\",\n chunk_size=None,\n ignore_flush=None,\n\ + \ encoding=None,\n errors=None,\n newline=None,\n **kwargs\n)" + parameters: + - description: (Optional) A mode string, as per standard Python open() + semantics.The first character must be 'r', to open the blob for reading, or + 'w' to open it for writing. The second character, if present, must be 't' + for (unicode) text mode, or 'b' for bytes mode. If the second character is + omitted, text mode is the default. + id: mode + var_type: str + - description: (Optional) For reads, the minimum number of bytes to read at a + time. If fewer bytes than the chunk_size are requested, the remainder is buffered. + For writes, the maximum number of bytes to buffer before sending data to the + server, and the size of each request when data is sent. Writes are implemented + as a "resumable upload", so chunk_size for writes must be exactly a multiple + of 256KiB as with other resumable uploads. The default is 40 MiB. + id: chunk_size + var_type: long + - description: (Optional) For non text-mode writes, makes flush() do nothing instead + of raising an error. flush() without closing is not supported by the remote + service and therefore calling it normally results in io.UnsupportedOperation. + However, that behavior is incompatible with some consumers and wrappers of + file objects in Python, such as zipfile.ZipFile or io.TextIOWrapper. Setting + ignore_flush will cause flush() to successfully do nothing, for compatibility + with those contexts. The correct way to actually flush data to the remote + server is to close() (using a context manager, such as in the example, will + cause this to happen automatically). + id: ignore_flush + var_type: bool + - description: (Optional) For text mode only, the name of the encoding that the + stream will be decoded or encoded with. If omitted, it defaults to locale.getpreferredencoding(False). + id: encoding + var_type: str + - description: (Optional) For text mode only, an optional string that specifies + how encoding and decoding errors are to be handled. Pass 'strict' to raise + a ValueError exception if there is an encoding error (the default of None + has the same effect), or pass 'ignore' to ignore errors. (Note that ignoring + encoding errors can lead to data loss.) Other more rarely-used options are + also available; see the Python 'io' module documentation for 'io.TextIOWrapper' + for a complete list. + id: errors + var_type: str + - description: (Optional) For text mode only, controls how line endings are handled. + It can be None, '', '\n', '\r', and '\r\n'. If None, reads use "universal + newline mode" and writes use the system default. See the Python 'io' module + documentation for 'io.TextIOWrapper' for details. + id: newline + var_type: str + type: method + uid: google.cloud.storage.blob.Blob.open +- &id023 + attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.owner + langs: + - python + module: google.cloud.storage.blob + name: owner + source: + id: owner + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Retrieve info about the owner of the object. + + + See https://cloud.google.com/storage/docs/json_api/v1/objects + + ' + syntax: + returns: + - description: Mapping of owner's role/ID, or None if the blob's + resource has not been loaded from the server. + var_type: dict or NoneType + type: property + uid: google.cloud.storage.blob.Blob.owner +- *id023 +- attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.patch + langs: + - python + module: google.cloud.storage.blob + name: patch + source: + id: patch + path: tests/testdata/handwritten/google/cloud/storage/_helpers.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/_helpers.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 281 + summary: 'Sends all changed properties in a PATCH request. + + + Updates the `_properties` with the response from the backend. + + + If `user_project` is set, bills the API request to that project. + + ' + syntax: + content: patch(client=None, if_generation_match=None, if_generation_not_match=None, + if_metageneration_match=None, if_metageneration_not_match=None, timeout=60, + retry=) + parameters: + - description: the client to use. If not passed, falls back to the client + stored on the current object. + id: client + var_type: Client or NoneType + - description: (Optional) See :ref:using-if-generation-match + id: if_generation_match + var_type: long + - description: (Optional) See :ref:using-if-generation-not-match + id: if_generation_not_match + var_type: long + - description: (Optional) See :ref:using-if-metageneration-match + id: if_metageneration_match + var_type: long + - description: (Optional) See :ref:using-if-metageneration-not-match + id: if_metageneration_not_match + var_type: long + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: '(Optional) How to retry the RPC. See: configuring_retries' + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + type: method + uid: google.cloud.storage.blob.Blob.patch +- &id024 + attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.path + langs: + - python + module: google.cloud.storage.blob + name: path + source: + id: path + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Getter property for the URL path to this Blob. + + ' + syntax: + returns: + - description: The URL path to this Blob. + var_type: str + type: property + uid: google.cloud.storage.blob.Blob.path +- *id024 +- attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.path_helper + langs: + - python + module: google.cloud.storage.blob + name: path_helper + source: + id: path_helper + path: tests/testdata/handwritten/google/cloud/storage/blob.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/blob.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 293 + summary: 'Relative URL path for a blob. + + ' + syntax: + content: path_helper(bucket_path, blob_name) + parameters: + - description: The URL path for a bucket. + id: bucket_path + var_type: str + - description: The name of the blob. + id: blob_name + var_type: str + returns: + - description: The relative URL path for blob_name. + var_type: str + type: method + uid: google.cloud.storage.blob.Blob.path_helper +- &id025 + attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.public_url + langs: + - python + module: google.cloud.storage.blob + name: public_url + source: + id: public_url + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'The public URL for this blob. + + + Use `make_public` to enable anonymous access via the returned + + URL. + + ' + syntax: + returns: + - description: The public URL for this blob. + var_type: string + type: property + uid: google.cloud.storage.blob.Blob.public_url +- *id025 +- attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.reload + langs: + - python + module: google.cloud.storage.blob + name: reload + source: + id: reload + path: tests/testdata/handwritten/google/cloud/storage/_helpers.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/_helpers.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 169 + summary: 'Reload properties from Cloud Storage. + + + If `user_project` is set, bills the API request to that project. + + ' + syntax: + content: reload(client=None, projection='noAcl', if_etag_match=None, if_etag_not_match=None, + if_generation_match=None, if_generation_not_match=None, if_metageneration_match=None, + if_metageneration_not_match=None, timeout=60, retry=) + parameters: + - description: the client to use. If not passed, falls back to the client + stored on the current object. + id: client + var_type: Client or NoneType + - description: (Optional) If used, must be 'full' or 'noAcl'. Defaults to 'noAcl'. + Specifies the set of properties to return. + id: projection + var_type: str + - description: (Optional) See :ref:using-if-etag-match + id: if_etag_match + var_type: Union[str, Set[str]] + - description: (Optional) See :ref:using-if-etag-not-match + id: if_etag_not_match + var_type: Union[str, Set[str]]) + - description: (Optional) See :ref:using-if-generation-match + id: if_generation_match + var_type: long + - description: (Optional) See :ref:using-if-generation-not-match + id: if_generation_not_match + var_type: long + - description: (Optional) See :ref:using-if-metageneration-match + id: if_metageneration_match + var_type: long + - description: (Optional) See :ref:using-if-metageneration-not-match + id: if_metageneration_not_match + var_type: long + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: '(Optional) How to retry the RPC. See: configuring_retries' + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + type: method + uid: google.cloud.storage.blob.Blob.reload +- &id026 + attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.retention_expiration_time + langs: + - python + module: google.cloud.storage.blob + name: retention_expiration_time + source: + id: retention_expiration_time + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Retrieve timestamp at which the object''s retention period expires. + + + See https://cloud.google.com/storage/docs/json_api/v1/objects + + ' + syntax: + returns: + - description: Datetime object parsed from RFC3339 valid timestamp, or None + if the property is not set locally. + var_type: datetime.datetime or NoneType + type: property + uid: google.cloud.storage.blob.Blob.retention_expiration_time +- *id026 +- attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.rewrite + langs: + - python + module: google.cloud.storage.blob + name: rewrite + source: + id: rewrite + path: tests/testdata/handwritten/google/cloud/storage/blob.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/blob.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 3431 + summary: 'Rewrite source blob into this one. + + + If `user_project` is set on the bucket, bills the API request + + to that project. + + ' + syntax: + content: rewrite(source, token=None, client=None, if_generation_match=None, if_generation_not_match=None, + if_metageneration_match=None, if_metageneration_not_match=None, if_source_generation_match=None, + if_source_generation_not_match=None, if_source_metageneration_match=None, if_source_metageneration_not_match=None, + timeout=60, retry=) + parameters: + - description: blob whose contents will be rewritten into this blob. + id: source + var_type: Blob + - description: (Optional) Token returned from an earlier, not-completed call to + rewrite the same source blob. If passed, result will include updated status, + total bytes written. + id: token + var_type: str + - description: (Optional) The client to use. If not passed, falls back to the + client stored on the blob's bucket. + id: client + var_type: Client + - description: (Optional) See :ref:using-if-generation-match Note + that the generation to be matched is that of the destination + blob. + id: if_generation_match + var_type: long + - description: (Optional) See :ref:using-if-generation-not-match + Note that the generation to be matched is that of the destination + blob. + id: if_generation_not_match + var_type: long + - description: (Optional) See :ref:using-if-metageneration-match + Note that the metageneration to be matched is that of the destination + blob. + id: if_metageneration_match + var_type: long + - description: (Optional) See :ref:using-if-metageneration-not-match + Note that the metageneration to be matched is that of the destination + blob. + id: if_metageneration_not_match + var_type: long + - description: (Optional) Makes the operation conditional on whether the source + object's generation matches the given value. + id: if_source_generation_match + var_type: long + - description: (Optional) Makes the operation conditional on whether the source + object's generation does not match the given value. + id: if_source_generation_not_match + var_type: long + - description: (Optional) Makes the operation conditional on whether the source + object's current metageneration matches the given value. + id: if_source_metageneration_match + var_type: long + - description: (Optional) Makes the operation conditional on whether the source + object's current metageneration does not match the given value. + id: if_source_metageneration_not_match + var_type: long + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: '(Optional) How to retry the RPC. See: configuring_retries' + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + returns: + - description: (token, bytes_rewritten, total_bytes), where token + is a rewrite token (None if the rewrite is complete), bytes_rewritten + is the number of bytes rewritten so far, and total_bytes is the + total number of bytes to be rewritten. + var_type: tuple + type: method + uid: google.cloud.storage.blob.Blob.rewrite +- &id027 + attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.self_link + langs: + - python + module: google.cloud.storage.blob + name: self_link + source: + id: self_link + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Retrieve the URI for the object. + + + See https://cloud.google.com/storage/docs/json_api/v1/objects + + ' + syntax: + returns: + - description: The self link for the blob or None if the blob's resource + has not been loaded from the server. + var_type: str or NoneType + type: property + uid: google.cloud.storage.blob.Blob.self_link +- *id027 +- attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.set_iam_policy + langs: + - python + module: google.cloud.storage.blob + name: set_iam_policy + source: + id: set_iam_policy + path: tests/testdata/handwritten/google/cloud/storage/blob.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/blob.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 3077 + summary: 'Update the IAM policy for the bucket. + + + ' + syntax: + content: set_iam_policy(policy, client=None, timeout=60, retry=) + parameters: + - description: policy instance used to update bucket's IAM policy. + id: policy + var_type: google.api_core.iam.Policy + - description: (Optional) The client to use. If not passed, falls back to the + client stored on the current bucket. + id: client + var_type: Client + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: '(Optional) How to retry the RPC. See: configuring_retries' + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + returns: + - description: the policy instance, based on the resource returned from the setIamPolicy + API request. + var_type: google.api_core.iam.Policy + type: method + uid: google.cloud.storage.blob.Blob.set_iam_policy +- &id028 + attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.size + langs: + - python + module: google.cloud.storage.blob + name: size + source: + id: size + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Size of the object, in bytes. + + + See https://cloud.google.com/storage/docs/json_api/v1/objects + + ' + syntax: + returns: + - description: The size of the blob or None if the blob's resource + has not been loaded from the server. + var_type: int or NoneType + type: property + uid: google.cloud.storage.blob.Blob.size +- *id028 +- &id029 + attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.storage_class + langs: + - python + module: google.cloud.storage.blob + name: storage_class + source: + id: storage_class + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Scalar property getter. + + + ' + syntax: {} + type: property + uid: google.cloud.storage.blob.Blob.storage_class +- *id029 +- &id030 + attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.temporary_hold + langs: + - python + module: google.cloud.storage.blob + name: temporary_hold + source: + id: temporary_hold + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Scalar property getter. + + + ' + syntax: {} + type: property + uid: google.cloud.storage.blob.Blob.temporary_hold +- *id030 +- attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.test_iam_permissions + langs: + - python + module: google.cloud.storage.blob + name: test_iam_permissions + source: + id: test_iam_permissions + path: tests/testdata/handwritten/google/cloud/storage/blob.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/blob.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 3138 + summary: 'API call: test permissions + + + ' + syntax: + content: test_iam_permissions(permissions, client=None, timeout=60, retry=) + parameters: + - description: the permissions to check + id: permissions + var_type: list of string + - description: (Optional) The client to use. If not passed, falls back to the + client stored on the current bucket. + id: client + var_type: Client + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: '(Optional) How to retry the RPC. See: configuring_retries' + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + returns: + - description: the permissions returned by the testIamPermissions + API request. + var_type: list of string + type: method + uid: google.cloud.storage.blob.Blob.test_iam_permissions +- &id031 + attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.time_created + langs: + - python + module: google.cloud.storage.blob + name: time_created + source: + id: time_created + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Retrieve the timestamp at which the object was created. + + + See https://cloud.google.com/storage/docs/json_api/v1/objects + + ' + syntax: + returns: + - description: Datetime object parsed from RFC3339 valid timestamp, or None + if the blob's resource has not been loaded from the server (see reload). + var_type: datetime.datetime or NoneType + type: property + uid: google.cloud.storage.blob.Blob.time_created +- *id031 +- &id032 + attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.time_deleted + langs: + - python + module: google.cloud.storage.blob + name: time_deleted + source: + id: time_deleted + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Retrieve the timestamp at which the object was deleted. + + + See https://cloud.google.com/storage/docs/json_api/v1/objects + + ' + syntax: + returns: + - description: Datetime object parsed from RFC3339 valid timestamp, or None + if the blob's resource has not been loaded from the server (see reload). + If the blob has not been deleted, this will never be set. + var_type: datetime.datetime or NoneType + type: property + uid: google.cloud.storage.blob.Blob.time_deleted +- *id032 +- attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.update + langs: + - python + module: google.cloud.storage.blob + name: update + source: + id: update + path: tests/testdata/handwritten/google/cloud/storage/_helpers.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/_helpers.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 352 + summary: 'Sends all properties in a PUT request. + + + Updates the `_properties` with the response from the backend. + + + If `user_project` is set, bills the API request to that project. + + ' + syntax: + content: update(client=None, if_generation_match=None, if_generation_not_match=None, + if_metageneration_match=None, if_metageneration_not_match=None, timeout=60, + retry=) + parameters: + - description: the client to use. If not passed, falls back to the client + stored on the current object. + id: client + var_type: Client or NoneType + - description: (Optional) See :ref:using-if-generation-match + id: if_generation_match + var_type: long + - description: (Optional) See :ref:using-if-generation-not-match + id: if_generation_not_match + var_type: long + - description: (Optional) See :ref:using-if-metageneration-match + id: if_metageneration_match + var_type: long + - description: (Optional) See :ref:using-if-metageneration-not-match + id: if_metageneration_not_match + var_type: long + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: '(Optional) How to retry the RPC. See: configuring_retries' + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + type: method + uid: google.cloud.storage.blob.Blob.update +- attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.update_storage_class + langs: + - python + module: google.cloud.storage.blob + name: update_storage_class + source: + id: update_storage_class + path: tests/testdata/handwritten/google/cloud/storage/blob.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/blob.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 3585 + summary: 'Update blob''s storage class via a rewrite-in-place. This helper will + + wait for the rewrite to complete before returning, so it may take some + + time for large files. + + + See + + https://cloud.google.com/storage/docs/per-object-storage-class + + + If `user_project` is set on the bucket, bills the API request + + to that project. + + ' + syntax: + content: update_storage_class(new_class, client=None, if_generation_match=None, + if_generation_not_match=None, if_metageneration_match=None, if_metageneration_not_match=None, + if_source_generation_match=None, if_source_generation_not_match=None, if_source_metageneration_match=None, + if_source_metageneration_not_match=None, timeout=60, retry=) + parameters: + - description: 'new storage class for the object. One of: NEARLINE_STORAGE_CLASS, + COLDLINE_STORAGE_CLASS, + ARCHIVE_STORAGE_CLASS, + STANDARD_STORAGE_CLASS, + MULTI_REGIONAL_LEGACY_STORAGE_CLASS, + or REGIONAL_LEGACY_STORAGE_CLASS.' + id: new_class + var_type: str + - description: (Optional) The client to use. If not passed, falls back to the + client stored on the blob's bucket. + id: client + var_type: Client + - description: (Optional) See :ref:using-if-generation-match Note + that the generation to be matched is that of the destination + blob. + id: if_generation_match + var_type: long + - description: (Optional) See :ref:using-if-generation-not-match + Note that the generation to be matched is that of the destination + blob. + id: if_generation_not_match + var_type: long + - description: (Optional) See :ref:using-if-metageneration-match + Note that the metageneration to be matched is that of the destination + blob. + id: if_metageneration_match + var_type: long + - description: (Optional) See :ref:using-if-metageneration-not-match + Note that the metageneration to be matched is that of the destination + blob. + id: if_metageneration_not_match + var_type: long + - description: (Optional) Makes the operation conditional on whether the source + object's generation matches the given value. + id: if_source_generation_match + var_type: long + - description: (Optional) Makes the operation conditional on whether the source + object's generation does not match the given value. + id: if_source_generation_not_match + var_type: long + - description: (Optional) Makes the operation conditional on whether the source + object's current metageneration matches the given value. + id: if_source_metageneration_match + var_type: long + - description: (Optional) Makes the operation conditional on whether the source + object's current metageneration does not match the given value. + id: if_source_metageneration_not_match + var_type: long + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: '(Optional) How to retry the RPC. See: configuring_retries' + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + type: method + uid: google.cloud.storage.blob.Blob.update_storage_class +- &id033 + attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.updated + langs: + - python + module: google.cloud.storage.blob + name: updated + source: + id: updated + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Retrieve the timestamp at which the object was updated. + + + See https://cloud.google.com/storage/docs/json_api/v1/objects + + ' + syntax: + returns: + - description: Datetime object parsed from RFC3339 valid timestamp, or None + if the blob's resource has not been loaded from the server (see reload). + var_type: datetime.datetime or NoneType + type: property + uid: google.cloud.storage.blob.Blob.updated +- *id033 +- attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.upload_from_file + langs: + - python + module: google.cloud.storage.blob + name: upload_from_file + source: + id: upload_from_file + path: tests/testdata/handwritten/google/cloud/storage/blob.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/blob.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 2388 + summary: "Upload the contents of this blob from a file-like object.\n\nThe content\ + \ type of the upload will be determined in order\nof precedence:\n\n- The value\ + \ passed in to this method (if not :data:`None`)\n- The value stored on the current\ + \ blob\n- The default value ('application/octet-stream')\n\n\n\ + \ See the [`object versioning`](https://cloud.google.com/storage/docs/object-versioning)\n\ + \ and [`lifecycle`](https://cloud.google.com/storage/docs/lifecycle)\n API\ + \ documents for details.\n\nIf the size of the data to be uploaded exceeds 8 MB\ + \ a resumable media\nrequest will be used, otherwise the content and the metadata\ + \ will be\nuploaded in a single multipart upload request.\n\nFor more fine-grained\ + \ over the upload process, check out\n[`google-resumable-media`](https://googleapis.dev/python/google-resumable-media/latest/index.html).\n\ + \nIf `user_project` is set on the bucket, bills the API request\nto that project.\n" + syntax: + content: upload_from_file(file_obj, rewind=False, size=None, content_type=None, + num_retries=None, client=None, predefined_acl=None, if_generation_match=None, + if_generation_not_match=None, if_metageneration_match=None, if_metageneration_not_match=None, + timeout=60, checksum=None, retry=) + exceptions: + - description: if the upload response returns an error status. + var_type: GoogleCloudErrorfile_obj). + If not provided, the upload will be concluded once file_obj is + exhausted. + id: size + var_type: int + - description: (Optional) Type of content being uploaded. + id: content_type + var_type: str + - description: 'Number of upload retries. By default, only uploads with if_generation_match + set will be retried, as uploads without the argument are not guaranteed to + be idempotent. Setting num_retries will override this default behavior and + guarantee retries even when if_generation_match is not set. (Deprecated: This + argument will be removed in a future release.)' + id: num_retries + var_type: int + - description: (Optional) The client to use. If not passed, falls back to the + client stored on the blob's bucket. + id: client + var_type: Client + - description: (Optional) Predefined access control list + id: predefined_acl + var_type: str + - description: (Optional) See :ref:using-if-generation-match + id: if_generation_match + var_type: long + - description: (Optional) See :ref:using-if-generation-not-match + id: if_generation_not_match + var_type: long + - description: (Optional) See :ref:using-if-metageneration-match + id: if_metageneration_match + var_type: long + - description: (Optional) See :ref:using-if-metageneration-not-match + id: if_metageneration_not_match + var_type: long + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: (Optional) The type of checksum to compute to verify the integrity + of the object. If the upload is completed in a single request, the checksum + will be entirely precomputed and the remote server will handle verification + and error handling. If the upload is too large and must be transmitted in + multiple requests, the checksum will be incrementally computed and the client + will handle verification and error handling, raising google.resumable_media.common.DataCorruption + on a mismatch and attempting to delete the corrupted file. Supported values + are "md5", "crc32c" and None. The default is None. + id: checksum + var_type: str + - description: (Optional) How to retry the RPC. A None value will disable retries. + A google.api_core.retry.Retry value will enable retries, and the object will + define retriable response codes and errors and configure backoff and timeout + options. A google.cloud.storage.retry.ConditionalRetryPolicy + value wraps a Retry object and activates it only if certain conditions are + met. This class exists to provide safe defaults for RPC calls that are not + technically safe to retry normally (due to potential data duplication or other + side-effects) but become safe to retry if a condition such as if_generation_match + is set. See the retry.py source code and docstrings in this package (google.cloud.storage.retry) for information + on retry types and how to configure them. Media operations (downloads and + uploads) do not support non-default predicates in a Retry object. The default + will always be used. Other configuration changes for Retry objects such as + delays and deadlines are respected. + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + type: method + uid: google.cloud.storage.blob.Blob.upload_from_file +- attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.upload_from_filename + langs: + - python + module: google.cloud.storage.blob + name: upload_from_filename + source: + id: upload_from_filename + path: tests/testdata/handwritten/google/cloud/storage/blob.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/blob.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 2558 + summary: "Upload this blob's contents from the content of a named file.\n\nThe content\ + \ type of the upload will be determined in order\nof precedence:\n\n- The value\ + \ passed in to this method (if not :data:`None`)\n- The value stored on the current\ + \ blob\n- The value given by `mimetypes.guess_type`\n- The default value ('application/octet-stream')\n\ + \n\n See the [`object versioning`](https://cloud.google.com/storage/docs/object-versioning)\n\ + \ and [`lifecycle`](https://cloud.google.com/storage/docs/lifecycle)\n API\ + \ documents for details.\n\nIf `user_project` is set on the bucket, bills the\ + \ API request\nto that project.\n\nSee a [code sample](https://cloud.google.com/storage/docs/samples/storage-upload-encrypted-file#storage_upload_encrypted_file-python)\n\ + to upload a file with a\n[`customer-supplied encryption key`](https://cloud.google.com/storage/docs/encryption#customer-supplied).\n" + syntax: + content: upload_from_filename(filename, content_type=None, num_retries=None, client=None, + predefined_acl=None, if_generation_match=None, if_generation_not_match=None, + if_metageneration_match=None, if_metageneration_not_match=None, timeout=60, + checksum=None, retry=) + parameters: + - description: The path to the file. + id: filename + var_type: str + - description: (Optional) Type of content being uploaded. + id: content_type + var_type: str + - description: (Optional) The client to use. If not passed, falls back to the + client stored on the blob's bucket. + id: client + var_type: Client + - description: 'Number of upload retries. By default, only uploads with if_generation_match + set will be retried, as uploads without the argument are not guaranteed to + be idempotent. Setting num_retries will override this default behavior and + guarantee retries even when if_generation_match is not set. (Deprecated: This + argument will be removed in a future release.)' + id: num_retries + var_type: int + - description: (Optional) Predefined access control list + id: predefined_acl + var_type: str + - description: (Optional) See :ref:using-if-generation-match + id: if_generation_match + var_type: long + - description: (Optional) See :ref:using-if-generation-not-match + id: if_generation_not_match + var_type: long + - description: (Optional) See :ref:using-if-metageneration-match + id: if_metageneration_match + var_type: long + - description: (Optional) See :ref:using-if-metageneration-not-match + id: if_metageneration_not_match + var_type: long + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: (Optional) The type of checksum to compute to verify the integrity + of the object. If the upload is completed in a single request, the checksum + will be entirely precomputed and the remote server will handle verification + and error handling. If the upload is too large and must be transmitted in + multiple requests, the checksum will be incrementally computed and the client + will handle verification and error handling, raising google.resumable_media.common.DataCorruption + on a mismatch and attempting to delete the corrupted file. Supported values + are "md5", "crc32c" and None. The default is None. + id: checksum + var_type: str + - description: (Optional) How to retry the RPC. A None value will disable retries. + A google.api_core.retry.Retry value will enable retries, and the object will + define retriable response codes and errors and configure backoff and timeout + options. A google.cloud.storage.retry.ConditionalRetryPolicy + value wraps a Retry object and activates it only if certain conditions are + met. This class exists to provide safe defaults for RPC calls that are not + technically safe to retry normally (due to potential data duplication or other + side-effects) but become safe to retry if a condition such as if_generation_match + is set. See the retry.py source code and docstrings in this package (google.cloud.storage.retry) for information + on retry types and how to configure them. Media operations (downloads and + uploads) do not support non-default predicates in a Retry object. The default + will always be used. Other configuration changes for Retry objects such as + delays and deadlines are respected. + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + type: method + uid: google.cloud.storage.blob.Blob.upload_from_filename +- attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.upload_from_string + langs: + - python + module: google.cloud.storage.blob + name: upload_from_string + source: + id: upload_from_string + path: tests/testdata/handwritten/google/cloud/storage/blob.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/blob.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 2699 + summary: "Upload contents of this blob from the provided string.\n\n\n See the [`object versioning`](https://cloud.google.com/storage/docs/object-versioning)\n\ + \ and [`lifecycle`](https://cloud.google.com/storage/docs/lifecycle)\n API\ + \ documents for details.\n\nIf `user_project` is set on the bucket, bills the\ + \ API request\nto that project.\n" + syntax: + content: upload_from_string(data, content_type='text/plain', num_retries=None, + client=None, predefined_acl=None, if_generation_match=None, if_generation_not_match=None, + if_metageneration_match=None, if_metageneration_not_match=None, timeout=60, + checksum=None, retry=) + parameters: + - description: The data to store in this blob. If the value is text, it will be + encoded as UTF-8. + id: data + var_type: bytes or str + - description: (Optional) Type of content being uploaded. Defaults to 'text/plain'. + id: content_type + var_type: str + - description: 'Number of upload retries. By default, only uploads with if_generation_match + set will be retried, as uploads without the argument are not guaranteed to + be idempotent. Setting num_retries will override this default behavior and + guarantee retries even when if_generation_match is not set. (Deprecated: This + argument will be removed in a future release.)' + id: num_retries + var_type: int + - description: (Optional) The client to use. If not passed, falls back to the + client stored on the blob's bucket. + id: client + var_type: Client + - description: (Optional) Predefined access control list + id: predefined_acl + var_type: str + - description: (Optional) See :ref:using-if-generation-match + id: if_generation_match + var_type: long + - description: (Optional) See :ref:using-if-generation-not-match + id: if_generation_not_match + var_type: long + - description: (Optional) See :ref:using-if-metageneration-match + id: if_metageneration_match + var_type: long + - description: (Optional) See :ref:using-if-metageneration-not-match + id: if_metageneration_not_match + var_type: long + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: (Optional) The type of checksum to compute to verify the integrity + of the object. If the upload is completed in a single request, the checksum + will be entirely precomputed and the remote server will handle verification + and error handling. If the upload is too large and must be transmitted in + multiple requests, the checksum will be incrementally computed and the client + will handle verification and error handling, raising google.resumable_media.common.DataCorruption + on a mismatch and attempting to delete the corrupted file. Supported values + are "md5", "crc32c" and None. The default is None. + id: checksum + var_type: str + - description: (Optional) How to retry the RPC. A None value will disable retries. + A google.api_core.retry.Retry value will enable retries, and the object will + define retriable response codes and errors and configure backoff and timeout + options. A google.cloud.storage.retry.ConditionalRetryPolicy + value wraps a Retry object and activates it only if certain conditions are + met. This class exists to provide safe defaults for RPC calls that are not + technically safe to retry normally (due to potential data duplication or other + side-effects) but become safe to retry if a condition such as if_generation_match + is set. See the retry.py source code and docstrings in this package (google.cloud.storage.retry) for information + on retry types and how to configure them. Media operations (downloads and + uploads) do not support non-default predicates in a Retry object. The default + will always be used. Other configuration changes for Retry objects such as + delays and deadlines are respected. + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + type: method + uid: google.cloud.storage.blob.Blob.upload_from_string +- &id034 + attributes: [] + class: google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob.Blob.user_project + langs: + - python + module: google.cloud.storage.blob + name: user_project + source: + id: user_project + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Project ID billed for API requests made via this blob. + + + Derived from bucket''s value. + + ' + syntax: {} + type: property + uid: google.cloud.storage.blob.Blob.user_project +- *id034 +references: +- fullName: google.cloud.storage.blob.Blob + isExternal: false + name: Blob + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob +- fullName: google.cloud.storage.blob.Blob.STORAGE_CLASSES + isExternal: false + name: STORAGE_CLASSES + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.STORAGE_CLASSES +- fullName: google.cloud.storage.blob.Blob.acl + isExternal: false + name: acl + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.acl +- fullName: google.cloud.storage.blob.Blob.bucket + isExternal: false + name: bucket + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.bucket +- fullName: google.cloud.storage.blob.Blob.cache_control + isExternal: false + name: cache_control + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.cache_control +- fullName: google.cloud.storage.blob.Blob.chunk_size + isExternal: false + name: chunk_size + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.chunk_size +- fullName: google.cloud.storage.blob.Blob.client + isExternal: false + name: client + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.client +- fullName: google.cloud.storage.blob.Blob.component_count + isExternal: false + name: component_count + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.component_count +- fullName: google.cloud.storage.blob.Blob.compose + isExternal: false + name: compose + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.compose +- fullName: google.cloud.storage.blob.Blob.content_disposition + isExternal: false + name: content_disposition + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.content_disposition +- fullName: google.cloud.storage.blob.Blob.content_encoding + isExternal: false + name: content_encoding + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.content_encoding +- fullName: google.cloud.storage.blob.Blob.content_language + isExternal: false + name: content_language + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.content_language +- fullName: google.cloud.storage.blob.Blob.content_type + isExternal: false + name: content_type + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.content_type +- fullName: google.cloud.storage.blob.Blob.crc32c + isExternal: false + name: crc32c + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.crc32c +- fullName: google.cloud.storage.blob.Blob.create_resumable_upload_session + isExternal: false + name: create_resumable_upload_session + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.create_resumable_upload_session +- fullName: google.cloud.storage.blob.Blob.custom_time + isExternal: false + name: custom_time + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.custom_time +- fullName: google.cloud.storage.blob.Blob.delete + isExternal: false + name: delete + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.delete +- fullName: google.cloud.storage.blob.Blob.download_as_bytes + isExternal: false + name: download_as_bytes + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.download_as_bytes +- fullName: google.cloud.storage.blob.Blob.download_as_string + isExternal: false + name: download_as_string + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.download_as_string +- fullName: google.cloud.storage.blob.Blob.download_as_text + isExternal: false + name: download_as_text + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.download_as_text +- fullName: google.cloud.storage.blob.Blob.download_to_file + isExternal: false + name: download_to_file + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.download_to_file +- fullName: google.cloud.storage.blob.Blob.download_to_filename + isExternal: false + name: download_to_filename + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.download_to_filename +- fullName: google.cloud.storage.blob.Blob.encryption_key + isExternal: false + name: encryption_key + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.encryption_key +- fullName: google.cloud.storage.blob.Blob.etag + isExternal: false + name: etag + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.etag +- fullName: google.cloud.storage.blob.Blob.event_based_hold + isExternal: false + name: event_based_hold + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.event_based_hold +- fullName: google.cloud.storage.blob.Blob.exists + isExternal: false + name: exists + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.exists +- fullName: google.cloud.storage.blob.Blob.from_string + isExternal: false + name: from_string + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.from_string +- fullName: google.cloud.storage.blob.Blob.generate_signed_url + isExternal: false + name: generate_signed_url + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.generate_signed_url +- fullName: google.cloud.storage.blob.Blob.generation + isExternal: false + name: generation + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.generation +- fullName: google.cloud.storage.blob.Blob.get_iam_policy + isExternal: false + name: get_iam_policy + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.get_iam_policy +- fullName: google.cloud.storage.blob.Blob.id + isExternal: false + name: id + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.id +- fullName: google.cloud.storage.blob.Blob.kms_key_name + isExternal: false + name: kms_key_name + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.kms_key_name +- fullName: google.cloud.storage.blob.Blob.make_private + isExternal: false + name: make_private + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.make_private +- fullName: google.cloud.storage.blob.Blob.make_public + isExternal: false + name: make_public + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.make_public +- fullName: google.cloud.storage.blob.Blob.md5_hash + isExternal: false + name: md5_hash + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.md5_hash +- fullName: google.cloud.storage.blob.Blob.media_link + isExternal: false + name: media_link + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.media_link +- fullName: google.cloud.storage.blob.Blob.metadata + isExternal: false + name: metadata + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.metadata +- fullName: google.cloud.storage.blob.Blob.metageneration + isExternal: false + name: metageneration + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.metageneration +- fullName: google.cloud.storage.blob.Blob.open + isExternal: false + name: open + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.open +- fullName: google.cloud.storage.blob.Blob.owner + isExternal: false + name: owner + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.owner +- fullName: google.cloud.storage.blob.Blob.patch + isExternal: false + name: patch + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.patch +- fullName: google.cloud.storage.blob.Blob.path + isExternal: false + name: path + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.path +- fullName: google.cloud.storage.blob.Blob.path_helper + isExternal: false + name: path_helper + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.path_helper +- fullName: google.cloud.storage.blob.Blob.public_url + isExternal: false + name: public_url + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.public_url +- fullName: google.cloud.storage.blob.Blob.reload + isExternal: false + name: reload + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.reload +- fullName: google.cloud.storage.blob.Blob.retention_expiration_time + isExternal: false + name: retention_expiration_time + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.retention_expiration_time +- fullName: google.cloud.storage.blob.Blob.rewrite + isExternal: false + name: rewrite + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.rewrite +- fullName: google.cloud.storage.blob.Blob.self_link + isExternal: false + name: self_link + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.self_link +- fullName: google.cloud.storage.blob.Blob.set_iam_policy + isExternal: false + name: set_iam_policy + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.set_iam_policy +- fullName: google.cloud.storage.blob.Blob.size + isExternal: false + name: size + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.size +- fullName: google.cloud.storage.blob.Blob.storage_class + isExternal: false + name: storage_class + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.storage_class +- fullName: google.cloud.storage.blob.Blob.temporary_hold + isExternal: false + name: temporary_hold + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.temporary_hold +- fullName: google.cloud.storage.blob.Blob.test_iam_permissions + isExternal: false + name: test_iam_permissions + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.test_iam_permissions +- fullName: google.cloud.storage.blob.Blob.time_created + isExternal: false + name: time_created + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.time_created +- fullName: google.cloud.storage.blob.Blob.time_deleted + isExternal: false + name: time_deleted + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.time_deleted +- fullName: google.cloud.storage.blob.Blob.update + isExternal: false + name: update + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.update +- fullName: google.cloud.storage.blob.Blob.update_storage_class + isExternal: false + name: update_storage_class + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.update_storage_class +- fullName: google.cloud.storage.blob.Blob.updated + isExternal: false + name: updated + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.updated +- fullName: google.cloud.storage.blob.Blob.upload_from_file + isExternal: false + name: upload_from_file + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.upload_from_file +- fullName: google.cloud.storage.blob.Blob.upload_from_filename + isExternal: false + name: upload_from_filename + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.upload_from_filename +- fullName: google.cloud.storage.blob.Blob.upload_from_string + isExternal: false + name: upload_from_string + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.upload_from_string +- fullName: google.cloud.storage.blob.Blob.user_project + isExternal: false + name: user_project + parent: google.cloud.storage.blob.Blob + uid: google.cloud.storage.blob.Blob.user_project diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.blob.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.blob.yml new file mode 100644 index 000000000000..7254f7548f84 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.blob.yml @@ -0,0 +1,32 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: [] + children: + - google.cloud.storage.blob.Blob + fullName: google.cloud.storage.blob + langs: + - python + module: google.cloud.storage.blob + name: blob + source: + id: blob + path: tests/testdata/handwritten/google/cloud/storage/blob.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/blob.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 0 + summary: 'Create / interact with Google Cloud Storage blobs. + + + ' + syntax: {} + type: module + uid: google.cloud.storage.blob +references: +- fullName: google.cloud.storage.blob.Blob + isExternal: false + name: Blob + parent: google.cloud.storage.blob + uid: google.cloud.storage.blob.Blob diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.bucket.Bucket.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.bucket.Bucket.yml new file mode 100644 index 000000000000..a282a30f9b58 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.bucket.Bucket.yml @@ -0,0 +1,3266 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: [] + children: + - google.cloud.storage.bucket.Bucket + - google.cloud.storage.bucket.Bucket.STORAGE_CLASSES + - google.cloud.storage.bucket.Bucket.acl + - google.cloud.storage.bucket.Bucket.add_lifecycle_abort_incomplete_multipart_upload_rule + - google.cloud.storage.bucket.Bucket.add_lifecycle_delete_rule + - google.cloud.storage.bucket.Bucket.add_lifecycle_set_storage_class_rule + - google.cloud.storage.bucket.Bucket.blob + - google.cloud.storage.bucket.Bucket.clear_lifecyle_rules + - google.cloud.storage.bucket.Bucket.client + - google.cloud.storage.bucket.Bucket.configure_website + - google.cloud.storage.bucket.Bucket.copy_blob + - google.cloud.storage.bucket.Bucket.cors + - google.cloud.storage.bucket.Bucket.create + - google.cloud.storage.bucket.Bucket.data_locations + - google.cloud.storage.bucket.Bucket.default_event_based_hold + - google.cloud.storage.bucket.Bucket.default_kms_key_name + - google.cloud.storage.bucket.Bucket.default_object_acl + - google.cloud.storage.bucket.Bucket.delete + - google.cloud.storage.bucket.Bucket.delete_blob + - google.cloud.storage.bucket.Bucket.delete_blobs + - google.cloud.storage.bucket.Bucket.disable_logging + - google.cloud.storage.bucket.Bucket.disable_website + - google.cloud.storage.bucket.Bucket.enable_logging + - google.cloud.storage.bucket.Bucket.etag + - google.cloud.storage.bucket.Bucket.exists + - google.cloud.storage.bucket.Bucket.from_string + - google.cloud.storage.bucket.Bucket.generate_signed_url + - google.cloud.storage.bucket.Bucket.generate_upload_policy + - google.cloud.storage.bucket.Bucket.get_blob + - google.cloud.storage.bucket.Bucket.get_iam_policy + - google.cloud.storage.bucket.Bucket.get_logging + - google.cloud.storage.bucket.Bucket.get_notification + - google.cloud.storage.bucket.Bucket.iam_configuration + - google.cloud.storage.bucket.Bucket.id + - google.cloud.storage.bucket.Bucket.labels + - google.cloud.storage.bucket.Bucket.lifecycle_rules + - google.cloud.storage.bucket.Bucket.list_blobs + - google.cloud.storage.bucket.Bucket.list_notifications + - google.cloud.storage.bucket.Bucket.location + - google.cloud.storage.bucket.Bucket.location_type + - google.cloud.storage.bucket.Bucket.lock_retention_policy + - google.cloud.storage.bucket.Bucket.make_private + - google.cloud.storage.bucket.Bucket.make_public + - google.cloud.storage.bucket.Bucket.metageneration + - google.cloud.storage.bucket.Bucket.notification + - google.cloud.storage.bucket.Bucket.owner + - google.cloud.storage.bucket.Bucket.patch + - google.cloud.storage.bucket.Bucket.path + - google.cloud.storage.bucket.Bucket.path_helper + - google.cloud.storage.bucket.Bucket.project_number + - google.cloud.storage.bucket.Bucket.reload + - google.cloud.storage.bucket.Bucket.rename_blob + - google.cloud.storage.bucket.Bucket.requester_pays + - google.cloud.storage.bucket.Bucket.retention_period + - google.cloud.storage.bucket.Bucket.retention_policy_effective_time + - google.cloud.storage.bucket.Bucket.retention_policy_locked + - google.cloud.storage.bucket.Bucket.rpo + - google.cloud.storage.bucket.Bucket.self_link + - google.cloud.storage.bucket.Bucket.set_iam_policy + - google.cloud.storage.bucket.Bucket.storage_class + - google.cloud.storage.bucket.Bucket.test_iam_permissions + - google.cloud.storage.bucket.Bucket.time_created + - google.cloud.storage.bucket.Bucket.update + - google.cloud.storage.bucket.Bucket.user_project + - google.cloud.storage.bucket.Bucket.versioning_enabled + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket + inheritance: + - inheritance: + - type: builtins.object + type: google.cloud.storage._helpers._PropertyMixin + langs: + - python + module: google.cloud.storage.bucket + name: Bucket + source: + id: Bucket + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 615 + summary: 'A class representing a Bucket on Cloud Storage. + + ' + syntax: + content: Bucket(client, name=None, user_project=None) + parameters: + - description: A client which holds credentials and project configuration for + the bucket (which requires a project). + id: client + var_type: Client + - description: The name of the bucket. Bucket names must start and end with a + number or letter. + id: name + var_type: str + - description: (Optional) the project ID to be billed for API requests made via + this instance. + id: user_project + var_type: str + type: class + uid: google.cloud.storage.bucket.Bucket +- attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket + inheritance: + - inheritance: + - type: builtins.object + type: google.cloud.storage._helpers._PropertyMixin + langs: + - python + module: google.cloud.storage.bucket + name: Bucket + source: + id: Bucket + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 615 + summary: "property `name`\n Get the bucket's name.\n\n" + syntax: + content: Bucket(client, name=None, user_project=None) + parameters: [] + type: method + uid: google.cloud.storage.bucket.Bucket +- attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.STORAGE_CLASSES + langs: + - python + module: google.cloud.storage.bucket + name: STORAGE_CLASSES + source: + id: STORAGE_CLASSES + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Allowed values for `storage_class`. + + + Default value is `STANDARD_STORAGE_CLASS`. + + + See + + https://cloud.google.com/storage/docs/json_api/v1/buckets#storageClass + + https://cloud.google.com/storage/docs/storage-classes + + + ' + syntax: {} + type: attribute + uid: google.cloud.storage.bucket.Bucket.STORAGE_CLASSES +- &id001 + attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.acl + langs: + - python + module: google.cloud.storage.bucket + name: acl + source: + id: acl + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Create our ACL on demand. + + + ' + syntax: {} + type: property + uid: google.cloud.storage.bucket.Bucket.acl +- *id001 +- attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.add_lifecycle_abort_incomplete_multipart_upload_rule + langs: + - python + module: google.cloud.storage.bucket + name: add_lifecycle_abort_incomplete_multipart_upload_rule + source: + id: add_lifecycle_abort_incomplete_multipart_upload_rule + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 2317 + summary: 'Add a "abort incomplete multipart upload" rule to lifecycle rules. + + + + + This defines a [lifecycle configuration](https://cloud.google.com/storage/docs/lifecycle), + + which is set on the bucket. For the general format of a lifecycle configuration, + see the + + [bucket resource representation for JSON](https://cloud.google.com/storage/docs/json_api/v1/buckets). + + ' + syntax: + content: add_lifecycle_abort_incomplete_multipart_upload_rule(**kw) + parameters: [] + type: method + uid: google.cloud.storage.bucket.Bucket.add_lifecycle_abort_incomplete_multipart_upload_rule +- attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.add_lifecycle_delete_rule + langs: + - python + module: google.cloud.storage.bucket + name: add_lifecycle_delete_rule + source: + id: add_lifecycle_delete_rule + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 2285 + summary: 'Add a "delete" rule to lifecycle rules configured for this bucket. + + + This defines a [lifecycle configuration](https://cloud.google.com/storage/docs/lifecycle), + + which is set on the bucket. For the general format of a lifecycle configuration, + see the + + [bucket resource representation for JSON](https://cloud.google.com/storage/docs/json_api/v1/buckets). + + See also a [code sample](https://cloud.google.com/storage/docs/samples/storage-enable-bucket-lifecycle-management#storage_enable_bucket_lifecycle_management-python). + + ' + syntax: + content: add_lifecycle_delete_rule(**kw) + parameters: [] + type: method + uid: google.cloud.storage.bucket.Bucket.add_lifecycle_delete_rule +- attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.add_lifecycle_set_storage_class_rule + langs: + - python + module: google.cloud.storage.bucket + name: add_lifecycle_set_storage_class_rule + source: + id: add_lifecycle_set_storage_class_rule + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 2300 + summary: 'Add a "set storage class" rule to lifecycle rules. + + + This defines a [lifecycle configuration](https://cloud.google.com/storage/docs/lifecycle), + + which is set on the bucket. For the general format of a lifecycle configuration, + see the + + [bucket resource representation for JSON](https://cloud.google.com/storage/docs/json_api/v1/buckets). + + ' + syntax: + content: add_lifecycle_set_storage_class_rule(storage_class, **kw) + parameters: + - description: new storage class to assign to matching items. + id: storage_class + var_type: str, one of STORAGE_CLASSES. + type: method + uid: google.cloud.storage.bucket.Bucket.add_lifecycle_set_storage_class_rule +- attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.blob + langs: + - python + module: google.cloud.storage.bucket + name: blob + source: + id: blob + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 758 + summary: 'Factory constructor for blob object. + + + ' + syntax: + content: "blob(\n blob_name, chunk_size=None, encryption_key=None, kms_key_name=None,\ + \ generation=None\n)" + parameters: + - description: The name of the blob to be instantiated. + id: blob_name + var_type: str + - description: The size of a chunk of data whenever iterating (in bytes). This + must be a multiple of 256 KB per the API specification. + id: chunk_size + var_type: int + - description: (Optional) 32 byte encryption key for customer-supplied encryption. + id: encryption_key + var_type: bytes + - description: (Optional) Resource name of KMS key used to encrypt blob's content. + id: kms_key_name + var_type: str + - description: (Optional) If present, selects a specific revision of this object. + id: generation + var_type: long + returns: + - description: The blob object created. + var_type: Blob + type: method + uid: google.cloud.storage.bucket.Bucket.blob +- attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.clear_lifecyle_rules + langs: + - python + module: google.cloud.storage.bucket + name: clear_lifecyle_rules + source: + id: clear_lifecyle_rules + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 2277 + summary: "Clear lifecycle rules configured for this bucket.\n\nSee https://cloud.google.com/storage/docs/lifecycle\ + \ and\n https://cloud.google.com/storage/docs/json_api/v1/buckets\n\n" + syntax: + content: clear_lifecyle_rules() + parameters: [] + type: method + uid: google.cloud.storage.bucket.Bucket.clear_lifecyle_rules +- &id002 + attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.client + langs: + - python + module: google.cloud.storage.bucket + name: client + source: + id: client + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'The client bound to this bucket. + + + ' + syntax: {} + type: property + uid: google.cloud.storage.bucket.Bucket.client +- *id002 +- attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.configure_website + langs: + - python + module: google.cloud.storage.bucket + name: configure_website + source: + id: configure_website + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 2663 + summary: 'Configure website-related properties. + + + See https://cloud.google.com/storage/docs/static-website + + + ' + syntax: + content: configure_website(main_page_suffix=None, not_found_page=None) + parameters: + - description: The page to use as the main page of a directory. Typically something + like index.html. + id: main_page_suffix + var_type: str + - description: The file to use when a page isn't found. + id: not_found_page + var_type: str + type: method + uid: google.cloud.storage.bucket.Bucket.configure_website +- attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.copy_blob + langs: + - python + module: google.cloud.storage.bucket + name: copy_blob + source: + id: copy_blob + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 1771 + summary: 'Copy the given blob to the given bucket, optionally with a new name. + + + If `user_project` is set, bills the API request to that project. + + + See [API reference docs](https://cloud.google.com/storage/docs/json_api/v1/objects/copy) + + and a [code sample](https://cloud.google.com/storage/docs/samples/storage-copy-file#storage_copy_file-python). + + ' + syntax: + content: copy_blob(blob, destination_bucket, new_name=None, client=None, preserve_acl=True, + source_generation=None, if_generation_match=None, if_generation_not_match=None, + if_metageneration_match=None, if_metageneration_not_match=None, if_source_generation_match=None, + if_source_generation_not_match=None, if_source_metageneration_match=None, if_source_metageneration_not_match=None, + timeout=60, retry=) + parameters: + - description: The blob to be copied. + id: blob + var_type: Blob + - description: The bucket into which the blob should be copied. + id: destination_bucket + var_type: Bucket + - description: (Optional) The new name for the copied file. + id: new_name + var_type: str + - description: (Optional) The client to use. If not passed, falls back to the + client stored on the current bucket. + id: client + var_type: Client or NoneType + - description: 'DEPRECATED. This argument is not functional! (Optional) Copies + ACL from old blob to new blob. Default: True.' + id: preserve_acl + var_type: bool + - description: (Optional) The generation of the blob to be copied. + id: source_generation + var_type: long + - description: (Optional) See :ref:using-if-generation-match Note + that the generation to be matched is that of the destination + blob. + id: if_generation_match + var_type: long + - description: (Optional) See :ref:using-if-generation-not-match + Note that the generation to be matched is that of the destination + blob. + id: if_generation_not_match + var_type: long + - description: (Optional) See :ref:using-if-metageneration-match + Note that the metageneration to be matched is that of the destination + blob. + id: if_metageneration_match + var_type: long + - description: (Optional) See :ref:using-if-metageneration-not-match + Note that the metageneration to be matched is that of the destination + blob. + id: if_metageneration_not_match + var_type: long + - description: (Optional) Makes the operation conditional on whether the source + object's generation matches the given value. + id: if_source_generation_match + var_type: long + - description: (Optional) Makes the operation conditional on whether the source + object's generation does not match the given value. + id: if_source_generation_not_match + var_type: long + - description: (Optional) Makes the operation conditional on whether the source + object's current metageneration matches the given value. + id: if_source_metageneration_match + var_type: long + - description: (Optional) Makes the operation conditional on whether the source + object's current metageneration does not match the given value. + id: if_source_metageneration_not_match + var_type: long + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: '(Optional) How to retry the RPC. See: configuring_retries' + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + returns: + - description: The new Blob. + var_type: Blob + type: method + uid: google.cloud.storage.bucket.Bucket.copy_blob +- &id003 + attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.cors + langs: + - python + module: google.cloud.storage.bucket + name: cors + source: + id: cors + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: "Retrieve or set CORS policies configured for this bucket.\n\nSee http://www.w3.org/TR/cors/\ + \ and\n https://cloud.google.com/storage/docs/json_api/v1/buckets\n\n\nNote:\nThe getter for this property returns a list which\ + \ contains\n*copies* of the bucket's CORS policy mappings. Mutating the list\n\ + or one of its dicts has no effect unless you then re-assign the\ndict via the\ + \ setter. E.g.:\n>>> policies = bucket.cors\n>>> policies.append({'origin': '/foo',\ + \ ...})\n>>> policies[1]['maxAgeSeconds'] = 3600\n>>> del policies[0]\n>>> bucket.cors\ + \ = policies\n>>> bucket.update()\n" + syntax: + returns: + - description: A sequence of mappings describing each CORS policy. + var_type: list of dictionaries + type: property + uid: google.cloud.storage.bucket.Bucket.cors +- *id003 +- attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.create + langs: + - python + module: google.cloud.storage.bucket + name: create + source: + id: create + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 915 + summary: 'DEPRECATED. Creates current bucket. + + + + + If the bucket already exists, will raise + + xref_Conflict. + + + This implements "storage.buckets.insert". + + + If `user_project` is set, bills the API request to that project. + + ' + syntax: + content: create(client=None, project=None, location=None, predefined_acl=None, + predefined_default_object_acl=None, timeout=60, retry=) + exceptions: + - description: if project is None and client's project + is also None. + var_type: ValueError + parameters: + - description: (Optional) The client to use. If not passed, falls back to the + client stored on the current bucket. + id: client + var_type: Client or NoneType + - description: (Optional) The project under which the bucket is to be created. + If not passed, uses the project set on the client. + id: project + var_type: str + - description: (Optional) The location of the bucket. If not passed, the default + location, US, will be used. See https://cloud.google.com/storage/docs/bucket-locations + id: location + var_type: str + - description: '(Optional) Name of predefined ACL to apply to bucket. See: https://cloud.google.com/storage/docs/access-control/lists#predefined-acl' + id: predefined_acl + var_type: str + - description: '(Optional) Name of predefined ACL to apply to bucket''s objects. + See: https://cloud.google.com/storage/docs/access-control/lists#predefined-acl' + id: predefined_default_object_acl + var_type: str + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: '(Optional) How to retry the RPC. See: configuring_retries' + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + type: method + uid: google.cloud.storage.bucket.Bucket.create +- &id004 + attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.data_locations + langs: + - python + module: google.cloud.storage.bucket + name: data_locations + source: + id: data_locations + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Retrieve the list of regional locations for custom dual-region buckets. + + + See https://cloud.google.com/storage/docs/json_api/v1/buckets and + + https://cloud.google.com/storage/docs/locations + + + Returns `None` if the property has not been set before creation, + + if the bucket''s resource has not been loaded from the server, + + or if the bucket is not a dual-regions bucket. + + + ' + syntax: {} + type: property + uid: google.cloud.storage.bucket.Bucket.data_locations +- *id004 +- &id005 + attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.default_event_based_hold + langs: + - python + module: google.cloud.storage.bucket + name: default_event_based_hold + source: + id: default_event_based_hold + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Scalar property getter. + + + ' + syntax: {} + type: property + uid: google.cloud.storage.bucket.Bucket.default_event_based_hold +- *id005 +- &id006 + attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.default_kms_key_name + langs: + - python + module: google.cloud.storage.bucket + name: default_kms_key_name + source: + id: default_kms_key_name + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Retrieve / set default KMS encryption key for objects in the bucket. + + + See https://cloud.google.com/storage/docs/json_api/v1/buckets + + + :setter: Set default KMS encryption key for items in this bucket. + + :getter: Get default KMS encryption key for items in this bucket. + + ' + syntax: + returns: + - description: Default KMS encryption key, or None if not set. + var_type: str + type: property + uid: google.cloud.storage.bucket.Bucket.default_kms_key_name +- *id006 +- &id007 + attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.default_object_acl + langs: + - python + module: google.cloud.storage.bucket + name: default_object_acl + source: + id: default_object_acl + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Create our defaultObjectACL on demand. + + + ' + syntax: {} + type: property + uid: google.cloud.storage.bucket.Bucket.default_object_acl +- *id007 +- attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.delete + langs: + - python + module: google.cloud.storage.bucket + name: delete + source: + id: delete + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 1475 + summary: 'Delete this bucket. + + + The bucket **must** be empty in order to submit a delete request. If + + `force=True` is passed, this will first attempt to delete all the + + objects / blobs in the bucket (i.e. try to empty the bucket). + + + If the bucket doesn''t exist, this will raise + + xref_NotFound. If the bucket is not empty + + (and `force=False`), will raise xref_Conflict. + + + If `force=True` and the bucket contains more than 256 objects / blobs + + this will cowardly refuse to delete the objects (or the bucket). This + + is to prevent accidental bucket deletion and to prevent extremely long + + runtime of this method. + + + If `user_project` is set, bills the API request to that project. + + ' + syntax: + content: delete(force=False, client=None, if_metageneration_match=None, if_metageneration_not_match=None, + timeout=60, retry=) + exceptions: + - description: if force is True and the bucket contains + more than 256 objects / blobs. + var_type: '`ValueError' + parameters: + - description: If True, empties the bucket's objects then deletes it. + id: force + var_type: bool + - description: (Optional) The client to use. If not passed, falls back to the + client stored on the current bucket. + id: client + var_type: Client or NoneType + - description: (Optional) Make the operation conditional on whether the blob's + current metageneration matches the given value. + id: if_metageneration_match + var_type: long + - description: (Optional) Make the operation conditional on whether the blob's + current metageneration does not match the given value. + id: if_metageneration_not_match + var_type: long + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: '(Optional) How to retry the RPC. See: configuring_retries' + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + type: method + uid: google.cloud.storage.bucket.Bucket.delete +- attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.delete_blob + langs: + - python + module: google.cloud.storage.bucket + name: delete_blob + source: + id: delete_blob + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 1578 + summary: 'Deletes a blob from the current bucket. + + + If `user_project` is set, bills the API request to that project. + + ' + syntax: + content: delete_blob(blob_name, client=None, generation=None, if_generation_match=None, + if_generation_not_match=None, if_metageneration_match=None, if_metageneration_not_match=None, + timeout=60, retry=) + exceptions: + - description: Raises a NotFound if the blob isn't found. To suppress the exception, + use delete_blobs by passing a no-op on_error callback. + var_type: NotFoundclient stored on the current bucket. + id: client + var_type: Client or NoneType + - description: (Optional) If present, permanently deletes a specific revision + of this object. + id: generation + var_type: long + - description: (Optional) See :ref:using-if-generation-match + id: if_generation_match + var_type: long + - description: (Optional) See :ref:using-if-generation-not-match + id: if_generation_not_match + var_type: long + - description: (Optional) See :ref:using-if-metageneration-match + id: if_metageneration_match + var_type: long + - description: (Optional) See :ref:using-if-metageneration-not-match + id: if_metageneration_not_match + var_type: long + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: '(Optional) How to retry the RPC. See: configuring_retries' + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + type: method + uid: google.cloud.storage.bucket.Bucket.delete_blob +- attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.delete_blobs + langs: + - python + module: google.cloud.storage.bucket + name: delete_blobs + source: + id: delete_blobs + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 1658 + summary: 'Deletes a list of blobs from the current bucket. + + + Uses `delete_blob` to delete each individual blob. + + + By default, any generation information in the list of blobs is ignored, and the + + live versions of all blobs are deleted. Set `preserve_generation` to True + + if blob generation should instead be propagated from the list of blobs. + + + If `user_project` is set, bills the API request to that project. + + ' + syntax: + content: delete_blobs(blobs, on_error=None, client=None, preserve_generation=False, + timeout=60, if_generation_match=None, if_generation_not_match=None, if_metageneration_match=None, + if_metageneration_not_match=None, retry=) + exceptions: + - description: (if on_error is not passed). + var_type: NotFoundBlob-s + or blob names to delete. + id: blobs + var_type: list + - description: '(Optional) Takes single argument: blob. Called once + for each blob raising NotFound; + otherwise, the exception is propagated.' + id: on_error + var_type: callable + - description: (Optional) The client to use. If not passed, falls back to the + client stored on the current bucket. + id: client + var_type: Client + - description: '(Optional) Deletes only the generation specified on the blob object, + instead of the live version, if set to True. Only :class:Blob + objects can have their generation set in this way. Default: False.' + id: preserve_generation + var_type: bool + - description: (Optional) See :ref:using-if-generation-match Note + that the length of the list must match the length of The list must match blobs + item-to-item. + id: if_generation_match + var_type: list of long + - description: (Optional) See :ref:using-if-generation-not-match + The list must match blobs item-to-item. + id: if_generation_not_match + var_type: list of long + - description: (Optional) See :ref:using-if-metageneration-match + The list must match blobs item-to-item. + id: if_metageneration_match + var_type: list of long + - description: (Optional) See :ref:using-if-metageneration-not-match + The list must match blobs item-to-item. + id: if_metageneration_not_match + var_type: list of long + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: '(Optional) How to retry the RPC. See: configuring_retries' + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + type: method + uid: google.cloud.storage.bucket.Bucket.delete_blobs +- attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.disable_logging + langs: + - python + module: google.cloud.storage.bucket + name: disable_logging + source: + id: disable_logging + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 2427 + summary: 'Disable access logging for this bucket. + + + See https://cloud.google.com/storage/docs/access-logs#disabling + + + ' + syntax: + content: disable_logging() + parameters: [] + type: method + uid: google.cloud.storage.bucket.Bucket.disable_logging +- attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.disable_website + langs: + - python + module: google.cloud.storage.bucket + name: disable_website + source: + id: disable_website + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 2686 + summary: 'Disable the website configuration for this bucket. + + + This is really just a shortcut for setting the website-related + + attributes to `None`. + + + ' + syntax: + content: disable_website() + parameters: [] + type: method + uid: google.cloud.storage.bucket.Bucket.disable_website +- attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.enable_logging + langs: + - python + module: google.cloud.storage.bucket + name: enable_logging + source: + id: enable_logging + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 2413 + summary: 'Enable access logging for this bucket. + + + See https://cloud.google.com/storage/docs/access-logs + + ' + syntax: + content: enable_logging(bucket_name, object_prefix="") + parameters: + - description: name of bucket in which to store access logs + id: bucket_name + var_type: str + - description: prefix for access log filenames + id: object_prefix + var_type: str + type: method + uid: google.cloud.storage.bucket.Bucket.enable_logging +- &id008 + attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.etag + langs: + - python + module: google.cloud.storage.bucket + name: etag + source: + id: etag + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: "Retrieve the ETag for the bucket.\n\nSee https://tools.ietf.org/html/rfc2616#section-3.11\ + \ and\n https://cloud.google.com/storage/docs/json_api/v1/buckets\n" + syntax: + returns: + - description: The bucket etag or None if the bucket's resource has + not been loaded from the server. + var_type: str or NoneType + type: property + uid: google.cloud.storage.bucket.Bucket.etag +- *id008 +- attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.exists + langs: + - python + module: google.cloud.storage.bucket + name: exists + source: + id: exists + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 831 + summary: 'Determines whether or not this bucket exists. + + + If `user_project` is set, bills the API request to that project. + + ' + syntax: + content: exists(client=None, timeout=60, if_etag_match=None, if_etag_not_match=None, + if_metageneration_match=None, if_metageneration_not_match=None, retry=) + parameters: + - description: (Optional) The client to use. If not passed, falls back to the + client stored on the current bucket. + id: client + var_type: Client or NoneType + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: (Optional) Make the operation conditional on whether the bucket's + current ETag matches the given value. + id: if_etag_match + var_type: Union[str, Set[str]] + - description: (Optional) Make the operation conditional on whether the bucket's + current ETag does not match the given value. + id: if_etag_not_match + var_type: Union[str, Set[str]]) + - description: (Optional) Make the operation conditional on whether the bucket's + current metageneration matches the given value. + id: if_metageneration_match + var_type: long + - description: (Optional) Make the operation conditional on whether the bucket's + current metageneration does not match the given value. + id: if_metageneration_not_match + var_type: long + - description: '(Optional) How to retry the RPC. See: configuring_retries' + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + returns: + - description: True if the bucket exists in Cloud Storage. + var_type: bool + type: method + uid: google.cloud.storage.bucket.Bucket.exists +- attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.from_string + langs: + - python + module: google.cloud.storage.bucket + name: from_string + source: + id: from_string + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 729 + summary: 'Get a constructor for bucket object by URI. + + + ```python + + from google.cloud import storage + + from google.cloud.storage.bucket import Bucket + + client = storage.Client() + + bucket = Bucket.from_string("gs://bucket", client=client) + + ``` + + ' + syntax: + content: from_string(uri, client=None) + parameters: + - description: The bucket uri pass to get bucket object. + id: uri + var_type: str + - description: (Optional) The client to use. Application code should *always* + pass client. + id: client + var_type: Client or NoneType + returns: + - description: The bucket object created. + var_type: Bucket + type: method + uid: google.cloud.storage.bucket.Bucket.from_string +- attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.generate_signed_url + langs: + - python + module: google.cloud.storage.bucket + name: generate_signed_url + source: + id: generate_signed_url + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 3156 + summary: 'Generates a signed URL for this bucket. + + + + + If `bucket_bound_hostname` is set as an argument of `api_access_endpoint`, + + `https` works only if using a `CDN`. + + ' + syntax: + content: "generate_signed_url(\n expiration=None,\n api_access_endpoint=\"\ + https://storage.googleapis.com\",\n method=\"GET\",\n headers=None,\n\ + \ query_parameters=None,\n client=None,\n credentials=None,\n version=None,\n\ + \ virtual_hosted_style=False,\n bucket_bound_hostname=None,\n scheme=\"\ + http\",\n)" + exceptions: + - description: when version is invalid. + var_type: '`ValueError' + - description: when expiration is not a valid type. + var_type: '`TypeError' + - description: if credentials is not an instance of google.auth.credentials.Signing. + var_type: '`AttributeError' + parameters: + - description: Point in time when the signed URL should expire. If a datetime + instance is passed without an explicit tzinfo set, it will be + assumed to be UTC. + id: expiration + var_type: Union[Integer, datetime.datetime, datetime.timedelta] + - description: (Optional) URI base. + id: api_access_endpoint + var_type: str + - description: The HTTP verb that will be used when requesting the URL. + id: method + var_type: str + - description: '(Optional) Additional HTTP headers to be included as part of the + signed URLs. See: https://cloud.google.com/storage/docs/xml-api/reference-headers + Requests using the signed URL *must* pass the specified header (name and value) + with each request for the URL.' + id: headers + var_type: dict + - description: '(Optional) Additional query parameters to be included as part + of the signed URLs. See: https://cloud.google.com/storage/docs/xml-api/reference-headers#query' + id: query_parameters + var_type: dict + - description: (Optional) The client to use. If not passed, falls back to the + client stored on the blob's bucket. + id: client + var_type: Client or NoneType + - description: The authorization credentials to attach to requests. These credentials + identify this application to the service. If none are specified, the client + will attempt to ascertain the credentials from the environment. + id: credentials + var_type: google.auth.credentials.Credentials or NoneType + - description: (Optional) The version of signed credential to create. Must be + one of 'v2' 'v4'. + id: version + var_type: str + - description: (Optional) If true, then construct the URL relative the bucket's + virtual hostname, e.g., '.storage.googleapis.com'. + id: virtual_hosted_style + var_type: bool + - description: '(Optional) If pass, then construct the URL relative to the bucket-bound + hostname. Value cane be a bare or with scheme, e.g., ''example.com'' or ''http://example.com''. + See: https://cloud.google.com/storage/docs/request-endpoints#cname' + id: bucket_bound_hostname + var_type: str + - description: (Optional) If bucket_bound_hostname is passed as a + bare hostname, use this value as the scheme. https will work + only when using a CDN. Defaults to "http". + id: scheme + var_type: str + returns: + - description: A signed URL you can use to access the resource until expiration. + var_type: str + type: method + uid: google.cloud.storage.bucket.Bucket.generate_signed_url +- attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.generate_upload_policy + langs: + - python + module: google.cloud.storage.bucket + name: generate_upload_policy + source: + id: generate_upload_policy + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 3049 + summary: 'Create a signed upload policy for uploading objects. + + + This method generates and signs a policy document. You can use + + [`policy documents`](https://cloud.google.com/storage/docs/xml-api/post-object-forms) + + to allow visitors to a website to upload files to + + Google Cloud Storage without giving them direct write access. + + See a [code sample](https://cloud.google.com/storage/docs/xml-api/post-object-forms#python). + + ' + syntax: + content: generate_upload_policy(conditions, expiration=None, client=None) + parameters: + - description: (Optional) Expiration in UTC. If not specified, the policy will + expire in 1 hour. + id: expiration + var_type: datetime + - description: A list of conditions as described in the policy documents + documentation. + id: conditions + var_type: list + - description: (Optional) The client to use. If not passed, falls back to the + client stored on the current bucket. + id: client + var_type: Client + returns: + - description: A dictionary of (form field name, form field value) of form fields + that should be added to your HTML upload form in order to attach the signature. + var_type: dict + type: method + uid: google.cloud.storage.bucket.Bucket.generate_upload_policy +- attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.get_blob + langs: + - python + module: google.cloud.storage.bucket + name: get_blob + source: + id: get_blob + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 1180 + summary: 'Get a blob object by name. + + + See a [code sample](https://cloud.google.com/storage/docs/samples/storage-get-metadata#storage_get_metadata-python) + + on how to retrieve metadata of an object. + + + If `user_project` is set, bills the API request to that project. + + ' + syntax: + content: get_blob(blob_name, client=None, encryption_key=None, generation=None, + if_etag_match=None, if_etag_not_match=None, if_generation_match=None, if_generation_not_match=None, + if_metageneration_match=None, if_metageneration_not_match=None, timeout=60, + retry=, **kwargs) + parameters: + - description: The name of the blob to retrieve. + id: blob_name + var_type: str + - description: (Optional) The client to use. If not passed, falls back to the + client stored on the current bucket. + id: client + var_type: Client or NoneType + - description: (Optional) 32 byte encryption key for customer-supplied encryption. + See https://cloud.google.com/storage/docs/encryption#customer-supplied. + id: encryption_key + var_type: bytes + - description: (Optional) If present, selects a specific revision of this object. + id: generation + var_type: long + - description: (Optional) See :ref:using-if-etag-match + id: if_etag_match + var_type: Union[str, Set[str]] + - description: (Optional) See :ref:using-if-etag-not-match + id: if_etag_not_match + var_type: Union[str, Set[str]] + - description: (Optional) See :ref:using-if-generation-match + id: if_generation_match + var_type: long + - description: (Optional) See :ref:using-if-generation-not-match + id: if_generation_not_match + var_type: long + - description: (Optional) See :ref:using-if-metageneration-match + id: if_metageneration_match + var_type: long + - description: (Optional) See :ref:using-if-metageneration-not-match + id: if_metageneration_not_match + var_type: long + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: '(Optional) How to retry the RPC. See: configuring_retries' + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + returns: + - description: The blob object if it exists, otherwise None. + var_type: Blob or None + type: method + uid: google.cloud.storage.bucket.Bucket.get_blob +- attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.get_iam_policy + langs: + - python + module: google.cloud.storage.bucket + name: get_iam_policy + source: + id: get_iam_policy + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 2694 + summary: 'Retrieve the IAM policy for the bucket. + + + See [API reference docs](https://cloud.google.com/storage/docs/json_api/v1/buckets/getIamPolicy) + + and a [code sample](https://cloud.google.com/storage/docs/samples/storage-view-bucket-iam-members#storage_view_bucket_iam_members-python). + + + If `user_project` is set, bills the API request to that project. + + ' + syntax: + content: get_iam_policy(client=None, requested_policy_version=None, timeout=60, + retry=) + parameters: + - description: (Optional) The client to use. If not passed, falls back to the + client stored on the current bucket. + id: client + var_type: Client or NoneType + - description: (Optional) The version of IAM policies to request. If a policy + with a condition is requested without setting this, the server will return + an error. This must be set to a value of 3 to retrieve IAM policies containing + conditions. This is to prevent client code that isn't aware of IAM conditions + from interpreting and modifying policies incorrectly. The service might return + a policy with version lower than the one that was requested, based on the + feature syntax in the policy fetched. + id: requested_policy_version + var_type: int or NoneType + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: '(Optional) How to retry the RPC. See: configuring_retries' + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + returns: + - description: the policy instance, based on the resource returned from the getIamPolicy + API request. + var_type: google.api_core.iam.Policy + type: method + uid: google.cloud.storage.bucket.Bucket.get_iam_policy +- attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.get_logging + langs: + - python + module: google.cloud.storage.bucket + name: get_logging + source: + id: get_logging + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 2401 + summary: 'Return info about access logging for this bucket. + + + See https://cloud.google.com/storage/docs/access-logs#status + + ' + syntax: + content: get_logging() + parameters: [] + returns: + - description: a dict w/ keys, logBucket and logObjectPrefix + (if logging is enabled), or None (if not). + var_type: dict or None + type: method + uid: google.cloud.storage.bucket.Bucket.get_logging +- attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.get_notification + langs: + - python + module: google.cloud.storage.bucket + name: get_notification + source: + id: get_notification + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 1438 + summary: 'Get Pub / Sub notification for this bucket. + + + See [API reference docs](https://cloud.google.com/storage/docs/json_api/v1/notifications/get) + + and a [code sample](https://cloud.google.com/storage/docs/samples/storage-print-pubsub-bucket-notification#storage_print_pubsub_bucket_notification-python). + + + If `user_project` is set, bills the API request to that project. + + ' + syntax: + content: get_notification(notification_id, client=None, timeout=60, retry=) + parameters: + - description: The notification id to retrieve the notification configuration. + id: notification_id + var_type: str + - description: (Optional) The client to use. If not passed, falls back to the + client stored on the current bucket. + id: client + var_type: Client or NoneType + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: '(Optional) How to retry the RPC. See: configuring_retries' + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + returns: + - description: notification instance. + var_type: .BucketNotification + type: method + uid: google.cloud.storage.bucket.Bucket.get_notification +- &id009 + attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.iam_configuration + langs: + - python + module: google.cloud.storage.bucket + name: iam_configuration + source: + id: iam_configuration + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Retrieve IAM configuration for this bucket. + + ' + syntax: + returns: + - description: an instance for managing the bucket's IAM configuration. + var_type: IAMConfiguration + type: property + uid: google.cloud.storage.bucket.Bucket.iam_configuration +- *id009 +- &id010 + attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.id + langs: + - python + module: google.cloud.storage.bucket + name: id + source: + id: id + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Retrieve the ID for the bucket. + + + See https://cloud.google.com/storage/docs/json_api/v1/buckets + + ' + syntax: + returns: + - description: The ID of the bucket or None if the bucket's resource + has not been loaded from the server. + var_type: str or NoneType + type: property + uid: google.cloud.storage.bucket.Bucket.id +- *id010 +- &id011 + attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.labels + langs: + - python + module: google.cloud.storage.bucket + name: labels + source: + id: labels + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Retrieve or set labels assigned to this bucket. + + + See + + https://cloud.google.com/storage/docs/json_api/v1/buckets#labels + + + ' + syntax: + returns: + - description: Name-value pairs (string->string) labelling the bucket. + var_type: dict + type: property + uid: google.cloud.storage.bucket.Bucket.labels +- *id011 +- &id012 + attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.lifecycle_rules + langs: + - python + module: google.cloud.storage.bucket + name: lifecycle_rules + source: + id: lifecycle_rules + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: "Retrieve or set lifecycle rules configured for this bucket.\n\nSee https://cloud.google.com/storage/docs/lifecycle\ + \ and\n https://cloud.google.com/storage/docs/json_api/v1/buckets\n\n\nNote:\nThe getter for this property returns a generator\ + \ which yields\n*copies* of the bucket's lifecycle rules mappings. Mutating the\n\ + output dicts has no effect unless you then re-assign the dict via\nthe setter.\ + \ E.g.:\n>>> rules = list(bucket.lifecycle_rules)\n>>> rules.append({'origin':\ + \ '/foo', ...})\n>>> rules[1]['rule']['action']['type'] = 'Delete'\n>>> del rules[0]\n\ + >>> bucket.lifecycle_rules = rules\n>>> bucket.update()\n" + syntax: + returns: + - description: A sequence of mappings describing each lifecycle rule. + var_type: generator(dict) + type: property + uid: google.cloud.storage.bucket.Bucket.lifecycle_rules +- *id012 +- attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.list_blobs + langs: + - python + module: google.cloud.storage.bucket + name: list_blobs + source: + id: list_blobs + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 1287 + summary: 'DEPRECATED. Return an iterator used to find blobs in the bucket. + + + + + If `user_project` is set, bills the API request to that project. + + ' + syntax: + content: list_blobs(max_results=None, page_token=None, prefix=None, delimiter=None, + start_offset=None, end_offset=None, include_trailing_delimiter=None, versions=None, + projection='noAcl', fields=None, client=None, timeout=60, retry=) + parameters: + - description: (Optional) The maximum number of blobs to return. + id: max_results + var_type: int + - description: '(Optional) If present, return the next batch of blobs, using the + value, which must correspond to the nextPageToken value returned + in the previous response. Deprecated: use the pages property + of the returned iterator instead of manually passing the token.' + id: page_token + var_type: str + - description: (Optional) Prefix used to filter blobs. + id: prefix + var_type: str + - description: (Optional) Delimiter, used with prefix to emulate + hierarchy. + id: delimiter + var_type: str + - description: (Optional) Filter results to objects whose names are lexicographically + equal to or after startOffset. If endOffset is also + set, the objects listed will have names between startOffset (inclusive) + and endOffset (exclusive). + id: start_offset + var_type: str + - description: (Optional) Filter results to objects whose names are lexicographically + before endOffset. If startOffset is also set, the + objects listed will have names between startOffset (inclusive) + and endOffset (exclusive). + id: end_offset + var_type: str + - description: (Optional) If true, objects that end in exactly one instance of + delimiter will have their metadata included in items + in addition to prefixes. + id: include_trailing_delimiter + var_type: boolean + - description: (Optional) Whether object versions should be returned as separate + blobs. + id: versions + var_type: bool + - description: (Optional) If used, must be 'full' or 'noAcl'. Defaults to 'noAcl'. + Specifies the set of properties to return. + id: projection + var_type: str + - description: '(Optional) Selector specifying which fields to include in a partial + response. Must be a list of fields. For example to get a partial response + with just the next page token and the name and language of each blob returned: + ''items(name,contentLanguage),nextPageToken''. See: https://cloud.google.com/storage/docs/json_api/v1/parameters#fields' + id: fields + var_type: str + - description: (Optional) The client to use. If not passed, falls back to the + client stored on the current bucket. + id: client + var_type: Client + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: '(Optional) How to retry the RPC. See: configuring_retries' + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + returns: + - description: Iterator of all Blob + in this bucket matching the arguments. + var_type: google.api_core.page_iterator.Iterator + type: method + uid: google.cloud.storage.bucket.Bucket.list_blobs +- attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.list_notifications + langs: + - python + module: google.cloud.storage.bucket + name: list_notifications + source: + id: list_notifications + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 1401 + summary: 'List Pub / Sub notifications for this bucket. + + + See: + + https://cloud.google.com/storage/docs/json_api/v1/notifications/list + + + If `user_project` is set, bills the API request to that project. + + ' + syntax: + content: list_notifications(client=None, timeout=60, retry=) + parameters: + - description: (Optional) The client to use. If not passed, falls back to the + client stored on the current bucket. + id: client + var_type: Client or NoneType + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: '(Optional) How to retry the RPC. See: configuring_retries' + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + returns: + - description: notification instances + var_type: list of .BucketNotification + type: method + uid: google.cloud.storage.bucket.Bucket.list_notifications +- &id013 + attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.location + langs: + - python + module: google.cloud.storage.bucket + name: location + source: + id: location + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Retrieve location configured for this bucket. + + + See https://cloud.google.com/storage/docs/json_api/v1/buckets and + + https://cloud.google.com/storage/docs/locations + + + Returns `None` if the property has not been set before creation, + + or if the bucket''s resource has not been loaded from the server. + + + ' + syntax: {} + type: property + uid: google.cloud.storage.bucket.Bucket.location +- *id013 +- &id014 + attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.location_type + langs: + - python + module: google.cloud.storage.bucket + name: location_type + source: + id: location_type + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Retrieve the location type for the bucket. + + + See https://cloud.google.com/storage/docs/storage-classes + + + :getter: Gets the the location type for this bucket. + + ' + syntax: + returns: + - description: If set, one of MULTI_REGION_LOCATION_TYPE, + REGION_LOCATION_TYPE, + or DUAL_REGION_LOCATION_TYPE, + else None. + var_type: str or NoneType + type: property + uid: google.cloud.storage.bucket.Bucket.location_type +- *id014 +- attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.lock_retention_policy + langs: + - python + module: google.cloud.storage.bucket + name: lock_retention_policy + source: + id: lock_retention_policy + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 3103 + summary: 'Lock the bucket''s retention policy. + + ' + syntax: + content: lock_retention_policy(client=None, timeout=60, retry=) + exceptions: + - description: if the bucket has no metageneration (i.e., new or never reloaded); + if the bucket has no retention policy assigned; if the bucket's retention + policy is already locked. + var_type: ValueError + parameters: + - description: (Optional) The client to use. If not passed, falls back to the + client stored on the blob's bucket. + id: client + var_type: Client or NoneType + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: '(Optional) How to retry the RPC. See: configuring_retries' + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + type: method + uid: google.cloud.storage.bucket.Bucket.lock_retention_policy +- attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.make_private + langs: + - python + module: google.cloud.storage.bucket + name: make_private + source: + id: make_private + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 2956 + summary: 'Update bucket''s ACL, revoking read access for anonymous users. + + ' + syntax: + content: make_private(recursive=False, future=False, client=None, timeout=60, + if_metageneration_match=None, if_metageneration_not_match=None, retry=) + exceptions: + - description: If recursive is True, and the bucket contains more + than 256 blobs. This is to prevent extremely long runtime of this method. + For such buckets, iterate over the blobs returned by list_blobs + and call make_private + for each blob. + var_type: ValueError + parameters: + - description: If True, this will make all blobs inside the bucket private as + well. + id: recursive + var_type: bool + - description: If True, this will make all objects created in the future private + as well. + id: future + var_type: bool + - description: (Optional) The client to use. If not passed, falls back to the + client stored on the current bucket. + id: client + var_type: Client or NoneType + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: (Optional) Make the operation conditional on whether the blob's + current metageneration matches the given value. + id: if_metageneration_match + var_type: long + - description: (Optional) Make the operation conditional on whether the blob's + current metageneration does not match the given value. + id: if_metageneration_not_match + var_type: long + - description: '(Optional) How to retry the RPC. See: configuring_retries' + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + type: method + uid: google.cloud.storage.bucket.Bucket.make_private +- attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.make_public + langs: + - python + module: google.cloud.storage.bucket + name: make_public + source: + id: make_public + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 2859 + summary: 'Update bucket''s ACL, granting read access to anonymous users. + + ' + syntax: + content: make_public(recursive=False, future=False, client=None, timeout=60, if_metageneration_match=None, + if_metageneration_not_match=None, retry=) + exceptions: + - description: If recursive is True, and the bucket contains more + than 256 blobs. This is to prevent extremely long runtime of this method. + For such buckets, iterate over the blobs returned by list_blobs + and call make_public + for each blob. + var_type: ValueError + parameters: + - description: If True, this will make all blobs inside the bucket public as well. + id: recursive + var_type: bool + - description: If True, this will make all objects created in the future public + as well. + id: future + var_type: bool + - description: (Optional) The client to use. If not passed, falls back to the + client stored on the current bucket. + id: client + var_type: Client or NoneType + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: (Optional) Make the operation conditional on whether the blob's + current metageneration matches the given value. + id: if_metageneration_match + var_type: long + - description: (Optional) Make the operation conditional on whether the blob's + current metageneration does not match the given value. + id: if_metageneration_not_match + var_type: long + - description: '(Optional) How to retry the RPC. See: configuring_retries' + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + type: method + uid: google.cloud.storage.bucket.Bucket.make_public +- &id015 + attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.metageneration + langs: + - python + module: google.cloud.storage.bucket + name: metageneration + source: + id: metageneration + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Retrieve the metageneration for the bucket. + + + See https://cloud.google.com/storage/docs/json_api/v1/buckets + + ' + syntax: + returns: + - description: The metageneration of the bucket or None if the bucket's + resource has not been loaded from the server. + var_type: int or NoneType + type: property + uid: google.cloud.storage.bucket.Bucket.metageneration +- *id015 +- attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.notification + langs: + - python + module: google.cloud.storage.bucket + name: notification + source: + id: notification + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 804 + summary: 'Factory: create a notification resource for the bucket. + + + See: `.BucketNotification` for parameters. + + ' + syntax: + content: "notification(\n topic_name=None,\n topic_project=None,\n custom_attributes=None,\n\ + \ event_types=None,\n blob_name_prefix=None,\n payload_format=\"NONE\"\ + ,\n notification_id=None,\n)" + parameters: [] + type: method + uid: google.cloud.storage.bucket.Bucket.notification +- &id016 + attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.owner + langs: + - python + module: google.cloud.storage.bucket + name: owner + source: + id: owner + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Retrieve info about the owner of the bucket. + + + See https://cloud.google.com/storage/docs/json_api/v1/buckets + + ' + syntax: + returns: + - description: Mapping of owner's role/ID. Returns None if the bucket's + resource has not been loaded from the server. + var_type: dict or NoneType + type: property + uid: google.cloud.storage.bucket.Bucket.owner +- *id016 +- attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.patch + langs: + - python + module: google.cloud.storage.bucket + name: patch + source: + id: patch + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 1097 + summary: 'Sends all changed properties in a PATCH request. + + + Updates the `_properties` with the response from the backend. + + + If `user_project` is set, bills the API request to that project. + + ' + syntax: + content: patch(client=None, timeout=60, if_metageneration_match=None, if_metageneration_not_match=None, + retry=) + parameters: + - description: the client to use. If not passed, falls back to the client + stored on the current object. + id: client + var_type: Client or NoneType + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: (Optional) Make the operation conditional on whether the blob's + current metageneration matches the given value. + id: if_metageneration_match + var_type: long + - description: (Optional) Make the operation conditional on whether the blob's + current metageneration does not match the given value. + id: if_metageneration_not_match + var_type: long + - description: '(Optional) How to retry the RPC. See: configuring_retries' + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + type: method + uid: google.cloud.storage.bucket.Bucket.patch +- &id017 + attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.path + langs: + - python + module: google.cloud.storage.bucket + name: path + source: + id: path + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'The URL path to this bucket. + + + ' + syntax: {} + type: property + uid: google.cloud.storage.bucket.Bucket.path +- *id017 +- attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.path_helper + langs: + - python + module: google.cloud.storage.bucket + name: path_helper + source: + id: path_helper + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 1160 + summary: 'Relative URL path for a bucket. + + ' + syntax: + content: path_helper(bucket_name) + parameters: + - description: The bucket name in the path. + id: bucket_name + var_type: str + returns: + - description: The relative URL path for bucket_name. + var_type: str + type: method + uid: google.cloud.storage.bucket.Bucket.path_helper +- &id018 + attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.project_number + langs: + - python + module: google.cloud.storage.bucket + name: project_number + source: + id: project_number + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Retrieve the number of the project to which the bucket is assigned. + + + See https://cloud.google.com/storage/docs/json_api/v1/buckets + + ' + syntax: + returns: + - description: The project number that owns the bucket or None if + the bucket's resource has not been loaded from the server. + var_type: int or NoneType + type: property + uid: google.cloud.storage.bucket.Bucket.project_number +- *id018 +- attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.reload + langs: + - python + module: google.cloud.storage.bucket + name: reload + source: + id: reload + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 1036 + summary: 'Reload properties from Cloud Storage. + + + If `user_project` is set, bills the API request to that project. + + ' + syntax: + content: reload(client=None, projection='noAcl', timeout=60, if_etag_match=None, + if_etag_not_match=None, if_metageneration_match=None, if_metageneration_not_match=None, + retry=) + parameters: + - description: the client to use. If not passed, falls back to the client + stored on the current object. + id: client + var_type: Client or NoneType + - description: (Optional) If used, must be 'full' or 'noAcl'. Defaults to 'noAcl'. + Specifies the set of properties to return. + id: projection + var_type: str + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: (Optional) Make the operation conditional on whether the bucket's + current ETag matches the given value. + id: if_etag_match + var_type: Union[str, Set[str]] + - description: (Optional) Make the operation conditional on whether the bucket's + current ETag does not match the given value. + id: if_etag_not_match + var_type: Union[str, Set[str]]) + - description: (Optional) Make the operation conditional on whether the bucket's + current metageneration matches the given value. + id: if_metageneration_match + var_type: long + - description: (Optional) Make the operation conditional on whether the bucket's + current metageneration does not match the given value. + id: if_metageneration_not_match + var_type: long + - description: '(Optional) How to retry the RPC. See: configuring_retries' + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + type: method + uid: google.cloud.storage.bucket.Bucket.reload +- attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.rename_blob + langs: + - python + module: google.cloud.storage.bucket + name: rename_blob + source: + id: rename_blob + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 1918 + summary: 'Rename the given blob using copy and delete operations. + + + If `user_project` is set, bills the API request to that project. + + + Effectively, copies blob to the same bucket with a new name, then + + deletes the blob. + + + ' + syntax: + content: rename_blob(blob, new_name, client=None, if_generation_match=None, if_generation_not_match=None, + if_metageneration_match=None, if_metageneration_not_match=None, if_source_generation_match=None, + if_source_generation_not_match=None, if_source_metageneration_match=None, if_source_metageneration_not_match=None, + timeout=60, retry=) + parameters: + - description: The blob to be renamed. + id: blob + var_type: Blob + - description: The new name for this blob. + id: new_name + var_type: str + - description: (Optional) The client to use. If not passed, falls back to the + client stored on the current bucket. + id: client + var_type: Client or NoneType + - description: (Optional) See :ref:using-if-generation-match Note + that the generation to be matched is that of the destination + blob. + id: if_generation_match + var_type: long + - description: (Optional) See :ref:using-if-generation-not-match + Note that the generation to be matched is that of the destination + blob. + id: if_generation_not_match + var_type: long + - description: (Optional) See :ref:using-if-metageneration-match + Note that the metageneration to be matched is that of the destination + blob. + id: if_metageneration_match + var_type: long + - description: (Optional) See :ref:using-if-metageneration-not-match + Note that the metageneration to be matched is that of the destination + blob. + id: if_metageneration_not_match + var_type: long + - description: (Optional) Makes the operation conditional on whether the source + object's generation matches the given value. Also used in the (implied) delete + request. + id: if_source_generation_match + var_type: long + - description: (Optional) Makes the operation conditional on whether the source + object's generation does not match the given value. Also used in the (implied) + delete request. + id: if_source_generation_not_match + var_type: long + - description: (Optional) Makes the operation conditional on whether the source + object's current metageneration matches the given value. Also used in the + (implied) delete request. + id: if_source_metageneration_match + var_type: long + - description: (Optional) Makes the operation conditional on whether the source + object's current metageneration does not match the given value. Also used + in the (implied) delete request. + id: if_source_metageneration_not_match + var_type: long + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: '(Optional) How to retry the RPC. See: configuring_retries' + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + returns: + - description: The newly-renamed blob. + var_type: Blob + type: method + uid: google.cloud.storage.bucket.Bucket.rename_blob +- &id019 + attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.requester_pays + langs: + - python + module: google.cloud.storage.bucket + name: requester_pays + source: + id: requester_pays + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Does the requester pay for API requests for this bucket? + + + See https://cloud.google.com/storage/docs/requester-pays for + + details. + + + :setter: Update whether requester pays for this bucket. + + :getter: Query whether requester pays for this bucket. + + ' + syntax: + returns: + - description: True if requester pays for API requests for the bucket, else False. + var_type: bool + type: property + uid: google.cloud.storage.bucket.Bucket.requester_pays +- *id019 +- &id020 + attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.retention_period + langs: + - python + module: google.cloud.storage.bucket + name: retention_period + source: + id: retention_period + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Retrieve or set the retention period for items in the bucket. + + ' + syntax: + returns: + - description: number of seconds to retain items after upload or release from + event-based lock, or None if the property is not set locally. + var_type: int or NoneType + type: property + uid: google.cloud.storage.bucket.Bucket.retention_period +- *id020 +- &id021 + attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.retention_policy_effective_time + langs: + - python + module: google.cloud.storage.bucket + name: retention_policy_effective_time + source: + id: retention_policy_effective_time + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Retrieve the effective time of the bucket''s retention policy. + + ' + syntax: + returns: + - description: point-in time at which the bucket's retention policy is effective, + or None if the property is not set locally. + var_type: datetime.datetime or NoneType + type: property + uid: google.cloud.storage.bucket.Bucket.retention_policy_effective_time +- *id021 +- &id022 + attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.retention_policy_locked + langs: + - python + module: google.cloud.storage.bucket + name: retention_policy_locked + source: + id: retention_policy_locked + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Retrieve whthere the bucket''s retention policy is locked. + + ' + syntax: + returns: + - description: True if the bucket's policy is locked, or else False if the policy + is not locked, or the property is not set locally. + var_type: bool + type: property + uid: google.cloud.storage.bucket.Bucket.retention_policy_locked +- *id022 +- &id023 + attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.rpo + langs: + - python + module: google.cloud.storage.bucket + name: rpo + source: + id: rpo + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Get the RPO (Recovery Point Objective) of this bucket + + + See: https://cloud.google.com/storage/docs/managing-turbo-replication + + + "ASYNC_TURBO" or "DEFAULT" + + + ' + syntax: {} + type: property + uid: google.cloud.storage.bucket.Bucket.rpo +- *id023 +- &id024 + attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.self_link + langs: + - python + module: google.cloud.storage.bucket + name: self_link + source: + id: self_link + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Retrieve the URI for the bucket. + + + See https://cloud.google.com/storage/docs/json_api/v1/buckets + + ' + syntax: + returns: + - description: The self link for the bucket or None if the bucket's + resource has not been loaded from the server. + var_type: str or NoneType + type: property + uid: google.cloud.storage.bucket.Bucket.self_link +- *id024 +- attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.set_iam_policy + langs: + - python + module: google.cloud.storage.bucket + name: set_iam_policy + source: + id: set_iam_policy + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 2756 + summary: 'Update the IAM policy for the bucket. + + + See + + https://cloud.google.com/storage/docs/json_api/v1/buckets/setIamPolicy + + + If `user_project` is set, bills the API request to that project. + + ' + syntax: + content: set_iam_policy(policy, client=None, timeout=60, retry=) + parameters: + - description: policy instance used to update bucket's IAM policy. + id: policy + var_type: google.api_core.iam.Policy + - description: (Optional) The client to use. If not passed, falls back to the + client stored on the current bucket. + id: client + var_type: Client or NoneType + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: '(Optional) How to retry the RPC. See: configuring_retries' + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + returns: + - description: the policy instance, based on the resource returned from the setIamPolicy + API request. + var_type: google.api_core.iam.Policy + type: method + uid: google.cloud.storage.bucket.Bucket.set_iam_policy +- &id025 + attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.storage_class + langs: + - python + module: google.cloud.storage.bucket + name: storage_class + source: + id: storage_class + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Retrieve or set the storage class for the bucket. + + + See https://cloud.google.com/storage/docs/storage-classes + + + :setter: Set the storage class for this bucket. + + :getter: Gets the the storage class for this bucket. + + ' + syntax: + returns: + - description: If set, one of NEARLINE_STORAGE_CLASS, + COLDLINE_STORAGE_CLASS, + ARCHIVE_STORAGE_CLASS, + STANDARD_STORAGE_CLASS, + MULTI_REGIONAL_LEGACY_STORAGE_CLASS, + REGIONAL_LEGACY_STORAGE_CLASS, + or DURABLE_REDUCED_AVAILABILITY_LEGACY_STORAGE_CLASS, + else None. + var_type: str or NoneType + type: property + uid: google.cloud.storage.bucket.Bucket.storage_class +- *id025 +- attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.test_iam_permissions + langs: + - python + module: google.cloud.storage.bucket + name: test_iam_permissions + source: + id: test_iam_permissions + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 2812 + summary: 'API call: test permissions + + + See + + https://cloud.google.com/storage/docs/json_api/v1/buckets/testIamPermissions + + + If `user_project` is set, bills the API request to that project. + + ' + syntax: + content: test_iam_permissions(permissions, client=None, timeout=60, retry=) + parameters: + - description: the permissions to check + id: permissions + var_type: list of string + - description: (Optional) The client to use. If not passed, falls back to the + client stored on the current bucket. + id: client + var_type: Client or NoneType + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: '(Optional) How to retry the RPC. See: configuring_retries' + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + returns: + - description: the permissions returned by the testIamPermissions + API request. + var_type: list of string + type: method + uid: google.cloud.storage.bucket.Bucket.test_iam_permissions +- &id026 + attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.time_created + langs: + - python + module: google.cloud.storage.bucket + name: time_created + source: + id: time_created + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Retrieve the timestamp at which the bucket was created. + + + See https://cloud.google.com/storage/docs/json_api/v1/buckets + + ' + syntax: + returns: + - description: Datetime object parsed from RFC3339 valid timestamp, or None + if the bucket's resource has not been loaded from the server. + var_type: datetime.datetime or NoneType + type: property + uid: google.cloud.storage.bucket.Bucket.time_created +- *id026 +- attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.update + langs: + - python + module: google.cloud.storage.bucket + name: update + source: + id: update + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 992 + summary: 'Sends all properties in a PUT request. + + + Updates the `_properties` with the response from the backend. + + + If `user_project` is set, bills the API request to that project. + + ' + syntax: + content: update(client=None, timeout=60, if_metageneration_match=None, if_metageneration_not_match=None, + retry=) + parameters: + - description: the client to use. If not passed, falls back to the client + stored on the current object. + id: client + var_type: Client or NoneType + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: (Optional) Make the operation conditional on whether the blob's + current metageneration matches the given value. + id: if_metageneration_match + var_type: long + - description: (Optional) Make the operation conditional on whether the blob's + current metageneration does not match the given value. + id: if_metageneration_not_match + var_type: long + - description: '(Optional) How to retry the RPC. See: configuring_retries' + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + type: method + uid: google.cloud.storage.bucket.Bucket.update +- &id027 + attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.user_project + langs: + - python + module: google.cloud.storage.bucket + name: user_project + source: + id: user_project + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Project ID to be billed for API requests made via this bucket. + + + If unset, API requests are billed to the bucket owner. + + + A user project is required for all operations on Requester Pays buckets. + + + See https://cloud.google.com/storage/docs/requester-pays#requirements for details. + + ' + syntax: {} + type: property + uid: google.cloud.storage.bucket.Bucket.user_project +- *id027 +- &id028 + attributes: [] + class: google.cloud.storage.bucket.Bucket + fullName: google.cloud.storage.bucket.Bucket.versioning_enabled + langs: + - python + module: google.cloud.storage.bucket + name: versioning_enabled + source: + id: versioning_enabled + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Is versioning enabled for this bucket? + + + See https://cloud.google.com/storage/docs/object-versioning for + + details. + + + :setter: Update whether versioning is enabled for this bucket. + + :getter: Query whether versioning is enabled for this bucket. + + ' + syntax: + returns: + - description: True if enabled, else False. + var_type: bool + type: property + uid: google.cloud.storage.bucket.Bucket.versioning_enabled +- *id028 +references: +- fullName: google.cloud.storage.bucket.Bucket + isExternal: false + name: Bucket + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket +- fullName: google.cloud.storage.bucket.Bucket.STORAGE_CLASSES + isExternal: false + name: STORAGE_CLASSES + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.STORAGE_CLASSES +- fullName: google.cloud.storage.bucket.Bucket.acl + isExternal: false + name: acl + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.acl +- fullName: google.cloud.storage.bucket.Bucket.add_lifecycle_abort_incomplete_multipart_upload_rule + isExternal: false + name: add_lifecycle_abort_incomplete_multipart_upload_rule + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.add_lifecycle_abort_incomplete_multipart_upload_rule +- fullName: google.cloud.storage.bucket.Bucket.add_lifecycle_delete_rule + isExternal: false + name: add_lifecycle_delete_rule + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.add_lifecycle_delete_rule +- fullName: google.cloud.storage.bucket.Bucket.add_lifecycle_set_storage_class_rule + isExternal: false + name: add_lifecycle_set_storage_class_rule + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.add_lifecycle_set_storage_class_rule +- fullName: google.cloud.storage.bucket.Bucket.blob + isExternal: false + name: blob + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.blob +- fullName: google.cloud.storage.bucket.Bucket.clear_lifecyle_rules + isExternal: false + name: clear_lifecyle_rules + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.clear_lifecyle_rules +- fullName: google.cloud.storage.bucket.Bucket.client + isExternal: false + name: client + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.client +- fullName: google.cloud.storage.bucket.Bucket.configure_website + isExternal: false + name: configure_website + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.configure_website +- fullName: google.cloud.storage.bucket.Bucket.copy_blob + isExternal: false + name: copy_blob + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.copy_blob +- fullName: google.cloud.storage.bucket.Bucket.cors + isExternal: false + name: cors + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.cors +- fullName: google.cloud.storage.bucket.Bucket.create + isExternal: false + name: create + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.create +- fullName: google.cloud.storage.bucket.Bucket.data_locations + isExternal: false + name: data_locations + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.data_locations +- fullName: google.cloud.storage.bucket.Bucket.default_event_based_hold + isExternal: false + name: default_event_based_hold + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.default_event_based_hold +- fullName: google.cloud.storage.bucket.Bucket.default_kms_key_name + isExternal: false + name: default_kms_key_name + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.default_kms_key_name +- fullName: google.cloud.storage.bucket.Bucket.default_object_acl + isExternal: false + name: default_object_acl + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.default_object_acl +- fullName: google.cloud.storage.bucket.Bucket.delete + isExternal: false + name: delete + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.delete +- fullName: google.cloud.storage.bucket.Bucket.delete_blob + isExternal: false + name: delete_blob + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.delete_blob +- fullName: google.cloud.storage.bucket.Bucket.delete_blobs + isExternal: false + name: delete_blobs + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.delete_blobs +- fullName: google.cloud.storage.bucket.Bucket.disable_logging + isExternal: false + name: disable_logging + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.disable_logging +- fullName: google.cloud.storage.bucket.Bucket.disable_website + isExternal: false + name: disable_website + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.disable_website +- fullName: google.cloud.storage.bucket.Bucket.enable_logging + isExternal: false + name: enable_logging + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.enable_logging +- fullName: google.cloud.storage.bucket.Bucket.etag + isExternal: false + name: etag + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.etag +- fullName: google.cloud.storage.bucket.Bucket.exists + isExternal: false + name: exists + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.exists +- fullName: google.cloud.storage.bucket.Bucket.from_string + isExternal: false + name: from_string + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.from_string +- fullName: google.cloud.storage.bucket.Bucket.generate_signed_url + isExternal: false + name: generate_signed_url + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.generate_signed_url +- fullName: google.cloud.storage.bucket.Bucket.generate_upload_policy + isExternal: false + name: generate_upload_policy + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.generate_upload_policy +- fullName: google.cloud.storage.bucket.Bucket.get_blob + isExternal: false + name: get_blob + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.get_blob +- fullName: google.cloud.storage.bucket.Bucket.get_iam_policy + isExternal: false + name: get_iam_policy + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.get_iam_policy +- fullName: google.cloud.storage.bucket.Bucket.get_logging + isExternal: false + name: get_logging + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.get_logging +- fullName: google.cloud.storage.bucket.Bucket.get_notification + isExternal: false + name: get_notification + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.get_notification +- fullName: google.cloud.storage.bucket.Bucket.iam_configuration + isExternal: false + name: iam_configuration + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.iam_configuration +- fullName: google.cloud.storage.bucket.Bucket.id + isExternal: false + name: id + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.id +- fullName: google.cloud.storage.bucket.Bucket.labels + isExternal: false + name: labels + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.labels +- fullName: google.cloud.storage.bucket.Bucket.lifecycle_rules + isExternal: false + name: lifecycle_rules + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.lifecycle_rules +- fullName: google.cloud.storage.bucket.Bucket.list_blobs + isExternal: false + name: list_blobs + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.list_blobs +- fullName: google.cloud.storage.bucket.Bucket.list_notifications + isExternal: false + name: list_notifications + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.list_notifications +- fullName: google.cloud.storage.bucket.Bucket.location + isExternal: false + name: location + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.location +- fullName: google.cloud.storage.bucket.Bucket.location_type + isExternal: false + name: location_type + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.location_type +- fullName: google.cloud.storage.bucket.Bucket.lock_retention_policy + isExternal: false + name: lock_retention_policy + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.lock_retention_policy +- fullName: google.cloud.storage.bucket.Bucket.make_private + isExternal: false + name: make_private + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.make_private +- fullName: google.cloud.storage.bucket.Bucket.make_public + isExternal: false + name: make_public + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.make_public +- fullName: google.cloud.storage.bucket.Bucket.metageneration + isExternal: false + name: metageneration + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.metageneration +- fullName: google.cloud.storage.bucket.Bucket.notification + isExternal: false + name: notification + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.notification +- fullName: google.cloud.storage.bucket.Bucket.owner + isExternal: false + name: owner + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.owner +- fullName: google.cloud.storage.bucket.Bucket.patch + isExternal: false + name: patch + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.patch +- fullName: google.cloud.storage.bucket.Bucket.path + isExternal: false + name: path + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.path +- fullName: google.cloud.storage.bucket.Bucket.path_helper + isExternal: false + name: path_helper + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.path_helper +- fullName: google.cloud.storage.bucket.Bucket.project_number + isExternal: false + name: project_number + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.project_number +- fullName: google.cloud.storage.bucket.Bucket.reload + isExternal: false + name: reload + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.reload +- fullName: google.cloud.storage.bucket.Bucket.rename_blob + isExternal: false + name: rename_blob + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.rename_blob +- fullName: google.cloud.storage.bucket.Bucket.requester_pays + isExternal: false + name: requester_pays + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.requester_pays +- fullName: google.cloud.storage.bucket.Bucket.retention_period + isExternal: false + name: retention_period + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.retention_period +- fullName: google.cloud.storage.bucket.Bucket.retention_policy_effective_time + isExternal: false + name: retention_policy_effective_time + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.retention_policy_effective_time +- fullName: google.cloud.storage.bucket.Bucket.retention_policy_locked + isExternal: false + name: retention_policy_locked + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.retention_policy_locked +- fullName: google.cloud.storage.bucket.Bucket.rpo + isExternal: false + name: rpo + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.rpo +- fullName: google.cloud.storage.bucket.Bucket.self_link + isExternal: false + name: self_link + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.self_link +- fullName: google.cloud.storage.bucket.Bucket.set_iam_policy + isExternal: false + name: set_iam_policy + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.set_iam_policy +- fullName: google.cloud.storage.bucket.Bucket.storage_class + isExternal: false + name: storage_class + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.storage_class +- fullName: google.cloud.storage.bucket.Bucket.test_iam_permissions + isExternal: false + name: test_iam_permissions + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.test_iam_permissions +- fullName: google.cloud.storage.bucket.Bucket.time_created + isExternal: false + name: time_created + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.time_created +- fullName: google.cloud.storage.bucket.Bucket.update + isExternal: false + name: update + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.update +- fullName: google.cloud.storage.bucket.Bucket.user_project + isExternal: false + name: user_project + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.user_project +- fullName: google.cloud.storage.bucket.Bucket.versioning_enabled + isExternal: false + name: versioning_enabled + parent: google.cloud.storage.bucket.Bucket + uid: google.cloud.storage.bucket.Bucket.versioning_enabled diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.bucket.IAMConfiguration.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.bucket.IAMConfiguration.yml new file mode 100644 index 000000000000..e53b211f7cc0 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.bucket.IAMConfiguration.yml @@ -0,0 +1,591 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: [] + children: + - google.cloud.storage.bucket.IAMConfiguration.bucket + - google.cloud.storage.bucket.IAMConfiguration.bucket_policy_only_enabled + - google.cloud.storage.bucket.IAMConfiguration.bucket_policy_only_locked_time + - google.cloud.storage.bucket.IAMConfiguration.clear + - google.cloud.storage.bucket.IAMConfiguration.copy + - google.cloud.storage.bucket.IAMConfiguration.from_api_repr + - google.cloud.storage.bucket.IAMConfiguration.fromkeys + - google.cloud.storage.bucket.IAMConfiguration.get + - google.cloud.storage.bucket.IAMConfiguration.items + - google.cloud.storage.bucket.IAMConfiguration.keys + - google.cloud.storage.bucket.IAMConfiguration.pop + - google.cloud.storage.bucket.IAMConfiguration.popitem + - google.cloud.storage.bucket.IAMConfiguration.public_access_prevention + - google.cloud.storage.bucket.IAMConfiguration.setdefault + - google.cloud.storage.bucket.IAMConfiguration.uniform_bucket_level_access_enabled + - google.cloud.storage.bucket.IAMConfiguration.uniform_bucket_level_access_locked_time + - google.cloud.storage.bucket.IAMConfiguration.update + - google.cloud.storage.bucket.IAMConfiguration.values + class: google.cloud.storage.bucket.IAMConfiguration + fullName: google.cloud.storage.bucket.IAMConfiguration + inheritance: + - inheritance: + - type: builtins.object + type: builtins.dict + langs: + - python + module: google.cloud.storage.bucket + name: IAMConfiguration + source: + id: IAMConfiguration + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 438 + summary: 'Map a bucket''s IAM configuration. + + ' + syntax: + content: IAMConfiguration(bucket, public_access_prevention=, uniform_bucket_level_access_enabled=, uniform_bucket_level_access_locked_time=, bucket_policy_only_enabled=, bucket_policy_only_locked_time=) + parameters: [] + type: class + uid: google.cloud.storage.bucket.IAMConfiguration +- &id001 + attributes: [] + class: google.cloud.storage.bucket.IAMConfiguration + fullName: google.cloud.storage.bucket.IAMConfiguration.bucket + langs: + - python + module: google.cloud.storage.bucket + name: bucket + source: + id: bucket + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Bucket for which this instance is the policy. + + ' + syntax: + returns: + - description: the instance's bucket. + var_type: Bucket + type: property + uid: google.cloud.storage.bucket.IAMConfiguration.bucket +- *id001 +- &id002 + attributes: [] + class: google.cloud.storage.bucket.IAMConfiguration + fullName: google.cloud.storage.bucket.IAMConfiguration.bucket_policy_only_enabled + langs: + - python + module: google.cloud.storage.bucket + name: bucket_policy_only_enabled + source: + id: bucket_policy_only_enabled + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Deprecated alias for `uniform_bucket_level_access_enabled`. + + ' + syntax: + returns: + - description: whether the bucket is configured to allow only IAM. + var_type: bool + type: property + uid: google.cloud.storage.bucket.IAMConfiguration.bucket_policy_only_enabled +- *id002 +- &id003 + attributes: [] + class: google.cloud.storage.bucket.IAMConfiguration + fullName: google.cloud.storage.bucket.IAMConfiguration.bucket_policy_only_locked_time + langs: + - python + module: google.cloud.storage.bucket + name: bucket_policy_only_locked_time + source: + id: bucket_policy_only_locked_time + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Deprecated alias for `uniform_bucket_level_access_locked_time`. + + ' + syntax: + returns: + - description: (readonly) Time after which bucket_policy_only_enabled + will be frozen as true. + var_type: Union[datetime.datetime, None] + type: property + uid: google.cloud.storage.bucket.IAMConfiguration.bucket_policy_only_locked_time +- *id003 +- class: google.cloud.storage.bucket.IAMConfiguration + fullName: google.cloud.storage.bucket.IAMConfiguration.clear + langs: + - python + module: google.cloud.storage.bucket + name: clear + source: + id: clear + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: API documentation for `storage.bucket.IAMConfiguration.clear` method. + syntax: + content: clear() + type: method + uid: google.cloud.storage.bucket.IAMConfiguration.clear +- class: google.cloud.storage.bucket.IAMConfiguration + fullName: google.cloud.storage.bucket.IAMConfiguration.copy + langs: + - python + module: google.cloud.storage.bucket + name: copy + source: + id: copy + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: API documentation for `storage.bucket.IAMConfiguration.copy` method. + syntax: + content: copy() + type: method + uid: google.cloud.storage.bucket.IAMConfiguration.copy +- attributes: [] + class: google.cloud.storage.bucket.IAMConfiguration + fullName: google.cloud.storage.bucket.IAMConfiguration.from_api_repr + langs: + - python + module: google.cloud.storage.bucket + name: from_api_repr + source: + id: from_api_repr + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 511 + summary: 'Factory: construct instance from resource. + + ' + syntax: + content: from_api_repr(resource, bucket) + parameters: + - description: mapping as returned from API call. + id: resource + var_type: dict + returns: + - description: Instance created from resource. + var_type: IAMConfiguration + type: method + uid: google.cloud.storage.bucket.IAMConfiguration.from_api_repr +- attributes: [] + class: google.cloud.storage.bucket.IAMConfiguration + fullName: google.cloud.storage.bucket.IAMConfiguration.fromkeys + langs: + - python + module: google.cloud.storage.bucket + name: fromkeys + source: + id: fromkeys + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Create a new dictionary with keys from iterable and values set to value. + + + ' + syntax: + content: fromkeys(value=None, /) + parameters: [] + type: method + uid: google.cloud.storage.bucket.IAMConfiguration.fromkeys +- attributes: [] + class: google.cloud.storage.bucket.IAMConfiguration + fullName: google.cloud.storage.bucket.IAMConfiguration.get + langs: + - python + module: google.cloud.storage.bucket + name: get + source: + id: get + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Return the value for key if key is in the dictionary, else default. + + + ' + syntax: + content: get(key, default=None, /) + parameters: [] + type: method + uid: google.cloud.storage.bucket.IAMConfiguration.get +- class: google.cloud.storage.bucket.IAMConfiguration + fullName: google.cloud.storage.bucket.IAMConfiguration.items + langs: + - python + module: google.cloud.storage.bucket + name: items + source: + id: items + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: API documentation for `storage.bucket.IAMConfiguration.items` method. + syntax: + content: items() + type: method + uid: google.cloud.storage.bucket.IAMConfiguration.items +- class: google.cloud.storage.bucket.IAMConfiguration + fullName: google.cloud.storage.bucket.IAMConfiguration.keys + langs: + - python + module: google.cloud.storage.bucket + name: keys + source: + id: keys + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: API documentation for `storage.bucket.IAMConfiguration.keys` method. + syntax: + content: keys() + type: method + uid: google.cloud.storage.bucket.IAMConfiguration.keys +- attributes: [] + class: google.cloud.storage.bucket.IAMConfiguration + fullName: google.cloud.storage.bucket.IAMConfiguration.pop + langs: + - python + module: google.cloud.storage.bucket + name: pop + source: + id: pop + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'If key is not found, default is returned if given, otherwise KeyError + is raised + + + ' + syntax: + content: pop(k[,d]) + type: method + uid: google.cloud.storage.bucket.IAMConfiguration.pop +- attributes: [] + class: google.cloud.storage.bucket.IAMConfiguration + fullName: google.cloud.storage.bucket.IAMConfiguration.popitem + langs: + - python + module: google.cloud.storage.bucket + name: popitem + source: + id: popitem + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Remove and return a (key, value) pair as a 2-tuple. + + + Pairs are returned in LIFO (last-in, first-out) order. + + Raises KeyError if the dict is empty. + + + ' + syntax: + content: popitem() + parameters: [] + type: method + uid: google.cloud.storage.bucket.IAMConfiguration.popitem +- &id004 + attributes: [] + class: google.cloud.storage.bucket.IAMConfiguration + fullName: google.cloud.storage.bucket.IAMConfiguration.public_access_prevention + langs: + - python + module: google.cloud.storage.bucket + name: public_access_prevention + source: + id: public_access_prevention + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: "Setting for public access prevention policy. Options are 'inherited' (default)\ + \ or 'enforced'.\n\n See: https://cloud.google.com/storage/docs/public-access-prevention\n" + syntax: + returns: + - description: the public access prevention status, either 'enforced' or 'inherited'. + var_type: string + type: property + uid: google.cloud.storage.bucket.IAMConfiguration.public_access_prevention +- *id004 +- attributes: [] + class: google.cloud.storage.bucket.IAMConfiguration + fullName: google.cloud.storage.bucket.IAMConfiguration.setdefault + langs: + - python + module: google.cloud.storage.bucket + name: setdefault + source: + id: setdefault + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Insert key with a value of default if key is not in the dictionary. + + + Return the value for key if key is in the dictionary, else default. + + + ' + syntax: + content: setdefault(key, default=None, /) + parameters: [] + type: method + uid: google.cloud.storage.bucket.IAMConfiguration.setdefault +- &id005 + attributes: [] + class: google.cloud.storage.bucket.IAMConfiguration + fullName: google.cloud.storage.bucket.IAMConfiguration.uniform_bucket_level_access_enabled + langs: + - python + module: google.cloud.storage.bucket + name: uniform_bucket_level_access_enabled + source: + id: uniform_bucket_level_access_enabled + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'If set, access checks only use bucket-level IAM policies or above. + + ' + syntax: + returns: + - description: whether the bucket is configured to allow only IAM. + var_type: bool + type: property + uid: google.cloud.storage.bucket.IAMConfiguration.uniform_bucket_level_access_enabled +- *id005 +- &id006 + attributes: [] + class: google.cloud.storage.bucket.IAMConfiguration + fullName: google.cloud.storage.bucket.IAMConfiguration.uniform_bucket_level_access_locked_time + langs: + - python + module: google.cloud.storage.bucket + name: uniform_bucket_level_access_locked_time + source: + id: uniform_bucket_level_access_locked_time + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Deadline for changing `uniform_bucket_level_access_enabled` from true + to false. + + + If the bucket''s `uniform_bucket_level_access_enabled` is true, this property + + is time time after which that setting becomes immutable. + + + If the bucket''s `uniform_bucket_level_access_enabled` is false, this property + + is `None`. + + ' + syntax: + returns: + - description: (readonly) Time after which uniform_bucket_level_access_enabled + will be frozen as true. + var_type: Union[datetime.datetime, None] + type: property + uid: google.cloud.storage.bucket.IAMConfiguration.uniform_bucket_level_access_locked_time +- *id006 +- attributes: [] + class: google.cloud.storage.bucket.IAMConfiguration + fullName: google.cloud.storage.bucket.IAMConfiguration.update + langs: + - python + module: google.cloud.storage.bucket + name: update + source: + id: update + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'If E is present and has a .keys() method, then does: for k in E: D[k] + = E[k] + + If E is present and lacks a .keys() method, then does: for k, v in E: D[k] = + v + + In either case, this is followed by: for k in F: D[k] = F[k] + + + ' + syntax: + content: update([E, ]**F) + type: method + uid: google.cloud.storage.bucket.IAMConfiguration.update +- class: google.cloud.storage.bucket.IAMConfiguration + fullName: google.cloud.storage.bucket.IAMConfiguration.values + langs: + - python + module: google.cloud.storage.bucket + name: values + source: + id: values + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: API documentation for `storage.bucket.IAMConfiguration.values` method. + syntax: + content: values() + type: method + uid: google.cloud.storage.bucket.IAMConfiguration.values +references: +- fullName: google.cloud.storage.bucket.IAMConfiguration.bucket + isExternal: false + name: bucket + parent: google.cloud.storage.bucket.IAMConfiguration + uid: google.cloud.storage.bucket.IAMConfiguration.bucket +- fullName: google.cloud.storage.bucket.IAMConfiguration.bucket_policy_only_enabled + isExternal: false + name: bucket_policy_only_enabled + parent: google.cloud.storage.bucket.IAMConfiguration + uid: google.cloud.storage.bucket.IAMConfiguration.bucket_policy_only_enabled +- fullName: google.cloud.storage.bucket.IAMConfiguration.bucket_policy_only_locked_time + isExternal: false + name: bucket_policy_only_locked_time + parent: google.cloud.storage.bucket.IAMConfiguration + uid: google.cloud.storage.bucket.IAMConfiguration.bucket_policy_only_locked_time +- fullName: google.cloud.storage.bucket.IAMConfiguration.clear + isExternal: false + name: clear + parent: google.cloud.storage.bucket.IAMConfiguration + uid: google.cloud.storage.bucket.IAMConfiguration.clear +- fullName: google.cloud.storage.bucket.IAMConfiguration.copy + isExternal: false + name: copy + parent: google.cloud.storage.bucket.IAMConfiguration + uid: google.cloud.storage.bucket.IAMConfiguration.copy +- fullName: google.cloud.storage.bucket.IAMConfiguration.from_api_repr + isExternal: false + name: from_api_repr + parent: google.cloud.storage.bucket.IAMConfiguration + uid: google.cloud.storage.bucket.IAMConfiguration.from_api_repr +- fullName: google.cloud.storage.bucket.IAMConfiguration.fromkeys + isExternal: false + name: fromkeys + parent: google.cloud.storage.bucket.IAMConfiguration + uid: google.cloud.storage.bucket.IAMConfiguration.fromkeys +- fullName: google.cloud.storage.bucket.IAMConfiguration.get + isExternal: false + name: get + parent: google.cloud.storage.bucket.IAMConfiguration + uid: google.cloud.storage.bucket.IAMConfiguration.get +- fullName: google.cloud.storage.bucket.IAMConfiguration.items + isExternal: false + name: items + parent: google.cloud.storage.bucket.IAMConfiguration + uid: google.cloud.storage.bucket.IAMConfiguration.items +- fullName: google.cloud.storage.bucket.IAMConfiguration.keys + isExternal: false + name: keys + parent: google.cloud.storage.bucket.IAMConfiguration + uid: google.cloud.storage.bucket.IAMConfiguration.keys +- fullName: google.cloud.storage.bucket.IAMConfiguration.pop + isExternal: false + name: pop + parent: google.cloud.storage.bucket.IAMConfiguration + uid: google.cloud.storage.bucket.IAMConfiguration.pop +- fullName: google.cloud.storage.bucket.IAMConfiguration.popitem + isExternal: false + name: popitem + parent: google.cloud.storage.bucket.IAMConfiguration + uid: google.cloud.storage.bucket.IAMConfiguration.popitem +- fullName: google.cloud.storage.bucket.IAMConfiguration.public_access_prevention + isExternal: false + name: public_access_prevention + parent: google.cloud.storage.bucket.IAMConfiguration + uid: google.cloud.storage.bucket.IAMConfiguration.public_access_prevention +- fullName: google.cloud.storage.bucket.IAMConfiguration.setdefault + isExternal: false + name: setdefault + parent: google.cloud.storage.bucket.IAMConfiguration + uid: google.cloud.storage.bucket.IAMConfiguration.setdefault +- fullName: google.cloud.storage.bucket.IAMConfiguration.uniform_bucket_level_access_enabled + isExternal: false + name: uniform_bucket_level_access_enabled + parent: google.cloud.storage.bucket.IAMConfiguration + uid: google.cloud.storage.bucket.IAMConfiguration.uniform_bucket_level_access_enabled +- fullName: google.cloud.storage.bucket.IAMConfiguration.uniform_bucket_level_access_locked_time + isExternal: false + name: uniform_bucket_level_access_locked_time + parent: google.cloud.storage.bucket.IAMConfiguration + uid: google.cloud.storage.bucket.IAMConfiguration.uniform_bucket_level_access_locked_time +- fullName: google.cloud.storage.bucket.IAMConfiguration.update + isExternal: false + name: update + parent: google.cloud.storage.bucket.IAMConfiguration + uid: google.cloud.storage.bucket.IAMConfiguration.update +- fullName: google.cloud.storage.bucket.IAMConfiguration.values + isExternal: false + name: values + parent: google.cloud.storage.bucket.IAMConfiguration + uid: google.cloud.storage.bucket.IAMConfiguration.values diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.yml new file mode 100644 index 000000000000..a2c361705505 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.yml @@ -0,0 +1,393 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: [] + children: + - google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.clear + - google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.copy + - google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.from_api_repr + - google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.fromkeys + - google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.get + - google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.items + - google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.keys + - google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.pop + - google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.popitem + - google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.setdefault + - google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.update + - google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.values + class: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload + fullName: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload + inheritance: + - inheritance: + - type: builtins.object + type: builtins.dict + langs: + - python + module: google.cloud.storage.bucket + name: LifecycleRuleAbortIncompleteMultipartUpload + source: + id: LifecycleRuleAbortIncompleteMultipartUpload + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 403 + summary: 'Map a rule aborting incomplete multipart uploads of matching items. + + + The "age" lifecycle condition is the only supported condition for this rule. + + ' + syntax: + content: LifecycleRuleAbortIncompleteMultipartUpload(**kw) + parameters: [] + type: class + uid: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload +- class: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload + fullName: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.clear + langs: + - python + module: google.cloud.storage.bucket + name: clear + source: + id: clear + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: API documentation for `storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.clear` + method. + syntax: + content: clear() + type: method + uid: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.clear +- class: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload + fullName: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.copy + langs: + - python + module: google.cloud.storage.bucket + name: copy + source: + id: copy + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: API documentation for `storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.copy` + method. + syntax: + content: copy() + type: method + uid: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.copy +- attributes: [] + class: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload + fullName: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.from_api_repr + langs: + - python + module: google.cloud.storage.bucket + name: from_api_repr + source: + id: from_api_repr + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 420 + summary: 'Factory: construct instance from resource. + + ' + syntax: + content: from_api_repr(resource) + parameters: + - description: mapping as returned from API call. + id: resource + var_type: dict + returns: + - description: Instance created from resource. + var_type: LifecycleRuleAbortIncompleteMultipartUpload + type: method + uid: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.from_api_repr +- attributes: [] + class: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload + fullName: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.fromkeys + langs: + - python + module: google.cloud.storage.bucket + name: fromkeys + source: + id: fromkeys + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Create a new dictionary with keys from iterable and values set to value. + + + ' + syntax: + content: fromkeys(value=None, /) + parameters: [] + type: method + uid: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.fromkeys +- attributes: [] + class: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload + fullName: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.get + langs: + - python + module: google.cloud.storage.bucket + name: get + source: + id: get + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Return the value for key if key is in the dictionary, else default. + + + ' + syntax: + content: get(key, default=None, /) + parameters: [] + type: method + uid: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.get +- class: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload + fullName: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.items + langs: + - python + module: google.cloud.storage.bucket + name: items + source: + id: items + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: API documentation for `storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.items` + method. + syntax: + content: items() + type: method + uid: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.items +- class: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload + fullName: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.keys + langs: + - python + module: google.cloud.storage.bucket + name: keys + source: + id: keys + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: API documentation for `storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.keys` + method. + syntax: + content: keys() + type: method + uid: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.keys +- attributes: [] + class: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload + fullName: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.pop + langs: + - python + module: google.cloud.storage.bucket + name: pop + source: + id: pop + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'If key is not found, default is returned if given, otherwise KeyError + is raised + + + ' + syntax: + content: pop(k[,d]) + type: method + uid: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.pop +- attributes: [] + class: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload + fullName: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.popitem + langs: + - python + module: google.cloud.storage.bucket + name: popitem + source: + id: popitem + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Remove and return a (key, value) pair as a 2-tuple. + + + Pairs are returned in LIFO (last-in, first-out) order. + + Raises KeyError if the dict is empty. + + + ' + syntax: + content: popitem() + parameters: [] + type: method + uid: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.popitem +- attributes: [] + class: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload + fullName: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.setdefault + langs: + - python + module: google.cloud.storage.bucket + name: setdefault + source: + id: setdefault + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Insert key with a value of default if key is not in the dictionary. + + + Return the value for key if key is in the dictionary, else default. + + + ' + syntax: + content: setdefault(key, default=None, /) + parameters: [] + type: method + uid: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.setdefault +- attributes: [] + class: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload + fullName: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.update + langs: + - python + module: google.cloud.storage.bucket + name: update + source: + id: update + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'If E is present and has a .keys() method, then does: for k in E: D[k] + = E[k] + + If E is present and lacks a .keys() method, then does: for k, v in E: D[k] = + v + + In either case, this is followed by: for k in F: D[k] = F[k] + + + ' + syntax: + content: update([E, ]**F) + type: method + uid: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.update +- class: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload + fullName: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.values + langs: + - python + module: google.cloud.storage.bucket + name: values + source: + id: values + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: API documentation for `storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.values` + method. + syntax: + content: values() + type: method + uid: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.values +references: +- fullName: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.clear + isExternal: false + name: clear + parent: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload + uid: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.clear +- fullName: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.copy + isExternal: false + name: copy + parent: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload + uid: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.copy +- fullName: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.from_api_repr + isExternal: false + name: from_api_repr + parent: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload + uid: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.from_api_repr +- fullName: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.fromkeys + isExternal: false + name: fromkeys + parent: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload + uid: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.fromkeys +- fullName: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.get + isExternal: false + name: get + parent: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload + uid: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.get +- fullName: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.items + isExternal: false + name: items + parent: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload + uid: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.items +- fullName: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.keys + isExternal: false + name: keys + parent: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload + uid: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.keys +- fullName: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.pop + isExternal: false + name: pop + parent: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload + uid: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.pop +- fullName: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.popitem + isExternal: false + name: popitem + parent: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload + uid: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.popitem +- fullName: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.setdefault + isExternal: false + name: setdefault + parent: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload + uid: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.setdefault +- fullName: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.update + isExternal: false + name: update + parent: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload + uid: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.update +- fullName: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.values + isExternal: false + name: values + parent: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload + uid: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload.values diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.bucket.LifecycleRuleConditions.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.bucket.LifecycleRuleConditions.yml new file mode 100644 index 000000000000..8a18d177bee8 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.bucket.LifecycleRuleConditions.yml @@ -0,0 +1,777 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: [] + children: + - google.cloud.storage.bucket.LifecycleRuleConditions.age + - google.cloud.storage.bucket.LifecycleRuleConditions.clear + - google.cloud.storage.bucket.LifecycleRuleConditions.copy + - google.cloud.storage.bucket.LifecycleRuleConditions.created_before + - google.cloud.storage.bucket.LifecycleRuleConditions.custom_time_before + - google.cloud.storage.bucket.LifecycleRuleConditions.days_since_custom_time + - google.cloud.storage.bucket.LifecycleRuleConditions.days_since_noncurrent_time + - google.cloud.storage.bucket.LifecycleRuleConditions.from_api_repr + - google.cloud.storage.bucket.LifecycleRuleConditions.fromkeys + - google.cloud.storage.bucket.LifecycleRuleConditions.get + - google.cloud.storage.bucket.LifecycleRuleConditions.is_live + - google.cloud.storage.bucket.LifecycleRuleConditions.items + - google.cloud.storage.bucket.LifecycleRuleConditions.keys + - google.cloud.storage.bucket.LifecycleRuleConditions.matches_prefix + - google.cloud.storage.bucket.LifecycleRuleConditions.matches_storage_class + - google.cloud.storage.bucket.LifecycleRuleConditions.matches_suffix + - google.cloud.storage.bucket.LifecycleRuleConditions.noncurrent_time_before + - google.cloud.storage.bucket.LifecycleRuleConditions.number_of_newer_versions + - google.cloud.storage.bucket.LifecycleRuleConditions.pop + - google.cloud.storage.bucket.LifecycleRuleConditions.popitem + - google.cloud.storage.bucket.LifecycleRuleConditions.setdefault + - google.cloud.storage.bucket.LifecycleRuleConditions.update + - google.cloud.storage.bucket.LifecycleRuleConditions.values + class: google.cloud.storage.bucket.LifecycleRuleConditions + fullName: google.cloud.storage.bucket.LifecycleRuleConditions + inheritance: + - inheritance: + - type: builtins.object + type: builtins.dict + langs: + - python + module: google.cloud.storage.bucket + name: LifecycleRuleConditions + source: + id: LifecycleRuleConditions + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 147 + summary: 'Map a single lifecycle rule for a bucket. + + + See: https://cloud.google.com/storage/docs/lifecycle + + ' + syntax: + content: "LifecycleRuleConditions(\n age=None,\n created_before=None,\n\ + \ is_live=None,\n matches_storage_class=None,\n number_of_newer_versions=None,\n\ + \ days_since_custom_time=None,\n custom_time_before=None,\n days_since_noncurrent_time=None,\n\ + \ noncurrent_time_before=None,\n matches_prefix=None,\n matches_suffix=None,\n\ + \ _factory=False,\n)" + exceptions: + - description: if no arguments are passed. + var_type: ValueError + parameters: + - description: (Optional) Apply rule action to items whose age, in days, exceeds + this value. + id: age + var_type: int + - description: (Optional) Apply rule action to items created before this date. + id: created_before + var_type: datetime.date + - description: (Optional) If true, apply rule action to non-versioned items, or + to items with no newer versions. If false, apply rule action to versioned + items with at least one newer version. + id: is_live + var_type: bool + - description: (Optional) Apply rule action to items which any prefix matches + the beginning of the item name. + id: matches_prefix + var_type: list(str) + - description: (Optional) Apply rule action to items whose storage class matches + this value. + id: matches_storage_class + var_type: list(str), one or more of Bucket.STORAGE_CLASSES. + - description: (Optional) Apply rule action to items which any suffix matches + the end of the item name. + id: matches_suffix + var_type: list(str) + - description: (Optional) Apply rule action to versioned items having N newer + versions. + id: number_of_newer_versions + var_type: int + - description: (Optional) Apply rule action to items whose number of days elapsed + since the custom timestamp. This condition is relevant only for versioned + objects. The value of the field must be a non negative integer. If it's zero, + the object version will become eligible for lifecycle action as soon as it + becomes custom. + id: days_since_custom_time + var_type: int + - description: (Optional) Date object parsed from RFC3339 valid date, apply rule + action to items whose custom time is before this date. This condition is relevant + only for versioned objects, e.g., 2019-03-16. + id: custom_time_before + var_type: datetime.date + - description: (Optional) Apply rule action to items whose number of days elapsed + since the non current timestamp. This condition is relevant only for versioned + objects. The value of the field must be a non negative integer. If it's zero, + the object version will become eligible for lifecycle action as soon as it + becomes non current. + id: days_since_noncurrent_time + var_type: int + - description: (Optional) Date object parsed from RFC3339 valid date, apply rule + action to items whose non current time is before this date. This condition + is relevant only for versioned objects, e.g, 2019-03-16. + id: noncurrent_time_before + var_type: datetime.date + type: class + uid: google.cloud.storage.bucket.LifecycleRuleConditions +- &id001 + attributes: [] + class: google.cloud.storage.bucket.LifecycleRuleConditions + fullName: google.cloud.storage.bucket.LifecycleRuleConditions.age + langs: + - python + module: google.cloud.storage.bucket + name: age + source: + id: age + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Conditon''s age value. + + + ' + syntax: {} + type: property + uid: google.cloud.storage.bucket.LifecycleRuleConditions.age +- *id001 +- class: google.cloud.storage.bucket.LifecycleRuleConditions + fullName: google.cloud.storage.bucket.LifecycleRuleConditions.clear + langs: + - python + module: google.cloud.storage.bucket + name: clear + source: + id: clear + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: API documentation for `storage.bucket.LifecycleRuleConditions.clear` method. + syntax: + content: clear() + type: method + uid: google.cloud.storage.bucket.LifecycleRuleConditions.clear +- class: google.cloud.storage.bucket.LifecycleRuleConditions + fullName: google.cloud.storage.bucket.LifecycleRuleConditions.copy + langs: + - python + module: google.cloud.storage.bucket + name: copy + source: + id: copy + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: API documentation for `storage.bucket.LifecycleRuleConditions.copy` method. + syntax: + content: copy() + type: method + uid: google.cloud.storage.bucket.LifecycleRuleConditions.copy +- &id002 + attributes: [] + class: google.cloud.storage.bucket.LifecycleRuleConditions + fullName: google.cloud.storage.bucket.LifecycleRuleConditions.created_before + langs: + - python + module: google.cloud.storage.bucket + name: created_before + source: + id: created_before + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Conditon''s created_before value. + + + ' + syntax: {} + type: property + uid: google.cloud.storage.bucket.LifecycleRuleConditions.created_before +- *id002 +- &id003 + attributes: [] + class: google.cloud.storage.bucket.LifecycleRuleConditions + fullName: google.cloud.storage.bucket.LifecycleRuleConditions.custom_time_before + langs: + - python + module: google.cloud.storage.bucket + name: custom_time_before + source: + id: custom_time_before + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Conditon''s ''custom_time_before'' value. + + + ' + syntax: {} + type: property + uid: google.cloud.storage.bucket.LifecycleRuleConditions.custom_time_before +- *id003 +- &id004 + attributes: [] + class: google.cloud.storage.bucket.LifecycleRuleConditions + fullName: google.cloud.storage.bucket.LifecycleRuleConditions.days_since_custom_time + langs: + - python + module: google.cloud.storage.bucket + name: days_since_custom_time + source: + id: days_since_custom_time + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Conditon''s ''days_since_custom_time'' value. + + + ' + syntax: {} + type: property + uid: google.cloud.storage.bucket.LifecycleRuleConditions.days_since_custom_time +- *id004 +- &id005 + attributes: [] + class: google.cloud.storage.bucket.LifecycleRuleConditions + fullName: google.cloud.storage.bucket.LifecycleRuleConditions.days_since_noncurrent_time + langs: + - python + module: google.cloud.storage.bucket + name: days_since_noncurrent_time + source: + id: days_since_noncurrent_time + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Conditon''s ''days_since_noncurrent_time'' value. + + + ' + syntax: {} + type: property + uid: google.cloud.storage.bucket.LifecycleRuleConditions.days_since_noncurrent_time +- *id005 +- attributes: [] + class: google.cloud.storage.bucket.LifecycleRuleConditions + fullName: google.cloud.storage.bucket.LifecycleRuleConditions.from_api_repr + langs: + - python + module: google.cloud.storage.bucket + name: from_api_repr + source: + id: from_api_repr + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 266 + summary: 'Factory: construct instance from resource. + + ' + syntax: + content: from_api_repr(resource) + parameters: + - description: mapping as returned from API call. + id: resource + var_type: dict + returns: + - description: Instance created from resource. + var_type: LifecycleRuleConditions + type: method + uid: google.cloud.storage.bucket.LifecycleRuleConditions.from_api_repr +- attributes: [] + class: google.cloud.storage.bucket.LifecycleRuleConditions + fullName: google.cloud.storage.bucket.LifecycleRuleConditions.fromkeys + langs: + - python + module: google.cloud.storage.bucket + name: fromkeys + source: + id: fromkeys + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Create a new dictionary with keys from iterable and values set to value. + + + ' + syntax: + content: fromkeys(value=None, /) + parameters: [] + type: method + uid: google.cloud.storage.bucket.LifecycleRuleConditions.fromkeys +- attributes: [] + class: google.cloud.storage.bucket.LifecycleRuleConditions + fullName: google.cloud.storage.bucket.LifecycleRuleConditions.get + langs: + - python + module: google.cloud.storage.bucket + name: get + source: + id: get + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Return the value for key if key is in the dictionary, else default. + + + ' + syntax: + content: get(key, default=None, /) + parameters: [] + type: method + uid: google.cloud.storage.bucket.LifecycleRuleConditions.get +- &id006 + attributes: [] + class: google.cloud.storage.bucket.LifecycleRuleConditions + fullName: google.cloud.storage.bucket.LifecycleRuleConditions.is_live + langs: + - python + module: google.cloud.storage.bucket + name: is_live + source: + id: is_live + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Conditon''s ''is_live'' value. + + + ' + syntax: {} + type: property + uid: google.cloud.storage.bucket.LifecycleRuleConditions.is_live +- *id006 +- class: google.cloud.storage.bucket.LifecycleRuleConditions + fullName: google.cloud.storage.bucket.LifecycleRuleConditions.items + langs: + - python + module: google.cloud.storage.bucket + name: items + source: + id: items + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: API documentation for `storage.bucket.LifecycleRuleConditions.items` method. + syntax: + content: items() + type: method + uid: google.cloud.storage.bucket.LifecycleRuleConditions.items +- class: google.cloud.storage.bucket.LifecycleRuleConditions + fullName: google.cloud.storage.bucket.LifecycleRuleConditions.keys + langs: + - python + module: google.cloud.storage.bucket + name: keys + source: + id: keys + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: API documentation for `storage.bucket.LifecycleRuleConditions.keys` method. + syntax: + content: keys() + type: method + uid: google.cloud.storage.bucket.LifecycleRuleConditions.keys +- &id007 + attributes: [] + class: google.cloud.storage.bucket.LifecycleRuleConditions + fullName: google.cloud.storage.bucket.LifecycleRuleConditions.matches_prefix + langs: + - python + module: google.cloud.storage.bucket + name: matches_prefix + source: + id: matches_prefix + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Conditon''s ''matches_prefix'' value. + + + ' + syntax: {} + type: property + uid: google.cloud.storage.bucket.LifecycleRuleConditions.matches_prefix +- *id007 +- &id008 + attributes: [] + class: google.cloud.storage.bucket.LifecycleRuleConditions + fullName: google.cloud.storage.bucket.LifecycleRuleConditions.matches_storage_class + langs: + - python + module: google.cloud.storage.bucket + name: matches_storage_class + source: + id: matches_storage_class + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Conditon''s ''matches_storage_class'' value. + + + ' + syntax: {} + type: property + uid: google.cloud.storage.bucket.LifecycleRuleConditions.matches_storage_class +- *id008 +- &id009 + attributes: [] + class: google.cloud.storage.bucket.LifecycleRuleConditions + fullName: google.cloud.storage.bucket.LifecycleRuleConditions.matches_suffix + langs: + - python + module: google.cloud.storage.bucket + name: matches_suffix + source: + id: matches_suffix + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Conditon''s ''matches_suffix'' value. + + + ' + syntax: {} + type: property + uid: google.cloud.storage.bucket.LifecycleRuleConditions.matches_suffix +- *id009 +- &id010 + attributes: [] + class: google.cloud.storage.bucket.LifecycleRuleConditions + fullName: google.cloud.storage.bucket.LifecycleRuleConditions.noncurrent_time_before + langs: + - python + module: google.cloud.storage.bucket + name: noncurrent_time_before + source: + id: noncurrent_time_before + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Conditon''s ''noncurrent_time_before'' value. + + + ' + syntax: {} + type: property + uid: google.cloud.storage.bucket.LifecycleRuleConditions.noncurrent_time_before +- *id010 +- &id011 + attributes: [] + class: google.cloud.storage.bucket.LifecycleRuleConditions + fullName: google.cloud.storage.bucket.LifecycleRuleConditions.number_of_newer_versions + langs: + - python + module: google.cloud.storage.bucket + name: number_of_newer_versions + source: + id: number_of_newer_versions + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Conditon''s ''number_of_newer_versions'' value. + + + ' + syntax: {} + type: property + uid: google.cloud.storage.bucket.LifecycleRuleConditions.number_of_newer_versions +- *id011 +- attributes: [] + class: google.cloud.storage.bucket.LifecycleRuleConditions + fullName: google.cloud.storage.bucket.LifecycleRuleConditions.pop + langs: + - python + module: google.cloud.storage.bucket + name: pop + source: + id: pop + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'If key is not found, default is returned if given, otherwise KeyError + is raised + + + ' + syntax: + content: pop(k[,d]) + type: method + uid: google.cloud.storage.bucket.LifecycleRuleConditions.pop +- attributes: [] + class: google.cloud.storage.bucket.LifecycleRuleConditions + fullName: google.cloud.storage.bucket.LifecycleRuleConditions.popitem + langs: + - python + module: google.cloud.storage.bucket + name: popitem + source: + id: popitem + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Remove and return a (key, value) pair as a 2-tuple. + + + Pairs are returned in LIFO (last-in, first-out) order. + + Raises KeyError if the dict is empty. + + + ' + syntax: + content: popitem() + parameters: [] + type: method + uid: google.cloud.storage.bucket.LifecycleRuleConditions.popitem +- attributes: [] + class: google.cloud.storage.bucket.LifecycleRuleConditions + fullName: google.cloud.storage.bucket.LifecycleRuleConditions.setdefault + langs: + - python + module: google.cloud.storage.bucket + name: setdefault + source: + id: setdefault + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Insert key with a value of default if key is not in the dictionary. + + + Return the value for key if key is in the dictionary, else default. + + + ' + syntax: + content: setdefault(key, default=None, /) + parameters: [] + type: method + uid: google.cloud.storage.bucket.LifecycleRuleConditions.setdefault +- attributes: [] + class: google.cloud.storage.bucket.LifecycleRuleConditions + fullName: google.cloud.storage.bucket.LifecycleRuleConditions.update + langs: + - python + module: google.cloud.storage.bucket + name: update + source: + id: update + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'If E is present and has a .keys() method, then does: for k in E: D[k] + = E[k] + + If E is present and lacks a .keys() method, then does: for k, v in E: D[k] = + v + + In either case, this is followed by: for k in F: D[k] = F[k] + + + ' + syntax: + content: update([E, ]**F) + type: method + uid: google.cloud.storage.bucket.LifecycleRuleConditions.update +- class: google.cloud.storage.bucket.LifecycleRuleConditions + fullName: google.cloud.storage.bucket.LifecycleRuleConditions.values + langs: + - python + module: google.cloud.storage.bucket + name: values + source: + id: values + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: API documentation for `storage.bucket.LifecycleRuleConditions.values` method. + syntax: + content: values() + type: method + uid: google.cloud.storage.bucket.LifecycleRuleConditions.values +references: +- fullName: google.cloud.storage.bucket.LifecycleRuleConditions.age + isExternal: false + name: age + parent: google.cloud.storage.bucket.LifecycleRuleConditions + uid: google.cloud.storage.bucket.LifecycleRuleConditions.age +- fullName: google.cloud.storage.bucket.LifecycleRuleConditions.clear + isExternal: false + name: clear + parent: google.cloud.storage.bucket.LifecycleRuleConditions + uid: google.cloud.storage.bucket.LifecycleRuleConditions.clear +- fullName: google.cloud.storage.bucket.LifecycleRuleConditions.copy + isExternal: false + name: copy + parent: google.cloud.storage.bucket.LifecycleRuleConditions + uid: google.cloud.storage.bucket.LifecycleRuleConditions.copy +- fullName: google.cloud.storage.bucket.LifecycleRuleConditions.created_before + isExternal: false + name: created_before + parent: google.cloud.storage.bucket.LifecycleRuleConditions + uid: google.cloud.storage.bucket.LifecycleRuleConditions.created_before +- fullName: google.cloud.storage.bucket.LifecycleRuleConditions.custom_time_before + isExternal: false + name: custom_time_before + parent: google.cloud.storage.bucket.LifecycleRuleConditions + uid: google.cloud.storage.bucket.LifecycleRuleConditions.custom_time_before +- fullName: google.cloud.storage.bucket.LifecycleRuleConditions.days_since_custom_time + isExternal: false + name: days_since_custom_time + parent: google.cloud.storage.bucket.LifecycleRuleConditions + uid: google.cloud.storage.bucket.LifecycleRuleConditions.days_since_custom_time +- fullName: google.cloud.storage.bucket.LifecycleRuleConditions.days_since_noncurrent_time + isExternal: false + name: days_since_noncurrent_time + parent: google.cloud.storage.bucket.LifecycleRuleConditions + uid: google.cloud.storage.bucket.LifecycleRuleConditions.days_since_noncurrent_time +- fullName: google.cloud.storage.bucket.LifecycleRuleConditions.from_api_repr + isExternal: false + name: from_api_repr + parent: google.cloud.storage.bucket.LifecycleRuleConditions + uid: google.cloud.storage.bucket.LifecycleRuleConditions.from_api_repr +- fullName: google.cloud.storage.bucket.LifecycleRuleConditions.fromkeys + isExternal: false + name: fromkeys + parent: google.cloud.storage.bucket.LifecycleRuleConditions + uid: google.cloud.storage.bucket.LifecycleRuleConditions.fromkeys +- fullName: google.cloud.storage.bucket.LifecycleRuleConditions.get + isExternal: false + name: get + parent: google.cloud.storage.bucket.LifecycleRuleConditions + uid: google.cloud.storage.bucket.LifecycleRuleConditions.get +- fullName: google.cloud.storage.bucket.LifecycleRuleConditions.is_live + isExternal: false + name: is_live + parent: google.cloud.storage.bucket.LifecycleRuleConditions + uid: google.cloud.storage.bucket.LifecycleRuleConditions.is_live +- fullName: google.cloud.storage.bucket.LifecycleRuleConditions.items + isExternal: false + name: items + parent: google.cloud.storage.bucket.LifecycleRuleConditions + uid: google.cloud.storage.bucket.LifecycleRuleConditions.items +- fullName: google.cloud.storage.bucket.LifecycleRuleConditions.keys + isExternal: false + name: keys + parent: google.cloud.storage.bucket.LifecycleRuleConditions + uid: google.cloud.storage.bucket.LifecycleRuleConditions.keys +- fullName: google.cloud.storage.bucket.LifecycleRuleConditions.matches_prefix + isExternal: false + name: matches_prefix + parent: google.cloud.storage.bucket.LifecycleRuleConditions + uid: google.cloud.storage.bucket.LifecycleRuleConditions.matches_prefix +- fullName: google.cloud.storage.bucket.LifecycleRuleConditions.matches_storage_class + isExternal: false + name: matches_storage_class + parent: google.cloud.storage.bucket.LifecycleRuleConditions + uid: google.cloud.storage.bucket.LifecycleRuleConditions.matches_storage_class +- fullName: google.cloud.storage.bucket.LifecycleRuleConditions.matches_suffix + isExternal: false + name: matches_suffix + parent: google.cloud.storage.bucket.LifecycleRuleConditions + uid: google.cloud.storage.bucket.LifecycleRuleConditions.matches_suffix +- fullName: google.cloud.storage.bucket.LifecycleRuleConditions.noncurrent_time_before + isExternal: false + name: noncurrent_time_before + parent: google.cloud.storage.bucket.LifecycleRuleConditions + uid: google.cloud.storage.bucket.LifecycleRuleConditions.noncurrent_time_before +- fullName: google.cloud.storage.bucket.LifecycleRuleConditions.number_of_newer_versions + isExternal: false + name: number_of_newer_versions + parent: google.cloud.storage.bucket.LifecycleRuleConditions + uid: google.cloud.storage.bucket.LifecycleRuleConditions.number_of_newer_versions +- fullName: google.cloud.storage.bucket.LifecycleRuleConditions.pop + isExternal: false + name: pop + parent: google.cloud.storage.bucket.LifecycleRuleConditions + uid: google.cloud.storage.bucket.LifecycleRuleConditions.pop +- fullName: google.cloud.storage.bucket.LifecycleRuleConditions.popitem + isExternal: false + name: popitem + parent: google.cloud.storage.bucket.LifecycleRuleConditions + uid: google.cloud.storage.bucket.LifecycleRuleConditions.popitem +- fullName: google.cloud.storage.bucket.LifecycleRuleConditions.setdefault + isExternal: false + name: setdefault + parent: google.cloud.storage.bucket.LifecycleRuleConditions + uid: google.cloud.storage.bucket.LifecycleRuleConditions.setdefault +- fullName: google.cloud.storage.bucket.LifecycleRuleConditions.update + isExternal: false + name: update + parent: google.cloud.storage.bucket.LifecycleRuleConditions + uid: google.cloud.storage.bucket.LifecycleRuleConditions.update +- fullName: google.cloud.storage.bucket.LifecycleRuleConditions.values + isExternal: false + name: values + parent: google.cloud.storage.bucket.LifecycleRuleConditions + uid: google.cloud.storage.bucket.LifecycleRuleConditions.values diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.bucket.LifecycleRuleDelete.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.bucket.LifecycleRuleDelete.yml new file mode 100644 index 000000000000..138a652d7fdb --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.bucket.LifecycleRuleDelete.yml @@ -0,0 +1,385 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: [] + children: + - google.cloud.storage.bucket.LifecycleRuleDelete.clear + - google.cloud.storage.bucket.LifecycleRuleDelete.copy + - google.cloud.storage.bucket.LifecycleRuleDelete.from_api_repr + - google.cloud.storage.bucket.LifecycleRuleDelete.fromkeys + - google.cloud.storage.bucket.LifecycleRuleDelete.get + - google.cloud.storage.bucket.LifecycleRuleDelete.items + - google.cloud.storage.bucket.LifecycleRuleDelete.keys + - google.cloud.storage.bucket.LifecycleRuleDelete.pop + - google.cloud.storage.bucket.LifecycleRuleDelete.popitem + - google.cloud.storage.bucket.LifecycleRuleDelete.setdefault + - google.cloud.storage.bucket.LifecycleRuleDelete.update + - google.cloud.storage.bucket.LifecycleRuleDelete.values + class: google.cloud.storage.bucket.LifecycleRuleDelete + fullName: google.cloud.storage.bucket.LifecycleRuleDelete + inheritance: + - inheritance: + - type: builtins.object + type: builtins.dict + langs: + - python + module: google.cloud.storage.bucket + name: LifecycleRuleDelete + source: + id: LifecycleRuleDelete + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 342 + summary: 'Map a lifecycle rule deleting matching items. + + ' + syntax: + content: LifecycleRuleDelete(**kw) + parameters: [] + type: class + uid: google.cloud.storage.bucket.LifecycleRuleDelete +- class: google.cloud.storage.bucket.LifecycleRuleDelete + fullName: google.cloud.storage.bucket.LifecycleRuleDelete.clear + langs: + - python + module: google.cloud.storage.bucket + name: clear + source: + id: clear + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: API documentation for `storage.bucket.LifecycleRuleDelete.clear` method. + syntax: + content: clear() + type: method + uid: google.cloud.storage.bucket.LifecycleRuleDelete.clear +- class: google.cloud.storage.bucket.LifecycleRuleDelete + fullName: google.cloud.storage.bucket.LifecycleRuleDelete.copy + langs: + - python + module: google.cloud.storage.bucket + name: copy + source: + id: copy + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: API documentation for `storage.bucket.LifecycleRuleDelete.copy` method. + syntax: + content: copy() + type: method + uid: google.cloud.storage.bucket.LifecycleRuleDelete.copy +- attributes: [] + class: google.cloud.storage.bucket.LifecycleRuleDelete + fullName: google.cloud.storage.bucket.LifecycleRuleDelete.from_api_repr + langs: + - python + module: google.cloud.storage.bucket + name: from_api_repr + source: + id: from_api_repr + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 354 + summary: 'Factory: construct instance from resource. + + ' + syntax: + content: from_api_repr(resource) + parameters: + - description: mapping as returned from API call. + id: resource + var_type: dict + returns: + - description: Instance created from resource. + var_type: LifecycleRuleDelete + type: method + uid: google.cloud.storage.bucket.LifecycleRuleDelete.from_api_repr +- attributes: [] + class: google.cloud.storage.bucket.LifecycleRuleDelete + fullName: google.cloud.storage.bucket.LifecycleRuleDelete.fromkeys + langs: + - python + module: google.cloud.storage.bucket + name: fromkeys + source: + id: fromkeys + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Create a new dictionary with keys from iterable and values set to value. + + + ' + syntax: + content: fromkeys(value=None, /) + parameters: [] + type: method + uid: google.cloud.storage.bucket.LifecycleRuleDelete.fromkeys +- attributes: [] + class: google.cloud.storage.bucket.LifecycleRuleDelete + fullName: google.cloud.storage.bucket.LifecycleRuleDelete.get + langs: + - python + module: google.cloud.storage.bucket + name: get + source: + id: get + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Return the value for key if key is in the dictionary, else default. + + + ' + syntax: + content: get(key, default=None, /) + parameters: [] + type: method + uid: google.cloud.storage.bucket.LifecycleRuleDelete.get +- class: google.cloud.storage.bucket.LifecycleRuleDelete + fullName: google.cloud.storage.bucket.LifecycleRuleDelete.items + langs: + - python + module: google.cloud.storage.bucket + name: items + source: + id: items + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: API documentation for `storage.bucket.LifecycleRuleDelete.items` method. + syntax: + content: items() + type: method + uid: google.cloud.storage.bucket.LifecycleRuleDelete.items +- class: google.cloud.storage.bucket.LifecycleRuleDelete + fullName: google.cloud.storage.bucket.LifecycleRuleDelete.keys + langs: + - python + module: google.cloud.storage.bucket + name: keys + source: + id: keys + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: API documentation for `storage.bucket.LifecycleRuleDelete.keys` method. + syntax: + content: keys() + type: method + uid: google.cloud.storage.bucket.LifecycleRuleDelete.keys +- attributes: [] + class: google.cloud.storage.bucket.LifecycleRuleDelete + fullName: google.cloud.storage.bucket.LifecycleRuleDelete.pop + langs: + - python + module: google.cloud.storage.bucket + name: pop + source: + id: pop + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'If key is not found, default is returned if given, otherwise KeyError + is raised + + + ' + syntax: + content: pop(k[,d]) + type: method + uid: google.cloud.storage.bucket.LifecycleRuleDelete.pop +- attributes: [] + class: google.cloud.storage.bucket.LifecycleRuleDelete + fullName: google.cloud.storage.bucket.LifecycleRuleDelete.popitem + langs: + - python + module: google.cloud.storage.bucket + name: popitem + source: + id: popitem + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Remove and return a (key, value) pair as a 2-tuple. + + + Pairs are returned in LIFO (last-in, first-out) order. + + Raises KeyError if the dict is empty. + + + ' + syntax: + content: popitem() + parameters: [] + type: method + uid: google.cloud.storage.bucket.LifecycleRuleDelete.popitem +- attributes: [] + class: google.cloud.storage.bucket.LifecycleRuleDelete + fullName: google.cloud.storage.bucket.LifecycleRuleDelete.setdefault + langs: + - python + module: google.cloud.storage.bucket + name: setdefault + source: + id: setdefault + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Insert key with a value of default if key is not in the dictionary. + + + Return the value for key if key is in the dictionary, else default. + + + ' + syntax: + content: setdefault(key, default=None, /) + parameters: [] + type: method + uid: google.cloud.storage.bucket.LifecycleRuleDelete.setdefault +- attributes: [] + class: google.cloud.storage.bucket.LifecycleRuleDelete + fullName: google.cloud.storage.bucket.LifecycleRuleDelete.update + langs: + - python + module: google.cloud.storage.bucket + name: update + source: + id: update + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'If E is present and has a .keys() method, then does: for k in E: D[k] + = E[k] + + If E is present and lacks a .keys() method, then does: for k, v in E: D[k] = + v + + In either case, this is followed by: for k in F: D[k] = F[k] + + + ' + syntax: + content: update([E, ]**F) + type: method + uid: google.cloud.storage.bucket.LifecycleRuleDelete.update +- class: google.cloud.storage.bucket.LifecycleRuleDelete + fullName: google.cloud.storage.bucket.LifecycleRuleDelete.values + langs: + - python + module: google.cloud.storage.bucket + name: values + source: + id: values + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: API documentation for `storage.bucket.LifecycleRuleDelete.values` method. + syntax: + content: values() + type: method + uid: google.cloud.storage.bucket.LifecycleRuleDelete.values +references: +- fullName: google.cloud.storage.bucket.LifecycleRuleDelete.clear + isExternal: false + name: clear + parent: google.cloud.storage.bucket.LifecycleRuleDelete + uid: google.cloud.storage.bucket.LifecycleRuleDelete.clear +- fullName: google.cloud.storage.bucket.LifecycleRuleDelete.copy + isExternal: false + name: copy + parent: google.cloud.storage.bucket.LifecycleRuleDelete + uid: google.cloud.storage.bucket.LifecycleRuleDelete.copy +- fullName: google.cloud.storage.bucket.LifecycleRuleDelete.from_api_repr + isExternal: false + name: from_api_repr + parent: google.cloud.storage.bucket.LifecycleRuleDelete + uid: google.cloud.storage.bucket.LifecycleRuleDelete.from_api_repr +- fullName: google.cloud.storage.bucket.LifecycleRuleDelete.fromkeys + isExternal: false + name: fromkeys + parent: google.cloud.storage.bucket.LifecycleRuleDelete + uid: google.cloud.storage.bucket.LifecycleRuleDelete.fromkeys +- fullName: google.cloud.storage.bucket.LifecycleRuleDelete.get + isExternal: false + name: get + parent: google.cloud.storage.bucket.LifecycleRuleDelete + uid: google.cloud.storage.bucket.LifecycleRuleDelete.get +- fullName: google.cloud.storage.bucket.LifecycleRuleDelete.items + isExternal: false + name: items + parent: google.cloud.storage.bucket.LifecycleRuleDelete + uid: google.cloud.storage.bucket.LifecycleRuleDelete.items +- fullName: google.cloud.storage.bucket.LifecycleRuleDelete.keys + isExternal: false + name: keys + parent: google.cloud.storage.bucket.LifecycleRuleDelete + uid: google.cloud.storage.bucket.LifecycleRuleDelete.keys +- fullName: google.cloud.storage.bucket.LifecycleRuleDelete.pop + isExternal: false + name: pop + parent: google.cloud.storage.bucket.LifecycleRuleDelete + uid: google.cloud.storage.bucket.LifecycleRuleDelete.pop +- fullName: google.cloud.storage.bucket.LifecycleRuleDelete.popitem + isExternal: false + name: popitem + parent: google.cloud.storage.bucket.LifecycleRuleDelete + uid: google.cloud.storage.bucket.LifecycleRuleDelete.popitem +- fullName: google.cloud.storage.bucket.LifecycleRuleDelete.setdefault + isExternal: false + name: setdefault + parent: google.cloud.storage.bucket.LifecycleRuleDelete + uid: google.cloud.storage.bucket.LifecycleRuleDelete.setdefault +- fullName: google.cloud.storage.bucket.LifecycleRuleDelete.update + isExternal: false + name: update + parent: google.cloud.storage.bucket.LifecycleRuleDelete + uid: google.cloud.storage.bucket.LifecycleRuleDelete.update +- fullName: google.cloud.storage.bucket.LifecycleRuleDelete.values + isExternal: false + name: values + parent: google.cloud.storage.bucket.LifecycleRuleDelete + uid: google.cloud.storage.bucket.LifecycleRuleDelete.values diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.bucket.LifecycleRuleSetStorageClass.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.bucket.LifecycleRuleSetStorageClass.yml new file mode 100644 index 000000000000..35d01ea100d4 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.bucket.LifecycleRuleSetStorageClass.yml @@ -0,0 +1,393 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: [] + children: + - google.cloud.storage.bucket.LifecycleRuleSetStorageClass.clear + - google.cloud.storage.bucket.LifecycleRuleSetStorageClass.copy + - google.cloud.storage.bucket.LifecycleRuleSetStorageClass.from_api_repr + - google.cloud.storage.bucket.LifecycleRuleSetStorageClass.fromkeys + - google.cloud.storage.bucket.LifecycleRuleSetStorageClass.get + - google.cloud.storage.bucket.LifecycleRuleSetStorageClass.items + - google.cloud.storage.bucket.LifecycleRuleSetStorageClass.keys + - google.cloud.storage.bucket.LifecycleRuleSetStorageClass.pop + - google.cloud.storage.bucket.LifecycleRuleSetStorageClass.popitem + - google.cloud.storage.bucket.LifecycleRuleSetStorageClass.setdefault + - google.cloud.storage.bucket.LifecycleRuleSetStorageClass.update + - google.cloud.storage.bucket.LifecycleRuleSetStorageClass.values + class: google.cloud.storage.bucket.LifecycleRuleSetStorageClass + fullName: google.cloud.storage.bucket.LifecycleRuleSetStorageClass + inheritance: + - inheritance: + - type: builtins.object + type: builtins.dict + langs: + - python + module: google.cloud.storage.bucket + name: LifecycleRuleSetStorageClass + source: + id: LifecycleRuleSetStorageClass + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 369 + summary: 'Map a lifecycle rule updating storage class of matching items. + + ' + syntax: + content: LifecycleRuleSetStorageClass(storage_class, **kw) + parameters: + - description: new storage class to assign to matching items. + id: storage_class + var_type: str, one of Bucket.STORAGE_CLASSES. + type: class + uid: google.cloud.storage.bucket.LifecycleRuleSetStorageClass +- class: google.cloud.storage.bucket.LifecycleRuleSetStorageClass + fullName: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.clear + langs: + - python + module: google.cloud.storage.bucket + name: clear + source: + id: clear + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: API documentation for `storage.bucket.LifecycleRuleSetStorageClass.clear` + method. + syntax: + content: clear() + type: method + uid: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.clear +- class: google.cloud.storage.bucket.LifecycleRuleSetStorageClass + fullName: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.copy + langs: + - python + module: google.cloud.storage.bucket + name: copy + source: + id: copy + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: API documentation for `storage.bucket.LifecycleRuleSetStorageClass.copy` + method. + syntax: + content: copy() + type: method + uid: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.copy +- attributes: [] + class: google.cloud.storage.bucket.LifecycleRuleSetStorageClass + fullName: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.from_api_repr + langs: + - python + module: google.cloud.storage.bucket + name: from_api_repr + source: + id: from_api_repr + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 387 + summary: 'Factory: construct instance from resource. + + ' + syntax: + content: from_api_repr(resource) + parameters: + - description: mapping as returned from API call. + id: resource + var_type: dict + returns: + - description: Instance created from resource. + var_type: LifecycleRuleSetStorageClass + type: method + uid: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.from_api_repr +- attributes: [] + class: google.cloud.storage.bucket.LifecycleRuleSetStorageClass + fullName: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.fromkeys + langs: + - python + module: google.cloud.storage.bucket + name: fromkeys + source: + id: fromkeys + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Create a new dictionary with keys from iterable and values set to value. + + + ' + syntax: + content: fromkeys(value=None, /) + parameters: [] + type: method + uid: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.fromkeys +- attributes: [] + class: google.cloud.storage.bucket.LifecycleRuleSetStorageClass + fullName: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.get + langs: + - python + module: google.cloud.storage.bucket + name: get + source: + id: get + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Return the value for key if key is in the dictionary, else default. + + + ' + syntax: + content: get(key, default=None, /) + parameters: [] + type: method + uid: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.get +- class: google.cloud.storage.bucket.LifecycleRuleSetStorageClass + fullName: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.items + langs: + - python + module: google.cloud.storage.bucket + name: items + source: + id: items + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: API documentation for `storage.bucket.LifecycleRuleSetStorageClass.items` + method. + syntax: + content: items() + type: method + uid: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.items +- class: google.cloud.storage.bucket.LifecycleRuleSetStorageClass + fullName: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.keys + langs: + - python + module: google.cloud.storage.bucket + name: keys + source: + id: keys + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: API documentation for `storage.bucket.LifecycleRuleSetStorageClass.keys` + method. + syntax: + content: keys() + type: method + uid: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.keys +- attributes: [] + class: google.cloud.storage.bucket.LifecycleRuleSetStorageClass + fullName: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.pop + langs: + - python + module: google.cloud.storage.bucket + name: pop + source: + id: pop + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'If key is not found, default is returned if given, otherwise KeyError + is raised + + + ' + syntax: + content: pop(k[,d]) + type: method + uid: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.pop +- attributes: [] + class: google.cloud.storage.bucket.LifecycleRuleSetStorageClass + fullName: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.popitem + langs: + - python + module: google.cloud.storage.bucket + name: popitem + source: + id: popitem + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Remove and return a (key, value) pair as a 2-tuple. + + + Pairs are returned in LIFO (last-in, first-out) order. + + Raises KeyError if the dict is empty. + + + ' + syntax: + content: popitem() + parameters: [] + type: method + uid: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.popitem +- attributes: [] + class: google.cloud.storage.bucket.LifecycleRuleSetStorageClass + fullName: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.setdefault + langs: + - python + module: google.cloud.storage.bucket + name: setdefault + source: + id: setdefault + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Insert key with a value of default if key is not in the dictionary. + + + Return the value for key if key is in the dictionary, else default. + + + ' + syntax: + content: setdefault(key, default=None, /) + parameters: [] + type: method + uid: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.setdefault +- attributes: [] + class: google.cloud.storage.bucket.LifecycleRuleSetStorageClass + fullName: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.update + langs: + - python + module: google.cloud.storage.bucket + name: update + source: + id: update + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'If E is present and has a .keys() method, then does: for k in E: D[k] + = E[k] + + If E is present and lacks a .keys() method, then does: for k, v in E: D[k] = + v + + In either case, this is followed by: for k in F: D[k] = F[k] + + + ' + syntax: + content: update([E, ]**F) + type: method + uid: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.update +- class: google.cloud.storage.bucket.LifecycleRuleSetStorageClass + fullName: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.values + langs: + - python + module: google.cloud.storage.bucket + name: values + source: + id: values + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: API documentation for `storage.bucket.LifecycleRuleSetStorageClass.values` + method. + syntax: + content: values() + type: method + uid: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.values +references: +- fullName: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.clear + isExternal: false + name: clear + parent: google.cloud.storage.bucket.LifecycleRuleSetStorageClass + uid: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.clear +- fullName: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.copy + isExternal: false + name: copy + parent: google.cloud.storage.bucket.LifecycleRuleSetStorageClass + uid: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.copy +- fullName: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.from_api_repr + isExternal: false + name: from_api_repr + parent: google.cloud.storage.bucket.LifecycleRuleSetStorageClass + uid: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.from_api_repr +- fullName: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.fromkeys + isExternal: false + name: fromkeys + parent: google.cloud.storage.bucket.LifecycleRuleSetStorageClass + uid: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.fromkeys +- fullName: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.get + isExternal: false + name: get + parent: google.cloud.storage.bucket.LifecycleRuleSetStorageClass + uid: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.get +- fullName: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.items + isExternal: false + name: items + parent: google.cloud.storage.bucket.LifecycleRuleSetStorageClass + uid: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.items +- fullName: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.keys + isExternal: false + name: keys + parent: google.cloud.storage.bucket.LifecycleRuleSetStorageClass + uid: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.keys +- fullName: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.pop + isExternal: false + name: pop + parent: google.cloud.storage.bucket.LifecycleRuleSetStorageClass + uid: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.pop +- fullName: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.popitem + isExternal: false + name: popitem + parent: google.cloud.storage.bucket.LifecycleRuleSetStorageClass + uid: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.popitem +- fullName: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.setdefault + isExternal: false + name: setdefault + parent: google.cloud.storage.bucket.LifecycleRuleSetStorageClass + uid: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.setdefault +- fullName: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.update + isExternal: false + name: update + parent: google.cloud.storage.bucket.LifecycleRuleSetStorageClass + uid: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.update +- fullName: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.values + isExternal: false + name: values + parent: google.cloud.storage.bucket.LifecycleRuleSetStorageClass + uid: google.cloud.storage.bucket.LifecycleRuleSetStorageClass.values diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.bucket.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.bucket.yml new file mode 100644 index 000000000000..c4537c62fca2 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.bucket.yml @@ -0,0 +1,62 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: [] + children: + - google.cloud.storage.bucket.Bucket + - google.cloud.storage.bucket.IAMConfiguration + - google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload + - google.cloud.storage.bucket.LifecycleRuleConditions + - google.cloud.storage.bucket.LifecycleRuleDelete + - google.cloud.storage.bucket.LifecycleRuleSetStorageClass + fullName: google.cloud.storage.bucket + langs: + - python + module: google.cloud.storage.bucket + name: bucket + source: + id: bucket + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/bucket.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 0 + summary: 'Create / interact with Google Cloud Storage buckets. + + + ' + syntax: {} + type: module + uid: google.cloud.storage.bucket +references: +- fullName: google.cloud.storage.bucket.Bucket + isExternal: false + name: Bucket + parent: google.cloud.storage.bucket + uid: google.cloud.storage.bucket.Bucket +- fullName: google.cloud.storage.bucket.IAMConfiguration + isExternal: false + name: IAMConfiguration + parent: google.cloud.storage.bucket + uid: google.cloud.storage.bucket.IAMConfiguration +- fullName: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload + isExternal: false + name: LifecycleRuleAbortIncompleteMultipartUpload + parent: google.cloud.storage.bucket + uid: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload +- fullName: google.cloud.storage.bucket.LifecycleRuleConditions + isExternal: false + name: LifecycleRuleConditions + parent: google.cloud.storage.bucket + uid: google.cloud.storage.bucket.LifecycleRuleConditions +- fullName: google.cloud.storage.bucket.LifecycleRuleDelete + isExternal: false + name: LifecycleRuleDelete + parent: google.cloud.storage.bucket + uid: google.cloud.storage.bucket.LifecycleRuleDelete +- fullName: google.cloud.storage.bucket.LifecycleRuleSetStorageClass + isExternal: false + name: LifecycleRuleSetStorageClass + parent: google.cloud.storage.bucket + uid: google.cloud.storage.bucket.LifecycleRuleSetStorageClass diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.client.Client.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.client.Client.yml new file mode 100644 index 000000000000..50b07a746e61 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.client.Client.yml @@ -0,0 +1,1069 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: [] + children: + - google.cloud.storage.client.Client.SCOPE + - google.cloud.storage.client.Client.batch + - google.cloud.storage.client.Client.bucket + - google.cloud.storage.client.Client.create_anonymous_client + - google.cloud.storage.client.Client.create_bucket + - google.cloud.storage.client.Client.create_hmac_key + - google.cloud.storage.client.Client.current_batch + - google.cloud.storage.client.Client.download_blob_to_file + - google.cloud.storage.client.Client.generate_signed_post_policy_v4 + - google.cloud.storage.client.Client.get_bucket + - google.cloud.storage.client.Client.get_hmac_key_metadata + - google.cloud.storage.client.Client.get_service_account_email + - google.cloud.storage.client.Client.list_blobs + - google.cloud.storage.client.Client.list_buckets + - google.cloud.storage.client.Client.list_hmac_keys + - google.cloud.storage.client.Client.lookup_bucket + class: google.cloud.storage.client.Client + fullName: google.cloud.storage.client.Client + inheritance: + - inheritance: + - inheritance: + - inheritance: + - type: builtins.object + type: google.cloud.client._ClientFactoryMixin + type: google.cloud.client.Client + - inheritance: + - type: builtins.object + type: google.cloud.client._ClientProjectMixin + type: google.cloud.client.ClientWithProject + langs: + - python + module: google.cloud.storage.client + name: Client + source: + id: Client + path: tests/testdata/handwritten/google/cloud/storage/client.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 66 + summary: 'Client to bundle configuration needed for API requests. + + ' + syntax: + content: Client(project=, credentials=None, _http=None, client_info=None, + client_options=None) + parameters: + - description: the project which the client acts on behalf of. Will be passed + when creating a topic. If not passed, falls back to the default inferred from + the environment. + id: project + var_type: str or None + - description: (Optional) The OAuth2 Credentials to use for this client. If not + passed (and if no _http object is passed), falls back to the + default inferred from the environment. + id: credentials + var_type: google.auth.credentials.Credentials + - description: (Optional) HTTP object to make requests. Can be any object that + defines request() with the same interface as requests.Session.request. + If not passed, an _http object is created that is bound to the + credentials for the current object. This parameter should be + considered private, and could change in the future. + id: _http + var_type: requests.Session + - description: The client info used to send a user-agent string along with API + requests. If None, then default info will be used. Generally, + you only need to set this if you're developing your own library or partner + tool. + id: client_info + var_type: google.api_core.client_info.ClientInfo + - description: (Optional) Client options used to set user options on the client. + API Endpoint should be set through client_options. + id: client_options + var_type: google.api_core.client_options.ClientOptions or dict + type: class + uid: google.cloud.storage.client.Client +- attributes: [] + class: google.cloud.storage.client.Client + fullName: google.cloud.storage.client.Client.SCOPE + langs: + - python + module: google.cloud.storage.client + name: SCOPE + source: + id: SCOPE + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'The scopes required for authenticating as a Cloud Storage consumer. + + + ' + syntax: {} + type: attribute + uid: google.cloud.storage.client.Client.SCOPE +- attributes: [] + class: google.cloud.storage.client.Client + fullName: google.cloud.storage.client.Client.batch + langs: + - python + module: google.cloud.storage.client + name: batch + source: + id: batch + path: tests/testdata/handwritten/google/cloud/storage/client.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 298 + summary: 'Factory constructor for batch object. + + + ' + syntax: + content: batch() + parameters: [] + returns: + - description: The batch object created. + var_type: Batch + type: method + uid: google.cloud.storage.client.Client.batch +- attributes: [] + class: google.cloud.storage.client.Client + fullName: google.cloud.storage.client.Client.bucket + langs: + - python + module: google.cloud.storage.client + name: bucket + source: + id: bucket + path: tests/testdata/handwritten/google/cloud/storage/client.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 279 + summary: 'Factory constructor for bucket object. + + + ' + syntax: + content: bucket(bucket_name, user_project=None) + parameters: + - description: The name of the bucket to be instantiated. + id: bucket_name + var_type: str + - description: (Optional) The project ID to be billed for API requests made via + the bucket. + id: user_project + var_type: str + returns: + - description: The bucket object created. + var_type: Bucket + type: method + uid: google.cloud.storage.client.Client.bucket +- attributes: [] + class: google.cloud.storage.client.Client + fullName: google.cloud.storage.client.Client.create_anonymous_client + langs: + - python + module: google.cloud.storage.client + name: create_anonymous_client + source: + id: create_anonymous_client + path: tests/testdata/handwritten/google/cloud/storage/client.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 174 + summary: 'Factory: return client with anonymous credentials. + + + ' + syntax: + content: create_anonymous_client() + parameters: [] + returns: + - description: Instance w/ anonymous credentials and no project. + var_type: Client + type: method + uid: google.cloud.storage.client.Client.create_anonymous_client +- attributes: [] + class: google.cloud.storage.client.Client + fullName: google.cloud.storage.client.Client.create_bucket + langs: + - python + module: google.cloud.storage.client + name: create_bucket + source: + id: create_bucket + path: tests/testdata/handwritten/google/cloud/storage/client.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 817 + summary: 'Create a new bucket via a POST request. + + + See [API reference docs](https://cloud.google.com/storage/docs/json_api/v1/buckets/insert) + and a [code sample](https://cloud.google.com/storage/docs/samples/storage-create-bucket#storage_create_bucket-python). + + ' + syntax: + content: create_bucket(bucket_or_name, requester_pays=None, project=None, user_project=None, + location=None, data_locations=None, predefined_acl=None, predefined_default_object_acl=None, + timeout=60, retry=) + exceptions: + - description: If the bucket already exists. + var_type: google.cloud.exceptions.Conflict + parameters: + - description: The bucket resource to pass or name to create. + id: bucket_or_name + var_type: Union[ Bucket, + str, ] + - description: DEPRECATED. Use Bucket().requester_pays instead. (Optional) Whether + requester pays for API requests for this bucket and its blobs. + id: requester_pays + var_type: bool + - description: (Optional) The project under which the bucket is to be created. + If not passed, uses the project set on the client. + id: project + var_type: str + - description: (Optional) The project ID to be billed for API requests made via + created bucket. + id: user_project + var_type: str + - description: '(Optional) The location of the bucket. If not passed, the default + location, US, will be used. If specifying a dual-region, data_locations + should be set in conjunction. See: https://cloud.google.com/storage/docs/locations' + id: location + var_type: str + - description: '(Optional) The list of regional locations of a custom dual-region + bucket. Dual-regions require exactly 2 regional locations. See: https://cloud.google.com/storage/docs/locations' + id: data_locations + var_type: list of str + - description: '(Optional) Name of predefined ACL to apply to bucket. See: https://cloud.google.com/storage/docs/access-control/lists#predefined-acl' + id: predefined_acl + var_type: str + - description: '(Optional) Name of predefined ACL to apply to bucket''s objects. + See: https://cloud.google.com/storage/docs/access-control/lists#predefined-acl' + id: predefined_default_object_acl + var_type: str + - description: The amount of time, in seconds, to wait for the server response. + Can also be passed as a tuple (connect_timeout, read_timeout). See requests.Session.request + documentation for details. + id: timeout + var_type: Optional[Union[float, Tuple[float, float]]] + - description: How to retry the RPC. A None value will disable retries. A google.api_core.retry.Retry + value will enable retries, and the object will define retriable response codes + and errors and configure backoff and timeout options. A google.cloud.storage.retry.ConditionalRetryPolicy + value wraps a Retry object and activates it only if certain conditions are + met. This class exists to provide safe defaults for RPC calls that are not + technically safe to retry normally (due to potential data duplication or other + side-effects) but become safe to retry if a condition such as if_metageneration_match + is set. See the retry.py source code and docstrings in this package (google.cloud.storage.retry) for information + on retry types and how to configure them. + id: retry + var_type: Optional[Union[google.api_core.retry.Retry, google.cloud.storage.retry.ConditionalRetryPolicy]] + type: method + uid: google.cloud.storage.client.Client.create_bucket +- attributes: [] + class: google.cloud.storage.client.Client + fullName: google.cloud.storage.client.Client.create_hmac_key + langs: + - python + module: google.cloud.storage.client + name: create_hmac_key + source: + id: create_hmac_key + path: tests/testdata/handwritten/google/cloud/storage/client.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 1360 + summary: 'Create an HMAC key for a service account. + + ' + syntax: + content: "create_hmac_key(\n service_account_email, project_id=None, user_project=None,\ + \ timeout=60, retry=None\n)" + parameters: + - description: e-mail address of the service account + id: service_account_email + var_type: str + - description: (Optional) Explicit project ID for the key. Defaults to the client's + project. + id: project_id + var_type: str + - description: (Optional) This parameter is currently ignored. + id: user_project + var_type: str + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: (Optional) How to retry the RPC. A None value will disable retries. + A google.api_core.retry.Retry value will enable retries, and the object will + define retriable response codes and errors and configure backoff and timeout + options. A google.cloud.storage.retry.ConditionalRetryPolicy + value wraps a Retry object and activates it only if certain conditions are + met. This class exists to provide safe defaults for RPC calls that are not + technically safe to retry normally (due to potential data duplication or other + side-effects) but become safe to retry if a condition such as if_metageneration_match + is set. See the retry.py source code and docstrings in this package (google.cloud.storage.retry) for information + on retry types and how to configure them. + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + returns: + - description: metadata for the created key, plus the bytes of the key's secret, + which is an 40-character base64-encoded string. + var_type: Tuple[HMACKeyMetadata, + str] + type: method + uid: google.cloud.storage.client.Client.create_hmac_key +- &id001 + attributes: [] + class: google.cloud.storage.client.Client + fullName: google.cloud.storage.client.Client.current_batch + langs: + - python + module: google.cloud.storage.client + name: current_batch + source: + id: current_batch + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Currently-active batch. + + ' + syntax: + returns: + - description: The batch at the top of the batch stack. + var_type: Batch or NoneType + (if no batch is active). + type: property + uid: google.cloud.storage.client.Client.current_batch +- *id001 +- attributes: [] + class: google.cloud.storage.client.Client + fullName: google.cloud.storage.client.Client.download_blob_to_file + langs: + - python + module: google.cloud.storage.client + name: download_blob_to_file + source: + id: download_blob_to_file + path: tests/testdata/handwritten/google/cloud/storage/client.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 953 + summary: 'Download the contents of a blob object or blob URI into a file-like object. + + + See https://cloud.google.com/storage/docs/downloading-objects + + ' + syntax: + content: download_blob_to_file(blob_or_uri, file_obj, start=None, end=None, raw_download=False, + if_etag_match=None, if_etag_not_match=None, if_generation_match=None, if_generation_not_match=None, + if_metageneration_match=None, if_metageneration_not_match=None, timeout=60, + checksum='md5', retry=) + parameters: + - description: The blob resource to pass or URI to download. + id: blob_or_uri + var_type: Union[ Blob, str, + ] + - description: A file handle to which to write the blob's data. + id: file_obj + var_type: file + - description: (Optional) The first byte in a range to be downloaded. + id: start + var_type: int + - description: (Optional) The last byte in a range to be downloaded. + id: end + var_type: int + - description: (Optional) If true, download the object without any expansion. + id: raw_download + var_type: bool + - description: (Optional) See :ref:using-if-etag-match + id: if_etag_match + var_type: Union[str, Set[str]] + - description: (Optional) See :ref:using-if-etag-not-match + id: if_etag_not_match + var_type: Union[str, Set[str]] + - description: (Optional) See :ref:using-if-generation-match + id: if_generation_match + var_type: long + - description: (Optional) See :ref:using-if-generation-not-match + id: if_generation_not_match + var_type: long + - description: (Optional) See :ref:using-if-metageneration-match + id: if_metageneration_match + var_type: long + - description: (Optional) See :ref:using-if-metageneration-not-match + id: if_metageneration_not_match + var_type: long + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: '[Union[float, Tuple[float, float]]]' + - description: (Optional) The type of checksum to compute to verify the integrity + of the object. The response headers must contain a checksum of the requested + type. If the headers lack an appropriate checksum (for instance in the case + of transcoded or ranged downloads where the remote service does not know the + correct checksum, including downloads where chunk_size is set) an INFO-level + log will be emitted. Supported values are "md5", "crc32c" and None. The default + is "md5". + id: checksum + var_type: str + - description: (Optional) How to retry the RPC. A None value will disable retries. + A google.api_core.retry.Retry value will enable retries, and the object will + define retriable response codes and errors and configure backoff and timeout + options. A google.cloud.storage.retry.ConditionalRetryPolicy + value wraps a Retry object and activates it only if certain conditions are + met. This class exists to provide safe defaults for RPC calls that are not + technically safe to retry normally (due to potential data duplication or other + side-effects) but become safe to retry if a condition such as if_metageneration_match + is set. See the retry.py source code and docstrings in this package (google.cloud.storage.retry) for information + on retry types and how to configure them. Media operations (downloads and + uploads) do not support non-default predicates in a Retry object. The default + will always be used. Other configuration changes for Retry objects such as + delays and deadlines are respected. + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + type: method + uid: google.cloud.storage.client.Client.download_blob_to_file +- attributes: [] + class: google.cloud.storage.client.Client + fullName: google.cloud.storage.client.Client.generate_signed_post_policy_v4 + langs: + - python + module: google.cloud.storage.client + name: generate_signed_post_policy_v4 + source: + id: generate_signed_post_policy_v4 + path: tests/testdata/handwritten/google/cloud/storage/client.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 1517 + summary: 'Generate a V4 signed policy object. Generated policy object allows user + to upload objects with a POST request. + + + ' + syntax: + content: "generate_signed_post_policy_v4(\n bucket_name,\n blob_name,\n\ + \ expiration,\n conditions=None,\n fields=None,\n credentials=None,\n\ + \ virtual_hosted_style=False,\n bucket_bound_hostname=None,\n scheme=\"\ + http\",\n service_account_email=None,\n access_token=None,\n)" + parameters: + - description: Bucket name. + id: bucket_name + var_type: str + - description: Object name. + id: blob_name + var_type: str + - description: Policy expiration time. If a datetime instance is + passed without an explicit tzinfo set, it will be assumed to + be UTC. + id: expiration + var_type: Union[Integer, datetime.datetime, datetime.timedelta] + - description: (Optional) List of POST policy conditions, which are used to restrict + what is allowed in the request. + id: conditions + var_type: list + - description: (Optional) Additional elements to include into request. + id: fields + var_type: dict + - description: (Optional) Credentials object with an associated private key to + sign text. + id: credentials + var_type: google.auth.credentials.Signing + - description: (Optional) If True, construct the URL relative to the bucket virtual + hostname, e.g., '.storage.googleapis.com'. + id: virtual_hosted_style + var_type: bool + - description: '(Optional) If passed, construct the URL relative to the bucket-bound + hostname. Value can be bare or with a scheme, e.g., ''example.com'' or ''http://example.com''. + See: https://cloud.google.com/storage/docs/request-endpoints#cname' + id: bucket_bound_hostname + var_type: str + - description: (Optional) If bucket_bound_hostname is passed as a + bare hostname, use this value as a scheme. https will work only + when using a CDN. Defaults to "http". + id: scheme + var_type: str + - description: (Optional) E-mail address of the service account. + id: service_account_email + var_type: str + - description: (Optional) Access token for a service account. + id: access_token + var_type: str + returns: + - description: Signed POST policy. + var_type: dict + type: method + uid: google.cloud.storage.client.Client.generate_signed_post_policy_v4 +- attributes: [] + class: google.cloud.storage.client.Client + fullName: google.cloud.storage.client.Client.get_bucket + langs: + - python + module: google.cloud.storage.client + name: get_bucket + source: + id: get_bucket + path: tests/testdata/handwritten/google/cloud/storage/client.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 705 + summary: 'Retrieve a bucket via a GET request. + + + See [API reference docs](https://cloud.google.com/storage/docs/json_api/v1/buckets/get) + and a [code sample](https://cloud.google.com/storage/docs/samples/storage-get-bucket-metadata#storage_get_bucket_metadata-python). + + ' + syntax: + content: get_bucket(bucket_or_name, timeout=60, if_metageneration_match=None, + if_metageneration_not_match=None, retry=) + exceptions: + - description: If the bucket is not found. + var_type: google.cloud.exceptions.NotFound + parameters: + - description: The bucket resource to pass or name to create. + id: bucket_or_name + var_type: Union[ Bucket, + str, ] + - description: The amount of time, in seconds, to wait for the server response. + Can also be passed as a tuple (connect_timeout, read_timeout). See requests.Session.request + documentation for details. + id: timeout + var_type: Optional[Union[float, Tuple[float, float]]] + - description: Make the operation conditional on whether the blob's current metageneration + matches the given value. + id: if_metageneration_match + var_type: Optional[long] + - description: Make the operation conditional on whether the blob's current metageneration + does not match the given value. + id: if_metageneration_not_match + var_type: Optional[long] + - description: How to retry the RPC. A None value will disable retries. A google.api_core.retry.Retry + value will enable retries, and the object will define retriable response codes + and errors and configure backoff and timeout options. A google.cloud.storage.retry.ConditionalRetryPolicy + value wraps a Retry object and activates it only if certain conditions are + met. This class exists to provide safe defaults for RPC calls that are not + technically safe to retry normally (due to potential data duplication or other + side-effects) but become safe to retry if a condition such as if_metageneration_match + is set. See the retry.py source code and docstrings in this package (google.cloud.storage.retry) for information + on retry types and how to configure them. + id: retry + var_type: Optional[Union[google.api_core.retry.Retry, google.cloud.storage.retry.ConditionalRetryPolicy]] + type: method + uid: google.cloud.storage.client.Client.get_bucket +- attributes: [] + class: google.cloud.storage.client.Client + fullName: google.cloud.storage.client.Client.get_hmac_key_metadata + langs: + - python + module: google.cloud.storage.client + name: get_hmac_key_metadata + source: + id: get_hmac_key_metadata + path: tests/testdata/handwritten/google/cloud/storage/client.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 1493 + summary: 'Return a metadata instance for the given HMAC key. + + ' + syntax: + content: get_hmac_key_metadata(access_id, project_id=None, user_project=None, + timeout=60) + parameters: + - description: Unique ID of an existing key. + id: access_id + var_type: str + - description: (Optional) Project ID of an existing key. Defaults to client's + project. + id: project_id + var_type: str + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: (Optional) This parameter is currently ignored. + id: user_project + var_type: str + type: method + uid: google.cloud.storage.client.Client.get_hmac_key_metadata +- attributes: [] + class: google.cloud.storage.client.Client + fullName: google.cloud.storage.client.Client.get_service_account_email + langs: + - python + module: google.cloud.storage.client + name: get_service_account_email + source: + id: get_service_account_email + path: tests/testdata/handwritten/google/cloud/storage/client.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 251 + summary: 'Get the email address of the project''s GCS service account + + ' + syntax: + content: get_service_account_email(project=None, timeout=60, retry=) + parameters: + - description: (Optional) Project ID to use for retreiving GCS service account + email address. Defaults to the client's project. + id: project + var_type: str + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: '(Optional) How to retry the RPC. See: configuring_retries' + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + returns: + - description: service account email address + var_type: str + type: method + uid: google.cloud.storage.client.Client.get_service_account_email +- attributes: [] + class: google.cloud.storage.client.Client + fullName: google.cloud.storage.client.Client.list_blobs + langs: + - python + module: google.cloud.storage.client + name: list_blobs + source: + id: list_blobs + path: tests/testdata/handwritten/google/cloud/storage/client.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 1094 + summary: 'Return an iterator used to find blobs in the bucket. + + + If `user_project` is set, bills the API request to that project. + + + ' + syntax: + content: list_blobs(bucket_or_name, max_results=None, page_token=None, prefix=None, + delimiter=None, start_offset=None, end_offset=None, include_trailing_delimiter=None, + versions=None, projection='noAcl', fields=None, page_size=None, timeout=60, + retry=) + parameters: + - description: The bucket resource to pass or name to create. + id: bucket_or_name + var_type: Union[ Bucket, + str, ] + - description: (Optional) The maximum number of blobs to return. + id: max_results + var_type: int + - description: '(Optional) If present, return the next batch of blobs, using the + value, which must correspond to the nextPageToken value returned + in the previous response. Deprecated: use the pages property + of the returned iterator instead of manually passing the token.' + id: page_token + var_type: str + - description: (Optional) Prefix used to filter blobs. + id: prefix + var_type: str + - description: (Optional) Delimiter, used with prefix to emulate + hierarchy. + id: delimiter + var_type: str + - description: (Optional) Filter results to objects whose names are lexicographically + equal to or after startOffset. If endOffset is also + set, the objects listed will have names between startOffset (inclusive) + and endOffset (exclusive). + id: start_offset + var_type: str + - description: (Optional) Filter results to objects whose names are lexicographically + before endOffset. If startOffset is also set, the + objects listed will have names between startOffset (inclusive) + and endOffset (exclusive). + id: end_offset + var_type: str + - description: (Optional) If true, objects that end in exactly one instance of + delimiter will have their metadata included in items + in addition to prefixes. + id: include_trailing_delimiter + var_type: boolean + - description: (Optional) Whether object versions should be returned as separate + blobs. + id: versions + var_type: bool + - description: (Optional) If used, must be 'full' or 'noAcl'. Defaults to 'noAcl'. + Specifies the set of properties to return. + id: projection + var_type: str + - description: '(Optional) Selector specifying which fields to include in a partial + response. Must be a list of fields. For example to get a partial response + with just the next page token and the name and language of each blob returned: + ''items(name,contentLanguage),nextPageToken''. See: https://cloud.google.com/storage/docs/json_api/v1/parameters#fields' + id: fields + var_type: str + - description: (Optional) Maximum number of blobs to return in each page. Defaults + to a value set by the API. + id: page_size + var_type: int + - description: The amount of time, in seconds, to wait for the server response. + Can also be passed as a tuple (connect_timeout, read_timeout). See requests.Session.request + documentation for details. + id: timeout + var_type: Optional[Union[float, Tuple[float, float]]] + - description: How to retry the RPC. A None value will disable retries. A google.api_core.retry.Retry + value will enable retries, and the object will define retriable response codes + and errors and configure backoff and timeout options. A google.cloud.storage.retry.ConditionalRetryPolicy + value wraps a Retry object and activates it only if certain conditions are + met. This class exists to provide safe defaults for RPC calls that are not + technically safe to retry normally (due to potential data duplication or other + side-effects) but become safe to retry if a condition such as if_metageneration_match + is set. See the retry.py source code and docstrings in this package (google.cloud.storage.retry) for information + on retry types and how to configure them. + id: retry + var_type: Optional[Union[google.api_core.retry.Retry, google.cloud.storage.retry.ConditionalRetryPolicy]] + type: method + uid: google.cloud.storage.client.Client.list_blobs +- attributes: [] + class: google.cloud.storage.client.Client + fullName: google.cloud.storage.client.Client.list_buckets + langs: + - python + module: google.cloud.storage.client + name: list_buckets + source: + id: list_buckets + path: tests/testdata/handwritten/google/cloud/storage/client.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 1255 + summary: 'Get all buckets in the project associated to the client. + + + This will not populate the list of blobs available in each + + bucket. + + + See [API reference docs](https://cloud.google.com/storage/docs/json_api/v1/buckets/list) + and a [code sample](https://cloud.google.com/storage/docs/samples/storage-list-buckets#storage_list_buckets-python). + + ' + syntax: + content: list_buckets(max_results=None, page_token=None, prefix=None, projection='noAcl', + fields=None, project=None, page_size=None, timeout=60, retry=) + exceptions: + - description: if both project is None and the client's + project is also None. + var_type: ValueError + parameters: + - description: (Optional) The maximum number of buckets to return. + id: max_results + var_type: int + - description: '(Optional) If present, return the next batch of buckets, using + the value, which must correspond to the nextPageToken value returned + in the previous response. Deprecated: use the pages property + of the returned iterator instead of manually passing the token.' + id: page_token + var_type: str + - description: (Optional) Filter results to buckets whose names begin with this + prefix. + id: prefix + var_type: str + - description: (Optional) Specifies the set of properties to return. If used, + must be 'full' or 'noAcl'. Defaults to 'noAcl'. + id: projection + var_type: str + - description: '(Optional) Selector specifying which fields to include in a partial + response. Must be a list of fields. For example to get a partial response + with just the next page token and the language of each bucket returned: ''items/id,nextPageToken''' + id: fields + var_type: str + - description: (Optional) The project whose buckets are to be listed. If not passed, + uses the project set on the client. + id: project + var_type: str + - description: (Optional) Maximum number of buckets to return in each page. Defaults + to a value set by the API. + id: page_size + var_type: int + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: '(Optional) How to retry the RPC. See: configuring_retries' + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + returns: + - description: Iterator of all Bucket + belonging to this project. + var_type: google.api_core.page_iterator.Iterator + type: method + uid: google.cloud.storage.client.Client.list_buckets +- attributes: [] + class: google.cloud.storage.client.Client + fullName: google.cloud.storage.client.Client.list_hmac_keys + langs: + - python + module: google.cloud.storage.client + name: list_hmac_keys + source: + id: list_hmac_keys + path: tests/testdata/handwritten/google/cloud/storage/client.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 1424 + summary: 'List HMAC keys for a project. + + ' + syntax: + content: list_hmac_keys(max_results=None, service_account_email=None, show_deleted_keys=None, + project_id=None, user_project=None, timeout=60, retry=) + parameters: + - description: (Optional) Max number of keys to return in a given page. + id: max_results + var_type: int + - description: (Optional) Limit keys to those created by the given service account. + id: service_account_email + var_type: str + - description: (Optional) Included deleted keys in the list. Default is to exclude + them. + id: show_deleted_keys + var_type: bool + - description: (Optional) Explicit project ID for the key. Defaults to the client's + project. + id: project_id + var_type: str + - description: (Optional) This parameter is currently ignored. + id: user_project + var_type: str + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: '(Optional) How to retry the RPC. See: configuring_retries' + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + returns: + - description: metadata for the created key, plus the bytes of the key's secret, + which is an 40-character base64-encoded string. + var_type: Tuple[HMACKeyMetadata, + str] + type: method + uid: google.cloud.storage.client.Client.list_hmac_keys +- attributes: [] + class: google.cloud.storage.client.Client + fullName: google.cloud.storage.client.Client.lookup_bucket + langs: + - python + module: google.cloud.storage.client + name: lookup_bucket + source: + id: lookup_bucket + path: tests/testdata/handwritten/google/cloud/storage/client.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 770 + summary: 'Get a bucket by name, returning None if not found. + + + You can use this if you would rather check for a None value + + than catching a NotFound exception. + + ' + syntax: + content: lookup_bucket(bucket_name, timeout=60, if_metageneration_match=None, + if_metageneration_not_match=None, retry=) + parameters: + - description: The name of the bucket to get. + id: bucket_name + var_type: str + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: (Optional) Make the operation conditional on whether the blob's + current metageneration matches the given value. + id: if_metageneration_match + var_type: long + - description: (Optional) Make the operation conditional on whether the blob's + current metageneration does not match the given value. + id: if_metageneration_not_match + var_type: long + - description: '(Optional) How to retry the RPC. See: configuring_retries' + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + returns: + - description: The bucket matching the name provided or None if not found. + var_type: Bucket or NoneType + type: method + uid: google.cloud.storage.client.Client.lookup_bucket +references: +- fullName: google.cloud.storage.client.Client.SCOPE + isExternal: false + name: SCOPE + parent: google.cloud.storage.client.Client + uid: google.cloud.storage.client.Client.SCOPE +- fullName: google.cloud.storage.client.Client.batch + isExternal: false + name: batch + parent: google.cloud.storage.client.Client + uid: google.cloud.storage.client.Client.batch +- fullName: google.cloud.storage.client.Client.bucket + isExternal: false + name: bucket + parent: google.cloud.storage.client.Client + uid: google.cloud.storage.client.Client.bucket +- fullName: google.cloud.storage.client.Client.create_anonymous_client + isExternal: false + name: create_anonymous_client + parent: google.cloud.storage.client.Client + uid: google.cloud.storage.client.Client.create_anonymous_client +- fullName: google.cloud.storage.client.Client.create_bucket + isExternal: false + name: create_bucket + parent: google.cloud.storage.client.Client + uid: google.cloud.storage.client.Client.create_bucket +- fullName: google.cloud.storage.client.Client.create_hmac_key + isExternal: false + name: create_hmac_key + parent: google.cloud.storage.client.Client + uid: google.cloud.storage.client.Client.create_hmac_key +- fullName: google.cloud.storage.client.Client.current_batch + isExternal: false + name: current_batch + parent: google.cloud.storage.client.Client + uid: google.cloud.storage.client.Client.current_batch +- fullName: google.cloud.storage.client.Client.download_blob_to_file + isExternal: false + name: download_blob_to_file + parent: google.cloud.storage.client.Client + uid: google.cloud.storage.client.Client.download_blob_to_file +- fullName: google.cloud.storage.client.Client.generate_signed_post_policy_v4 + isExternal: false + name: generate_signed_post_policy_v4 + parent: google.cloud.storage.client.Client + uid: google.cloud.storage.client.Client.generate_signed_post_policy_v4 +- fullName: google.cloud.storage.client.Client.get_bucket + isExternal: false + name: get_bucket + parent: google.cloud.storage.client.Client + uid: google.cloud.storage.client.Client.get_bucket +- fullName: google.cloud.storage.client.Client.get_hmac_key_metadata + isExternal: false + name: get_hmac_key_metadata + parent: google.cloud.storage.client.Client + uid: google.cloud.storage.client.Client.get_hmac_key_metadata +- fullName: google.cloud.storage.client.Client.get_service_account_email + isExternal: false + name: get_service_account_email + parent: google.cloud.storage.client.Client + uid: google.cloud.storage.client.Client.get_service_account_email +- fullName: google.cloud.storage.client.Client.list_blobs + isExternal: false + name: list_blobs + parent: google.cloud.storage.client.Client + uid: google.cloud.storage.client.Client.list_blobs +- fullName: google.cloud.storage.client.Client.list_buckets + isExternal: false + name: list_buckets + parent: google.cloud.storage.client.Client + uid: google.cloud.storage.client.Client.list_buckets +- fullName: google.cloud.storage.client.Client.list_hmac_keys + isExternal: false + name: list_hmac_keys + parent: google.cloud.storage.client.Client + uid: google.cloud.storage.client.Client.list_hmac_keys +- fullName: google.cloud.storage.client.Client.lookup_bucket + isExternal: false + name: lookup_bucket + parent: google.cloud.storage.client.Client + uid: google.cloud.storage.client.Client.lookup_bucket diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.client.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.client.yml new file mode 100644 index 000000000000..8a57d4653a90 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.client.yml @@ -0,0 +1,32 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: [] + children: + - google.cloud.storage.client.Client + fullName: google.cloud.storage.client + langs: + - python + module: google.cloud.storage.client + name: client + source: + id: client + path: tests/testdata/handwritten/google/cloud/storage/client.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/client.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 0 + summary: 'Client for interacting with the Google Cloud Storage API. + + + ' + syntax: {} + type: module + uid: google.cloud.storage.client +references: +- fullName: google.cloud.storage.client.Client + isExternal: false + name: Client + parent: google.cloud.storage.client + uid: google.cloud.storage.client.Client diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.constants.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.constants.yml new file mode 100644 index 000000000000..999e24cba0f0 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.constants.yml @@ -0,0 +1,26 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: [] + children: [] + fullName: google.cloud.storage.constants + langs: + - python + module: google.cloud.storage.constants + name: constants + source: + id: constants + path: tests/testdata/handwritten/google/cloud/storage/constants.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/constants.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 0 + summary: 'Constants used across google.cloud.storage modules. + + + ' + syntax: {} + type: module + uid: google.cloud.storage.constants +references: [] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.fileio.BlobReader.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.fileio.BlobReader.yml new file mode 100644 index 000000000000..85533673397d --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.fileio.BlobReader.yml @@ -0,0 +1,330 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: [] + children: + - google.cloud.storage.fileio.BlobReader.close + - google.cloud.storage.fileio.BlobReader.read + - google.cloud.storage.fileio.BlobReader.read1 + - google.cloud.storage.fileio.BlobReader.readable + - google.cloud.storage.fileio.BlobReader.seek + - google.cloud.storage.fileio.BlobReader.seekable + - google.cloud.storage.fileio.BlobReader.writable + class: google.cloud.storage.fileio.BlobReader + fullName: google.cloud.storage.fileio.BlobReader + inheritance: + - inheritance: + - inheritance: + - inheritance: + - type: builtins.object + type: _io._IOBase + type: _io._BufferedIOBase + - inheritance: + - inheritance: + - type: builtins.object + type: _io._IOBase + type: io.IOBase + type: io.BufferedIOBase + langs: + - python + module: google.cloud.storage.fileio + name: BlobReader + source: + id: BlobReader + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 59 + summary: 'A file-like object that reads from a blob. + + ' + syntax: + content: BlobReader(blob, chunk_size=None, retry=, **download_kwargs) + parameters: + - description: The blob to download. + id: blob + var_type: '''google.cloud.storage.blob.Blob''' + - description: (Optional) The minimum number of bytes to read at a time. If fewer + bytes than the chunk_size are requested, the remainder is buffered. The default + is the chunk_size of the blob, or 40MiB. + id: chunk_size + var_type: long + - description: (Optional) How to retry the RPC. A None value will disable retries. + A google.api_core.retry.Retry value will enable retries, and the object will + define retriable response codes and errors and configure backoff and timeout + options. A google.cloud.storage.retry.ConditionalRetryPolicy + value wraps a Retry object and activates it only if certain conditions are + met. This class exists to provide safe defaults for RPC calls that are not + technically safe to retry normally (due to potential data duplication or other + side-effects) but become safe to retry if a condition such as if_metageneration_match + is set. See the retry.py source code and docstrings in this package (google.cloud.storage.retry) for information + on retry types and how to configure them. Media operations (downloads and + uploads) do not support non-default predicates in a Retry object. The default + will always be used. Other configuration changes for Retry objects such as + delays and deadlines are respected. + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + type: class + uid: google.cloud.storage.fileio.BlobReader +- attributes: [] + class: google.cloud.storage.fileio.BlobReader + fullName: google.cloud.storage.fileio.BlobReader.close + langs: + - python + module: google.cloud.storage.fileio + name: close + source: + id: close + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 211 + summary: 'Flush and close the IO object. + + + This method has no effect if the file is already closed. + + + ' + syntax: + content: close() + parameters: [] + type: method + uid: google.cloud.storage.fileio.BlobReader.close +- attributes: [] + class: google.cloud.storage.fileio.BlobReader + fullName: google.cloud.storage.fileio.BlobReader.read + langs: + - python + module: google.cloud.storage.fileio + name: read + source: + id: read + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 123 + summary: 'Read and return up to n bytes. + + + If the argument is omitted, None, or negative, reads and + + returns all data until EOF. + + + If the argument is positive, and the underlying raw stream is + + not ''interactive'', multiple raw reads may be issued to satisfy + + the byte count (unless EOF is reached first). But for + + interactive raw streams (as well as sockets and pipes), at most + + one raw read will be issued, and a short result does not imply + + that EOF is imminent. + + + Returns an empty bytes object on EOF. + + + Returns None if the underlying raw stream was open in non-blocking + + mode and no data is available at the moment. + + + ' + syntax: + content: read(size=-1) + parameters: [] + type: method + uid: google.cloud.storage.fileio.BlobReader.read +- attributes: [] + class: google.cloud.storage.fileio.BlobReader + fullName: google.cloud.storage.fileio.BlobReader.read1 + langs: + - python + module: google.cloud.storage.fileio + name: read1 + source: + id: read1 + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 168 + summary: 'Read and return up to n bytes, with at most one read() call + + to the underlying raw stream. A short result does not imply + + that EOF is imminent. + + + Returns an empty bytes object on EOF. + + + ' + syntax: + content: read1(size=-1) + parameters: [] + type: method + uid: google.cloud.storage.fileio.BlobReader.read1 +- attributes: [] + class: google.cloud.storage.fileio.BlobReader + fullName: google.cloud.storage.fileio.BlobReader.readable + langs: + - python + module: google.cloud.storage.fileio + name: readable + source: + id: readable + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 218 + summary: 'Return whether object was opened for reading. + + + If False, read() will raise OSError. + + + ' + syntax: + content: readable() + parameters: [] + type: method + uid: google.cloud.storage.fileio.BlobReader.readable +- attributes: [] + class: google.cloud.storage.fileio.BlobReader + fullName: google.cloud.storage.fileio.BlobReader.seek + langs: + - python + module: google.cloud.storage.fileio + name: seek + source: + id: seek + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 171 + summary: 'Seek within the blob. + + + This implementation of seek() uses knowledge of the blob size to + + validate that the reported position does not exceed the blob last byte. + + If the blob size is not already known it will call blob.reload(). + + + ' + syntax: + content: seek(pos, whence=0) + parameters: [] + type: method + uid: google.cloud.storage.fileio.BlobReader.seek +- attributes: [] + class: google.cloud.storage.fileio.BlobReader + fullName: google.cloud.storage.fileio.BlobReader.seekable + langs: + - python + module: google.cloud.storage.fileio + name: seekable + source: + id: seekable + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 224 + summary: 'Return whether object supports random access. + + + If False, seek(), tell() and truncate() will raise OSError. + + This method may need to do a test seek(). + + + ' + syntax: + content: seekable() + parameters: [] + type: method + uid: google.cloud.storage.fileio.BlobReader.seekable +- attributes: [] + class: google.cloud.storage.fileio.BlobReader + fullName: google.cloud.storage.fileio.BlobReader.writable + langs: + - python + module: google.cloud.storage.fileio + name: writable + source: + id: writable + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 221 + summary: 'Return whether object was opened for writing. + + + If False, write() will raise OSError. + + + ' + syntax: + content: writable() + parameters: [] + type: method + uid: google.cloud.storage.fileio.BlobReader.writable +references: +- fullName: google.cloud.storage.fileio.BlobReader.close + isExternal: false + name: close + parent: google.cloud.storage.fileio.BlobReader + uid: google.cloud.storage.fileio.BlobReader.close +- fullName: google.cloud.storage.fileio.BlobReader.read + isExternal: false + name: read + parent: google.cloud.storage.fileio.BlobReader + uid: google.cloud.storage.fileio.BlobReader.read +- fullName: google.cloud.storage.fileio.BlobReader.read1 + isExternal: false + name: read1 + parent: google.cloud.storage.fileio.BlobReader + uid: google.cloud.storage.fileio.BlobReader.read1 +- fullName: google.cloud.storage.fileio.BlobReader.readable + isExternal: false + name: readable + parent: google.cloud.storage.fileio.BlobReader + uid: google.cloud.storage.fileio.BlobReader.readable +- fullName: google.cloud.storage.fileio.BlobReader.seek + isExternal: false + name: seek + parent: google.cloud.storage.fileio.BlobReader + uid: google.cloud.storage.fileio.BlobReader.seek +- fullName: google.cloud.storage.fileio.BlobReader.seekable + isExternal: false + name: seekable + parent: google.cloud.storage.fileio.BlobReader + uid: google.cloud.storage.fileio.BlobReader.seekable +- fullName: google.cloud.storage.fileio.BlobReader.writable + isExternal: false + name: writable + parent: google.cloud.storage.fileio.BlobReader + uid: google.cloud.storage.fileio.BlobReader.writable diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.fileio.BlobWriter.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.fileio.BlobWriter.yml new file mode 100644 index 000000000000..d3f1b47634d5 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.fileio.BlobWriter.yml @@ -0,0 +1,320 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: [] + children: + - google.cloud.storage.fileio.BlobWriter.close + - google.cloud.storage.fileio.BlobWriter.flush + - google.cloud.storage.fileio.BlobWriter.readable + - google.cloud.storage.fileio.BlobWriter.seekable + - google.cloud.storage.fileio.BlobWriter.tell + - google.cloud.storage.fileio.BlobWriter.writable + - google.cloud.storage.fileio.BlobWriter.write + class: google.cloud.storage.fileio.BlobWriter + fullName: google.cloud.storage.fileio.BlobWriter + inheritance: + - inheritance: + - inheritance: + - inheritance: + - type: builtins.object + type: _io._IOBase + type: _io._BufferedIOBase + - inheritance: + - inheritance: + - type: builtins.object + type: _io._IOBase + type: io.IOBase + type: io.BufferedIOBase + langs: + - python + module: google.cloud.storage.fileio + name: BlobWriter + source: + id: BlobWriter + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 228 + summary: 'A file-like object that writes to a blob. + + ' + syntax: + content: BlobWriter(blob, chunk_size=None, text_mode=False, ignore_flush=False, + retry=, **upload_kwargs) + parameters: + - description: The blob to which to write. + id: blob + var_type: '''google.cloud.storage.blob.Blob''' + - description: (Optional) The maximum number of bytes to buffer before sending + data to the server, and the size of each request when data is sent. Writes + are implemented as a "resumable upload", so chunk_size for writes must be + exactly a multiple of 256KiB as with other resumable uploads. The default + is the chunk_size of the blob, or 40 MiB. + id: chunk_size + var_type: long + - description: (Deprecated) A synonym for ignore_flush. For backwards-compatibility, + if True, sets ignore_flush to True. Use ignore_flush instead. This parameter + will be removed in a future release. + id: text_mode + var_type: bool + - description: Makes flush() do nothing instead of raise an error. flush() without + closing is not supported by the remote service and therefore calling it on + this class normally results in io.UnsupportedOperation. However, that behavior + is incompatible with some consumers and wrappers of file objects in Python, + such as zipfile.ZipFile or io.TextIOWrapper. Setting ignore_flush will cause + flush() to successfully do nothing, for compatibility with those contexts. + The correct way to actually flush data to the remote server is to close() + (using this object as a context manager is recommended). + id: ignore_flush + var_type: bool + - description: (Optional) How to retry the RPC. A None value will disable retries. + A google.api_core.retry.Retry value will enable retries, and the object will + define retriable response codes and errors and configure backoff and timeout + options. A google.cloud.storage.retry.ConditionalRetryPolicy + value wraps a Retry object and activates it only if certain conditions are + met. This class exists to provide safe defaults for RPC calls that are not + technically safe to retry normally (due to potential data duplication or other + side-effects) but become safe to retry if a condition such as if_metageneration_match + is set. See the retry.py source code and docstrings in this package (google.cloud.storage.retry) for information + on retry types and how to configure them. Media operations (downloads and + uploads) do not support non-default predicates in a Retry object. The default + will always be used. Other configuration changes for Retry objects such as + delays and deadlines are respected. + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + type: class + uid: google.cloud.storage.fileio.BlobWriter +- attributes: [] + class: google.cloud.storage.fileio.BlobWriter + fullName: google.cloud.storage.fileio.BlobWriter.close + langs: + - python + module: google.cloud.storage.fileio + name: close + source: + id: close + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 429 + summary: 'Flush and close the IO object. + + + This method has no effect if the file is already closed. + + + ' + syntax: + content: close() + parameters: [] + type: method + uid: google.cloud.storage.fileio.BlobWriter.close +- attributes: [] + class: google.cloud.storage.fileio.BlobWriter + fullName: google.cloud.storage.fileio.BlobWriter.flush + langs: + - python + module: google.cloud.storage.fileio + name: flush + source: + id: flush + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 419 + summary: 'Flush write buffers, if applicable. + + + This is not implemented for read-only and non-blocking streams. + + + ' + syntax: + content: flush() + parameters: [] + type: method + uid: google.cloud.storage.fileio.BlobWriter.flush +- attributes: [] + class: google.cloud.storage.fileio.BlobWriter + fullName: google.cloud.storage.fileio.BlobWriter.readable + langs: + - python + module: google.cloud.storage.fileio + name: readable + source: + id: readable + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 438 + summary: 'Return whether object was opened for reading. + + + If False, read() will raise OSError. + + + ' + syntax: + content: readable() + parameters: [] + type: method + uid: google.cloud.storage.fileio.BlobWriter.readable +- attributes: [] + class: google.cloud.storage.fileio.BlobWriter + fullName: google.cloud.storage.fileio.BlobWriter.seekable + langs: + - python + module: google.cloud.storage.fileio + name: seekable + source: + id: seekable + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 444 + summary: 'Return whether object supports random access. + + + If False, seek(), tell() and truncate() will raise OSError. + + This method may need to do a test seek(). + + + ' + syntax: + content: seekable() + parameters: [] + type: method + uid: google.cloud.storage.fileio.BlobWriter.seekable +- attributes: [] + class: google.cloud.storage.fileio.BlobWriter + fullName: google.cloud.storage.fileio.BlobWriter.tell + langs: + - python + module: google.cloud.storage.fileio + name: tell + source: + id: tell + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 416 + summary: 'Return current stream position. + + + ' + syntax: + content: tell() + parameters: [] + type: method + uid: google.cloud.storage.fileio.BlobWriter.tell +- attributes: [] + class: google.cloud.storage.fileio.BlobWriter + fullName: google.cloud.storage.fileio.BlobWriter.writable + langs: + - python + module: google.cloud.storage.fileio + name: writable + source: + id: writable + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 441 + summary: 'Return whether object was opened for writing. + + + If False, write() will raise OSError. + + + ' + syntax: + content: writable() + parameters: [] + type: method + uid: google.cloud.storage.fileio.BlobWriter.writable +- attributes: [] + class: google.cloud.storage.fileio.BlobWriter + fullName: google.cloud.storage.fileio.BlobWriter.write + langs: + - python + module: google.cloud.storage.fileio + name: write + source: + id: write + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 349 + summary: 'Write the given buffer to the IO stream. + + + Returns the number of bytes written, which is always the length of b + + in bytes. + + + Raises BlockingIOError if the buffer is full and the + + underlying raw stream cannot accept more data at the moment. + + + ' + syntax: + content: write(b) + parameters: [] + type: method + uid: google.cloud.storage.fileio.BlobWriter.write +references: +- fullName: google.cloud.storage.fileio.BlobWriter.close + isExternal: false + name: close + parent: google.cloud.storage.fileio.BlobWriter + uid: google.cloud.storage.fileio.BlobWriter.close +- fullName: google.cloud.storage.fileio.BlobWriter.flush + isExternal: false + name: flush + parent: google.cloud.storage.fileio.BlobWriter + uid: google.cloud.storage.fileio.BlobWriter.flush +- fullName: google.cloud.storage.fileio.BlobWriter.readable + isExternal: false + name: readable + parent: google.cloud.storage.fileio.BlobWriter + uid: google.cloud.storage.fileio.BlobWriter.readable +- fullName: google.cloud.storage.fileio.BlobWriter.seekable + isExternal: false + name: seekable + parent: google.cloud.storage.fileio.BlobWriter + uid: google.cloud.storage.fileio.BlobWriter.seekable +- fullName: google.cloud.storage.fileio.BlobWriter.tell + isExternal: false + name: tell + parent: google.cloud.storage.fileio.BlobWriter + uid: google.cloud.storage.fileio.BlobWriter.tell +- fullName: google.cloud.storage.fileio.BlobWriter.writable + isExternal: false + name: writable + parent: google.cloud.storage.fileio.BlobWriter + uid: google.cloud.storage.fileio.BlobWriter.writable +- fullName: google.cloud.storage.fileio.BlobWriter.write + isExternal: false + name: write + parent: google.cloud.storage.fileio.BlobWriter + uid: google.cloud.storage.fileio.BlobWriter.write diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.fileio.SlidingBuffer.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.fileio.SlidingBuffer.yml new file mode 100644 index 000000000000..33883d1580c7 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.fileio.SlidingBuffer.yml @@ -0,0 +1,248 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: [] + children: + - google.cloud.storage.fileio.SlidingBuffer.__len__ + - google.cloud.storage.fileio.SlidingBuffer.flush + - google.cloud.storage.fileio.SlidingBuffer.read + - google.cloud.storage.fileio.SlidingBuffer.seek + - google.cloud.storage.fileio.SlidingBuffer.tell + - google.cloud.storage.fileio.SlidingBuffer.write + class: google.cloud.storage.fileio.SlidingBuffer + fullName: google.cloud.storage.fileio.SlidingBuffer + inheritance: + - type: builtins.object + langs: + - python + module: google.cloud.storage.fileio + name: SlidingBuffer + source: + id: SlidingBuffer + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 448 + summary: 'A non-rewindable buffer that frees memory of chunks already consumed. + + + This class is necessary because `google-resumable-media-python` expects + + `tell()` to work relative to the start of the file, not relative to a place + + in an intermediate buffer. Using this class, we present an external + + interface with consistent seek and tell behavior without having to actually + + store bytes already sent. + + + Behavior of this class differs from an ordinary BytesIO buffer. `write()` + + will always append to the end of the file only and not change the seek + + position otherwise. `flush()` will delete all data already read (data to the + + left of the seek position). `tell()` will report the seek position of the + + buffer including all deleted data. Additionally the class implements + + __len__() which will report the size of the actual underlying buffer. + + + This class does not attempt to implement the entire Python I/O interface. + + + ' + syntax: + content: SlidingBuffer() + parameters: [] + type: class + uid: google.cloud.storage.fileio.SlidingBuffer +- attributes: [] + class: google.cloud.storage.fileio.SlidingBuffer + fullName: google.cloud.storage.fileio.SlidingBuffer.__len__ + langs: + - python + module: google.cloud.storage.fileio + name: __len__ + source: + id: __len__ + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 531 + summary: 'Determine the size of the buffer by seeking to the end. + + + ' + syntax: + content: __len__() + parameters: [] + type: method + uid: google.cloud.storage.fileio.SlidingBuffer.__len__ +- attributes: [] + class: google.cloud.storage.fileio.SlidingBuffer + fullName: google.cloud.storage.fileio.SlidingBuffer.flush + langs: + - python + module: google.cloud.storage.fileio + name: flush + source: + id: flush + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 489 + summary: 'Delete already-read data (all data to the left of the position). + + + ' + syntax: + content: flush() + parameters: [] + type: method + uid: google.cloud.storage.fileio.SlidingBuffer.flush +- attributes: [] + class: google.cloud.storage.fileio.SlidingBuffer + fullName: google.cloud.storage.fileio.SlidingBuffer.read + langs: + - python + module: google.cloud.storage.fileio + name: read + source: + id: read + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 481 + summary: 'Read and move the cursor. + + + ' + syntax: + content: read(size=-1) + parameters: [] + type: method + uid: google.cloud.storage.fileio.SlidingBuffer.read +- attributes: [] + class: google.cloud.storage.fileio.SlidingBuffer + fullName: google.cloud.storage.fileio.SlidingBuffer.seek + langs: + - python + module: google.cloud.storage.fileio + name: seek + source: + id: seek + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 505 + summary: 'Seek to a position (backwards only) within the internal buffer. + + + This implementation of seek() verifies that the seek destination is + + contained in _buffer. It will raise ValueError if the destination byte + + has already been purged from the buffer. + + + The "whence" argument is not supported in this implementation. + + + ' + syntax: + content: seek(pos) + parameters: [] + type: method + uid: google.cloud.storage.fileio.SlidingBuffer.seek +- attributes: [] + class: google.cloud.storage.fileio.SlidingBuffer + fullName: google.cloud.storage.fileio.SlidingBuffer.tell + langs: + - python + module: google.cloud.storage.fileio + name: tell + source: + id: tell + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 501 + summary: 'Report how many bytes have been read from the buffer in total. + + + ' + syntax: + content: tell() + parameters: [] + type: method + uid: google.cloud.storage.fileio.SlidingBuffer.tell +- attributes: [] + class: google.cloud.storage.fileio.SlidingBuffer + fullName: google.cloud.storage.fileio.SlidingBuffer.write + langs: + - python + module: google.cloud.storage.fileio + name: write + source: + id: write + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 471 + summary: 'Append to the end of the buffer without changing the position. + + + ' + syntax: + content: write(b) + parameters: [] + type: method + uid: google.cloud.storage.fileio.SlidingBuffer.write +references: +- fullName: google.cloud.storage.fileio.SlidingBuffer.__len__ + isExternal: false + name: __len__ + parent: google.cloud.storage.fileio.SlidingBuffer + uid: google.cloud.storage.fileio.SlidingBuffer.__len__ +- fullName: google.cloud.storage.fileio.SlidingBuffer.flush + isExternal: false + name: flush + parent: google.cloud.storage.fileio.SlidingBuffer + uid: google.cloud.storage.fileio.SlidingBuffer.flush +- fullName: google.cloud.storage.fileio.SlidingBuffer.read + isExternal: false + name: read + parent: google.cloud.storage.fileio.SlidingBuffer + uid: google.cloud.storage.fileio.SlidingBuffer.read +- fullName: google.cloud.storage.fileio.SlidingBuffer.seek + isExternal: false + name: seek + parent: google.cloud.storage.fileio.SlidingBuffer + uid: google.cloud.storage.fileio.SlidingBuffer.seek +- fullName: google.cloud.storage.fileio.SlidingBuffer.tell + isExternal: false + name: tell + parent: google.cloud.storage.fileio.SlidingBuffer + uid: google.cloud.storage.fileio.SlidingBuffer.tell +- fullName: google.cloud.storage.fileio.SlidingBuffer.write + isExternal: false + name: write + parent: google.cloud.storage.fileio.SlidingBuffer + uid: google.cloud.storage.fileio.SlidingBuffer.write diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.fileio.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.fileio.yml new file mode 100644 index 000000000000..9ae6c2e3a20d --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.fileio.yml @@ -0,0 +1,44 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: [] + children: + - google.cloud.storage.fileio.BlobReader + - google.cloud.storage.fileio.BlobWriter + - google.cloud.storage.fileio.SlidingBuffer + fullName: google.cloud.storage.fileio + langs: + - python + module: google.cloud.storage.fileio + name: fileio + source: + id: fileio + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/fileio.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 0 + summary: 'Module for file-like access of blobs, usually invoked via Blob.open(). + + + ' + syntax: {} + type: module + uid: google.cloud.storage.fileio +references: +- fullName: google.cloud.storage.fileio.BlobReader + isExternal: false + name: BlobReader + parent: google.cloud.storage.fileio + uid: google.cloud.storage.fileio.BlobReader +- fullName: google.cloud.storage.fileio.BlobWriter + isExternal: false + name: BlobWriter + parent: google.cloud.storage.fileio + uid: google.cloud.storage.fileio.BlobWriter +- fullName: google.cloud.storage.fileio.SlidingBuffer + isExternal: false + name: SlidingBuffer + parent: google.cloud.storage.fileio + uid: google.cloud.storage.fileio.SlidingBuffer diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.hmac_key.HMACKeyMetadata.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.hmac_key.HMACKeyMetadata.yml new file mode 100644 index 000000000000..e4497beeeee6 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.hmac_key.HMACKeyMetadata.yml @@ -0,0 +1,606 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: [] + children: + - google.cloud.storage.hmac_key.HMACKeyMetadata.ACTIVE_STATE + - google.cloud.storage.hmac_key.HMACKeyMetadata.DELETED_STATE + - google.cloud.storage.hmac_key.HMACKeyMetadata.INACTIVE_STATE + - google.cloud.storage.hmac_key.HMACKeyMetadata.access_id + - google.cloud.storage.hmac_key.HMACKeyMetadata.delete + - google.cloud.storage.hmac_key.HMACKeyMetadata.etag + - google.cloud.storage.hmac_key.HMACKeyMetadata.exists + - google.cloud.storage.hmac_key.HMACKeyMetadata.id + - google.cloud.storage.hmac_key.HMACKeyMetadata.path + - google.cloud.storage.hmac_key.HMACKeyMetadata.project + - google.cloud.storage.hmac_key.HMACKeyMetadata.reload + - google.cloud.storage.hmac_key.HMACKeyMetadata.service_account_email + - google.cloud.storage.hmac_key.HMACKeyMetadata.state + - google.cloud.storage.hmac_key.HMACKeyMetadata.time_created + - google.cloud.storage.hmac_key.HMACKeyMetadata.update + - google.cloud.storage.hmac_key.HMACKeyMetadata.updated + - google.cloud.storage.hmac_key.HMACKeyMetadata.user_project + class: google.cloud.storage.hmac_key.HMACKeyMetadata + fullName: google.cloud.storage.hmac_key.HMACKeyMetadata + inheritance: + - type: builtins.object + langs: + - python + module: google.cloud.storage.hmac_key + name: HMACKeyMetadata + source: + id: HMACKeyMetadata + path: tests/testdata/handwritten/google/cloud/storage/hmac_key.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/hmac_key.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 28 + summary: 'Metadata about an HMAC service account key withn Cloud Storage. + + ' + syntax: + content: HMACKeyMetadata(client, access_id=None, project_id=None, user_project=None) + parameters: + - description: client associated with the key metadata. + id: client + var_type: Client + - description: (Optional) Unique ID of an existing key. + id: access_id + var_type: str + - description: (Optional) Project ID of an existing key. Defaults to client's + project. + id: project_id + var_type: str + - description: (Optional) This parameter is currently ignored. + id: user_project + var_type: str + type: class + uid: google.cloud.storage.hmac_key.HMACKeyMetadata +- attributes: [] + class: google.cloud.storage.hmac_key.HMACKeyMetadata + fullName: google.cloud.storage.hmac_key.HMACKeyMetadata.ACTIVE_STATE + langs: + - python + module: google.cloud.storage.hmac_key + name: ACTIVE_STATE + source: + id: ACTIVE_STATE + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Key is active, and may be used to sign requests. + + + ' + syntax: {} + type: attribute + uid: google.cloud.storage.hmac_key.HMACKeyMetadata.ACTIVE_STATE +- attributes: [] + class: google.cloud.storage.hmac_key.HMACKeyMetadata + fullName: google.cloud.storage.hmac_key.HMACKeyMetadata.DELETED_STATE + langs: + - python + module: google.cloud.storage.hmac_key + name: DELETED_STATE + source: + id: DELETED_STATE + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Key is deleted. It cannot be re-activated. + + + ' + syntax: {} + type: attribute + uid: google.cloud.storage.hmac_key.HMACKeyMetadata.DELETED_STATE +- attributes: [] + class: google.cloud.storage.hmac_key.HMACKeyMetadata + fullName: google.cloud.storage.hmac_key.HMACKeyMetadata.INACTIVE_STATE + langs: + - python + module: google.cloud.storage.hmac_key + name: INACTIVE_STATE + source: + id: INACTIVE_STATE + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Key is inactive, and may not be used to sign requests. + + + It can be re-activated via `update`. + + + ' + syntax: {} + type: attribute + uid: google.cloud.storage.hmac_key.HMACKeyMetadata.INACTIVE_STATE +- &id001 + attributes: [] + class: google.cloud.storage.hmac_key.HMACKeyMetadata + fullName: google.cloud.storage.hmac_key.HMACKeyMetadata.access_id + langs: + - python + module: google.cloud.storage.hmac_key + name: access_id + source: + id: access_id + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Access ID of the key. + + ' + syntax: + returns: + - description: unique identifier of the key within a project. + var_type: str or None + type: property + uid: google.cloud.storage.hmac_key.HMACKeyMetadata.access_id +- *id001 +- attributes: [] + class: google.cloud.storage.hmac_key.HMACKeyMetadata + fullName: google.cloud.storage.hmac_key.HMACKeyMetadata.delete + langs: + - python + module: google.cloud.storage.hmac_key + name: delete + source: + id: delete + path: tests/testdata/handwritten/google/cloud/storage/hmac_key.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/hmac_key.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 277 + summary: 'Delete the key from Cloud Storage. + + ' + syntax: + content: delete(timeout=60, retry=) + exceptions: + - description: if the key does not exist on the back-end. + var_type: google.api_core.exceptions.NotFound + parameters: + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: '(Optional) How to retry the RPC. See: configuring_retries' + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + type: method + uid: google.cloud.storage.hmac_key.HMACKeyMetadata.delete +- &id002 + attributes: [] + class: google.cloud.storage.hmac_key.HMACKeyMetadata + fullName: google.cloud.storage.hmac_key.HMACKeyMetadata.etag + langs: + - python + module: google.cloud.storage.hmac_key + name: etag + source: + id: etag + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'ETag identifying the version of the key metadata. + + ' + syntax: + returns: + - description: ETag for the version of the key's metadata. + var_type: str or None + type: property + uid: google.cloud.storage.hmac_key.HMACKeyMetadata.etag +- *id002 +- attributes: [] + class: google.cloud.storage.hmac_key.HMACKeyMetadata + fullName: google.cloud.storage.hmac_key.HMACKeyMetadata.exists + langs: + - python + module: google.cloud.storage.hmac_key + name: exists + source: + id: exists + path: tests/testdata/handwritten/google/cloud/storage/hmac_key.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/hmac_key.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 190 + summary: 'Determine whether or not the key for this metadata exists. + + ' + syntax: + content: exists(timeout=60, retry=) + parameters: + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: '(Optional) How to retry the RPC. See: configuring_retries' + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + returns: + - description: True if the key exists in Cloud Storage. + var_type: bool + type: method + uid: google.cloud.storage.hmac_key.HMACKeyMetadata.exists +- &id003 + attributes: [] + class: google.cloud.storage.hmac_key.HMACKeyMetadata + fullName: google.cloud.storage.hmac_key.HMACKeyMetadata.id + langs: + - python + module: google.cloud.storage.hmac_key + name: id + source: + id: id + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'ID of the key, including the Project ID and the Access ID. + + ' + syntax: + returns: + - description: ID of the key. + var_type: str or None + type: property + uid: google.cloud.storage.hmac_key.HMACKeyMetadata.id +- *id003 +- &id004 + attributes: [] + class: google.cloud.storage.hmac_key.HMACKeyMetadata + fullName: google.cloud.storage.hmac_key.HMACKeyMetadata.path + langs: + - python + module: google.cloud.storage.hmac_key + name: path + source: + id: path + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Resource path for the metadata''s key. + + + ' + syntax: {} + type: property + uid: google.cloud.storage.hmac_key.HMACKeyMetadata.path +- *id004 +- &id005 + attributes: [] + class: google.cloud.storage.hmac_key.HMACKeyMetadata + fullName: google.cloud.storage.hmac_key.HMACKeyMetadata.project + langs: + - python + module: google.cloud.storage.hmac_key + name: project + source: + id: project + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Project ID associated with the key. + + ' + syntax: + returns: + - description: project identfier for the key. + var_type: str or None + type: property + uid: google.cloud.storage.hmac_key.HMACKeyMetadata.project +- *id005 +- attributes: [] + class: google.cloud.storage.hmac_key.HMACKeyMetadata + fullName: google.cloud.storage.hmac_key.HMACKeyMetadata.reload + langs: + - python + module: google.cloud.storage.hmac_key + name: reload + source: + id: reload + path: tests/testdata/handwritten/google/cloud/storage/hmac_key.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/hmac_key.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 222 + summary: 'Reload properties from Cloud Storage. + + ' + syntax: + content: reload(timeout=60, retry=) + exceptions: + - description: if the key does not exist on the back-end. + var_type: google.api_core.exceptions.NotFound + parameters: + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: '(Optional) How to retry the RPC. See: configuring_retries' + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + type: method + uid: google.cloud.storage.hmac_key.HMACKeyMetadata.reload +- &id006 + attributes: [] + class: google.cloud.storage.hmac_key.HMACKeyMetadata + fullName: google.cloud.storage.hmac_key.HMACKeyMetadata.service_account_email + langs: + - python + module: google.cloud.storage.hmac_key + name: service_account_email + source: + id: service_account_email + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Service account e-mail address associated with the key. + + ' + syntax: + returns: + - description: e-mail address for the service account which created the key. + var_type: str or None + type: property + uid: google.cloud.storage.hmac_key.HMACKeyMetadata.service_account_email +- *id006 +- &id007 + attributes: [] + class: google.cloud.storage.hmac_key.HMACKeyMetadata + fullName: google.cloud.storage.hmac_key.HMACKeyMetadata.state + langs: + - python + module: google.cloud.storage.hmac_key + name: state + source: + id: state + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: "Get / set key's state.\n\nOne of:\n - `ACTIVE`\n - `INACTIVE`\n\ + \ - `DELETED`\n" + syntax: + returns: + - description: key's current state. + var_type: str or None + type: property + uid: google.cloud.storage.hmac_key.HMACKeyMetadata.state +- *id007 +- &id008 + attributes: [] + class: google.cloud.storage.hmac_key.HMACKeyMetadata + fullName: google.cloud.storage.hmac_key.HMACKeyMetadata.time_created + langs: + - python + module: google.cloud.storage.hmac_key + name: time_created + source: + id: time_created + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Retrieve the timestamp at which the HMAC key was created. + + ' + syntax: + returns: + - description: Datetime object parsed from RFC3339 valid timestamp, or None + if the bucket's resource has not been loaded from the server. + var_type: datetime.datetime or NoneType + type: property + uid: google.cloud.storage.hmac_key.HMACKeyMetadata.time_created +- *id008 +- attributes: [] + class: google.cloud.storage.hmac_key.HMACKeyMetadata + fullName: google.cloud.storage.hmac_key.HMACKeyMetadata.update + langs: + - python + module: google.cloud.storage.hmac_key + name: update + source: + id: update + path: tests/testdata/handwritten/google/cloud/storage/hmac_key.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/hmac_key.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 249 + summary: 'Save writable properties to Cloud Storage. + + ' + syntax: + content: update(timeout=60, retry=) + exceptions: + - description: if the key does not exist on the back-end. + var_type: google.api_core.exceptions.NotFound + parameters: + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: '(Optional) How to retry the RPC. See: configuring_retries' + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + type: method + uid: google.cloud.storage.hmac_key.HMACKeyMetadata.update +- &id009 + attributes: [] + class: google.cloud.storage.hmac_key.HMACKeyMetadata + fullName: google.cloud.storage.hmac_key.HMACKeyMetadata.updated + langs: + - python + module: google.cloud.storage.hmac_key + name: updated + source: + id: updated + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Retrieve the timestamp at which the HMAC key was created. + + ' + syntax: + returns: + - description: Datetime object parsed from RFC3339 valid timestamp, or None + if the bucket's resource has not been loaded from the server. + var_type: datetime.datetime or NoneType + type: property + uid: google.cloud.storage.hmac_key.HMACKeyMetadata.updated +- *id009 +- &id010 + attributes: [] + class: google.cloud.storage.hmac_key.HMACKeyMetadata + fullName: google.cloud.storage.hmac_key.HMACKeyMetadata.user_project + langs: + - python + module: google.cloud.storage.hmac_key + name: user_project + source: + id: user_project + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Project ID to be billed for API requests made via this bucket. + + + This property is currently ignored by the server. + + ' + syntax: {} + type: property + uid: google.cloud.storage.hmac_key.HMACKeyMetadata.user_project +- *id010 +references: +- fullName: google.cloud.storage.hmac_key.HMACKeyMetadata.ACTIVE_STATE + isExternal: false + name: ACTIVE_STATE + parent: google.cloud.storage.hmac_key.HMACKeyMetadata + uid: google.cloud.storage.hmac_key.HMACKeyMetadata.ACTIVE_STATE +- fullName: google.cloud.storage.hmac_key.HMACKeyMetadata.DELETED_STATE + isExternal: false + name: DELETED_STATE + parent: google.cloud.storage.hmac_key.HMACKeyMetadata + uid: google.cloud.storage.hmac_key.HMACKeyMetadata.DELETED_STATE +- fullName: google.cloud.storage.hmac_key.HMACKeyMetadata.INACTIVE_STATE + isExternal: false + name: INACTIVE_STATE + parent: google.cloud.storage.hmac_key.HMACKeyMetadata + uid: google.cloud.storage.hmac_key.HMACKeyMetadata.INACTIVE_STATE +- fullName: google.cloud.storage.hmac_key.HMACKeyMetadata.access_id + isExternal: false + name: access_id + parent: google.cloud.storage.hmac_key.HMACKeyMetadata + uid: google.cloud.storage.hmac_key.HMACKeyMetadata.access_id +- fullName: google.cloud.storage.hmac_key.HMACKeyMetadata.delete + isExternal: false + name: delete + parent: google.cloud.storage.hmac_key.HMACKeyMetadata + uid: google.cloud.storage.hmac_key.HMACKeyMetadata.delete +- fullName: google.cloud.storage.hmac_key.HMACKeyMetadata.etag + isExternal: false + name: etag + parent: google.cloud.storage.hmac_key.HMACKeyMetadata + uid: google.cloud.storage.hmac_key.HMACKeyMetadata.etag +- fullName: google.cloud.storage.hmac_key.HMACKeyMetadata.exists + isExternal: false + name: exists + parent: google.cloud.storage.hmac_key.HMACKeyMetadata + uid: google.cloud.storage.hmac_key.HMACKeyMetadata.exists +- fullName: google.cloud.storage.hmac_key.HMACKeyMetadata.id + isExternal: false + name: id + parent: google.cloud.storage.hmac_key.HMACKeyMetadata + uid: google.cloud.storage.hmac_key.HMACKeyMetadata.id +- fullName: google.cloud.storage.hmac_key.HMACKeyMetadata.path + isExternal: false + name: path + parent: google.cloud.storage.hmac_key.HMACKeyMetadata + uid: google.cloud.storage.hmac_key.HMACKeyMetadata.path +- fullName: google.cloud.storage.hmac_key.HMACKeyMetadata.project + isExternal: false + name: project + parent: google.cloud.storage.hmac_key.HMACKeyMetadata + uid: google.cloud.storage.hmac_key.HMACKeyMetadata.project +- fullName: google.cloud.storage.hmac_key.HMACKeyMetadata.reload + isExternal: false + name: reload + parent: google.cloud.storage.hmac_key.HMACKeyMetadata + uid: google.cloud.storage.hmac_key.HMACKeyMetadata.reload +- fullName: google.cloud.storage.hmac_key.HMACKeyMetadata.service_account_email + isExternal: false + name: service_account_email + parent: google.cloud.storage.hmac_key.HMACKeyMetadata + uid: google.cloud.storage.hmac_key.HMACKeyMetadata.service_account_email +- fullName: google.cloud.storage.hmac_key.HMACKeyMetadata.state + isExternal: false + name: state + parent: google.cloud.storage.hmac_key.HMACKeyMetadata + uid: google.cloud.storage.hmac_key.HMACKeyMetadata.state +- fullName: google.cloud.storage.hmac_key.HMACKeyMetadata.time_created + isExternal: false + name: time_created + parent: google.cloud.storage.hmac_key.HMACKeyMetadata + uid: google.cloud.storage.hmac_key.HMACKeyMetadata.time_created +- fullName: google.cloud.storage.hmac_key.HMACKeyMetadata.update + isExternal: false + name: update + parent: google.cloud.storage.hmac_key.HMACKeyMetadata + uid: google.cloud.storage.hmac_key.HMACKeyMetadata.update +- fullName: google.cloud.storage.hmac_key.HMACKeyMetadata.updated + isExternal: false + name: updated + parent: google.cloud.storage.hmac_key.HMACKeyMetadata + uid: google.cloud.storage.hmac_key.HMACKeyMetadata.updated +- fullName: google.cloud.storage.hmac_key.HMACKeyMetadata.user_project + isExternal: false + name: user_project + parent: google.cloud.storage.hmac_key.HMACKeyMetadata + uid: google.cloud.storage.hmac_key.HMACKeyMetadata.user_project diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.hmac_key.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.hmac_key.yml new file mode 100644 index 000000000000..ecb89e0190dc --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.hmac_key.yml @@ -0,0 +1,36 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: [] + children: + - google.cloud.storage.hmac_key.HMACKeyMetadata + fullName: google.cloud.storage.hmac_key + langs: + - python + module: google.cloud.storage.hmac_key + name: hmac_key + source: + id: hmac_key + path: tests/testdata/handwritten/google/cloud/storage/hmac_key.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/hmac_key.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 0 + summary: 'Configure HMAC keys that can be used to authenticate requests to Google + Cloud Storage. + + + See [HMAC keys documentation](https://cloud.google.com/storage/docs/authentication/hmackeys) + + + ' + syntax: {} + type: module + uid: google.cloud.storage.hmac_key +references: +- fullName: google.cloud.storage.hmac_key.HMACKeyMetadata + isExternal: false + name: HMACKeyMetadata + parent: google.cloud.storage.hmac_key + uid: google.cloud.storage.hmac_key.HMACKeyMetadata diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.notification.BucketNotification.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.notification.BucketNotification.yml new file mode 100644 index 000000000000..2ebe0ca4fc10 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.notification.BucketNotification.yml @@ -0,0 +1,679 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: [] + children: + - google.cloud.storage.notification.BucketNotification.blob_name_prefix + - google.cloud.storage.notification.BucketNotification.bucket + - google.cloud.storage.notification.BucketNotification.client + - google.cloud.storage.notification.BucketNotification.create + - google.cloud.storage.notification.BucketNotification.custom_attributes + - google.cloud.storage.notification.BucketNotification.delete + - google.cloud.storage.notification.BucketNotification.etag + - google.cloud.storage.notification.BucketNotification.event_types + - google.cloud.storage.notification.BucketNotification.exists + - google.cloud.storage.notification.BucketNotification.from_api_repr + - google.cloud.storage.notification.BucketNotification.notification_id + - google.cloud.storage.notification.BucketNotification.path + - google.cloud.storage.notification.BucketNotification.payload_format + - google.cloud.storage.notification.BucketNotification.reload + - google.cloud.storage.notification.BucketNotification.self_link + - google.cloud.storage.notification.BucketNotification.topic_name + - google.cloud.storage.notification.BucketNotification.topic_project + class: google.cloud.storage.notification.BucketNotification + fullName: google.cloud.storage.notification.BucketNotification + inheritance: + - type: builtins.object + langs: + - python + module: google.cloud.storage.notification + name: BucketNotification + source: + id: BucketNotification + path: tests/testdata/handwritten/google/cloud/storage/notification.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/notification.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 48 + summary: 'Represent a single notification resource for a bucket. + + + See: https://cloud.google.com/storage/docs/json_api/v1/notifications + + ' + syntax: + content: "BucketNotification(\n bucket,\n topic_name=None,\n topic_project=None,\n\ + \ custom_attributes=None,\n event_types=None,\n blob_name_prefix=None,\n\ + \ payload_format=\"NONE\",\n notification_id=None,\n)" + parameters: + - description: Bucket to which the notification is bound. + id: bucket + var_type: Bucket + - description: (Optional) Topic name to which notifications are published. + id: topic_name + var_type: str + - description: (Optional) Project ID of topic to which notifications are published. + If not passed, uses the project ID of the bucket's client. + id: topic_project + var_type: str + - description: (Optional) Additional attributes passed with notification events. + id: custom_attributes + var_type: dict + - description: (Optional) Event types for which notification events are published. + id: event_types + var_type: list(str) + - description: (Optional) Prefix of blob names for which notification events are + published. + id: blob_name_prefix + var_type: str + - description: (Optional) Format of payload for notification events. + id: payload_format + var_type: str + - description: (Optional) The ID of the notification. + id: notification_id + var_type: str + type: class + uid: google.cloud.storage.notification.BucketNotification +- &id001 + attributes: [] + class: google.cloud.storage.notification.BucketNotification + fullName: google.cloud.storage.notification.BucketNotification.blob_name_prefix + langs: + - python + module: google.cloud.storage.notification + name: blob_name_prefix + source: + id: blob_name_prefix + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Prefix of blob names for which notification events are published. + + + ' + syntax: {} + type: property + uid: google.cloud.storage.notification.BucketNotification.blob_name_prefix +- *id001 +- &id002 + attributes: [] + class: google.cloud.storage.notification.BucketNotification + fullName: google.cloud.storage.notification.BucketNotification.bucket + langs: + - python + module: google.cloud.storage.notification + name: bucket + source: + id: bucket + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Bucket to which the notification is bound. + + + ' + syntax: {} + type: property + uid: google.cloud.storage.notification.BucketNotification.bucket +- *id002 +- &id003 + attributes: [] + class: google.cloud.storage.notification.BucketNotification + fullName: google.cloud.storage.notification.BucketNotification.client + langs: + - python + module: google.cloud.storage.notification + name: client + source: + id: client + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'The client bound to this notfication. + + + ' + syntax: {} + type: property + uid: google.cloud.storage.notification.BucketNotification.client +- *id003 +- attributes: [] + class: google.cloud.storage.notification.BucketNotification + fullName: google.cloud.storage.notification.BucketNotification.create + langs: + - python + module: google.cloud.storage.notification + name: create + source: + id: create + path: tests/testdata/handwritten/google/cloud/storage/notification.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/notification.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 233 + summary: 'API wrapper: create the notification. + + + See: + + https://cloud.google.com/storage/docs/json_api/v1/notifications/insert + + + If `user_project` is set on the bucket, bills the API request + + to that project. + + ' + syntax: + content: create(client=None, timeout=60, retry=None) + exceptions: + - description: if the notification already exists. + var_type: ValueError + parameters: + - description: (Optional) The client to use. If not passed, falls back to the + client stored on the notification's bucket. + id: client + var_type: Client + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: '(Optional) How to retry the RPC. See: configuring_retries' + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + type: method + uid: google.cloud.storage.notification.BucketNotification.create +- &id004 + attributes: [] + class: google.cloud.storage.notification.BucketNotification + fullName: google.cloud.storage.notification.BucketNotification.custom_attributes + langs: + - python + module: google.cloud.storage.notification + name: custom_attributes + source: + id: custom_attributes + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Custom attributes passed with notification events. + + + ' + syntax: {} + type: property + uid: google.cloud.storage.notification.BucketNotification.custom_attributes +- *id004 +- attributes: [] + class: google.cloud.storage.notification.BucketNotification + fullName: google.cloud.storage.notification.BucketNotification.delete + langs: + - python + module: google.cloud.storage.notification + name: delete + source: + id: delete + path: tests/testdata/handwritten/google/cloud/storage/notification.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/notification.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 374 + summary: 'Delete this notification. + + + See: + + https://cloud.google.com/storage/docs/json_api/v1/notifications/delete + + + If `user_project` is set on the bucket, bills the API request + + to that project. + + ' + syntax: + content: delete(client=None, timeout=60, retry=) + exceptions: + - description: if the notification does not exist. + var_type: google.api_core.exceptions.NotFound + - description: if the notification has no ID. + var_type: ValueError + parameters: + - description: (Optional) The client to use. If not passed, falls back to the + client stored on the current bucket. + id: client + var_type: Client or NoneType + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: '(Optional) How to retry the RPC. See: configuring_retries' + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + type: method + uid: google.cloud.storage.notification.BucketNotification.delete +- &id005 + attributes: [] + class: google.cloud.storage.notification.BucketNotification + fullName: google.cloud.storage.notification.BucketNotification.etag + langs: + - python + module: google.cloud.storage.notification + name: etag + source: + id: etag + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Server-set ETag of notification resource. + + + ' + syntax: {} + type: property + uid: google.cloud.storage.notification.BucketNotification.etag +- *id005 +- &id006 + attributes: [] + class: google.cloud.storage.notification.BucketNotification + fullName: google.cloud.storage.notification.BucketNotification.event_types + langs: + - python + module: google.cloud.storage.notification + name: event_types + source: + id: event_types + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Event types for which notification events are published. + + + ' + syntax: {} + type: property + uid: google.cloud.storage.notification.BucketNotification.event_types +- *id006 +- attributes: [] + class: google.cloud.storage.notification.BucketNotification + fullName: google.cloud.storage.notification.BucketNotification.exists + langs: + - python + module: google.cloud.storage.notification + name: exists + source: + id: exists + path: tests/testdata/handwritten/google/cloud/storage/notification.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/notification.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 285 + summary: 'Test whether this notification exists. + + + See: + + https://cloud.google.com/storage/docs/json_api/v1/notifications/get + + + If `user_project` is set on the bucket, bills the API request + + to that project. + + ' + syntax: + content: exists(client=None, timeout=60, retry=) + exceptions: + - description: if the notification has no ID. + var_type: ValueError + parameters: + - description: (Optional) The client to use. If not passed, falls back to the + client stored on the current bucket. + id: client + var_type: Client or NoneType + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: '(Optional) How to retry the RPC. See: configuring_retries' + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + returns: + - description: True, if the notification exists, else False. + var_type: bool + type: method + uid: google.cloud.storage.notification.BucketNotification.exists +- attributes: [] + class: google.cloud.storage.notification.BucketNotification + fullName: google.cloud.storage.notification.BucketNotification.from_api_repr + langs: + - python + module: google.cloud.storage.notification + name: from_api_repr + source: + id: from_api_repr + path: tests/testdata/handwritten/google/cloud/storage/notification.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/notification.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 125 + summary: 'Construct an instance from the JSON repr returned by the server. + + + See: https://cloud.google.com/storage/docs/json_api/v1/notifications + + ' + syntax: + content: from_api_repr(resource, bucket) + parameters: + - description: JSON repr of the notification + id: resource + var_type: dict + - description: Bucket to which the notification is bound. + id: bucket + var_type: Bucket + returns: + - description: the new notification instance + var_type: BucketNotification + type: method + uid: google.cloud.storage.notification.BucketNotification.from_api_repr +- &id007 + attributes: [] + class: google.cloud.storage.notification.BucketNotification + fullName: google.cloud.storage.notification.BucketNotification.notification_id + langs: + - python + module: google.cloud.storage.notification + name: notification_id + source: + id: notification_id + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Server-set ID of notification resource. + + + ' + syntax: {} + type: property + uid: google.cloud.storage.notification.BucketNotification.notification_id +- *id007 +- &id008 + attributes: [] + class: google.cloud.storage.notification.BucketNotification + fullName: google.cloud.storage.notification.BucketNotification.path + langs: + - python + module: google.cloud.storage.notification + name: path + source: + id: path + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'The URL path for this notification. + + + ' + syntax: {} + type: property + uid: google.cloud.storage.notification.BucketNotification.path +- *id008 +- &id009 + attributes: [] + class: google.cloud.storage.notification.BucketNotification + fullName: google.cloud.storage.notification.BucketNotification.payload_format + langs: + - python + module: google.cloud.storage.notification + name: payload_format + source: + id: payload_format + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Format of payload of notification events. + + + ' + syntax: {} + type: property + uid: google.cloud.storage.notification.BucketNotification.payload_format +- *id009 +- attributes: [] + class: google.cloud.storage.notification.BucketNotification + fullName: google.cloud.storage.notification.BucketNotification.reload + langs: + - python + module: google.cloud.storage.notification + name: reload + source: + id: reload + path: tests/testdata/handwritten/google/cloud/storage/notification.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/notification.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 332 + summary: 'Update this notification from the server configuration. + + + See: + + https://cloud.google.com/storage/docs/json_api/v1/notifications/get + + + If `user_project` is set on the bucket, bills the API request + + to that project. + + ' + syntax: + content: reload(client=None, timeout=60, retry=) + exceptions: + - description: if the notification has no ID. + var_type: ValueError + parameters: + - description: (Optional) The client to use. If not passed, falls back to the + client stored on the current bucket. + id: client + var_type: Client or NoneType + - description: '(Optional) The amount of time, in seconds, to wait for the server + response. See: configuring_timeouts' + id: timeout + var_type: float or tuple + - description: '(Optional) How to retry the RPC. See: configuring_retries' + id: retry + var_type: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + type: method + uid: google.cloud.storage.notification.BucketNotification.reload +- &id010 + attributes: [] + class: google.cloud.storage.notification.BucketNotification + fullName: google.cloud.storage.notification.BucketNotification.self_link + langs: + - python + module: google.cloud.storage.notification + name: self_link + source: + id: self_link + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Server-set ETag of notification resource. + + + ' + syntax: {} + type: property + uid: google.cloud.storage.notification.BucketNotification.self_link +- *id010 +- &id011 + attributes: [] + class: google.cloud.storage.notification.BucketNotification + fullName: google.cloud.storage.notification.BucketNotification.topic_name + langs: + - python + module: google.cloud.storage.notification + name: topic_name + source: + id: topic_name + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Topic name to which notifications are published. + + + ' + syntax: {} + type: property + uid: google.cloud.storage.notification.BucketNotification.topic_name +- *id011 +- &id012 + attributes: [] + class: google.cloud.storage.notification.BucketNotification + fullName: google.cloud.storage.notification.BucketNotification.topic_project + langs: + - python + module: google.cloud.storage.notification + name: topic_project + source: + id: topic_project + path: null + remote: + branch: add_goldens + path: null + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: null + summary: 'Project ID of topic to which notifications are published. + + + ' + syntax: {} + type: property + uid: google.cloud.storage.notification.BucketNotification.topic_project +- *id012 +references: +- fullName: google.cloud.storage.notification.BucketNotification.blob_name_prefix + isExternal: false + name: blob_name_prefix + parent: google.cloud.storage.notification.BucketNotification + uid: google.cloud.storage.notification.BucketNotification.blob_name_prefix +- fullName: google.cloud.storage.notification.BucketNotification.bucket + isExternal: false + name: bucket + parent: google.cloud.storage.notification.BucketNotification + uid: google.cloud.storage.notification.BucketNotification.bucket +- fullName: google.cloud.storage.notification.BucketNotification.client + isExternal: false + name: client + parent: google.cloud.storage.notification.BucketNotification + uid: google.cloud.storage.notification.BucketNotification.client +- fullName: google.cloud.storage.notification.BucketNotification.create + isExternal: false + name: create + parent: google.cloud.storage.notification.BucketNotification + uid: google.cloud.storage.notification.BucketNotification.create +- fullName: google.cloud.storage.notification.BucketNotification.custom_attributes + isExternal: false + name: custom_attributes + parent: google.cloud.storage.notification.BucketNotification + uid: google.cloud.storage.notification.BucketNotification.custom_attributes +- fullName: google.cloud.storage.notification.BucketNotification.delete + isExternal: false + name: delete + parent: google.cloud.storage.notification.BucketNotification + uid: google.cloud.storage.notification.BucketNotification.delete +- fullName: google.cloud.storage.notification.BucketNotification.etag + isExternal: false + name: etag + parent: google.cloud.storage.notification.BucketNotification + uid: google.cloud.storage.notification.BucketNotification.etag +- fullName: google.cloud.storage.notification.BucketNotification.event_types + isExternal: false + name: event_types + parent: google.cloud.storage.notification.BucketNotification + uid: google.cloud.storage.notification.BucketNotification.event_types +- fullName: google.cloud.storage.notification.BucketNotification.exists + isExternal: false + name: exists + parent: google.cloud.storage.notification.BucketNotification + uid: google.cloud.storage.notification.BucketNotification.exists +- fullName: google.cloud.storage.notification.BucketNotification.from_api_repr + isExternal: false + name: from_api_repr + parent: google.cloud.storage.notification.BucketNotification + uid: google.cloud.storage.notification.BucketNotification.from_api_repr +- fullName: google.cloud.storage.notification.BucketNotification.notification_id + isExternal: false + name: notification_id + parent: google.cloud.storage.notification.BucketNotification + uid: google.cloud.storage.notification.BucketNotification.notification_id +- fullName: google.cloud.storage.notification.BucketNotification.path + isExternal: false + name: path + parent: google.cloud.storage.notification.BucketNotification + uid: google.cloud.storage.notification.BucketNotification.path +- fullName: google.cloud.storage.notification.BucketNotification.payload_format + isExternal: false + name: payload_format + parent: google.cloud.storage.notification.BucketNotification + uid: google.cloud.storage.notification.BucketNotification.payload_format +- fullName: google.cloud.storage.notification.BucketNotification.reload + isExternal: false + name: reload + parent: google.cloud.storage.notification.BucketNotification + uid: google.cloud.storage.notification.BucketNotification.reload +- fullName: google.cloud.storage.notification.BucketNotification.self_link + isExternal: false + name: self_link + parent: google.cloud.storage.notification.BucketNotification + uid: google.cloud.storage.notification.BucketNotification.self_link +- fullName: google.cloud.storage.notification.BucketNotification.topic_name + isExternal: false + name: topic_name + parent: google.cloud.storage.notification.BucketNotification + uid: google.cloud.storage.notification.BucketNotification.topic_name +- fullName: google.cloud.storage.notification.BucketNotification.topic_project + isExternal: false + name: topic_project + parent: google.cloud.storage.notification.BucketNotification + uid: google.cloud.storage.notification.BucketNotification.topic_project diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.notification.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.notification.yml new file mode 100644 index 000000000000..bafeef3d4fd5 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.notification.yml @@ -0,0 +1,36 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: [] + children: + - google.cloud.storage.notification.BucketNotification + fullName: google.cloud.storage.notification + langs: + - python + module: google.cloud.storage.notification + name: notification + source: + id: notification + path: tests/testdata/handwritten/google/cloud/storage/notification.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/notification.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 0 + summary: 'Configure bucket notification resources to interact with Google Cloud + Pub/Sub. + + + See [Cloud Pub/Sub Notifications for Google Cloud Storage](https://cloud.google.com/storage/docs/pubsub-notifications) + + + ' + syntax: {} + type: module + uid: google.cloud.storage.notification +references: +- fullName: google.cloud.storage.notification.BucketNotification + isExternal: false + name: BucketNotification + parent: google.cloud.storage.notification + uid: google.cloud.storage.notification.BucketNotification diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.retry.ConditionalRetryPolicy.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.retry.ConditionalRetryPolicy.yml new file mode 100644 index 000000000000..524d46d60c89 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.retry.ConditionalRetryPolicy.yml @@ -0,0 +1,61 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: [] + children: [] + class: google.cloud.storage.retry.ConditionalRetryPolicy + fullName: google.cloud.storage.retry.ConditionalRetryPolicy + inheritance: + - type: builtins.object + langs: + - python + module: google.cloud.storage.retry + name: ConditionalRetryPolicy + source: + id: ConditionalRetryPolicy + path: tests/testdata/handwritten/google/cloud/storage/retry.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/retry.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 71 + summary: 'A class for use when an API call is only conditionally safe to retry. + + + This class is intended for use in inspecting the API call parameters of an + + API call to verify that any flags necessary to make the API call idempotent + + (such as specifying an `if_generation_match` or related flag) are present. + + + It can be used in place of a `retry.Retry` object, in which case + + `_http.Connection.api_request` will pass the requested api call keyword + + arguments into the `conditional_predicate` and return the `retry_policy` + + if the conditions are met. + + ' + syntax: + content: ConditionalRetryPolicy(retry_policy, conditional_predicate, required_kwargs) + parameters: + - description: A retry object defining timeouts, persistence and which exceptions + to retry. + id: retry_policy + var_type: class:google.api_core.retry.Retry + - description: A callable that accepts exactly the number of arguments in required_kwargs, + in order, and returns True if the arguments have sufficient data to determine + that the call is safe to retry (idempotent). + id: conditional_predicate + var_type: callable + - description: A list of keyword argument keys that will be extracted from the + API call and passed into the conditional predicate in order. + For example, ["query_params"] is commmonly used for preconditions + in query_params. + id: required_kwargs + var_type: list(str) + type: class + uid: google.cloud.storage.retry.ConditionalRetryPolicy +references: [] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.retry.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.retry.yml new file mode 100644 index 000000000000..1e2ebfe013e9 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/google.cloud.storage.retry.yml @@ -0,0 +1,156 @@ +### YamlMime:UniversalReference +api_name: [] +items: +- attributes: [] + children: + - google.cloud.storage.retry.ConditionalRetryPolicy + - google.cloud.storage.retry.is_etag_in_data + - google.cloud.storage.retry.is_etag_in_json + - google.cloud.storage.retry.is_generation_specified + - google.cloud.storage.retry.is_metageneration_specified + fullName: google.cloud.storage.retry + langs: + - python + module: google.cloud.storage.retry + name: retry + source: + id: retry + path: tests/testdata/handwritten/google/cloud/storage/retry.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/retry.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 0 + summary: 'Helpers for configuring retries with exponential back-off. + + + See [Retry Strategy for Google Cloud Storage](https://cloud.google.com/storage/docs/retry-strategy#client-libraries) + + + ' + syntax: {} + type: module + uid: google.cloud.storage.retry +- attributes: [] + fullName: google.cloud.storage.retry.is_etag_in_data + langs: + - python + module: google.cloud.storage.retry + name: is_etag_in_data + source: + id: is_etag_in_data + path: tests/testdata/handwritten/google/cloud/storage/retry.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/retry.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 124 + summary: 'Return True if an etag is contained in the request body. + + ' + syntax: + content: is_etag_in_data(data) + parameters: + - description: A dict representing the request JSON body. If not passed, returns + False. + id: data + var_type: dict or None + type: function + uid: google.cloud.storage.retry.is_etag_in_data +- attributes: [] + fullName: google.cloud.storage.retry.is_etag_in_json + langs: + - python + module: google.cloud.storage.retry + name: is_etag_in_json + source: + id: is_etag_in_json + path: tests/testdata/handwritten/google/cloud/storage/retry.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/retry.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 133 + summary: '`is_etag_in_json` is supported for backwards-compatibility reasons only; + + please use `is_etag_in_data` instead. + + + ' + syntax: + content: is_etag_in_json(data) + parameters: [] + type: function + uid: google.cloud.storage.retry.is_etag_in_json +- attributes: [] + fullName: google.cloud.storage.retry.is_generation_specified + langs: + - python + module: google.cloud.storage.retry + name: is_generation_specified + source: + id: is_generation_specified + path: tests/testdata/handwritten/google/cloud/storage/retry.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/retry.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 111 + summary: 'Return True if generation or if_generation_match is specified. + + + ' + syntax: + content: is_generation_specified(query_params) + parameters: [] + type: function + uid: google.cloud.storage.retry.is_generation_specified +- attributes: [] + fullName: google.cloud.storage.retry.is_metageneration_specified + langs: + - python + module: google.cloud.storage.retry + name: is_metageneration_specified + source: + id: is_metageneration_specified + path: tests/testdata/handwritten/google/cloud/storage/retry.py + remote: + branch: add_goldens + path: tests/testdata/handwritten/google/cloud/storage/retry.py + repo: https://github.com/googleapis/sphinx-docfx-yaml + startLine: 118 + summary: 'Return True if if_metageneration_match is specified. + + + ' + syntax: + content: is_metageneration_specified(query_params) + parameters: [] + type: function + uid: google.cloud.storage.retry.is_metageneration_specified +references: +- fullName: google.cloud.storage.retry.ConditionalRetryPolicy + isExternal: false + name: ConditionalRetryPolicy + parent: google.cloud.storage.retry + uid: google.cloud.storage.retry.ConditionalRetryPolicy +- fullName: google.cloud.storage.retry.is_etag_in_data + isExternal: false + name: is_etag_in_data + parent: google.cloud.storage.retry + uid: google.cloud.storage.retry.is_etag_in_data +- fullName: google.cloud.storage.retry.is_etag_in_json + isExternal: false + name: is_etag_in_json + parent: google.cloud.storage.retry + uid: google.cloud.storage.retry.is_etag_in_json +- fullName: google.cloud.storage.retry.is_generation_specified + isExternal: false + name: is_generation_specified + parent: google.cloud.storage.retry + uid: google.cloud.storage.retry.is_generation_specified +- fullName: google.cloud.storage.retry.is_metageneration_specified + isExternal: false + name: is_metageneration_specified + parent: google.cloud.storage.retry + uid: google.cloud.storage.retry.is_metageneration_specified diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/index.md b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/index.md new file mode 100644 index 000000000000..f939956767cc --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/index.md @@ -0,0 +1,87 @@ +# Python Client for Google Cloud Storage API + +[![image](https://img.shields.io/badge/support-stable-gold.svg)](https://github.com/googleapis/google-cloud-python/blob/main/README.rst#stability-levels) [![image](https://img.shields.io/pypi/v/google-cloud-storage.svg)](https://pypi.org/project/google-cloud-storage/) [![image](https://img.shields.io/pypi/pyversions/google-cloud-storage.svg)](https://pypi.org/project/google-cloud-storage/) + +[Google Cloud Storage API](https://cloud.google.com/storage): is a durable and highly available object storage service. Google Cloud Storage is almost infinitely scalable and guarantees consistency: when a write succeeds, the latest copy of the object will be returned to any GET, globally. + + +* [Client Library Documentation](https://cloud.google.com/python/docs/reference/storage/latest) + + +* [Product Documentation](https://cloud.google.com/storage) + +## Quick Start + +In order to use this library, you first need to go through the following steps: + + +1. [Select or create a Cloud Platform project.](https://console.cloud.google.com/project) + + +2. [Enable billing for your project.](https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project) + + +3. [Enable the Google Cloud Storage API.](https://cloud.google.com/storage) + + +4. [Setup Authentication.](https://googleapis.dev/python/google-api-core/latest/auth.html) + +### Installation + +Install this library in a [virtualenv](https://virtualenv.pypa.io/en/latest/) using pip. [virtualenv](https://virtualenv.pypa.io/en/latest/) is a tool to +create isolated Python environments. The basic problem it addresses is one of +dependencies and versions, and indirectly permissions. + +With [virtualenv](https://virtualenv.pypa.io/en/latest/), it’s possible to install this library without needing system +install permissions, and without clashing with the installed system +dependencies. + +### Code samples and snippets + +Code samples and snippets live in the samples/ folder. + +#### Supported Python Versions + +Our client libraries are compatible with all current [active](https://devguide.python.org/devcycle/#in-development-main-branch) and [maintenance](https://devguide.python.org/devcycle/#maintenance-branches) versions of +Python. + +Python >= 3.7 + +#### Unsupported Python Versions + +Python <= 3.6 + +If you are using an [end-of-life](https://devguide.python.org/devcycle/#end-of-life-branches) +version of Python, we recommend that you update as soon as possible to an actively supported version. + +#### Mac/Linux + +```console +pip install virtualenv +virtualenv +source /bin/activate +/bin/pip install google-cloud-storage +``` + +#### Windows + +```console +pip install virtualenv +virtualenv +\Scripts\activate +\Scripts\pip.exe install google-cloud-storage +``` + +### Next Steps + + +* Read the [Client Library Documentation](https://cloud.google.com/python/docs/reference/storage/latest) for Google Cloud Storage API +to see other available methods on the client. + + +* Read the [Google Cloud Storage API Product documentation](https://cloud.google.com/storage) to learn +more about the product and see How-to Guides. + + +* View this [README](https://github.com/googleapis/google-cloud-python/blob/main/README.rst) to see the full list of Cloud +APIs that we cover. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/toc.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/toc.yml new file mode 100644 index 000000000000..2a358edbeaf3 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/handwritten/toc.yml @@ -0,0 +1,95 @@ +- items: + - href: index.md + name: Overview + - href: changelog.md + name: Changelog + - items: + - items: + - name: Overview + uid: google.cloud.storage.acl + - name: ACL + uid: google.cloud.storage.acl.ACL + - name: BucketACL + uid: google.cloud.storage.acl.BucketACL + - name: DefaultObjectACL + uid: google.cloud.storage.acl.DefaultObjectACL + - name: ObjectACL + uid: google.cloud.storage.acl.ObjectACL + name: acl + uid: google.cloud.storage.acl + - items: + - name: Overview + uid: google.cloud.storage.batch + - name: Batch + uid: google.cloud.storage.batch.Batch + - name: MIMEApplicationHTTP + uid: google.cloud.storage.batch.MIMEApplicationHTTP + name: batch + uid: google.cloud.storage.batch + - items: + - name: Overview + uid: google.cloud.storage.blob + - name: Blob + uid: google.cloud.storage.blob.Blob + name: blob + uid: google.cloud.storage.blob + - items: + - name: Overview + uid: google.cloud.storage.bucket + - name: Bucket + uid: google.cloud.storage.bucket.Bucket + - name: IAMConfiguration + uid: google.cloud.storage.bucket.IAMConfiguration + - name: LifecycleRuleAbortIncompleteMultipartUpload + uid: google.cloud.storage.bucket.LifecycleRuleAbortIncompleteMultipartUpload + - name: LifecycleRuleConditions + uid: google.cloud.storage.bucket.LifecycleRuleConditions + - name: LifecycleRuleDelete + uid: google.cloud.storage.bucket.LifecycleRuleDelete + - name: LifecycleRuleSetStorageClass + uid: google.cloud.storage.bucket.LifecycleRuleSetStorageClass + name: bucket + uid: google.cloud.storage.bucket + - items: + - name: Overview + uid: google.cloud.storage.client + - name: Client + uid: google.cloud.storage.client.Client + name: client + uid: google.cloud.storage.client + - name: constants + uid: google.cloud.storage.constants + - items: + - name: Overview + uid: google.cloud.storage.fileio + - name: BlobReader + uid: google.cloud.storage.fileio.BlobReader + - name: BlobWriter + uid: google.cloud.storage.fileio.BlobWriter + - name: SlidingBuffer + uid: google.cloud.storage.fileio.SlidingBuffer + name: fileio + uid: google.cloud.storage.fileio + - items: + - name: Overview + uid: google.cloud.storage.hmac_key + - name: HMACKeyMetadata + uid: google.cloud.storage.hmac_key.HMACKeyMetadata + name: hmac_key + uid: google.cloud.storage.hmac_key + - items: + - name: Overview + uid: google.cloud.storage.notification + - name: BucketNotification + uid: google.cloud.storage.notification.BucketNotification + name: notification + uid: google.cloud.storage.notification + - items: + - name: Overview + uid: google.cloud.storage.retry + - name: ConditionalRetryPolicy + uid: google.cloud.storage.retry.ConditionalRetryPolicy + name: retry + uid: google.cloud.storage.retry + name: Storage + name: google-cloud-storage diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/CHANGELOG.md b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/CHANGELOG.md new file mode 100644 index 000000000000..5c312a242a04 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/CHANGELOG.md @@ -0,0 +1,932 @@ +# Changelog + +[PyPI History][1] + +[1]: https://pypi.org/project/google-cloud-storage/#history + +## [2.5.0](https://github.com/googleapis/python-storage/compare/v2.4.0...v2.5.0) (2022-07-24) + + +### Features + +* Custom Placement Config Dual Region Support ([#819](https://github.com/googleapis/python-storage/issues/819)) ([febece7](https://github.com/googleapis/python-storage/commit/febece76802252278bb7626d931973a76561382a)) + + +### Documentation + +* open file-like objects in byte mode for uploads ([#824](https://github.com/googleapis/python-storage/issues/824)) ([4bd3d1d](https://github.com/googleapis/python-storage/commit/4bd3d1ddf21196b075bbd84cdcb553c5d7355b93)) + +## [2.4.0](https://github.com/googleapis/python-storage/compare/v2.3.0...v2.4.0) (2022-06-07) + + +### Features + +* add AbortIncompleteMultipartUpload lifecycle rule ([#765](https://github.com/googleapis/python-storage/issues/765)) ([b2e5150](https://github.com/googleapis/python-storage/commit/b2e5150f191c04acb47ad98cef88512451aff81d)) +* support OLM Prefix/Suffix ([#773](https://github.com/googleapis/python-storage/issues/773)) ([187cf50](https://github.com/googleapis/python-storage/commit/187cf503194cf636640ca8ba787f9e8c216ea763)) + + +### Bug Fixes + +* fix rewrite object in CMEK enabled bucket ([#807](https://github.com/googleapis/python-storage/issues/807)) ([9b3cbf3](https://github.com/googleapis/python-storage/commit/9b3cbf3789c21462eac3c776cd29df12701e792f)) + + +### Documentation + +* fix changelog header to consistent size ([#802](https://github.com/googleapis/python-storage/issues/802)) ([4dd0907](https://github.com/googleapis/python-storage/commit/4dd0907b68e20d1ffcd0fe350831867197917e0d)) +* **samples:** Update the Recovery Point Objective (RPO) sample output ([#725](https://github.com/googleapis/python-storage/issues/725)) ([b0bf411](https://github.com/googleapis/python-storage/commit/b0bf411f8fec8712b3eeb99a2dd33de6d82312f8)) +* Update generation_metageneration.rst with a missing space ([#798](https://github.com/googleapis/python-storage/issues/798)) ([1e7cdb6](https://github.com/googleapis/python-storage/commit/1e7cdb655beb2a61a0d1b984c4d0468ec31bf463)) +* update retry docs ([#808](https://github.com/googleapis/python-storage/issues/808)) ([c365d5b](https://github.com/googleapis/python-storage/commit/c365d5bbd78292adb6861da3cdfae9ab7b39b844)) + +## [2.3.0](https://github.com/googleapis/python-storage/compare/v2.2.1...v2.3.0) (2022-04-12) + + +### Features + +* add dual region bucket support and sample ([#748](https://github.com/googleapis/python-storage/issues/748)) ([752e8ab](https://github.com/googleapis/python-storage/commit/752e8ab42d23afd68738e4d7ca6cdeee416dfd50)) +* track invocation id for retry metrics ([#741](https://github.com/googleapis/python-storage/issues/741)) ([bd56931](https://github.com/googleapis/python-storage/commit/bd5693164e7331df5f14186fd002e72e5203d7ee)) + + +### Bug Fixes + +* **deps:** drop pkg_resources ([#744](https://github.com/googleapis/python-storage/issues/744)) ([e963f33](https://github.com/googleapis/python-storage/commit/e963f33ced2852b64d721d69928b54443461ec9c)) + + +### Documentation + +* fix links in blob module ([#759](https://github.com/googleapis/python-storage/issues/759)) ([9b29314](https://github.com/googleapis/python-storage/commit/9b2931430b0796ffb23ec4efacd82dacad36f40f)) + +## [2.2.1](https://github.com/googleapis/python-storage/compare/v2.2.0...v2.2.1) (2022-03-15) + + +### Bug Fixes + +* remove py.typed marker file for PEP 561 ([#735](https://github.com/googleapis/python-storage/issues/735)) ([f77d2f7](https://github.com/googleapis/python-storage/commit/f77d2f787f435f2f898e9babcdab81225672ad4f)), closes [#734](https://github.com/googleapis/python-storage/issues/734) + +## [2.2.0](https://github.com/googleapis/python-storage/compare/v2.1.0...v2.2.0) (2022-03-14) + + +### Features + +* allow no project in client methods using storage emulator ([#703](https://github.com/googleapis/python-storage/issues/703)) ([bcde0ec](https://github.com/googleapis/python-storage/commit/bcde0ec619d7d303892bcc0863b7f977c79f7649)) + + +### Bug Fixes + +* add user agent in python-storage when calling resumable media ([c7bf615](https://github.com/googleapis/python-storage/commit/c7bf615909a04f3bab3efb1047a9f4ba659bba19)) +* **deps:** require google-api-core>=1.31.5, >=2.3.2 ([#722](https://github.com/googleapis/python-storage/issues/722)) ([e9aab38](https://github.com/googleapis/python-storage/commit/e9aab389f868799d4425133954bad4f1cbb85786)) +* Fix BlobReader handling of interleaved reads and seeks ([#721](https://github.com/googleapis/python-storage/issues/721)) ([5d1cfd2](https://github.com/googleapis/python-storage/commit/5d1cfd2050321481a3bc4acbe80537ea666506fa)) +* retry client side requests timeout ([#727](https://github.com/googleapis/python-storage/issues/727)) ([e0b3b35](https://github.com/googleapis/python-storage/commit/e0b3b354d51e4be7c563d7f2f628a7139df842c0)) + + +### Documentation + +* fixed download_blob_to_file example ([#704](https://github.com/googleapis/python-storage/issues/704)) ([2c94d98](https://github.com/googleapis/python-storage/commit/2c94d98ed21cc768cfa54fac3d734254fc4d8480)) + +## [2.1.0](https://github.com/googleapis/python-storage/compare/v2.0.0...v2.1.0) (2022-01-19) + + +### Features + +* add turbo replication support and samples ([#622](https://github.com/googleapis/python-storage/issues/622)) ([4dafc81](https://github.com/googleapis/python-storage/commit/4dafc815470480ce9de7f0357e331d3fbd0ae9b7)) +* avoid authentication with storage emulator ([#679](https://github.com/googleapis/python-storage/issues/679)) ([8789afa](https://github.com/googleapis/python-storage/commit/8789afaaa1b2bd6f03fae72e3d87ce004ec10129)) +* remove python 3.6 support ([#689](https://github.com/googleapis/python-storage/issues/689)) ([8aa4130](https://github.com/googleapis/python-storage/commit/8aa4130ee068a1922161c8ca54a53a4a51d65ce0)) + +## [2.0.0](https://github.com/googleapis/python-storage/compare/v1.44.0...v2.0.0) (2022-01-12) + + +### ⚠ BREAKING CHANGES + +* Remove Python 2 support (#657) + +### Features + +* Remove Python 2 support ([#657](https://github.com/googleapis/python-storage/issues/657)) ([b611670](https://github.com/googleapis/python-storage/commit/b6116700a4a32d28404c39018138e545f3f7910e)) + +## [1.44.0](https://www.github.com/googleapis/python-storage/compare/v1.43.0...v1.44.0) (2022-01-05) + + +### Features + +* add raw_download kwarg to BlobReader ([#668](https://www.github.com/googleapis/python-storage/issues/668)) ([10cdad6](https://www.github.com/googleapis/python-storage/commit/10cdad630739a324ae0b16a3d14a67ca4c8a23c2)) + + +### Documentation + +* Describe code sample more specifically ([#660](https://www.github.com/googleapis/python-storage/issues/660)) ([0459cb4](https://www.github.com/googleapis/python-storage/commit/0459cb4e866696c46385a5ad72e2a85db810a36b)) +* refresh readme instructions ([#667](https://www.github.com/googleapis/python-storage/issues/667)) ([ceb9314](https://www.github.com/googleapis/python-storage/commit/ceb931403a755f2a0bdc20144287dbc4700c3360)) +* This is just a simple PR to better describe what the code is doing in the comments. ([0459cb4](https://www.github.com/googleapis/python-storage/commit/0459cb4e866696c46385a5ad72e2a85db810a36b)) +* use writeable streamin example for 'download_blob_to_file' ([#676](https://www.github.com/googleapis/python-storage/issues/676)) ([96092d4](https://www.github.com/googleapis/python-storage/commit/96092d4be36be478f9671e8940de4fd09cc6f7f0)) + +## [1.43.0](https://www.github.com/googleapis/python-storage/compare/v1.42.3...v1.43.0) (2021-11-15) + + +### Features + +* add ignore_flush parameter to BlobWriter ([#644](https://www.github.com/googleapis/python-storage/issues/644)) ([af9c9dc](https://www.github.com/googleapis/python-storage/commit/af9c9dc83d8582167b74105167af17c9809455de)) +* add support for Python 3.10 ([#615](https://www.github.com/googleapis/python-storage/issues/615)) ([f81a2d0](https://www.github.com/googleapis/python-storage/commit/f81a2d054616c1ca1734997a16a8f47f98ab346b)) + + +### Bug Fixes + +* raise a ValueError in BucketNotification.create() if a topic name is not set ([#617](https://www.github.com/googleapis/python-storage/issues/617)) ([9dd78df](https://www.github.com/googleapis/python-storage/commit/9dd78df444d21af51af7858e8958b505a26c0b79)) + + +### Documentation + +* add contributing and authoring guides under samples/ ([#633](https://www.github.com/googleapis/python-storage/issues/633)) ([420591a](https://www.github.com/googleapis/python-storage/commit/420591a2b71f823dbe80f4a4405d8a514f87e0fb)) +* add links to samples and how to guides ([#641](https://www.github.com/googleapis/python-storage/issues/641)) ([49f78b0](https://www.github.com/googleapis/python-storage/commit/49f78b09fed6d9f486639fd0a72542c30a0df084)) +* add README to samples subdirectory ([#639](https://www.github.com/googleapis/python-storage/issues/639)) ([58af882](https://www.github.com/googleapis/python-storage/commit/58af882c047c31f59486513c568737082bca6350)) +* update samples readme with cli args ([#651](https://www.github.com/googleapis/python-storage/issues/651)) ([75dda81](https://www.github.com/googleapis/python-storage/commit/75dda810e808074d18dfe7915f1403ad01bf2f02)) + +## [1.42.3](https://www.github.com/googleapis/python-storage/compare/v1.42.2...v1.42.3) (2021-09-30) + + +### Bug Fixes + +* changeover unspecified to inherited ([#603](https://www.github.com/googleapis/python-storage/issues/603)) ([283a419](https://www.github.com/googleapis/python-storage/commit/283a4196865d9b5275e87f54737d1faee40cc946)) +* check response code in batch.finish ([#609](https://www.github.com/googleapis/python-storage/issues/609)) ([318a286](https://www.github.com/googleapis/python-storage/commit/318a286d709427bfe9f3a37e933c255ac51b3033)) +* skip tests that use unspecified pap until we get the change in ([#600](https://www.github.com/googleapis/python-storage/issues/600)) ([38b9b55](https://www.github.com/googleapis/python-storage/commit/38b9b5582e2c6bbd1acab2b49410084170466fad)) + +## [1.42.2](https://www.github.com/googleapis/python-storage/compare/v1.42.1...v1.42.2) (2021-09-16) + + +### Bug Fixes + +* add preconditions and retry config support to ACL patch operationss ([#586](https://www.github.com/googleapis/python-storage/issues/586)) ([4333caf](https://www.github.com/googleapis/python-storage/commit/4333caf3674d78b3dfbc161a796abac604d57953)) +* add unpinned protobuf for python3 ([#592](https://www.github.com/googleapis/python-storage/issues/592)) ([53f7ad0](https://www.github.com/googleapis/python-storage/commit/53f7ad0204ad425011da9162d1a78f8276c837eb)) +* pin six as a required dependency ([#589](https://www.github.com/googleapis/python-storage/issues/589)) ([9ca97bf](https://www.github.com/googleapis/python-storage/commit/9ca97bf9139c71cd033c78af73da904b27d8ff50)) + +## [1.42.1](https://www.github.com/googleapis/python-storage/compare/v1.42.0...v1.42.1) (2021-09-07) + + +### Bug Fixes + +* do not append duplicates to user agent string ([#570](https://www.github.com/googleapis/python-storage/issues/570)) ([57cf3a1](https://www.github.com/googleapis/python-storage/commit/57cf3a1f27292939ed097ef8afa3f4392c4b83e0)) + + +### Documentation + +* pass explicit 'client' in '{Blob.Bucket}.from_string' examples ([#545](https://www.github.com/googleapis/python-storage/issues/545)) ([6eff22d](https://www.github.com/googleapis/python-storage/commit/6eff22db0e8c8689208ee52fa815f3ea00675094)) + +## [1.42.0](https://www.github.com/googleapis/python-storage/compare/v1.41.1...v1.42.0) (2021-08-05) + + +### Features + +* add 'page_size' parameter to 'Bucket.list_blobs, list_buckets ([#520](https://www.github.com/googleapis/python-storage/issues/520)) ([c5f4ad8](https://www.github.com/googleapis/python-storage/commit/c5f4ad8fddd1849a4229b0126c4c022bccb90128)) + + +### Bug Fixes + +* **deps:** add explicit ranges for 'google-api-core' and 'google-auth' ([#530](https://www.github.com/googleapis/python-storage/issues/530)) ([310f207](https://www.github.com/googleapis/python-storage/commit/310f207411da0382af310172344f19c644c14e6a)) +* downloading no longer marks metadata fields as 'changed' ([#523](https://www.github.com/googleapis/python-storage/issues/523)) ([160d1ec](https://www.github.com/googleapis/python-storage/commit/160d1ecb41f1f269b25cb68b2d2f7daf418bf01c)) +* make 'requests.exceptions.ChunkedEncodingError retryable by default ([#526](https://www.github.com/googleapis/python-storage/issues/526)) ([4abb403](https://www.github.com/googleapis/python-storage/commit/4abb40310eca7ec45afc4bc5e4dfafbe083e74d2)) + + +### Documentation + +* update supported / removed Python versions in README ([#519](https://www.github.com/googleapis/python-storage/issues/519)) ([1f1b138](https://www.github.com/googleapis/python-storage/commit/1f1b138865fb171535ee0cf768aff1987ed58914)) + +## [1.41.1](https://www.github.com/googleapis/python-storage/compare/v1.41.0...v1.41.1) (2021-07-20) + + +### Bug Fixes + +* **deps:** pin `{api,cloud}-core`, `auth` to allow 2.x versions on Python 3 ([#512](https://www.github.com/googleapis/python-storage/issues/512)) ([4d7500e](https://www.github.com/googleapis/python-storage/commit/4d7500e39c51efd817b8363b69c88be040f3edb8)) +* remove trailing commas from error message constants ([#505](https://www.github.com/googleapis/python-storage/issues/505)) ([d4a86ce](https://www.github.com/googleapis/python-storage/commit/d4a86ceb7a7c5e00ba7bae37c7078d52478040ff)), closes [#501](https://www.github.com/googleapis/python-storage/issues/501) + + +### Documentation + +* replace usage of deprecated function `download_as_string` in docs ([#508](https://www.github.com/googleapis/python-storage/issues/508)) ([8dfa4d4](https://www.github.com/googleapis/python-storage/commit/8dfa4d429dce94b671dc3e3755e52ab82733f61a)) + +## [1.41.0](https://www.github.com/googleapis/python-storage/compare/v1.40.0...v1.41.0) (2021-07-13) + + +### Features + +* add support for Etag headers on reads ([#489](https://www.github.com/googleapis/python-storage/issues/489)) ([741d3fd](https://www.github.com/googleapis/python-storage/commit/741d3fda4e4280022cede29ebeb7c2ea09e73b6f)) + + +### Bug Fixes + +* **deps:** update minimum dependency versions to pick up bugfixes ([#496](https://www.github.com/googleapis/python-storage/issues/496)) ([92251a5](https://www.github.com/googleapis/python-storage/commit/92251a5c8ea4d663773506eb1c630201a657aa69)), closes [#494](https://www.github.com/googleapis/python-storage/issues/494) +* populate etag / generation / metageneration properties during download ([#488](https://www.github.com/googleapis/python-storage/issues/488)) ([49ba14c](https://www.github.com/googleapis/python-storage/commit/49ba14c9c47dbe6bc2bb45d53bbe5621c131fbcb)) +* revise and rename is_etag_in_json(data) ([#483](https://www.github.com/googleapis/python-storage/issues/483)) ([0a52546](https://www.github.com/googleapis/python-storage/commit/0a5254647bf1155874fe48f3891bcc34a76b0b81)) + +## [1.40.0](https://www.github.com/googleapis/python-storage/compare/v1.39.0...v1.40.0) (2021-06-30) + + +### Features + +* add preconditions and retry configuration to blob.create_resumable_upload_session ([#484](https://www.github.com/googleapis/python-storage/issues/484)) ([0ae35ee](https://www.github.com/googleapis/python-storage/commit/0ae35eef0fe82fe60bc095c4b183102bb1dabeeb)) +* add public access prevention to bucket IAM configuration ([#304](https://www.github.com/googleapis/python-storage/issues/304)) ([e3e57a9](https://www.github.com/googleapis/python-storage/commit/e3e57a9c779d6b87852063787f19e27c76b1bb14)) + + +### Bug Fixes + +* replace default retry for upload operations ([#480](https://www.github.com/googleapis/python-storage/issues/480)) ([c027ccf](https://www.github.com/googleapis/python-storage/commit/c027ccf4279fb05e041754294f10744b7d81beea)) + +## [1.39.0](https://www.github.com/googleapis/python-storage/compare/v1.38.0...v1.39.0) (2021-06-21) + + +### Features + +* media operation retries can be configured using the same interface as with non-media operation ([#447](https://www.github.com/googleapis/python-storage/issues/447)) ([0dbbb8a](https://www.github.com/googleapis/python-storage/commit/0dbbb8ac17a4b632707485ee6c7cc15e4670efaa)) + + +### Bug Fixes + +* add ConnectionError to default retry ([#445](https://www.github.com/googleapis/python-storage/issues/445)) ([8344253](https://www.github.com/googleapis/python-storage/commit/8344253a1969b9d04b81f87a6d7bddd3ddb55006)) +* apply idempotency policies for ACLs ([#458](https://www.github.com/googleapis/python-storage/issues/458)) ([2232f38](https://www.github.com/googleapis/python-storage/commit/2232f38933dbdfeb4f6585291794d332771ffdf2)) +* replace python lifecycle action parsing ValueError with warning ([#437](https://www.github.com/googleapis/python-storage/issues/437)) ([2532d50](https://www.github.com/googleapis/python-storage/commit/2532d506b44fc1ef0fa0a996822d29e7459c465a)) +* revise blob.compose query parameters `if_generation_match` ([#454](https://www.github.com/googleapis/python-storage/issues/454)) ([70d19e7](https://www.github.com/googleapis/python-storage/commit/70d19e72831dee112bb07f38b50beef4890c1155)) + + +### Documentation + +* streamline 'timeout' / 'retry' docs in docstrings ([#461](https://www.github.com/googleapis/python-storage/issues/461)) ([78b2eba](https://www.github.com/googleapis/python-storage/commit/78b2eba81003b437cd24f2b8d269ea2455682507)) +* streamline docstrings for conditional parmas ([#464](https://www.github.com/googleapis/python-storage/issues/464)) ([6999370](https://www.github.com/googleapis/python-storage/commit/69993702390322df07cc2e818003186a47524c2b)) + +## [1.38.0](https://www.github.com/googleapis/python-storage/compare/v1.37.1...v1.38.0) (2021-04-26) + + +### Features + +* add getters and setters for encryption_key and kms_key_name ([#409](https://www.github.com/googleapis/python-storage/issues/409)) ([2adfb59](https://www.github.com/googleapis/python-storage/commit/2adfb593d5ad19320affe480455568c1410b9d93)) + + +### Bug Fixes + +* retry auth.TransportError errors ([#418](https://www.github.com/googleapis/python-storage/issues/418)) ([23a8db8](https://www.github.com/googleapis/python-storage/commit/23a8db839909a0781343cb18edffaea06a0b7092)) + + +### Documentation + +* revise docstrings for generate_signed_url ([#408](https://www.github.com/googleapis/python-storage/issues/408)) ([f090548](https://www.github.com/googleapis/python-storage/commit/f090548437142b635191e90dcee1acd4c38e565c)) + +## [1.37.1](https://www.github.com/googleapis/python-storage/compare/v1.37.0...v1.37.1) (2021-04-02) + + +### Bug Fixes + +* Ensure consistency check in test runs even if expected error occurs ([#402](https://www.github.com/googleapis/python-storage/issues/402)) ([416bcd4](https://www.github.com/googleapis/python-storage/commit/416bcd42406ec57e51f04e5d9b0c58509f80520c)) +* silence expected errors for routine operations on BlobReader ([#400](https://www.github.com/googleapis/python-storage/issues/400)) ([d52853b](https://www.github.com/googleapis/python-storage/commit/d52853b420f50012e02c395f5407e3018922c048)) + +## [1.37.0](https://www.github.com/googleapis/python-storage/compare/v1.36.2...v1.37.0) (2021-03-24) + + +### Features + +* add blob.open() for file-like I/O ([#385](https://www.github.com/googleapis/python-storage/issues/385)) ([440a0a4](https://www.github.com/googleapis/python-storage/commit/440a0a4ffe00b1f7c562b0e9c1e47dbadeca33e1)), closes [#29](https://www.github.com/googleapis/python-storage/issues/29) + + +### Bug Fixes + +* update user_project usage and documentation in bucket/client class methods ([#396](https://www.github.com/googleapis/python-storage/issues/396)) ([1a2734b](https://www.github.com/googleapis/python-storage/commit/1a2734ba6d316ce51e4e141571331e86196462b9)) + +## [1.36.2](https://www.github.com/googleapis/python-storage/compare/v1.36.1...v1.36.2) (2021-03-09) + + +### Bug Fixes + +* update batch connection to request api endpoint info from client ([#392](https://www.github.com/googleapis/python-storage/issues/392)) ([91fc6d9](https://www.github.com/googleapis/python-storage/commit/91fc6d9870a36308b15a827ed6a691e5b4669b62)) + +## [1.36.1](https://www.github.com/googleapis/python-storage/compare/v1.36.0...v1.36.1) (2021-02-19) + + +### Bug Fixes + +* allow metadata keys to be cleared ([#383](https://www.github.com/googleapis/python-storage/issues/383)) ([79d27da](https://www.github.com/googleapis/python-storage/commit/79d27da9fe842e44a9091076ea0ef52c5ef5ff72)), closes [#381](https://www.github.com/googleapis/python-storage/issues/381) +* allow signed url version v4 without signed credentials ([#356](https://www.github.com/googleapis/python-storage/issues/356)) ([3e69bf9](https://www.github.com/googleapis/python-storage/commit/3e69bf92496616c5de28094dd42260b35c3bf982)) +* correctly encode bytes for V2 signature ([#382](https://www.github.com/googleapis/python-storage/issues/382)) ([f44212b](https://www.github.com/googleapis/python-storage/commit/f44212b7b91a67ca661898400fe632f9fb3ec8f6)) + +## [1.36.0](https://www.github.com/googleapis/python-storage/compare/v1.35.1...v1.36.0) (2021-02-10) + + +### Features + +* add mtls support ([#367](https://www.github.com/googleapis/python-storage/issues/367)) ([d35ab35](https://www.github.com/googleapis/python-storage/commit/d35ab3537d1828505f614d32b79b67173c9438c0)) + + +### Bug Fixes + +* correctly decode times without microseconds ([#375](https://www.github.com/googleapis/python-storage/issues/375)) ([37a1eb5](https://www.github.com/googleapis/python-storage/commit/37a1eb54095b4f857771784007dd049ffafbc11d)), closes [#363](https://www.github.com/googleapis/python-storage/issues/363) +* expose num_retries parameter for blob upload methods ([#353](https://www.github.com/googleapis/python-storage/issues/353)) ([fdabd6a](https://www.github.com/googleapis/python-storage/commit/fdabd6af74da4b15fbb5d40fb8f80a9b478b9607)), closes [#352](https://www.github.com/googleapis/python-storage/issues/352) +* pass the unused parameter ([#349](https://www.github.com/googleapis/python-storage/issues/349)) ([5c60d24](https://www.github.com/googleapis/python-storage/commit/5c60d240aa98d2a1dcc6933d6da2ce60ea1b7559)) +* set custom_time on uploads ([#374](https://www.github.com/googleapis/python-storage/issues/374)) ([f048be1](https://www.github.com/googleapis/python-storage/commit/f048be10416f51cea4e6c8c5b805df7b5d9c4d32)), closes [#372](https://www.github.com/googleapis/python-storage/issues/372) + +## [1.35.1](https://www.github.com/googleapis/python-storage/compare/v1.35.0...v1.35.1) (2021-01-28) + + +### Bug Fixes + +* address incorrect usage of request preconditions ([#366](https://www.github.com/googleapis/python-storage/issues/366)) ([321658c](https://www.github.com/googleapis/python-storage/commit/321658c3b9ccaf22d08dd881c93206590f8275b7)) +* Amend default retry behavior for bucket operations on client ([#358](https://www.github.com/googleapis/python-storage/issues/358)) ([b91e57d](https://www.github.com/googleapis/python-storage/commit/b91e57d6ca314ac4feaec30bf355fcf7ac4468c0)) + +## [1.35.0](https://www.github.com/googleapis/python-storage/compare/v1.34.0...v1.35.0) (2020-12-14) + + +### Features + +* support ConnectionError retries for media operations ([#342](https://www.github.com/googleapis/python-storage/issues/342)) ([e55b25b](https://www.github.com/googleapis/python-storage/commit/e55b25be1e32f17b17bffe1da99fca5062f180cb)) + +## [1.34.0](https://www.github.com/googleapis/python-storage/compare/v1.33.0...v1.34.0) (2020-12-11) + + +### Features + +* make retry parameter public and added in other methods ([#331](https://www.github.com/googleapis/python-storage/issues/331)) ([910e34c](https://www.github.com/googleapis/python-storage/commit/910e34c57de5823bc3a04adbd87cbfe27fb41882)) + + +### Bug Fixes + +* avoid triggering global logging config ([#333](https://www.github.com/googleapis/python-storage/issues/333)) ([602108a](https://www.github.com/googleapis/python-storage/commit/602108a976503271fe0d85c8d7891ce8083aca89)), closes [#332](https://www.github.com/googleapis/python-storage/issues/332) +* fall back to 'charset' of 'content_type' in 'download_as_text' ([#326](https://www.github.com/googleapis/python-storage/issues/326)) ([63ff233](https://www.github.com/googleapis/python-storage/commit/63ff23387f5873c609490be8e58d69ba34a10a5e)), closes [#319](https://www.github.com/googleapis/python-storage/issues/319) +* fix conditional retry handling of camelCase query params ([#340](https://www.github.com/googleapis/python-storage/issues/340)) ([4ff6141](https://www.github.com/googleapis/python-storage/commit/4ff614161f6a2654a59706f4f72b5fbb614e70ec)) +* retry uploads only conditionally ([#316](https://www.github.com/googleapis/python-storage/issues/316)) ([547740c](https://www.github.com/googleapis/python-storage/commit/547740c0a898492e76ce5e60dd20c7ddb8a53d1f)) +* update 'custom_time' setter to record change ([#323](https://www.github.com/googleapis/python-storage/issues/323)) ([5174154](https://www.github.com/googleapis/python-storage/commit/5174154fe73bb6581efc3cd32ebe12014ceab306)), closes [#322](https://www.github.com/googleapis/python-storage/issues/322) + +## [1.33.0](https://www.github.com/googleapis/python-storage/compare/v1.32.0...v1.33.0) (2020-11-16) + + +### Features + +* add classifiers for python3.9 and remove for python3.5 ([#295](https://www.github.com/googleapis/python-storage/issues/295)) ([f072825](https://www.github.com/googleapis/python-storage/commit/f072825ce03d774fd95d9fe3db95a8c7130b0e8a)) +* add testing support for Python 3.9, drop Python 3.5 ([#313](https://www.github.com/googleapis/python-storage/issues/313)) ([fa14009](https://www.github.com/googleapis/python-storage/commit/fa140092877a277abbb23785657590a274a86d61)) + + +### Bug Fixes + +* use passed-in `client` within `Blob.from_string` and helpers ([#290](https://www.github.com/googleapis/python-storage/issues/290)) ([d457ce3](https://www.github.com/googleapis/python-storage/commit/d457ce3e161555c9117ae288ec0c9cd5f8d5fe3a)), closes [#286](https://www.github.com/googleapis/python-storage/issues/286) +* preserve `metadata` value when uploading new file content ([#298](https://www.github.com/googleapis/python-storage/issues/298)) ([5ab6b0d](https://www.github.com/googleapis/python-storage/commit/5ab6b0d9a2b27ae830740a7a0226fc1e241e9ec4)), closes [#293](https://www.github.com/googleapis/python-storage/issues/293) + +## [1.32.0](https://www.github.com/googleapis/python-storage/compare/v1.31.2...v1.32.0) (2020-10-16) + + +### Features + +* retry API calls with exponential backoff ([#287](https://www.github.com/googleapis/python-storage/issues/287)) ([fbe5d9c](https://www.github.com/googleapis/python-storage/commit/fbe5d9ca8684c6a992dcdee977fc8dd012a96a5c)) + + +### Bug Fixes + +* field policy return string ([#282](https://www.github.com/googleapis/python-storage/issues/282)) ([c356b84](https://www.github.com/googleapis/python-storage/commit/c356b8484a758548d5f4823a495ab70c798cfaaf)) +* self-upload files for Unicode system test ([#296](https://www.github.com/googleapis/python-storage/issues/296)) ([6f865d9](https://www.github.com/googleapis/python-storage/commit/6f865d97a19278884356055dfeeaae92f7c63cc1)) +* use version.py for versioning, avoid issues with discovering version via get_distribution ([#288](https://www.github.com/googleapis/python-storage/issues/288)) ([fcd1c4f](https://www.github.com/googleapis/python-storage/commit/fcd1c4f7c947eb95d6937783fd69670a570f145e)) + +## [1.31.2](https://www.github.com/googleapis/python-storage/compare/v1.31.1...v1.31.2) (2020-09-23) + + +### Documentation + +* fix docstring example for 'blob.generate_signed_url' ([#278](https://www.github.com/googleapis/python-storage/issues/278)) ([2dc91c9](https://www.github.com/googleapis/python-storage/commit/2dc91c947e3693023b4478a15c460693808ea2d9)) + +## [1.31.1](https://www.github.com/googleapis/python-storage/compare/v1.31.0...v1.31.1) (2020-09-16) + + +### Bug Fixes + +* add requests as a dependency ([#271](https://www.github.com/googleapis/python-storage/issues/271)) ([ec52b38](https://www.github.com/googleapis/python-storage/commit/ec52b38df211fad18a86d7e16d83db79de59d5f5)) +* preserve existing blob hashes when 'X-Goog-Hash header' is not present ([#267](https://www.github.com/googleapis/python-storage/issues/267)) ([277afb8](https://www.github.com/googleapis/python-storage/commit/277afb83f464d77b163f2722272092df4180411e)) +* **blob:** base64 includes additional characters ([#258](https://www.github.com/googleapis/python-storage/issues/258)) ([cf0774a](https://www.github.com/googleapis/python-storage/commit/cf0774aa8ffd45d340aff9a7d2236d8d65c8ae93)) + + +### Documentation + +* add docs signed_url expiration take default utc ([#250](https://www.github.com/googleapis/python-storage/issues/250)) ([944ab18](https://www.github.com/googleapis/python-storage/commit/944ab1827b3ca0bd1d3aafc2829245290e9bde59)) + +## [1.31.0](https://www.github.com/googleapis/python-storage/compare/v1.30.0...v1.31.0) (2020-08-26) + + +### Features + +* add configurable checksumming for blob uploads and downloads ([#246](https://www.github.com/googleapis/python-storage/issues/246)) ([23b7d1c](https://www.github.com/googleapis/python-storage/commit/23b7d1c3155deae3c804c510dee3a7cec97cd46c)) +* add support for 'Blob.custom_time' and lifecycle rules ([#199](https://www.github.com/googleapis/python-storage/issues/199)) ([180873d](https://www.github.com/googleapis/python-storage/commit/180873de139f7f8e00b7bef423bc15760cf68cc2)) +* error message return from api ([#235](https://www.github.com/googleapis/python-storage/issues/235)) ([a8de586](https://www.github.com/googleapis/python-storage/commit/a8de5868f32b45868f178f420138fcd2fe42f5fd)) +* **storage:** add support of daysSinceNoncurrentTime and noncurrentTimeBefore ([#162](https://www.github.com/googleapis/python-storage/issues/162)) ([136c097](https://www.github.com/googleapis/python-storage/commit/136c0970f8ef7ad4751104e3b8b7dd3204220a67)) +* pass 'client_options' to base class ctor ([#225](https://www.github.com/googleapis/python-storage/issues/225)) ([e1f91fc](https://www.github.com/googleapis/python-storage/commit/e1f91fcca6c001bc3b0c5f759a7a003fcf60c0a6)), closes [#210](https://www.github.com/googleapis/python-storage/issues/210) +* rename 'Blob.download_as_{string,bytes}', add 'Blob.download_as_text' ([#182](https://www.github.com/googleapis/python-storage/issues/182)) ([73107c3](https://www.github.com/googleapis/python-storage/commit/73107c35f23c4a358e957c2b8188300a7fa958fe)) + + +### Bug Fixes + +* change datetime.now to utcnow ([#251](https://www.github.com/googleapis/python-storage/issues/251)) ([3465d08](https://www.github.com/googleapis/python-storage/commit/3465d08e098edb250dee5e97d1fb9ded8bae5700)), closes [#228](https://www.github.com/googleapis/python-storage/issues/228) +* extract hashes correctly during download ([#238](https://www.github.com/googleapis/python-storage/issues/238)) ([23cfb65](https://www.github.com/googleapis/python-storage/commit/23cfb65c3a3b10759c67846e162e4ed77a3f5307)) +* repair mal-formed docstring ([#255](https://www.github.com/googleapis/python-storage/issues/255)) ([e722376](https://www.github.com/googleapis/python-storage/commit/e722376371cb8a3acc46d6c84fb41f4e874f41aa)) + + +### Documentation + +* update docs build (via synth) ([#222](https://www.github.com/googleapis/python-storage/issues/222)) ([4c5adfa](https://www.github.com/googleapis/python-storage/commit/4c5adfa6e05bf018d72ee1a7e99679fd55f2c662)) + +## [1.30.0](https://www.github.com/googleapis/python-storage/compare/v1.29.0...v1.30.0) (2020-07-24) + + +### Features + +* add timeouts to Blob methods where missing ([#185](https://www.github.com/googleapis/python-storage/issues/185)) ([6eeb855](https://www.github.com/googleapis/python-storage/commit/6eeb855aa0e6a7835d1d4f6e72951e43af22ab57)) +* auto-populate standard headers for non-chunked downloads ([#204](https://www.github.com/googleapis/python-storage/issues/204)) ([d8432cd](https://www.github.com/googleapis/python-storage/commit/d8432cd65a4e9b38eebd1ade2ff00f2f44bb0ef6)), closes [#24](https://www.github.com/googleapis/python-storage/issues/24) +* migrate to Service Account Credentials API ([#189](https://www.github.com/googleapis/python-storage/issues/189)) ([e4990d0](https://www.github.com/googleapis/python-storage/commit/e4990d06043dbd8d1a417f3a1a67fe8746071f1c)) + + +### Bug Fixes + +* add multiprocessing.rst to synthool excludes ([#186](https://www.github.com/googleapis/python-storage/issues/186)) ([4d76e38](https://www.github.com/googleapis/python-storage/commit/4d76e3882210ed2818a43256265f6df31348d410)) + + +### Documentation + +* fix indent in code blocks ([#171](https://www.github.com/googleapis/python-storage/issues/171)) ([62d1543](https://www.github.com/googleapis/python-storage/commit/62d1543e18040b286b23464562aa6eb998074c54)), closes [#170](https://www.github.com/googleapis/python-storage/issues/170) +* remove doubled word in docstring ([#209](https://www.github.com/googleapis/python-storage/issues/209)) ([7a4e7a5](https://www.github.com/googleapis/python-storage/commit/7a4e7a5974abedb0b7b2e110cacbfcd0a40346b6)) + + +### Documentation + +* fix indent in code blocks ([#171](https://www.github.com/googleapis/python-storage/issues/171)) ([62d1543](https://www.github.com/googleapis/python-storage/commit/62d1543e18040b286b23464562aa6eb998074c54)), closes [#170](https://www.github.com/googleapis/python-storage/issues/170) +* remove doubled word in docstring ([#209](https://www.github.com/googleapis/python-storage/issues/209)) ([7a4e7a5](https://www.github.com/googleapis/python-storage/commit/7a4e7a5974abedb0b7b2e110cacbfcd0a40346b6)) + + +### Dependencies + +* prep for grmp-1.0.0 release ([#211](https://www.github.com/googleapis/python-storage/issues/211)) ([55bae9a](https://www.github.com/googleapis/python-storage/commit/55bae9a0e7c0db512c10c6b3b621cd2ef05c9729)) + + +## [1.29.0](https://www.github.com/googleapis/python-storage/compare/v1.28.1...v1.29.0) (2020-06-09) + + +### Features + +* add *generation*match args into Blob.compose() ([#122](https://www.github.com/googleapis/python-storage/issues/122)) ([dc01c59](https://www.github.com/googleapis/python-storage/commit/dc01c59e036164326aeeea164098cf2e6e0dc12c)) +* add Bucket.reload() and Bucket.update() wrappers to restrict generation match args ([#153](https://www.github.com/googleapis/python-storage/issues/153)) ([76dd9ac](https://www.github.com/googleapis/python-storage/commit/76dd9ac7e8b7765defc5b521cfe059e08e33c65c)), closes [#127](https://www.github.com/googleapis/python-storage/issues/127) +* add helper for bucket bound hostname URLs ([#137](https://www.github.com/googleapis/python-storage/issues/137)) ([b26f9fa](https://www.github.com/googleapis/python-storage/commit/b26f9fa8a767b7d5affea8d2c4b87163ce979fd2)), closes [#121](https://www.github.com/googleapis/python-storage/issues/121) +* add if*generation*match support for Bucket.rename_blob() ([#141](https://www.github.com/googleapis/python-storage/issues/141)) ([f52efc8](https://www.github.com/googleapis/python-storage/commit/f52efc807355c82aa3ea621cdadcc316175f0abf)) +* add if*generation*Match support, pt1 ([#123](https://www.github.com/googleapis/python-storage/issues/123)) ([0944442](https://www.github.com/googleapis/python-storage/commit/094444280dd7b7735e24071e5381508cbd392260)) +* add offset and includeTrailingPrefix options to list_blobs ([#125](https://www.github.com/googleapis/python-storage/issues/125)) ([d84c0dd](https://www.github.com/googleapis/python-storage/commit/d84c0ddfd00fa731acfe9899c668041456b08ab7)) +* Create CODEOWNERS ([#135](https://www.github.com/googleapis/python-storage/issues/135)) ([32a8d55](https://www.github.com/googleapis/python-storage/commit/32a8d55b6ec56a9f7c0a3502fbe23c1ba1cc8ad2)) + + +### Bug Fixes + +* add documentaion of list_blobs with user project ([#147](https://www.github.com/googleapis/python-storage/issues/147)) ([792b21f](https://www.github.com/googleapis/python-storage/commit/792b21fd2263b518d56f79cab6a4a1bb06c6e4e7)) +* add projection parameter to blob.reload method ([#146](https://www.github.com/googleapis/python-storage/issues/146)) ([ddad20b](https://www.github.com/googleapis/python-storage/commit/ddad20b3c3d2e6bf482e34dad85fa4b0ff90e1b1)) +* add unused variables to method generation match ([#152](https://www.github.com/googleapis/python-storage/issues/152)) ([f6574bb](https://www.github.com/googleapis/python-storage/commit/f6574bb84c60c30989d05dba97b423579360cdb2)) +* change the method names in snippets file ([#161](https://www.github.com/googleapis/python-storage/issues/161)) ([e516ed9](https://www.github.com/googleapis/python-storage/commit/e516ed9be518e30df4e201d3242f979c0b081086)) +* fix upload object with bucket cmek enabled ([#158](https://www.github.com/googleapis/python-storage/issues/158)) ([5f27ffa](https://www.github.com/googleapis/python-storage/commit/5f27ffa3b1b55681453b594a0ef9e2811fc5f0c8)) +* set default POST policy scheme to "http" ([#172](https://www.github.com/googleapis/python-storage/issues/172)) ([90c020d](https://www.github.com/googleapis/python-storage/commit/90c020d69a69ebc396416e4086a2e0838932130c)) + +## [1.28.1](https://www.github.com/googleapis/python-storage/compare/v1.28.0...v1.28.1) (2020-04-28) + + +### Bug Fixes + +* anonymous credentials for private bucket ([#107](https://www.github.com/googleapis/python-storage/issues/107)) ([6152ab4](https://www.github.com/googleapis/python-storage/commit/6152ab4067d39ba824f9b6a17b83859dd7236cec)) +* add bucket name into POST policy conditions ([#118](https://www.github.com/googleapis/python-storage/issues/118)) ([311ecab](https://www.github.com/googleapis/python-storage/commit/311ecabf8acc3018cef0697dd29483693f7722b9)) + +## [1.28.0](https://www.github.com/googleapis/python-storage/compare/v1.27.0...v1.28.0) (2020-04-22) + + +### Features + +* add arguments for *GenerationMatch uploading options ([#111](https://www.github.com/googleapis/python-storage/issues/111)) ([b11aa5f](https://www.github.com/googleapis/python-storage/commit/b11aa5f00753b094580847bc62c154ae0e584dbc)) + + +### Bug Fixes + +* fix incorrect mtime by UTC offset ([#42](https://www.github.com/googleapis/python-storage/issues/42)) ([76bd652](https://www.github.com/googleapis/python-storage/commit/76bd652a3078d94e03e566b6a387fc488ab26910)) +* remove expiration strict conversion ([#106](https://www.github.com/googleapis/python-storage/issues/106)) ([9550dad](https://www.github.com/googleapis/python-storage/commit/9550dad6e63e249110fc9dcda245061b76dacdcf)), closes [#105](https://www.github.com/googleapis/python-storage/issues/105) + +## [1.27.0](https://www.github.com/googleapis/python-storage/compare/v1.26.0...v1.27.0) (2020-04-01) + + +### Features + +* generate signed URLs for blobs/buckets using virtual hostname ([#58](https://www.github.com/googleapis/python-storage/issues/58)) ([23df542](https://www.github.com/googleapis/python-storage/commit/23df542d0669852b05139023d5ef1ae14a09f4c7)) +* Add cname support for V4 signature ([#72](https://www.github.com/googleapis/python-storage/issues/72)) ([cc853af](https://www.github.com/googleapis/python-storage/commit/cc853af6bf8e44e5b16e8cdfb3a275629ffb1f27)) +* add conformance tests for virtual hosted style signed URLs ([#83](https://www.github.com/googleapis/python-storage/issues/83)) ([5adc8b0](https://www.github.com/googleapis/python-storage/commit/5adc8b0e6ffe28185a4085cd1fc8c1b4998094aa)) +* add get notification method ([#77](https://www.github.com/googleapis/python-storage/issues/77)) ([f602252](https://www.github.com/googleapis/python-storage/commit/f6022521bee0824e1b291211703afc5eae6c6891)) +* improve v4 signature query parameters encoding ([#48](https://www.github.com/googleapis/python-storage/issues/48)) ([8df0b55](https://www.github.com/googleapis/python-storage/commit/8df0b554a1904787889309707f08c6b8683cad44)) + + +### Bug Fixes + +* fix blob metadata to None regression ([#60](https://www.github.com/googleapis/python-storage/issues/60)) ([a834d1b](https://www.github.com/googleapis/python-storage/commit/a834d1b54aa96152ced4d841c4e0c241acd2d8d8)) +* add classifer for Python 3.8 ([#63](https://www.github.com/googleapis/python-storage/issues/63)) ([1b9b6bc](https://www.github.com/googleapis/python-storage/commit/1b9b6bc2601ee336a8399266852fb850e368b30a)) +* make v4 signing formatting consistent w/ spec ([#56](https://www.github.com/googleapis/python-storage/issues/56)) ([8712da8](https://www.github.com/googleapis/python-storage/commit/8712da84c93600a736e72a097c42a49b4724347d)) +* use correct IAM object admin role ([#71](https://www.github.com/googleapis/python-storage/issues/71)) ([2e27edd](https://www.github.com/googleapis/python-storage/commit/2e27edd3fe65cd5e17c12bf11f2b58f611937d61)) +* remove docstring of retrun in reload method ([#78](https://www.github.com/googleapis/python-storage/issues/78)) ([4abeb1c](https://www.github.com/googleapis/python-storage/commit/4abeb1c0810c4e5d716758536da9fc204fa4c2a9)) +* use OrderedDict while encoding POST policy ([#95](https://www.github.com/googleapis/python-storage/issues/95)) ([df560e1](https://www.github.com/googleapis/python-storage/commit/df560e178369a6d03140e412a25af6ec7444f5a1)) + +## [1.26.0](https://www.github.com/googleapis/python-storage/compare/v1.25.0...v1.26.0) (2020-02-12) + + +### Features + +* add support for signing URLs using token ([#9889](https://www.github.com/googleapis/google-cloud-python/issues/9889)) ([ad280bf](https://www.github.com/googleapis/python-storage/commit/ad280bf506d3d7a37c402d06eac07422a5fe80af)) +* add timeout parameter to public methods ([#44](https://www.github.com/googleapis/python-storage/issues/44)) ([63abf07](https://www.github.com/googleapis/python-storage/commit/63abf0778686df1caa001270dd22f9df0daf0c78)) + + +### Bug Fixes + +* fix documentation of max_result parameter in list_blob ([#43](https://www.github.com/googleapis/python-storage/issues/43)) ([ff15f19](https://www.github.com/googleapis/python-storage/commit/ff15f19d3a5830acdd540181dc6e9d07ca7d88ee)) +* fix system test and change scope for iam access token ([#47](https://www.github.com/googleapis/python-storage/issues/47)) ([bc5375f](https://www.github.com/googleapis/python-storage/commit/bc5375f4c88f7e6ad1afbe7667c49d9a846e9757)) +* remove low version error assertion from iam conditions system tests ([#53](https://www.github.com/googleapis/python-storage/issues/53)) ([8904aee](https://www.github.com/googleapis/python-storage/commit/8904aee9ad5dc01ab83e1460b6f186a739668eb7)) + +## 1.25.0 + +01-16-2020 11:00 PST + +### Implementation Changes +- fix: replace unsafe six.PY3 with PY2 for better future compatibility with Python 4 ([#10081](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/10081)) +- fix(storage): fix document of delete blob ([#10015](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/10015)) + +### New Features +- feat(storage): support optionsRequestedPolicyVersion ([#9989](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/9989)) + +### Dependencies +- chore(storage): bump core dependency to 1.2.0 ([#10160](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/10160)) + +## 1.24.1 + +01-02-2020 13:20 PST + + +### Implementation Changes +- Add 'ARCHIVE' storage class ([#9533](https://github.com/googleapis/google-cloud-python/pull/9533)) + +## 1.24.0 + +01-02-2020 10:39 PST + + +### Implementation Changes +-str() metadata for for blob ([#9796](https://github.com/googleapis/google-cloud-python/pull/9796)) + +### New Features +- Add timeout parameter to Batch interface to match google-cloud-core ([#10010](https://github.com/googleapis/google-cloud-python/pull/10010)) + +## 1.23.0 + +11-12-2019 12:57 PST + + +### Implementation Changes +- Move `create_bucket` implementation from `Bucket` to `Client`. ([#8604](https://github.com/googleapis/google-cloud-python/pull/8604)) + +### New Features +- Add opt-in raw download support. ([#9572](https://github.com/googleapis/google-cloud-python/pull/9572)) + +### Dependencies +- Pin `google-resumable-media >= 0.5.0, < 0.6dev`. ([#9572](https://github.com/googleapis/google-cloud-python/pull/9572)) + +### Documentation +- Add python 2 sunset banner to documentation. ([#9036](https://github.com/googleapis/google-cloud-python/pull/9036)) + +### Internal / Testing Changes +- Fix query-string order dependent assert. ([#9728](https://github.com/googleapis/google-cloud-python/pull/9728)) +- Normalize VPCSC configuration in system tests. ([#9616](https://github.com/googleapis/google-cloud-python/pull/9616)) + +## 1.22.0 + +11-05-2019 10:22 PST + + +### New Features +- Add UBLA attrs to IAMConfiguration. ([#9475](https://github.com/googleapis/google-cloud-python/pull/9475)) + +## 1.21.0 + +10-28-2019 21:52 PDT + +### Implementation Changes +- Add gcloud-python header to user agent ([#9551](https://github.com/googleapis/google-cloud-python/pull/9551)) +- Don't report a gapic version for storage ([#9549](https://github.com/googleapis/google-cloud-python/pull/9549)) +- Update storage endpoint from www.googleapis.com to storage.googleapis.com ([#9543](https://github.com/googleapis/google-cloud-python/pull/9543)) +- Call anonymous client method to remove dependency of google application credentials ([#9455](https://github.com/googleapis/google-cloud-python/pull/9455)) +- Enable CSEK w/ V4 signed URLs ([#9450](https://github.com/googleapis/google-cloud-python/pull/9450)) + +### New Features +- Support predefined ACLs in `Bucket.create` ([#9334](https://github.com/googleapis/google-cloud-python/pull/9334)) + +### Documentation +- Add `hmac_key` and notification documentation rst files ([#9529](https://github.com/googleapis/google-cloud-python/pull/9529)) +- Remove references to the old authentication credentials ([#9456](https://github.com/googleapis/google-cloud-python/pull/9456)) +- Clarify docstring for `Blob.download_as_string` ([#9332](https://github.com/googleapis/google-cloud-python/pull/9332)) + +## 1.20.0 + +09-26-2019 06:45 PDT + + +### New Features +- Add `user_project` param to HMAC-related methods. ([#9237](https://github.com/googleapis/google-cloud-python/pull/9237)) +- Add `Blob.from_string` and `Bucket.from_string` factories. ([#9143](https://github.com/googleapis/google-cloud-python/pull/9143)) + +### Documentation +- Fix intersphinx reference to `requests`. ([#9294](https://github.com/googleapis/google-cloud-python/pull/9294)) +- Fix deep / broken URL for service account setup. ([#9164](https://github.com/googleapis/google-cloud-python/pull/9164)) + +### Internal / Testing Changes +- Fix typo in `_helpers.py`. ([#9239](https://github.com/googleapis/google-cloud-python/pull/9239)) +- In systests, retry bucket creation on 503. ([#9248](https://github.com/googleapis/google-cloud-python/pull/9248)) +- Avoid using `REGIONAL` / `MULTI_REGIONAL` in examples, tests. ([#9205](https://github.com/googleapis/google-cloud-python/pull/9205)) +- Move `benchwrapper` into `tests/perf`. ([#9246](https://github.com/googleapis/google-cloud-python/pull/9246)) +- Add support for `STORAGE_EMULATOR_HOST`; add `benchwrapper` script. ([#9219](https://github.com/googleapis/google-cloud-python/pull/9219)) + + +## 1.19.0 + +08-28-2019 09:45 PDT + +### Implementation Changes +- Expose 'HMACKeyMetadata.id' field. ([#9115](https://github.com/googleapis/google-cloud-python/pull/9115)) +- Make 'Blob.bucket' a readonly property. ([#9113](https://github.com/googleapis/google-cloud-python/pull/9113)) +- Clarify 'response_type' for signed_url methods. ([#8942](https://github.com/googleapis/google-cloud-python/pull/8942)) + +### New Features +- Add `client_options` to constructors for manual clients. ([#9054](https://github.com/googleapis/google-cloud-python/pull/9054)) + +### Documentation +- Remove compatability badges from READMEs. ([#9035](https://github.com/googleapis/google-cloud-python/pull/9035)) + +### Internal / Testing Changes +- Remove CI for gh-pages, use googleapis.dev for api_core refs. ([#9085](https://github.com/googleapis/google-cloud-python/pull/9085)) +- Fix tests broken by yesterday's google-resumable-media release. ([#9119](https://github.com/googleapis/google-cloud-python/pull/9119)) +- Harden 'test_access_to_public_bucket' systest against 429 / 503 errors. ([#8997](https://github.com/googleapis/google-cloud-python/pull/8997)) + +## 1.18.0 + +08-07-2019 00:37 PDT + + +### New Features +- Add HMAC key support. ([#8430](https://github.com/googleapis/google-cloud-python/pull/8430)) + +### Documentation +- Mark old storage classes as legacy, not deprecated. ([#8887](https://github.com/googleapis/google-cloud-python/pull/8887)) + +### Internal / Testing Changes +- Normalize 'lint' / 'blacken' support under nox. ([#8831](https://github.com/googleapis/google-cloud-python/pull/8831)) +- Update intersphinx mapping for requests. ([#8805](https://github.com/googleapis/google-cloud-python/pull/8805)) + +## 1.17.0 + +07-24-2019 12:37 PDT + + +### New Features +- Add `Bucket.location_type` property. ([#8570](https://github.com/googleapis/google-cloud-python/pull/8570)) +- Add `Client.list_blobs(bucket_or_name)`. ([#8375](https://github.com/googleapis/google-cloud-python/pull/8375)) + + +### Implementation Changes +- Retry bucket creation in signing setup. ([#8620](https://github.com/googleapis/google-cloud-python/pull/8620)) +- Fix URI -> blob name conversion in `Client download_blob_to_file`. ([#8440](https://github.com/googleapis/google-cloud-python/pull/8440)) +- Avoid escaping tilde in blob public / signed URLs. ([#8434](https://github.com/googleapis/google-cloud-python/pull/8434)) +- Add generation to 'Blob.__repr__'. ([#8423](https://github.com/googleapis/google-cloud-python/pull/8423)) + +### Documentation +- Link to googleapis.dev documentation in READMEs. ([#8705](https://github.com/googleapis/google-cloud-python/pull/8705)) +- Add compatibility check badges to READMEs. ([#8288](https://github.com/googleapis/google-cloud-python/pull/8288)) +- Fix example in `Client.download_blob_to_file` docstring. ([#8629](https://github.com/googleapis/google-cloud-python/pull/8629)) +- Remove typing information for kwargs to not conflict with type checkers ([#8546](https://github.com/googleapis/google-cloud-python/pull/8546)) + +### Internal / Testing Changes +- Skip failing `test_bpo_set_unset_preserves_acls` systest. ([#8617](https://github.com/googleapis/google-cloud-python/pull/8617)) +- Add nox session 'docs'. ([#8478](https://github.com/googleapis/google-cloud-python/pull/8478)) +- Add docs job to publish to googleapis.dev. ([#8464](https://github.com/googleapis/google-cloud-python/pull/8464)) + +## 1.16.1 + +06-04-2019 11:09 PDT + + +### Dependencies +- Don't pin `google-api-core` in libs using `google-cloud-core`. ([#8213](https://github.com/googleapis/google-cloud-python/pull/8213)) + +### Documentation +- Fix example in `download_blob_to_file` docstring. ([#8201](https://github.com/googleapis/google-cloud-python/pull/8201)) +- Tweak `fields` docstring further. ([#8040](https://github.com/googleapis/google-cloud-python/pull/8040)) +- Improve docs for `fields` argument to `Bucket.list_blobs`. ([#8023](https://github.com/googleapis/google-cloud-python/pull/8023)) +- Fix docs typo. ([#8027](https://github.com/googleapis/google-cloud-python/pull/8027)) + +### Internal / Testing Changes +- Retry harder in face of 409/429 during module teardown. ([#8113](https://github.com/googleapis/google-cloud-python/pull/8113)) +- Add more retries for 429s during teardown operations. ([#8112](https://github.com/googleapis/google-cloud-python/pull/8112)) + +## 1.16.0 + +05-16-2019 12:55 PDT + + +### New Features +- Update `Client.create_bucket` to take a Bucket object or string. ([#7820](https://github.com/googleapis/google-cloud-python/pull/7820)) +- Update `Client.get_bucket` to take a `Bucket` object or string. ([#7856](https://github.com/googleapis/google-cloud-python/pull/7856)) +- Add `Client.download_blob_to_file` method. ([#7949](https://github.com/googleapis/google-cloud-python/pull/7949)) +- Add `client_info` support to client / connection. ([#7872](https://github.com/googleapis/google-cloud-python/pull/7872)) + +### Dependencies +- Pin `google-cloud-core >= 1.0.0, < 2.0dev`. ([#7993](https://github.com/googleapis/google-cloud-python/pull/7993)) +- Pin `google-auth >= 1.2.0`. ([#7798](https://github.com/googleapis/google-cloud-python/pull/7798)) + +## 1.15.0 + +04-17-2019 15:37 PDT + +### New Features +- Add support for V4 signed URLs ([#7460](https://github.com/googleapis/google-cloud-python/pull/7460)) +- Add generation arguments to bucket / blob methods. ([#7444](https://github.com/googleapis/google-cloud-python/pull/7444)) + +### Implementation Changes +- Remove classifier for Python 3.4 for end-of-life. ([#7535](https://github.com/googleapis/google-cloud-python/pull/7535)) +- Ensure that 'Blob.reload' passes encryption headers. ([#7441](https://github.com/googleapis/google-cloud-python/pull/7441)) + +### Documentation +- Update client library documentation URLs. ([#7307](https://github.com/googleapis/google-cloud-python/pull/7307)) + +### Internal / Testing Changes +- Fix failing system tests ([#7714](https://github.com/googleapis/google-cloud-python/pull/7714)) +- Increase number of retries for 429 errors. ([#7484](https://github.com/googleapis/google-cloud-python/pull/7484)) +- Un-flake KMS integration tests expecting empty bucket. ([#7479](https://github.com/googleapis/google-cloud-python/pull/7479)) + +## 1.14.0 + +02-06-2019 12:49 PST + + +### New Features +- Add 'Bucket.iam_configuration' property, enabling Bucket-Policy-Only. ([#7066](https://github.com/googleapis/google-cloud-python/pull/7066)) + +### Documentation +- Improve docs for 'generate_signed_url'. ([#7201](https://github.com/googleapis/google-cloud-python/pull/7201)) + +## 1.13.2 + +12-17-2018 17:02 PST + + +### Implementation Changes +- Update `Blob.update_storage_class` to support rewrite tokens. ([#6527](https://github.com/googleapis/google-cloud-python/pull/6527)) + +### Internal / Testing Changes +- Skip signing tests for insufficient credentials ([#6917](https://github.com/googleapis/google-cloud-python/pull/6917)) +- Document Python 2 deprecation ([#6910](https://github.com/googleapis/google-cloud-python/pull/6910)) +- Normalize docs for `page_size` / `max_results` / `page_token`. ([#6842](https://github.com/googleapis/google-cloud-python/pull/6842)) + +## 1.13.1 + +12-10-2018 13:31 PST + + +### Implementation Changes +- Import `iam.policy` from `google.api_core`. ([#6741](https://github.com/googleapis/google-cloud-python/pull/6741)) +- Accomodate new back-end restriction on retention period. ([#6388](https://github.com/googleapis/google-cloud-python/pull/6388)) +- Avoid deleting a blob renamed to itself ([#6365](https://github.com/googleapis/google-cloud-python/pull/6365)) + +### Dependencies +- Update dependency to google-cloud-core ([#6835](https://github.com/googleapis/google-cloud-python/pull/6835)) +- Bump minimum `api_core` version for all GAPIC libs to 1.4.1. ([#6391](https://github.com/googleapis/google-cloud-python/pull/6391)) + +### Documentation +- Normalize use of support level badges ([#6159](https://github.com/googleapis/google-cloud-python/pull/6159)) + +### Internal / Testing Changes +- Blacken libraries ([#6794](https://github.com/googleapis/google-cloud-python/pull/6794)) +- Add templates for flake8, coveragerc, noxfile, and black. ([#6642](https://github.com/googleapis/google-cloud-python/pull/6642)) +- Harden teardown in system tests. ([#6444](https://github.com/googleapis/google-cloud-python/pull/6444)) +- Harden `create_bucket` call in systests vs. 429 TooManyRequests. ([#6401](https://github.com/googleapis/google-cloud-python/pull/6401)) +- Skip public bucket test in VPC Service Controls ([#6230](https://github.com/googleapis/google-cloud-python/pull/6230)) +- Fix lint failure. ([#6219](https://github.com/googleapis/google-cloud-python/pull/6219)) +- Disable test running in VPC Service Controls restricted environment ([#6215](https://github.com/googleapis/google-cloud-python/pull/6215)) +- Use new Nox ([#6175](https://github.com/googleapis/google-cloud-python/pull/6175)) + +## 1.13.0 + +### New Features +- Add support for bucket retention policies ([#5534](https://github.com/googleapis/google-cloud-python/pull/5534)) +- Allow `destination.content_type` to be None in `Blob.compose`. ([#6031](https://github.com/googleapis/google-cloud-python/pull/6031)) + +### Implementation Changes +- Ensure that `method` for `Blob.generate_signed_url` is uppercase. ([#6110](https://github.com/googleapis/google-cloud-python/pull/6110)) + +### Documentation +- Clarify GCS URL signing limitations on GCE ([#6104](https://github.com/googleapis/google-cloud-python/pull/6104)) +- Redirect renamed 'usage.html'/'client.html' -> 'index.html'. ([#5996](https://github.com/googleapis/google-cloud-python/pull/5996)) + +## 1.12.0 + +### New Features +- Add support for Python 3.7, drop support for Python 3.4. ([#5942](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/5942)) +- Add lifecycle rules helpers to bucket. ([#5877](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/5877)) + +### Implementation Changes +- Add 'stacklevel=2' to deprecation warnings. ([#5897](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/5897)) + +### Documentation +- Storage docs: fix typos. ([#5933](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/5933)) +- Prep storage docs for repo split. ([#5923](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/5923)) + +### Internal / Testing Changes +- Harden systest teardown further. ([#5900](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/5900)) +- Nox: use inplace installs ([#5865](https://github.com/GoogleCloudPlatform/google-cloud-python/pull/5865)) + +## 1.11.0 + +### Implementation Changes +- Preserve message / args from an `InvalidResponse`. (#5492) +- Fix generating signed urls for blobs with non-ascii names. (#5625) +- Move bucket location specification to `Bucket.create`; deprecate `Bucket.location` setter (#5808) + +### New Features +- Add `Client.get_service_account_email`. (#5765) + +### Documentation +- Clarify `None` values for resource-backed properties. (#5509) +- Elaborate docs for `{Bucket,Blob}.make_{public,private}`; note how to enable anonymous accesss to `Blob.public_url`. (#5767) + +### Internal / Testing Changes +- Harden `create_bucket` systest against 429 responses. (#5535) +- Add system test: signed URLs w/ non-ASCII blob name. (#5626) +- Harden `tearDownModule` against 429 TooManyRequests. (#5701) +- Retry `notification.create()` on `503 ServiceUnavailable`. (#5741) +- Fix failing KMS system tests. (#5832, #5837, #5860) + +## 1.10.0 + +### New Features +- Add support for KMS keys (#5259) +- Add `{Blob,Bucket}make_private` method (#5336) + +### Internal / Testing Changes +- Modify system tests to use prerelease versions of grpcio (#5304) + +## 1.9.0 + +### Implementation Changes +- Change GCS batch endpoint from `/batch` to `/batch/storage/v1` (#5040) + +### New Features +- Allow uploading files larger than 2GB by using Resumable Media Requests (#5187) +- Add range downloads (#5081) + +### Documentation +- Update docstring to reflect correct units (#5277) +- Replace link to 404 object IAM docs with a note on limited utility. (#5181) +- Update doc reference in GCS client documentation (#5084) +- Add see also for `Bucket.create` method call for `Client.create_bucket()` documentation. (#5073) +- Link out to requester pays docs. (#5065) + +### Internal / Testing Changes +- Add testing support for Python 3.7; remove testing support for Python 3.4. (#5295) +- Fix bad trove classifier +- Remove unused var (flake8 warning) (#5280) +- Fix unit test moving batch to batch/storage/v1 (#5082) + +## 1.8.0 + +### New features + +- Implement predefined acl (#4757) +- Add support for resumable signed url generation (#4789) + +### Implementation changes + +- Do not quote embedded slashes for public / signed URLs (#4716) + +### Dependencies + +- Update dependency range for api-core to include v1.0.0 releases (#4944) + +### Documentation + +- Missing word in docstring (#4763) + +### Testing and internal changes + +- Install local dependencies when running lint (#4936) +- Re-enable lint for tests, remove usage of pylint (#4921) +- Normalize all setup.py files (#4909) + +## 1.7.0 + +### Features + +- Enable anonymous access to blobs in public buckets (#4315) +- Make project optional / overridable for storage client (#4381) +- Relax regex used to test for valid project IDs (#4543) +- Add support for `source_generation` parameter to `Bucket.copy_blob` (#4546) + +## 1.6.0 + +### Documentation + +- Added link to "Python Development Environment Setup Guide" in + project README (#4187, h/t to @michaelawyu) + +### Dependencies + +- Upgrading to `google-cloud-core >= 0.28.0` and adding dependency + on `google-api-core` (#4221, #4280) +- Requiring `google-resumable-media >= 0.3.1` (#4244) + +PyPI: https://pypi.org/project/google-cloud-storage/1.6.0/ diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/README.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/README.rst new file mode 100644 index 000000000000..3b2f847365bd --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/README.rst @@ -0,0 +1,107 @@ +Python Client for Google Cloud Storage API +========================================== + +|stable| |pypi| |versions| + +`Google Cloud Storage API`_: is a durable and highly available object storage service. Google Cloud Storage is almost infinitely scalable and guarantees consistency: when a write succeeds, the latest copy of the object will be returned to any GET, globally. + +- `Client Library Documentation`_ +- `Product Documentation`_ + +.. |stable| image:: https://img.shields.io/badge/support-stable-gold.svg + :target: https://github.com/googleapis/google-cloud-python/blob/main/README.rst#stability-levels +.. |pypi| image:: https://img.shields.io/pypi/v/google-cloud-storage.svg + :target: https://pypi.org/project/google-cloud-storage/ +.. |versions| image:: https://img.shields.io/pypi/pyversions/google-cloud-storage.svg + :target: https://pypi.org/project/google-cloud-storage/ +.. _Google Cloud Storage API: https://cloud.google.com/storage +.. _Client Library Documentation: https://cloud.google.com/python/docs/reference/storage/latest +.. _Product Documentation: https://cloud.google.com/storage + +Quick Start +----------- + +In order to use this library, you first need to go through the following steps: + +1. `Select or create a Cloud Platform project.`_ +2. `Enable billing for your project.`_ +3. `Enable the Google Cloud Storage API.`_ +4. `Setup Authentication.`_ + +.. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project +.. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project +.. _Enable the Google Cloud Storage API.: https://cloud.google.com/storage +.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html + +Installation +~~~~~~~~~~~~ + +Install this library in a `virtualenv`_ using pip. `virtualenv`_ is a tool to +create isolated Python environments. The basic problem it addresses is one of +dependencies and versions, and indirectly permissions. + +With `virtualenv`_, it's possible to install this library without needing system +install permissions, and without clashing with the installed system +dependencies. + +.. _`virtualenv`: https://virtualenv.pypa.io/en/latest/ + + +Code samples and snippets +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Code samples and snippets live in the `samples/` folder. + + +Supported Python Versions +^^^^^^^^^^^^^^^^^^^^^^^^^ +Our client libraries are compatible with all current `active`_ and `maintenance`_ versions of +Python. + +Python >= 3.7 + +.. _active: https://devguide.python.org/devcycle/#in-development-main-branch +.. _maintenance: https://devguide.python.org/devcycle/#maintenance-branches + +Unsupported Python Versions +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Python <= 3.6 + +If you are using an `end-of-life`_ +version of Python, we recommend that you update as soon as possible to an actively supported version. + +.. _end-of-life: https://devguide.python.org/devcycle/#end-of-life-branches + +Mac/Linux +^^^^^^^^^ + +.. code-block:: console + + pip install virtualenv + virtualenv + source /bin/activate + /bin/pip install google-cloud-storage + + +Windows +^^^^^^^ + +.. code-block:: console + + pip install virtualenv + virtualenv + \Scripts\activate + \Scripts\pip.exe install google-cloud-storage + +Next Steps +~~~~~~~~~~ + +- Read the `Client Library Documentation`_ for Google Cloud Storage API + to see other available methods on the client. +- Read the `Google Cloud Storage API Product documentation`_ to learn + more about the product and see How-to Guides. +- View this `README`_ to see the full list of Cloud + APIs that we cover. + +.. _Google Cloud Storage API Product documentation: https://cloud.google.com/storage +.. _README: https://github.com/googleapis/google-cloud-python/blob/main/README.rst diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/README.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/README.rst new file mode 120000 index 000000000000..89a0106941ff --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/README.rst @@ -0,0 +1 @@ +../README.rst \ No newline at end of file diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/_static/custom.css b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/_static/custom.css new file mode 100644 index 000000000000..b0a295464b23 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/_static/custom.css @@ -0,0 +1,20 @@ +div#python2-eol { + border-color: red; + border-width: medium; +} + +/* Ensure minimum width for 'Parameters' / 'Returns' column */ +dl.field-list > dt { + min-width: 100px +} + +/* Insert space between methods for readability */ +dl.method { + padding-top: 10px; + padding-bottom: 10px +} + +/* Insert empty space between classes */ +dl.class { + padding-bottom: 50px +} diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/_templates/layout.html b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/_templates/layout.html new file mode 100644 index 000000000000..6316a537f72b --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/_templates/layout.html @@ -0,0 +1,50 @@ + +{% extends "!layout.html" %} +{%- block content %} +{%- if theme_fixed_sidebar|lower == 'true' %} +
+ {{ sidebar() }} + {%- block document %} +
+ {%- if render_sidebar %} +
+ {%- endif %} + + {%- block relbar_top %} + {%- if theme_show_relbar_top|tobool %} + + {%- endif %} + {% endblock %} + +
+
+ As of January 1, 2020 this library no longer supports Python 2 on the latest released version. + Library versions released prior to that date will continue to be available. For more information please + visit Python 2 support on Google Cloud. +
+ {% block body %} {% endblock %} +
+ + {%- block relbar_bottom %} + {%- if theme_show_relbar_bottom|tobool %} + + {%- endif %} + {% endblock %} + + {%- if render_sidebar %} +
+ {%- endif %} +
+ {%- endblock %} +
+
+{%- else %} +{{ super() }} +{%- endif %} +{%- endblock %} diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/changelog.md b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/changelog.md new file mode 120000 index 000000000000..04c99a55caae --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/changelog.md @@ -0,0 +1 @@ +../CHANGELOG.md \ No newline at end of file diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/conf.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/conf.py new file mode 100644 index 000000000000..0e6ccdff05b0 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/conf.py @@ -0,0 +1,385 @@ +# -*- coding: utf-8 -*- +# Copyright 2021 Google LLC +# +# 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. +# +# google-cloud-storage documentation build configuration file +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os +import shlex + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +sys.path.insert(0, os.path.abspath("..")) + +# For plugins that can not read conf.py. +# See also: https://github.com/docascode/sphinx-docfx-yaml/issues/85 +sys.path.insert(0, os.path.abspath(".")) + +__version__ = "" + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +needs_sphinx = "1.5.5" + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + "sphinx.ext.autodoc", + "sphinx.ext.autosummary", + "sphinx.ext.intersphinx", + "sphinx.ext.coverage", + "sphinx.ext.doctest", + "sphinx.ext.napoleon", + "sphinx.ext.todo", + "sphinx.ext.viewcode", + "recommonmark", +] + +# autodoc/autosummary flags +autoclass_content = "both" +autodoc_default_options = {"members": True} +autosummary_generate = True + + +# Add any paths that contain templates here, relative to this directory. +templates_path = ["_templates"] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# source_suffix = ['.rst', '.md'] +source_suffix = [".rst", ".md"] + +# The encoding of source files. +# source_encoding = 'utf-8-sig' + +# The root toctree document. +root_doc = "index" + +# General information about the project. +project = "google-cloud-storage" +copyright = "2019, Google" +author = "Google APIs" + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The full version, including alpha/beta/rc tags. +release = __version__ +# The short X.Y version. +version = ".".join(release.split(".")[0:2]) + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +# today = '' +# Else, today_fmt is used as the format for a strftime call. +# today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = [ + "_build", + "**/.nox/**/*", + "samples/AUTHORING_GUIDE.md", + "samples/CONTRIBUTING.md", + "samples/snippets/README.rst", +] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +# default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +# add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +# add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +# show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = "sphinx" + +# A list of ignored prefixes for module index sorting. +# modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +# keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = True + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = "alabaster" + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +html_theme_options = { + "description": "Google Cloud Client Libraries for google-cloud-storage", + "github_user": "googleapis", + "github_repo": "python-storage", + "github_banner": True, + "font_family": "'Roboto', Georgia, sans", + "head_font_family": "'Roboto', Georgia, serif", + "code_font_family": "'Roboto Mono', 'Consolas', monospace", +} + +# Add any paths that contain custom themes here, relative to this directory. +# html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +# html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +# html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +# html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +# html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ["_static"] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +# html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +# html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +# html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +# html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +# html_additional_pages = {} + +# If false, no module index is generated. +# html_domain_indices = True + +# If false, no index is generated. +# html_use_index = True + +# If true, the index is split into individual pages for each letter. +# html_split_index = False + +# If true, links to the reST sources are added to the pages. +# html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +# html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +# html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +# html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +# html_file_suffix = None + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr' +# html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# Now only 'ja' uses this config value +# html_search_options = {'type': 'default'} + +# The name of a javascript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +# html_search_scorer = 'scorer.js' + +# Output file base name for HTML help builder. +htmlhelp_basename = "google-cloud-storage-doc" + +# -- Options for warnings ------------------------------------------------------ + + +suppress_warnings = [ + # Temporarily suppress this to avoid "more than one target found for + # cross-reference" warning, which are intractable for us to avoid while in + # a mono-repo. + # See https://github.com/sphinx-doc/sphinx/blob + # /2a65ffeef5c107c19084fabdd706cdff3f52d93c/sphinx/domains/python.py#L843 + "ref.python" +] + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + #'papersize': 'letterpaper', + # The font size ('10pt', '11pt' or '12pt'). + #'pointsize': '10pt', + # Additional stuff for the LaTeX preamble. + #'preamble': '', + # Latex figure (float) alignment + #'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + ( + root_doc, + "google-cloud-storage.tex", + "google-cloud-storage Documentation", + author, + "manual", + ) +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +# latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +# latex_use_parts = False + +# If true, show page references after internal links. +# latex_show_pagerefs = False + +# If true, show URL addresses after external links. +# latex_show_urls = False + +# Documents to append as an appendix to all manuals. +# latex_appendices = [] + +# If false, no module index is generated. +# latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ( + root_doc, + "google-cloud-storage", + "google-cloud-storage Documentation", + [author], + 1, + ) +] + +# If true, show URL addresses after external links. +# man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ( + root_doc, + "google-cloud-storage", + "google-cloud-storage Documentation", + author, + "google-cloud-storage", + "google-cloud-storage Library", + "APIs", + ) +] + +# Documents to append as an appendix to all manuals. +# texinfo_appendices = [] + +# If false, no module index is generated. +# texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +# texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +# texinfo_no_detailmenu = False + + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = { + "python": ("https://python.readthedocs.org/en/latest/", None), + "google-auth": ("https://googleapis.dev/python/google-auth/latest/", None), + "google.api_core": ( + "https://googleapis.dev/python/google-api-core/latest/", + None, + ), + "grpc": ("https://grpc.github.io/grpc/python/", None), + "proto-plus": ("https://proto-plus-python.readthedocs.io/en/latest/", None), + "protobuf": ("https://googleapis.dev/python/protobuf/latest/", None), + "requests": ("https://requests.readthedocs.io/en/stable/", None), +} + + +# Napoleon settings +napoleon_google_docstring = True +napoleon_numpy_docstring = True +napoleon_include_private_with_doc = False +napoleon_include_special_with_doc = True +napoleon_use_admonition_for_examples = False +napoleon_use_admonition_for_notes = False +napoleon_use_admonition_for_references = False +napoleon_use_ivar = False +napoleon_use_param = True +napoleon_use_rtype = True diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/index.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/index.rst new file mode 100644 index 000000000000..5a9109944948 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/index.rst @@ -0,0 +1,31 @@ +.. include:: README.rst + +.. note:: + + Because the storage client uses the third-party :mod:`requests` library by + default, it is safe to share instances across threads. In multiprocessing + scenarious, best practice is to create client instances *after* + :class:`multiprocessing.Pool` or :class:`multiprocessing.Process` invokes + :func:`os.fork`. + +API Reference +------------- +.. toctree:: + :maxdepth: 2 + + storage/modules + +More Examples +------------- +.. toctree:: + :maxdepth: 2 + + Official Google Cloud Storage How-to Guides + Official Google Cloud Storage Samples + +Changelog +--------- +.. toctree:: + :maxdepth: 2 + + changelog diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/acl.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/acl.rst new file mode 100644 index 000000000000..f96cd659799a --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/acl.rst @@ -0,0 +1,89 @@ +ACL +=== + +Cloud Storage uses access control lists (ACLs) to manage object and bucket access. +ACLs are the mechanism you use to share files with other users and allow +other users to access your buckets and files. + +ACLs are suitable for fine-grained control, but you may prefer using IAM to +control access at the project level. See also: +`Cloud Storage Control Access to Data `_ + + +:class:`google.cloud.storage.bucket.Bucket` has a getting method that creates +an ACL object under the hood, and you can interact with that using +:func:`google.cloud.storage.bucket.Bucket.acl`: + +.. code-block:: python + + client = storage.Client() + bucket = client.get_bucket(bucket_name) + acl = bucket.acl + +Adding and removing permissions can be done with the following methods +(in increasing order of granularity): + +- :func:`ACL.all` + corresponds to access for all users. +- :func:`ACL.all_authenticated` corresponds + to access for all users that are signed into a Google account. +- :func:`ACL.domain` corresponds to access on a + per Google Apps domain (ie, ``example.com``). +- :func:`ACL.group` corresponds to access on a + per group basis (either by ID or e-mail address). +- :func:`ACL.user` corresponds to access on a + per user basis (either by ID or e-mail address). + +And you are able to ``grant`` and ``revoke`` the following roles: + +- **Reading**: + :func:`_ACLEntity.grant_read` and :func:`_ACLEntity.revoke_read` +- **Writing**: + :func:`_ACLEntity.grant_write` and :func:`_ACLEntity.revoke_write` +- **Owning**: + :func:`_ACLEntity.grant_owner` and :func:`_ACLEntity.revoke_owner` + +You can use any of these like any other factory method (these happen to +be :class:`_ACLEntity` factories): + +.. code-block:: python + + acl.user("me@example.org").grant_read() + acl.all_authenticated().grant_write() + +After that, you can save any changes you make with the +:func:`google.cloud.storage.acl.ACL.save` method: + +.. code-block:: python + + acl.save() + + +You can alternatively save any existing :class:`google.cloud.storage.acl.ACL` +object (whether it was created by a factory method or not) from a +:class:`google.cloud.storage.bucket.Bucket`: + +.. code-block:: python + + bucket.acl.save(acl=acl) + + +To get the list of ``entity`` and ``role`` for each unique pair, the +:class:`ACL` class is iterable: + +.. code-block:: python + + print(list(acl)) + # [{'role': 'OWNER', 'entity': 'allUsers'}, ...] + + +This list of tuples can be used as the ``entity`` and ``role`` fields +when sending metadata for ACLs to the API. + + +ACL Module +---------- + +.. automodule:: google.cloud.storage.acl + :members: + :show-inheritance: diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/batch.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/batch.rst new file mode 100644 index 000000000000..992dd9349157 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/batch.rst @@ -0,0 +1,6 @@ +Batches +~~~~~~~ + +.. automodule:: google.cloud.storage.batch + :members: + :show-inheritance: diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/blobs.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/blobs.rst new file mode 100644 index 000000000000..19392a741d64 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/blobs.rst @@ -0,0 +1,7 @@ +Blobs / Objects +~~~~~~~~~~~~~~~ + +.. automodule:: google.cloud.storage.blob + :members: + :inherited-members: + :show-inheritance: diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/buckets.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/buckets.rst new file mode 100644 index 000000000000..c42d7e303166 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/buckets.rst @@ -0,0 +1,7 @@ +Buckets +~~~~~~~ + +.. automodule:: google.cloud.storage.bucket + :members: + :inherited-members: + :show-inheritance: diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/client.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/client.rst new file mode 100644 index 000000000000..54f094dea9be --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/client.rst @@ -0,0 +1,6 @@ +Storage Client +~~~~~~~~~~~~~~ + +.. automodule:: google.cloud.storage.client + :members: + :show-inheritance: diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/constants.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/constants.rst new file mode 100644 index 000000000000..ddf5b81f29a7 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/constants.rst @@ -0,0 +1,7 @@ +Constants +~~~~~~~~~ + +.. automodule:: google.cloud.storage.constants + :members: + :member-order: bysource + diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/fileio.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/fileio.rst new file mode 100644 index 000000000000..9ad214a25349 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/fileio.rst @@ -0,0 +1,6 @@ +FileIO +~~~~~~~ + +.. automodule:: google.cloud.storage.fileio + :members: + :show-inheritance: \ No newline at end of file diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/generation_metageneration.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/generation_metageneration.rst new file mode 100644 index 000000000000..eb77dad15f6a --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/generation_metageneration.rst @@ -0,0 +1,167 @@ +Conditional Requests Via ETag / Generation / Metageneration Preconditions +========================================================================= + +Preconditions tell Cloud Storage to only perform a request if the +:ref:`ETag `, :ref:`generation `, or +:ref:`metageneration ` number of the affected object +meets your precondition criteria. These checks of the ETag, generation, and +metageneration numbers ensure that the object is in the expected state, +allowing you to perform safe read-modify-write updates and conditional +operations on objects + +Concepts +-------- + +.. _concept-etag: + +ETag +:::::::::::::: + +An ETag is returned as part of the response header whenever a resource is +returned, as well as included in the resource itself. Users should make no +assumptions about the value used in an ETag except that it changes whenever the +underlying data changes, per the +`specification `_ + +The ``ETag`` attribute is set by the GCS back-end, and is read-only in the +client library. + +.. _concept-metageneration: + +Metageneration +:::::::::::::: + +When you create a :class:`~google.cloud.storage.bucket.Bucket`, +its :attr:`~google.cloud.storage.bucket.Bucket.metageneration` is initialized +to ``1``, representing the initial version of the bucket's metadata. + +When you first upload a +:class:`~google.cloud.storage.blob.Blob` ("Object" in the GCS back-end docs), +its :attr:`~google.cloud.storage.blob.Blob.metageneration` is likewise +initialized to ``1``. representing the initial version of the blob's metadata. + +The ``metageneration`` attribute is set by the GCS back-end, and is read-only +in the client library. + +Each time you patch or update the bucket's / blob's metadata, its +``metageneration`` is incremented. + + +.. _concept-generation: + +Generation +:::::::::: + +Each time you upload a new version of a file to a +:class:`~google.cloud.storage.blob.Blob` ("Object" in the GCS back-end docs), +the Blob's :attr:`~google.cloud.storage.blob.generation` is changed, and its +:attr:`~google.cloud.storage.blob.metageneration` is reset to ``1`` (the first +metadata version for that generation of the blob). + +The ``generation`` attribute is set by the GCS back-end, and is read-only +in the client library. + +See also +:::::::: + +- `Storage API Generation Precondition docs`_ + +.. _Storage API Generation Precondition docs: + https://cloud.google.com/storage/docs/generations-preconditions + + +Conditional Parameters +---------------------- + +.. _using-if-etag-match: + +Using ``if_etag_match`` +::::::::::::::::::::::::::::: + +Passing the ``if_etag_match`` parameter to a method which retrieves a +blob resource (e.g., +:meth:`Blob.reload `) +makes the operation conditional on whether the blob's current ``ETag`` matches +the given value. This parameter is not supported for modification (e.g., +:meth:`Blob.update `). + + +.. _using-if-etag-not-match: + +Using ``if_etag_not_match`` +::::::::::::::::::::::::::::: + +Passing the ``if_etag_not_match`` parameter to a method which retrieves a +blob resource (e.g., +:meth:`Blob.reload `) +makes the operation conditional on whether the blob's current ``ETag`` matches +the given value. This parameter is not supported for modification (e.g., +:meth:`Blob.update `). + + +.. _using-if-generation-match: + +Using ``if_generation_match`` +::::::::::::::::::::::::::::: + +Passing the ``if_generation_match`` parameter to a method which retrieves a +blob resource (e.g., +:meth:`Blob.reload `) or modifies +the blob (e.g., +:meth:`Blob.update `) +makes the operation conditional on whether the blob's current ``generation`` +matches the given value. + +As a special case, passing ``0`` as the value for ``if_generation_match`` +makes the operation succeed only if there are no live versions of the blob. + + +.. _using-if-generation-not-match: + +Using ``if_generation_not_match`` +::::::::::::::::::::::::::::::::: + +Passing the ``if_generation_not_match`` parameter to a method which retrieves +a blob resource (e.g., +:meth:`Blob.reload `) or modifies +the blob (e.g., +:meth:`Blob.update `) +makes the operation conditional on whether the blob's current ``generation`` +does **not** match the given value. + +If no live version of the blob exists, the precondition fails. + +As a special case, passing ``0`` as the value for ``if_generation_not_match`` +makes the operation succeed only if there **is** a live version of the blob. + + +.. _using-if-metageneration-match: + +Using ``if_metageneration_match`` +::::::::::::::::::::::::::::::::: + +Passing the ``if_metageneration_match`` parameter to a method which retrieves +a blob or bucket resource +(e.g., :meth:`Blob.reload `, +:meth:`Bucket.reload `) +or modifies the blob or bucket (e.g., +:meth:`Blob.update ` +:meth:`Bucket.patch `) +makes the operation conditional on whether the resource's current +``metageneration`` matches the given value. + + +.. _using-if-metageneration-not-match: + +Using ``if_metageneration_not_match`` +::::::::::::::::::::::::::::::::::::: + +Passing the ``if_metageneration_not_match`` parameter to a method which +retrieves a blob or bucket resource +(e.g., :meth:`Blob.reload `, +:meth:`Bucket.reload `) +or modifies the blob or bucket (e.g., +:meth:`Blob.update ` +:meth:`Bucket.patch `) +makes the operation conditional on whether the resource's current +``metageneration`` does **not** match the given value. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/hmac_key.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/hmac_key.rst new file mode 100644 index 000000000000..432be5f64ebe --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/hmac_key.rst @@ -0,0 +1,6 @@ +HMAC Key Metadata +~~~~~~~~~~~~~~~~~ + +.. automodule:: google.cloud.storage.hmac_key + :members: + :show-inheritance: diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/modules.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/modules.rst new file mode 100644 index 000000000000..9148a43859a9 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/modules.rst @@ -0,0 +1,17 @@ +Modules for Python Storage +-------------------------- +.. toctree:: + :maxdepth: 2 + + client + blobs + buckets + acl + batch + fileio + constants + hmac_key + notification + retry + retry_timeout + generation_metageneration \ No newline at end of file diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/notification.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/notification.rst new file mode 100644 index 000000000000..cdb381d2f703 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/notification.rst @@ -0,0 +1,6 @@ +Notification +~~~~~~~~~~~~ + +.. automodule:: google.cloud.storage.notification + :members: + :show-inheritance: diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/retry.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/retry.rst new file mode 100644 index 000000000000..bb56905394bd --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/retry.rst @@ -0,0 +1,6 @@ +Retry +---------------- + +.. automodule:: google.cloud.storage.retry + :members: + :show-inheritance: \ No newline at end of file diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/retry_timeout.rst b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/retry_timeout.rst new file mode 100644 index 000000000000..bc19126582d0 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/retry_timeout.rst @@ -0,0 +1,159 @@ +Configuring Timeouts and Retries +================================ + +When using object methods which invoke Google Cloud Storage API methods, +you have several options for how the library handles timeouts and +how it retries transient errors. + + +.. _configuring_timeouts: + +Configuring Timeouts +-------------------- + +For a number of reasons, methods which invoke API methods may take +longer than expected or desired. By default, such methods all time out +after a default interval, 60.0 seconds. Rather than blocking your application +code for that interval, you may choose to configure explicit timeouts +in your code, using one of three forms: + +- You can pass a single integer or float which functions as the timeout for the + entire request. E.g.: + +.. code-block:: python + + bucket = client.get_bucket(BUCKET_NAME, timeout=300.0) # five minutes + +- You can also be passed as a two-tuple, ``(connect_timeout, read_timeout)``, + where the ``connect_timeout`` sets the maximum time required to establish + the connection to the server, and the ``read_timeout`` sets the maximum + time to wait for a completed response. E.g.: + +.. code-block:: python + + bucket = client.get_bucket(BUCKET_NAME, timeout=(3, 10)) + + +- You can also pass ``None`` as the timeout value: in this case, the library + will block indefinitely for a response. E.g.: + +.. code-block:: python + + bucket = client.get_bucket(BUCKET_NAME, timeout=None) + +.. note:: + Depending on the retry strategy, a request may be + repeated several times using the same timeout each time. + +See also: + + `Timeouts in requests `_ + + +.. _configuring_retries: + +Configuring Retries +-------------------- + +.. note:: + + For more background on retries, see also the + `GCS Retry Strategies Document `_ + +Methods which invoke API methods may fail for a number of reasons, some of +which represent "transient" conditions, and thus can be retried +automatically. The library tries to provide a sensible default retry policy +for each method, base on its semantics: + +- For API requests which are always idempotent, the library uses its + :data:`~google.cloud.storage.retry.DEFAULT_RETRY` policy, which + retries any API request which returns a "transient" error. + +- For API requests which are idempotent only if the blob has + the same "generation", the library uses its + :data:`~google.cloud.storage.retry.DEFAULT_RETRY_IF_GENERATION_SPECIFIED` + policy, which retries API requests which returns a "transient" error, + but only if the original request includes a ``generation`` or + ``ifGenerationMatch`` header. + +- For API requests which are idempotent only if the bucket or blob has + the same "metageneration", the library uses its + :data:`~google.cloud.storage.retry.DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED` + policy, which retries API requests which returns a "transient" error, + but only if the original request includes an ``ifMetagenerationMatch`` header. + +- For API requests which are idempotent only if the bucket or blob has + the same "etag", the library uses its + :data:`~google.cloud.storage.retry.DEFAULT_RETRY_IF_ETAG_IN_JSON` + policy, which retries API requests which returns a "transient" error, + but only if the original request includes an ``ETAG`` in its payload. + +- For those API requests which are never idempotent, the library passes + ``retry=None`` by default, suppressing any retries. + +Rather than using one of the default policies, you may choose to configure an +explicit policy in your code. + +- You can pass ``None`` as a retry policy to disable retries. E.g.: + +.. code-block:: python + + bucket = client.get_bucket(BUCKET_NAME, retry=None) + +- You can modify the default retry behavior and create a copy of :data:`~google.cloud.storage.retry.DEFAULT_RETRY` + by calling it with a ``with_XXX`` method. E.g.: + +.. code-block:: python + + from google.cloud.storage.retry import DEFAULT_RETRY + + # Customize retry with a deadline of 500 seconds (default=120 seconds). + modified_retry = DEFAULT_RETRY.with_deadline(500.0) + # Customize retry with an initial wait time of 1.5 (default=1.0). + # Customize retry with a wait time multiplier per iteration of 1.2 (default=2.0). + # Customize retry with a maximum wait time of 45.0 (default=60.0). + modified_retry = modified_retry.with_delay(initial=1.5, multiplier=1.2, maximum=45.0) + +- You can pass an instance of :class:`google.api_core.retry.Retry` to enable + retries; the passed object will define retriable response codes and errors, + as well as configuring backoff and retry interval options. E.g.: + +.. code-block:: python + + from google.api_core import exceptions + from google.api_core.retry import Retry + + _MY_RETRIABLE_TYPES = [ + exceptions.TooManyRequests, # 429 + exceptions.InternalServerError, # 500 + exceptions.BadGateway, # 502 + exceptions.ServiceUnavailable, # 503 + ] + + def is_retryable(exc): + return isinstance(exc, _MY_RETRIABLE_TYPES) + + my_retry_policy = Retry(predicate=is_retryable) + bucket = client.get_bucket(BUCKET_NAME, retry=my_retry_policy) + +- You can pass an instance of + :class:`google.cloud.storage.retry.ConditionalRetryPolicy`, which wraps a + :class:`~google.cloud.storage.retry.RetryPolicy`, activating it only if + certain conditions are met. This class exists to provide safe defaults + for RPC calls that are not technically safe to retry normally (due to + potential data duplication or other side-effects) but become safe to retry + if a condition such as if_metageneration_match is set. E.g.: + +.. code-block:: python + + from google.api_core.retry import Retry + from google.cloud.storage.retry import ConditionalRetryPolicy + from google.cloud.storage.retry import is_etag_in_data + + def is_retryable(exc): + ... # as above + + my_retry_policy = Retry(predicate=is_retryable) + my_cond_policy = ConditionalRetryPolicy( + my_retry_policy, conditional_predicate=is_etag_in_data, ["query_params"]) + bucket = client.get_bucket(BUCKET_NAME, retry=my_cond_policy) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/snippets.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/snippets.py new file mode 100644 index 000000000000..93884900f92a --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/docs/storage/snippets.py @@ -0,0 +1,316 @@ +# Copyright 2016 Google LLC +# +# 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. + +"""Testable usage examples for Google Cloud Storage API wrapper + +Each example function takes a ``client`` argument (which must be an instance +of :class:`google.cloud.storage.client.Client`) and uses it to perform a task +with the API. + +To facilitate running the examples as system tests, each example is also passed +a ``to_delete`` list; the function adds to the list any objects created which +need to be deleted during teardown. +""" + +from google.cloud import storage + + +def snippet(func): + """Mark ``func`` as a snippet example function.""" + func._snippet = True + return func + + +@snippet +def storage_get_started(to_delete): + # START storage_get_started + client = storage.Client() + bucket = client.get_bucket("bucket-id-here") + # Then do other things... + blob = bucket.get_blob("/remote/path/to/file.txt") + assert blob.download_as_string() == b"My old contents!" + blob.upload_from_string("New contents!") + blob2 = bucket.blob("/remote/path/storage.txt") + blob2.upload_from_filename(filename="/local/path.txt") + # END storage_get_started + + to_delete.append(bucket) + + +@snippet +def client_bucket_acl(client, to_delete): + bucket_name = "system-test-bucket" + client.create_bucket(bucket_name) + + # START client_bucket_acl + client = storage.Client() + bucket = client.get_bucket(bucket_name) + acl = bucket.acl + # END client_bucket_acl + to_delete.append(bucket) + + # START acl_user_settings + acl.user("me@example.org").grant_read() + acl.all_authenticated().grant_write() + # END acl_user_settings + + # START acl_save + acl.save() + # END acl_save + + # START acl_revoke_write + acl.all().grant_read() + acl.all().revoke_write() + # END acl_revoke_write + + # START acl_save_bucket + bucket.acl.save(acl=acl) + # END acl_save_bucket + + # START acl_print + print(list(acl)) + # [{'role': 'OWNER', 'entity': 'allUsers'}, ...] + # END acl_print + + +@snippet +def download_to_file(to_delete): + # START download_to_file + from google.cloud.storage import Blob + + client = storage.Client(project="my-project") + bucket = client.get_bucket("my-bucket") + encryption_key = "c7f32af42e45e85b9848a6a14dd2a8f6" + blob = Blob("secure-data", bucket, encryption_key=encryption_key) + blob.upload_from_string("my secret message.") + with open("/tmp/my-secure-file", "wb") as file_obj: + client.download_to_file(blob, file_obj) + # END download_to_file + + to_delete.append(blob) + + +@snippet +def upload_from_file(to_delete): + # START upload_from_file + from google.cloud.storage import Blob + + client = storage.Client(project="my-project") + bucket = client.get_bucket("my-bucket") + encryption_key = "aa426195405adee2c8081bb9e7e74b19" + blob = Blob("secure-data", bucket, encryption_key=encryption_key) + with open("my-file", "rb") as my_file: + blob.upload_from_file(my_file) + # END upload_from_file + + to_delete.append(blob) + + +@snippet +def get_blob(to_delete): + from google.cloud.storage.blob import Blob + + # START get_blob + client = storage.Client() + bucket = client.get_bucket("my-bucket") + assert isinstance(bucket.get_blob("/path/to/blob.txt"), Blob) + # + assert not bucket.get_blob("/does-not-exist.txt") + # None + # END get_blob + + to_delete.append(bucket) + + +@snippet +def delete_blob(to_delete): + # START delete_blob + from google.cloud.exceptions import NotFound + + client = storage.Client() + bucket = client.get_bucket("my-bucket") + blobs = list(client.list_blobs(bucket)) + assert len(blobs) > 0 + # [] + bucket.delete_blob("my-file.txt") + try: + bucket.delete_blob("doesnt-exist") + except NotFound: + pass + # END delete_blob + + blob = None + # START delete_blobs + bucket.delete_blobs([blob], on_error=lambda blob: None) + # END delete_blobs + + to_delete.append(bucket) + + +@snippet +def configure_website(to_delete): + bucket_name = "test-bucket" + # START configure_website + client = storage.Client() + bucket = client.get_bucket(bucket_name) + bucket.configure_website("index.html", "404.html") + # END configure_website + + # START make_public + bucket.make_public(recursive=True, future=True) + # END make_public + + to_delete.append(bucket) + + +@snippet +def get_bucket(client, to_delete): + import google + + # START get_bucket + try: + bucket = client.get_bucket("my-bucket") + except google.cloud.exceptions.NotFound: + print("Sorry, that bucket does not exist!") + # END get_bucket + to_delete.append(bucket) + + +@snippet +def add_lifecycle_delete_rule(client, to_delete): + # START add_lifecycle_delete_rule + bucket = client.get_bucket("my-bucket") + bucket.add_lifecycle_delete_rule(age=2) + bucket.patch() + # END add_lifecycle_delete_rule + to_delete.append(bucket) + + +@snippet +def add_lifecycle_set_storage_class_rule(client, to_delete): + # START add_lifecycle_set_storage_class_rule + bucket = client.get_bucket("my-bucket") + bucket.add_lifecycle_set_storage_class_rule( + "COLD_LINE", matches_storage_class=["NEARLINE"] + ) + bucket.patch() + # END add_lifecycle_set_storage_class_rule + to_delete.append(bucket) + + +@snippet +def lookup_bucket(client, to_delete): + from google.cloud.storage.bucket import Bucket + + # START lookup_bucket + bucket = client.lookup_bucket("doesnt-exist") + assert not bucket + # None + bucket = client.lookup_bucket("my-bucket") + assert isinstance(bucket, Bucket) + # + # END lookup_bucket + + to_delete.append(bucket) + + +@snippet +def create_bucket(client, to_delete): + from google.cloud.storage import Bucket + + # START create_bucket + bucket = client.create_bucket("my-bucket") + assert isinstance(bucket, Bucket) + # + # END create_bucket + + to_delete.append(bucket) + + +@snippet +def list_buckets(client, to_delete): + # START list_buckets + for bucket in client.list_buckets(): + print(bucket) + # END list_buckets + + for bucket in client.list_buckets(): + to_delete.append(bucket) + + +@snippet +def policy_document(client): + # pylint: disable=unused-argument + # START policy_document + bucket = client.bucket("my-bucket") + conditions = [["starts-with", "$key", ""], {"acl": "public-read"}] + + policy = bucket.generate_upload_policy(conditions) + + # Generate an upload form using the form fields. + policy_fields = "".join( + f'' + for key, value in policy.items() + ) + + upload_form = ( + '
' + '' + '' + '' + '' + '' + "{policy_fields}" + "
" + ).format(bucket_name=bucket.name, policy_fields=policy_fields) + + print(upload_form) + # END policy_document + + +def _line_no(func): + code = getattr(func, "__code__", None) or getattr(func, "func_code") + return code.co_firstlineno + + +def _find_examples(): + funcs = [obj for obj in globals().values() if getattr(obj, "_snippet", False)] + for func in sorted(funcs, key=_line_no): + yield func + + +def _name_and_doc(func): + return func.__name__, func.__doc__ + + +def main(): + client = storage.Client() + for example in _find_examples(): + to_delete = [] + name, doc = _name_and_doc(example) + print(f"{name:>25}: {doc}") + + try: + example(client, to_delete) + except AssertionError as failure: + print(f" FAIL: {failure}") + except Exception as error: # pylint: disable=broad-except + print(f" ERROR: {error!r}") + for item in to_delete: + item.delete() + + +if __name__ == "__main__": + main() diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/__init__.py new file mode 100644 index 000000000000..0e1bc5131ba6 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/__init__.py @@ -0,0 +1,22 @@ +# Copyright 2016 Google LLC +# +# 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. + +try: + import pkg_resources + + pkg_resources.declare_namespace(__name__) +except ImportError: + import pkgutil + + __path__ = pkgutil.extend_path(__path__, __name__) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/__init__.py new file mode 100644 index 000000000000..0e1bc5131ba6 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/__init__.py @@ -0,0 +1,22 @@ +# Copyright 2016 Google LLC +# +# 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. + +try: + import pkg_resources + + pkg_resources.declare_namespace(__name__) +except ImportError: + import pkgutil + + __path__ = pkgutil.extend_path(__path__, __name__) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/__init__.py new file mode 100644 index 000000000000..4e9c47f4a03b --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/__init__.py @@ -0,0 +1,41 @@ +# Copyright 2014 Google LLC +# +# 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. + +"""Shortcut methods for getting set up with Google Cloud Storage. + +You'll typically use these to get started with the API: + +.. literalinclude:: snippets.py + :start-after: START storage_get_started + :end-before: END storage_get_started + :dedent: 4 + +The main concepts with this API are: + +- :class:`~google.cloud.storage.bucket.Bucket` which represents a particular + bucket (akin to a mounted disk on a computer). + +- :class:`~google.cloud.storage.blob.Blob` which represents a pointer to a + particular entity in Cloud Storage (akin to a file path on a remote + machine). +""" + +from google.cloud.storage.version import __version__ +from google.cloud.storage.batch import Batch +from google.cloud.storage.blob import Blob +from google.cloud.storage.bucket import Bucket +from google.cloud.storage.client import Client + + +__all__ = ["__version__", "Batch", "Blob", "Bucket", "Client"] diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/_helpers.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/_helpers.py new file mode 100644 index 000000000000..82bb4230e747 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/_helpers.py @@ -0,0 +1,614 @@ +# Copyright 2014 Google LLC +# +# 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. + +"""Helper functions for Cloud Storage utility classes. + +These are *not* part of the API. +""" + +import base64 +from hashlib import md5 +import os +from urllib.parse import urlsplit +from uuid import uuid4 + +from google import resumable_media +from google.auth import environment_vars +from google.cloud.storage.constants import _DEFAULT_TIMEOUT +from google.cloud.storage.retry import DEFAULT_RETRY +from google.cloud.storage.retry import DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED + + +STORAGE_EMULATOR_ENV_VAR = "STORAGE_EMULATOR_HOST" +"""Environment variable defining host for Storage emulator.""" + +_DEFAULT_STORAGE_HOST = os.getenv( + "API_ENDPOINT_OVERRIDE", "https://storage.googleapis.com" +) +"""Default storage host for JSON API.""" + +_API_VERSION = os.getenv("API_VERSION_OVERRIDE", "v1") +"""API version of the default storage host""" + +_BASE_STORAGE_URI = "storage.googleapis.com" +"""Base request endpoint URI for JSON API.""" + +# etag match parameters in snake case and equivalent header +_ETAG_MATCH_PARAMETERS = ( + ("if_etag_match", "If-Match"), + ("if_etag_not_match", "If-None-Match"), +) + +# generation match parameters in camel and snake cases +_GENERATION_MATCH_PARAMETERS = ( + ("if_generation_match", "ifGenerationMatch"), + ("if_generation_not_match", "ifGenerationNotMatch"), + ("if_metageneration_match", "ifMetagenerationMatch"), + ("if_metageneration_not_match", "ifMetagenerationNotMatch"), + ("if_source_generation_match", "ifSourceGenerationMatch"), + ("if_source_generation_not_match", "ifSourceGenerationNotMatch"), + ("if_source_metageneration_match", "ifSourceMetagenerationMatch"), + ("if_source_metageneration_not_match", "ifSourceMetagenerationNotMatch"), +) + +_NUM_RETRIES_MESSAGE = ( + "`num_retries` has been deprecated and will be removed in a future " + "release. Use the `retry` argument with a Retry or ConditionalRetryPolicy " + "object, or None, instead." +) + + +def _get_storage_host(): + return os.environ.get(STORAGE_EMULATOR_ENV_VAR, _DEFAULT_STORAGE_HOST) + + +def _get_environ_project(): + return os.getenv( + environment_vars.PROJECT, + os.getenv(environment_vars.LEGACY_PROJECT), + ) + + +def _validate_name(name): + """Pre-flight ``Bucket`` name validation. + + :type name: str or :data:`NoneType` + :param name: Proposed bucket name. + + :rtype: str or :data:`NoneType` + :returns: ``name`` if valid. + """ + if name is None: + return + + # The first and last characters must be alphanumeric. + if not all([name[0].isalnum(), name[-1].isalnum()]): + raise ValueError("Bucket names must start and end with a number or letter.") + return name + + +class _PropertyMixin(object): + """Abstract mixin for cloud storage classes with associated properties. + + Non-abstract subclasses should implement: + - path + - client + - user_project + + :type name: str + :param name: The name of the object. Bucket names must start and end with a + number or letter. + """ + + def __init__(self, name=None): + self.name = name + self._properties = {} + self._changes = set() + + @property + def path(self): + """Abstract getter for the object path.""" + raise NotImplementedError + + @property + def client(self): + """Abstract getter for the object client.""" + raise NotImplementedError + + @property + def user_project(self): + """Abstract getter for the object user_project.""" + raise NotImplementedError + + def _require_client(self, client): + """Check client or verify over-ride. + + :type client: :class:`~google.cloud.storage.client.Client` or + ``NoneType`` + :param client: the client to use. If not passed, falls back to the + ``client`` stored on the current object. + + :rtype: :class:`google.cloud.storage.client.Client` + :returns: The client passed in or the currently bound client. + """ + if client is None: + client = self.client + return client + + def _encryption_headers(self): + """Return any encryption headers needed to fetch the object. + + .. note:: + Defined here because :meth:`reload` calls it, but this method is + really only relevant for :class:`~google.cloud.storage.blob.Blob`. + + :rtype: dict + :returns: a mapping of encryption-related headers. + """ + return {} + + @property + def _query_params(self): + """Default query parameters.""" + params = {} + if self.user_project is not None: + params["userProject"] = self.user_project + return params + + def reload( + self, + client=None, + projection="noAcl", + if_etag_match=None, + if_etag_not_match=None, + if_generation_match=None, + if_generation_not_match=None, + if_metageneration_match=None, + if_metageneration_not_match=None, + timeout=_DEFAULT_TIMEOUT, + retry=DEFAULT_RETRY, + ): + """Reload properties from Cloud Storage. + + If :attr:`user_project` is set, bills the API request to that project. + + :type client: :class:`~google.cloud.storage.client.Client` or + ``NoneType`` + :param client: the client to use. If not passed, falls back to the + ``client`` stored on the current object. + + :type projection: str + :param projection: (Optional) If used, must be 'full' or 'noAcl'. + Defaults to ``'noAcl'``. Specifies the set of + properties to return. + + :type if_etag_match: Union[str, Set[str]] + :param if_etag_match: (Optional) See :ref:`using-if-etag-match` + + :type if_etag_not_match: Union[str, Set[str]]) + :param if_etag_not_match: (Optional) See :ref:`using-if-etag-not-match` + + :type if_generation_match: long + :param if_generation_match: + (Optional) See :ref:`using-if-generation-match` + + :type if_generation_not_match: long + :param if_generation_not_match: + (Optional) See :ref:`using-if-generation-not-match` + + :type if_metageneration_match: long + :param if_metageneration_match: + (Optional) See :ref:`using-if-metageneration-match` + + :type if_metageneration_not_match: long + :param if_metageneration_not_match: + (Optional) See :ref:`using-if-metageneration-not-match` + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + """ + client = self._require_client(client) + query_params = self._query_params + # Pass only '?projection=noAcl' here because 'acl' and related + # are handled via custom endpoints. + query_params["projection"] = projection + _add_generation_match_parameters( + query_params, + if_generation_match=if_generation_match, + if_generation_not_match=if_generation_not_match, + if_metageneration_match=if_metageneration_match, + if_metageneration_not_match=if_metageneration_not_match, + ) + headers = self._encryption_headers() + _add_etag_match_headers( + headers, if_etag_match=if_etag_match, if_etag_not_match=if_etag_not_match + ) + api_response = client._get_resource( + self.path, + query_params=query_params, + headers=headers, + timeout=timeout, + retry=retry, + _target_object=self, + ) + self._set_properties(api_response) + + def _patch_property(self, name, value): + """Update field of this object's properties. + + This method will only update the field provided and will not + touch the other fields. + + It **will not** reload the properties from the server. The behavior is + local only and syncing occurs via :meth:`patch`. + + :type name: str + :param name: The field name to update. + + :type value: object + :param value: The value being updated. + """ + self._changes.add(name) + self._properties[name] = value + + def _set_properties(self, value): + """Set the properties for the current object. + + :type value: dict or :class:`google.cloud.storage.batch._FutureDict` + :param value: The properties to be set. + """ + self._properties = value + # If the values are reset, the changes must as well. + self._changes = set() + + def patch( + self, + client=None, + if_generation_match=None, + if_generation_not_match=None, + if_metageneration_match=None, + if_metageneration_not_match=None, + timeout=_DEFAULT_TIMEOUT, + retry=DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED, + ): + """Sends all changed properties in a PATCH request. + + Updates the ``_properties`` with the response from the backend. + + If :attr:`user_project` is set, bills the API request to that project. + + :type client: :class:`~google.cloud.storage.client.Client` or + ``NoneType`` + :param client: the client to use. If not passed, falls back to the + ``client`` stored on the current object. + + :type if_generation_match: long + :param if_generation_match: + (Optional) See :ref:`using-if-generation-match` + + :type if_generation_not_match: long + :param if_generation_not_match: + (Optional) See :ref:`using-if-generation-not-match` + + :type if_metageneration_match: long + :param if_metageneration_match: + (Optional) See :ref:`using-if-metageneration-match` + + :type if_metageneration_not_match: long + :param if_metageneration_not_match: + (Optional) See :ref:`using-if-metageneration-not-match` + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + """ + client = self._require_client(client) + query_params = self._query_params + # Pass '?projection=full' here because 'PATCH' documented not + # to work properly w/ 'noAcl'. + query_params["projection"] = "full" + _add_generation_match_parameters( + query_params, + if_generation_match=if_generation_match, + if_generation_not_match=if_generation_not_match, + if_metageneration_match=if_metageneration_match, + if_metageneration_not_match=if_metageneration_not_match, + ) + update_properties = {key: self._properties[key] for key in self._changes} + + # Make the API call. + api_response = client._patch_resource( + self.path, + update_properties, + query_params=query_params, + _target_object=self, + timeout=timeout, + retry=retry, + ) + self._set_properties(api_response) + + def update( + self, + client=None, + if_generation_match=None, + if_generation_not_match=None, + if_metageneration_match=None, + if_metageneration_not_match=None, + timeout=_DEFAULT_TIMEOUT, + retry=DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED, + ): + """Sends all properties in a PUT request. + + Updates the ``_properties`` with the response from the backend. + + If :attr:`user_project` is set, bills the API request to that project. + + :type client: :class:`~google.cloud.storage.client.Client` or + ``NoneType`` + :param client: the client to use. If not passed, falls back to the + ``client`` stored on the current object. + + :type if_generation_match: long + :param if_generation_match: + (Optional) See :ref:`using-if-generation-match` + + :type if_generation_not_match: long + :param if_generation_not_match: + (Optional) See :ref:`using-if-generation-not-match` + + :type if_metageneration_match: long + :param if_metageneration_match: + (Optional) See :ref:`using-if-metageneration-match` + + :type if_metageneration_not_match: long + :param if_metageneration_not_match: + (Optional) See :ref:`using-if-metageneration-not-match` + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + """ + client = self._require_client(client) + + query_params = self._query_params + query_params["projection"] = "full" + _add_generation_match_parameters( + query_params, + if_generation_match=if_generation_match, + if_generation_not_match=if_generation_not_match, + if_metageneration_match=if_metageneration_match, + if_metageneration_not_match=if_metageneration_not_match, + ) + + api_response = client._put_resource( + self.path, + self._properties, + query_params=query_params, + timeout=timeout, + retry=retry, + _target_object=self, + ) + self._set_properties(api_response) + + +def _scalar_property(fieldname): + """Create a property descriptor around the :class:`_PropertyMixin` helpers.""" + + def _getter(self): + """Scalar property getter.""" + return self._properties.get(fieldname) + + def _setter(self, value): + """Scalar property setter.""" + self._patch_property(fieldname, value) + + return property(_getter, _setter) + + +def _write_buffer_to_hash(buffer_object, hash_obj, digest_block_size=8192): + """Read blocks from a buffer and update a hash with them. + + :type buffer_object: bytes buffer + :param buffer_object: Buffer containing bytes used to update a hash object. + + :type hash_obj: object that implements update + :param hash_obj: A hash object (MD5 or CRC32-C). + + :type digest_block_size: int + :param digest_block_size: The block size to write to the hash. + Defaults to 8192. + """ + block = buffer_object.read(digest_block_size) + + while len(block) > 0: + hash_obj.update(block) + # Update the block for the next iteration. + block = buffer_object.read(digest_block_size) + + +def _base64_md5hash(buffer_object): + """Get MD5 hash of bytes (as base64). + + :type buffer_object: bytes buffer + :param buffer_object: Buffer containing bytes used to compute an MD5 + hash (as base64). + + :rtype: str + :returns: A base64 encoded digest of the MD5 hash. + """ + hash_obj = md5() + _write_buffer_to_hash(buffer_object, hash_obj) + digest_bytes = hash_obj.digest() + return base64.b64encode(digest_bytes) + + +def _add_etag_match_headers(headers, **match_parameters): + """Add generation match parameters into the given parameters list. + + :type headers: dict + :param headers: Headers dict. + + :type match_parameters: dict + :param match_parameters: if*etag*match parameters to add. + """ + for snakecase_name, header_name in _ETAG_MATCH_PARAMETERS: + value = match_parameters.get(snakecase_name) + + if value is not None: + if isinstance(value, str): + value = [value] + headers[header_name] = ", ".join(value) + + +def _add_generation_match_parameters(parameters, **match_parameters): + """Add generation match parameters into the given parameters list. + + :type parameters: list or dict + :param parameters: Parameters list or dict. + + :type match_parameters: dict + :param match_parameters: if*generation*match parameters to add. + + :raises: :exc:`ValueError` if ``parameters`` is not a ``list()`` + or a ``dict()``. + """ + for snakecase_name, camelcase_name in _GENERATION_MATCH_PARAMETERS: + value = match_parameters.get(snakecase_name) + + if value is not None: + if isinstance(parameters, list): + parameters.append((camelcase_name, value)) + + elif isinstance(parameters, dict): + parameters[camelcase_name] = value + + else: + raise ValueError( + "`parameters` argument should be a dict() or a list()." + ) + + +def _raise_if_more_than_one_set(**kwargs): + """Raise ``ValueError`` exception if more than one parameter was set. + + :type error: :exc:`ValueError` + :param error: Description of which fields were set + + :raises: :class:`~ValueError` containing the fields that were set + """ + if sum(arg is not None for arg in kwargs.values()) > 1: + escaped_keys = [f"'{name}'" for name in kwargs.keys()] + + keys_but_last = ", ".join(escaped_keys[:-1]) + last_key = escaped_keys[-1] + + msg = f"Pass at most one of {keys_but_last} and {last_key}" + + raise ValueError(msg) + + +def _bucket_bound_hostname_url(host, scheme=None): + """Helper to build bucket bound hostname URL. + + :type host: str + :param host: Host name. + + :type scheme: str + :param scheme: (Optional) Web scheme. If passed, use it + as a scheme in the result URL. + + :rtype: str + :returns: A bucket bound hostname URL. + """ + url_parts = urlsplit(host) + if url_parts.scheme and url_parts.netloc: + return host + + return f"{scheme}://{host}" + + +def _api_core_retry_to_resumable_media_retry(retry, num_retries=None): + """Convert google.api.core.Retry to google.resumable_media.RetryStrategy. + + Custom predicates are not translated. + + :type retry: google.api_core.Retry + :param retry: (Optional) The google.api_core.Retry object to translate. + + :type num_retries: int + :param num_retries: (Optional) The number of retries desired. This is + supported for backwards compatibility and is mutually exclusive with + `retry`. + + :rtype: google.resumable_media.RetryStrategy + :returns: A RetryStrategy with all applicable attributes copied from input, + or a RetryStrategy with max_retries set to 0 if None was input. + """ + + if retry is not None and num_retries is not None: + raise ValueError("num_retries and retry arguments are mutually exclusive") + + elif retry is not None: + return resumable_media.RetryStrategy( + max_sleep=retry._maximum, + max_cumulative_retry=retry._deadline, + initial_delay=retry._initial, + multiplier=retry._multiplier, + ) + elif num_retries is not None: + return resumable_media.RetryStrategy(max_retries=num_retries) + else: + return resumable_media.RetryStrategy(max_retries=0) + + +def _get_invocation_id(): + return "gccl-invocation-id/" + str(uuid4()) + + +def _get_default_headers( + user_agent, + content_type="application/json; charset=UTF-8", + x_upload_content_type=None, +): + """Get the headers for a request. + + Args: + user_agent (str): The user-agent for requests. + Returns: + Dict: The headers to be used for the request. + """ + return { + "Accept": "application/json", + "Accept-Encoding": "gzip, deflate", + "User-Agent": user_agent, + "X-Goog-API-Client": f"{user_agent} {_get_invocation_id()}", + "content-type": content_type, + "x-upload-content-type": x_upload_content_type or content_type, + } diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/_http.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/_http.py new file mode 100644 index 000000000000..fdf1d56b4148 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/_http.py @@ -0,0 +1,72 @@ +# Copyright 2014 Google LLC +# +# 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. + +"""Create / interact with Google Cloud Storage connections.""" + +import functools +from google.cloud import _http +from google.cloud.storage import __version__ +from google.cloud.storage import _helpers + + +class Connection(_http.JSONConnection): + """A connection to Google Cloud Storage via the JSON REST API. Mutual TLS feature will be + enabled if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "true". + + :type client: :class:`~google.cloud.storage.client.Client` + :param client: The client that owns the current connection. + + :type client_info: :class:`~google.api_core.client_info.ClientInfo` + :param client_info: (Optional) instance used to generate user agent. + + :type api_endpoint: str + :param api_endpoint: (Optional) api endpoint to use. + """ + + DEFAULT_API_ENDPOINT = _helpers._DEFAULT_STORAGE_HOST + DEFAULT_API_MTLS_ENDPOINT = "https://storage.mtls.googleapis.com" + + def __init__(self, client, client_info=None, api_endpoint=None): + super(Connection, self).__init__(client, client_info) + self.API_BASE_URL = api_endpoint or self.DEFAULT_API_ENDPOINT + self.API_BASE_MTLS_URL = self.DEFAULT_API_MTLS_ENDPOINT + self.ALLOW_AUTO_SWITCH_TO_MTLS_URL = api_endpoint is None + self._client_info.client_library_version = __version__ + + # TODO: When metrics all use gccl, this should be removed #9552 + if self._client_info.user_agent is None: # pragma: no branch + self._client_info.user_agent = "" + agent_version = f"gcloud-python/{__version__}" + if agent_version not in self._client_info.user_agent: + self._client_info.user_agent += f" {agent_version} " + + API_VERSION = _helpers._API_VERSION + """The version of the API, used in building the API call's URL.""" + + API_URL_TEMPLATE = "{api_base_url}/storage/{api_version}{path}" + """A template for the URL of a particular API call.""" + + def api_request(self, *args, **kwargs): + retry = kwargs.pop("retry", None) + kwargs["extra_api_info"] = _helpers._get_invocation_id() + call = functools.partial(super(Connection, self).api_request, *args, **kwargs) + if retry: + # If this is a ConditionalRetryPolicy, check conditions. + try: + retry = retry.get_retry_policy_if_conditions_met(**kwargs) + except AttributeError: # This is not a ConditionalRetryPolicy. + pass + if retry: + call = retry(call) + return call() diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/_signing.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/_signing.py new file mode 100644 index 000000000000..fb50a2acc5c5 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/_signing.py @@ -0,0 +1,720 @@ +# Copyright 2017 Google LLC +# +# 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. + + +import base64 +import binascii +import collections +import datetime +import hashlib +import json + +import http +import urllib + +import google.auth.credentials + +from google.auth import exceptions +from google.auth.transport import requests +from google.cloud import _helpers + + +NOW = datetime.datetime.utcnow # To be replaced by tests. + +SERVICE_ACCOUNT_URL = ( + "https://googleapis.dev/python/google-api-core/latest/" + "auth.html#setting-up-a-service-account" +) + + +def ensure_signed_credentials(credentials): + """Raise AttributeError if the credentials are unsigned. + + :type credentials: :class:`google.auth.credentials.Signing` + :param credentials: The credentials used to create a private key + for signing text. + + :raises: :exc:`AttributeError` if credentials is not an instance + of :class:`google.auth.credentials.Signing`. + """ + if not isinstance(credentials, google.auth.credentials.Signing): + raise AttributeError( + "you need a private key to sign credentials." + "the credentials you are currently using {} " + "just contains a token. see {} for more " + "details.".format(type(credentials), SERVICE_ACCOUNT_URL) + ) + + +def get_signed_query_params_v2(credentials, expiration, string_to_sign): + """Gets query parameters for creating a signed URL. + + :type credentials: :class:`google.auth.credentials.Signing` + :param credentials: The credentials used to create a private key + for signing text. + + :type expiration: int or long + :param expiration: When the signed URL should expire. + + :type string_to_sign: str + :param string_to_sign: The string to be signed by the credentials. + + :raises: :exc:`AttributeError` if credentials is not an instance + of :class:`google.auth.credentials.Signing`. + + :rtype: dict + :returns: Query parameters matching the signing credentials with a + signed payload. + """ + ensure_signed_credentials(credentials) + signature_bytes = credentials.sign_bytes(string_to_sign.encode("ascii")) + signature = base64.b64encode(signature_bytes) + service_account_name = credentials.signer_email + return { + "GoogleAccessId": service_account_name, + "Expires": expiration, + "Signature": signature, + } + + +def get_expiration_seconds_v2(expiration): + """Convert 'expiration' to a number of seconds in the future. + + :type expiration: Union[Integer, datetime.datetime, datetime.timedelta] + :param expiration: Point in time when the signed URL should expire. If + a ``datetime`` instance is passed without an explicit + ``tzinfo`` set, it will be assumed to be ``UTC``. + + :raises: :exc:`TypeError` when expiration is not a valid type. + + :rtype: int + :returns: a timestamp as an absolute number of seconds since epoch. + """ + # If it's a timedelta, add it to `now` in UTC. + if isinstance(expiration, datetime.timedelta): + now = NOW().replace(tzinfo=_helpers.UTC) + expiration = now + expiration + + # If it's a datetime, convert to a timestamp. + if isinstance(expiration, datetime.datetime): + micros = _helpers._microseconds_from_datetime(expiration) + expiration = micros // 10**6 + + if not isinstance(expiration, int): + raise TypeError( + "Expected an integer timestamp, datetime, or " + "timedelta. Got %s" % type(expiration) + ) + return expiration + + +_EXPIRATION_TYPES = (int, datetime.datetime, datetime.timedelta) + + +def get_expiration_seconds_v4(expiration): + """Convert 'expiration' to a number of seconds offset from the current time. + + :type expiration: Union[Integer, datetime.datetime, datetime.timedelta] + :param expiration: Point in time when the signed URL should expire. If + a ``datetime`` instance is passed without an explicit + ``tzinfo`` set, it will be assumed to be ``UTC``. + + :raises: :exc:`TypeError` when expiration is not a valid type. + :raises: :exc:`ValueError` when expiration is too large. + :rtype: Integer + :returns: seconds in the future when the signed URL will expire + """ + if not isinstance(expiration, _EXPIRATION_TYPES): + raise TypeError( + "Expected an integer timestamp, datetime, or " + "timedelta. Got %s" % type(expiration) + ) + + now = NOW().replace(tzinfo=_helpers.UTC) + + if isinstance(expiration, int): + seconds = expiration + + if isinstance(expiration, datetime.datetime): + + if expiration.tzinfo is None: + expiration = expiration.replace(tzinfo=_helpers.UTC) + + expiration = expiration - now + + if isinstance(expiration, datetime.timedelta): + seconds = int(expiration.total_seconds()) + + if seconds > SEVEN_DAYS: + raise ValueError(f"Max allowed expiration interval is seven days {SEVEN_DAYS}") + + return seconds + + +def get_canonical_headers(headers): + """Canonicalize headers for signing. + + See: + https://cloud.google.com/storage/docs/access-control/signed-urls#about-canonical-extension-headers + + :type headers: Union[dict|List(Tuple(str,str))] + :param headers: + (Optional) Additional HTTP headers to be included as part of the + signed URLs. See: + https://cloud.google.com/storage/docs/xml-api/reference-headers + Requests using the signed URL *must* pass the specified header + (name and value) with each request for the URL. + + :rtype: str + :returns: List of headers, normalized / sortted per the URL refernced above. + """ + if headers is None: + headers = [] + elif isinstance(headers, dict): + headers = list(headers.items()) + + if not headers: + return [], [] + + normalized = collections.defaultdict(list) + for key, val in headers: + key = key.lower().strip() + val = " ".join(val.split()) + normalized[key].append(val) + + ordered_headers = sorted((key, ",".join(val)) for key, val in normalized.items()) + + canonical_headers = ["{}:{}".format(*item) for item in ordered_headers] + return canonical_headers, ordered_headers + + +_Canonical = collections.namedtuple( + "_Canonical", ["method", "resource", "query_parameters", "headers"] +) + + +def canonicalize_v2(method, resource, query_parameters, headers): + """Canonicalize method, resource per the V2 spec. + + :type method: str + :param method: The HTTP verb that will be used when requesting the URL. + Defaults to ``'GET'``. If method is ``'RESUMABLE'`` then the + signature will additionally contain the `x-goog-resumable` + header, and the method changed to POST. See the signed URL + docs regarding this flow: + https://cloud.google.com/storage/docs/access-control/signed-urls + + :type resource: str + :param resource: A pointer to a specific resource + (typically, ``/bucket-name/path/to/blob.txt``). + + :type query_parameters: dict + :param query_parameters: + (Optional) Additional query parameters to be included as part of the + signed URLs. See: + https://cloud.google.com/storage/docs/xml-api/reference-headers#query + + :type headers: Union[dict|List(Tuple(str,str))] + :param headers: + (Optional) Additional HTTP headers to be included as part of the + signed URLs. See: + https://cloud.google.com/storage/docs/xml-api/reference-headers + Requests using the signed URL *must* pass the specified header + (name and value) with each request for the URL. + + :rtype: :class:_Canonical + :returns: Canonical method, resource, query_parameters, and headers. + """ + headers, _ = get_canonical_headers(headers) + + if method == "RESUMABLE": + method = "POST" + headers.append("x-goog-resumable:start") + + if query_parameters is None: + return _Canonical(method, resource, [], headers) + + normalized_qp = sorted( + (key.lower(), value and value.strip() or "") + for key, value in query_parameters.items() + ) + encoded_qp = urllib.parse.urlencode(normalized_qp) + canonical_resource = f"{resource}?{encoded_qp}" + return _Canonical(method, canonical_resource, normalized_qp, headers) + + +def generate_signed_url_v2( + credentials, + resource, + expiration, + api_access_endpoint="", + method="GET", + content_md5=None, + content_type=None, + response_type=None, + response_disposition=None, + generation=None, + headers=None, + query_parameters=None, + service_account_email=None, + access_token=None, +): + """Generate a V2 signed URL to provide query-string auth'n to a resource. + + .. note:: + + Assumes ``credentials`` implements the + :class:`google.auth.credentials.Signing` interface. Also assumes + ``credentials`` has a ``signer_email`` property which + identifies the credentials. + + .. note:: + + If you are on Google Compute Engine, you can't generate a signed URL. + If you'd like to be able to generate a signed URL from GCE, you can use a + standard service account from a JSON file rather than a GCE service account. + + See headers [reference](https://cloud.google.com/storage/docs/reference-headers) + for more details on optional arguments. + + :type credentials: :class:`google.auth.credentials.Signing` + :param credentials: Credentials object with an associated private key to + sign text. + + :type resource: str + :param resource: A pointer to a specific resource + (typically, ``/bucket-name/path/to/blob.txt``). + Caller should have already URL-encoded the value. + + :type expiration: Union[Integer, datetime.datetime, datetime.timedelta] + :param expiration: Point in time when the signed URL should expire. If + a ``datetime`` instance is passed without an explicit + ``tzinfo`` set, it will be assumed to be ``UTC``. + + :type api_access_endpoint: str + :param api_access_endpoint: (Optional) URI base. Defaults to empty string. + + :type method: str + :param method: The HTTP verb that will be used when requesting the URL. + Defaults to ``'GET'``. If method is ``'RESUMABLE'`` then the + signature will additionally contain the `x-goog-resumable` + header, and the method changed to POST. See the signed URL + docs regarding this flow: + https://cloud.google.com/storage/docs/access-control/signed-urls + + + :type content_md5: str + :param content_md5: (Optional) The MD5 hash of the object referenced by + ``resource``. + + :type content_type: str + :param content_type: (Optional) The content type of the object referenced + by ``resource``. + + :type response_type: str + :param response_type: (Optional) Content type of responses to requests for + the signed URL. Ignored if content_type is set on + object/blob metadata. + + :type response_disposition: str + :param response_disposition: (Optional) Content disposition of responses to + requests for the signed URL. + + :type generation: str + :param generation: (Optional) A value that indicates which generation of + the resource to fetch. + + :type headers: Union[dict|List(Tuple(str,str))] + :param headers: + (Optional) Additional HTTP headers to be included as part of the + signed URLs. See: + https://cloud.google.com/storage/docs/xml-api/reference-headers + Requests using the signed URL *must* pass the specified header + (name and value) with each request for the URL. + + :type service_account_email: str + :param service_account_email: (Optional) E-mail address of the service account. + + :type access_token: str + :param access_token: (Optional) Access token for a service account. + + :type query_parameters: dict + :param query_parameters: + (Optional) Additional query parameters to be included as part of the + signed URLs. See: + https://cloud.google.com/storage/docs/xml-api/reference-headers#query + + :raises: :exc:`TypeError` when expiration is not a valid type. + :raises: :exc:`AttributeError` if credentials is not an instance + of :class:`google.auth.credentials.Signing`. + + :rtype: str + :returns: A signed URL you can use to access the resource + until expiration. + """ + expiration_stamp = get_expiration_seconds_v2(expiration) + + canonical = canonicalize_v2(method, resource, query_parameters, headers) + + # Generate the string to sign. + elements_to_sign = [ + canonical.method, + content_md5 or "", + content_type or "", + str(expiration_stamp), + ] + elements_to_sign.extend(canonical.headers) + elements_to_sign.append(canonical.resource) + string_to_sign = "\n".join(elements_to_sign) + + # If you are on Google Compute Engine, you can't generate a signed URL. + # See https://github.com/googleapis/google-cloud-python/issues/922 + # Set the right query parameters. + if access_token and service_account_email: + signature = _sign_message(string_to_sign, access_token, service_account_email) + signed_query_params = { + "GoogleAccessId": service_account_email, + "Expires": expiration_stamp, + "Signature": signature, + } + else: + signed_query_params = get_signed_query_params_v2( + credentials, expiration_stamp, string_to_sign + ) + + if response_type is not None: + signed_query_params["response-content-type"] = response_type + if response_disposition is not None: + signed_query_params["response-content-disposition"] = response_disposition + if generation is not None: + signed_query_params["generation"] = generation + + signed_query_params.update(canonical.query_parameters) + sorted_signed_query_params = sorted(signed_query_params.items()) + + # Return the built URL. + return "{endpoint}{resource}?{querystring}".format( + endpoint=api_access_endpoint, + resource=resource, + querystring=urllib.parse.urlencode(sorted_signed_query_params), + ) + + +SEVEN_DAYS = 7 * 24 * 60 * 60 # max age for V4 signed URLs. +DEFAULT_ENDPOINT = "https://storage.googleapis.com" + + +def generate_signed_url_v4( + credentials, + resource, + expiration, + api_access_endpoint=DEFAULT_ENDPOINT, + method="GET", + content_md5=None, + content_type=None, + response_type=None, + response_disposition=None, + generation=None, + headers=None, + query_parameters=None, + service_account_email=None, + access_token=None, + _request_timestamp=None, # for testing only +): + """Generate a V4 signed URL to provide query-string auth'n to a resource. + + .. note:: + + Assumes ``credentials`` implements the + :class:`google.auth.credentials.Signing` interface. Also assumes + ``credentials`` has a ``signer_email`` property which + identifies the credentials. + + .. note:: + + If you are on Google Compute Engine, you can't generate a signed URL. + If you'd like to be able to generate a signed URL from GCE,you can use a + standard service account from a JSON file rather than a GCE service account. + + See headers [reference](https://cloud.google.com/storage/docs/reference-headers) + for more details on optional arguments. + + :type credentials: :class:`google.auth.credentials.Signing` + :param credentials: Credentials object with an associated private key to + sign text. That credentials must provide signer_email + only if service_account_email and access_token are not + passed. + + :type resource: str + :param resource: A pointer to a specific resource + (typically, ``/bucket-name/path/to/blob.txt``). + Caller should have already URL-encoded the value. + + :type expiration: Union[Integer, datetime.datetime, datetime.timedelta] + :param expiration: Point in time when the signed URL should expire. If + a ``datetime`` instance is passed without an explicit + ``tzinfo`` set, it will be assumed to be ``UTC``. + + :type api_access_endpoint: str + :param api_access_endpoint: (Optional) URI base. Defaults to + "https://storage.googleapis.com/" + + :type method: str + :param method: The HTTP verb that will be used when requesting the URL. + Defaults to ``'GET'``. If method is ``'RESUMABLE'`` then the + signature will additionally contain the `x-goog-resumable` + header, and the method changed to POST. See the signed URL + docs regarding this flow: + https://cloud.google.com/storage/docs/access-control/signed-urls + + + :type content_md5: str + :param content_md5: (Optional) The MD5 hash of the object referenced by + ``resource``. + + :type content_type: str + :param content_type: (Optional) The content type of the object referenced + by ``resource``. + + :type response_type: str + :param response_type: (Optional) Content type of responses to requests for + the signed URL. Ignored if content_type is set on + object/blob metadata. + + :type response_disposition: str + :param response_disposition: (Optional) Content disposition of responses to + requests for the signed URL. + + :type generation: str + :param generation: (Optional) A value that indicates which generation of + the resource to fetch. + + :type headers: dict + :param headers: + (Optional) Additional HTTP headers to be included as part of the + signed URLs. See: + https://cloud.google.com/storage/docs/xml-api/reference-headers + Requests using the signed URL *must* pass the specified header + (name and value) with each request for the URL. + + :type query_parameters: dict + :param query_parameters: + (Optional) Additional query parameters to be included as part of the + signed URLs. See: + https://cloud.google.com/storage/docs/xml-api/reference-headers#query + + :type service_account_email: str + :param service_account_email: (Optional) E-mail address of the service account. + + :type access_token: str + :param access_token: (Optional) Access token for a service account. + + :raises: :exc:`TypeError` when expiration is not a valid type. + :raises: :exc:`AttributeError` if credentials is not an instance + of :class:`google.auth.credentials.Signing`. + + :rtype: str + :returns: A signed URL you can use to access the resource + until expiration. + """ + expiration_seconds = get_expiration_seconds_v4(expiration) + + if _request_timestamp is None: + request_timestamp, datestamp = get_v4_now_dtstamps() + else: + request_timestamp = _request_timestamp + datestamp = _request_timestamp[:8] + + # If you are on Google Compute Engine, you can't generate a signed URL. + # See https://github.com/googleapis/google-cloud-python/issues/922 + client_email = service_account_email + if not access_token or not service_account_email: + ensure_signed_credentials(credentials) + client_email = credentials.signer_email + + credential_scope = f"{datestamp}/auto/storage/goog4_request" + credential = f"{client_email}/{credential_scope}" + + if headers is None: + headers = {} + + if content_type is not None: + headers["Content-Type"] = content_type + + if content_md5 is not None: + headers["Content-MD5"] = content_md5 + + header_names = [key.lower() for key in headers] + if "host" not in header_names: + headers["Host"] = urllib.parse.urlparse(api_access_endpoint).netloc + + if method.upper() == "RESUMABLE": + method = "POST" + headers["x-goog-resumable"] = "start" + + canonical_headers, ordered_headers = get_canonical_headers(headers) + canonical_header_string = ( + "\n".join(canonical_headers) + "\n" + ) # Yes, Virginia, the extra newline is part of the spec. + signed_headers = ";".join([key for key, _ in ordered_headers]) + + if query_parameters is None: + query_parameters = {} + else: + query_parameters = {key: value or "" for key, value in query_parameters.items()} + + query_parameters["X-Goog-Algorithm"] = "GOOG4-RSA-SHA256" + query_parameters["X-Goog-Credential"] = credential + query_parameters["X-Goog-Date"] = request_timestamp + query_parameters["X-Goog-Expires"] = expiration_seconds + query_parameters["X-Goog-SignedHeaders"] = signed_headers + + if response_type is not None: + query_parameters["response-content-type"] = response_type + + if response_disposition is not None: + query_parameters["response-content-disposition"] = response_disposition + + if generation is not None: + query_parameters["generation"] = generation + + canonical_query_string = _url_encode(query_parameters) + + lowercased_headers = dict(ordered_headers) + + if "x-goog-content-sha256" in lowercased_headers: + payload = lowercased_headers["x-goog-content-sha256"] + else: + payload = "UNSIGNED-PAYLOAD" + + canonical_elements = [ + method, + resource, + canonical_query_string, + canonical_header_string, + signed_headers, + payload, + ] + canonical_request = "\n".join(canonical_elements) + + canonical_request_hash = hashlib.sha256( + canonical_request.encode("ascii") + ).hexdigest() + + string_elements = [ + "GOOG4-RSA-SHA256", + request_timestamp, + credential_scope, + canonical_request_hash, + ] + string_to_sign = "\n".join(string_elements) + + if access_token and service_account_email: + signature = _sign_message(string_to_sign, access_token, service_account_email) + signature_bytes = base64.b64decode(signature) + signature = binascii.hexlify(signature_bytes).decode("ascii") + else: + signature_bytes = credentials.sign_bytes(string_to_sign.encode("ascii")) + signature = binascii.hexlify(signature_bytes).decode("ascii") + + return "{}{}?{}&X-Goog-Signature={}".format( + api_access_endpoint, resource, canonical_query_string, signature + ) + + +def get_v4_now_dtstamps(): + """Get current timestamp and datestamp in V4 valid format. + + :rtype: str, str + :returns: Current timestamp, datestamp. + """ + now = NOW() + timestamp = now.strftime("%Y%m%dT%H%M%SZ") + datestamp = now.date().strftime("%Y%m%d") + return timestamp, datestamp + + +def _sign_message(message, access_token, service_account_email): + + """Signs a message. + + :type message: str + :param message: The message to be signed. + + :type access_token: str + :param access_token: Access token for a service account. + + + :type service_account_email: str + :param service_account_email: E-mail address of the service account. + + :raises: :exc:`TransportError` if an `access_token` is unauthorized. + + :rtype: str + :returns: The signature of the message. + + """ + message = _helpers._to_bytes(message) + + method = "POST" + url = "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/{}:signBlob?alt=json".format( + service_account_email + ) + headers = { + "Authorization": "Bearer " + access_token, + "Content-type": "application/json", + } + body = json.dumps({"payload": base64.b64encode(message).decode("utf-8")}) + + request = requests.Request() + response = request(url=url, method=method, body=body, headers=headers) + + if response.status != http.client.OK: + raise exceptions.TransportError( + f"Error calling the IAM signBytes API: {response.data}" + ) + + data = json.loads(response.data.decode("utf-8")) + return data["signedBlob"] + + +def _url_encode(query_params): + """Encode query params into URL. + + :type query_params: dict + :param query_params: Query params to be encoded. + + :rtype: str + :returns: URL encoded query params. + """ + params = [ + f"{_quote_param(name)}={_quote_param(value)}" + for name, value in query_params.items() + ] + + return "&".join(sorted(params)) + + +def _quote_param(param): + """Quote query param. + + :type param: Any + :param param: Query param to be encoded. + + :rtype: str + :returns: URL encoded query param. + """ + if not isinstance(param, bytes): + param = str(param) + return urllib.parse.quote(param, safe="~") diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/acl.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/acl.py new file mode 100644 index 000000000000..4458966cecd0 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/acl.py @@ -0,0 +1,750 @@ +# Copyright 2014 Google LLC +# +# 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. + +"""Manage access to objects and buckets.""" + +from google.cloud.storage._helpers import _add_generation_match_parameters +from google.cloud.storage.constants import _DEFAULT_TIMEOUT +from google.cloud.storage.retry import DEFAULT_RETRY +from google.cloud.storage.retry import DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED + + +class _ACLEntity(object): + """Class representing a set of roles for an entity. + + This is a helper class that you likely won't ever construct + outside of using the factor methods on the :class:`ACL` object. + + :type entity_type: str + :param entity_type: The type of entity (ie, 'group' or 'user'). + + :type identifier: str + :param identifier: (Optional) The ID or e-mail of the entity. For the special + entity types (like 'allUsers'). + """ + + READER_ROLE = "READER" + WRITER_ROLE = "WRITER" + OWNER_ROLE = "OWNER" + + def __init__(self, entity_type, identifier=None): + self.identifier = identifier + self.roles = set([]) + self.type = entity_type + + def __str__(self): + if not self.identifier: + return str(self.type) + else: + return "{acl.type}-{acl.identifier}".format(acl=self) + + def __repr__(self): + return f"" + + def get_roles(self): + """Get the list of roles permitted by this entity. + + :rtype: list of strings + :returns: The list of roles associated with this entity. + """ + return self.roles + + def grant(self, role): + """Add a role to the entity. + + :type role: str + :param role: The role to add to the entity. + """ + self.roles.add(role) + + def revoke(self, role): + """Remove a role from the entity. + + :type role: str + :param role: The role to remove from the entity. + """ + if role in self.roles: + self.roles.remove(role) + + def grant_read(self): + """Grant read access to the current entity.""" + self.grant(_ACLEntity.READER_ROLE) + + def grant_write(self): + """Grant write access to the current entity.""" + self.grant(_ACLEntity.WRITER_ROLE) + + def grant_owner(self): + """Grant owner access to the current entity.""" + self.grant(_ACLEntity.OWNER_ROLE) + + def revoke_read(self): + """Revoke read access from the current entity.""" + self.revoke(_ACLEntity.READER_ROLE) + + def revoke_write(self): + """Revoke write access from the current entity.""" + self.revoke(_ACLEntity.WRITER_ROLE) + + def revoke_owner(self): + """Revoke owner access from the current entity.""" + self.revoke(_ACLEntity.OWNER_ROLE) + + +class ACL(object): + """Container class representing a list of access controls.""" + + _URL_PATH_ELEM = "acl" + _PREDEFINED_QUERY_PARAM = "predefinedAcl" + + PREDEFINED_XML_ACLS = { + # XML API name -> JSON API name + "project-private": "projectPrivate", + "public-read": "publicRead", + "public-read-write": "publicReadWrite", + "authenticated-read": "authenticatedRead", + "bucket-owner-read": "bucketOwnerRead", + "bucket-owner-full-control": "bucketOwnerFullControl", + } + + PREDEFINED_JSON_ACLS = frozenset( + [ + "private", + "projectPrivate", + "publicRead", + "publicReadWrite", + "authenticatedRead", + "bucketOwnerRead", + "bucketOwnerFullControl", + ] + ) + """See + https://cloud.google.com/storage/docs/access-control/lists#predefined-acl + """ + + loaded = False + + # Subclasses must override to provide these attributes (typically, + # as properties). + client = None + reload_path = None + save_path = None + user_project = None + + def __init__(self): + self.entities = {} + + def _ensure_loaded(self, timeout=_DEFAULT_TIMEOUT): + """Load if not already loaded. + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + """ + if not self.loaded: + self.reload(timeout=timeout) + + @classmethod + def validate_predefined(cls, predefined): + """Ensures predefined is in list of predefined json values + + :type predefined: str + :param predefined: name of a predefined acl + + :type predefined: str + :param predefined: validated JSON name of predefined acl + + :raises: :exc: `ValueError`: If predefined is not a valid acl + """ + predefined = cls.PREDEFINED_XML_ACLS.get(predefined, predefined) + if predefined and predefined not in cls.PREDEFINED_JSON_ACLS: + raise ValueError(f"Invalid predefined ACL: {predefined}") + return predefined + + def reset(self): + """Remove all entities from the ACL, and clear the ``loaded`` flag.""" + self.entities.clear() + self.loaded = False + + def __iter__(self): + self._ensure_loaded() + + for entity in self.entities.values(): + for role in entity.get_roles(): + if role: + yield {"entity": str(entity), "role": role} + + def entity_from_dict(self, entity_dict): + """Build an _ACLEntity object from a dictionary of data. + + An entity is a mutable object that represents a list of roles + belonging to either a user or group or the special types for all + users and all authenticated users. + + :type entity_dict: dict + :param entity_dict: Dictionary full of data from an ACL lookup. + + :rtype: :class:`_ACLEntity` + :returns: An Entity constructed from the dictionary. + """ + entity = entity_dict["entity"] + role = entity_dict["role"] + + if entity == "allUsers": + entity = self.all() + + elif entity == "allAuthenticatedUsers": + entity = self.all_authenticated() + + elif "-" in entity: + entity_type, identifier = entity.split("-", 1) + entity = self.entity(entity_type=entity_type, identifier=identifier) + + if not isinstance(entity, _ACLEntity): + raise ValueError(f"Invalid dictionary: {entity_dict}") + + entity.grant(role) + return entity + + def has_entity(self, entity): + """Returns whether or not this ACL has any entries for an entity. + + :type entity: :class:`_ACLEntity` + :param entity: The entity to check for existence in this ACL. + + :rtype: bool + :returns: True of the entity exists in the ACL. + """ + self._ensure_loaded() + return str(entity) in self.entities + + def get_entity(self, entity, default=None): + """Gets an entity object from the ACL. + + :type entity: :class:`_ACLEntity` or string + :param entity: The entity to get lookup in the ACL. + + :type default: anything + :param default: This value will be returned if the entity + doesn't exist. + + :rtype: :class:`_ACLEntity` + :returns: The corresponding entity or the value provided + to ``default``. + """ + self._ensure_loaded() + return self.entities.get(str(entity), default) + + def add_entity(self, entity): + """Add an entity to the ACL. + + :type entity: :class:`_ACLEntity` + :param entity: The entity to add to this ACL. + """ + self._ensure_loaded() + self.entities[str(entity)] = entity + + def entity(self, entity_type, identifier=None): + """Factory method for creating an Entity. + + If an entity with the same type and identifier already exists, + this will return a reference to that entity. If not, it will + create a new one and add it to the list of known entities for + this ACL. + + :type entity_type: str + :param entity_type: The type of entity to create + (ie, ``user``, ``group``, etc) + + :type identifier: str + :param identifier: The ID of the entity (if applicable). + This can be either an ID or an e-mail address. + + :rtype: :class:`_ACLEntity` + :returns: A new Entity or a reference to an existing identical entity. + """ + entity = _ACLEntity(entity_type=entity_type, identifier=identifier) + if self.has_entity(entity): + entity = self.get_entity(entity) + else: + self.add_entity(entity) + return entity + + def user(self, identifier): + """Factory method for a user Entity. + + :type identifier: str + :param identifier: An id or e-mail for this particular user. + + :rtype: :class:`_ACLEntity` + :returns: An Entity corresponding to this user. + """ + return self.entity("user", identifier=identifier) + + def group(self, identifier): + """Factory method for a group Entity. + + :type identifier: str + :param identifier: An id or e-mail for this particular group. + + :rtype: :class:`_ACLEntity` + :returns: An Entity corresponding to this group. + """ + return self.entity("group", identifier=identifier) + + def domain(self, domain): + """Factory method for a domain Entity. + + :type domain: str + :param domain: The domain for this entity. + + :rtype: :class:`_ACLEntity` + :returns: An entity corresponding to this domain. + """ + return self.entity("domain", identifier=domain) + + def all(self): + """Factory method for an Entity representing all users. + + :rtype: :class:`_ACLEntity` + :returns: An entity representing all users. + """ + return self.entity("allUsers") + + def all_authenticated(self): + """Factory method for an Entity representing all authenticated users. + + :rtype: :class:`_ACLEntity` + :returns: An entity representing all authenticated users. + """ + return self.entity("allAuthenticatedUsers") + + def get_entities(self): + """Get a list of all Entity objects. + + :rtype: list of :class:`_ACLEntity` objects + :returns: A list of all Entity objects. + """ + self._ensure_loaded() + return list(self.entities.values()) + + @property + def client(self): + """Abstract getter for the object client.""" + raise NotImplementedError + + def _require_client(self, client): + """Check client or verify over-ride. + + :type client: :class:`~google.cloud.storage.client.Client` or + ``NoneType`` + :param client: the client to use. If not passed, falls back to the + ``client`` stored on the current ACL. + + :rtype: :class:`google.cloud.storage.client.Client` + :returns: The client passed in or the currently bound client. + """ + if client is None: + client = self.client + return client + + def reload(self, client=None, timeout=_DEFAULT_TIMEOUT, retry=DEFAULT_RETRY): + """Reload the ACL data from Cloud Storage. + + If :attr:`user_project` is set, bills the API request to that project. + + :type client: :class:`~google.cloud.storage.client.Client` or + ``NoneType`` + :param client: (Optional) The client to use. If not passed, falls back + to the ``client`` stored on the ACL's parent. + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type retry: :class:`~google.api_core.retry.Retry` + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + """ + path = self.reload_path + client = self._require_client(client) + query_params = {} + + if self.user_project is not None: + query_params["userProject"] = self.user_project + + self.entities.clear() + + found = client._get_resource( + path, + query_params=query_params, + timeout=timeout, + retry=retry, + ) + self.loaded = True + + for entry in found.get("items", ()): + self.add_entity(self.entity_from_dict(entry)) + + def _save( + self, + acl, + predefined, + client, + if_generation_match=None, + if_generation_not_match=None, + if_metageneration_match=None, + if_metageneration_not_match=None, + timeout=_DEFAULT_TIMEOUT, + retry=DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED, + ): + """Helper for :meth:`save` and :meth:`save_predefined`. + + :type acl: :class:`google.cloud.storage.acl.ACL`, or a compatible list. + :param acl: The ACL object to save. If left blank, this will save + current entries. + + :type predefined: str + :param predefined: An identifier for a predefined ACL. Must be one of the + keys in :attr:`PREDEFINED_JSON_ACLS` If passed, `acl` must be None. + + :type client: :class:`~google.cloud.storage.client.Client` or + ``NoneType`` + :param client: (Optional) The client to use. If not passed, falls back + to the ``client`` stored on the ACL's parent. + + :type if_generation_match: long + :param if_generation_match: + (Optional) See :ref:`using-if-generation-match` + + :type if_generation_not_match: long + :param if_generation_not_match: + (Optional) See :ref:`using-if-generation-not-match` + + :type if_metageneration_match: long + :param if_metageneration_match: + (Optional) See :ref:`using-if-metageneration-match` + + :type if_metageneration_not_match: long + :param if_metageneration_not_match: + (Optional) See :ref:`using-if-metageneration-not-match` + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + """ + client = self._require_client(client) + query_params = {"projection": "full"} + + if predefined is not None: + acl = [] + query_params[self._PREDEFINED_QUERY_PARAM] = predefined + + if self.user_project is not None: + query_params["userProject"] = self.user_project + + _add_generation_match_parameters( + query_params, + if_generation_match=if_generation_match, + if_generation_not_match=if_generation_not_match, + if_metageneration_match=if_metageneration_match, + if_metageneration_not_match=if_metageneration_not_match, + ) + + path = self.save_path + + result = client._patch_resource( + path, + {self._URL_PATH_ELEM: list(acl)}, + query_params=query_params, + timeout=timeout, + retry=retry, + ) + + self.entities.clear() + + for entry in result.get(self._URL_PATH_ELEM, ()): + self.add_entity(self.entity_from_dict(entry)) + + self.loaded = True + + def save( + self, + acl=None, + client=None, + if_generation_match=None, + if_generation_not_match=None, + if_metageneration_match=None, + if_metageneration_not_match=None, + timeout=_DEFAULT_TIMEOUT, + retry=DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED, + ): + """Save this ACL for the current bucket. + + If :attr:`user_project` is set, bills the API request to that project. + + :type acl: :class:`google.cloud.storage.acl.ACL`, or a compatible list. + :param acl: The ACL object to save. If left blank, this will save + current entries. + + :type client: :class:`~google.cloud.storage.client.Client` or + ``NoneType`` + :param client: (Optional) The client to use. If not passed, falls back + to the ``client`` stored on the ACL's parent. + + :type if_generation_match: long + :param if_generation_match: + (Optional) See :ref:`using-if-generation-match` + + :type if_generation_not_match: long + :param if_generation_not_match: + (Optional) See :ref:`using-if-generation-not-match` + + :type if_metageneration_match: long + :param if_metageneration_match: + (Optional) See :ref:`using-if-metageneration-match` + + :type if_metageneration_not_match: long + :param if_metageneration_not_match: + (Optional) See :ref:`using-if-metageneration-not-match` + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + """ + if acl is None: + acl = self + save_to_backend = acl.loaded + else: + save_to_backend = True + + if save_to_backend: + self._save( + acl, + None, + client, + if_generation_match=if_generation_match, + if_generation_not_match=if_generation_not_match, + if_metageneration_match=if_metageneration_match, + if_metageneration_not_match=if_metageneration_not_match, + timeout=timeout, + retry=retry, + ) + + def save_predefined( + self, + predefined, + client=None, + if_generation_match=None, + if_generation_not_match=None, + if_metageneration_match=None, + if_metageneration_not_match=None, + timeout=_DEFAULT_TIMEOUT, + retry=DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED, + ): + """Save this ACL for the current bucket using a predefined ACL. + + If :attr:`user_project` is set, bills the API request to that project. + + :type predefined: str + :param predefined: An identifier for a predefined ACL. Must be one + of the keys in :attr:`PREDEFINED_JSON_ACLS` + or :attr:`PREDEFINED_XML_ACLS` (which will be + aliased to the corresponding JSON name). + If passed, `acl` must be None. + + :type client: :class:`~google.cloud.storage.client.Client` or + ``NoneType`` + :param client: (Optional) The client to use. If not passed, falls back + to the ``client`` stored on the ACL's parent. + + :type if_generation_match: long + :param if_generation_match: + (Optional) See :ref:`using-if-generation-match` + + :type if_generation_not_match: long + :param if_generation_not_match: + (Optional) See :ref:`using-if-generation-not-match` + + :type if_metageneration_match: long + :param if_metageneration_match: + (Optional) See :ref:`using-if-metageneration-match` + + :type if_metageneration_not_match: long + :param if_metageneration_not_match: + (Optional) See :ref:`using-if-metageneration-not-match` + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + """ + predefined = self.validate_predefined(predefined) + self._save( + None, + predefined, + client, + if_generation_match=if_generation_match, + if_generation_not_match=if_generation_not_match, + if_metageneration_match=if_metageneration_match, + if_metageneration_not_match=if_metageneration_not_match, + timeout=timeout, + retry=retry, + ) + + def clear( + self, + client=None, + if_generation_match=None, + if_generation_not_match=None, + if_metageneration_match=None, + if_metageneration_not_match=None, + timeout=_DEFAULT_TIMEOUT, + retry=DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED, + ): + """Remove all ACL entries. + + If :attr:`user_project` is set, bills the API request to that project. + + Note that this won't actually remove *ALL* the rules, but it + will remove all the non-default rules. In short, you'll still + have access to a bucket that you created even after you clear + ACL rules with this method. + + :type client: :class:`~google.cloud.storage.client.Client` or + ``NoneType`` + :param client: (Optional) The client to use. If not passed, falls back + to the ``client`` stored on the ACL's parent. + + :type if_generation_match: long + :param if_generation_match: + (Optional) See :ref:`using-if-generation-match` + + :type if_generation_not_match: long + :param if_generation_not_match: + (Optional) See :ref:`using-if-generation-not-match` + + :type if_metageneration_match: long + :param if_metageneration_match: + (Optional) See :ref:`using-if-metageneration-match` + + :type if_metageneration_not_match: long + :param if_metageneration_not_match: + (Optional) See :ref:`using-if-metageneration-not-match` + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + """ + self.save( + [], + client=client, + if_generation_match=if_generation_match, + if_generation_not_match=if_generation_not_match, + if_metageneration_match=if_metageneration_match, + if_metageneration_not_match=if_metageneration_not_match, + timeout=timeout, + retry=retry, + ) + + +class BucketACL(ACL): + """An ACL specifically for a bucket. + + :type bucket: :class:`google.cloud.storage.bucket.Bucket` + :param bucket: The bucket to which this ACL relates. + """ + + def __init__(self, bucket): + super(BucketACL, self).__init__() + self.bucket = bucket + + @property + def client(self): + """The client bound to this ACL's bucket.""" + return self.bucket.client + + @property + def reload_path(self): + """Compute the path for GET API requests for this ACL.""" + return f"{self.bucket.path}/{self._URL_PATH_ELEM}" + + @property + def save_path(self): + """Compute the path for PATCH API requests for this ACL.""" + return self.bucket.path + + @property + def user_project(self): + """Compute the user project charged for API requests for this ACL.""" + return self.bucket.user_project + + +class DefaultObjectACL(BucketACL): + """A class representing the default object ACL for a bucket.""" + + _URL_PATH_ELEM = "defaultObjectAcl" + _PREDEFINED_QUERY_PARAM = "predefinedDefaultObjectAcl" + + +class ObjectACL(ACL): + """An ACL specifically for a Cloud Storage object / blob. + + :type blob: :class:`google.cloud.storage.blob.Blob` + :param blob: The blob that this ACL corresponds to. + """ + + def __init__(self, blob): + super(ObjectACL, self).__init__() + self.blob = blob + + @property + def client(self): + """The client bound to this ACL's blob.""" + return self.blob.client + + @property + def reload_path(self): + """Compute the path for GET API requests for this ACL.""" + return f"{self.blob.path}/acl" + + @property + def save_path(self): + """Compute the path for PATCH API requests for this ACL.""" + return self.blob.path + + @property + def user_project(self): + """Compute the user project charged for API requests for this ACL.""" + return self.blob.user_project diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/batch.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/batch.py new file mode 100644 index 000000000000..599aa3a7f7d1 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/batch.py @@ -0,0 +1,339 @@ +# Copyright 2014 Google LLC +# +# 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. +"""Batch updates / deletes of storage buckets / blobs. + +See https://cloud.google.com/storage/docs/json_api/v1/how-tos/batch +""" +from email.encoders import encode_noop +from email.generator import Generator +from email.mime.application import MIMEApplication +from email.mime.multipart import MIMEMultipart +from email.parser import Parser +import io +import json + +import requests + +from google.cloud import _helpers +from google.cloud import exceptions +from google.cloud.storage._http import Connection +from google.cloud.storage.constants import _DEFAULT_TIMEOUT + + +class MIMEApplicationHTTP(MIMEApplication): + """MIME type for ``application/http``. + + Constructs payload from headers and body + + :type method: str + :param method: HTTP method + + :type uri: str + :param uri: URI for HTTP request + + :type headers: dict + :param headers: HTTP headers + + :type body: str + :param body: (Optional) HTTP payload + + """ + + def __init__(self, method, uri, headers, body): + if isinstance(body, dict): + body = json.dumps(body) + headers["Content-Type"] = "application/json" + headers["Content-Length"] = len(body) + if body is None: + body = "" + lines = [f"{method} {uri} HTTP/1.1"] + lines.extend([f"{key}: {value}" for key, value in sorted(headers.items())]) + lines.append("") + lines.append(body) + payload = "\r\n".join(lines) + super().__init__(payload, "http", encode_noop) + + +class _FutureDict(object): + """Class to hold a future value for a deferred request. + + Used by for requests that get sent in a :class:`Batch`. + """ + + @staticmethod + def get(key, default=None): + """Stand-in for dict.get. + + :type key: object + :param key: Hashable dictionary key. + + :type default: object + :param default: Fallback value to dict.get. + + :raises: :class:`KeyError` always since the future is intended to fail + as a dictionary. + """ + raise KeyError(f"Cannot get({key!r}, default={default!r}) on a future") + + def __getitem__(self, key): + """Stand-in for dict[key]. + + :type key: object + :param key: Hashable dictionary key. + + :raises: :class:`KeyError` always since the future is intended to fail + as a dictionary. + """ + raise KeyError(f"Cannot get item {key!r} from a future") + + def __setitem__(self, key, value): + """Stand-in for dict[key] = value. + + :type key: object + :param key: Hashable dictionary key. + + :type value: object + :param value: Dictionary value. + + :raises: :class:`KeyError` always since the future is intended to fail + as a dictionary. + """ + raise KeyError(f"Cannot set {key!r} -> {value!r} on a future") + + +class _FutureResponse(requests.Response): + """Reponse that returns a placeholder dictionary for a batched requests.""" + + def __init__(self, future_dict): + super(_FutureResponse, self).__init__() + self._future_dict = future_dict + self.status_code = 204 + + def json(self): + return self._future_dict + + @property + def content(self): + return self._future_dict + + +class Batch(Connection): + """Proxy an underlying connection, batching up change operations. + + :type client: :class:`google.cloud.storage.client.Client` + :param client: The client to use for making connections. + """ + + _MAX_BATCH_SIZE = 1000 + + def __init__(self, client): + api_endpoint = client._connection.API_BASE_URL + client_info = client._connection._client_info + super(Batch, self).__init__( + client, client_info=client_info, api_endpoint=api_endpoint + ) + self._requests = [] + self._target_objects = [] + + def _do_request( + self, method, url, headers, data, target_object, timeout=_DEFAULT_TIMEOUT + ): + """Override Connection: defer actual HTTP request. + + Only allow up to ``_MAX_BATCH_SIZE`` requests to be deferred. + + :type method: str + :param method: The HTTP method to use in the request. + + :type url: str + :param url: The URL to send the request to. + + :type headers: dict + :param headers: A dictionary of HTTP headers to send with the request. + + :type data: str + :param data: The data to send as the body of the request. + + :type target_object: object + :param target_object: + (Optional) This allows us to enable custom behavior in our batch + connection. Here we defer an HTTP request and complete + initialization of the object at a later time. + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :rtype: tuple of ``response`` (a dictionary of sorts) + and ``content`` (a string). + :returns: The HTTP response object and the content of the response. + """ + if len(self._requests) >= self._MAX_BATCH_SIZE: + raise ValueError( + "Too many deferred requests (max %d)" % self._MAX_BATCH_SIZE + ) + self._requests.append((method, url, headers, data, timeout)) + result = _FutureDict() + self._target_objects.append(target_object) + if target_object is not None: + target_object._properties = result + return _FutureResponse(result) + + def _prepare_batch_request(self): + """Prepares headers and body for a batch request. + + :rtype: tuple (dict, str) + :returns: The pair of headers and body of the batch request to be sent. + :raises: :class:`ValueError` if no requests have been deferred. + """ + if len(self._requests) == 0: + raise ValueError("No deferred requests") + + multi = MIMEMultipart() + + # Use timeout of last request, default to _DEFAULT_TIMEOUT + timeout = _DEFAULT_TIMEOUT + for method, uri, headers, body, _timeout in self._requests: + subrequest = MIMEApplicationHTTP(method, uri, headers, body) + multi.attach(subrequest) + timeout = _timeout + + buf = io.StringIO() + generator = Generator(buf, False, 0) + generator.flatten(multi) + payload = buf.getvalue() + + # Strip off redundant header text + _, body = payload.split("\n\n", 1) + return dict(multi._headers), body, timeout + + def _finish_futures(self, responses): + """Apply all the batch responses to the futures created. + + :type responses: list of (headers, payload) tuples. + :param responses: List of headers and payloads from each response in + the batch. + + :raises: :class:`ValueError` if no requests have been deferred. + """ + # If a bad status occurs, we track it, but don't raise an exception + # until all futures have been populated. + exception_args = None + + if len(self._target_objects) != len(responses): # pragma: NO COVER + raise ValueError("Expected a response for every request.") + + for target_object, subresponse in zip(self._target_objects, responses): + if not 200 <= subresponse.status_code < 300: + exception_args = exception_args or subresponse + elif target_object is not None: + try: + target_object._properties = subresponse.json() + except ValueError: + target_object._properties = subresponse.content + + if exception_args is not None: + raise exceptions.from_http_response(exception_args) + + def finish(self): + """Submit a single `multipart/mixed` request with deferred requests. + + :rtype: list of tuples + :returns: one ``(headers, payload)`` tuple per deferred request. + """ + headers, body, timeout = self._prepare_batch_request() + + url = f"{self.API_BASE_URL}/batch/storage/v1" + + # Use the private ``_base_connection`` rather than the property + # ``_connection``, since the property may be this + # current batch. + response = self._client._base_connection._make_request( + "POST", url, data=body, headers=headers, timeout=timeout + ) + + # Raise exception if the top-level batch request fails + if not 200 <= response.status_code < 300: + raise exceptions.from_http_response(response) + + responses = list(_unpack_batch_response(response)) + self._finish_futures(responses) + return responses + + def current(self): + """Return the topmost batch, or None.""" + return self._client.current_batch + + def __enter__(self): + self._client._push_batch(self) + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + try: + if exc_type is None: + self.finish() + finally: + self._client._pop_batch() + + +def _generate_faux_mime_message(parser, response): + """Convert response, content -> (multipart) email.message. + + Helper for _unpack_batch_response. + """ + # We coerce to bytes to get consistent concat across + # Py2 and Py3. Percent formatting is insufficient since + # it includes the b in Py3. + content_type = _helpers._to_bytes(response.headers.get("content-type", "")) + + faux_message = b"".join( + [b"Content-Type: ", content_type, b"\nMIME-Version: 1.0\n\n", response.content] + ) + + return parser.parsestr(faux_message.decode("utf-8")) + + +def _unpack_batch_response(response): + """Convert requests.Response -> [(headers, payload)]. + + Creates a generator of tuples of emulating the responses to + :meth:`requests.Session.request`. + + :type response: :class:`requests.Response` + :param response: HTTP response / headers from a request. + """ + parser = Parser() + message = _generate_faux_mime_message(parser, response) + + if not isinstance(message._payload, list): # pragma: NO COVER + raise ValueError("Bad response: not multi-part") + + for subrequest in message._payload: + status_line, rest = subrequest._payload.split("\n", 1) + _, status, _ = status_line.split(" ", 2) + sub_message = parser.parsestr(rest) + payload = sub_message._payload + msg_headers = dict(sub_message._headers) + content_id = msg_headers.get("Content-ID") + + subresponse = requests.Response() + subresponse.request = requests.Request( + method="BATCH", url=f"contentid://{content_id}" + ).prepare() + subresponse.status_code = int(status) + subresponse.headers.update(msg_headers) + subresponse._content = payload.encode("utf-8") + + yield subresponse diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/blob.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/blob.py new file mode 100644 index 000000000000..6f4952f443fa --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/blob.py @@ -0,0 +1,4389 @@ +# Copyright 2014 Google LLC +# +# 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. + +# pylint: disable=too-many-lines + +"""Create / interact with Google Cloud Storage blobs. +""" + +import base64 +import cgi +import copy +import hashlib +from io import BytesIO +from io import TextIOWrapper +import logging +import mimetypes +import os +import re +from urllib.parse import parse_qsl +from urllib.parse import quote +from urllib.parse import urlencode +from urllib.parse import urlsplit +from urllib.parse import urlunsplit +import warnings + +from google import resumable_media +from google.resumable_media.requests import ChunkedDownload +from google.resumable_media.requests import Download +from google.resumable_media.requests import RawDownload +from google.resumable_media.requests import RawChunkedDownload +from google.resumable_media.requests import MultipartUpload +from google.resumable_media.requests import ResumableUpload + +from google.api_core.iam import Policy +from google.cloud import exceptions +from google.cloud._helpers import _bytes_to_unicode +from google.cloud._helpers import _datetime_to_rfc3339 +from google.cloud._helpers import _rfc3339_nanos_to_datetime +from google.cloud._helpers import _to_bytes +from google.cloud.exceptions import NotFound +from google.cloud.storage._helpers import _add_etag_match_headers +from google.cloud.storage._helpers import _add_generation_match_parameters +from google.cloud.storage._helpers import _PropertyMixin +from google.cloud.storage._helpers import _scalar_property +from google.cloud.storage._helpers import _bucket_bound_hostname_url +from google.cloud.storage._helpers import _raise_if_more_than_one_set +from google.cloud.storage._helpers import _api_core_retry_to_resumable_media_retry +from google.cloud.storage._helpers import _get_default_headers +from google.cloud.storage._signing import generate_signed_url_v2 +from google.cloud.storage._signing import generate_signed_url_v4 +from google.cloud.storage._helpers import _NUM_RETRIES_MESSAGE +from google.cloud.storage._helpers import _DEFAULT_STORAGE_HOST +from google.cloud.storage._helpers import _API_VERSION +from google.cloud.storage.acl import ACL +from google.cloud.storage.acl import ObjectACL +from google.cloud.storage.constants import _DEFAULT_TIMEOUT +from google.cloud.storage.constants import ARCHIVE_STORAGE_CLASS +from google.cloud.storage.constants import COLDLINE_STORAGE_CLASS +from google.cloud.storage.constants import MULTI_REGIONAL_LEGACY_STORAGE_CLASS +from google.cloud.storage.constants import NEARLINE_STORAGE_CLASS +from google.cloud.storage.constants import REGIONAL_LEGACY_STORAGE_CLASS +from google.cloud.storage.constants import STANDARD_STORAGE_CLASS +from google.cloud.storage.retry import ConditionalRetryPolicy +from google.cloud.storage.retry import DEFAULT_RETRY +from google.cloud.storage.retry import DEFAULT_RETRY_IF_ETAG_IN_JSON +from google.cloud.storage.retry import DEFAULT_RETRY_IF_GENERATION_SPECIFIED +from google.cloud.storage.retry import DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED +from google.cloud.storage.fileio import BlobReader +from google.cloud.storage.fileio import BlobWriter + + +_API_ACCESS_ENDPOINT = _DEFAULT_STORAGE_HOST +_DEFAULT_CONTENT_TYPE = "application/octet-stream" +_DOWNLOAD_URL_TEMPLATE = "{hostname}/download/storage/{api_version}{path}?alt=media" +_BASE_UPLOAD_TEMPLATE = ( + "{hostname}/upload/storage/{api_version}{bucket_path}/o?uploadType=" +) +_MULTIPART_URL_TEMPLATE = _BASE_UPLOAD_TEMPLATE + "multipart" +_RESUMABLE_URL_TEMPLATE = _BASE_UPLOAD_TEMPLATE + "resumable" +# NOTE: "acl" is also writeable but we defer ACL management to +# the classes in the google.cloud.storage.acl module. +_CONTENT_TYPE_FIELD = "contentType" +_WRITABLE_FIELDS = ( + "cacheControl", + "contentDisposition", + "contentEncoding", + "contentLanguage", + _CONTENT_TYPE_FIELD, + "crc32c", + "customTime", + "md5Hash", + "metadata", + "name", + "storageClass", +) +_READ_LESS_THAN_SIZE = ( + "Size {:d} was specified but the file-like object only had " "{:d} bytes remaining." +) +_CHUNKED_DOWNLOAD_CHECKSUM_MESSAGE = ( + "A checksum of type `{}` was requested, but checksumming is not available " + "for downloads when chunk_size is set." +) +_COMPOSE_IF_GENERATION_LIST_DEPRECATED = ( + "'if_generation_match: type list' is deprecated and supported for " + "backwards-compatability reasons only. Use 'if_source_generation_match' " + "instead' to match source objects' generations." +) +_COMPOSE_IF_GENERATION_LIST_AND_IF_SOURCE_GENERATION_ERROR = ( + "Use 'if_generation_match' to match the generation of the destination " + "object by passing in a generation number, instead of a list. " + "Use 'if_source_generation_match' to match source objects generations." +) +_COMPOSE_IF_METAGENERATION_LIST_DEPRECATED = ( + "'if_metageneration_match: type list' is deprecated and supported for " + "backwards-compatability reasons only. Note that the metageneration to " + "be matched is that of the destination blob. Please pass in a single " + "value (type long)." +) +_COMPOSE_IF_SOURCE_GENERATION_MISMATCH_ERROR = ( + "'if_source_generation_match' length must be the same as 'sources' length" +) +_DOWNLOAD_AS_STRING_DEPRECATED = ( + "Blob.download_as_string() is deprecated and will be removed in future. " + "Use Blob.download_as_bytes() instead." +) + + +_DEFAULT_CHUNKSIZE = 104857600 # 1024 * 1024 B * 100 = 100 MB +_MAX_MULTIPART_SIZE = 8388608 # 8 MB + +_logger = logging.getLogger(__name__) + + +class Blob(_PropertyMixin): + """A wrapper around Cloud Storage's concept of an ``Object``. + + :type name: str + :param name: The name of the blob. This corresponds to the unique path of + the object in the bucket. If bytes, will be converted to a + unicode object. Blob / object names can contain any sequence + of valid unicode characters, of length 1-1024 bytes when + UTF-8 encoded. + + :type bucket: :class:`google.cloud.storage.bucket.Bucket` + :param bucket: The bucket to which this blob belongs. + + :type chunk_size: int + :param chunk_size: + (Optional) The size of a chunk of data whenever iterating (in bytes). + This must be a multiple of 256 KB per the API specification. If not + specified, the chunk_size of the blob itself is used. If that is not + specified, a default value of 40 MB is used. + + :type encryption_key: bytes + :param encryption_key: + (Optional) 32 byte encryption key for customer-supplied encryption. + See https://cloud.google.com/storage/docs/encryption#customer-supplied. + + :type kms_key_name: str + :param kms_key_name: + (Optional) Resource name of Cloud KMS key used to encrypt the blob's + contents. + + :type generation: long + :param generation: + (Optional) If present, selects a specific revision of this object. + """ + + _chunk_size = None # Default value for each instance. + _CHUNK_SIZE_MULTIPLE = 256 * 1024 + """Number (256 KB, in bytes) that must divide the chunk size.""" + + STORAGE_CLASSES = ( + STANDARD_STORAGE_CLASS, + NEARLINE_STORAGE_CLASS, + COLDLINE_STORAGE_CLASS, + ARCHIVE_STORAGE_CLASS, + MULTI_REGIONAL_LEGACY_STORAGE_CLASS, + REGIONAL_LEGACY_STORAGE_CLASS, + ) + """Allowed values for :attr:`storage_class`. + + See + https://cloud.google.com/storage/docs/json_api/v1/objects#storageClass + https://cloud.google.com/storage/docs/per-object-storage-class + + .. note:: + This list does not include 'DURABLE_REDUCED_AVAILABILITY', which + is only documented for buckets (and deprecated). + """ + + def __init__( + self, + name, + bucket, + chunk_size=None, + encryption_key=None, + kms_key_name=None, + generation=None, + ): + """ + property :attr:`name` + Get the blob's name. + """ + name = _bytes_to_unicode(name) + super(Blob, self).__init__(name=name) + + self.chunk_size = chunk_size # Check that setter accepts value. + self._bucket = bucket + self._acl = ObjectACL(self) + _raise_if_more_than_one_set( + encryption_key=encryption_key, kms_key_name=kms_key_name + ) + + self._encryption_key = encryption_key + + if kms_key_name is not None: + self._properties["kmsKeyName"] = kms_key_name + + if generation is not None: + self._properties["generation"] = generation + + @property + def bucket(self): + """Bucket which contains the object. + + :rtype: :class:`~google.cloud.storage.bucket.Bucket` + :returns: The object's bucket. + """ + return self._bucket + + @property + def chunk_size(self): + """Get the blob's default chunk size. + + :rtype: int or ``NoneType`` + :returns: The current blob's chunk size, if it is set. + """ + return self._chunk_size + + @chunk_size.setter + def chunk_size(self, value): + """Set the blob's default chunk size. + + :type value: int + :param value: (Optional) The current blob's chunk size, if it is set. + + :raises: :class:`ValueError` if ``value`` is not ``None`` and is not a + multiple of 256 KB. + """ + if value is not None and value > 0 and value % self._CHUNK_SIZE_MULTIPLE != 0: + raise ValueError( + "Chunk size must be a multiple of %d." % (self._CHUNK_SIZE_MULTIPLE,) + ) + self._chunk_size = value + + @property + def encryption_key(self): + """Retrieve the customer-supplied encryption key for the object. + + :rtype: bytes or ``NoneType`` + :returns: + The encryption key or ``None`` if no customer-supplied encryption key was used, + or the blob's resource has not been loaded from the server. + """ + return self._encryption_key + + @encryption_key.setter + def encryption_key(self, value): + """Set the blob's encryption key. + + See https://cloud.google.com/storage/docs/encryption#customer-supplied + + To perform a key rotation for an encrypted blob, use :meth:`rewrite`. + See https://cloud.google.com/storage/docs/encryption/using-customer-supplied-keys?hl=ca#rotating + + :type value: bytes + :param value: 32 byte encryption key for customer-supplied encryption. + """ + self._encryption_key = value + + @staticmethod + def path_helper(bucket_path, blob_name): + """Relative URL path for a blob. + + :type bucket_path: str + :param bucket_path: The URL path for a bucket. + + :type blob_name: str + :param blob_name: The name of the blob. + + :rtype: str + :returns: The relative URL path for ``blob_name``. + """ + return bucket_path + "/o/" + _quote(blob_name) + + @property + def acl(self): + """Create our ACL on demand.""" + return self._acl + + def __repr__(self): + if self.bucket: + bucket_name = self.bucket.name + else: + bucket_name = None + + return f"" + + @property + def path(self): + """Getter property for the URL path to this Blob. + + :rtype: str + :returns: The URL path to this Blob. + """ + if not self.name: + raise ValueError("Cannot determine path without a blob name.") + + return self.path_helper(self.bucket.path, self.name) + + @property + def client(self): + """The client bound to this blob.""" + return self.bucket.client + + @property + def user_project(self): + """Project ID billed for API requests made via this blob. + + Derived from bucket's value. + + :rtype: str + """ + return self.bucket.user_project + + def _encryption_headers(self): + """Return any encryption headers needed to fetch the object. + + :rtype: List(Tuple(str, str)) + :returns: a list of tuples to be passed as headers. + """ + return _get_encryption_headers(self._encryption_key) + + @property + def _query_params(self): + """Default query parameters.""" + params = {} + if self.generation is not None: + params["generation"] = self.generation + if self.user_project is not None: + params["userProject"] = self.user_project + return params + + @property + def public_url(self): + """The public URL for this blob. + + Use :meth:`make_public` to enable anonymous access via the returned + URL. + + :rtype: `string` + :returns: The public URL for this blob. + """ + return "{storage_base_url}/{bucket_name}/{quoted_name}".format( + storage_base_url=_API_ACCESS_ENDPOINT, + bucket_name=self.bucket.name, + quoted_name=_quote(self.name, safe=b"/~"), + ) + + @classmethod + def from_string(cls, uri, client=None): + """Get a constructor for blob object by URI. + + .. code-block:: python + + from google.cloud import storage + from google.cloud.storage.blob import Blob + client = storage.Client() + blob = Blob.from_string("gs://bucket/object", client=client) + + :type uri: str + :param uri: The blob uri pass to get blob object. + + :type client: :class:`~google.cloud.storage.client.Client` + :param client: + (Optional) The client to use. Application code should + *always* pass ``client``. + + :rtype: :class:`google.cloud.storage.blob.Blob` + :returns: The blob object created. + """ + from google.cloud.storage.bucket import Bucket + + scheme, netloc, path, query, frag = urlsplit(uri) + if scheme != "gs": + raise ValueError("URI scheme must be gs") + + bucket = Bucket(client, name=netloc) + return cls(path[1:], bucket) + + def generate_signed_url( + self, + expiration=None, + api_access_endpoint=_API_ACCESS_ENDPOINT, + method="GET", + content_md5=None, + content_type=None, + response_disposition=None, + response_type=None, + generation=None, + headers=None, + query_parameters=None, + client=None, + credentials=None, + version=None, + service_account_email=None, + access_token=None, + virtual_hosted_style=False, + bucket_bound_hostname=None, + scheme="http", + ): + """Generates a signed URL for this blob. + + .. note:: + + If you are on Google Compute Engine, you can't generate a signed + URL using GCE service account. + If you'd like to be able to generate a signed URL from GCE, + you can use a standard service account from a JSON file rather + than a GCE service account. + + If you have a blob that you want to allow access to for a set + amount of time, you can use this method to generate a URL that + is only valid within a certain time period. + + See a [code sample](https://cloud.google.com/storage/docs/samples/storage-generate-signed-url-v4#storage_generate_signed_url_v4-python). + + This is particularly useful if you don't want publicly + accessible blobs, but don't want to require users to explicitly + log in. + + If ``bucket_bound_hostname`` is set as an argument of :attr:`api_access_endpoint`, + ``https`` works only if using a ``CDN``. + + :type expiration: Union[Integer, datetime.datetime, datetime.timedelta] + :param expiration: + Point in time when the signed URL should expire. If a ``datetime`` + instance is passed without an explicit ``tzinfo`` set, it will be + assumed to be ``UTC``. + + :type api_access_endpoint: str + :param api_access_endpoint: (Optional) URI base. + + :type method: str + :param method: The HTTP verb that will be used when requesting the URL. + + :type content_md5: str + :param content_md5: + (Optional) The MD5 hash of the object referenced by ``resource``. + + :type content_type: str + :param content_type: + (Optional) The content type of the object referenced by + ``resource``. + + :type response_disposition: str + :param response_disposition: + (Optional) Content disposition of responses to requests for the + signed URL. For example, to enable the signed URL to initiate a + file of ``blog.png``, use the value ``'attachment; + filename=blob.png'``. + + :type response_type: str + :param response_type: + (Optional) Content type of responses to requests for the signed + URL. Ignored if content_type is set on object/blob metadata. + + :type generation: str + :param generation: + (Optional) A value that indicates which generation of the resource + to fetch. + + :type headers: dict + :param headers: + (Optional) Additional HTTP headers to be included as part of the + signed URLs. See: + https://cloud.google.com/storage/docs/xml-api/reference-headers + Requests using the signed URL *must* pass the specified header + (name and value) with each request for the URL. + + :type query_parameters: dict + :param query_parameters: + (Optional) Additional query parameters to be included as part of the + signed URLs. See: + https://cloud.google.com/storage/docs/xml-api/reference-headers#query + + :type client: :class:`~google.cloud.storage.client.Client` + :param client: + (Optional) The client to use. If not passed, falls back to the + ``client`` stored on the blob's bucket. + + :type credentials: :class:`google.auth.credentials.Credentials` + :param credentials: + (Optional) The authorization credentials to attach to requests. + These credentials identify this application to the service. If + none are specified, the client will attempt to ascertain the + credentials from the environment. + + :type version: str + :param version: + (Optional) The version of signed credential to create. Must be one + of 'v2' | 'v4'. + + :type service_account_email: str + :param service_account_email: + (Optional) E-mail address of the service account. + + :type access_token: str + :param access_token: (Optional) Access token for a service account. + + :type virtual_hosted_style: bool + :param virtual_hosted_style: + (Optional) If true, then construct the URL relative the bucket's + virtual hostname, e.g., '.storage.googleapis.com'. + + :type bucket_bound_hostname: str + :param bucket_bound_hostname: + (Optional) If passed, then construct the URL relative to the + bucket-bound hostname. Value can be a bare or with scheme, e.g., + 'example.com' or 'http://example.com'. See: + https://cloud.google.com/storage/docs/request-endpoints#cname + + :type scheme: str + :param scheme: + (Optional) If ``bucket_bound_hostname`` is passed as a bare + hostname, use this value as the scheme. ``https`` will work only + when using a CDN. Defaults to ``"http"``. + + :raises: :exc:`ValueError` when version is invalid. + :raises: :exc:`TypeError` when expiration is not a valid type. + :raises: :exc:`AttributeError` if credentials is not an instance + of :class:`google.auth.credentials.Signing`. + + :rtype: str + :returns: A signed URL you can use to access the resource + until expiration. + """ + if version is None: + version = "v2" + elif version not in ("v2", "v4"): + raise ValueError("'version' must be either 'v2' or 'v4'") + + quoted_name = _quote(self.name, safe=b"/~") + + # If you are on Google Compute Engine, you can't generate a signed URL + # using GCE service account. + # See https://github.com/googleapis/google-auth-library-python/issues/50 + if virtual_hosted_style: + api_access_endpoint = f"https://{self.bucket.name}.storage.googleapis.com" + elif bucket_bound_hostname: + api_access_endpoint = _bucket_bound_hostname_url( + bucket_bound_hostname, scheme + ) + else: + resource = f"/{self.bucket.name}/{quoted_name}" + + if virtual_hosted_style or bucket_bound_hostname: + resource = f"/{quoted_name}" + + if credentials is None: + client = self._require_client(client) + credentials = client._credentials + + if version == "v2": + helper = generate_signed_url_v2 + else: + helper = generate_signed_url_v4 + + if self._encryption_key is not None: + encryption_headers = _get_encryption_headers(self._encryption_key) + if headers is None: + headers = {} + if version == "v2": + # See: https://cloud.google.com/storage/docs/access-control/signed-urls-v2#about-canonical-extension-headers + v2_copy_only = "X-Goog-Encryption-Algorithm" + headers[v2_copy_only] = encryption_headers[v2_copy_only] + else: + headers.update(encryption_headers) + + return helper( + credentials, + resource=resource, + expiration=expiration, + api_access_endpoint=api_access_endpoint, + method=method.upper(), + content_md5=content_md5, + content_type=content_type, + response_type=response_type, + response_disposition=response_disposition, + generation=generation, + headers=headers, + query_parameters=query_parameters, + service_account_email=service_account_email, + access_token=access_token, + ) + + def exists( + self, + client=None, + if_etag_match=None, + if_etag_not_match=None, + if_generation_match=None, + if_generation_not_match=None, + if_metageneration_match=None, + if_metageneration_not_match=None, + timeout=_DEFAULT_TIMEOUT, + retry=DEFAULT_RETRY, + ): + """Determines whether or not this blob exists. + + If :attr:`user_project` is set on the bucket, bills the API request + to that project. + + :type client: :class:`~google.cloud.storage.client.Client` + :param client: + (Optional) The client to use. If not passed, falls back to the + ``client`` stored on the blob's bucket. + + :type if_etag_match: Union[str, Set[str]] + :param if_etag_match: + (Optional) See :ref:`using-if-etag-match` + + :type if_etag_not_match: Union[str, Set[str]] + :param if_etag_not_match: + (Optional) See :ref:`using-if-etag-not-match` + + :type if_generation_match: long + :param if_generation_match: + (Optional) See :ref:`using-if-generation-match` + + :type if_generation_not_match: long + :param if_generation_not_match: + (Optional) See :ref:`using-if-generation-not-match` + + :type if_metageneration_match: long + :param if_metageneration_match: + (Optional) See :ref:`using-if-metageneration-match` + + :type if_metageneration_not_match: long + :param if_metageneration_not_match: + (Optional) See :ref:`using-if-metageneration-not-match` + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + + :rtype: bool + :returns: True if the blob exists in Cloud Storage. + """ + client = self._require_client(client) + # We only need the status code (200 or not) so we seek to + # minimize the returned payload. + query_params = self._query_params + query_params["fields"] = "name" + + _add_generation_match_parameters( + query_params, + if_generation_match=if_generation_match, + if_generation_not_match=if_generation_not_match, + if_metageneration_match=if_metageneration_match, + if_metageneration_not_match=if_metageneration_not_match, + ) + + headers = {} + _add_etag_match_headers( + headers, if_etag_match=if_etag_match, if_etag_not_match=if_etag_not_match + ) + + try: + # We intentionally pass `_target_object=None` since fields=name + # would limit the local properties. + client._get_resource( + self.path, + query_params=query_params, + headers=headers, + timeout=timeout, + retry=retry, + _target_object=None, + ) + except NotFound: + # NOTE: This will not fail immediately in a batch. However, when + # Batch.finish() is called, the resulting `NotFound` will be + # raised. + return False + return True + + def delete( + self, + client=None, + if_generation_match=None, + if_generation_not_match=None, + if_metageneration_match=None, + if_metageneration_not_match=None, + timeout=_DEFAULT_TIMEOUT, + retry=DEFAULT_RETRY_IF_GENERATION_SPECIFIED, + ): + """Deletes a blob from Cloud Storage. + + If :attr:`user_project` is set on the bucket, bills the API request + to that project. + + :type client: :class:`~google.cloud.storage.client.Client` + :param client: + (Optional) The client to use. If not passed, falls back to the + ``client`` stored on the blob's bucket. + + :type if_generation_match: long + :param if_generation_match: + (Optional) See :ref:`using-if-generation-match` + + :type if_generation_not_match: long + :param if_generation_not_match: + (Optional) See :ref:`using-if-generation-not-match` + + :type if_metageneration_match: long + :param if_metageneration_match: + (Optional) See :ref:`using-if-metageneration-match` + + :type if_metageneration_not_match: long + :param if_metageneration_not_match: + (Optional) See :ref:`using-if-metageneration-not-match` + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + + :raises: :class:`google.cloud.exceptions.NotFound` + (propagated from + :meth:`google.cloud.storage.bucket.Bucket.delete_blob`). + """ + self.bucket.delete_blob( + self.name, + client=client, + generation=self.generation, + timeout=timeout, + if_generation_match=if_generation_match, + if_generation_not_match=if_generation_not_match, + if_metageneration_match=if_metageneration_match, + if_metageneration_not_match=if_metageneration_not_match, + retry=retry, + ) + + def _get_transport(self, client): + """Return the client's transport. + + :type client: :class:`~google.cloud.storage.client.Client` + :param client: + (Optional) The client to use. If not passed, falls back to the + ``client`` stored on the blob's bucket. + + :rtype transport: + :class:`~google.auth.transport.requests.AuthorizedSession` + :returns: The transport (with credentials) that will + make authenticated requests. + """ + client = self._require_client(client) + return client._http + + def _get_download_url( + self, + client, + if_generation_match=None, + if_generation_not_match=None, + if_metageneration_match=None, + if_metageneration_not_match=None, + ): + """Get the download URL for the current blob. + + If the ``media_link`` has been loaded, it will be used, otherwise + the URL will be constructed from the current blob's path (and possibly + generation) to avoid a round trip. + + :type client: :class:`~google.cloud.storage.client.Client` + :param client: The client to use. + + :type if_generation_match: long + :param if_generation_match: + (Optional) See :ref:`using-if-generation-match` + + :type if_generation_not_match: long + :param if_generation_not_match: + (Optional) See :ref:`using-if-generation-not-match` + + :type if_metageneration_match: long + :param if_metageneration_match: + (Optional) See :ref:`using-if-metageneration-match` + + :type if_metageneration_not_match: long + :param if_metageneration_not_match: + (Optional) See :ref:`using-if-metageneration-not-match` + + :rtype: str + :returns: The download URL for the current blob. + """ + name_value_pairs = [] + if self.media_link is None: + hostname = _get_host_name(client._connection) + base_url = _DOWNLOAD_URL_TEMPLATE.format( + hostname=hostname, path=self.path, api_version=_API_VERSION + ) + if self.generation is not None: + name_value_pairs.append(("generation", f"{self.generation:d}")) + else: + base_url = self.media_link + + if self.user_project is not None: + name_value_pairs.append(("userProject", self.user_project)) + + _add_generation_match_parameters( + name_value_pairs, + if_generation_match=if_generation_match, + if_generation_not_match=if_generation_not_match, + if_metageneration_match=if_metageneration_match, + if_metageneration_not_match=if_metageneration_not_match, + ) + return _add_query_parameters(base_url, name_value_pairs) + + def _extract_headers_from_download(self, response): + """Extract headers from a non-chunked request's http object. + + This avoids the need to make a second request for commonly used + headers. + + :type response: + :class requests.models.Response + :param response: The server response from downloading a non-chunked file + """ + self._properties["contentEncoding"] = response.headers.get( + "Content-Encoding", None + ) + self._properties[_CONTENT_TYPE_FIELD] = response.headers.get( + "Content-Type", None + ) + self._properties["cacheControl"] = response.headers.get("Cache-Control", None) + self._properties["storageClass"] = response.headers.get( + "X-Goog-Storage-Class", None + ) + self._properties["contentLanguage"] = response.headers.get( + "Content-Language", None + ) + self._properties["etag"] = response.headers.get("ETag", None) + self._properties["generation"] = response.headers.get("X-goog-generation", None) + self._properties["metageneration"] = response.headers.get( + "X-goog-metageneration", None + ) + # 'X-Goog-Hash': 'crc32c=4gcgLQ==,md5=CS9tHYTtyFntzj7B9nkkJQ==', + x_goog_hash = response.headers.get("X-Goog-Hash", "") + + if x_goog_hash: + digests = {} + for encoded_digest in x_goog_hash.split(","): + match = re.match(r"(crc32c|md5)=([\w\d/\+/]+={0,3})", encoded_digest) + if match: + method, digest = match.groups() + digests[method] = digest + + self._properties["crc32c"] = digests.get("crc32c", None) + self._properties["md5Hash"] = digests.get("md5", None) + + def _do_download( + self, + transport, + file_obj, + download_url, + headers, + start=None, + end=None, + raw_download=False, + timeout=_DEFAULT_TIMEOUT, + checksum="md5", + retry=None, + ): + """Perform a download without any error handling. + + This is intended to be called by :meth:`download_to_file` so it can + be wrapped with error handling / remapping. + + :type transport: + :class:`~google.auth.transport.requests.AuthorizedSession` + :param transport: + The transport (with credentials) that will make authenticated + requests. + + :type file_obj: file + :param file_obj: A file handle to which to write the blob's data. + + :type download_url: str + :param download_url: The URL where the media can be accessed. + + :type headers: dict + :param headers: Headers to be sent with the request(s). + + :type start: int + :param start: (Optional) The first byte in a range to be downloaded. + + :type end: int + :param end: (Optional) The last byte in a range to be downloaded. + + :type raw_download: bool + :param raw_download: + (Optional) If true, download the object without any expansion. + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type checksum: str + :param checksum: + (Optional) The type of checksum to compute to verify the integrity + of the object. The response headers must contain a checksum of the + requested type. If the headers lack an appropriate checksum (for + instance in the case of transcoded or ranged downloads where the + remote service does not know the correct checksum, including + downloads where chunk_size is set) an INFO-level log will be + emitted. Supported values are "md5", "crc32c" and None. The default + is "md5". + + :type retry: google.api_core.retry.Retry + :param retry: (Optional) How to retry the RPC. A None value will disable + retries. A google.api_core.retry.Retry value will enable retries, + and the object will configure backoff and timeout options. Custom + predicates (customizable error codes) are not supported for media + operations such as this one. + + This private method does not accept ConditionalRetryPolicy values + because the information necessary to evaluate the policy is instead + evaluated in client.download_blob_to_file(). + + See the retry.py source code and docstrings in this package + (google.cloud.storage.retry) for information on retry types and how + to configure them. + """ + + retry_strategy = _api_core_retry_to_resumable_media_retry(retry) + + if self.chunk_size is None: + if raw_download: + klass = RawDownload + else: + klass = Download + + download = klass( + download_url, + stream=file_obj, + headers=headers, + start=start, + end=end, + checksum=checksum, + ) + download._retry_strategy = retry_strategy + response = download.consume(transport, timeout=timeout) + self._extract_headers_from_download(response) + else: + + if checksum: + msg = _CHUNKED_DOWNLOAD_CHECKSUM_MESSAGE.format(checksum) + _logger.info(msg) + + if raw_download: + klass = RawChunkedDownload + else: + klass = ChunkedDownload + + download = klass( + download_url, + self.chunk_size, + file_obj, + headers=headers, + start=start if start else 0, + end=end, + ) + + download._retry_strategy = retry_strategy + while not download.finished: + download.consume_next_chunk(transport, timeout=timeout) + + def download_to_file( + self, + file_obj, + client=None, + start=None, + end=None, + raw_download=False, + if_etag_match=None, + if_etag_not_match=None, + if_generation_match=None, + if_generation_not_match=None, + if_metageneration_match=None, + if_metageneration_not_match=None, + timeout=_DEFAULT_TIMEOUT, + checksum="md5", + retry=DEFAULT_RETRY, + ): + """DEPRECATED. Download the contents of this blob into a file-like object. + + .. note:: + + If the server-set property, :attr:`media_link`, is not yet + initialized, makes an additional API request to load it. + + If the :attr:`chunk_size` of a current blob is `None`, will download data + in single download request otherwise it will download the :attr:`chunk_size` + of data in each request. + + For more fine-grained control over the download process, check out + [`google-resumable-media`](https://googleapis.dev/python/google-resumable-media/latest/index.html). + For example, this library allows downloading **parts** of a blob rather than the whole thing. + + If :attr:`user_project` is set on the bucket, bills the API request + to that project. + + :type file_obj: file + :param file_obj: A file handle to which to write the blob's data. + + :type client: :class:`~google.cloud.storage.client.Client` + :param client: + (Optional) The client to use. If not passed, falls back to the + ``client`` stored on the blob's bucket. + + :type start: int + :param start: (Optional) The first byte in a range to be downloaded. + + :type end: int + :param end: (Optional) The last byte in a range to be downloaded. + + :type raw_download: bool + :param raw_download: + (Optional) If true, download the object without any expansion. + + :type if_etag_match: Union[str, Set[str]] + :param if_etag_match: + (Optional) See :ref:`using-if-etag-match` + + :type if_etag_not_match: Union[str, Set[str]] + :param if_etag_not_match: + (Optional) See :ref:`using-if-etag-not-match` + + :type if_generation_match: long + :param if_generation_match: + (Optional) See :ref:`using-if-generation-match` + + :type if_generation_not_match: long + :param if_generation_not_match: + (Optional) See :ref:`using-if-generation-not-match` + + :type if_metageneration_match: long + :param if_metageneration_match: + (Optional) See :ref:`using-if-metageneration-match` + + :type if_metageneration_not_match: long + :param if_metageneration_not_match: + (Optional) See :ref:`using-if-metageneration-not-match` + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type checksum: str + :param checksum: + (Optional) The type of checksum to compute to verify the integrity + of the object. The response headers must contain a checksum of the + requested type. If the headers lack an appropriate checksum (for + instance in the case of transcoded or ranged downloads where the + remote service does not know the correct checksum, including + downloads where chunk_size is set) an INFO-level log will be + emitted. Supported values are "md5", "crc32c" and None. The default + is "md5". + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: (Optional) How to retry the RPC. A None value will disable + retries. A google.api_core.retry.Retry value will enable retries, + and the object will define retriable response codes and errors and + configure backoff and timeout options. + + A google.cloud.storage.retry.ConditionalRetryPolicy value wraps a + Retry object and activates it only if certain conditions are met. + This class exists to provide safe defaults for RPC calls that are + not technically safe to retry normally (due to potential data + duplication or other side-effects) but become safe to retry if a + condition such as if_metageneration_match is set. + + See the retry.py source code and docstrings in this package + (google.cloud.storage.retry) for information on retry types and how + to configure them. + + Media operations (downloads and uploads) do not support non-default + predicates in a Retry object. The default will always be used. Other + configuration changes for Retry objects such as delays and deadlines + are respected. + + :raises: :class:`google.cloud.exceptions.NotFound` + """ + client = self._require_client(client) + + client.download_blob_to_file( + self, + file_obj=file_obj, + start=start, + end=end, + raw_download=raw_download, + if_etag_match=if_etag_match, + if_etag_not_match=if_etag_not_match, + if_generation_match=if_generation_match, + if_generation_not_match=if_generation_not_match, + if_metageneration_match=if_metageneration_match, + if_metageneration_not_match=if_metageneration_not_match, + timeout=timeout, + checksum=checksum, + retry=retry, + ) + + def download_to_filename( + self, + filename, + client=None, + start=None, + end=None, + raw_download=False, + if_etag_match=None, + if_etag_not_match=None, + if_generation_match=None, + if_generation_not_match=None, + if_metageneration_match=None, + if_metageneration_not_match=None, + timeout=_DEFAULT_TIMEOUT, + checksum="md5", + retry=DEFAULT_RETRY, + ): + """Download the contents of this blob into a named file. + + If :attr:`user_project` is set on the bucket, bills the API request + to that project. + + See a [code sample](https://cloud.google.com/storage/docs/samples/storage-download-encrypted-file#storage_download_encrypted_file-python) + to download a file with a [`customer-supplied encryption key`](https://cloud.google.com/storage/docs/encryption#customer-supplied). + + :type filename: str + :param filename: A filename to be passed to ``open``. + + :type client: :class:`~google.cloud.storage.client.Client` + :param client: + (Optional) The client to use. If not passed, falls back to the + ``client`` stored on the blob's bucket. + + :type start: int + :param start: (Optional) The first byte in a range to be downloaded. + + :type end: int + :param end: (Optional) The last byte in a range to be downloaded. + + :type raw_download: bool + :param raw_download: + (Optional) If true, download the object without any expansion. + + :type if_etag_match: Union[str, Set[str]] + :param if_etag_match: + (Optional) See :ref:`using-if-etag-match` + + :type if_etag_not_match: Union[str, Set[str]] + :param if_etag_not_match: + (Optional) See :ref:`using-if-etag-not-match` + + :type if_generation_match: long + :param if_generation_match: + (Optional) See :ref:`using-if-generation-match` + + :type if_generation_not_match: long + :param if_generation_not_match: + (Optional) See :ref:`using-if-generation-not-match` + + :type if_metageneration_match: long + :param if_metageneration_match: + (Optional) See :ref:`using-if-metageneration-match` + + :type if_metageneration_not_match: long + :param if_metageneration_not_match: + (Optional) See :ref:`using-if-metageneration-not-match` + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type checksum: str + :param checksum: + (Optional) The type of checksum to compute to verify the integrity + of the object. The response headers must contain a checksum of the + requested type. If the headers lack an appropriate checksum (for + instance in the case of transcoded or ranged downloads where the + remote service does not know the correct checksum, including + downloads where chunk_size is set) an INFO-level log will be + emitted. Supported values are "md5", "crc32c" and None. The default + is "md5". + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: (Optional) How to retry the RPC. A None value will disable + retries. A google.api_core.retry.Retry value will enable retries, + and the object will define retriable response codes and errors and + configure backoff and timeout options. + + A google.cloud.storage.retry.ConditionalRetryPolicy value wraps a + Retry object and activates it only if certain conditions are met. + This class exists to provide safe defaults for RPC calls that are + not technically safe to retry normally (due to potential data + duplication or other side-effects) but become safe to retry if a + condition such as if_metageneration_match is set. + + See the retry.py source code and docstrings in this package + (google.cloud.storage.retry) for information on retry types and how + to configure them. + + Media operations (downloads and uploads) do not support non-default + predicates in a Retry object. The default will always be used. Other + configuration changes for Retry objects such as delays and deadlines + are respected. + + :raises: :class:`google.cloud.exceptions.NotFound` + """ + client = self._require_client(client) + try: + with open(filename, "wb") as file_obj: + client.download_blob_to_file( + self, + file_obj, + start=start, + end=end, + raw_download=raw_download, + if_etag_match=if_etag_match, + if_etag_not_match=if_etag_not_match, + if_generation_match=if_generation_match, + if_generation_not_match=if_generation_not_match, + if_metageneration_match=if_metageneration_match, + if_metageneration_not_match=if_metageneration_not_match, + timeout=timeout, + checksum=checksum, + retry=retry, + ) + except resumable_media.DataCorruption: + # Delete the corrupt downloaded file. + os.remove(filename) + raise + + updated = self.updated + if updated is not None: + mtime = updated.timestamp() + os.utime(file_obj.name, (mtime, mtime)) + + def download_as_bytes( + self, + client=None, + start=None, + end=None, + raw_download=False, + if_etag_match=None, + if_etag_not_match=None, + if_generation_match=None, + if_generation_not_match=None, + if_metageneration_match=None, + if_metageneration_not_match=None, + timeout=_DEFAULT_TIMEOUT, + checksum="md5", + retry=DEFAULT_RETRY, + ): + """Download the contents of this blob as a bytes object. + + If :attr:`user_project` is set on the bucket, bills the API request + to that project. + + :type client: :class:`~google.cloud.storage.client.Client` + :param client: + (Optional) The client to use. If not passed, falls back to the + ``client`` stored on the blob's bucket. + + :type start: int + :param start: (Optional) The first byte in a range to be downloaded. + + :type end: int + :param end: (Optional) The last byte in a range to be downloaded. + + :type raw_download: bool + :param raw_download: + (Optional) If true, download the object without any expansion. + + :type if_etag_match: Union[str, Set[str]] + :param if_etag_match: + (Optional) See :ref:`using-if-etag-match` + + :type if_etag_not_match: Union[str, Set[str]] + :param if_etag_not_match: + (Optional) See :ref:`using-if-etag-not-match` + + :type if_generation_match: long + :param if_generation_match: + (Optional) See :ref:`using-if-generation-match` + + :type if_generation_not_match: long + :param if_generation_not_match: + (Optional) See :ref:`using-if-generation-not-match` + + :type if_metageneration_match: long + :param if_metageneration_match: + (Optional) See :ref:`using-if-metageneration-match` + + :type if_metageneration_not_match: long + :param if_metageneration_not_match: + (Optional) See :ref:`using-if-metageneration-not-match` + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type checksum: str + :param checksum: + (Optional) The type of checksum to compute to verify the integrity + of the object. The response headers must contain a checksum of the + requested type. If the headers lack an appropriate checksum (for + instance in the case of transcoded or ranged downloads where the + remote service does not know the correct checksum, including + downloads where chunk_size is set) an INFO-level log will be + emitted. Supported values are "md5", "crc32c" and None. The default + is "md5". + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: (Optional) How to retry the RPC. A None value will disable + retries. A google.api_core.retry.Retry value will enable retries, + and the object will define retriable response codes and errors and + configure backoff and timeout options. + + A google.cloud.storage.retry.ConditionalRetryPolicy value wraps a + Retry object and activates it only if certain conditions are met. + This class exists to provide safe defaults for RPC calls that are + not technically safe to retry normally (due to potential data + duplication or other side-effects) but become safe to retry if a + condition such as if_metageneration_match is set. + + See the retry.py source code and docstrings in this package + (google.cloud.storage.retry) for information on retry types and how + to configure them. + + Media operations (downloads and uploads) do not support non-default + predicates in a Retry object. The default will always be used. Other + configuration changes for Retry objects such as delays and deadlines + are respected. + + :rtype: bytes + :returns: The data stored in this blob. + + :raises: :class:`google.cloud.exceptions.NotFound` + """ + client = self._require_client(client) + string_buffer = BytesIO() + client.download_blob_to_file( + self, + string_buffer, + start=start, + end=end, + raw_download=raw_download, + if_etag_match=if_etag_match, + if_etag_not_match=if_etag_not_match, + if_generation_match=if_generation_match, + if_generation_not_match=if_generation_not_match, + if_metageneration_match=if_metageneration_match, + if_metageneration_not_match=if_metageneration_not_match, + timeout=timeout, + checksum=checksum, + retry=retry, + ) + return string_buffer.getvalue() + + def download_as_string( + self, + client=None, + start=None, + end=None, + raw_download=False, + if_etag_match=None, + if_etag_not_match=None, + if_generation_match=None, + if_generation_not_match=None, + if_metageneration_match=None, + if_metageneration_not_match=None, + timeout=_DEFAULT_TIMEOUT, + retry=DEFAULT_RETRY, + ): + """(Deprecated) Download the contents of this blob as a bytes object. + + If :attr:`user_project` is set on the bucket, bills the API request + to that project. + + .. note:: + Deprecated alias for :meth:`download_as_bytes`. + + :type client: :class:`~google.cloud.storage.client.Client` + :param client: + (Optional) The client to use. If not passed, falls back to the + ``client`` stored on the blob's bucket. + + :type start: int + :param start: (Optional) The first byte in a range to be downloaded. + + :type end: int + :param end: (Optional) The last byte in a range to be downloaded. + + :type raw_download: bool + :param raw_download: + (Optional) If true, download the object without any expansion. + + :type if_etag_match: Union[str, Set[str]] + :param if_etag_match: + (Optional) See :ref:`using-if-etag-match` + + :type if_etag_not_match: Union[str, Set[str]] + :param if_etag_not_match: + (Optional) See :ref:`using-if-etag-not-match` + + :type if_generation_match: long + :param if_generation_match: + (Optional) See :ref:`using-if-generation-match` + + :type if_generation_not_match: long + :param if_generation_not_match: + (Optional) See :ref:`using-if-generation-not-match` + + :type if_metageneration_match: long + :param if_metageneration_match: + (Optional) See :ref:`using-if-metageneration-match` + + :type if_metageneration_not_match: long + :param if_metageneration_not_match: + (Optional) See :ref:`using-if-metageneration-not-match` + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: (Optional) How to retry the RPC. A None value will disable + retries. A google.api_core.retry.Retry value will enable retries, + and the object will define retriable response codes and errors and + configure backoff and timeout options. + + A google.cloud.storage.retry.ConditionalRetryPolicy value wraps a + Retry object and activates it only if certain conditions are met. + This class exists to provide safe defaults for RPC calls that are + not technically safe to retry normally (due to potential data + duplication or other side-effects) but become safe to retry if a + condition such as if_metageneration_match is set. + + See the retry.py source code and docstrings in this package + (google.cloud.storage.retry) for information on retry types and how + to configure them. + + Media operations (downloads and uploads) do not support non-default + predicates in a Retry object. The default will always be used. Other + configuration changes for Retry objects such as delays and deadlines + are respected. + + :rtype: bytes + :returns: The data stored in this blob. + + :raises: :class:`google.cloud.exceptions.NotFound` + """ + warnings.warn( + _DOWNLOAD_AS_STRING_DEPRECATED, PendingDeprecationWarning, stacklevel=2 + ) + return self.download_as_bytes( + client=client, + start=start, + end=end, + raw_download=raw_download, + if_etag_match=if_etag_match, + if_etag_not_match=if_etag_not_match, + if_generation_match=if_generation_match, + if_generation_not_match=if_generation_not_match, + if_metageneration_match=if_metageneration_match, + if_metageneration_not_match=if_metageneration_not_match, + timeout=timeout, + retry=retry, + ) + + def download_as_text( + self, + client=None, + start=None, + end=None, + raw_download=False, + encoding=None, + if_etag_match=None, + if_etag_not_match=None, + if_generation_match=None, + if_generation_not_match=None, + if_metageneration_match=None, + if_metageneration_not_match=None, + timeout=_DEFAULT_TIMEOUT, + retry=DEFAULT_RETRY, + ): + """Download the contents of this blob as text (*not* bytes). + + If :attr:`user_project` is set on the bucket, bills the API request + to that project. + + :type client: :class:`~google.cloud.storage.client.Client` + :param client: + (Optional) The client to use. If not passed, falls back to the + ``client`` stored on the blob's bucket. + + :type start: int + :param start: (Optional) The first byte in a range to be downloaded. + + :type end: int + :param end: (Optional) The last byte in a range to be downloaded. + + :type raw_download: bool + :param raw_download: + (Optional) If true, download the object without any expansion. + + :type encoding: str + :param encoding: (Optional) encoding to be used to decode the + downloaded bytes. Defaults to the ``charset`` param of + attr:`content_type`, or else to "utf-8". + + :type if_etag_match: Union[str, Set[str]] + :param if_etag_match: + (Optional) See :ref:`using-if-etag-match` + + :type if_etag_not_match: Union[str, Set[str]] + :param if_etag_not_match: + (Optional) See :ref:`using-if-etag-not-match` + + :type if_generation_match: long + :param if_generation_match: + (Optional) See :ref:`using-if-generation-match` + + :type if_generation_not_match: long + :param if_generation_not_match: + (Optional) See :ref:`using-if-generation-not-match` + + :type if_metageneration_match: long + :param if_metageneration_match: + (Optional) See :ref:`using-if-metageneration-match` + + :type if_metageneration_not_match: long + :param if_metageneration_not_match: + (Optional) See :ref:`using-if-metageneration-not-match` + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: (Optional) How to retry the RPC. A None value will disable + retries. A google.api_core.retry.Retry value will enable retries, + and the object will define retriable response codes and errors and + configure backoff and timeout options. + + A google.cloud.storage.retry.ConditionalRetryPolicy value wraps a + Retry object and activates it only if certain conditions are met. + This class exists to provide safe defaults for RPC calls that are + not technically safe to retry normally (due to potential data + duplication or other side-effects) but become safe to retry if a + condition such as if_metageneration_match is set. + + See the retry.py source code and docstrings in this package + (google.cloud.storage.retry) for information on retry types and how + to configure them. + + Media operations (downloads and uploads) do not support non-default + predicates in a Retry object. The default will always be used. Other + configuration changes for Retry objects such as delays and deadlines + are respected. + + :rtype: text + :returns: The data stored in this blob, decoded to text. + """ + data = self.download_as_bytes( + client=client, + start=start, + end=end, + raw_download=raw_download, + if_etag_match=if_etag_match, + if_etag_not_match=if_etag_not_match, + if_generation_match=if_generation_match, + if_generation_not_match=if_generation_not_match, + if_metageneration_match=if_metageneration_match, + if_metageneration_not_match=if_metageneration_not_match, + timeout=timeout, + retry=retry, + ) + + if encoding is not None: + return data.decode(encoding) + + if self.content_type is not None: + _, params = cgi.parse_header(self.content_type) + if "charset" in params: + return data.decode(params["charset"]) + + return data.decode("utf-8") + + def _get_content_type(self, content_type, filename=None): + """Determine the content type from the current object. + + The return value will be determined in order of precedence: + + - The value passed in to this method (if not :data:`None`) + - The value stored on the current blob + - The default value ('application/octet-stream') + + :type content_type: str + :param content_type: (Optional) Type of content. + + :type filename: str + :param filename: + (Optional) The name of the file where the content is stored. + + :rtype: str + :returns: Type of content gathered from the object. + """ + if content_type is None: + content_type = self.content_type + + if content_type is None and filename is not None: + content_type, _ = mimetypes.guess_type(filename) + + if content_type is None: + content_type = _DEFAULT_CONTENT_TYPE + + return content_type + + def _get_writable_metadata(self): + """Get the object / blob metadata which is writable. + + This is intended to be used when creating a new object / blob. + + See the [`API reference docs`](https://cloud.google.com/storage/docs/json_api/v1/objects) + for more information, the fields marked as writable are: + + * ``acl`` + * ``cacheControl`` + * ``contentDisposition`` + * ``contentEncoding`` + * ``contentLanguage`` + * ``contentType`` + * ``crc32c`` + * ``customTime`` + * ``md5Hash`` + * ``metadata`` + * ``name`` + * ``storageClass`` + + For now, we don't support ``acl``, access control lists should be + managed directly through :class:`ObjectACL` methods. + """ + # NOTE: This assumes `self.name` is unicode. + object_metadata = {"name": self.name} + for key in self._changes: + if key in _WRITABLE_FIELDS: + object_metadata[key] = self._properties[key] + + return object_metadata + + def _get_upload_arguments(self, client, content_type): + """Get required arguments for performing an upload. + + The content type returned will be determined in order of precedence: + + - The value passed in to this method (if not :data:`None`) + - The value stored on the current blob + - The default value ('application/octet-stream') + + :type content_type: str + :param content_type: Type of content being uploaded (or :data:`None`). + + :rtype: tuple + :returns: A triple of + + * A header dictionary + * An object metadata dictionary + * The ``content_type`` as a string (according to precedence) + """ + content_type = self._get_content_type(content_type) + headers = { + **_get_default_headers(client._connection.user_agent, content_type), + **_get_encryption_headers(self._encryption_key), + } + object_metadata = self._get_writable_metadata() + return headers, object_metadata, content_type + + def _do_multipart_upload( + self, + client, + stream, + content_type, + size, + num_retries, + predefined_acl, + if_generation_match, + if_generation_not_match, + if_metageneration_match, + if_metageneration_not_match, + timeout=_DEFAULT_TIMEOUT, + checksum=None, + retry=None, + ): + """Perform a multipart upload. + + The content type of the upload will be determined in order + of precedence: + + - The value passed in to this method (if not :data:`None`) + - The value stored on the current blob + - The default value ('application/octet-stream') + + :type client: :class:`~google.cloud.storage.client.Client` + :param client: + (Optional) The client to use. If not passed, falls back to the + ``client`` stored on the blob's bucket. + + :type stream: IO[bytes] + :param stream: A bytes IO object open for reading. + + :type content_type: str + :param content_type: Type of content being uploaded (or :data:`None`). + + :type size: int + :param size: + The number of bytes to be uploaded (which will be read from + ``stream``). If not provided, the upload will be concluded once + ``stream`` is exhausted (or :data:`None`). + + :type num_retries: int + :param num_retries: + Number of upload retries. By default, only uploads with + if_generation_match set will be retried, as uploads without the + argument are not guaranteed to be idempotent. Setting num_retries + will override this default behavior and guarantee retries even when + if_generation_match is not set. (Deprecated: This argument + will be removed in a future release.) + + :type predefined_acl: str + :param predefined_acl: (Optional) Predefined access control list + + :type if_generation_match: long + :param if_generation_match: + (Optional) See :ref:`using-if-generation-match` + + :type if_generation_not_match: long + :param if_generation_not_match: + (Optional) See :ref:`using-if-generation-not-match` + + :type if_metageneration_match: long + :param if_metageneration_match: + (Optional) See :ref:`using-if-metageneration-match` + + :type if_metageneration_not_match: long + :param if_metageneration_not_match: + (Optional) See :ref:`using-if-metageneration-not-match` + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type checksum: str + :param checksum: + (Optional) The type of checksum to compute to verify + the integrity of the object. The request metadata will be amended + to include the computed value. Using this option will override a + manually-set checksum value. Supported values are "md5", + "crc32c" and None. The default is None. + + :type retry: google.api_core.retry.Retry + :param retry: (Optional) How to retry the RPC. A None value will disable + retries. A google.api_core.retry.Retry value will enable retries, + and the object will configure backoff and timeout options. Custom + predicates (customizable error codes) are not supported for media + operations such as this one. + + This private method does not accept ConditionalRetryPolicy values + because the information necessary to evaluate the policy is instead + evaluated in blob._do_upload(). + + See the retry.py source code and docstrings in this package + (google.cloud.storage.retry) for information on retry types and how + to configure them. + + :rtype: :class:`~requests.Response` + :returns: The "200 OK" response object returned after the multipart + upload request. + :raises: :exc:`ValueError` if ``size`` is not :data:`None` but the + ``stream`` has fewer than ``size`` bytes remaining. + """ + if size is None: + data = stream.read() + else: + data = stream.read(size) + if len(data) < size: + msg = _READ_LESS_THAN_SIZE.format(size, len(data)) + raise ValueError(msg) + + client = self._require_client(client) + transport = self._get_transport(client) + if "metadata" in self._properties and "metadata" not in self._changes: + self._changes.add("metadata") + info = self._get_upload_arguments(client, content_type) + headers, object_metadata, content_type = info + + hostname = _get_host_name(client._connection) + base_url = _MULTIPART_URL_TEMPLATE.format( + hostname=hostname, bucket_path=self.bucket.path, api_version=_API_VERSION + ) + name_value_pairs = [] + + if self.user_project is not None: + name_value_pairs.append(("userProject", self.user_project)) + + # When a Customer Managed Encryption Key is used to encrypt Cloud Storage object + # at rest, object resource metadata will store the version of the Key Management + # Service cryptographic material. If a Blob instance with KMS Key metadata set is + # used to upload a new version of the object then the existing kmsKeyName version + # value can't be used in the upload request and the client instead ignores it. + if ( + self.kms_key_name is not None + and "cryptoKeyVersions" not in self.kms_key_name + ): + name_value_pairs.append(("kmsKeyName", self.kms_key_name)) + + if predefined_acl is not None: + name_value_pairs.append(("predefinedAcl", predefined_acl)) + + if if_generation_match is not None: + name_value_pairs.append(("ifGenerationMatch", if_generation_match)) + + if if_generation_not_match is not None: + name_value_pairs.append(("ifGenerationNotMatch", if_generation_not_match)) + + if if_metageneration_match is not None: + name_value_pairs.append(("ifMetagenerationMatch", if_metageneration_match)) + + if if_metageneration_not_match is not None: + name_value_pairs.append( + ("ifMetaGenerationNotMatch", if_metageneration_not_match) + ) + + upload_url = _add_query_parameters(base_url, name_value_pairs) + upload = MultipartUpload(upload_url, headers=headers, checksum=checksum) + + upload._retry_strategy = _api_core_retry_to_resumable_media_retry( + retry, num_retries + ) + + response = upload.transmit( + transport, data, object_metadata, content_type, timeout=timeout + ) + + return response + + def _initiate_resumable_upload( + self, + client, + stream, + content_type, + size, + num_retries, + predefined_acl=None, + extra_headers=None, + chunk_size=None, + if_generation_match=None, + if_generation_not_match=None, + if_metageneration_match=None, + if_metageneration_not_match=None, + timeout=_DEFAULT_TIMEOUT, + checksum=None, + retry=None, + ): + """Initiate a resumable upload. + + The content type of the upload will be determined in order + of precedence: + + - The value passed in to this method (if not :data:`None`) + - The value stored on the current blob + - The default value ('application/octet-stream') + + :type client: :class:`~google.cloud.storage.client.Client` + :param client: + (Optional) The client to use. If not passed, falls back to the + ``client`` stored on the blob's bucket. + + :type stream: IO[bytes] + :param stream: A bytes IO object open for reading. + + :type content_type: str + :param content_type: Type of content being uploaded (or :data:`None`). + + :type size: int + :param size: + The number of bytes to be uploaded (which will be read from + ``stream``). If not provided, the upload will be concluded once + ``stream`` is exhausted (or :data:`None`). + + :type predefined_acl: str + :param predefined_acl: (Optional) Predefined access control list + + :type num_retries: int + :param num_retries: + Number of upload retries. By default, only uploads with + if_generation_match set will be retried, as uploads without the + argument are not guaranteed to be idempotent. Setting num_retries + will override this default behavior and guarantee retries even when + if_generation_match is not set. (Deprecated: This argument + will be removed in a future release.) + + :type extra_headers: dict + :param extra_headers: + (Optional) Extra headers to add to standard headers. + + :type chunk_size: int + :param chunk_size: + (Optional) Chunk size to use when creating a + :class:`~google.resumable_media.requests.ResumableUpload`. + If not passed, will fall back to the chunk size on the + current blob, if the chunk size of a current blob is also + `None`, will set the default value. + The default value of ``chunk_size`` is 100 MB. + + :type if_generation_match: long + :param if_generation_match: + (Optional) See :ref:`using-if-generation-match` + + :type if_generation_not_match: long + :param if_generation_not_match: + (Optional) See :ref:`using-if-generation-not-match` + + :type if_metageneration_match: long + :param if_metageneration_match: + (Optional) See :ref:`using-if-metageneration-match` + + :type if_metageneration_not_match: long + :param if_metageneration_not_match: + (Optional) See :ref:`using-if-metageneration-not-match` + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type checksum: str + :param checksum: + (Optional) The type of checksum to compute to verify + the integrity of the object. After the upload is complete, the + server-computed checksum of the resulting object will be checked + and google.resumable_media.common.DataCorruption will be raised on + a mismatch. On a validation failure, the client will attempt to + delete the uploaded object automatically. Supported values + are "md5", "crc32c" and None. The default is None. + + :type retry: google.api_core.retry.Retry + :param retry: (Optional) How to retry the RPC. A None value will disable + retries. A google.api_core.retry.Retry value will enable retries, + and the object will configure backoff and timeout options. Custom + predicates (customizable error codes) are not supported for media + operations such as this one. + + This private method does not accept ConditionalRetryPolicy values + because the information necessary to evaluate the policy is instead + evaluated in blob._do_upload(). + + See the retry.py source code and docstrings in this package + (google.cloud.storage.retry) for information on retry types and how + to configure them. + + :rtype: tuple + :returns: + Pair of + + * The :class:`~google.resumable_media.requests.ResumableUpload` + that was created + * The ``transport`` used to initiate the upload. + """ + client = self._require_client(client) + if chunk_size is None: + chunk_size = self.chunk_size + if chunk_size is None: + chunk_size = _DEFAULT_CHUNKSIZE + + transport = self._get_transport(client) + if "metadata" in self._properties and "metadata" not in self._changes: + self._changes.add("metadata") + info = self._get_upload_arguments(client, content_type) + headers, object_metadata, content_type = info + if extra_headers is not None: + headers.update(extra_headers) + + hostname = _get_host_name(client._connection) + base_url = _RESUMABLE_URL_TEMPLATE.format( + hostname=hostname, bucket_path=self.bucket.path, api_version=_API_VERSION + ) + name_value_pairs = [] + + if self.user_project is not None: + name_value_pairs.append(("userProject", self.user_project)) + + # When a Customer Managed Encryption Key is used to encrypt Cloud Storage object + # at rest, object resource metadata will store the version of the Key Management + # Service cryptographic material. If a Blob instance with KMS Key metadata set is + # used to upload a new version of the object then the existing kmsKeyName version + # value can't be used in the upload request and the client instead ignores it. + if ( + self.kms_key_name is not None + and "cryptoKeyVersions" not in self.kms_key_name + ): + name_value_pairs.append(("kmsKeyName", self.kms_key_name)) + + if predefined_acl is not None: + name_value_pairs.append(("predefinedAcl", predefined_acl)) + + if if_generation_match is not None: + name_value_pairs.append(("ifGenerationMatch", if_generation_match)) + + if if_generation_not_match is not None: + name_value_pairs.append(("ifGenerationNotMatch", if_generation_not_match)) + + if if_metageneration_match is not None: + name_value_pairs.append(("ifMetagenerationMatch", if_metageneration_match)) + + if if_metageneration_not_match is not None: + name_value_pairs.append( + ("ifMetaGenerationNotMatch", if_metageneration_not_match) + ) + + upload_url = _add_query_parameters(base_url, name_value_pairs) + upload = ResumableUpload( + upload_url, chunk_size, headers=headers, checksum=checksum + ) + + upload._retry_strategy = _api_core_retry_to_resumable_media_retry( + retry, num_retries + ) + + upload.initiate( + transport, + stream, + object_metadata, + content_type, + total_bytes=size, + stream_final=False, + timeout=timeout, + ) + + return upload, transport + + def _do_resumable_upload( + self, + client, + stream, + content_type, + size, + num_retries, + predefined_acl, + if_generation_match, + if_generation_not_match, + if_metageneration_match, + if_metageneration_not_match, + timeout=_DEFAULT_TIMEOUT, + checksum=None, + retry=None, + ): + """Perform a resumable upload. + + Assumes ``chunk_size`` is not :data:`None` on the current blob. + The default value of ``chunk_size`` is 100 MB. + + The content type of the upload will be determined in order + of precedence: + + - The value passed in to this method (if not :data:`None`) + - The value stored on the current blob + - The default value ('application/octet-stream') + + :type client: :class:`~google.cloud.storage.client.Client` + :param client: + (Optional) The client to use. If not passed, falls back to the + ``client`` stored on the blob's bucket. + + :type stream: IO[bytes] + :param stream: A bytes IO object open for reading. + + :type content_type: str + :param content_type: Type of content being uploaded (or :data:`None`). + + :type size: int + :param size: + The number of bytes to be uploaded (which will be read from + ``stream``). If not provided, the upload will be concluded once + ``stream`` is exhausted (or :data:`None`). + + :type num_retries: int + :param num_retries: + Number of upload retries. By default, only uploads with + if_generation_match set will be retried, as uploads without the + argument are not guaranteed to be idempotent. Setting num_retries + will override this default behavior and guarantee retries even when + if_generation_match is not set. (Deprecated: This argument + will be removed in a future release.) + + :type predefined_acl: str + :param predefined_acl: (Optional) Predefined access control list + + :type if_generation_match: long + :param if_generation_match: + (Optional) See :ref:`using-if-generation-match` + + :type if_generation_not_match: long + :param if_generation_not_match: + (Optional) See :ref:`using-if-generation-not-match` + + :type if_metageneration_match: long + :param if_metageneration_match: + (Optional) See :ref:`using-if-metageneration-match` + + :type if_metageneration_not_match: long + :param if_metageneration_not_match: + (Optional) See :ref:`using-if-metageneration-not-match` + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type checksum: str + :param checksum: + (Optional) The type of checksum to compute to verify + the integrity of the object. After the upload is complete, the + server-computed checksum of the resulting object will be checked + and google.resumable_media.common.DataCorruption will be raised on + a mismatch. On a validation failure, the client will attempt to + delete the uploaded object automatically. Supported values + are "md5", "crc32c" and None. The default is None. + + :type retry: google.api_core.retry.Retry + :param retry: (Optional) How to retry the RPC. A None value will disable + retries. A google.api_core.retry.Retry value will enable retries, + and the object will configure backoff and timeout options. Custom + predicates (customizable error codes) are not supported for media + operations such as this one. + + This private method does not accept ConditionalRetryPolicy values + because the information necessary to evaluate the policy is instead + evaluated in blob._do_upload(). + + See the retry.py source code and docstrings in this package + (google.cloud.storage.retry) for information on retry types and how + to configure them. + + :rtype: :class:`~requests.Response` + :returns: The "200 OK" response object returned after the final chunk + is uploaded. + """ + upload, transport = self._initiate_resumable_upload( + client, + stream, + content_type, + size, + num_retries, + predefined_acl=predefined_acl, + if_generation_match=if_generation_match, + if_generation_not_match=if_generation_not_match, + if_metageneration_match=if_metageneration_match, + if_metageneration_not_match=if_metageneration_not_match, + timeout=timeout, + checksum=checksum, + retry=retry, + ) + while not upload.finished: + try: + response = upload.transmit_next_chunk(transport, timeout=timeout) + except resumable_media.DataCorruption: + # Attempt to delete the corrupted object. + self.delete() + raise + return response + + def _do_upload( + self, + client, + stream, + content_type, + size, + num_retries, + predefined_acl, + if_generation_match, + if_generation_not_match, + if_metageneration_match, + if_metageneration_not_match, + timeout=_DEFAULT_TIMEOUT, + checksum=None, + retry=None, + ): + """Determine an upload strategy and then perform the upload. + + If the size of the data to be uploaded exceeds 8 MB a resumable media + request will be used, otherwise the content and the metadata will be + uploaded in a single multipart upload request. + + The content type of the upload will be determined in order + of precedence: + + - The value passed in to this method (if not :data:`None`) + - The value stored on the current blob + - The default value ('application/octet-stream') + + :type client: :class:`~google.cloud.storage.client.Client` + :param client: + (Optional) The client to use. If not passed, falls back to the + ``client`` stored on the blob's bucket. + + :type stream: IO[bytes] + :param stream: A bytes IO object open for reading. + + :type content_type: str + :param content_type: Type of content being uploaded (or :data:`None`). + + :type size: int + :param size: + The number of bytes to be uploaded (which will be read from + ``stream``). If not provided, the upload will be concluded once + ``stream`` is exhausted (or :data:`None`). + + :type num_retries: int + :param num_retries: + Number of upload retries. By default, only uploads with + if_generation_match set will be retried, as uploads without the + argument are not guaranteed to be idempotent. Setting num_retries + will override this default behavior and guarantee retries even when + if_generation_match is not set. (Deprecated: This argument + will be removed in a future release.) + + :type predefined_acl: str + :param predefined_acl: (Optional) Predefined access control list + + :type if_generation_match: long + :param if_generation_match: + (Optional) See :ref:`using-if-generation-match` + + :type if_generation_not_match: long + :param if_generation_not_match: + (Optional) See :ref:`using-if-generation-not-match` + + :type if_metageneration_match: long + :param if_metageneration_match: + (Optional) See :ref:`using-if-metageneration-match` + + :type if_metageneration_not_match: long + :param if_metageneration_not_match: + (Optional) See :ref:`using-if-metageneration-not-match` + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type checksum: str + :param checksum: + (Optional) The type of checksum to compute to verify + the integrity of the object. If the upload is completed in a single + request, the checksum will be entirely precomputed and the remote + server will handle verification and error handling. If the upload + is too large and must be transmitted in multiple requests, the + checksum will be incrementally computed and the client will handle + verification and error handling, raising + google.resumable_media.common.DataCorruption on a mismatch and + attempting to delete the corrupted file. Supported values are + "md5", "crc32c" and None. The default is None. + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: (Optional) How to retry the RPC. A None value will disable + retries. A google.api_core.retry.Retry value will enable retries, + and the object will define retriable response codes and errors and + configure backoff and timeout options. + + A google.cloud.storage.retry.ConditionalRetryPolicy value wraps a + Retry object and activates it only if certain conditions are met. + This class exists to provide safe defaults for RPC calls that are + not technically safe to retry normally (due to potential data + duplication or other side-effects) but become safe to retry if a + condition such as if_generation_match is set. + + See the retry.py source code and docstrings in this package + (google.cloud.storage.retry) for information on retry types and how + to configure them. + + Media operations (downloads and uploads) do not support non-default + predicates in a Retry object. The default will always be used. Other + configuration changes for Retry objects such as delays and deadlines + are respected. + + :rtype: dict + :returns: The parsed JSON from the "200 OK" response. This will be the + **only** response in the multipart case and it will be the + **final** response in the resumable case. + """ + + # Handle ConditionalRetryPolicy. + if isinstance(retry, ConditionalRetryPolicy): + # Conditional retries are designed for non-media calls, which change + # arguments into query_params dictionaries. Media operations work + # differently, so here we make a "fake" query_params to feed to the + # ConditionalRetryPolicy. + query_params = { + "ifGenerationMatch": if_generation_match, + "ifMetagenerationMatch": if_metageneration_match, + } + retry = retry.get_retry_policy_if_conditions_met(query_params=query_params) + + if size is not None and size <= _MAX_MULTIPART_SIZE: + response = self._do_multipart_upload( + client, + stream, + content_type, + size, + num_retries, + predefined_acl, + if_generation_match, + if_generation_not_match, + if_metageneration_match, + if_metageneration_not_match, + timeout=timeout, + checksum=checksum, + retry=retry, + ) + else: + response = self._do_resumable_upload( + client, + stream, + content_type, + size, + num_retries, + predefined_acl, + if_generation_match, + if_generation_not_match, + if_metageneration_match, + if_metageneration_not_match, + timeout=timeout, + checksum=checksum, + retry=retry, + ) + + return response.json() + + def upload_from_file( + self, + file_obj, + rewind=False, + size=None, + content_type=None, + num_retries=None, + client=None, + predefined_acl=None, + if_generation_match=None, + if_generation_not_match=None, + if_metageneration_match=None, + if_metageneration_not_match=None, + timeout=_DEFAULT_TIMEOUT, + checksum=None, + retry=DEFAULT_RETRY_IF_GENERATION_SPECIFIED, + ): + """Upload the contents of this blob from a file-like object. + + The content type of the upload will be determined in order + of precedence: + + - The value passed in to this method (if not :data:`None`) + - The value stored on the current blob + - The default value ('application/octet-stream') + + .. note:: + The effect of uploading to an existing blob depends on the + "versioning" and "lifecycle" policies defined on the blob's + bucket. In the absence of those policies, upload will + overwrite any existing contents. + + See the [`object versioning`](https://cloud.google.com/storage/docs/object-versioning) + and [`lifecycle`](https://cloud.google.com/storage/docs/lifecycle) + API documents for details. + + If the size of the data to be uploaded exceeds 8 MB a resumable media + request will be used, otherwise the content and the metadata will be + uploaded in a single multipart upload request. + + For more fine-grained over the upload process, check out + [`google-resumable-media`](https://googleapis.dev/python/google-resumable-media/latest/index.html). + + If :attr:`user_project` is set on the bucket, bills the API request + to that project. + + :type file_obj: file + :param file_obj: A file handle opened in binary mode for reading. + + :type rewind: bool + :param rewind: + If True, seek to the beginning of the file handle before writing + the file to Cloud Storage. + + :type size: int + :param size: + The number of bytes to be uploaded (which will be read from + ``file_obj``). If not provided, the upload will be concluded once + ``file_obj`` is exhausted. + + :type content_type: str + :param content_type: (Optional) Type of content being uploaded. + + :type num_retries: int + :param num_retries: + Number of upload retries. By default, only uploads with + if_generation_match set will be retried, as uploads without the + argument are not guaranteed to be idempotent. Setting num_retries + will override this default behavior and guarantee retries even when + if_generation_match is not set. (Deprecated: This argument + will be removed in a future release.) + + :type client: :class:`~google.cloud.storage.client.Client` + :param client: + (Optional) The client to use. If not passed, falls back to the + ``client`` stored on the blob's bucket. + + :type predefined_acl: str + :param predefined_acl: (Optional) Predefined access control list + + :type if_generation_match: long + :param if_generation_match: + (Optional) See :ref:`using-if-generation-match` + + :type if_generation_not_match: long + :param if_generation_not_match: + (Optional) See :ref:`using-if-generation-not-match` + + :type if_metageneration_match: long + :param if_metageneration_match: + (Optional) See :ref:`using-if-metageneration-match` + + :type if_metageneration_not_match: long + :param if_metageneration_not_match: + (Optional) See :ref:`using-if-metageneration-not-match` + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type checksum: str + :param checksum: + (Optional) The type of checksum to compute to verify + the integrity of the object. If the upload is completed in a single + request, the checksum will be entirely precomputed and the remote + server will handle verification and error handling. If the upload + is too large and must be transmitted in multiple requests, the + checksum will be incrementally computed and the client will handle + verification and error handling, raising + google.resumable_media.common.DataCorruption on a mismatch and + attempting to delete the corrupted file. Supported values are + "md5", "crc32c" and None. The default is None. + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: (Optional) How to retry the RPC. A None value will disable + retries. A google.api_core.retry.Retry value will enable retries, + and the object will define retriable response codes and errors and + configure backoff and timeout options. + + A google.cloud.storage.retry.ConditionalRetryPolicy value wraps a + Retry object and activates it only if certain conditions are met. + This class exists to provide safe defaults for RPC calls that are + not technically safe to retry normally (due to potential data + duplication or other side-effects) but become safe to retry if a + condition such as if_generation_match is set. + + See the retry.py source code and docstrings in this package + (google.cloud.storage.retry) for information on retry types and how + to configure them. + + Media operations (downloads and uploads) do not support non-default + predicates in a Retry object. The default will always be used. Other + configuration changes for Retry objects such as delays and deadlines + are respected. + + :raises: :class:`~google.cloud.exceptions.GoogleCloudError` + if the upload response returns an error status. + """ + if num_retries is not None: + warnings.warn(_NUM_RETRIES_MESSAGE, DeprecationWarning, stacklevel=2) + # num_retries and retry are mutually exclusive. If num_retries is + # set and retry is exactly the default, then nullify retry for + # backwards compatibility. + if retry is DEFAULT_RETRY_IF_GENERATION_SPECIFIED: + retry = None + + _maybe_rewind(file_obj, rewind=rewind) + predefined_acl = ACL.validate_predefined(predefined_acl) + + try: + created_json = self._do_upload( + client, + file_obj, + content_type, + size, + num_retries, + predefined_acl, + if_generation_match, + if_generation_not_match, + if_metageneration_match, + if_metageneration_not_match, + timeout=timeout, + checksum=checksum, + retry=retry, + ) + self._set_properties(created_json) + except resumable_media.InvalidResponse as exc: + _raise_from_invalid_response(exc) + + def upload_from_filename( + self, + filename, + content_type=None, + num_retries=None, + client=None, + predefined_acl=None, + if_generation_match=None, + if_generation_not_match=None, + if_metageneration_match=None, + if_metageneration_not_match=None, + timeout=_DEFAULT_TIMEOUT, + checksum=None, + retry=DEFAULT_RETRY_IF_GENERATION_SPECIFIED, + ): + """Upload this blob's contents from the content of a named file. + + The content type of the upload will be determined in order + of precedence: + + - The value passed in to this method (if not :data:`None`) + - The value stored on the current blob + - The value given by ``mimetypes.guess_type`` + - The default value ('application/octet-stream') + + .. note:: + The effect of uploading to an existing blob depends on the + "versioning" and "lifecycle" policies defined on the blob's + bucket. In the absence of those policies, upload will + overwrite any existing contents. + + See the [`object versioning`](https://cloud.google.com/storage/docs/object-versioning) + and [`lifecycle`](https://cloud.google.com/storage/docs/lifecycle) + API documents for details. + + If :attr:`user_project` is set on the bucket, bills the API request + to that project. + + See a [code sample](https://cloud.google.com/storage/docs/samples/storage-upload-encrypted-file#storage_upload_encrypted_file-python) + to upload a file with a + [`customer-supplied encryption key`](https://cloud.google.com/storage/docs/encryption#customer-supplied). + + :type filename: str + :param filename: The path to the file. + + :type content_type: str + :param content_type: (Optional) Type of content being uploaded. + + :type client: :class:`~google.cloud.storage.client.Client` + :param client: + (Optional) The client to use. If not passed, falls back to the + ``client`` stored on the blob's bucket. + + :type num_retries: int + :param num_retries: + Number of upload retries. By default, only uploads with + if_generation_match set will be retried, as uploads without the + argument are not guaranteed to be idempotent. Setting num_retries + will override this default behavior and guarantee retries even when + if_generation_match is not set. (Deprecated: This argument + will be removed in a future release.) + + :type predefined_acl: str + :param predefined_acl: (Optional) Predefined access control list + + :type if_generation_match: long + :param if_generation_match: + (Optional) See :ref:`using-if-generation-match` + + :type if_generation_not_match: long + :param if_generation_not_match: + (Optional) See :ref:`using-if-generation-not-match` + + :type if_metageneration_match: long + :param if_metageneration_match: + (Optional) See :ref:`using-if-metageneration-match` + + :type if_metageneration_not_match: long + :param if_metageneration_not_match: + (Optional) See :ref:`using-if-metageneration-not-match` + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type checksum: str + :param checksum: + (Optional) The type of checksum to compute to verify + the integrity of the object. If the upload is completed in a single + request, the checksum will be entirely precomputed and the remote + server will handle verification and error handling. If the upload + is too large and must be transmitted in multiple requests, the + checksum will be incrementally computed and the client will handle + verification and error handling, raising + google.resumable_media.common.DataCorruption on a mismatch and + attempting to delete the corrupted file. Supported values are + "md5", "crc32c" and None. The default is None. + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: (Optional) How to retry the RPC. A None value will disable + retries. A google.api_core.retry.Retry value will enable retries, + and the object will define retriable response codes and errors and + configure backoff and timeout options. + + A google.cloud.storage.retry.ConditionalRetryPolicy value wraps a + Retry object and activates it only if certain conditions are met. + This class exists to provide safe defaults for RPC calls that are + not technically safe to retry normally (due to potential data + duplication or other side-effects) but become safe to retry if a + condition such as if_generation_match is set. + + See the retry.py source code and docstrings in this package + (google.cloud.storage.retry) for information on retry types and how + to configure them. + + Media operations (downloads and uploads) do not support non-default + predicates in a Retry object. The default will always be used. Other + configuration changes for Retry objects such as delays and deadlines + are respected. + """ + content_type = self._get_content_type(content_type, filename=filename) + + with open(filename, "rb") as file_obj: + total_bytes = os.fstat(file_obj.fileno()).st_size + self.upload_from_file( + file_obj, + content_type=content_type, + num_retries=num_retries, + client=client, + size=total_bytes, + predefined_acl=predefined_acl, + if_generation_match=if_generation_match, + if_generation_not_match=if_generation_not_match, + if_metageneration_match=if_metageneration_match, + if_metageneration_not_match=if_metageneration_not_match, + timeout=timeout, + checksum=checksum, + retry=retry, + ) + + def upload_from_string( + self, + data, + content_type="text/plain", + num_retries=None, + client=None, + predefined_acl=None, + if_generation_match=None, + if_generation_not_match=None, + if_metageneration_match=None, + if_metageneration_not_match=None, + timeout=_DEFAULT_TIMEOUT, + checksum=None, + retry=DEFAULT_RETRY_IF_GENERATION_SPECIFIED, + ): + """Upload contents of this blob from the provided string. + + .. note:: + The effect of uploading to an existing blob depends on the + "versioning" and "lifecycle" policies defined on the blob's + bucket. In the absence of those policies, upload will + overwrite any existing contents. + + See the [`object versioning`](https://cloud.google.com/storage/docs/object-versioning) + and [`lifecycle`](https://cloud.google.com/storage/docs/lifecycle) + API documents for details. + + If :attr:`user_project` is set on the bucket, bills the API request + to that project. + + :type data: bytes or str + :param data: + The data to store in this blob. If the value is text, it will be + encoded as UTF-8. + + :type content_type: str + :param content_type: + (Optional) Type of content being uploaded. Defaults to + ``'text/plain'``. + + :type num_retries: int + :param num_retries: + Number of upload retries. By default, only uploads with + if_generation_match set will be retried, as uploads without the + argument are not guaranteed to be idempotent. Setting num_retries + will override this default behavior and guarantee retries even when + if_generation_match is not set. (Deprecated: This argument + will be removed in a future release.) + + :type client: :class:`~google.cloud.storage.client.Client` + :param client: + (Optional) The client to use. If not passed, falls back to the + ``client`` stored on the blob's bucket. + + :type predefined_acl: str + :param predefined_acl: (Optional) Predefined access control list + + :type if_generation_match: long + :param if_generation_match: + (Optional) See :ref:`using-if-generation-match` + + :type if_generation_not_match: long + :param if_generation_not_match: + (Optional) See :ref:`using-if-generation-not-match` + + :type if_metageneration_match: long + :param if_metageneration_match: + (Optional) See :ref:`using-if-metageneration-match` + + :type if_metageneration_not_match: long + :param if_metageneration_not_match: + (Optional) See :ref:`using-if-metageneration-not-match` + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type checksum: str + :param checksum: + (Optional) The type of checksum to compute to verify + the integrity of the object. If the upload is completed in a single + request, the checksum will be entirely precomputed and the remote + server will handle verification and error handling. If the upload + is too large and must be transmitted in multiple requests, the + checksum will be incrementally computed and the client will handle + verification and error handling, raising + google.resumable_media.common.DataCorruption on a mismatch and + attempting to delete the corrupted file. Supported values are + "md5", "crc32c" and None. The default is None. + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: (Optional) How to retry the RPC. A None value will disable + retries. A google.api_core.retry.Retry value will enable retries, + and the object will define retriable response codes and errors and + configure backoff and timeout options. + + A google.cloud.storage.retry.ConditionalRetryPolicy value wraps a + Retry object and activates it only if certain conditions are met. + This class exists to provide safe defaults for RPC calls that are + not technically safe to retry normally (due to potential data + duplication or other side-effects) but become safe to retry if a + condition such as if_generation_match is set. + + See the retry.py source code and docstrings in this package + (google.cloud.storage.retry) for information on retry types and how + to configure them. + + Media operations (downloads and uploads) do not support non-default + predicates in a Retry object. The default will always be used. Other + configuration changes for Retry objects such as delays and deadlines + are respected. + """ + data = _to_bytes(data, encoding="utf-8") + string_buffer = BytesIO(data) + self.upload_from_file( + file_obj=string_buffer, + size=len(data), + content_type=content_type, + num_retries=num_retries, + client=client, + predefined_acl=predefined_acl, + if_generation_match=if_generation_match, + if_generation_not_match=if_generation_not_match, + if_metageneration_match=if_metageneration_match, + if_metageneration_not_match=if_metageneration_not_match, + timeout=timeout, + checksum=checksum, + retry=retry, + ) + + def create_resumable_upload_session( + self, + content_type=None, + size=None, + origin=None, + client=None, + timeout=_DEFAULT_TIMEOUT, + checksum=None, + predefined_acl=None, + if_generation_match=None, + if_generation_not_match=None, + if_metageneration_match=None, + if_metageneration_not_match=None, + retry=DEFAULT_RETRY_IF_GENERATION_SPECIFIED, + ): + """Create a resumable upload session. + + Resumable upload sessions allow you to start an upload session from + one client and complete the session in another. This method is called + by the initiator to set the metadata and limits. The initiator then + passes the session URL to the client that will upload the binary data. + The client performs a PUT request on the session URL to complete the + upload. This process allows untrusted clients to upload to an + access-controlled bucket. + + For more details, see the + documentation on [`signed URLs`](https://cloud.google.com/storage/docs/access-control/signed-urls#signing-resumable). + + The content type of the upload will be determined in order + of precedence: + + - The value passed in to this method (if not :data:`None`) + - The value stored on the current blob + - The default value ('application/octet-stream') + + .. note:: + The effect of uploading to an existing blob depends on the + "versioning" and "lifecycle" policies defined on the blob's + bucket. In the absence of those policies, upload will + overwrite any existing contents. + + See the [`object versioning`](https://cloud.google.com/storage/docs/object-versioning) + and [`lifecycle`](https://cloud.google.com/storage/docs/lifecycle) + API documents for details. + + If :attr:`encryption_key` is set, the blob will be encrypted with + a [`customer-supplied`](https://cloud.google.com/storage/docs/encryption#customer-supplied) + encryption key. + + If :attr:`user_project` is set on the bucket, bills the API request + to that project. + + :type size: int + :param size: + (Optional) The maximum number of bytes that can be uploaded using + this session. If the size is not known when creating the session, + this should be left blank. + + :type content_type: str + :param content_type: (Optional) Type of content being uploaded. + + :type origin: str + :param origin: + (Optional) If set, the upload can only be completed by a user-agent + that uploads from the given origin. This can be useful when passing + the session to a web client. + + :type client: :class:`~google.cloud.storage.client.Client` + :param client: + (Optional) The client to use. If not passed, falls back to the + ``client`` stored on the blob's bucket. + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type checksum: str + :param checksum: + (Optional) The type of checksum to compute to verify + the integrity of the object. After the upload is complete, the + server-computed checksum of the resulting object will be checked + and google.resumable_media.common.DataCorruption will be raised on + a mismatch. On a validation failure, the client will attempt to + delete the uploaded object automatically. Supported values + are "md5", "crc32c" and None. The default is None. + + :type predefined_acl: str + :param predefined_acl: (Optional) Predefined access control list + + :type if_generation_match: long + :param if_generation_match: + (Optional) See :ref:`using-if-generation-match` + + :type if_generation_not_match: long + :param if_generation_not_match: + (Optional) See :ref:`using-if-generation-not-match` + + :type if_metageneration_match: long + :param if_metageneration_match: + (Optional) See :ref:`using-if-metageneration-match` + + :type if_metageneration_not_match: long + :param if_metageneration_not_match: + (Optional) See :ref:`using-if-metageneration-not-match` + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: (Optional) How to retry the RPC. A None value will disable + retries. A google.api_core.retry.Retry value will enable retries, + and the object will define retriable response codes and errors and + configure backoff and timeout options. + A google.cloud.storage.retry.ConditionalRetryPolicy value wraps a + Retry object and activates it only if certain conditions are met. + This class exists to provide safe defaults for RPC calls that are + not technically safe to retry normally (due to potential data + duplication or other side-effects) but become safe to retry if a + condition such as if_generation_match is set. + See the retry.py source code and docstrings in this package + (google.cloud.storage.retry) for information on retry types and how + to configure them. + Media operations (downloads and uploads) do not support non-default + predicates in a Retry object. The default will always be used. Other + configuration changes for Retry objects such as delays and deadlines + are respected. + + :rtype: str + :returns: The resumable upload session URL. The upload can be + completed by making an HTTP PUT request with the + file's contents. + + :raises: :class:`google.cloud.exceptions.GoogleCloudError` + if the session creation response returns an error status. + """ + + # Handle ConditionalRetryPolicy. + if isinstance(retry, ConditionalRetryPolicy): + # Conditional retries are designed for non-media calls, which change + # arguments into query_params dictionaries. Media operations work + # differently, so here we make a "fake" query_params to feed to the + # ConditionalRetryPolicy. + query_params = { + "ifGenerationMatch": if_generation_match, + "ifMetagenerationMatch": if_metageneration_match, + } + retry = retry.get_retry_policy_if_conditions_met(query_params=query_params) + + extra_headers = {} + if origin is not None: + # This header is specifically for client-side uploads, it + # determines the origins allowed for CORS. + extra_headers["Origin"] = origin + + try: + fake_stream = BytesIO(b"") + # Send a fake the chunk size which we **know** will be acceptable + # to the `ResumableUpload` constructor. The chunk size only + # matters when **sending** bytes to an upload. + upload, _ = self._initiate_resumable_upload( + client, + fake_stream, + content_type, + size, + None, + predefined_acl=predefined_acl, + if_generation_match=if_generation_match, + if_generation_not_match=if_generation_not_match, + if_metageneration_match=if_metageneration_match, + if_metageneration_not_match=if_metageneration_not_match, + extra_headers=extra_headers, + chunk_size=self._CHUNK_SIZE_MULTIPLE, + timeout=timeout, + checksum=checksum, + retry=retry, + ) + + return upload.resumable_url + except resumable_media.InvalidResponse as exc: + _raise_from_invalid_response(exc) + + def get_iam_policy( + self, + client=None, + requested_policy_version=None, + timeout=_DEFAULT_TIMEOUT, + retry=DEFAULT_RETRY, + ): + """Retrieve the IAM policy for the object. + + .. note:: + + Blob- / object-level IAM support does not yet exist and methods + currently call an internal ACL backend not providing any utility + beyond the blob's :attr:`acl` at this time. The API may be enhanced + in the future and is currently undocumented. Use :attr:`acl` for + managing object access control. + + If :attr:`user_project` is set on the bucket, bills the API request + to that project. + + :type client: :class:`~google.cloud.storage.client.Client` + :param client: + (Optional) The client to use. If not passed, falls back to the + ``client`` stored on the current object's bucket. + + :type requested_policy_version: int or ``NoneType`` + :param requested_policy_version: + (Optional) The version of IAM policies to request. If a policy + with a condition is requested without setting this, the server will + return an error. This must be set to a value of 3 to retrieve IAM + policies containing conditions. This is to prevent client code that + isn't aware of IAM conditions from interpreting and modifying + policies incorrectly. The service might return a policy with + version lower than the one that was requested, based on the feature + syntax in the policy fetched. + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + + :rtype: :class:`google.api_core.iam.Policy` + :returns: the policy instance, based on the resource returned from + the ``getIamPolicy`` API request. + """ + client = self._require_client(client) + + query_params = {} + + if self.user_project is not None: + query_params["userProject"] = self.user_project + + if requested_policy_version is not None: + query_params["optionsRequestedPolicyVersion"] = requested_policy_version + + info = client._get_resource( + f"{self.path}/iam", + query_params=query_params, + timeout=timeout, + retry=retry, + _target_object=None, + ) + return Policy.from_api_repr(info) + + def set_iam_policy( + self, + policy, + client=None, + timeout=_DEFAULT_TIMEOUT, + retry=DEFAULT_RETRY_IF_ETAG_IN_JSON, + ): + """Update the IAM policy for the bucket. + + .. note:: + + Blob- / object-level IAM support does not yet exist and methods + currently call an internal ACL backend not providing any utility + beyond the blob's :attr:`acl` at this time. The API may be enhanced + in the future and is currently undocumented. Use :attr:`acl` for + managing object access control. + + If :attr:`user_project` is set on the bucket, bills the API request + to that project. + + :type policy: :class:`google.api_core.iam.Policy` + :param policy: policy instance used to update bucket's IAM policy. + + :type client: :class:`~google.cloud.storage.client.Client` + :param client: + (Optional) The client to use. If not passed, falls back to the + ``client`` stored on the current bucket. + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + + :rtype: :class:`google.api_core.iam.Policy` + :returns: the policy instance, based on the resource returned from + the ``setIamPolicy`` API request. + """ + client = self._require_client(client) + + query_params = {} + + if self.user_project is not None: + query_params["userProject"] = self.user_project + + path = f"{self.path}/iam" + resource = policy.to_api_repr() + resource["resourceId"] = self.path + info = client._put_resource( + path, + resource, + query_params=query_params, + timeout=timeout, + retry=retry, + _target_object=None, + ) + return Policy.from_api_repr(info) + + def test_iam_permissions( + self, permissions, client=None, timeout=_DEFAULT_TIMEOUT, retry=DEFAULT_RETRY + ): + """API call: test permissions + + .. note:: + + Blob- / object-level IAM support does not yet exist and methods + currently call an internal ACL backend not providing any utility + beyond the blob's :attr:`acl` at this time. The API may be enhanced + in the future and is currently undocumented. Use :attr:`acl` for + managing object access control. + + If :attr:`user_project` is set on the bucket, bills the API request + to that project. + + :type permissions: list of string + :param permissions: the permissions to check + + :type client: :class:`~google.cloud.storage.client.Client` + :param client: + (Optional) The client to use. If not passed, falls back to the + ``client`` stored on the current bucket. + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + + :rtype: list of string + :returns: the permissions returned by the ``testIamPermissions`` API + request. + """ + client = self._require_client(client) + query_params = {"permissions": permissions} + + if self.user_project is not None: + query_params["userProject"] = self.user_project + + path = f"{self.path}/iam/testPermissions" + resp = client._get_resource( + path, + query_params=query_params, + timeout=timeout, + retry=retry, + _target_object=None, + ) + + return resp.get("permissions", []) + + def make_public( + self, + client=None, + timeout=_DEFAULT_TIMEOUT, + if_generation_match=None, + if_generation_not_match=None, + if_metageneration_match=None, + if_metageneration_not_match=None, + retry=DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED, + ): + """Update blob's ACL, granting read access to anonymous users. + + :type client: :class:`~google.cloud.storage.client.Client` or + ``NoneType`` + :param client: (Optional) The client to use. If not passed, falls back + to the ``client`` stored on the blob's bucket. + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type if_generation_match: long + :param if_generation_match: + (Optional) See :ref:`using-if-generation-match` + + :type if_generation_not_match: long + :param if_generation_not_match: + (Optional) See :ref:`using-if-generation-not-match` + + :type if_metageneration_match: long + :param if_metageneration_match: + (Optional) See :ref:`using-if-metageneration-match` + + :type if_metageneration_not_match: long + :param if_metageneration_not_match: + (Optional) See :ref:`using-if-metageneration-not-match` + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + """ + self.acl.all().grant_read() + self.acl.save( + client=client, + timeout=timeout, + if_generation_match=if_generation_match, + if_generation_not_match=if_generation_not_match, + if_metageneration_match=if_metageneration_match, + if_metageneration_not_match=if_metageneration_not_match, + retry=retry, + ) + + def make_private( + self, + client=None, + timeout=_DEFAULT_TIMEOUT, + if_generation_match=None, + if_generation_not_match=None, + if_metageneration_match=None, + if_metageneration_not_match=None, + retry=DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED, + ): + """Update blob's ACL, revoking read access for anonymous users. + + :type client: :class:`~google.cloud.storage.client.Client` or + ``NoneType`` + :param client: (Optional) The client to use. If not passed, falls back + to the ``client`` stored on the blob's bucket. + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type if_generation_match: long + :param if_generation_match: + (Optional) See :ref:`using-if-generation-match` + + :type if_generation_not_match: long + :param if_generation_not_match: + (Optional) See :ref:`using-if-generation-not-match` + + :type if_metageneration_match: long + :param if_metageneration_match: + (Optional) See :ref:`using-if-metageneration-match` + + :type if_metageneration_not_match: long + :param if_metageneration_not_match: + (Optional) See :ref:`using-if-metageneration-not-match` + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + """ + self.acl.all().revoke_read() + self.acl.save( + client=client, + timeout=timeout, + if_generation_match=if_generation_match, + if_generation_not_match=if_generation_not_match, + if_metageneration_match=if_metageneration_match, + if_metageneration_not_match=if_metageneration_not_match, + retry=retry, + ) + + def compose( + self, + sources, + client=None, + timeout=_DEFAULT_TIMEOUT, + if_generation_match=None, + if_metageneration_match=None, + if_source_generation_match=None, + retry=DEFAULT_RETRY_IF_GENERATION_SPECIFIED, + ): + """Concatenate source blobs into this one. + + If :attr:`user_project` is set on the bucket, bills the API request + to that project. + + See [API reference docs](https://cloud.google.com/storage/docs/json_api/v1/objects/compose) + and a [code sample](https://cloud.google.com/storage/docs/samples/storage-compose-file#storage_compose_file-python). + + :type sources: list of :class:`Blob` + :param sources: Blobs whose contents will be composed into this blob. + + :type client: :class:`~google.cloud.storage.client.Client` + :param client: + (Optional) The client to use. If not passed, falls back to the + ``client`` stored on the blob's bucket. + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type if_generation_match: long + :param if_generation_match: + (Optional) Makes the operation conditional on whether the + destination object's current generation matches the given value. + Setting to 0 makes the operation succeed only if there are no live + versions of the object. + Note: In a previous version, this argument worked identically to the + ``if_source_generation_match`` argument. For + backwards-compatibility reasons, if a list is passed in, + this argument will behave like ``if_source_generation_match`` + and also issue a DeprecationWarning. + + :type if_metageneration_match: long + :param if_metageneration_match: + (Optional) Makes the operation conditional on whether the + destination object's current metageneration matches the given + value. + + If a list of long is passed in, no match operation will be + performed. (Deprecated: type(list of long) is supported for + backwards-compatability reasons only.) + + :type if_source_generation_match: list of long + :param if_source_generation_match: + (Optional) Makes the operation conditional on whether the current + generation of each source blob matches the corresponding generation. + The list must match ``sources`` item-to-item. + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + """ + sources_len = len(sources) + client = self._require_client(client) + query_params = {} + + if isinstance(if_generation_match, list): + warnings.warn( + _COMPOSE_IF_GENERATION_LIST_DEPRECATED, + DeprecationWarning, + stacklevel=2, + ) + + if if_source_generation_match is not None: + raise ValueError( + _COMPOSE_IF_GENERATION_LIST_AND_IF_SOURCE_GENERATION_ERROR + ) + + if_source_generation_match = if_generation_match + if_generation_match = None + + if isinstance(if_metageneration_match, list): + warnings.warn( + _COMPOSE_IF_METAGENERATION_LIST_DEPRECATED, + DeprecationWarning, + stacklevel=2, + ) + + if_metageneration_match = None + + if if_source_generation_match is None: + if_source_generation_match = [None] * sources_len + if len(if_source_generation_match) != sources_len: + raise ValueError(_COMPOSE_IF_SOURCE_GENERATION_MISMATCH_ERROR) + + source_objects = [] + for source, source_generation in zip(sources, if_source_generation_match): + source_object = {"name": source.name, "generation": source.generation} + + preconditions = {} + if source_generation is not None: + preconditions["ifGenerationMatch"] = source_generation + + if preconditions: + source_object["objectPreconditions"] = preconditions + + source_objects.append(source_object) + + request = { + "sourceObjects": source_objects, + "destination": self._properties.copy(), + } + + if self.user_project is not None: + query_params["userProject"] = self.user_project + + _add_generation_match_parameters( + query_params, + if_generation_match=if_generation_match, + if_metageneration_match=if_metageneration_match, + ) + + api_response = client._post_resource( + f"{self.path}/compose", + request, + query_params=query_params, + timeout=timeout, + retry=retry, + _target_object=self, + ) + self._set_properties(api_response) + + def rewrite( + self, + source, + token=None, + client=None, + if_generation_match=None, + if_generation_not_match=None, + if_metageneration_match=None, + if_metageneration_not_match=None, + if_source_generation_match=None, + if_source_generation_not_match=None, + if_source_metageneration_match=None, + if_source_metageneration_not_match=None, + timeout=_DEFAULT_TIMEOUT, + retry=DEFAULT_RETRY_IF_GENERATION_SPECIFIED, + ): + """Rewrite source blob into this one. + + If :attr:`user_project` is set on the bucket, bills the API request + to that project. + + :type source: :class:`Blob` + :param source: blob whose contents will be rewritten into this blob. + + :type token: str + :param token: + (Optional) Token returned from an earlier, not-completed call to + rewrite the same source blob. If passed, result will include + updated status, total bytes written. + + :type client: :class:`~google.cloud.storage.client.Client` + :param client: + (Optional) The client to use. If not passed, falls back to the + ``client`` stored on the blob's bucket. + + :type if_generation_match: long + :param if_generation_match: + (Optional) See :ref:`using-if-generation-match` + Note that the generation to be matched is that of the + ``destination`` blob. + + :type if_generation_not_match: long + :param if_generation_not_match: + (Optional) See :ref:`using-if-generation-not-match` + Note that the generation to be matched is that of the + ``destination`` blob. + + :type if_metageneration_match: long + :param if_metageneration_match: + (Optional) See :ref:`using-if-metageneration-match` + Note that the metageneration to be matched is that of the + ``destination`` blob. + + :type if_metageneration_not_match: long + :param if_metageneration_not_match: + (Optional) See :ref:`using-if-metageneration-not-match` + Note that the metageneration to be matched is that of the + ``destination`` blob. + + :type if_source_generation_match: long + :param if_source_generation_match: + (Optional) Makes the operation conditional on whether the source + object's generation matches the given value. + + :type if_source_generation_not_match: long + :param if_source_generation_not_match: + (Optional) Makes the operation conditional on whether the source + object's generation does not match the given value. + + :type if_source_metageneration_match: long + :param if_source_metageneration_match: + (Optional) Makes the operation conditional on whether the source + object's current metageneration matches the given value. + + :type if_source_metageneration_not_match: long + :param if_source_metageneration_not_match: + (Optional) Makes the operation conditional on whether the source + object's current metageneration does not match the given value. + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + + :rtype: tuple + :returns: ``(token, bytes_rewritten, total_bytes)``, where ``token`` + is a rewrite token (``None`` if the rewrite is complete), + ``bytes_rewritten`` is the number of bytes rewritten so far, + and ``total_bytes`` is the total number of bytes to be + rewritten. + """ + client = self._require_client(client) + headers = _get_encryption_headers(self._encryption_key) + headers.update(_get_encryption_headers(source._encryption_key, source=True)) + + query_params = self._query_params + if "generation" in query_params: + del query_params["generation"] + + if token: + query_params["rewriteToken"] = token + + if source.generation: + query_params["sourceGeneration"] = source.generation + + # When a Customer Managed Encryption Key is used to encrypt Cloud Storage object + # at rest, object resource metadata will store the version of the Key Management + # Service cryptographic material. If a Blob instance with KMS Key metadata set is + # used to rewrite the object, then the existing kmsKeyName version + # value can't be used in the rewrite request and the client instead ignores it. + if ( + self.kms_key_name is not None + and "cryptoKeyVersions" not in self.kms_key_name + ): + query_params["destinationKmsKeyName"] = self.kms_key_name + + _add_generation_match_parameters( + query_params, + if_generation_match=if_generation_match, + if_generation_not_match=if_generation_not_match, + if_metageneration_match=if_metageneration_match, + if_metageneration_not_match=if_metageneration_not_match, + if_source_generation_match=if_source_generation_match, + if_source_generation_not_match=if_source_generation_not_match, + if_source_metageneration_match=if_source_metageneration_match, + if_source_metageneration_not_match=if_source_metageneration_not_match, + ) + + path = f"{source.path}/rewriteTo{self.path}" + api_response = client._post_resource( + path, + self._properties, + query_params=query_params, + headers=headers, + timeout=timeout, + retry=retry, + _target_object=self, + ) + rewritten = int(api_response["totalBytesRewritten"]) + size = int(api_response["objectSize"]) + + # The resource key is set if and only if the API response is + # completely done. Additionally, there is no rewrite token to return + # in this case. + if api_response["done"]: + self._set_properties(api_response["resource"]) + return None, rewritten, size + + return api_response["rewriteToken"], rewritten, size + + def update_storage_class( + self, + new_class, + client=None, + if_generation_match=None, + if_generation_not_match=None, + if_metageneration_match=None, + if_metageneration_not_match=None, + if_source_generation_match=None, + if_source_generation_not_match=None, + if_source_metageneration_match=None, + if_source_metageneration_not_match=None, + timeout=_DEFAULT_TIMEOUT, + retry=DEFAULT_RETRY_IF_GENERATION_SPECIFIED, + ): + """Update blob's storage class via a rewrite-in-place. This helper will + wait for the rewrite to complete before returning, so it may take some + time for large files. + + See + https://cloud.google.com/storage/docs/per-object-storage-class + + If :attr:`user_project` is set on the bucket, bills the API request + to that project. + + :type new_class: str + :param new_class: + new storage class for the object. One of: + :attr:`~google.cloud.storage.constants.NEARLINE_STORAGE_CLASS`, + :attr:`~google.cloud.storage.constants.COLDLINE_STORAGE_CLASS`, + :attr:`~google.cloud.storage.constants.ARCHIVE_STORAGE_CLASS`, + :attr:`~google.cloud.storage.constants.STANDARD_STORAGE_CLASS`, + :attr:`~google.cloud.storage.constants.MULTI_REGIONAL_LEGACY_STORAGE_CLASS`, + or + :attr:`~google.cloud.storage.constants.REGIONAL_LEGACY_STORAGE_CLASS`. + + :type client: :class:`~google.cloud.storage.client.Client` + :param client: + (Optional) The client to use. If not passed, falls back to the + ``client`` stored on the blob's bucket. + + :type if_generation_match: long + :param if_generation_match: + (Optional) See :ref:`using-if-generation-match` + Note that the generation to be matched is that of the + ``destination`` blob. + + :type if_generation_not_match: long + :param if_generation_not_match: + (Optional) See :ref:`using-if-generation-not-match` + Note that the generation to be matched is that of the + ``destination`` blob. + + :type if_metageneration_match: long + :param if_metageneration_match: + (Optional) See :ref:`using-if-metageneration-match` + Note that the metageneration to be matched is that of the + ``destination`` blob. + + :type if_metageneration_not_match: long + :param if_metageneration_not_match: + (Optional) See :ref:`using-if-metageneration-not-match` + Note that the metageneration to be matched is that of the + ``destination`` blob. + + :type if_source_generation_match: long + :param if_source_generation_match: + (Optional) Makes the operation conditional on whether the source + object's generation matches the given value. + + :type if_source_generation_not_match: long + :param if_source_generation_not_match: + (Optional) Makes the operation conditional on whether the source + object's generation does not match the given value. + + :type if_source_metageneration_match: long + :param if_source_metageneration_match: + (Optional) Makes the operation conditional on whether the source + object's current metageneration matches the given value. + + :type if_source_metageneration_not_match: long + :param if_source_metageneration_not_match: + (Optional) Makes the operation conditional on whether the source + object's current metageneration does not match the given value. + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + """ + # Update current blob's storage class prior to rewrite + self._patch_property("storageClass", new_class) + + # Execute consecutive rewrite operations until operation is done + token, _, _ = self.rewrite( + self, + if_generation_match=if_generation_match, + if_generation_not_match=if_generation_not_match, + if_metageneration_match=if_metageneration_match, + if_metageneration_not_match=if_metageneration_not_match, + if_source_generation_match=if_source_generation_match, + if_source_generation_not_match=if_source_generation_not_match, + if_source_metageneration_match=if_source_metageneration_match, + if_source_metageneration_not_match=if_source_metageneration_not_match, + timeout=timeout, + retry=retry, + ) + while token is not None: + token, _, _ = self.rewrite( + self, + token=token, + if_generation_match=if_generation_match, + if_generation_not_match=if_generation_not_match, + if_metageneration_match=if_metageneration_match, + if_metageneration_not_match=if_metageneration_not_match, + if_source_generation_match=if_source_generation_match, + if_source_generation_not_match=if_source_generation_not_match, + if_source_metageneration_match=if_source_metageneration_match, + if_source_metageneration_not_match=if_source_metageneration_not_match, + timeout=timeout, + retry=retry, + ) + + def open( + self, + mode="r", + chunk_size=None, + ignore_flush=None, + encoding=None, + errors=None, + newline=None, + **kwargs, + ): + r"""Create a file handler for file-like I/O to or from this blob. + + This method can be used as a context manager, just like Python's + built-in 'open()' function. + + While reading, as with other read methods, if blob.generation is not set + the most recent blob generation will be used. Because the file-like IO + reader downloads progressively in chunks, this could result in data from + multiple versions being mixed together. If this is a concern, use + either bucket.get_blob(), or blob.reload(), which will download the + latest generation number and set it; or, if the generation is known, set + it manually, for instance with bucket.blob(generation=123456). + + Checksumming (hashing) to verify data integrity is disabled for reads + using this feature because reads are implemented using request ranges, + which do not provide checksums to validate. See + https://cloud.google.com/storage/docs/hashes-etags for details. + + See a [code sample](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_fileio_write_read.py). + + Keyword arguments to pass to the underlying API calls. + For both uploads and downloads, the following arguments are + supported: + + - ``if_generation_match`` + - ``if_generation_not_match`` + - ``if_metageneration_match`` + - ``if_metageneration_not_match`` + - ``timeout`` + - ``retry`` + + For downloads only, the following additional arguments are supported: + + - ``raw_download`` + + For uploads only, the following additional arguments are supported: + + - ``content_type`` + - ``num_retries`` + - ``predefined_acl`` + - ``checksum`` + + .. note:: + + ``num_retries`` is supported for backwards-compatibility + reasons only; please use ``retry`` with a Retry object or + ConditionalRetryPolicy instead. + + :type mode: str + :param mode: + (Optional) A mode string, as per standard Python `open()` semantics.The first + character must be 'r', to open the blob for reading, or 'w' to open + it for writing. The second character, if present, must be 't' for + (unicode) text mode, or 'b' for bytes mode. If the second character + is omitted, text mode is the default. + + :type chunk_size: long + :param chunk_size: + (Optional) For reads, the minimum number of bytes to read at a time. + If fewer bytes than the chunk_size are requested, the remainder is + buffered. For writes, the maximum number of bytes to buffer before + sending data to the server, and the size of each request when data + is sent. Writes are implemented as a "resumable upload", so + chunk_size for writes must be exactly a multiple of 256KiB as with + other resumable uploads. The default is 40 MiB. + + :type ignore_flush: bool + :param ignore_flush: + (Optional) For non text-mode writes, makes flush() do nothing + instead of raising an error. flush() without closing is not + supported by the remote service and therefore calling it normally + results in io.UnsupportedOperation. However, that behavior is + incompatible with some consumers and wrappers of file objects in + Python, such as zipfile.ZipFile or io.TextIOWrapper. Setting + ignore_flush will cause flush() to successfully do nothing, for + compatibility with those contexts. The correct way to actually flush + data to the remote server is to close() (using a context manager, + such as in the example, will cause this to happen automatically). + + :type encoding: str + :param encoding: + (Optional) For text mode only, the name of the encoding that the stream will + be decoded or encoded with. If omitted, it defaults to + locale.getpreferredencoding(False). + + :type errors: str + :param errors: + (Optional) For text mode only, an optional string that specifies how encoding + and decoding errors are to be handled. Pass 'strict' to raise a + ValueError exception if there is an encoding error (the default of + None has the same effect), or pass 'ignore' to ignore errors. (Note + that ignoring encoding errors can lead to data loss.) Other more + rarely-used options are also available; see the Python 'io' module + documentation for 'io.TextIOWrapper' for a complete list. + + :type newline: str + :param newline: + (Optional) For text mode only, controls how line endings are handled. It can + be None, '', '\n', '\r', and '\r\n'. If None, reads use "universal + newline mode" and writes use the system default. See the Python + 'io' module documentation for 'io.TextIOWrapper' for details. + + :returns: A 'BlobReader' or 'BlobWriter' from + 'google.cloud.storage.fileio', or an 'io.TextIOWrapper' around one + of those classes, depending on the 'mode' argument. + """ + if mode == "rb": + if encoding or errors or newline: + raise ValueError( + "encoding, errors and newline arguments are for text mode only" + ) + if ignore_flush: + raise ValueError( + "ignore_flush argument is for non-text write mode only" + ) + return BlobReader(self, chunk_size=chunk_size, **kwargs) + elif mode == "wb": + if encoding or errors or newline: + raise ValueError( + "encoding, errors and newline arguments are for text mode only" + ) + return BlobWriter( + self, chunk_size=chunk_size, ignore_flush=ignore_flush, **kwargs + ) + elif mode in ("r", "rt"): + if ignore_flush: + raise ValueError( + "ignore_flush argument is for non-text write mode only" + ) + return TextIOWrapper( + BlobReader(self, chunk_size=chunk_size, **kwargs), + encoding=encoding, + errors=errors, + newline=newline, + ) + elif mode in ("w", "wt"): + if ignore_flush is False: + raise ValueError( + "ignore_flush is required for text mode writing and " + "cannot be set to False" + ) + return TextIOWrapper( + BlobWriter(self, chunk_size=chunk_size, ignore_flush=True, **kwargs), + encoding=encoding, + errors=errors, + newline=newline, + ) + else: + raise NotImplementedError( + "Supported modes strings are 'r', 'rb', 'rt', 'w', 'wb', and 'wt' only." + ) + + cache_control = _scalar_property("cacheControl") + """HTTP 'Cache-Control' header for this object. + + See [`RFC 7234`](https://tools.ietf.org/html/rfc7234#section-5.2) + and [`API reference docs`](https://cloud.google.com/storage/docs/json_api/v1/objects). + + :rtype: str or ``NoneType`` + + """ + + content_disposition = _scalar_property("contentDisposition") + """HTTP 'Content-Disposition' header for this object. + + See [`RFC 6266`](https://tools.ietf.org/html/rfc7234#section-5.2) and + [`API reference docs`](https://cloud.google.com/storage/docs/json_api/v1/objects). + + :rtype: str or ``NoneType`` + """ + + content_encoding = _scalar_property("contentEncoding") + """HTTP 'Content-Encoding' header for this object. + + See [`RFC 7231`](https://tools.ietf.org/html/rfc7231#section-3.1.2.2) and + [`API reference docs`](https://cloud.google.com/storage/docs/json_api/v1/objects). + + :rtype: str or ``NoneType`` + """ + + content_language = _scalar_property("contentLanguage") + """HTTP 'Content-Language' header for this object. + + See [`BCP47`](https://tools.ietf.org/html/bcp47) and + [`API reference docs`](https://cloud.google.com/storage/docs/json_api/v1/objects). + + :rtype: str or ``NoneType`` + """ + + content_type = _scalar_property(_CONTENT_TYPE_FIELD) + """HTTP 'Content-Type' header for this object. + + See [`RFC 2616`](https://tools.ietf.org/html/rfc2616#section-14.17) and + [`API reference docs`](https://cloud.google.com/storage/docs/json_api/v1/objects). + + :rtype: str or ``NoneType`` + """ + + crc32c = _scalar_property("crc32c") + """CRC32C checksum for this object. + + This returns the blob's CRC32C checksum. To retrieve the value, first use a + reload method of the Blob class which loads the blob's properties from the server. + + See [`RFC 4960`](https://tools.ietf.org/html/rfc4960#appendix-B) and + [`API reference docs`](https://cloud.google.com/storage/docs/json_api/v1/objects). + + If not set before upload, the server will compute the hash. + + :rtype: str or ``NoneType`` + """ + + @property + def component_count(self): + """Number of underlying components that make up this object. + + See https://cloud.google.com/storage/docs/json_api/v1/objects + + :rtype: int or ``NoneType`` + :returns: The component count (in case of a composed object) or + ``None`` if the blob's resource has not been loaded from + the server. This property will not be set on objects + not created via ``compose``. + """ + component_count = self._properties.get("componentCount") + if component_count is not None: + return int(component_count) + + @property + def etag(self): + """Retrieve the ETag for the object. + + See [`RFC 2616 (etags)`](https://tools.ietf.org/html/rfc2616#section-3.11) and + [`API reference docs`](https://cloud.google.com/storage/docs/json_api/v1/objects). + + :rtype: str or ``NoneType`` + :returns: The blob etag or ``None`` if the blob's resource has not + been loaded from the server. + """ + return self._properties.get("etag") + + event_based_hold = _scalar_property("eventBasedHold") + """Is an event-based hold active on the object? + + See [`API reference docs`](https://cloud.google.com/storage/docs/json_api/v1/objects). + + If the property is not set locally, returns :data:`None`. + + :rtype: bool or ``NoneType`` + """ + + @property + def generation(self): + """Retrieve the generation for the object. + + See https://cloud.google.com/storage/docs/json_api/v1/objects + + :rtype: int or ``NoneType`` + :returns: The generation of the blob or ``None`` if the blob's + resource has not been loaded from the server. + """ + generation = self._properties.get("generation") + if generation is not None: + return int(generation) + + @property + def id(self): + """Retrieve the ID for the object. + + See https://cloud.google.com/storage/docs/json_api/v1/objects + + The ID consists of the bucket name, object name, and generation number. + + :rtype: str or ``NoneType`` + :returns: The ID of the blob or ``None`` if the blob's + resource has not been loaded from the server. + """ + return self._properties.get("id") + + md5_hash = _scalar_property("md5Hash") + """MD5 hash for this object. + + This returns the blob's MD5 hash. To retrieve the value, first use a + reload method of the Blob class which loads the blob's properties from the server. + + See [`RFC 1321`](https://tools.ietf.org/html/rfc1321) and + [`API reference docs`](https://cloud.google.com/storage/docs/json_api/v1/objects). + + If not set before upload, the server will compute the hash. + + :rtype: str or ``NoneType`` + """ + + @property + def media_link(self): + """Retrieve the media download URI for the object. + + See https://cloud.google.com/storage/docs/json_api/v1/objects + + :rtype: str or ``NoneType`` + :returns: The media link for the blob or ``None`` if the blob's + resource has not been loaded from the server. + """ + return self._properties.get("mediaLink") + + @property + def metadata(self): + """Retrieve arbitrary/application specific metadata for the object. + + See https://cloud.google.com/storage/docs/json_api/v1/objects + + :setter: Update arbitrary/application specific metadata for the + object. + :getter: Retrieve arbitrary/application specific metadata for + the object. + + :rtype: dict or ``NoneType`` + :returns: The metadata associated with the blob or ``None`` if the + property is not set. + """ + return copy.deepcopy(self._properties.get("metadata")) + + @metadata.setter + def metadata(self, value): + """Update arbitrary/application specific metadata for the object. + + Values are stored to GCS as strings. To delete a key, set its value to + None and call blob.patch(). + + See https://cloud.google.com/storage/docs/json_api/v1/objects + + :type value: dict + :param value: The blob metadata to set. + """ + if value is not None: + value = {k: str(v) if v is not None else None for k, v in value.items()} + self._patch_property("metadata", value) + + @property + def metageneration(self): + """Retrieve the metageneration for the object. + + See https://cloud.google.com/storage/docs/json_api/v1/objects + + :rtype: int or ``NoneType`` + :returns: The metageneration of the blob or ``None`` if the blob's + resource has not been loaded from the server. + """ + metageneration = self._properties.get("metageneration") + if metageneration is not None: + return int(metageneration) + + @property + def owner(self): + """Retrieve info about the owner of the object. + + See https://cloud.google.com/storage/docs/json_api/v1/objects + + :rtype: dict or ``NoneType`` + :returns: Mapping of owner's role/ID, or ``None`` if the blob's + resource has not been loaded from the server. + """ + return copy.deepcopy(self._properties.get("owner")) + + @property + def retention_expiration_time(self): + """Retrieve timestamp at which the object's retention period expires. + + See https://cloud.google.com/storage/docs/json_api/v1/objects + + :rtype: :class:`datetime.datetime` or ``NoneType`` + :returns: Datetime object parsed from RFC3339 valid timestamp, or + ``None`` if the property is not set locally. + """ + value = self._properties.get("retentionExpirationTime") + if value is not None: + return _rfc3339_nanos_to_datetime(value) + + @property + def self_link(self): + """Retrieve the URI for the object. + + See https://cloud.google.com/storage/docs/json_api/v1/objects + + :rtype: str or ``NoneType`` + :returns: The self link for the blob or ``None`` if the blob's + resource has not been loaded from the server. + """ + return self._properties.get("selfLink") + + @property + def size(self): + """Size of the object, in bytes. + + See https://cloud.google.com/storage/docs/json_api/v1/objects + + :rtype: int or ``NoneType`` + :returns: The size of the blob or ``None`` if the blob's + resource has not been loaded from the server. + """ + size = self._properties.get("size") + if size is not None: + return int(size) + + @property + def kms_key_name(self): + """Resource name of Cloud KMS key used to encrypt the blob's contents. + + :rtype: str or ``NoneType`` + :returns: + The resource name or ``None`` if no Cloud KMS key was used, + or the blob's resource has not been loaded from the server. + """ + return self._properties.get("kmsKeyName") + + @kms_key_name.setter + def kms_key_name(self, value): + """Set KMS encryption key for object. + + :type value: str or ``NoneType`` + :param value: new KMS key name (None to clear any existing key). + """ + self._patch_property("kmsKeyName", value) + + storage_class = _scalar_property("storageClass") + """Retrieve the storage class for the object. + + This can only be set at blob / object **creation** time. If you'd + like to change the storage class **after** the blob / object already + exists in a bucket, call :meth:`update_storage_class` (which uses + :meth:`rewrite`). + + See https://cloud.google.com/storage/docs/storage-classes + + :rtype: str or ``NoneType`` + :returns: + If set, one of + :attr:`~google.cloud.storage.constants.STANDARD_STORAGE_CLASS`, + :attr:`~google.cloud.storage.constants.NEARLINE_STORAGE_CLASS`, + :attr:`~google.cloud.storage.constants.COLDLINE_STORAGE_CLASS`, + :attr:`~google.cloud.storage.constants.ARCHIVE_STORAGE_CLASS`, + :attr:`~google.cloud.storage.constants.MULTI_REGIONAL_LEGACY_STORAGE_CLASS`, + :attr:`~google.cloud.storage.constants.REGIONAL_LEGACY_STORAGE_CLASS`, + :attr:`~google.cloud.storage.constants.DURABLE_REDUCED_AVAILABILITY_STORAGE_CLASS`, + else ``None``. + """ + + temporary_hold = _scalar_property("temporaryHold") + """Is a temporary hold active on the object? + + See [`API reference docs`](https://cloud.google.com/storage/docs/json_api/v1/objects). + + If the property is not set locally, returns :data:`None`. + + :rtype: bool or ``NoneType`` + """ + + @property + def time_deleted(self): + """Retrieve the timestamp at which the object was deleted. + + See https://cloud.google.com/storage/docs/json_api/v1/objects + + :rtype: :class:`datetime.datetime` or ``NoneType`` + :returns: Datetime object parsed from RFC3339 valid timestamp, or + ``None`` if the blob's resource has not been loaded from + the server (see :meth:`reload`). If the blob has + not been deleted, this will never be set. + """ + value = self._properties.get("timeDeleted") + if value is not None: + return _rfc3339_nanos_to_datetime(value) + + @property + def time_created(self): + """Retrieve the timestamp at which the object was created. + + See https://cloud.google.com/storage/docs/json_api/v1/objects + + :rtype: :class:`datetime.datetime` or ``NoneType`` + :returns: Datetime object parsed from RFC3339 valid timestamp, or + ``None`` if the blob's resource has not been loaded from + the server (see :meth:`reload`). + """ + value = self._properties.get("timeCreated") + if value is not None: + return _rfc3339_nanos_to_datetime(value) + + @property + def updated(self): + """Retrieve the timestamp at which the object was updated. + + See https://cloud.google.com/storage/docs/json_api/v1/objects + + :rtype: :class:`datetime.datetime` or ``NoneType`` + :returns: Datetime object parsed from RFC3339 valid timestamp, or + ``None`` if the blob's resource has not been loaded from + the server (see :meth:`reload`). + """ + value = self._properties.get("updated") + if value is not None: + return _rfc3339_nanos_to_datetime(value) + + @property + def custom_time(self): + """Retrieve the custom time for the object. + + See https://cloud.google.com/storage/docs/json_api/v1/objects + + :rtype: :class:`datetime.datetime` or ``NoneType`` + :returns: Datetime object parsed from RFC3339 valid timestamp, or + ``None`` if the blob's resource has not been loaded from + the server (see :meth:`reload`). + """ + value = self._properties.get("customTime") + if value is not None: + return _rfc3339_nanos_to_datetime(value) + + @custom_time.setter + def custom_time(self, value): + """Set the custom time for the object. + + Once set on the server side object, this value can't be unset, but may + only changed to a custom datetime in the future. + + If :attr:`custom_time` must be unset, either perform a rewrite + operation or upload the data again. + + See https://cloud.google.com/storage/docs/json_api/v1/objects + + :type value: :class:`datetime.datetime` + :param value: new value + """ + if value is not None: + value = _datetime_to_rfc3339(value) + + self._patch_property("customTime", value) + + +def _get_host_name(connection): + """Returns the host name from the given connection. + + :type connection: :class:`~google.cloud.storage._http.Connection` + :param connection: The connection object. + + :rtype: str + :returns: The host name. + """ + # TODO: After google-cloud-core 1.6.0 is stable and we upgrade it + # to 1.6.0 in setup.py, we no longer need to check the attribute + # existence. We can simply return connection.get_api_base_url_for_mtls(). + return ( + connection.API_BASE_URL + if not hasattr(connection, "get_api_base_url_for_mtls") + else connection.get_api_base_url_for_mtls() + ) + + +def _get_encryption_headers(key, source=False): + """Builds customer encryption key headers + + :type key: bytes + :param key: 32 byte key to build request key and hash. + + :type source: bool + :param source: If true, return headers for the "source" blob; otherwise, + return headers for the "destination" blob. + + :rtype: dict + :returns: dict of HTTP headers being sent in request. + """ + if key is None: + return {} + + key = _to_bytes(key) + key_hash = hashlib.sha256(key).digest() + key_hash = base64.b64encode(key_hash) + key = base64.b64encode(key) + + if source: + prefix = "X-Goog-Copy-Source-Encryption-" + else: + prefix = "X-Goog-Encryption-" + + return { + prefix + "Algorithm": "AES256", + prefix + "Key": _bytes_to_unicode(key), + prefix + "Key-Sha256": _bytes_to_unicode(key_hash), + } + + +def _quote(value, safe=b"~"): + """URL-quote a string. + + If the value is unicode, this method first UTF-8 encodes it as bytes and + then quotes the bytes. (In Python 3, ``urllib.parse.quote`` does this + encoding automatically, but in Python 2, non-ASCII characters cannot be + quoted.) + + :type value: str or bytes + :param value: The value to be URL-quoted. + + :type safe: bytes + :param safe: Bytes *not* to be quoted. By default, includes only ``b'~'``. + + :rtype: str + :returns: The encoded value (bytes in Python 2, unicode in Python 3). + """ + value = _to_bytes(value, encoding="utf-8") + return quote(value, safe=safe) + + +def _maybe_rewind(stream, rewind=False): + """Rewind the stream if desired. + + :type stream: IO[bytes] + :param stream: A bytes IO object open for reading. + + :type rewind: bool + :param rewind: Indicates if we should seek to the beginning of the stream. + """ + if rewind: + stream.seek(0, os.SEEK_SET) + + +def _raise_from_invalid_response(error): + """Re-wrap and raise an ``InvalidResponse`` exception. + + :type error: :exc:`google.resumable_media.InvalidResponse` + :param error: A caught exception from the ``google-resumable-media`` + library. + + :raises: :class:`~google.cloud.exceptions.GoogleCloudError` corresponding + to the failed status code + """ + response = error.response + + # The 'response.text' gives the actual reason of error, where 'error' gives + # the message of expected status code. + if response.text: + error_message = response.text + ": " + str(error) + else: + error_message = str(error) + + message = f"{response.request.method} {response.request.url}: {error_message}" + + raise exceptions.from_http_status(response.status_code, message, response=response) + + +def _add_query_parameters(base_url, name_value_pairs): + """Add one query parameter to a base URL. + + :type base_url: string + :param base_url: Base URL (may already contain query parameters) + + :type name_value_pairs: list of (string, string) tuples. + :param name_value_pairs: Names and values of the query parameters to add + + :rtype: string + :returns: URL with additional query strings appended. + """ + if len(name_value_pairs) == 0: + return base_url + + scheme, netloc, path, query, frag = urlsplit(base_url) + query = parse_qsl(query) + query.extend(name_value_pairs) + return urlunsplit((scheme, netloc, path, urlencode(query), frag)) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/bucket.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/bucket.py new file mode 100644 index 000000000000..0a7b09bbb9c9 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/bucket.py @@ -0,0 +1,3309 @@ +# Copyright 2014 Google LLC +# +# 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. + +"""Create / interact with Google Cloud Storage buckets.""" + +import base64 +import copy +import datetime +import json +from urllib.parse import urlsplit +import warnings + +from google.api_core import datetime_helpers +from google.cloud._helpers import _datetime_to_rfc3339 +from google.cloud._helpers import _NOW +from google.cloud._helpers import _rfc3339_nanos_to_datetime +from google.cloud.exceptions import NotFound +from google.api_core.iam import Policy +from google.cloud.storage import _signing +from google.cloud.storage._helpers import _add_etag_match_headers +from google.cloud.storage._helpers import _add_generation_match_parameters +from google.cloud.storage._helpers import _PropertyMixin +from google.cloud.storage._helpers import _scalar_property +from google.cloud.storage._helpers import _validate_name +from google.cloud.storage._signing import generate_signed_url_v2 +from google.cloud.storage._signing import generate_signed_url_v4 +from google.cloud.storage._helpers import _bucket_bound_hostname_url +from google.cloud.storage.acl import BucketACL +from google.cloud.storage.acl import DefaultObjectACL +from google.cloud.storage.blob import Blob +from google.cloud.storage.constants import _DEFAULT_TIMEOUT +from google.cloud.storage.constants import ARCHIVE_STORAGE_CLASS +from google.cloud.storage.constants import COLDLINE_STORAGE_CLASS +from google.cloud.storage.constants import DUAL_REGION_LOCATION_TYPE +from google.cloud.storage.constants import ( + DURABLE_REDUCED_AVAILABILITY_LEGACY_STORAGE_CLASS, +) +from google.cloud.storage.constants import MULTI_REGIONAL_LEGACY_STORAGE_CLASS +from google.cloud.storage.constants import MULTI_REGION_LOCATION_TYPE +from google.cloud.storage.constants import NEARLINE_STORAGE_CLASS +from google.cloud.storage.constants import PUBLIC_ACCESS_PREVENTION_INHERITED +from google.cloud.storage.constants import REGIONAL_LEGACY_STORAGE_CLASS +from google.cloud.storage.constants import REGION_LOCATION_TYPE +from google.cloud.storage.constants import STANDARD_STORAGE_CLASS +from google.cloud.storage.notification import BucketNotification +from google.cloud.storage.notification import NONE_PAYLOAD_FORMAT +from google.cloud.storage.retry import DEFAULT_RETRY +from google.cloud.storage.retry import DEFAULT_RETRY_IF_GENERATION_SPECIFIED +from google.cloud.storage.retry import DEFAULT_RETRY_IF_ETAG_IN_JSON +from google.cloud.storage.retry import DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED + + +_UBLA_BPO_ENABLED_MESSAGE = ( + "Pass only one of 'uniform_bucket_level_access_enabled' / " + "'bucket_policy_only_enabled' to 'IAMConfiguration'." +) +_BPO_ENABLED_MESSAGE = ( + "'IAMConfiguration.bucket_policy_only_enabled' is deprecated. " + "Instead, use 'IAMConfiguration.uniform_bucket_level_access_enabled'." +) +_UBLA_BPO_LOCK_TIME_MESSAGE = ( + "Pass only one of 'uniform_bucket_level_access_lock_time' / " + "'bucket_policy_only_lock_time' to 'IAMConfiguration'." +) +_BPO_LOCK_TIME_MESSAGE = ( + "'IAMConfiguration.bucket_policy_only_lock_time' is deprecated. " + "Instead, use 'IAMConfiguration.uniform_bucket_level_access_lock_time'." +) +_LOCATION_SETTER_MESSAGE = ( + "Assignment to 'Bucket.location' is deprecated, as it is only " + "valid before the bucket is created. Instead, pass the location " + "to `Bucket.create`." +) +_API_ACCESS_ENDPOINT = "https://storage.googleapis.com" + + +def _blobs_page_start(iterator, page, response): + """Grab prefixes after a :class:`~google.cloud.iterator.Page` started. + + :type iterator: :class:`~google.api_core.page_iterator.Iterator` + :param iterator: The iterator that is currently in use. + + :type page: :class:`~google.cloud.api.core.page_iterator.Page` + :param page: The page that was just created. + + :type response: dict + :param response: The JSON API response for a page of blobs. + """ + page.prefixes = tuple(response.get("prefixes", ())) + iterator.prefixes.update(page.prefixes) + + +def _item_to_blob(iterator, item): + """Convert a JSON blob to the native object. + + .. note:: + + This assumes that the ``bucket`` attribute has been + added to the iterator after being created. + + :type iterator: :class:`~google.api_core.page_iterator.Iterator` + :param iterator: The iterator that has retrieved the item. + + :type item: dict + :param item: An item to be converted to a blob. + + :rtype: :class:`.Blob` + :returns: The next blob in the page. + """ + name = item.get("name") + blob = Blob(name, bucket=iterator.bucket) + blob._set_properties(item) + return blob + + +def _item_to_notification(iterator, item): + """Convert a JSON blob to the native object. + + .. note:: + + This assumes that the ``bucket`` attribute has been + added to the iterator after being created. + + :type iterator: :class:`~google.api_core.page_iterator.Iterator` + :param iterator: The iterator that has retrieved the item. + + :type item: dict + :param item: An item to be converted to a blob. + + :rtype: :class:`.BucketNotification` + :returns: The next notification being iterated. + """ + return BucketNotification.from_api_repr(item, bucket=iterator.bucket) + + +class LifecycleRuleConditions(dict): + """Map a single lifecycle rule for a bucket. + + See: https://cloud.google.com/storage/docs/lifecycle + + :type age: int + :param age: (Optional) Apply rule action to items whose age, in days, + exceeds this value. + + :type created_before: datetime.date + :param created_before: (Optional) Apply rule action to items created + before this date. + + :type is_live: bool + :param is_live: (Optional) If true, apply rule action to non-versioned + items, or to items with no newer versions. If false, apply + rule action to versioned items with at least one newer + version. + + :type matches_prefix: list(str) + :param matches_prefix: (Optional) Apply rule action to items which + any prefix matches the beginning of the item name. + + :type matches_storage_class: list(str), one or more of + :attr:`Bucket.STORAGE_CLASSES`. + :param matches_storage_class: (Optional) Apply rule action to items + whose storage class matches this value. + + :type matches_suffix: list(str) + :param matches_suffix: (Optional) Apply rule action to items which + any suffix matches the end of the item name. + + :type number_of_newer_versions: int + :param number_of_newer_versions: (Optional) Apply rule action to versioned + items having N newer versions. + + :type days_since_custom_time: int + :param days_since_custom_time: (Optional) Apply rule action to items whose number of days + elapsed since the custom timestamp. This condition is relevant + only for versioned objects. The value of the field must be a non + negative integer. If it's zero, the object version will become + eligible for lifecycle action as soon as it becomes custom. + + :type custom_time_before: :class:`datetime.date` + :param custom_time_before: (Optional) Date object parsed from RFC3339 valid date, apply rule action + to items whose custom time is before this date. This condition is relevant + only for versioned objects, e.g., 2019-03-16. + + :type days_since_noncurrent_time: int + :param days_since_noncurrent_time: (Optional) Apply rule action to items whose number of days + elapsed since the non current timestamp. This condition + is relevant only for versioned objects. The value of the field + must be a non negative integer. If it's zero, the object version + will become eligible for lifecycle action as soon as it becomes + non current. + + :type noncurrent_time_before: :class:`datetime.date` + :param noncurrent_time_before: (Optional) Date object parsed from RFC3339 valid date, apply + rule action to items whose non current time is before this date. + This condition is relevant only for versioned objects, e.g, 2019-03-16. + + :raises ValueError: if no arguments are passed. + """ + + def __init__( + self, + age=None, + created_before=None, + is_live=None, + matches_storage_class=None, + number_of_newer_versions=None, + days_since_custom_time=None, + custom_time_before=None, + days_since_noncurrent_time=None, + noncurrent_time_before=None, + matches_prefix=None, + matches_suffix=None, + _factory=False, + ): + conditions = {} + + if age is not None: + conditions["age"] = age + + if created_before is not None: + conditions["createdBefore"] = created_before.isoformat() + + if is_live is not None: + conditions["isLive"] = is_live + + if matches_storage_class is not None: + conditions["matchesStorageClass"] = matches_storage_class + + if number_of_newer_versions is not None: + conditions["numNewerVersions"] = number_of_newer_versions + + if days_since_custom_time is not None: + conditions["daysSinceCustomTime"] = days_since_custom_time + + if custom_time_before is not None: + conditions["customTimeBefore"] = custom_time_before.isoformat() + + if days_since_noncurrent_time is not None: + conditions["daysSinceNoncurrentTime"] = days_since_noncurrent_time + + if noncurrent_time_before is not None: + conditions["noncurrentTimeBefore"] = noncurrent_time_before.isoformat() + + if matches_prefix is not None: + conditions["matchesPrefix"] = matches_prefix + + if matches_suffix is not None: + conditions["matchesSuffix"] = matches_suffix + + if not _factory and not conditions: + raise ValueError("Supply at least one condition") + + super(LifecycleRuleConditions, self).__init__(conditions) + + @classmethod + def from_api_repr(cls, resource): + """Factory: construct instance from resource. + + :type resource: dict + :param resource: mapping as returned from API call. + + :rtype: :class:`LifecycleRuleConditions` + :returns: Instance created from resource. + """ + instance = cls(_factory=True) + instance.update(resource) + return instance + + @property + def age(self): + """Conditon's age value.""" + return self.get("age") + + @property + def created_before(self): + """Conditon's created_before value.""" + before = self.get("createdBefore") + if before is not None: + return datetime_helpers.from_iso8601_date(before) + + @property + def is_live(self): + """Conditon's 'is_live' value.""" + return self.get("isLive") + + @property + def matches_prefix(self): + """Conditon's 'matches_prefix' value.""" + return self.get("matchesPrefix") + + @property + def matches_storage_class(self): + """Conditon's 'matches_storage_class' value.""" + return self.get("matchesStorageClass") + + @property + def matches_suffix(self): + """Conditon's 'matches_suffix' value.""" + return self.get("matchesSuffix") + + @property + def number_of_newer_versions(self): + """Conditon's 'number_of_newer_versions' value.""" + return self.get("numNewerVersions") + + @property + def days_since_custom_time(self): + """Conditon's 'days_since_custom_time' value.""" + return self.get("daysSinceCustomTime") + + @property + def custom_time_before(self): + """Conditon's 'custom_time_before' value.""" + before = self.get("customTimeBefore") + if before is not None: + return datetime_helpers.from_iso8601_date(before) + + @property + def days_since_noncurrent_time(self): + """Conditon's 'days_since_noncurrent_time' value.""" + return self.get("daysSinceNoncurrentTime") + + @property + def noncurrent_time_before(self): + """Conditon's 'noncurrent_time_before' value.""" + before = self.get("noncurrentTimeBefore") + if before is not None: + return datetime_helpers.from_iso8601_date(before) + + +class LifecycleRuleDelete(dict): + """Map a lifecycle rule deleting matching items. + + :type kw: dict + :params kw: arguments passed to :class:`LifecycleRuleConditions`. + """ + + def __init__(self, **kw): + conditions = LifecycleRuleConditions(**kw) + rule = {"action": {"type": "Delete"}, "condition": dict(conditions)} + super().__init__(rule) + + @classmethod + def from_api_repr(cls, resource): + """Factory: construct instance from resource. + + :type resource: dict + :param resource: mapping as returned from API call. + + :rtype: :class:`LifecycleRuleDelete` + :returns: Instance created from resource. + """ + instance = cls(_factory=True) + instance.update(resource) + return instance + + +class LifecycleRuleSetStorageClass(dict): + """Map a lifecycle rule updating storage class of matching items. + + :type storage_class: str, one of :attr:`Bucket.STORAGE_CLASSES`. + :param storage_class: new storage class to assign to matching items. + + :type kw: dict + :params kw: arguments passed to :class:`LifecycleRuleConditions`. + """ + + def __init__(self, storage_class, **kw): + conditions = LifecycleRuleConditions(**kw) + rule = { + "action": {"type": "SetStorageClass", "storageClass": storage_class}, + "condition": dict(conditions), + } + super().__init__(rule) + + @classmethod + def from_api_repr(cls, resource): + """Factory: construct instance from resource. + + :type resource: dict + :param resource: mapping as returned from API call. + + :rtype: :class:`LifecycleRuleSetStorageClass` + :returns: Instance created from resource. + """ + action = resource["action"] + instance = cls(action["storageClass"], _factory=True) + instance.update(resource) + return instance + + +class LifecycleRuleAbortIncompleteMultipartUpload(dict): + """Map a rule aborting incomplete multipart uploads of matching items. + + The "age" lifecycle condition is the only supported condition for this rule. + + :type kw: dict + :params kw: arguments passed to :class:`LifecycleRuleConditions`. + """ + + def __init__(self, **kw): + conditions = LifecycleRuleConditions(**kw) + rule = { + "action": {"type": "AbortIncompleteMultipartUpload"}, + "condition": dict(conditions), + } + super().__init__(rule) + + @classmethod + def from_api_repr(cls, resource): + """Factory: construct instance from resource. + + :type resource: dict + :param resource: mapping as returned from API call. + + :rtype: :class:`LifecycleRuleAbortIncompleteMultipartUpload` + :returns: Instance created from resource. + """ + instance = cls(_factory=True) + instance.update(resource) + return instance + + +_default = object() + + +class IAMConfiguration(dict): + """Map a bucket's IAM configuration. + + :type bucket: :class:`Bucket` + :params bucket: Bucket for which this instance is the policy. + + :type public_access_prevention: str + :params public_access_prevention: + (Optional) Whether the public access prevention policy is 'inherited' (default) or 'enforced' + See: https://cloud.google.com/storage/docs/public-access-prevention + + :type uniform_bucket_level_access_enabled: bool + :params bucket_policy_only_enabled: + (Optional) Whether the IAM-only policy is enabled for the bucket. + + :type uniform_bucket_level_access_locked_time: :class:`datetime.datetime` + :params uniform_bucket_level_locked_time: + (Optional) When the bucket's IAM-only policy was enabled. + This value should normally only be set by the back-end API. + + :type bucket_policy_only_enabled: bool + :params bucket_policy_only_enabled: + Deprecated alias for :data:`uniform_bucket_level_access_enabled`. + + :type bucket_policy_only_locked_time: :class:`datetime.datetime` + :params bucket_policy_only_locked_time: + Deprecated alias for :data:`uniform_bucket_level_access_locked_time`. + """ + + def __init__( + self, + bucket, + public_access_prevention=_default, + uniform_bucket_level_access_enabled=_default, + uniform_bucket_level_access_locked_time=_default, + bucket_policy_only_enabled=_default, + bucket_policy_only_locked_time=_default, + ): + if bucket_policy_only_enabled is not _default: + + if uniform_bucket_level_access_enabled is not _default: + raise ValueError(_UBLA_BPO_ENABLED_MESSAGE) + + warnings.warn(_BPO_ENABLED_MESSAGE, DeprecationWarning, stacklevel=2) + uniform_bucket_level_access_enabled = bucket_policy_only_enabled + + if bucket_policy_only_locked_time is not _default: + + if uniform_bucket_level_access_locked_time is not _default: + raise ValueError(_UBLA_BPO_LOCK_TIME_MESSAGE) + + warnings.warn(_BPO_LOCK_TIME_MESSAGE, DeprecationWarning, stacklevel=2) + uniform_bucket_level_access_locked_time = bucket_policy_only_locked_time + + if uniform_bucket_level_access_enabled is _default: + uniform_bucket_level_access_enabled = False + + if public_access_prevention is _default: + public_access_prevention = PUBLIC_ACCESS_PREVENTION_INHERITED + + data = { + "uniformBucketLevelAccess": { + "enabled": uniform_bucket_level_access_enabled + }, + "publicAccessPrevention": public_access_prevention, + } + if uniform_bucket_level_access_locked_time is not _default: + data["uniformBucketLevelAccess"]["lockedTime"] = _datetime_to_rfc3339( + uniform_bucket_level_access_locked_time + ) + super(IAMConfiguration, self).__init__(data) + self._bucket = bucket + + @classmethod + def from_api_repr(cls, resource, bucket): + """Factory: construct instance from resource. + + :type bucket: :class:`Bucket` + :params bucket: Bucket for which this instance is the policy. + + :type resource: dict + :param resource: mapping as returned from API call. + + :rtype: :class:`IAMConfiguration` + :returns: Instance created from resource. + """ + instance = cls(bucket) + instance.update(resource) + return instance + + @property + def bucket(self): + """Bucket for which this instance is the policy. + + :rtype: :class:`Bucket` + :returns: the instance's bucket. + """ + return self._bucket + + @property + def public_access_prevention(self): + """Setting for public access prevention policy. Options are 'inherited' (default) or 'enforced'. + + See: https://cloud.google.com/storage/docs/public-access-prevention + + :rtype: string + :returns: the public access prevention status, either 'enforced' or 'inherited'. + """ + return self["publicAccessPrevention"] + + @public_access_prevention.setter + def public_access_prevention(self, value): + self["publicAccessPrevention"] = value + self.bucket._patch_property("iamConfiguration", self) + + @property + def uniform_bucket_level_access_enabled(self): + """If set, access checks only use bucket-level IAM policies or above. + + :rtype: bool + :returns: whether the bucket is configured to allow only IAM. + """ + ubla = self.get("uniformBucketLevelAccess", {}) + return ubla.get("enabled", False) + + @uniform_bucket_level_access_enabled.setter + def uniform_bucket_level_access_enabled(self, value): + ubla = self.setdefault("uniformBucketLevelAccess", {}) + ubla["enabled"] = bool(value) + self.bucket._patch_property("iamConfiguration", self) + + @property + def uniform_bucket_level_access_locked_time(self): + """Deadline for changing :attr:`uniform_bucket_level_access_enabled` from true to false. + + If the bucket's :attr:`uniform_bucket_level_access_enabled` is true, this property + is time time after which that setting becomes immutable. + + If the bucket's :attr:`uniform_bucket_level_access_enabled` is false, this property + is ``None``. + + :rtype: Union[:class:`datetime.datetime`, None] + :returns: (readonly) Time after which :attr:`uniform_bucket_level_access_enabled` will + be frozen as true. + """ + ubla = self.get("uniformBucketLevelAccess", {}) + stamp = ubla.get("lockedTime") + if stamp is not None: + stamp = _rfc3339_nanos_to_datetime(stamp) + return stamp + + @property + def bucket_policy_only_enabled(self): + """Deprecated alias for :attr:`uniform_bucket_level_access_enabled`. + + :rtype: bool + :returns: whether the bucket is configured to allow only IAM. + """ + return self.uniform_bucket_level_access_enabled + + @bucket_policy_only_enabled.setter + def bucket_policy_only_enabled(self, value): + warnings.warn(_BPO_ENABLED_MESSAGE, DeprecationWarning, stacklevel=2) + self.uniform_bucket_level_access_enabled = value + + @property + def bucket_policy_only_locked_time(self): + """Deprecated alias for :attr:`uniform_bucket_level_access_locked_time`. + + :rtype: Union[:class:`datetime.datetime`, None] + :returns: + (readonly) Time after which :attr:`bucket_policy_only_enabled` will + be frozen as true. + """ + return self.uniform_bucket_level_access_locked_time + + +class Bucket(_PropertyMixin): + """A class representing a Bucket on Cloud Storage. + + :type client: :class:`google.cloud.storage.client.Client` + :param client: A client which holds credentials and project configuration + for the bucket (which requires a project). + + :type name: str + :param name: The name of the bucket. Bucket names must start and end with a + number or letter. + + :type user_project: str + :param user_project: (Optional) the project ID to be billed for API + requests made via this instance. + """ + + _MAX_OBJECTS_FOR_ITERATION = 256 + """Maximum number of existing objects allowed in iteration. + + This is used in Bucket.delete() and Bucket.make_public(). + """ + + STORAGE_CLASSES = ( + STANDARD_STORAGE_CLASS, + NEARLINE_STORAGE_CLASS, + COLDLINE_STORAGE_CLASS, + ARCHIVE_STORAGE_CLASS, + MULTI_REGIONAL_LEGACY_STORAGE_CLASS, # legacy + REGIONAL_LEGACY_STORAGE_CLASS, # legacy + DURABLE_REDUCED_AVAILABILITY_LEGACY_STORAGE_CLASS, # legacy + ) + """Allowed values for :attr:`storage_class`. + + Default value is :attr:`STANDARD_STORAGE_CLASS`. + + See + https://cloud.google.com/storage/docs/json_api/v1/buckets#storageClass + https://cloud.google.com/storage/docs/storage-classes + """ + + _LOCATION_TYPES = ( + MULTI_REGION_LOCATION_TYPE, + REGION_LOCATION_TYPE, + DUAL_REGION_LOCATION_TYPE, + ) + """Allowed values for :attr:`location_type`.""" + + def __init__(self, client, name=None, user_project=None): + """ + property :attr:`name` + Get the bucket's name. + """ + name = _validate_name(name) + super(Bucket, self).__init__(name=name) + self._client = client + self._acl = BucketACL(self) + self._default_object_acl = DefaultObjectACL(self) + self._label_removals = set() + self._user_project = user_project + + def __repr__(self): + return f"" + + @property + def client(self): + """The client bound to this bucket.""" + return self._client + + def _set_properties(self, value): + """Set the properties for the current object. + + :type value: dict or :class:`google.cloud.storage.batch._FutureDict` + :param value: The properties to be set. + """ + self._label_removals.clear() + return super(Bucket, self)._set_properties(value) + + @property + def rpo(self): + """Get the RPO (Recovery Point Objective) of this bucket + + See: https://cloud.google.com/storage/docs/managing-turbo-replication + + "ASYNC_TURBO" or "DEFAULT" + :rtype: str + """ + return self._properties.get("rpo") + + @rpo.setter + def rpo(self, value): + """ + Set the RPO (Recovery Point Objective) of this bucket. + + See: https://cloud.google.com/storage/docs/managing-turbo-replication + + :type value: str + :param value: "ASYNC_TURBO" or "DEFAULT" + """ + self._patch_property("rpo", value) + + @property + def user_project(self): + """Project ID to be billed for API requests made via this bucket. + + If unset, API requests are billed to the bucket owner. + + A user project is required for all operations on Requester Pays buckets. + + See https://cloud.google.com/storage/docs/requester-pays#requirements for details. + + :rtype: str + """ + return self._user_project + + @classmethod + def from_string(cls, uri, client=None): + """Get a constructor for bucket object by URI. + + .. code-block:: python + + from google.cloud import storage + from google.cloud.storage.bucket import Bucket + client = storage.Client() + bucket = Bucket.from_string("gs://bucket", client=client) + + :type uri: str + :param uri: The bucket uri pass to get bucket object. + + :type client: :class:`~google.cloud.storage.client.Client` or + ``NoneType`` + :param client: (Optional) The client to use. Application code should + *always* pass ``client``. + + :rtype: :class:`google.cloud.storage.bucket.Bucket` + :returns: The bucket object created. + """ + scheme, netloc, path, query, frag = urlsplit(uri) + + if scheme != "gs": + raise ValueError("URI scheme must be gs") + + return cls(client, name=netloc) + + def blob( + self, + blob_name, + chunk_size=None, + encryption_key=None, + kms_key_name=None, + generation=None, + ): + """Factory constructor for blob object. + + .. note:: + This will not make an HTTP request; it simply instantiates + a blob object owned by this bucket. + + :type blob_name: str + :param blob_name: The name of the blob to be instantiated. + + :type chunk_size: int + :param chunk_size: The size of a chunk of data whenever iterating + (in bytes). This must be a multiple of 256 KB per + the API specification. + + :type encryption_key: bytes + :param encryption_key: + (Optional) 32 byte encryption key for customer-supplied encryption. + + :type kms_key_name: str + :param kms_key_name: + (Optional) Resource name of KMS key used to encrypt blob's content. + + :type generation: long + :param generation: (Optional) If present, selects a specific revision of + this object. + + :rtype: :class:`google.cloud.storage.blob.Blob` + :returns: The blob object created. + """ + return Blob( + name=blob_name, + bucket=self, + chunk_size=chunk_size, + encryption_key=encryption_key, + kms_key_name=kms_key_name, + generation=generation, + ) + + def notification( + self, + topic_name=None, + topic_project=None, + custom_attributes=None, + event_types=None, + blob_name_prefix=None, + payload_format=NONE_PAYLOAD_FORMAT, + notification_id=None, + ): + """Factory: create a notification resource for the bucket. + + See: :class:`.BucketNotification` for parameters. + + :rtype: :class:`.BucketNotification` + """ + return BucketNotification( + self, + topic_name=topic_name, + topic_project=topic_project, + custom_attributes=custom_attributes, + event_types=event_types, + blob_name_prefix=blob_name_prefix, + payload_format=payload_format, + notification_id=notification_id, + ) + + def exists( + self, + client=None, + timeout=_DEFAULT_TIMEOUT, + if_etag_match=None, + if_etag_not_match=None, + if_metageneration_match=None, + if_metageneration_not_match=None, + retry=DEFAULT_RETRY, + ): + """Determines whether or not this bucket exists. + + If :attr:`user_project` is set, bills the API request to that project. + + :type client: :class:`~google.cloud.storage.client.Client` or + ``NoneType`` + :param client: (Optional) The client to use. If not passed, falls back + to the ``client`` stored on the current bucket. + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type if_etag_match: Union[str, Set[str]] + :param if_etag_match: (Optional) Make the operation conditional on whether the + bucket's current ETag matches the given value. + + :type if_etag_not_match: Union[str, Set[str]]) + :param if_etag_not_match: (Optional) Make the operation conditional on whether the + bucket's current ETag does not match the given value. + + :type if_metageneration_match: long + :param if_metageneration_match: (Optional) Make the operation conditional on whether the + bucket's current metageneration matches the given value. + + :type if_metageneration_not_match: long + :param if_metageneration_not_match: (Optional) Make the operation conditional on whether the + bucket's current metageneration does not match the given value. + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + + :rtype: bool + :returns: True if the bucket exists in Cloud Storage. + """ + client = self._require_client(client) + # We only need the status code (200 or not) so we seek to + # minimize the returned payload. + query_params = {"fields": "name"} + + if self.user_project is not None: + query_params["userProject"] = self.user_project + + _add_generation_match_parameters( + query_params, + if_metageneration_match=if_metageneration_match, + if_metageneration_not_match=if_metageneration_not_match, + ) + + headers = {} + _add_etag_match_headers( + headers, if_etag_match=if_etag_match, if_etag_not_match=if_etag_not_match + ) + + try: + # We intentionally pass `_target_object=None` since fields=name + # would limit the local properties. + client._get_resource( + self.path, + query_params=query_params, + headers=headers, + timeout=timeout, + retry=retry, + _target_object=None, + ) + except NotFound: + # NOTE: This will not fail immediately in a batch. However, when + # Batch.finish() is called, the resulting `NotFound` will be + # raised. + return False + return True + + def create( + self, + client=None, + project=None, + location=None, + predefined_acl=None, + predefined_default_object_acl=None, + timeout=_DEFAULT_TIMEOUT, + retry=DEFAULT_RETRY, + ): + """DEPRECATED. Creates current bucket. + + .. note:: + Direct use of this method is deprecated. Use ``Client.create_bucket()`` instead. + + If the bucket already exists, will raise + :class:`google.cloud.exceptions.Conflict`. + + This implements "storage.buckets.insert". + + If :attr:`user_project` is set, bills the API request to that project. + + :type client: :class:`~google.cloud.storage.client.Client` or + ``NoneType`` + :param client: (Optional) The client to use. If not passed, falls back + to the ``client`` stored on the current bucket. + + :type project: str + :param project: (Optional) The project under which the bucket is to + be created. If not passed, uses the project set on + the client. + :raises ValueError: if ``project`` is None and client's + :attr:`project` is also None. + + :type location: str + :param location: (Optional) The location of the bucket. If not passed, + the default location, US, will be used. See + https://cloud.google.com/storage/docs/bucket-locations + + :type predefined_acl: str + :param predefined_acl: + (Optional) Name of predefined ACL to apply to bucket. See: + https://cloud.google.com/storage/docs/access-control/lists#predefined-acl + + :type predefined_default_object_acl: str + :param predefined_default_object_acl: + (Optional) Name of predefined ACL to apply to bucket's objects. See: + https://cloud.google.com/storage/docs/access-control/lists#predefined-acl + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + """ + warnings.warn( + "Bucket.create() is deprecated and will be removed in future." + "Use Client.create_bucket() instead.", + PendingDeprecationWarning, + stacklevel=1, + ) + + client = self._require_client(client) + client.create_bucket( + bucket_or_name=self, + project=project, + user_project=self.user_project, + location=location, + predefined_acl=predefined_acl, + predefined_default_object_acl=predefined_default_object_acl, + timeout=timeout, + retry=retry, + ) + + def update( + self, + client=None, + timeout=_DEFAULT_TIMEOUT, + if_metageneration_match=None, + if_metageneration_not_match=None, + retry=DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED, + ): + """Sends all properties in a PUT request. + + Updates the ``_properties`` with the response from the backend. + + If :attr:`user_project` is set, bills the API request to that project. + + :type client: :class:`~google.cloud.storage.client.Client` or + ``NoneType`` + :param client: the client to use. If not passed, falls back to the + ``client`` stored on the current object. + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type if_metageneration_match: long + :param if_metageneration_match: (Optional) Make the operation conditional on whether the + blob's current metageneration matches the given value. + + :type if_metageneration_not_match: long + :param if_metageneration_not_match: (Optional) Make the operation conditional on whether the + blob's current metageneration does not match the given value. + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + """ + super(Bucket, self).update( + client=client, + timeout=timeout, + if_metageneration_match=if_metageneration_match, + if_metageneration_not_match=if_metageneration_not_match, + retry=retry, + ) + + def reload( + self, + client=None, + projection="noAcl", + timeout=_DEFAULT_TIMEOUT, + if_etag_match=None, + if_etag_not_match=None, + if_metageneration_match=None, + if_metageneration_not_match=None, + retry=DEFAULT_RETRY, + ): + """Reload properties from Cloud Storage. + + If :attr:`user_project` is set, bills the API request to that project. + + :type client: :class:`~google.cloud.storage.client.Client` or + ``NoneType`` + :param client: the client to use. If not passed, falls back to the + ``client`` stored on the current object. + + :type projection: str + :param projection: (Optional) If used, must be 'full' or 'noAcl'. + Defaults to ``'noAcl'``. Specifies the set of + properties to return. + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type if_etag_match: Union[str, Set[str]] + :param if_etag_match: (Optional) Make the operation conditional on whether the + bucket's current ETag matches the given value. + + :type if_etag_not_match: Union[str, Set[str]]) + :param if_etag_not_match: (Optional) Make the operation conditional on whether the + bucket's current ETag does not match the given value. + + :type if_metageneration_match: long + :param if_metageneration_match: (Optional) Make the operation conditional on whether the + bucket's current metageneration matches the given value. + + :type if_metageneration_not_match: long + :param if_metageneration_not_match: (Optional) Make the operation conditional on whether the + bucket's current metageneration does not match the given value. + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + """ + super(Bucket, self).reload( + client=client, + projection=projection, + timeout=timeout, + if_etag_match=if_etag_match, + if_etag_not_match=if_etag_not_match, + if_metageneration_match=if_metageneration_match, + if_metageneration_not_match=if_metageneration_not_match, + retry=retry, + ) + + def patch( + self, + client=None, + timeout=_DEFAULT_TIMEOUT, + if_metageneration_match=None, + if_metageneration_not_match=None, + retry=DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED, + ): + """Sends all changed properties in a PATCH request. + + Updates the ``_properties`` with the response from the backend. + + If :attr:`user_project` is set, bills the API request to that project. + + :type client: :class:`~google.cloud.storage.client.Client` or + ``NoneType`` + :param client: the client to use. If not passed, falls back to the + ``client`` stored on the current object. + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type if_metageneration_match: long + :param if_metageneration_match: (Optional) Make the operation conditional on whether the + blob's current metageneration matches the given value. + + :type if_metageneration_not_match: long + :param if_metageneration_not_match: (Optional) Make the operation conditional on whether the + blob's current metageneration does not match the given value. + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + """ + # Special case: For buckets, it is possible that labels are being + # removed; this requires special handling. + if self._label_removals: + self._changes.add("labels") + self._properties.setdefault("labels", {}) + for removed_label in self._label_removals: + self._properties["labels"][removed_label] = None + + # Call the superclass method. + super(Bucket, self).patch( + client=client, + if_metageneration_match=if_metageneration_match, + if_metageneration_not_match=if_metageneration_not_match, + timeout=timeout, + retry=retry, + ) + + @property + def acl(self): + """Create our ACL on demand.""" + return self._acl + + @property + def default_object_acl(self): + """Create our defaultObjectACL on demand.""" + return self._default_object_acl + + @staticmethod + def path_helper(bucket_name): + """Relative URL path for a bucket. + + :type bucket_name: str + :param bucket_name: The bucket name in the path. + + :rtype: str + :returns: The relative URL path for ``bucket_name``. + """ + return "/b/" + bucket_name + + @property + def path(self): + """The URL path to this bucket.""" + if not self.name: + raise ValueError("Cannot determine path without bucket name.") + + return self.path_helper(self.name) + + def get_blob( + self, + blob_name, + client=None, + encryption_key=None, + generation=None, + if_etag_match=None, + if_etag_not_match=None, + if_generation_match=None, + if_generation_not_match=None, + if_metageneration_match=None, + if_metageneration_not_match=None, + timeout=_DEFAULT_TIMEOUT, + retry=DEFAULT_RETRY, + **kwargs, + ): + """Get a blob object by name. + + See a [code sample](https://cloud.google.com/storage/docs/samples/storage-get-metadata#storage_get_metadata-python) + on how to retrieve metadata of an object. + + If :attr:`user_project` is set, bills the API request to that project. + + :type blob_name: str + :param blob_name: The name of the blob to retrieve. + + :type client: :class:`~google.cloud.storage.client.Client` or + ``NoneType`` + :param client: (Optional) The client to use. If not passed, falls back + to the ``client`` stored on the current bucket. + + :type encryption_key: bytes + :param encryption_key: + (Optional) 32 byte encryption key for customer-supplied encryption. + See + https://cloud.google.com/storage/docs/encryption#customer-supplied. + + :type generation: long + :param generation: + (Optional) If present, selects a specific revision of this object. + + :type if_etag_match: Union[str, Set[str]] + :param if_etag_match: + (Optional) See :ref:`using-if-etag-match` + + :type if_etag_not_match: Union[str, Set[str]] + :param if_etag_not_match: + (Optional) See :ref:`using-if-etag-not-match` + + :type if_generation_match: long + :param if_generation_match: + (Optional) See :ref:`using-if-generation-match` + + :type if_generation_not_match: long + :param if_generation_not_match: + (Optional) See :ref:`using-if-generation-not-match` + + :type if_metageneration_match: long + :param if_metageneration_match: + (Optional) See :ref:`using-if-metageneration-match` + + :type if_metageneration_not_match: long + :param if_metageneration_not_match: + (Optional) See :ref:`using-if-metageneration-not-match` + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + + :param kwargs: Keyword arguments to pass to the + :class:`~google.cloud.storage.blob.Blob` constructor. + + :rtype: :class:`google.cloud.storage.blob.Blob` or None + :returns: The blob object if it exists, otherwise None. + """ + blob = Blob( + bucket=self, + name=blob_name, + encryption_key=encryption_key, + generation=generation, + **kwargs, + ) + try: + # NOTE: This will not fail immediately in a batch. However, when + # Batch.finish() is called, the resulting `NotFound` will be + # raised. + blob.reload( + client=client, + timeout=timeout, + if_etag_match=if_etag_match, + if_etag_not_match=if_etag_not_match, + if_generation_match=if_generation_match, + if_generation_not_match=if_generation_not_match, + if_metageneration_match=if_metageneration_match, + if_metageneration_not_match=if_metageneration_not_match, + retry=retry, + ) + except NotFound: + return None + else: + return blob + + def list_blobs( + self, + max_results=None, + page_token=None, + prefix=None, + delimiter=None, + start_offset=None, + end_offset=None, + include_trailing_delimiter=None, + versions=None, + projection="noAcl", + fields=None, + client=None, + timeout=_DEFAULT_TIMEOUT, + retry=DEFAULT_RETRY, + ): + """DEPRECATED. Return an iterator used to find blobs in the bucket. + + .. note:: + Direct use of this method is deprecated. Use ``Client.list_blobs`` instead. + + If :attr:`user_project` is set, bills the API request to that project. + + :type max_results: int + :param max_results: + (Optional) The maximum number of blobs to return. + + :type page_token: str + :param page_token: + (Optional) If present, return the next batch of blobs, using the + value, which must correspond to the ``nextPageToken`` value + returned in the previous response. Deprecated: use the ``pages`` + property of the returned iterator instead of manually passing the + token. + + :type prefix: str + :param prefix: (Optional) Prefix used to filter blobs. + + :type delimiter: str + :param delimiter: (Optional) Delimiter, used with ``prefix`` to + emulate hierarchy. + + :type start_offset: str + :param start_offset: + (Optional) Filter results to objects whose names are + lexicographically equal to or after ``startOffset``. If + ``endOffset`` is also set, the objects listed will have names + between ``startOffset`` (inclusive) and ``endOffset`` (exclusive). + + :type end_offset: str + :param end_offset: + (Optional) Filter results to objects whose names are + lexicographically before ``endOffset``. If ``startOffset`` is also + set, the objects listed will have names between ``startOffset`` + (inclusive) and ``endOffset`` (exclusive). + + :type include_trailing_delimiter: boolean + :param include_trailing_delimiter: + (Optional) If true, objects that end in exactly one instance of + ``delimiter`` will have their metadata included in ``items`` in + addition to ``prefixes``. + + :type versions: bool + :param versions: (Optional) Whether object versions should be returned + as separate blobs. + + :type projection: str + :param projection: (Optional) If used, must be 'full' or 'noAcl'. + Defaults to ``'noAcl'``. Specifies the set of + properties to return. + + :type fields: str + :param fields: + (Optional) Selector specifying which fields to include + in a partial response. Must be a list of fields. For + example to get a partial response with just the next + page token and the name and language of each blob returned: + ``'items(name,contentLanguage),nextPageToken'``. + See: https://cloud.google.com/storage/docs/json_api/v1/parameters#fields + + :type client: :class:`~google.cloud.storage.client.Client` + :param client: (Optional) The client to use. If not passed, falls back + to the ``client`` stored on the current bucket. + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + + :rtype: :class:`~google.api_core.page_iterator.Iterator` + :returns: Iterator of all :class:`~google.cloud.storage.blob.Blob` + in this bucket matching the arguments. + """ + client = self._require_client(client) + return client.list_blobs( + self, + max_results=max_results, + page_token=page_token, + prefix=prefix, + delimiter=delimiter, + start_offset=start_offset, + end_offset=end_offset, + include_trailing_delimiter=include_trailing_delimiter, + versions=versions, + projection=projection, + fields=fields, + timeout=timeout, + retry=retry, + ) + + def list_notifications( + self, client=None, timeout=_DEFAULT_TIMEOUT, retry=DEFAULT_RETRY + ): + """List Pub / Sub notifications for this bucket. + + See: + https://cloud.google.com/storage/docs/json_api/v1/notifications/list + + If :attr:`user_project` is set, bills the API request to that project. + + :type client: :class:`~google.cloud.storage.client.Client` or + ``NoneType`` + :param client: (Optional) The client to use. If not passed, falls back + to the ``client`` stored on the current bucket. + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + + :rtype: list of :class:`.BucketNotification` + :returns: notification instances + """ + client = self._require_client(client) + path = self.path + "/notificationConfigs" + iterator = client._list_resource( + path, + _item_to_notification, + timeout=timeout, + retry=retry, + ) + iterator.bucket = self + return iterator + + def get_notification( + self, + notification_id, + client=None, + timeout=_DEFAULT_TIMEOUT, + retry=DEFAULT_RETRY, + ): + """Get Pub / Sub notification for this bucket. + + See [API reference docs](https://cloud.google.com/storage/docs/json_api/v1/notifications/get) + and a [code sample](https://cloud.google.com/storage/docs/samples/storage-print-pubsub-bucket-notification#storage_print_pubsub_bucket_notification-python). + + If :attr:`user_project` is set, bills the API request to that project. + + :type notification_id: str + :param notification_id: The notification id to retrieve the notification configuration. + + :type client: :class:`~google.cloud.storage.client.Client` or + ``NoneType`` + :param client: (Optional) The client to use. If not passed, falls back + to the ``client`` stored on the current bucket. + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + + :rtype: :class:`.BucketNotification` + :returns: notification instance. + """ + notification = self.notification(notification_id=notification_id) + notification.reload(client=client, timeout=timeout, retry=retry) + return notification + + def delete( + self, + force=False, + client=None, + if_metageneration_match=None, + if_metageneration_not_match=None, + timeout=_DEFAULT_TIMEOUT, + retry=DEFAULT_RETRY, + ): + """Delete this bucket. + + The bucket **must** be empty in order to submit a delete request. If + ``force=True`` is passed, this will first attempt to delete all the + objects / blobs in the bucket (i.e. try to empty the bucket). + + If the bucket doesn't exist, this will raise + :class:`google.cloud.exceptions.NotFound`. If the bucket is not empty + (and ``force=False``), will raise :class:`google.cloud.exceptions.Conflict`. + + If ``force=True`` and the bucket contains more than 256 objects / blobs + this will cowardly refuse to delete the objects (or the bucket). This + is to prevent accidental bucket deletion and to prevent extremely long + runtime of this method. + + If :attr:`user_project` is set, bills the API request to that project. + + :type force: bool + :param force: If True, empties the bucket's objects then deletes it. + + :type client: :class:`~google.cloud.storage.client.Client` or + ``NoneType`` + :param client: (Optional) The client to use. If not passed, falls back + to the ``client`` stored on the current bucket. + + :type if_metageneration_match: long + :param if_metageneration_match: (Optional) Make the operation conditional on whether the + blob's current metageneration matches the given value. + + :type if_metageneration_not_match: long + :param if_metageneration_not_match: (Optional) Make the operation conditional on whether the + blob's current metageneration does not match the given value. + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + + :raises: :class:`ValueError` if ``force`` is ``True`` and the bucket + contains more than 256 objects / blobs. + """ + client = self._require_client(client) + query_params = {} + + if self.user_project is not None: + query_params["userProject"] = self.user_project + + _add_generation_match_parameters( + query_params, + if_metageneration_match=if_metageneration_match, + if_metageneration_not_match=if_metageneration_not_match, + ) + if force: + blobs = list( + self.list_blobs( + max_results=self._MAX_OBJECTS_FOR_ITERATION + 1, + client=client, + timeout=timeout, + retry=retry, + ) + ) + if len(blobs) > self._MAX_OBJECTS_FOR_ITERATION: + message = ( + "Refusing to delete bucket with more than " + "%d objects. If you actually want to delete " + "this bucket, please delete the objects " + "yourself before calling Bucket.delete()." + ) % (self._MAX_OBJECTS_FOR_ITERATION,) + raise ValueError(message) + + # Ignore 404 errors on delete. + self.delete_blobs( + blobs, + on_error=lambda blob: None, + client=client, + timeout=timeout, + retry=retry, + ) + + # We intentionally pass `_target_object=None` since a DELETE + # request has no response value (whether in a standard request or + # in a batch request). + client._delete_resource( + self.path, + query_params=query_params, + timeout=timeout, + retry=retry, + _target_object=None, + ) + + def delete_blob( + self, + blob_name, + client=None, + generation=None, + if_generation_match=None, + if_generation_not_match=None, + if_metageneration_match=None, + if_metageneration_not_match=None, + timeout=_DEFAULT_TIMEOUT, + retry=DEFAULT_RETRY_IF_GENERATION_SPECIFIED, + ): + """Deletes a blob from the current bucket. + + If :attr:`user_project` is set, bills the API request to that project. + + :type blob_name: str + :param blob_name: A blob name to delete. + + :type client: :class:`~google.cloud.storage.client.Client` or + ``NoneType`` + :param client: (Optional) The client to use. If not passed, falls back + to the ``client`` stored on the current bucket. + + :type generation: long + :param generation: (Optional) If present, permanently deletes a specific + revision of this object. + + :type if_generation_match: long + :param if_generation_match: + (Optional) See :ref:`using-if-generation-match` + + :type if_generation_not_match: long + :param if_generation_not_match: + (Optional) See :ref:`using-if-generation-not-match` + + :type if_metageneration_match: long + :param if_metageneration_match: + (Optional) See :ref:`using-if-metageneration-match` + + :type if_metageneration_not_match: long + :param if_metageneration_not_match: + (Optional) See :ref:`using-if-metageneration-not-match` + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + + :raises: :class:`google.cloud.exceptions.NotFound` Raises a NotFound + if the blob isn't found. To suppress + the exception, use :meth:`delete_blobs` by passing a no-op + ``on_error`` callback. + """ + client = self._require_client(client) + blob = Blob(blob_name, bucket=self, generation=generation) + + query_params = copy.deepcopy(blob._query_params) + _add_generation_match_parameters( + query_params, + if_generation_match=if_generation_match, + if_generation_not_match=if_generation_not_match, + if_metageneration_match=if_metageneration_match, + if_metageneration_not_match=if_metageneration_not_match, + ) + # We intentionally pass `_target_object=None` since a DELETE + # request has no response value (whether in a standard request or + # in a batch request). + client._delete_resource( + blob.path, + query_params=query_params, + timeout=timeout, + retry=retry, + _target_object=None, + ) + + def delete_blobs( + self, + blobs, + on_error=None, + client=None, + preserve_generation=False, + timeout=_DEFAULT_TIMEOUT, + if_generation_match=None, + if_generation_not_match=None, + if_metageneration_match=None, + if_metageneration_not_match=None, + retry=DEFAULT_RETRY_IF_GENERATION_SPECIFIED, + ): + """Deletes a list of blobs from the current bucket. + + Uses :meth:`delete_blob` to delete each individual blob. + + By default, any generation information in the list of blobs is ignored, and the + live versions of all blobs are deleted. Set `preserve_generation` to True + if blob generation should instead be propagated from the list of blobs. + + If :attr:`user_project` is set, bills the API request to that project. + + :type blobs: list + :param blobs: A list of :class:`~google.cloud.storage.blob.Blob`-s or + blob names to delete. + + :type on_error: callable + :param on_error: (Optional) Takes single argument: ``blob``. + Called once for each blob raising + :class:`~google.cloud.exceptions.NotFound`; + otherwise, the exception is propagated. + + :type client: :class:`~google.cloud.storage.client.Client` + :param client: (Optional) The client to use. If not passed, falls back + to the ``client`` stored on the current bucket. + + :type preserve_generation: bool + :param preserve_generation: (Optional) Deletes only the generation specified on the blob object, + instead of the live version, if set to True. Only :class:~google.cloud.storage.blob.Blob + objects can have their generation set in this way. + Default: False. + + :type if_generation_match: list of long + :param if_generation_match: + (Optional) See :ref:`using-if-generation-match` + Note that the length of the list must match the length of + The list must match ``blobs`` item-to-item. + + :type if_generation_not_match: list of long + :param if_generation_not_match: + (Optional) See :ref:`using-if-generation-not-match` + The list must match ``blobs`` item-to-item. + + :type if_metageneration_match: list of long + :param if_metageneration_match: + (Optional) See :ref:`using-if-metageneration-match` + The list must match ``blobs`` item-to-item. + + :type if_metageneration_not_match: list of long + :param if_metageneration_not_match: + (Optional) See :ref:`using-if-metageneration-not-match` + The list must match ``blobs`` item-to-item. + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + + :raises: :class:`~google.cloud.exceptions.NotFound` (if + `on_error` is not passed). + """ + _raise_if_len_differs( + len(blobs), + if_generation_match=if_generation_match, + if_generation_not_match=if_generation_not_match, + if_metageneration_match=if_metageneration_match, + if_metageneration_not_match=if_metageneration_not_match, + ) + if_generation_match = iter(if_generation_match or []) + if_generation_not_match = iter(if_generation_not_match or []) + if_metageneration_match = iter(if_metageneration_match or []) + if_metageneration_not_match = iter(if_metageneration_not_match or []) + + for blob in blobs: + try: + blob_name = blob + generation = None + if not isinstance(blob_name, str): + blob_name = blob.name + generation = blob.generation if preserve_generation else None + + self.delete_blob( + blob_name, + client=client, + generation=generation, + if_generation_match=next(if_generation_match, None), + if_generation_not_match=next(if_generation_not_match, None), + if_metageneration_match=next(if_metageneration_match, None), + if_metageneration_not_match=next(if_metageneration_not_match, None), + timeout=timeout, + retry=retry, + ) + except NotFound: + if on_error is not None: + on_error(blob) + else: + raise + + def copy_blob( + self, + blob, + destination_bucket, + new_name=None, + client=None, + preserve_acl=True, + source_generation=None, + if_generation_match=None, + if_generation_not_match=None, + if_metageneration_match=None, + if_metageneration_not_match=None, + if_source_generation_match=None, + if_source_generation_not_match=None, + if_source_metageneration_match=None, + if_source_metageneration_not_match=None, + timeout=_DEFAULT_TIMEOUT, + retry=DEFAULT_RETRY_IF_GENERATION_SPECIFIED, + ): + """Copy the given blob to the given bucket, optionally with a new name. + + If :attr:`user_project` is set, bills the API request to that project. + + See [API reference docs](https://cloud.google.com/storage/docs/json_api/v1/objects/copy) + and a [code sample](https://cloud.google.com/storage/docs/samples/storage-copy-file#storage_copy_file-python). + + :type blob: :class:`google.cloud.storage.blob.Blob` + :param blob: The blob to be copied. + + :type destination_bucket: :class:`google.cloud.storage.bucket.Bucket` + :param destination_bucket: The bucket into which the blob should be + copied. + + :type new_name: str + :param new_name: (Optional) The new name for the copied file. + + :type client: :class:`~google.cloud.storage.client.Client` or + ``NoneType`` + :param client: (Optional) The client to use. If not passed, falls back + to the ``client`` stored on the current bucket. + + :type preserve_acl: bool + :param preserve_acl: DEPRECATED. This argument is not functional! + (Optional) Copies ACL from old blob to new blob. + Default: True. + + :type source_generation: long + :param source_generation: (Optional) The generation of the blob to be + copied. + + :type if_generation_match: long + :param if_generation_match: + (Optional) See :ref:`using-if-generation-match` + Note that the generation to be matched is that of the + ``destination`` blob. + + :type if_generation_not_match: long + :param if_generation_not_match: + (Optional) See :ref:`using-if-generation-not-match` + Note that the generation to be matched is that of the + ``destination`` blob. + + :type if_metageneration_match: long + :param if_metageneration_match: + (Optional) See :ref:`using-if-metageneration-match` + Note that the metageneration to be matched is that of the + ``destination`` blob. + + :type if_metageneration_not_match: long + :param if_metageneration_not_match: + (Optional) See :ref:`using-if-metageneration-not-match` + Note that the metageneration to be matched is that of the + ``destination`` blob. + + :type if_source_generation_match: long + :param if_source_generation_match: + (Optional) Makes the operation conditional on whether the source + object's generation matches the given value. + + :type if_source_generation_not_match: long + :param if_source_generation_not_match: + (Optional) Makes the operation conditional on whether the source + object's generation does not match the given value. + + :type if_source_metageneration_match: long + :param if_source_metageneration_match: + (Optional) Makes the operation conditional on whether the source + object's current metageneration matches the given value. + + :type if_source_metageneration_not_match: long + :param if_source_metageneration_not_match: + (Optional) Makes the operation conditional on whether the source + object's current metageneration does not match the given value. + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + + :rtype: :class:`google.cloud.storage.blob.Blob` + :returns: The new Blob. + """ + client = self._require_client(client) + query_params = {} + + if self.user_project is not None: + query_params["userProject"] = self.user_project + + if source_generation is not None: + query_params["sourceGeneration"] = source_generation + + _add_generation_match_parameters( + query_params, + if_generation_match=if_generation_match, + if_generation_not_match=if_generation_not_match, + if_metageneration_match=if_metageneration_match, + if_metageneration_not_match=if_metageneration_not_match, + if_source_generation_match=if_source_generation_match, + if_source_generation_not_match=if_source_generation_not_match, + if_source_metageneration_match=if_source_metageneration_match, + if_source_metageneration_not_match=if_source_metageneration_not_match, + ) + + if new_name is None: + new_name = blob.name + + new_blob = Blob(bucket=destination_bucket, name=new_name) + api_path = blob.path + "/copyTo" + new_blob.path + copy_result = client._post_resource( + api_path, + None, + query_params=query_params, + timeout=timeout, + retry=retry, + _target_object=new_blob, + ) + + if not preserve_acl: + new_blob.acl.save(acl={}, client=client, timeout=timeout) + + new_blob._set_properties(copy_result) + return new_blob + + def rename_blob( + self, + blob, + new_name, + client=None, + if_generation_match=None, + if_generation_not_match=None, + if_metageneration_match=None, + if_metageneration_not_match=None, + if_source_generation_match=None, + if_source_generation_not_match=None, + if_source_metageneration_match=None, + if_source_metageneration_not_match=None, + timeout=_DEFAULT_TIMEOUT, + retry=DEFAULT_RETRY_IF_GENERATION_SPECIFIED, + ): + """Rename the given blob using copy and delete operations. + + If :attr:`user_project` is set, bills the API request to that project. + + Effectively, copies blob to the same bucket with a new name, then + deletes the blob. + + .. warning:: + + This method will first duplicate the data and then delete the + old blob. This means that with very large objects renaming + could be a very (temporarily) costly or a very slow operation. + If you need more control over the copy and deletion, instead + use `google.cloud.storage.blob.Blob.copy_to` and + `google.cloud.storage.blob.Blob.delete` directly. + + :type blob: :class:`google.cloud.storage.blob.Blob` + :param blob: The blob to be renamed. + + :type new_name: str + :param new_name: The new name for this blob. + + :type client: :class:`~google.cloud.storage.client.Client` or + ``NoneType`` + :param client: (Optional) The client to use. If not passed, falls back + to the ``client`` stored on the current bucket. + + :type if_generation_match: long + :param if_generation_match: + (Optional) See :ref:`using-if-generation-match` + Note that the generation to be matched is that of the + ``destination`` blob. + + :type if_generation_not_match: long + :param if_generation_not_match: + (Optional) See :ref:`using-if-generation-not-match` + Note that the generation to be matched is that of the + ``destination`` blob. + + :type if_metageneration_match: long + :param if_metageneration_match: + (Optional) See :ref:`using-if-metageneration-match` + Note that the metageneration to be matched is that of the + ``destination`` blob. + + :type if_metageneration_not_match: long + :param if_metageneration_not_match: + (Optional) See :ref:`using-if-metageneration-not-match` + Note that the metageneration to be matched is that of the + ``destination`` blob. + + :type if_source_generation_match: long + :param if_source_generation_match: + (Optional) Makes the operation conditional on whether the source + object's generation matches the given value. Also used in the + (implied) delete request. + + :type if_source_generation_not_match: long + :param if_source_generation_not_match: + (Optional) Makes the operation conditional on whether the source + object's generation does not match the given value. Also used in + the (implied) delete request. + + :type if_source_metageneration_match: long + :param if_source_metageneration_match: + (Optional) Makes the operation conditional on whether the source + object's current metageneration matches the given value. Also used + in the (implied) delete request. + + :type if_source_metageneration_not_match: long + :param if_source_metageneration_not_match: + (Optional) Makes the operation conditional on whether the source + object's current metageneration does not match the given value. + Also used in the (implied) delete request. + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + + :rtype: :class:`Blob` + :returns: The newly-renamed blob. + """ + same_name = blob.name == new_name + + new_blob = self.copy_blob( + blob, + self, + new_name, + client=client, + timeout=timeout, + if_generation_match=if_generation_match, + if_generation_not_match=if_generation_not_match, + if_metageneration_match=if_metageneration_match, + if_metageneration_not_match=if_metageneration_not_match, + if_source_generation_match=if_source_generation_match, + if_source_generation_not_match=if_source_generation_not_match, + if_source_metageneration_match=if_source_metageneration_match, + if_source_metageneration_not_match=if_source_metageneration_not_match, + retry=retry, + ) + + if not same_name: + blob.delete( + client=client, + timeout=timeout, + if_generation_match=if_source_generation_match, + if_generation_not_match=if_source_generation_not_match, + if_metageneration_match=if_source_metageneration_match, + if_metageneration_not_match=if_source_metageneration_not_match, + retry=retry, + ) + return new_blob + + @property + def cors(self): + """Retrieve or set CORS policies configured for this bucket. + + See http://www.w3.org/TR/cors/ and + https://cloud.google.com/storage/docs/json_api/v1/buckets + + .. note:: + + The getter for this property returns a list which contains + *copies* of the bucket's CORS policy mappings. Mutating the list + or one of its dicts has no effect unless you then re-assign the + dict via the setter. E.g.: + + >>> policies = bucket.cors + >>> policies.append({'origin': '/foo', ...}) + >>> policies[1]['maxAgeSeconds'] = 3600 + >>> del policies[0] + >>> bucket.cors = policies + >>> bucket.update() + + :setter: Set CORS policies for this bucket. + :getter: Gets the CORS policies for this bucket. + + :rtype: list of dictionaries + :returns: A sequence of mappings describing each CORS policy. + """ + return [copy.deepcopy(policy) for policy in self._properties.get("cors", ())] + + @cors.setter + def cors(self, entries): + """Set CORS policies configured for this bucket. + + See http://www.w3.org/TR/cors/ and + https://cloud.google.com/storage/docs/json_api/v1/buckets + + :type entries: list of dictionaries + :param entries: A sequence of mappings describing each CORS policy. + """ + self._patch_property("cors", entries) + + default_event_based_hold = _scalar_property("defaultEventBasedHold") + """Are uploaded objects automatically placed under an even-based hold? + + If True, uploaded objects will be placed under an event-based hold to + be released at a future time. When released an object will then begin + the retention period determined by the policy retention period for the + object bucket. + + See https://cloud.google.com/storage/docs/json_api/v1/buckets + + If the property is not set locally, returns ``None``. + + :rtype: bool or ``NoneType`` + """ + + @property + def default_kms_key_name(self): + """Retrieve / set default KMS encryption key for objects in the bucket. + + See https://cloud.google.com/storage/docs/json_api/v1/buckets + + :setter: Set default KMS encryption key for items in this bucket. + :getter: Get default KMS encryption key for items in this bucket. + + :rtype: str + :returns: Default KMS encryption key, or ``None`` if not set. + """ + encryption_config = self._properties.get("encryption", {}) + return encryption_config.get("defaultKmsKeyName") + + @default_kms_key_name.setter + def default_kms_key_name(self, value): + """Set default KMS encryption key for objects in the bucket. + + :type value: str or None + :param value: new KMS key name (None to clear any existing key). + """ + encryption_config = self._properties.get("encryption", {}) + encryption_config["defaultKmsKeyName"] = value + self._patch_property("encryption", encryption_config) + + @property + def labels(self): + """Retrieve or set labels assigned to this bucket. + + See + https://cloud.google.com/storage/docs/json_api/v1/buckets#labels + + .. note:: + + The getter for this property returns a dict which is a *copy* + of the bucket's labels. Mutating that dict has no effect unless + you then re-assign the dict via the setter. E.g.: + + >>> labels = bucket.labels + >>> labels['new_key'] = 'some-label' + >>> del labels['old_key'] + >>> bucket.labels = labels + >>> bucket.update() + + :setter: Set labels for this bucket. + :getter: Gets the labels for this bucket. + + :rtype: :class:`dict` + :returns: Name-value pairs (string->string) labelling the bucket. + """ + labels = self._properties.get("labels") + if labels is None: + return {} + return copy.deepcopy(labels) + + @labels.setter + def labels(self, mapping): + """Set labels assigned to this bucket. + + See + https://cloud.google.com/storage/docs/json_api/v1/buckets#labels + + :type mapping: :class:`dict` + :param mapping: Name-value pairs (string->string) labelling the bucket. + """ + # If any labels have been expressly removed, we need to track this + # so that a future .patch() call can do the correct thing. + existing = set([k for k in self.labels.keys()]) + incoming = set([k for k in mapping.keys()]) + self._label_removals = self._label_removals.union(existing.difference(incoming)) + mapping = {k: str(v) for k, v in mapping.items()} + + # Actually update the labels on the object. + self._patch_property("labels", copy.deepcopy(mapping)) + + @property + def etag(self): + """Retrieve the ETag for the bucket. + + See https://tools.ietf.org/html/rfc2616#section-3.11 and + https://cloud.google.com/storage/docs/json_api/v1/buckets + + :rtype: str or ``NoneType`` + :returns: The bucket etag or ``None`` if the bucket's + resource has not been loaded from the server. + """ + return self._properties.get("etag") + + @property + def id(self): + """Retrieve the ID for the bucket. + + See https://cloud.google.com/storage/docs/json_api/v1/buckets + + :rtype: str or ``NoneType`` + :returns: The ID of the bucket or ``None`` if the bucket's + resource has not been loaded from the server. + """ + return self._properties.get("id") + + @property + def iam_configuration(self): + """Retrieve IAM configuration for this bucket. + + :rtype: :class:`IAMConfiguration` + :returns: an instance for managing the bucket's IAM configuration. + """ + info = self._properties.get("iamConfiguration", {}) + return IAMConfiguration.from_api_repr(info, self) + + @property + def lifecycle_rules(self): + """Retrieve or set lifecycle rules configured for this bucket. + + See https://cloud.google.com/storage/docs/lifecycle and + https://cloud.google.com/storage/docs/json_api/v1/buckets + + .. note:: + + The getter for this property returns a generator which yields + *copies* of the bucket's lifecycle rules mappings. Mutating the + output dicts has no effect unless you then re-assign the dict via + the setter. E.g.: + + >>> rules = list(bucket.lifecycle_rules) + >>> rules.append({'origin': '/foo', ...}) + >>> rules[1]['rule']['action']['type'] = 'Delete' + >>> del rules[0] + >>> bucket.lifecycle_rules = rules + >>> bucket.update() + + :setter: Set lifecycle rules for this bucket. + :getter: Gets the lifecycle rules for this bucket. + + :rtype: generator(dict) + :returns: A sequence of mappings describing each lifecycle rule. + """ + info = self._properties.get("lifecycle", {}) + for rule in info.get("rule", ()): + action_type = rule["action"]["type"] + if action_type == "Delete": + yield LifecycleRuleDelete.from_api_repr(rule) + elif action_type == "SetStorageClass": + yield LifecycleRuleSetStorageClass.from_api_repr(rule) + elif action_type == "AbortIncompleteMultipartUpload": + yield LifecycleRuleAbortIncompleteMultipartUpload.from_api_repr(rule) + else: + warnings.warn( + "Unknown lifecycle rule type received: {}. Please upgrade to the latest version of google-cloud-storage.".format( + rule + ), + UserWarning, + stacklevel=1, + ) + + @lifecycle_rules.setter + def lifecycle_rules(self, rules): + """Set lifecycle rules configured for this bucket. + + See https://cloud.google.com/storage/docs/lifecycle and + https://cloud.google.com/storage/docs/json_api/v1/buckets + + :type rules: list of dictionaries + :param rules: A sequence of mappings describing each lifecycle rule. + """ + rules = [dict(rule) for rule in rules] # Convert helpers if needed + self._patch_property("lifecycle", {"rule": rules}) + + def clear_lifecyle_rules(self): + """Clear lifecycle rules configured for this bucket. + + See https://cloud.google.com/storage/docs/lifecycle and + https://cloud.google.com/storage/docs/json_api/v1/buckets + """ + self.lifecycle_rules = [] + + def add_lifecycle_delete_rule(self, **kw): + """Add a "delete" rule to lifecycle rules configured for this bucket. + + This defines a [lifecycle configuration](https://cloud.google.com/storage/docs/lifecycle), + which is set on the bucket. For the general format of a lifecycle configuration, see the + [bucket resource representation for JSON](https://cloud.google.com/storage/docs/json_api/v1/buckets). + See also a [code sample](https://cloud.google.com/storage/docs/samples/storage-enable-bucket-lifecycle-management#storage_enable_bucket_lifecycle_management-python). + + :type kw: dict + :params kw: arguments passed to :class:`LifecycleRuleConditions`. + """ + rules = list(self.lifecycle_rules) + rules.append(LifecycleRuleDelete(**kw)) + self.lifecycle_rules = rules + + def add_lifecycle_set_storage_class_rule(self, storage_class, **kw): + """Add a "set storage class" rule to lifecycle rules. + + This defines a [lifecycle configuration](https://cloud.google.com/storage/docs/lifecycle), + which is set on the bucket. For the general format of a lifecycle configuration, see the + [bucket resource representation for JSON](https://cloud.google.com/storage/docs/json_api/v1/buckets). + + :type storage_class: str, one of :attr:`STORAGE_CLASSES`. + :param storage_class: new storage class to assign to matching items. + + :type kw: dict + :params kw: arguments passed to :class:`LifecycleRuleConditions`. + """ + rules = list(self.lifecycle_rules) + rules.append(LifecycleRuleSetStorageClass(storage_class, **kw)) + self.lifecycle_rules = rules + + def add_lifecycle_abort_incomplete_multipart_upload_rule(self, **kw): + """Add a "abort incomplete multipart upload" rule to lifecycle rules. + + .. note:: + The "age" lifecycle condition is the only supported condition + for this rule. + + This defines a [lifecycle configuration](https://cloud.google.com/storage/docs/lifecycle), + which is set on the bucket. For the general format of a lifecycle configuration, see the + [bucket resource representation for JSON](https://cloud.google.com/storage/docs/json_api/v1/buckets). + + :type kw: dict + :params kw: arguments passed to :class:`LifecycleRuleConditions`. + """ + rules = list(self.lifecycle_rules) + rules.append(LifecycleRuleAbortIncompleteMultipartUpload(**kw)) + self.lifecycle_rules = rules + + _location = _scalar_property("location") + + @property + def location(self): + """Retrieve location configured for this bucket. + + See https://cloud.google.com/storage/docs/json_api/v1/buckets and + https://cloud.google.com/storage/docs/locations + + Returns ``None`` if the property has not been set before creation, + or if the bucket's resource has not been loaded from the server. + :rtype: str or ``NoneType`` + """ + return self._location + + @location.setter + def location(self, value): + """(Deprecated) Set `Bucket.location` + + This can only be set at bucket **creation** time. + + See https://cloud.google.com/storage/docs/json_api/v1/buckets and + https://cloud.google.com/storage/docs/bucket-locations + + .. warning:: + + Assignment to 'Bucket.location' is deprecated, as it is only + valid before the bucket is created. Instead, pass the location + to `Bucket.create`. + """ + warnings.warn(_LOCATION_SETTER_MESSAGE, DeprecationWarning, stacklevel=2) + self._location = value + + @property + def data_locations(self): + """Retrieve the list of regional locations for custom dual-region buckets. + + See https://cloud.google.com/storage/docs/json_api/v1/buckets and + https://cloud.google.com/storage/docs/locations + + Returns ``None`` if the property has not been set before creation, + if the bucket's resource has not been loaded from the server, + or if the bucket is not a dual-regions bucket. + :rtype: list of str or ``NoneType`` + """ + custom_placement_config = self._properties.get("customPlacementConfig", {}) + return custom_placement_config.get("dataLocations") + + @property + def location_type(self): + """Retrieve the location type for the bucket. + + See https://cloud.google.com/storage/docs/storage-classes + + :getter: Gets the the location type for this bucket. + + :rtype: str or ``NoneType`` + :returns: + If set, one of + :attr:`~google.cloud.storage.constants.MULTI_REGION_LOCATION_TYPE`, + :attr:`~google.cloud.storage.constants.REGION_LOCATION_TYPE`, or + :attr:`~google.cloud.storage.constants.DUAL_REGION_LOCATION_TYPE`, + else ``None``. + """ + return self._properties.get("locationType") + + def get_logging(self): + """Return info about access logging for this bucket. + + See https://cloud.google.com/storage/docs/access-logs#status + + :rtype: dict or None + :returns: a dict w/ keys, ``logBucket`` and ``logObjectPrefix`` + (if logging is enabled), or None (if not). + """ + info = self._properties.get("logging") + return copy.deepcopy(info) + + def enable_logging(self, bucket_name, object_prefix=""): + """Enable access logging for this bucket. + + See https://cloud.google.com/storage/docs/access-logs + + :type bucket_name: str + :param bucket_name: name of bucket in which to store access logs + + :type object_prefix: str + :param object_prefix: prefix for access log filenames + """ + info = {"logBucket": bucket_name, "logObjectPrefix": object_prefix} + self._patch_property("logging", info) + + def disable_logging(self): + """Disable access logging for this bucket. + + See https://cloud.google.com/storage/docs/access-logs#disabling + """ + self._patch_property("logging", None) + + @property + def metageneration(self): + """Retrieve the metageneration for the bucket. + + See https://cloud.google.com/storage/docs/json_api/v1/buckets + + :rtype: int or ``NoneType`` + :returns: The metageneration of the bucket or ``None`` if the bucket's + resource has not been loaded from the server. + """ + metageneration = self._properties.get("metageneration") + if metageneration is not None: + return int(metageneration) + + @property + def owner(self): + """Retrieve info about the owner of the bucket. + + See https://cloud.google.com/storage/docs/json_api/v1/buckets + + :rtype: dict or ``NoneType`` + :returns: Mapping of owner's role/ID. Returns ``None`` if the bucket's + resource has not been loaded from the server. + """ + return copy.deepcopy(self._properties.get("owner")) + + @property + def project_number(self): + """Retrieve the number of the project to which the bucket is assigned. + + See https://cloud.google.com/storage/docs/json_api/v1/buckets + + :rtype: int or ``NoneType`` + :returns: The project number that owns the bucket or ``None`` if + the bucket's resource has not been loaded from the server. + """ + project_number = self._properties.get("projectNumber") + if project_number is not None: + return int(project_number) + + @property + def retention_policy_effective_time(self): + """Retrieve the effective time of the bucket's retention policy. + + :rtype: datetime.datetime or ``NoneType`` + :returns: point-in time at which the bucket's retention policy is + effective, or ``None`` if the property is not + set locally. + """ + policy = self._properties.get("retentionPolicy") + if policy is not None: + timestamp = policy.get("effectiveTime") + if timestamp is not None: + return _rfc3339_nanos_to_datetime(timestamp) + + @property + def retention_policy_locked(self): + """Retrieve whthere the bucket's retention policy is locked. + + :rtype: bool + :returns: True if the bucket's policy is locked, or else False + if the policy is not locked, or the property is not + set locally. + """ + policy = self._properties.get("retentionPolicy") + if policy is not None: + return policy.get("isLocked") + + @property + def retention_period(self): + """Retrieve or set the retention period for items in the bucket. + + :rtype: int or ``NoneType`` + :returns: number of seconds to retain items after upload or release + from event-based lock, or ``None`` if the property is not + set locally. + """ + policy = self._properties.get("retentionPolicy") + if policy is not None: + period = policy.get("retentionPeriod") + if period is not None: + return int(period) + + @retention_period.setter + def retention_period(self, value): + """Set the retention period for items in the bucket. + + :type value: int + :param value: + number of seconds to retain items after upload or release from + event-based lock. + + :raises ValueError: if the bucket's retention policy is locked. + """ + policy = self._properties.setdefault("retentionPolicy", {}) + if value is not None: + policy["retentionPeriod"] = str(value) + else: + policy = None + self._patch_property("retentionPolicy", policy) + + @property + def self_link(self): + """Retrieve the URI for the bucket. + + See https://cloud.google.com/storage/docs/json_api/v1/buckets + + :rtype: str or ``NoneType`` + :returns: The self link for the bucket or ``None`` if + the bucket's resource has not been loaded from the server. + """ + return self._properties.get("selfLink") + + @property + def storage_class(self): + """Retrieve or set the storage class for the bucket. + + See https://cloud.google.com/storage/docs/storage-classes + + :setter: Set the storage class for this bucket. + :getter: Gets the the storage class for this bucket. + + :rtype: str or ``NoneType`` + :returns: + If set, one of + :attr:`~google.cloud.storage.constants.NEARLINE_STORAGE_CLASS`, + :attr:`~google.cloud.storage.constants.COLDLINE_STORAGE_CLASS`, + :attr:`~google.cloud.storage.constants.ARCHIVE_STORAGE_CLASS`, + :attr:`~google.cloud.storage.constants.STANDARD_STORAGE_CLASS`, + :attr:`~google.cloud.storage.constants.MULTI_REGIONAL_LEGACY_STORAGE_CLASS`, + :attr:`~google.cloud.storage.constants.REGIONAL_LEGACY_STORAGE_CLASS`, + or + :attr:`~google.cloud.storage.constants.DURABLE_REDUCED_AVAILABILITY_LEGACY_STORAGE_CLASS`, + else ``None``. + """ + return self._properties.get("storageClass") + + @storage_class.setter + def storage_class(self, value): + """Set the storage class for the bucket. + + See https://cloud.google.com/storage/docs/storage-classes + + :type value: str + :param value: + One of + :attr:`~google.cloud.storage.constants.NEARLINE_STORAGE_CLASS`, + :attr:`~google.cloud.storage.constants.COLDLINE_STORAGE_CLASS`, + :attr:`~google.cloud.storage.constants.ARCHIVE_STORAGE_CLASS`, + :attr:`~google.cloud.storage.constants.STANDARD_STORAGE_CLASS`, + :attr:`~google.cloud.storage.constants.MULTI_REGIONAL_LEGACY_STORAGE_CLASS`, + :attr:`~google.cloud.storage.constants.REGIONAL_LEGACY_STORAGE_CLASS`, + or + :attr:`~google.cloud.storage.constants.DURABLE_REDUCED_AVAILABILITY_LEGACY_STORAGE_CLASS`, + """ + self._patch_property("storageClass", value) + + @property + def time_created(self): + """Retrieve the timestamp at which the bucket was created. + + See https://cloud.google.com/storage/docs/json_api/v1/buckets + + :rtype: :class:`datetime.datetime` or ``NoneType`` + :returns: Datetime object parsed from RFC3339 valid timestamp, or + ``None`` if the bucket's resource has not been loaded + from the server. + """ + value = self._properties.get("timeCreated") + if value is not None: + return _rfc3339_nanos_to_datetime(value) + + @property + def versioning_enabled(self): + """Is versioning enabled for this bucket? + + See https://cloud.google.com/storage/docs/object-versioning for + details. + + :setter: Update whether versioning is enabled for this bucket. + :getter: Query whether versioning is enabled for this bucket. + + :rtype: bool + :returns: True if enabled, else False. + """ + versioning = self._properties.get("versioning", {}) + return versioning.get("enabled", False) + + @versioning_enabled.setter + def versioning_enabled(self, value): + """Enable versioning for this bucket. + + See https://cloud.google.com/storage/docs/object-versioning for + details. + + :type value: convertible to boolean + :param value: should versioning be enabled for the bucket? + """ + self._patch_property("versioning", {"enabled": bool(value)}) + + @property + def requester_pays(self): + """Does the requester pay for API requests for this bucket? + + See https://cloud.google.com/storage/docs/requester-pays for + details. + + :setter: Update whether requester pays for this bucket. + :getter: Query whether requester pays for this bucket. + + :rtype: bool + :returns: True if requester pays for API requests for the bucket, + else False. + """ + versioning = self._properties.get("billing", {}) + return versioning.get("requesterPays", False) + + @requester_pays.setter + def requester_pays(self, value): + """Update whether requester pays for API requests for this bucket. + + See https://cloud.google.com/storage/docs/using-requester-pays for + details. + + :type value: convertible to boolean + :param value: should requester pay for API requests for the bucket? + """ + self._patch_property("billing", {"requesterPays": bool(value)}) + + def configure_website(self, main_page_suffix=None, not_found_page=None): + """Configure website-related properties. + + See https://cloud.google.com/storage/docs/static-website + + .. note:: + This configures the bucket's website-related properties,controlling how + the service behaves when accessing bucket contents as a web site. + See [tutorials](https://cloud.google.com/storage/docs/hosting-static-website) and + [code samples](https://cloud.google.com/storage/docs/samples/storage-define-bucket-website-configuration#storage_define_bucket_website_configuration-python) + for more information. + + :type main_page_suffix: str + :param main_page_suffix: The page to use as the main page + of a directory. + Typically something like index.html. + + :type not_found_page: str + :param not_found_page: The file to use when a page isn't found. + """ + data = {"mainPageSuffix": main_page_suffix, "notFoundPage": not_found_page} + self._patch_property("website", data) + + def disable_website(self): + """Disable the website configuration for this bucket. + + This is really just a shortcut for setting the website-related + attributes to ``None``. + """ + return self.configure_website(None, None) + + def get_iam_policy( + self, + client=None, + requested_policy_version=None, + timeout=_DEFAULT_TIMEOUT, + retry=DEFAULT_RETRY, + ): + """Retrieve the IAM policy for the bucket. + + See [API reference docs](https://cloud.google.com/storage/docs/json_api/v1/buckets/getIamPolicy) + and a [code sample](https://cloud.google.com/storage/docs/samples/storage-view-bucket-iam-members#storage_view_bucket_iam_members-python). + + If :attr:`user_project` is set, bills the API request to that project. + + :type client: :class:`~google.cloud.storage.client.Client` or + ``NoneType`` + :param client: (Optional) The client to use. If not passed, falls back + to the ``client`` stored on the current bucket. + + :type requested_policy_version: int or ``NoneType`` + :param requested_policy_version: (Optional) The version of IAM policies to request. + If a policy with a condition is requested without + setting this, the server will return an error. + This must be set to a value of 3 to retrieve IAM + policies containing conditions. This is to prevent + client code that isn't aware of IAM conditions from + interpreting and modifying policies incorrectly. + The service might return a policy with version lower + than the one that was requested, based on the + feature syntax in the policy fetched. + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + + :rtype: :class:`google.api_core.iam.Policy` + :returns: the policy instance, based on the resource returned from + the ``getIamPolicy`` API request. + """ + client = self._require_client(client) + query_params = {} + + if self.user_project is not None: + query_params["userProject"] = self.user_project + + if requested_policy_version is not None: + query_params["optionsRequestedPolicyVersion"] = requested_policy_version + + info = client._get_resource( + f"{self.path}/iam", + query_params=query_params, + timeout=timeout, + retry=retry, + _target_object=None, + ) + return Policy.from_api_repr(info) + + def set_iam_policy( + self, + policy, + client=None, + timeout=_DEFAULT_TIMEOUT, + retry=DEFAULT_RETRY_IF_ETAG_IN_JSON, + ): + """Update the IAM policy for the bucket. + + See + https://cloud.google.com/storage/docs/json_api/v1/buckets/setIamPolicy + + If :attr:`user_project` is set, bills the API request to that project. + + :type policy: :class:`google.api_core.iam.Policy` + :param policy: policy instance used to update bucket's IAM policy. + + :type client: :class:`~google.cloud.storage.client.Client` or + ``NoneType`` + :param client: (Optional) The client to use. If not passed, falls back + to the ``client`` stored on the current bucket. + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + + :rtype: :class:`google.api_core.iam.Policy` + :returns: the policy instance, based on the resource returned from + the ``setIamPolicy`` API request. + """ + client = self._require_client(client) + query_params = {} + + if self.user_project is not None: + query_params["userProject"] = self.user_project + + path = f"{self.path}/iam" + resource = policy.to_api_repr() + resource["resourceId"] = self.path + + info = client._put_resource( + path, + resource, + query_params=query_params, + timeout=timeout, + retry=retry, + _target_object=None, + ) + + return Policy.from_api_repr(info) + + def test_iam_permissions( + self, permissions, client=None, timeout=_DEFAULT_TIMEOUT, retry=DEFAULT_RETRY + ): + """API call: test permissions + + See + https://cloud.google.com/storage/docs/json_api/v1/buckets/testIamPermissions + + If :attr:`user_project` is set, bills the API request to that project. + + :type permissions: list of string + :param permissions: the permissions to check + + :type client: :class:`~google.cloud.storage.client.Client` or + ``NoneType`` + :param client: (Optional) The client to use. If not passed, falls back + to the ``client`` stored on the current bucket. + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + + :rtype: list of string + :returns: the permissions returned by the ``testIamPermissions`` API + request. + """ + client = self._require_client(client) + query_params = {"permissions": permissions} + + if self.user_project is not None: + query_params["userProject"] = self.user_project + + path = f"{self.path}/iam/testPermissions" + resp = client._get_resource( + path, + query_params=query_params, + timeout=timeout, + retry=retry, + _target_object=None, + ) + return resp.get("permissions", []) + + def make_public( + self, + recursive=False, + future=False, + client=None, + timeout=_DEFAULT_TIMEOUT, + if_metageneration_match=None, + if_metageneration_not_match=None, + retry=DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED, + ): + """Update bucket's ACL, granting read access to anonymous users. + + :type recursive: bool + :param recursive: If True, this will make all blobs inside the bucket + public as well. + + :type future: bool + :param future: If True, this will make all objects created in the + future public as well. + + :type client: :class:`~google.cloud.storage.client.Client` or + ``NoneType`` + :param client: (Optional) The client to use. If not passed, falls back + to the ``client`` stored on the current bucket. + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type if_metageneration_match: long + :param if_metageneration_match: (Optional) Make the operation conditional on whether the + blob's current metageneration matches the given value. + + :type if_metageneration_not_match: long + :param if_metageneration_not_match: (Optional) Make the operation conditional on whether the + blob's current metageneration does not match the given value. + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + + :raises ValueError: + If ``recursive`` is True, and the bucket contains more than 256 + blobs. This is to prevent extremely long runtime of this + method. For such buckets, iterate over the blobs returned by + :meth:`list_blobs` and call + :meth:`~google.cloud.storage.blob.Blob.make_public` + for each blob. + """ + self.acl.all().grant_read() + self.acl.save( + client=client, + timeout=timeout, + if_metageneration_match=if_metageneration_match, + if_metageneration_not_match=if_metageneration_not_match, + retry=retry, + ) + + if future: + doa = self.default_object_acl + if not doa.loaded: + doa.reload(client=client, timeout=timeout) + doa.all().grant_read() + doa.save( + client=client, + timeout=timeout, + if_metageneration_match=if_metageneration_match, + if_metageneration_not_match=if_metageneration_not_match, + retry=retry, + ) + + if recursive: + blobs = list( + self.list_blobs( + projection="full", + max_results=self._MAX_OBJECTS_FOR_ITERATION + 1, + client=client, + timeout=timeout, + ) + ) + if len(blobs) > self._MAX_OBJECTS_FOR_ITERATION: + message = ( + "Refusing to make public recursively with more than " + "%d objects. If you actually want to make every object " + "in this bucket public, iterate through the blobs " + "returned by 'Bucket.list_blobs()' and call " + "'make_public' on each one." + ) % (self._MAX_OBJECTS_FOR_ITERATION,) + raise ValueError(message) + + for blob in blobs: + blob.acl.all().grant_read() + blob.acl.save( + client=client, + timeout=timeout, + ) + + def make_private( + self, + recursive=False, + future=False, + client=None, + timeout=_DEFAULT_TIMEOUT, + if_metageneration_match=None, + if_metageneration_not_match=None, + retry=DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED, + ): + """Update bucket's ACL, revoking read access for anonymous users. + + :type recursive: bool + :param recursive: If True, this will make all blobs inside the bucket + private as well. + + :type future: bool + :param future: If True, this will make all objects created in the + future private as well. + + :type client: :class:`~google.cloud.storage.client.Client` or + ``NoneType`` + :param client: (Optional) The client to use. If not passed, falls back + to the ``client`` stored on the current bucket. + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type if_metageneration_match: long + :param if_metageneration_match: (Optional) Make the operation conditional on whether the + blob's current metageneration matches the given value. + :type if_metageneration_not_match: long + :param if_metageneration_not_match: (Optional) Make the operation conditional on whether the + blob's current metageneration does not match the given value. + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + + :raises ValueError: + If ``recursive`` is True, and the bucket contains more than 256 + blobs. This is to prevent extremely long runtime of this + method. For such buckets, iterate over the blobs returned by + :meth:`list_blobs` and call + :meth:`~google.cloud.storage.blob.Blob.make_private` + for each blob. + """ + self.acl.all().revoke_read() + self.acl.save( + client=client, + timeout=timeout, + if_metageneration_match=if_metageneration_match, + if_metageneration_not_match=if_metageneration_not_match, + retry=retry, + ) + + if future: + doa = self.default_object_acl + if not doa.loaded: + doa.reload(client=client, timeout=timeout) + doa.all().revoke_read() + doa.save( + client=client, + timeout=timeout, + if_metageneration_match=if_metageneration_match, + if_metageneration_not_match=if_metageneration_not_match, + retry=retry, + ) + + if recursive: + blobs = list( + self.list_blobs( + projection="full", + max_results=self._MAX_OBJECTS_FOR_ITERATION + 1, + client=client, + timeout=timeout, + ) + ) + if len(blobs) > self._MAX_OBJECTS_FOR_ITERATION: + message = ( + "Refusing to make private recursively with more than " + "%d objects. If you actually want to make every object " + "in this bucket private, iterate through the blobs " + "returned by 'Bucket.list_blobs()' and call " + "'make_private' on each one." + ) % (self._MAX_OBJECTS_FOR_ITERATION,) + raise ValueError(message) + + for blob in blobs: + blob.acl.all().revoke_read() + blob.acl.save(client=client, timeout=timeout) + + def generate_upload_policy(self, conditions, expiration=None, client=None): + """Create a signed upload policy for uploading objects. + + This method generates and signs a policy document. You can use + [`policy documents`](https://cloud.google.com/storage/docs/xml-api/post-object-forms) + to allow visitors to a website to upload files to + Google Cloud Storage without giving them direct write access. + See a [code sample](https://cloud.google.com/storage/docs/xml-api/post-object-forms#python). + + :type expiration: datetime + :param expiration: (Optional) Expiration in UTC. If not specified, the + policy will expire in 1 hour. + + :type conditions: list + :param conditions: A list of conditions as described in the + `policy documents` documentation. + + :type client: :class:`~google.cloud.storage.client.Client` + :param client: (Optional) The client to use. If not passed, falls back + to the ``client`` stored on the current bucket. + + :rtype: dict + :returns: A dictionary of (form field name, form field value) of form + fields that should be added to your HTML upload form in order + to attach the signature. + """ + client = self._require_client(client) + credentials = client._credentials + _signing.ensure_signed_credentials(credentials) + + if expiration is None: + expiration = _NOW() + datetime.timedelta(hours=1) + + conditions = conditions + [{"bucket": self.name}] + + policy_document = { + "expiration": _datetime_to_rfc3339(expiration), + "conditions": conditions, + } + + encoded_policy_document = base64.b64encode( + json.dumps(policy_document).encode("utf-8") + ) + signature = base64.b64encode(credentials.sign_bytes(encoded_policy_document)) + + fields = { + "bucket": self.name, + "GoogleAccessId": credentials.signer_email, + "policy": encoded_policy_document.decode("utf-8"), + "signature": signature.decode("utf-8"), + } + + return fields + + def lock_retention_policy( + self, client=None, timeout=_DEFAULT_TIMEOUT, retry=DEFAULT_RETRY + ): + """Lock the bucket's retention policy. + + :type client: :class:`~google.cloud.storage.client.Client` or + ``NoneType`` + :param client: (Optional) The client to use. If not passed, falls back + to the ``client`` stored on the blob's bucket. + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + + :raises ValueError: + if the bucket has no metageneration (i.e., new or never reloaded); + if the bucket has no retention policy assigned; + if the bucket's retention policy is already locked. + """ + if "metageneration" not in self._properties: + raise ValueError("Bucket has no retention policy assigned: try 'reload'?") + + policy = self._properties.get("retentionPolicy") + + if policy is None: + raise ValueError("Bucket has no retention policy assigned: try 'reload'?") + + if policy.get("isLocked"): + raise ValueError("Bucket's retention policy is already locked.") + + client = self._require_client(client) + + query_params = {"ifMetagenerationMatch": self.metageneration} + + if self.user_project is not None: + query_params["userProject"] = self.user_project + + path = f"/b/{self.name}/lockRetentionPolicy" + api_response = client._post_resource( + path, + None, + query_params=query_params, + timeout=timeout, + retry=retry, + _target_object=self, + ) + self._set_properties(api_response) + + def generate_signed_url( + self, + expiration=None, + api_access_endpoint=_API_ACCESS_ENDPOINT, + method="GET", + headers=None, + query_parameters=None, + client=None, + credentials=None, + version=None, + virtual_hosted_style=False, + bucket_bound_hostname=None, + scheme="http", + ): + """Generates a signed URL for this bucket. + + .. note:: + + If you are on Google Compute Engine, you can't generate a signed + URL using GCE service account. If you'd like to be able to generate + a signed URL from GCE, you can use a standard service account from a + JSON file rather than a GCE service account. + + If you have a bucket that you want to allow access to for a set + amount of time, you can use this method to generate a URL that + is only valid within a certain time period. + + If ``bucket_bound_hostname`` is set as an argument of :attr:`api_access_endpoint`, + ``https`` works only if using a ``CDN``. + + :type expiration: Union[Integer, datetime.datetime, datetime.timedelta] + :param expiration: Point in time when the signed URL should expire. If + a ``datetime`` instance is passed without an explicit + ``tzinfo`` set, it will be assumed to be ``UTC``. + + :type api_access_endpoint: str + :param api_access_endpoint: (Optional) URI base. + + :type method: str + :param method: The HTTP verb that will be used when requesting the URL. + + :type headers: dict + :param headers: + (Optional) Additional HTTP headers to be included as part of the + signed URLs. See: + https://cloud.google.com/storage/docs/xml-api/reference-headers + Requests using the signed URL *must* pass the specified header + (name and value) with each request for the URL. + + :type query_parameters: dict + :param query_parameters: + (Optional) Additional query parameters to be included as part of the + signed URLs. See: + https://cloud.google.com/storage/docs/xml-api/reference-headers#query + + :type client: :class:`~google.cloud.storage.client.Client` or + ``NoneType`` + :param client: (Optional) The client to use. If not passed, falls back + to the ``client`` stored on the blob's bucket. + + + :type credentials: :class:`google.auth.credentials.Credentials` or + :class:`NoneType` + :param credentials: The authorization credentials to attach to requests. + These credentials identify this application to the service. + If none are specified, the client will attempt to ascertain + the credentials from the environment. + + :type version: str + :param version: (Optional) The version of signed credential to create. + Must be one of 'v2' | 'v4'. + + :type virtual_hosted_style: bool + :param virtual_hosted_style: + (Optional) If true, then construct the URL relative the bucket's + virtual hostname, e.g., '.storage.googleapis.com'. + + :type bucket_bound_hostname: str + :param bucket_bound_hostname: + (Optional) If pass, then construct the URL relative to the bucket-bound hostname. + Value cane be a bare or with scheme, e.g., 'example.com' or 'http://example.com'. + See: https://cloud.google.com/storage/docs/request-endpoints#cname + + :type scheme: str + :param scheme: + (Optional) If ``bucket_bound_hostname`` is passed as a bare hostname, use + this value as the scheme. ``https`` will work only when using a CDN. + Defaults to ``"http"``. + + :raises: :exc:`ValueError` when version is invalid. + :raises: :exc:`TypeError` when expiration is not a valid type. + :raises: :exc:`AttributeError` if credentials is not an instance + of :class:`google.auth.credentials.Signing`. + + :rtype: str + :returns: A signed URL you can use to access the resource + until expiration. + """ + if version is None: + version = "v2" + elif version not in ("v2", "v4"): + raise ValueError("'version' must be either 'v2' or 'v4'") + + # If you are on Google Compute Engine, you can't generate a signed URL + # using GCE service account. + # See https://github.com/googleapis/google-auth-library-python/issues/50 + if virtual_hosted_style: + api_access_endpoint = f"https://{self.name}.storage.googleapis.com" + elif bucket_bound_hostname: + api_access_endpoint = _bucket_bound_hostname_url( + bucket_bound_hostname, scheme + ) + else: + resource = f"/{self.name}" + + if virtual_hosted_style or bucket_bound_hostname: + resource = "/" + + if credentials is None: + client = self._require_client(client) + credentials = client._credentials + + if version == "v2": + helper = generate_signed_url_v2 + else: + helper = generate_signed_url_v4 + + return helper( + credentials, + resource=resource, + expiration=expiration, + api_access_endpoint=api_access_endpoint, + method=method.upper(), + headers=headers, + query_parameters=query_parameters, + ) + + +def _raise_if_len_differs(expected_len, **generation_match_args): + """ + Raise an error if any generation match argument + is set and its len differs from the given value. + + :type expected_len: int + :param expected_len: Expected argument length in case it's set. + + :type generation_match_args: dict + :param generation_match_args: Lists, which length must be checked. + + :raises: :exc:`ValueError` if any argument set, but has an unexpected length. + """ + for name, value in generation_match_args.items(): + if value is not None and len(value) != expected_len: + raise ValueError(f"'{name}' length must be the same as 'blobs' length") diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/client.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/client.py new file mode 100644 index 000000000000..56bfa67cfa5a --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/client.py @@ -0,0 +1,1701 @@ +# Copyright 2015 Google LLC +# +# 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. + +"""Client for interacting with the Google Cloud Storage API.""" + +import base64 +import binascii +import collections +import datetime +import functools +import json +import warnings +import google.api_core.client_options + +from google.auth.credentials import AnonymousCredentials + +from google import resumable_media + +from google.api_core import page_iterator +from google.cloud._helpers import _LocalStack, _NOW +from google.cloud.client import ClientWithProject +from google.cloud.exceptions import NotFound +from google.cloud.storage._helpers import _get_default_headers +from google.cloud.storage._helpers import _get_environ_project +from google.cloud.storage._helpers import _get_storage_host +from google.cloud.storage._helpers import _BASE_STORAGE_URI +from google.cloud.storage._helpers import _DEFAULT_STORAGE_HOST +from google.cloud.storage._helpers import _bucket_bound_hostname_url +from google.cloud.storage._helpers import _add_etag_match_headers +from google.cloud.storage._http import Connection +from google.cloud.storage._signing import ( + get_expiration_seconds_v4, + get_v4_now_dtstamps, + ensure_signed_credentials, + _sign_message, +) +from google.cloud.storage.batch import Batch +from google.cloud.storage.bucket import Bucket, _item_to_blob, _blobs_page_start +from google.cloud.storage.blob import ( + Blob, + _get_encryption_headers, + _raise_from_invalid_response, +) +from google.cloud.storage.hmac_key import HMACKeyMetadata +from google.cloud.storage.acl import BucketACL +from google.cloud.storage.acl import DefaultObjectACL +from google.cloud.storage.constants import _DEFAULT_TIMEOUT +from google.cloud.storage.retry import DEFAULT_RETRY +from google.cloud.storage.retry import ConditionalRetryPolicy + + +_marker = object() + + +class Client(ClientWithProject): + """Client to bundle configuration needed for API requests. + + :type project: str or None + :param project: the project which the client acts on behalf of. Will be + passed when creating a topic. If not passed, + falls back to the default inferred from the environment. + + :type credentials: :class:`~google.auth.credentials.Credentials` + :param credentials: (Optional) The OAuth2 Credentials to use for this + client. If not passed (and if no ``_http`` object is + passed), falls back to the default inferred from the + environment. + + :type _http: :class:`~requests.Session` + :param _http: (Optional) HTTP object to make requests. Can be any object + that defines ``request()`` with the same interface as + :meth:`requests.Session.request`. If not passed, an + ``_http`` object is created that is bound to the + ``credentials`` for the current object. + This parameter should be considered private, and could + change in the future. + + :type client_info: :class:`~google.api_core.client_info.ClientInfo` + :param client_info: + The client info used to send a user-agent string along with API + requests. If ``None``, then default info will be used. Generally, + you only need to set this if you're developing your own library + or partner tool. + + :type client_options: :class:`~google.api_core.client_options.ClientOptions` or :class:`dict` + :param client_options: (Optional) Client options used to set user options on the client. + API Endpoint should be set through client_options. + """ + + SCOPE = ( + "https://www.googleapis.com/auth/devstorage.full_control", + "https://www.googleapis.com/auth/devstorage.read_only", + "https://www.googleapis.com/auth/devstorage.read_write", + ) + """The scopes required for authenticating as a Cloud Storage consumer.""" + + def __init__( + self, + project=_marker, + credentials=None, + _http=None, + client_info=None, + client_options=None, + ): + self._base_connection = None + + if project is None: + no_project = True + project = "" + else: + no_project = False + + if project is _marker: + project = None + + kw_args = {"client_info": client_info} + + # `api_endpoint` should be only set by the user via `client_options`, + # or if the _get_storage_host() returns a non-default value. + # `api_endpoint` plays an important role for mTLS, if it is not set, + # then mTLS logic will be applied to decide which endpoint will be used. + storage_host = _get_storage_host() + kw_args["api_endpoint"] = ( + storage_host if storage_host != _DEFAULT_STORAGE_HOST else None + ) + + if client_options: + if type(client_options) == dict: + client_options = google.api_core.client_options.from_dict( + client_options + ) + if client_options.api_endpoint: + api_endpoint = client_options.api_endpoint + kw_args["api_endpoint"] = api_endpoint + + # Use anonymous credentials and no project when + # STORAGE_EMULATOR_HOST or a non-default api_endpoint is set. + if ( + kw_args["api_endpoint"] is not None + and _BASE_STORAGE_URI not in kw_args["api_endpoint"] + ): + if credentials is None: + credentials = AnonymousCredentials() + if project is None: + project = _get_environ_project() + if project is None: + no_project = True + project = "" + + super(Client, self).__init__( + project=project, + credentials=credentials, + client_options=client_options, + _http=_http, + ) + + if no_project: + self.project = None + + self._connection = Connection(self, **kw_args) + self._batch_stack = _LocalStack() + + @classmethod + def create_anonymous_client(cls): + """Factory: return client with anonymous credentials. + + .. note:: + + Such a client has only limited access to "public" buckets: + listing their contents and downloading their blobs. + + :rtype: :class:`google.cloud.storage.client.Client` + :returns: Instance w/ anonymous credentials and no project. + """ + client = cls(project="", credentials=AnonymousCredentials()) + client.project = None + return client + + @property + def _connection(self): + """Get connection or batch on the client. + + :rtype: :class:`google.cloud.storage._http.Connection` + :returns: The connection set on the client, or the batch + if one is set. + """ + if self.current_batch is not None: + return self.current_batch + else: + return self._base_connection + + @_connection.setter + def _connection(self, value): + """Set connection on the client. + + Intended to be used by constructor (since the base class calls) + self._connection = connection + Will raise if the connection is set more than once. + + :type value: :class:`google.cloud.storage._http.Connection` + :param value: The connection set on the client. + + :raises: :class:`ValueError` if connection has already been set. + """ + if self._base_connection is not None: + raise ValueError("Connection already set on client") + self._base_connection = value + + def _push_batch(self, batch): + """Push a batch onto our stack. + + "Protected", intended for use by batch context mgrs. + + :type batch: :class:`google.cloud.storage.batch.Batch` + :param batch: newly-active batch + """ + self._batch_stack.push(batch) + + def _pop_batch(self): + """Pop a batch from our stack. + + "Protected", intended for use by batch context mgrs. + + :raises: IndexError if the stack is empty. + :rtype: :class:`google.cloud.storage.batch.Batch` + :returns: the top-most batch/transaction, after removing it. + """ + return self._batch_stack.pop() + + @property + def current_batch(self): + """Currently-active batch. + + :rtype: :class:`google.cloud.storage.batch.Batch` or ``NoneType`` (if + no batch is active). + :returns: The batch at the top of the batch stack. + """ + return self._batch_stack.top + + def get_service_account_email( + self, project=None, timeout=_DEFAULT_TIMEOUT, retry=DEFAULT_RETRY + ): + """Get the email address of the project's GCS service account + + :type project: str + :param project: + (Optional) Project ID to use for retreiving GCS service account + email address. Defaults to the client's project. + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + + :rtype: str + :returns: service account email address + """ + if project is None: + project = self.project + + path = f"/projects/{project}/serviceAccount" + api_response = self._get_resource(path, timeout=timeout, retry=retry) + return api_response["email_address"] + + def bucket(self, bucket_name, user_project=None): + """Factory constructor for bucket object. + + .. note:: + This will not make an HTTP request; it simply instantiates + a bucket object owned by this client. + + :type bucket_name: str + :param bucket_name: The name of the bucket to be instantiated. + + :type user_project: str + :param user_project: (Optional) The project ID to be billed for API + requests made via the bucket. + + :rtype: :class:`google.cloud.storage.bucket.Bucket` + :returns: The bucket object created. + """ + return Bucket(client=self, name=bucket_name, user_project=user_project) + + def batch(self): + """Factory constructor for batch object. + + .. note:: + This will not make an HTTP request; it simply instantiates + a batch object owned by this client. + + :rtype: :class:`google.cloud.storage.batch.Batch` + :returns: The batch object created. + """ + return Batch(client=self) + + def _get_resource( + self, + path, + query_params=None, + headers=None, + timeout=_DEFAULT_TIMEOUT, + retry=DEFAULT_RETRY, + _target_object=None, + ): + """Helper for bucket / blob methods making API 'GET' calls. + + Args: + path str: + The path of the resource to fetch. + + query_params Optional[dict]: + HTTP query parameters to be passed + + headers Optional[dict]: + HTTP headers to be passed + + timeout (Optional[Union[float, Tuple[float, float]]]): + The amount of time, in seconds, to wait for the server response. + + Can also be passed as a tuple (connect_timeout, read_timeout). + See :meth:`requests.Session.request` documentation for details. + + retry (Optional[Union[google.api_core.retry.Retry, google.cloud.storage.retry.ConditionalRetryPolicy]]): + How to retry the RPC. A None value will disable retries. + A google.api_core.retry.Retry value will enable retries, and the object will + define retriable response codes and errors and configure backoff and timeout options. + + A google.cloud.storage.retry.ConditionalRetryPolicy value wraps a Retry object and + activates it only if certain conditions are met. This class exists to provide safe defaults + for RPC calls that are not technically safe to retry normally (due to potential data + duplication or other side-effects) but become safe to retry if a condition such as + if_metageneration_match is set. + + See the retry.py source code and docstrings in this package (google.cloud.storage.retry) for + information on retry types and how to configure them. + + _target_object (Union[ \ + :class:`~google.cloud.storage.bucket.Bucket`, \ + :class:`~google.cloud.storage.bucket.blob`, \ + ]): + Object to which future data is to be applied -- only relevant + in the context of a batch. + + Returns: + dict + The JSON resource fetched + + Raises: + google.cloud.exceptions.NotFound + If the bucket is not found. + """ + return self._connection.api_request( + method="GET", + path=path, + query_params=query_params, + headers=headers, + timeout=timeout, + retry=retry, + _target_object=_target_object, + ) + + def _list_resource( + self, + path, + item_to_value, + page_token=None, + max_results=None, + extra_params=None, + page_start=page_iterator._do_nothing_page_start, + page_size=None, + timeout=_DEFAULT_TIMEOUT, + retry=DEFAULT_RETRY, + ): + api_request = functools.partial( + self._connection.api_request, timeout=timeout, retry=retry + ) + return page_iterator.HTTPIterator( + client=self, + api_request=api_request, + path=path, + item_to_value=item_to_value, + page_token=page_token, + max_results=max_results, + extra_params=extra_params, + page_start=page_start, + page_size=page_size, + ) + + def _patch_resource( + self, + path, + data, + query_params=None, + headers=None, + timeout=_DEFAULT_TIMEOUT, + retry=None, + _target_object=None, + ): + """Helper for bucket / blob methods making API 'PATCH' calls. + + Args: + path str: + The path of the resource to fetch. + + data dict: + The data to be patched. + + query_params Optional[dict]: + HTTP query parameters to be passed + + headers Optional[dict]: + HTTP headers to be passed + + timeout (Optional[Union[float, Tuple[float, float]]]): + The amount of time, in seconds, to wait for the server response. + + Can also be passed as a tuple (connect_timeout, read_timeout). + See :meth:`requests.Session.request` documentation for details. + + retry (Optional[Union[google.api_core.retry.Retry, google.cloud.storage.retry.ConditionalRetryPolicy]]): + How to retry the RPC. A None value will disable retries. + A google.api_core.retry.Retry value will enable retries, and the object will + define retriable response codes and errors and configure backoff and timeout options. + + A google.cloud.storage.retry.ConditionalRetryPolicy value wraps a Retry object and + activates it only if certain conditions are met. This class exists to provide safe defaults + for RPC calls that are not technically safe to retry normally (due to potential data + duplication or other side-effects) but become safe to retry if a condition such as + if_metageneration_match is set. + + See the retry.py source code and docstrings in this package (google.cloud.storage.retry) for + information on retry types and how to configure them. + + _target_object (Union[ \ + :class:`~google.cloud.storage.bucket.Bucket`, \ + :class:`~google.cloud.storage.bucket.blob`, \ + ]): + Object to which future data is to be applied -- only relevant + in the context of a batch. + + Returns: + dict + The JSON resource fetched + + Raises: + google.cloud.exceptions.NotFound + If the bucket is not found. + """ + return self._connection.api_request( + method="PATCH", + path=path, + data=data, + query_params=query_params, + headers=headers, + timeout=timeout, + retry=retry, + _target_object=_target_object, + ) + + def _put_resource( + self, + path, + data, + query_params=None, + headers=None, + timeout=_DEFAULT_TIMEOUT, + retry=None, + _target_object=None, + ): + """Helper for bucket / blob methods making API 'PUT' calls. + + Args: + path str: + The path of the resource to fetch. + + data dict: + The data to be patched. + + query_params Optional[dict]: + HTTP query parameters to be passed + + headers Optional[dict]: + HTTP headers to be passed + + timeout (Optional[Union[float, Tuple[float, float]]]): + The amount of time, in seconds, to wait for the server response. + + Can also be passed as a tuple (connect_timeout, read_timeout). + See :meth:`requests.Session.request` documentation for details. + + retry (Optional[Union[google.api_core.retry.Retry, google.cloud.storage.retry.ConditionalRetryPolicy]]): + How to retry the RPC. A None value will disable retries. + A google.api_core.retry.Retry value will enable retries, and the object will + define retriable response codes and errors and configure backoff and timeout options. + + A google.cloud.storage.retry.ConditionalRetryPolicy value wraps a Retry object and + activates it only if certain conditions are met. This class exists to provide safe defaults + for RPC calls that are not technically safe to retry normally (due to potential data + duplication or other side-effects) but become safe to retry if a condition such as + if_metageneration_match is set. + + See the retry.py source code and docstrings in this package (google.cloud.storage.retry) for + information on retry types and how to configure them. + + _target_object (Union[ \ + :class:`~google.cloud.storage.bucket.Bucket`, \ + :class:`~google.cloud.storage.bucket.blob`, \ + ]): + Object to which future data is to be applied -- only relevant + in the context of a batch. + + Returns: + dict + The JSON resource fetched + + Raises: + google.cloud.exceptions.NotFound + If the bucket is not found. + """ + return self._connection.api_request( + method="PUT", + path=path, + data=data, + query_params=query_params, + headers=headers, + timeout=timeout, + retry=retry, + _target_object=_target_object, + ) + + def _post_resource( + self, + path, + data, + query_params=None, + headers=None, + timeout=_DEFAULT_TIMEOUT, + retry=None, + _target_object=None, + ): + """Helper for bucket / blob methods making API 'POST' calls. + + Args: + path str: + The path of the resource to which to post. + + data dict: + The data to be posted. + + query_params Optional[dict]: + HTTP query parameters to be passed + + headers Optional[dict]: + HTTP headers to be passed + + timeout (Optional[Union[float, Tuple[float, float]]]): + The amount of time, in seconds, to wait for the server response. + + Can also be passed as a tuple (connect_timeout, read_timeout). + See :meth:`requests.Session.request` documentation for details. + + retry (Optional[Union[google.api_core.retry.Retry, google.cloud.storage.retry.ConditionalRetryPolicy]]): + How to retry the RPC. A None value will disable retries. + A google.api_core.retry.Retry value will enable retries, and the object will + define retriable response codes and errors and configure backoff and timeout options. + + A google.cloud.storage.retry.ConditionalRetryPolicy value wraps a Retry object and + activates it only if certain conditions are met. This class exists to provide safe defaults + for RPC calls that are not technically safe to retry normally (due to potential data + duplication or other side-effects) but become safe to retry if a condition such as + if_metageneration_match is set. + + See the retry.py source code and docstrings in this package (google.cloud.storage.retry) for + information on retry types and how to configure them. + + _target_object (Union[ \ + :class:`~google.cloud.storage.bucket.Bucket`, \ + :class:`~google.cloud.storage.bucket.blob`, \ + ]): + Object to which future data is to be applied -- only relevant + in the context of a batch. + + Returns: + dict + The JSON resource returned from the post. + + Raises: + google.cloud.exceptions.NotFound + If the bucket is not found. + """ + + return self._connection.api_request( + method="POST", + path=path, + data=data, + query_params=query_params, + headers=headers, + timeout=timeout, + retry=retry, + _target_object=_target_object, + ) + + def _delete_resource( + self, + path, + query_params=None, + headers=None, + timeout=_DEFAULT_TIMEOUT, + retry=DEFAULT_RETRY, + _target_object=None, + ): + """Helper for bucket / blob methods making API 'DELETE' calls. + + Args: + path str: + The path of the resource to delete. + + query_params Optional[dict]: + HTTP query parameters to be passed + + headers Optional[dict]: + HTTP headers to be passed + + timeout (Optional[Union[float, Tuple[float, float]]]): + The amount of time, in seconds, to wait for the server response. + + Can also be passed as a tuple (connect_timeout, read_timeout). + See :meth:`requests.Session.request` documentation for details. + + retry (Optional[Union[google.api_core.retry.Retry, google.cloud.storage.retry.ConditionalRetryPolicy]]): + How to retry the RPC. A None value will disable retries. + A google.api_core.retry.Retry value will enable retries, and the object will + define retriable response codes and errors and configure backoff and timeout options. + + A google.cloud.storage.retry.ConditionalRetryPolicy value wraps a Retry object and + activates it only if certain conditions are met. This class exists to provide safe defaults + for RPC calls that are not technically safe to retry normally (due to potential data + duplication or other side-effects) but become safe to retry if a condition such as + if_metageneration_match is set. + + See the retry.py source code and docstrings in this package (google.cloud.storage.retry) for + information on retry types and how to configure them. + + _target_object (Union[ \ + :class:`~google.cloud.storage.bucket.Bucket`, \ + :class:`~google.cloud.storage.bucket.blob`, \ + ]): + Object to which future data is to be applied -- only relevant + in the context of a batch. + + Returns: + dict + The JSON resource fetched + + Raises: + google.cloud.exceptions.NotFound + If the bucket is not found. + """ + return self._connection.api_request( + method="DELETE", + path=path, + query_params=query_params, + headers=headers, + timeout=timeout, + retry=retry, + _target_object=_target_object, + ) + + def _bucket_arg_to_bucket(self, bucket_or_name): + """Helper to return given bucket or create new by name. + + Args: + bucket_or_name (Union[ \ + :class:`~google.cloud.storage.bucket.Bucket`, \ + str, \ + ]): + The bucket resource to pass or name to create. + + Returns: + google.cloud.storage.bucket.Bucket + The newly created bucket or the given one. + """ + if isinstance(bucket_or_name, Bucket): + bucket = bucket_or_name + if bucket.client is None: + bucket._client = self + else: + bucket = Bucket(self, name=bucket_or_name) + return bucket + + def get_bucket( + self, + bucket_or_name, + timeout=_DEFAULT_TIMEOUT, + if_metageneration_match=None, + if_metageneration_not_match=None, + retry=DEFAULT_RETRY, + ): + """Retrieve a bucket via a GET request. + + See [API reference docs](https://cloud.google.com/storage/docs/json_api/v1/buckets/get) and a [code sample](https://cloud.google.com/storage/docs/samples/storage-get-bucket-metadata#storage_get_bucket_metadata-python). + + Args: + bucket_or_name (Union[ \ + :class:`~google.cloud.storage.bucket.Bucket`, \ + str, \ + ]): + The bucket resource to pass or name to create. + + timeout (Optional[Union[float, Tuple[float, float]]]): + The amount of time, in seconds, to wait for the server response. + + Can also be passed as a tuple (connect_timeout, read_timeout). + See :meth:`requests.Session.request` documentation for details. + + if_metageneration_match (Optional[long]): + Make the operation conditional on whether the + blob's current metageneration matches the given value. + + if_metageneration_not_match (Optional[long]): + Make the operation conditional on whether the blob's + current metageneration does not match the given value. + + retry (Optional[Union[google.api_core.retry.Retry, google.cloud.storage.retry.ConditionalRetryPolicy]]): + How to retry the RPC. A None value will disable retries. + A google.api_core.retry.Retry value will enable retries, and the object will + define retriable response codes and errors and configure backoff and timeout options. + + A google.cloud.storage.retry.ConditionalRetryPolicy value wraps a Retry object and + activates it only if certain conditions are met. This class exists to provide safe defaults + for RPC calls that are not technically safe to retry normally (due to potential data + duplication or other side-effects) but become safe to retry if a condition such as + if_metageneration_match is set. + + See the retry.py source code and docstrings in this package (google.cloud.storage.retry) for + information on retry types and how to configure them. + + Returns: + google.cloud.storage.bucket.Bucket + The bucket matching the name provided. + + Raises: + google.cloud.exceptions.NotFound + If the bucket is not found. + """ + bucket = self._bucket_arg_to_bucket(bucket_or_name) + bucket.reload( + client=self, + timeout=timeout, + if_metageneration_match=if_metageneration_match, + if_metageneration_not_match=if_metageneration_not_match, + retry=retry, + ) + return bucket + + def lookup_bucket( + self, + bucket_name, + timeout=_DEFAULT_TIMEOUT, + if_metageneration_match=None, + if_metageneration_not_match=None, + retry=DEFAULT_RETRY, + ): + """Get a bucket by name, returning None if not found. + + You can use this if you would rather check for a None value + than catching a NotFound exception. + + :type bucket_name: str + :param bucket_name: The name of the bucket to get. + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type if_metageneration_match: long + :param if_metageneration_match: (Optional) Make the operation conditional on whether the + blob's current metageneration matches the given value. + + :type if_metageneration_not_match: long + :param if_metageneration_not_match: (Optional) Make the operation conditional on whether the + blob's current metageneration does not match the given value. + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + + :rtype: :class:`google.cloud.storage.bucket.Bucket` or ``NoneType`` + :returns: The bucket matching the name provided or None if not found. + """ + try: + return self.get_bucket( + bucket_name, + timeout=timeout, + if_metageneration_match=if_metageneration_match, + if_metageneration_not_match=if_metageneration_not_match, + retry=retry, + ) + except NotFound: + return None + + def create_bucket( + self, + bucket_or_name, + requester_pays=None, + project=None, + user_project=None, + location=None, + data_locations=None, + predefined_acl=None, + predefined_default_object_acl=None, + timeout=_DEFAULT_TIMEOUT, + retry=DEFAULT_RETRY, + ): + """Create a new bucket via a POST request. + + See [API reference docs](https://cloud.google.com/storage/docs/json_api/v1/buckets/insert) and a [code sample](https://cloud.google.com/storage/docs/samples/storage-create-bucket#storage_create_bucket-python). + + Args: + bucket_or_name (Union[ \ + :class:`~google.cloud.storage.bucket.Bucket`, \ + str, \ + ]): + The bucket resource to pass or name to create. + requester_pays (bool): + DEPRECATED. Use Bucket().requester_pays instead. + (Optional) Whether requester pays for API requests for + this bucket and its blobs. + project (str): + (Optional) The project under which the bucket is to be created. + If not passed, uses the project set on the client. + user_project (str): + (Optional) The project ID to be billed for API requests + made via created bucket. + location (str): + (Optional) The location of the bucket. If not passed, + the default location, US, will be used. If specifying a dual-region, + `data_locations` should be set in conjunction. See: + https://cloud.google.com/storage/docs/locations + data_locations (list of str): + (Optional) The list of regional locations of a custom dual-region bucket. + Dual-regions require exactly 2 regional locations. See: + https://cloud.google.com/storage/docs/locations + predefined_acl (str): + (Optional) Name of predefined ACL to apply to bucket. See: + https://cloud.google.com/storage/docs/access-control/lists#predefined-acl + predefined_default_object_acl (str): + (Optional) Name of predefined ACL to apply to bucket's objects. See: + https://cloud.google.com/storage/docs/access-control/lists#predefined-acl + timeout (Optional[Union[float, Tuple[float, float]]]): + The amount of time, in seconds, to wait for the server response. + + Can also be passed as a tuple (connect_timeout, read_timeout). + See :meth:`requests.Session.request` documentation for details. + + retry (Optional[Union[google.api_core.retry.Retry, google.cloud.storage.retry.ConditionalRetryPolicy]]): + How to retry the RPC. A None value will disable retries. + A google.api_core.retry.Retry value will enable retries, and the object will + define retriable response codes and errors and configure backoff and timeout options. + + A google.cloud.storage.retry.ConditionalRetryPolicy value wraps a Retry object and + activates it only if certain conditions are met. This class exists to provide safe defaults + for RPC calls that are not technically safe to retry normally (due to potential data + duplication or other side-effects) but become safe to retry if a condition such as + if_metageneration_match is set. + + See the retry.py source code and docstrings in this package (google.cloud.storage.retry) for + information on retry types and how to configure them. + + Returns: + google.cloud.storage.bucket.Bucket + The newly created bucket. + + Raises: + google.cloud.exceptions.Conflict + If the bucket already exists. + """ + bucket = self._bucket_arg_to_bucket(bucket_or_name) + query_params = {} + + if project is None: + project = self.project + + # Use no project if STORAGE_EMULATOR_HOST is set + if _BASE_STORAGE_URI not in _get_storage_host(): + if project is None: + project = _get_environ_project() + if project is None: + project = "" + + # Only include the project parameter if a project is set. + # If a project is not set, falls back to API validation (BadRequest). + if project is not None: + query_params = {"project": project} + + if requester_pays is not None: + warnings.warn( + "requester_pays arg is deprecated. Use Bucket().requester_pays instead.", + PendingDeprecationWarning, + stacklevel=1, + ) + bucket.requester_pays = requester_pays + + if predefined_acl is not None: + predefined_acl = BucketACL.validate_predefined(predefined_acl) + query_params["predefinedAcl"] = predefined_acl + + if predefined_default_object_acl is not None: + predefined_default_object_acl = DefaultObjectACL.validate_predefined( + predefined_default_object_acl + ) + query_params["predefinedDefaultObjectAcl"] = predefined_default_object_acl + + if user_project is not None: + query_params["userProject"] = user_project + + properties = {key: bucket._properties[key] for key in bucket._changes} + properties["name"] = bucket.name + + if location is not None: + properties["location"] = location + + if data_locations is not None: + properties["customPlacementConfig"] = {"dataLocations": data_locations} + + api_response = self._post_resource( + "/b", + properties, + query_params=query_params, + timeout=timeout, + retry=retry, + _target_object=bucket, + ) + + bucket._set_properties(api_response) + return bucket + + def download_blob_to_file( + self, + blob_or_uri, + file_obj, + start=None, + end=None, + raw_download=False, + if_etag_match=None, + if_etag_not_match=None, + if_generation_match=None, + if_generation_not_match=None, + if_metageneration_match=None, + if_metageneration_not_match=None, + timeout=_DEFAULT_TIMEOUT, + checksum="md5", + retry=DEFAULT_RETRY, + ): + """Download the contents of a blob object or blob URI into a file-like object. + + See https://cloud.google.com/storage/docs/downloading-objects + + Args: + blob_or_uri (Union[ \ + :class:`~google.cloud.storage.blob.Blob`, \ + str, \ + ]): + The blob resource to pass or URI to download. + + file_obj (file): + A file handle to which to write the blob's data. + + start (int): + (Optional) The first byte in a range to be downloaded. + + end (int): + (Optional) The last byte in a range to be downloaded. + + raw_download (bool): + (Optional) If true, download the object without any expansion. + + if_etag_match (Union[str, Set[str]]): + (Optional) See :ref:`using-if-etag-match` + + if_etag_not_match (Union[str, Set[str]]): + (Optional) See :ref:`using-if-etag-not-match` + + if_generation_match (long): + (Optional) See :ref:`using-if-generation-match` + + if_generation_not_match (long): + (Optional) See :ref:`using-if-generation-not-match` + + if_metageneration_match (long): + (Optional) See :ref:`using-if-metageneration-match` + + if_metageneration_not_match (long): + (Optional) See :ref:`using-if-metageneration-not-match` + + timeout ([Union[float, Tuple[float, float]]]): + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + checksum (str): + (Optional) The type of checksum to compute to verify the integrity + of the object. The response headers must contain a checksum of the + requested type. If the headers lack an appropriate checksum (for + instance in the case of transcoded or ranged downloads where the + remote service does not know the correct checksum, including + downloads where chunk_size is set) an INFO-level log will be + emitted. Supported values are "md5", "crc32c" and None. The default + is "md5". + retry (google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy) + (Optional) How to retry the RPC. A None value will disable + retries. A google.api_core.retry.Retry value will enable retries, + and the object will define retriable response codes and errors and + configure backoff and timeout options. + + A google.cloud.storage.retry.ConditionalRetryPolicy value wraps a + Retry object and activates it only if certain conditions are met. + This class exists to provide safe defaults for RPC calls that are + not technically safe to retry normally (due to potential data + duplication or other side-effects) but become safe to retry if a + condition such as if_metageneration_match is set. + + See the retry.py source code and docstrings in this package + (google.cloud.storage.retry) for information on retry types and how + to configure them. + + Media operations (downloads and uploads) do not support non-default + predicates in a Retry object. The default will always be used. Other + configuration changes for Retry objects such as delays and deadlines + are respected. + """ + + # Handle ConditionalRetryPolicy. + if isinstance(retry, ConditionalRetryPolicy): + # Conditional retries are designed for non-media calls, which change + # arguments into query_params dictionaries. Media operations work + # differently, so here we make a "fake" query_params to feed to the + # ConditionalRetryPolicy. + query_params = { + "ifGenerationMatch": if_generation_match, + "ifMetagenerationMatch": if_metageneration_match, + } + retry = retry.get_retry_policy_if_conditions_met(query_params=query_params) + + if not isinstance(blob_or_uri, Blob): + blob_or_uri = Blob.from_string(blob_or_uri) + download_url = blob_or_uri._get_download_url( + self, + if_generation_match=if_generation_match, + if_generation_not_match=if_generation_not_match, + if_metageneration_match=if_metageneration_match, + if_metageneration_not_match=if_metageneration_not_match, + ) + headers = _get_encryption_headers(blob_or_uri._encryption_key) + headers["accept-encoding"] = "gzip" + _add_etag_match_headers( + headers, + if_etag_match=if_etag_match, + if_etag_not_match=if_etag_not_match, + ) + headers = {**_get_default_headers(self._connection.user_agent), **headers} + + transport = self._http + try: + blob_or_uri._do_download( + transport, + file_obj, + download_url, + headers, + start, + end, + raw_download, + timeout=timeout, + checksum=checksum, + retry=retry, + ) + except resumable_media.InvalidResponse as exc: + _raise_from_invalid_response(exc) + + def list_blobs( + self, + bucket_or_name, + max_results=None, + page_token=None, + prefix=None, + delimiter=None, + start_offset=None, + end_offset=None, + include_trailing_delimiter=None, + versions=None, + projection="noAcl", + fields=None, + page_size=None, + timeout=_DEFAULT_TIMEOUT, + retry=DEFAULT_RETRY, + ): + """Return an iterator used to find blobs in the bucket. + + If :attr:`user_project` is set, bills the API request to that project. + + .. note:: + List prefixes (directories) in a bucket using a prefix and delimiter. + See a [code sample](https://cloud.google.com/storage/docs/samples/storage-list-files-with-prefix#storage_list_files_with_prefix-python) + listing objects using a prefix filter. + + Args: + bucket_or_name (Union[ \ + :class:`~google.cloud.storage.bucket.Bucket`, \ + str, \ + ]): + The bucket resource to pass or name to create. + + max_results (int): + (Optional) The maximum number of blobs to return. + + page_token (str): + (Optional) If present, return the next batch of blobs, using the + value, which must correspond to the ``nextPageToken`` value + returned in the previous response. Deprecated: use the ``pages`` + property of the returned iterator instead of manually passing the + token. + + prefix (str): + (Optional) Prefix used to filter blobs. + + delimiter (str): + (Optional) Delimiter, used with ``prefix`` to + emulate hierarchy. + + start_offset (str): + (Optional) Filter results to objects whose names are + lexicographically equal to or after ``startOffset``. If + ``endOffset`` is also set, the objects listed will have names + between ``startOffset`` (inclusive) and ``endOffset`` + (exclusive). + + end_offset (str): + (Optional) Filter results to objects whose names are + lexicographically before ``endOffset``. If ``startOffset`` is + also set, the objects listed will have names between + ``startOffset`` (inclusive) and ``endOffset`` (exclusive). + + include_trailing_delimiter (boolean): + (Optional) If true, objects that end in exactly one instance of + ``delimiter`` will have their metadata included in ``items`` in + addition to ``prefixes``. + + versions (bool): + (Optional) Whether object versions should be returned + as separate blobs. + + projection (str): + (Optional) If used, must be 'full' or 'noAcl'. + Defaults to ``'noAcl'``. Specifies the set of + properties to return. + + fields (str): + (Optional) Selector specifying which fields to include + in a partial response. Must be a list of fields. For + example to get a partial response with just the next + page token and the name and language of each blob returned: + ``'items(name,contentLanguage),nextPageToken'``. + See: https://cloud.google.com/storage/docs/json_api/v1/parameters#fields + + page_size (int): + (Optional) Maximum number of blobs to return in each page. + Defaults to a value set by the API. + + timeout (Optional[Union[float, Tuple[float, float]]]): + The amount of time, in seconds, to wait for the server response. + + Can also be passed as a tuple (connect_timeout, read_timeout). + See :meth:`requests.Session.request` documentation for details. + + retry (Optional[Union[google.api_core.retry.Retry, google.cloud.storage.retry.ConditionalRetryPolicy]]): + How to retry the RPC. A None value will disable retries. + A google.api_core.retry.Retry value will enable retries, and the object will + define retriable response codes and errors and configure backoff and timeout options. + + A google.cloud.storage.retry.ConditionalRetryPolicy value wraps a Retry object and + activates it only if certain conditions are met. This class exists to provide safe defaults + for RPC calls that are not technically safe to retry normally (due to potential data + duplication or other side-effects) but become safe to retry if a condition such as + if_metageneration_match is set. + + See the retry.py source code and docstrings in this package (google.cloud.storage.retry) for + information on retry types and how to configure them. + + Returns: + Iterator of all :class:`~google.cloud.storage.blob.Blob` + in this bucket matching the arguments. The RPC call + returns a response when the iterator is consumed. + + As part of the response, you'll also get back an iterator.prefixes entity that lists object names + up to and including the requested delimiter. Duplicate entries are omitted from this list. + """ + bucket = self._bucket_arg_to_bucket(bucket_or_name) + + extra_params = {"projection": projection} + + if prefix is not None: + extra_params["prefix"] = prefix + + if delimiter is not None: + extra_params["delimiter"] = delimiter + + if start_offset is not None: + extra_params["startOffset"] = start_offset + + if end_offset is not None: + extra_params["endOffset"] = end_offset + + if include_trailing_delimiter is not None: + extra_params["includeTrailingDelimiter"] = include_trailing_delimiter + + if versions is not None: + extra_params["versions"] = versions + + if fields is not None: + extra_params["fields"] = fields + + if bucket.user_project is not None: + extra_params["userProject"] = bucket.user_project + + path = bucket.path + "/o" + iterator = self._list_resource( + path, + _item_to_blob, + page_token=page_token, + max_results=max_results, + extra_params=extra_params, + page_start=_blobs_page_start, + page_size=page_size, + timeout=timeout, + retry=retry, + ) + iterator.bucket = bucket + iterator.prefixes = set() + return iterator + + def list_buckets( + self, + max_results=None, + page_token=None, + prefix=None, + projection="noAcl", + fields=None, + project=None, + page_size=None, + timeout=_DEFAULT_TIMEOUT, + retry=DEFAULT_RETRY, + ): + """Get all buckets in the project associated to the client. + + This will not populate the list of blobs available in each + bucket. + + See [API reference docs](https://cloud.google.com/storage/docs/json_api/v1/buckets/list) and a [code sample](https://cloud.google.com/storage/docs/samples/storage-list-buckets#storage_list_buckets-python). + + :type max_results: int + :param max_results: (Optional) The maximum number of buckets to return. + + :type page_token: str + :param page_token: + (Optional) If present, return the next batch of buckets, using the + value, which must correspond to the ``nextPageToken`` value + returned in the previous response. Deprecated: use the ``pages`` + property of the returned iterator instead of manually passing the + token. + + :type prefix: str + :param prefix: (Optional) Filter results to buckets whose names begin + with this prefix. + + :type projection: str + :param projection: + (Optional) Specifies the set of properties to return. If used, must + be 'full' or 'noAcl'. Defaults to 'noAcl'. + + :type fields: str + :param fields: + (Optional) Selector specifying which fields to include in a partial + response. Must be a list of fields. For example to get a partial + response with just the next page token and the language of each + bucket returned: 'items/id,nextPageToken' + + :type project: str + :param project: (Optional) The project whose buckets are to be listed. + If not passed, uses the project set on the client. + + :type page_size: int + :param page_size: (Optional) Maximum number of buckets to return in each page. + Defaults to a value set by the API. + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + + :rtype: :class:`~google.api_core.page_iterator.Iterator` + :raises ValueError: if both ``project`` is ``None`` and the client's + project is also ``None``. + :returns: Iterator of all :class:`~google.cloud.storage.bucket.Bucket` + belonging to this project. + """ + extra_params = {} + + if project is None: + project = self.project + + # Use no project if STORAGE_EMULATOR_HOST is set + if _BASE_STORAGE_URI not in _get_storage_host(): + if project is None: + project = _get_environ_project() + if project is None: + project = "" + + # Only include the project parameter if a project is set. + # If a project is not set, falls back to API validation (BadRequest). + if project is not None: + extra_params = {"project": project} + + if prefix is not None: + extra_params["prefix"] = prefix + + extra_params["projection"] = projection + + if fields is not None: + extra_params["fields"] = fields + + return self._list_resource( + "/b", + _item_to_bucket, + page_token=page_token, + max_results=max_results, + extra_params=extra_params, + page_size=page_size, + timeout=timeout, + retry=retry, + ) + + def create_hmac_key( + self, + service_account_email, + project_id=None, + user_project=None, + timeout=_DEFAULT_TIMEOUT, + retry=None, + ): + """Create an HMAC key for a service account. + + :type service_account_email: str + :param service_account_email: e-mail address of the service account + + :type project_id: str + :param project_id: (Optional) Explicit project ID for the key. + Defaults to the client's project. + + :type user_project: str + :param user_project: (Optional) This parameter is currently ignored. + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: (Optional) How to retry the RPC. A None value will disable retries. + A google.api_core.retry.Retry value will enable retries, and the object will + define retriable response codes and errors and configure backoff and timeout options. + + A google.cloud.storage.retry.ConditionalRetryPolicy value wraps a Retry object and + activates it only if certain conditions are met. This class exists to provide safe defaults + for RPC calls that are not technically safe to retry normally (due to potential data + duplication or other side-effects) but become safe to retry if a condition such as + if_metageneration_match is set. + + See the retry.py source code and docstrings in this package (google.cloud.storage.retry) for + information on retry types and how to configure them. + + :rtype: + Tuple[:class:`~google.cloud.storage.hmac_key.HMACKeyMetadata`, str] + :returns: metadata for the created key, plus the bytes of the key's secret, which is an 40-character base64-encoded string. + """ + if project_id is None: + project_id = self.project + + path = f"/projects/{project_id}/hmacKeys" + qs_params = {"serviceAccountEmail": service_account_email} + + if user_project is not None: + qs_params["userProject"] = user_project + + api_response = self._post_resource( + path, + None, + query_params=qs_params, + timeout=timeout, + retry=retry, + ) + metadata = HMACKeyMetadata(self) + metadata._properties = api_response["metadata"] + secret = api_response["secret"] + return metadata, secret + + def list_hmac_keys( + self, + max_results=None, + service_account_email=None, + show_deleted_keys=None, + project_id=None, + user_project=None, + timeout=_DEFAULT_TIMEOUT, + retry=DEFAULT_RETRY, + ): + """List HMAC keys for a project. + + :type max_results: int + :param max_results: + (Optional) Max number of keys to return in a given page. + + :type service_account_email: str + :param service_account_email: + (Optional) Limit keys to those created by the given service account. + + :type show_deleted_keys: bool + :param show_deleted_keys: + (Optional) Included deleted keys in the list. Default is to + exclude them. + + :type project_id: str + :param project_id: (Optional) Explicit project ID for the key. + Defaults to the client's project. + + :type user_project: str + :param user_project: (Optional) This parameter is currently ignored. + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + + :rtype: + Tuple[:class:`~google.cloud.storage.hmac_key.HMACKeyMetadata`, str] + :returns: metadata for the created key, plus the bytes of the key's secret, which is an 40-character base64-encoded string. + """ + if project_id is None: + project_id = self.project + + path = f"/projects/{project_id}/hmacKeys" + extra_params = {} + + if service_account_email is not None: + extra_params["serviceAccountEmail"] = service_account_email + + if show_deleted_keys is not None: + extra_params["showDeletedKeys"] = show_deleted_keys + + if user_project is not None: + extra_params["userProject"] = user_project + + return self._list_resource( + path, + _item_to_hmac_key_metadata, + max_results=max_results, + extra_params=extra_params, + timeout=timeout, + retry=retry, + ) + + def get_hmac_key_metadata( + self, access_id, project_id=None, user_project=None, timeout=_DEFAULT_TIMEOUT + ): + """Return a metadata instance for the given HMAC key. + + :type access_id: str + :param access_id: Unique ID of an existing key. + + :type project_id: str + :param project_id: (Optional) Project ID of an existing key. + Defaults to client's project. + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type user_project: str + :param user_project: (Optional) This parameter is currently ignored. + """ + metadata = HMACKeyMetadata(self, access_id, project_id, user_project) + metadata.reload(timeout=timeout) # raises NotFound for missing key + return metadata + + def generate_signed_post_policy_v4( + self, + bucket_name, + blob_name, + expiration, + conditions=None, + fields=None, + credentials=None, + virtual_hosted_style=False, + bucket_bound_hostname=None, + scheme="http", + service_account_email=None, + access_token=None, + ): + """Generate a V4 signed policy object. Generated policy object allows user to upload objects with a POST request. + + .. note:: + + Assumes ``credentials`` implements the + :class:`google.auth.credentials.Signing` interface. Also assumes + ``credentials`` has a ``service_account_email`` property which + identifies the credentials. + + See a [code sample](https://github.com/googleapis/python-storage/blob/main/samples/snippets/storage_generate_signed_post_policy_v4.py). + + :type bucket_name: str + :param bucket_name: Bucket name. + + :type blob_name: str + :param blob_name: Object name. + + :type expiration: Union[Integer, datetime.datetime, datetime.timedelta] + :param expiration: Policy expiration time. If a ``datetime`` instance is + passed without an explicit ``tzinfo`` set, it will be + assumed to be ``UTC``. + + :type conditions: list + :param conditions: (Optional) List of POST policy conditions, which are + used to restrict what is allowed in the request. + + :type fields: dict + :param fields: (Optional) Additional elements to include into request. + + :type credentials: :class:`google.auth.credentials.Signing` + :param credentials: (Optional) Credentials object with an associated private + key to sign text. + + :type virtual_hosted_style: bool + :param virtual_hosted_style: (Optional) If True, construct the URL relative to the bucket + virtual hostname, e.g., '.storage.googleapis.com'. + + :type bucket_bound_hostname: str + :param bucket_bound_hostname: + (Optional) If passed, construct the URL relative to the bucket-bound hostname. + Value can be bare or with a scheme, e.g., 'example.com' or 'http://example.com'. + See: https://cloud.google.com/storage/docs/request-endpoints#cname + + :type scheme: str + :param scheme: + (Optional) If ``bucket_bound_hostname`` is passed as a bare hostname, use + this value as a scheme. ``https`` will work only when using a CDN. + Defaults to ``"http"``. + + :type service_account_email: str + :param service_account_email: (Optional) E-mail address of the service account. + + :type access_token: str + :param access_token: (Optional) Access token for a service account. + + :rtype: dict + :returns: Signed POST policy. + """ + credentials = self._credentials if credentials is None else credentials + ensure_signed_credentials(credentials) + + # prepare policy conditions and fields + timestamp, datestamp = get_v4_now_dtstamps() + + x_goog_credential = "{email}/{datestamp}/auto/storage/goog4_request".format( + email=credentials.signer_email, datestamp=datestamp + ) + required_conditions = [ + {"bucket": bucket_name}, + {"key": blob_name}, + {"x-goog-date": timestamp}, + {"x-goog-credential": x_goog_credential}, + {"x-goog-algorithm": "GOOG4-RSA-SHA256"}, + ] + + conditions = conditions or [] + policy_fields = {} + for key, value in sorted((fields or {}).items()): + if not key.startswith("x-ignore-"): + policy_fields[key] = value + conditions.append({key: value}) + + conditions += required_conditions + + # calculate policy expiration time + now = _NOW() + if expiration is None: + expiration = now + datetime.timedelta(hours=1) + + policy_expires = now + datetime.timedelta( + seconds=get_expiration_seconds_v4(expiration) + ) + + # encode policy for signing + policy = json.dumps( + collections.OrderedDict( + sorted( + { + "conditions": conditions, + "expiration": policy_expires.isoformat() + "Z", + }.items() + ) + ), + separators=(",", ":"), + ) + str_to_sign = base64.b64encode(policy.encode("utf-8")) + + # sign the policy and get its cryptographic signature + if access_token and service_account_email: + signature = _sign_message(str_to_sign, access_token, service_account_email) + signature_bytes = base64.b64decode(signature) + else: + signature_bytes = credentials.sign_bytes(str_to_sign) + + # get hexadecimal representation of the signature + signature = binascii.hexlify(signature_bytes).decode("utf-8") + + policy_fields.update( + { + "key": blob_name, + "x-goog-algorithm": "GOOG4-RSA-SHA256", + "x-goog-credential": x_goog_credential, + "x-goog-date": timestamp, + "x-goog-signature": signature, + "policy": str_to_sign.decode("utf-8"), + } + ) + # designate URL + if virtual_hosted_style: + url = f"https://{bucket_name}.storage.googleapis.com/" + elif bucket_bound_hostname: + url = f"{_bucket_bound_hostname_url(bucket_bound_hostname, scheme)}/" + else: + url = f"https://storage.googleapis.com/{bucket_name}/" + + return {"url": url, "fields": policy_fields} + + +def _item_to_bucket(iterator, item): + """Convert a JSON bucket to the native object. + + :type iterator: :class:`~google.api_core.page_iterator.Iterator` + :param iterator: The iterator that has retrieved the item. + + :type item: dict + :param item: An item to be converted to a bucket. + + :rtype: :class:`.Bucket` + :returns: The next bucket in the page. + """ + name = item.get("name") + bucket = Bucket(iterator.client, name) + bucket._set_properties(item) + return bucket + + +def _item_to_hmac_key_metadata(iterator, item): + """Convert a JSON key metadata resource to the native object. + + :type iterator: :class:`~google.api_core.page_iterator.Iterator` + :param iterator: The iterator that has retrieved the item. + + :type item: dict + :param item: An item to be converted to a key metadata instance. + + :rtype: :class:`~google.cloud.storage.hmac_key.HMACKeyMetadata` + :returns: The next key metadata instance in the page. + """ + metadata = HMACKeyMetadata(iterator.client) + metadata._properties = item + return metadata diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/constants.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/constants.py new file mode 100644 index 000000000000..5d649729523d --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/constants.py @@ -0,0 +1,134 @@ +# Copyright 2019 Google LLC +# +# 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. + +"""Constants used across google.cloud.storage modules.""" + +# Storage classes + +STANDARD_STORAGE_CLASS = "STANDARD" +"""Storage class for objects accessed more than once per month. + +See: https://cloud.google.com/storage/docs/storage-classes +""" + +NEARLINE_STORAGE_CLASS = "NEARLINE" +"""Storage class for objects accessed at most once per month. + +See: https://cloud.google.com/storage/docs/storage-classes +""" + +COLDLINE_STORAGE_CLASS = "COLDLINE" +"""Storage class for objects accessed at most once per year. + +See: https://cloud.google.com/storage/docs/storage-classes +""" + +ARCHIVE_STORAGE_CLASS = "ARCHIVE" +"""Storage class for objects accessed less frequently than once per year. + +See: https://cloud.google.com/storage/docs/storage-classes +""" + +MULTI_REGIONAL_LEGACY_STORAGE_CLASS = "MULTI_REGIONAL" +"""Legacy storage class. + +Alias for :attr:`STANDARD_STORAGE_CLASS`. + +Can only be used for objects in buckets whose +:attr:`~google.cloud.storage.bucket.Bucket.location_type` is +:attr:`~google.cloud.storage.bucket.Bucket.MULTI_REGION_LOCATION_TYPE`. + +See: https://cloud.google.com/storage/docs/storage-classes +""" + +REGIONAL_LEGACY_STORAGE_CLASS = "REGIONAL" +"""Legacy storage class. + +Alias for :attr:`STANDARD_STORAGE_CLASS`. + +Can only be used for objects in buckets whose +:attr:`~google.cloud.storage.bucket.Bucket.location_type` is +:attr:`~google.cloud.storage.bucket.Bucket.REGION_LOCATION_TYPE`. + +See: https://cloud.google.com/storage/docs/storage-classes +""" + +DURABLE_REDUCED_AVAILABILITY_LEGACY_STORAGE_CLASS = "DURABLE_REDUCED_AVAILABILITY" +"""Legacy storage class. + +Similar to :attr:`NEARLINE_STORAGE_CLASS`. +""" + + +# Location types + +MULTI_REGION_LOCATION_TYPE = "multi-region" +"""Location type: data will be replicated across regions in a multi-region. + +Provides highest availability across largest area. +""" + +REGION_LOCATION_TYPE = "region" +"""Location type: data will be stored within a single region. + +Provides lowest latency within a single region. +""" + +DUAL_REGION_LOCATION_TYPE = "dual-region" +"""Location type: data will be stored within two primary regions. + +Provides high availability and low latency across two regions. +""" + + +# Internal constants + +_DEFAULT_TIMEOUT = 60 # in seconds +"""The default request timeout in seconds if a timeout is not explicitly given. +""" + +# Public Access Prevention +PUBLIC_ACCESS_PREVENTION_ENFORCED = "enforced" +"""Enforced public access prevention value. + +See: https://cloud.google.com/storage/docs/public-access-prevention +""" + +PUBLIC_ACCESS_PREVENTION_UNSPECIFIED = "unspecified" +"""Unspecified public access prevention value. + +DEPRECATED: Use 'PUBLIC_ACCESS_PREVENTION_INHERITED' instead. + +See: https://cloud.google.com/storage/docs/public-access-prevention +""" + +PUBLIC_ACCESS_PREVENTION_INHERITED = "inherited" +"""Inherited public access prevention value. + +See: https://cloud.google.com/storage/docs/public-access-prevention +""" + +RPO_ASYNC_TURBO = "ASYNC_TURBO" +"""The recovery point objective (RPO) indicates how quickly newly written objects are asynchronously replicated to a separate geographic location. +When the RPO value is set to ASYNC_TURBO, the turbo replication feature is enabled. + +See: https://cloud.google.com/storage/docs/managing-turbo-replication +""" + +RPO_DEFAULT = "DEFAULT" +"""The recovery point objective (RPO) indicates how quickly newly written objects are asynchronously replicated to a separate geographic location. +When the RPO value is set to DEFAULT, the default replication behavior is enabled. + +See: https://cloud.google.com/storage/docs/managing-turbo-replication +""" diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/fileio.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/fileio.py new file mode 100644 index 000000000000..d09a3c885765 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/fileio.py @@ -0,0 +1,546 @@ +# Copyright 2021 Google LLC +# +# 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. + +"""Module for file-like access of blobs, usually invoked via Blob.open().""" + +import io +import warnings + +from google.api_core.exceptions import RequestRangeNotSatisfiable +from google.cloud.storage._helpers import _NUM_RETRIES_MESSAGE +from google.cloud.storage.retry import DEFAULT_RETRY +from google.cloud.storage.retry import DEFAULT_RETRY_IF_GENERATION_SPECIFIED +from google.cloud.storage.retry import ConditionalRetryPolicy + + +# Resumable uploads require a chunk size of precisely a multiple of 256 KiB. +CHUNK_SIZE_MULTIPLE = 256 * 1024 # 256 KiB +DEFAULT_CHUNK_SIZE = 40 * 1024 * 1024 # 40 MiB + +# Valid keyword arguments for download methods, and blob.reload() if needed. +# Note: Changes here need to be reflected in the blob.open() docstring. +VALID_DOWNLOAD_KWARGS = { + "if_generation_match", + "if_generation_not_match", + "if_metageneration_match", + "if_metageneration_not_match", + "timeout", + "retry", + "raw_download", +} + +# Valid keyword arguments for upload methods. +# Note: Changes here need to be reflected in the blob.open() docstring. +VALID_UPLOAD_KWARGS = { + "content_type", + "predefined_acl", + "num_retries", + "if_generation_match", + "if_generation_not_match", + "if_metageneration_match", + "if_metageneration_not_match", + "timeout", + "checksum", + "retry", +} + + +class BlobReader(io.BufferedIOBase): + """A file-like object that reads from a blob. + + :type blob: 'google.cloud.storage.blob.Blob' + :param blob: + The blob to download. + + :type chunk_size: long + :param chunk_size: + (Optional) The minimum number of bytes to read at a time. If fewer + bytes than the chunk_size are requested, the remainder is buffered. + The default is the chunk_size of the blob, or 40MiB. + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. A None value will disable + retries. A google.api_core.retry.Retry value will enable retries, + and the object will define retriable response codes and errors and + configure backoff and timeout options. + + A google.cloud.storage.retry.ConditionalRetryPolicy value wraps a + Retry object and activates it only if certain conditions are met. + This class exists to provide safe defaults for RPC calls that are + not technically safe to retry normally (due to potential data + duplication or other side-effects) but become safe to retry if a + condition such as if_metageneration_match is set. + + See the retry.py source code and docstrings in this package + (google.cloud.storage.retry) for information on retry types and how + to configure them. + + Media operations (downloads and uploads) do not support non-default + predicates in a Retry object. The default will always be used. Other + configuration changes for Retry objects such as delays and deadlines + are respected. + + :param download_kwargs: + Keyword arguments to pass to the underlying API calls. + The following arguments are supported: + + - ``if_generation_match`` + - ``if_generation_not_match`` + - ``if_metageneration_match`` + - ``if_metageneration_not_match`` + - ``timeout`` + + Note that download_kwargs are also applied to blob.reload(), if a reload + is needed during seek(). + """ + + def __init__(self, blob, chunk_size=None, retry=DEFAULT_RETRY, **download_kwargs): + for kwarg in download_kwargs: + if kwarg not in VALID_DOWNLOAD_KWARGS: + raise ValueError( + f"BlobReader does not support keyword argument {kwarg}." + ) + + self._blob = blob + self._pos = 0 + self._buffer = io.BytesIO() + self._chunk_size = chunk_size or blob.chunk_size or DEFAULT_CHUNK_SIZE + self._retry = retry + self._download_kwargs = download_kwargs + + def read(self, size=-1): + self._checkClosed() # Raises ValueError if closed. + + result = self._buffer.read(size) + # If the read request demands more bytes than are buffered, fetch more. + remaining_size = size - len(result) + if remaining_size > 0 or size < 0: + self._pos += self._buffer.tell() + read_size = len(result) + + self._buffer.seek(0) + self._buffer.truncate(0) # Clear the buffer to make way for new data. + fetch_start = self._pos + if size > 0: + # Fetch the larger of self._chunk_size or the remaining_size. + fetch_end = fetch_start + max(remaining_size, self._chunk_size) + else: + fetch_end = None + + # Download the blob. Checksumming must be disabled as we are using + # chunked downloads, and the server only knows the checksum of the + # entire file. + try: + result += self._blob.download_as_bytes( + start=fetch_start, + end=fetch_end, + checksum=None, + retry=self._retry, + **self._download_kwargs, + ) + except RequestRangeNotSatisfiable: + # We've reached the end of the file. Python file objects should + # return an empty response in this case, not raise an error. + pass + + # If more bytes were read than is immediately needed, buffer the + # remainder and then trim the result. + if size > 0 and len(result) > size: + self._buffer.write(result[size:]) + self._buffer.seek(0) + result = result[:size] + # Increment relative offset by true amount read. + self._pos += len(result) - read_size + return result + + def read1(self, size=-1): + return self.read(size) + + def seek(self, pos, whence=0): + """Seek within the blob. + + This implementation of seek() uses knowledge of the blob size to + validate that the reported position does not exceed the blob last byte. + If the blob size is not already known it will call blob.reload(). + """ + self._checkClosed() # Raises ValueError if closed. + + if self._blob.size is None: + self._blob.reload(**self._download_kwargs) + + initial_offset = self._pos + self._buffer.tell() + + if whence == 0: + target_pos = pos + elif whence == 1: + target_pos = initial_offset + pos + elif whence == 2: + target_pos = self._blob.size + pos + if whence not in {0, 1, 2}: + raise ValueError("invalid whence value") + + if target_pos > self._blob.size: + target_pos = self._blob.size + + # Seek or invalidate buffer as needed. + if target_pos < self._pos: + # Target position < relative offset <= true offset. + # As data is not in buffer, invalidate buffer. + self._buffer.seek(0) + self._buffer.truncate(0) + new_pos = target_pos + self._pos = target_pos + else: + # relative offset <= target position <= size of file. + difference = target_pos - initial_offset + new_pos = self._pos + self._buffer.seek(difference, 1) + return new_pos + + def close(self): + self._buffer.close() + + def _checkClosed(self): + if self._buffer.closed: + raise ValueError("I/O operation on closed file.") + + def readable(self): + return True + + def writable(self): + return False + + def seekable(self): + return True + + +class BlobWriter(io.BufferedIOBase): + """A file-like object that writes to a blob. + + :type blob: 'google.cloud.storage.blob.Blob' + :param blob: + The blob to which to write. + + :type chunk_size: long + :param chunk_size: + (Optional) The maximum number of bytes to buffer before sending data + to the server, and the size of each request when data is sent. + Writes are implemented as a "resumable upload", so chunk_size for + writes must be exactly a multiple of 256KiB as with other resumable + uploads. The default is the chunk_size of the blob, or 40 MiB. + + :type text_mode: bool + :param text_mode: + (Deprecated) A synonym for ignore_flush. For backwards-compatibility, + if True, sets ignore_flush to True. Use ignore_flush instead. This + parameter will be removed in a future release. + + :type ignore_flush: bool + :param ignore_flush: + Makes flush() do nothing instead of raise an error. flush() without + closing is not supported by the remote service and therefore calling it + on this class normally results in io.UnsupportedOperation. However, that + behavior is incompatible with some consumers and wrappers of file + objects in Python, such as zipfile.ZipFile or io.TextIOWrapper. Setting + ignore_flush will cause flush() to successfully do nothing, for + compatibility with those contexts. The correct way to actually flush + data to the remote server is to close() (using this object as a context + manager is recommended). + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. A None value will disable + retries. A google.api_core.retry.Retry value will enable retries, + and the object will define retriable response codes and errors and + configure backoff and timeout options. + + A google.cloud.storage.retry.ConditionalRetryPolicy value wraps a + Retry object and activates it only if certain conditions are met. + This class exists to provide safe defaults for RPC calls that are + not technically safe to retry normally (due to potential data + duplication or other side-effects) but become safe to retry if a + condition such as if_metageneration_match is set. + + See the retry.py source code and docstrings in this package + (google.cloud.storage.retry) for information on retry types and how + to configure them. + + Media operations (downloads and uploads) do not support non-default + predicates in a Retry object. The default will always be used. Other + configuration changes for Retry objects such as delays and deadlines + are respected. + + :param upload_kwargs: + Keyword arguments to pass to the underlying API + calls. The following arguments are supported: + + - ``if_generation_match`` + - ``if_generation_not_match`` + - ``if_metageneration_match`` + - ``if_metageneration_not_match`` + - ``timeout`` + - ``content_type`` + - ``num_retries`` + - ``predefined_acl`` + - ``checksum`` + """ + + def __init__( + self, + blob, + chunk_size=None, + text_mode=False, + ignore_flush=False, + retry=DEFAULT_RETRY_IF_GENERATION_SPECIFIED, + **upload_kwargs, + ): + for kwarg in upload_kwargs: + if kwarg not in VALID_UPLOAD_KWARGS: + raise ValueError( + f"BlobWriter does not support keyword argument {kwarg}." + ) + self._blob = blob + self._buffer = SlidingBuffer() + self._upload_and_transport = None + # Resumable uploads require a chunk size of a multiple of 256KiB. + # self._chunk_size must not be changed after the upload is initiated. + self._chunk_size = chunk_size or blob.chunk_size or DEFAULT_CHUNK_SIZE + # text_mode is a deprecated synonym for ignore_flush + self._ignore_flush = ignore_flush or text_mode + self._retry = retry + self._upload_kwargs = upload_kwargs + + @property + def _chunk_size(self): + """Get the blob's default chunk size. + + :rtype: int or ``NoneType`` + :returns: The current blob's chunk size, if it is set. + """ + return self.__chunk_size + + @_chunk_size.setter + def _chunk_size(self, value): + """Set the blob's default chunk size. + + :type value: int + :param value: (Optional) The current blob's chunk size, if it is set. + + :raises: :class:`ValueError` if ``value`` is not ``None`` and is not a + multiple of 256 KiB. + """ + if value is not None and value > 0 and value % CHUNK_SIZE_MULTIPLE != 0: + raise ValueError( + "Chunk size must be a multiple of %d." % CHUNK_SIZE_MULTIPLE + ) + self.__chunk_size = value + + def write(self, b): + self._checkClosed() # Raises ValueError if closed. + + pos = self._buffer.write(b) + + # If there is enough content, upload chunks. + num_chunks = len(self._buffer) // self._chunk_size + if num_chunks: + self._upload_chunks_from_buffer(num_chunks) + + return pos + + def _initiate_upload(self): + # num_retries is only supported for backwards-compatibility reasons. + num_retries = self._upload_kwargs.pop("num_retries", None) + retry = self._retry + content_type = self._upload_kwargs.pop("content_type", None) + + if num_retries is not None: + warnings.warn(_NUM_RETRIES_MESSAGE, DeprecationWarning, stacklevel=2) + # num_retries and retry are mutually exclusive. If num_retries is + # set and retry is exactly the default, then nullify retry for + # backwards compatibility. + if retry is DEFAULT_RETRY_IF_GENERATION_SPECIFIED: + retry = None + + # Handle ConditionalRetryPolicy. + if isinstance(retry, ConditionalRetryPolicy): + # Conditional retries are designed for non-media calls, which change + # arguments into query_params dictionaries. Media operations work + # differently, so here we make a "fake" query_params to feed to the + # ConditionalRetryPolicy. + query_params = { + "ifGenerationMatch": self._upload_kwargs.get("if_generation_match"), + "ifMetagenerationMatch": self._upload_kwargs.get( + "if_metageneration_match" + ), + } + retry = retry.get_retry_policy_if_conditions_met(query_params=query_params) + + self._upload_and_transport = self._blob._initiate_resumable_upload( + self._blob.bucket.client, + self._buffer, + content_type, + None, + num_retries, + chunk_size=self._chunk_size, + retry=retry, + **self._upload_kwargs, + ) + + def _upload_chunks_from_buffer(self, num_chunks): + """Upload a specified number of chunks.""" + + # Initialize the upload if necessary. + if not self._upload_and_transport: + self._initiate_upload() + + upload, transport = self._upload_and_transport + + # Upload chunks. The SlidingBuffer class will manage seek position. + for _ in range(num_chunks): + upload.transmit_next_chunk(transport) + + # Wipe the buffer of chunks uploaded, preserving any remaining data. + self._buffer.flush() + + def tell(self): + return self._buffer.tell() + len(self._buffer) + + def flush(self): + # flush() is not fully supported by the remote service, so raise an + # error here, unless self._ignore_flush is set. + if not self._ignore_flush: + raise io.UnsupportedOperation( + "Cannot flush without finalizing upload. Use close() instead, " + "or set ignore_flush=True when constructing this class (see " + "docstring)." + ) + + def close(self): + if not self._buffer.closed: + self._upload_chunks_from_buffer(1) + self._buffer.close() + + def _checkClosed(self): + if self._buffer.closed: + raise ValueError("I/O operation on closed file.") + + def readable(self): + return False + + def writable(self): + return True + + def seekable(self): + return False + + +class SlidingBuffer(object): + """A non-rewindable buffer that frees memory of chunks already consumed. + + This class is necessary because `google-resumable-media-python` expects + `tell()` to work relative to the start of the file, not relative to a place + in an intermediate buffer. Using this class, we present an external + interface with consistent seek and tell behavior without having to actually + store bytes already sent. + + Behavior of this class differs from an ordinary BytesIO buffer. `write()` + will always append to the end of the file only and not change the seek + position otherwise. `flush()` will delete all data already read (data to the + left of the seek position). `tell()` will report the seek position of the + buffer including all deleted data. Additionally the class implements + __len__() which will report the size of the actual underlying buffer. + + This class does not attempt to implement the entire Python I/O interface. + """ + + def __init__(self): + self._buffer = io.BytesIO() + self._cursor = 0 + + def write(self, b): + """Append to the end of the buffer without changing the position.""" + self._checkClosed() # Raises ValueError if closed. + + bookmark = self._buffer.tell() + self._buffer.seek(0, io.SEEK_END) + pos = self._buffer.write(b) + self._buffer.seek(bookmark) + return self._cursor + pos + + def read(self, size=-1): + """Read and move the cursor.""" + self._checkClosed() # Raises ValueError if closed. + + data = self._buffer.read(size) + self._cursor += len(data) + return data + + def flush(self): + """Delete already-read data (all data to the left of the position).""" + self._checkClosed() # Raises ValueError if closed. + + # BytesIO can't be deleted from the left, so save any leftover, unread + # data and truncate at 0, then readd leftover data. + leftover = self._buffer.read() + self._buffer.seek(0) + self._buffer.truncate(0) + self._buffer.write(leftover) + self._buffer.seek(0) + + def tell(self): + """Report how many bytes have been read from the buffer in total.""" + return self._cursor + + def seek(self, pos): + """Seek to a position (backwards only) within the internal buffer. + + This implementation of seek() verifies that the seek destination is + contained in _buffer. It will raise ValueError if the destination byte + has already been purged from the buffer. + + The "whence" argument is not supported in this implementation. + """ + self._checkClosed() # Raises ValueError if closed. + + buffer_initial_pos = self._buffer.tell() + difference = pos - self._cursor + buffer_seek_result = self._buffer.seek(difference, io.SEEK_CUR) + if ( + not buffer_seek_result - buffer_initial_pos == difference + or pos > self._cursor + ): + # The seek did not arrive at the expected byte because the internal + # buffer does not (or no longer) contains the byte. Reset and raise. + self._buffer.seek(buffer_initial_pos) + raise ValueError("Cannot seek() to that value.") + + self._cursor = pos + return self._cursor + + def __len__(self): + """Determine the size of the buffer by seeking to the end.""" + bookmark = self._buffer.tell() + length = self._buffer.seek(0, io.SEEK_END) + self._buffer.seek(bookmark) + return length + + def close(self): + return self._buffer.close() + + def _checkClosed(self): + return self._buffer._checkClosed() + + @property + def closed(self): + return self._buffer.closed diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/hmac_key.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/hmac_key.py new file mode 100644 index 000000000000..41f513ec6bf8 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/hmac_key.py @@ -0,0 +1,301 @@ +# Copyright 2019 Google LLC +# +# 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. + +"""Configure HMAC keys that can be used to authenticate requests to Google Cloud Storage. + +See [HMAC keys documentation](https://cloud.google.com/storage/docs/authentication/hmackeys) +""" + +from google.cloud.exceptions import NotFound +from google.cloud._helpers import _rfc3339_nanos_to_datetime + +from google.cloud.storage.constants import _DEFAULT_TIMEOUT +from google.cloud.storage.retry import DEFAULT_RETRY +from google.cloud.storage.retry import DEFAULT_RETRY_IF_ETAG_IN_JSON + + +class HMACKeyMetadata(object): + """Metadata about an HMAC service account key withn Cloud Storage. + + :type client: :class:`~google.cloud.stoage.client.Client` + :param client: client associated with the key metadata. + + :type access_id: str + :param access_id: (Optional) Unique ID of an existing key. + + :type project_id: str + :param project_id: (Optional) Project ID of an existing key. + Defaults to client's project. + + :type user_project: str + :param user_project: (Optional) This parameter is currently ignored. + """ + + ACTIVE_STATE = "ACTIVE" + """Key is active, and may be used to sign requests.""" + INACTIVE_STATE = "INACTIVE" + """Key is inactive, and may not be used to sign requests. + + It can be re-activated via :meth:`update`. + """ + DELETED_STATE = "DELETED" + """Key is deleted. It cannot be re-activated.""" + + _SETTABLE_STATES = (ACTIVE_STATE, INACTIVE_STATE) + + def __init__(self, client, access_id=None, project_id=None, user_project=None): + self._client = client + self._properties = {} + + if access_id is not None: + self._properties["accessId"] = access_id + + if project_id is not None: + self._properties["projectId"] = project_id + + self._user_project = user_project + + def __eq__(self, other): + if not isinstance(other, self.__class__): + return NotImplemented + + return self._client == other._client and self.access_id == other.access_id + + def __hash__(self): + return hash(self._client) + hash(self.access_id) + + @property + def access_id(self): + """Access ID of the key. + + :rtype: str or None + :returns: unique identifier of the key within a project. + """ + return self._properties.get("accessId") + + @property + def etag(self): + """ETag identifying the version of the key metadata. + + :rtype: str or None + :returns: ETag for the version of the key's metadata. + """ + return self._properties.get("etag") + + @property + def id(self): + """ID of the key, including the Project ID and the Access ID. + + :rtype: str or None + :returns: ID of the key. + """ + return self._properties.get("id") + + @property + def project(self): + """Project ID associated with the key. + + :rtype: str or None + :returns: project identfier for the key. + """ + return self._properties.get("projectId") + + @property + def service_account_email(self): + """Service account e-mail address associated with the key. + + :rtype: str or None + :returns: e-mail address for the service account which created the key. + """ + return self._properties.get("serviceAccountEmail") + + @property + def state(self): + """Get / set key's state. + + One of: + - ``ACTIVE`` + - ``INACTIVE`` + - ``DELETED`` + + :rtype: str or None + :returns: key's current state. + """ + return self._properties.get("state") + + @state.setter + def state(self, value): + self._properties["state"] = value + + @property + def time_created(self): + """Retrieve the timestamp at which the HMAC key was created. + + :rtype: :class:`datetime.datetime` or ``NoneType`` + :returns: Datetime object parsed from RFC3339 valid timestamp, or + ``None`` if the bucket's resource has not been loaded + from the server. + """ + value = self._properties.get("timeCreated") + if value is not None: + return _rfc3339_nanos_to_datetime(value) + + @property + def updated(self): + """Retrieve the timestamp at which the HMAC key was created. + + :rtype: :class:`datetime.datetime` or ``NoneType`` + :returns: Datetime object parsed from RFC3339 valid timestamp, or + ``None`` if the bucket's resource has not been loaded + from the server. + """ + value = self._properties.get("updated") + if value is not None: + return _rfc3339_nanos_to_datetime(value) + + @property + def path(self): + """Resource path for the metadata's key.""" + + if self.access_id is None: + raise ValueError("No 'access_id' set.") + + project = self.project + if project is None: + project = self._client.project + + return f"/projects/{project}/hmacKeys/{self.access_id}" + + @property + def user_project(self): + """Project ID to be billed for API requests made via this bucket. + + This property is currently ignored by the server. + + :rtype: str + """ + return self._user_project + + def exists(self, timeout=_DEFAULT_TIMEOUT, retry=DEFAULT_RETRY): + """Determine whether or not the key for this metadata exists. + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + + :rtype: bool + :returns: True if the key exists in Cloud Storage. + """ + try: + qs_params = {} + + if self.user_project is not None: + qs_params["userProject"] = self.user_project + + self._client._get_resource( + self.path, + query_params=qs_params, + timeout=timeout, + retry=retry, + ) + except NotFound: + return False + else: + return True + + def reload(self, timeout=_DEFAULT_TIMEOUT, retry=DEFAULT_RETRY): + """Reload properties from Cloud Storage. + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + + :raises :class:`~google.api_core.exceptions.NotFound`: + if the key does not exist on the back-end. + """ + qs_params = {} + + if self.user_project is not None: + qs_params["userProject"] = self.user_project + + self._properties = self._client._get_resource( + self.path, + query_params=qs_params, + timeout=timeout, + retry=retry, + ) + + def update(self, timeout=_DEFAULT_TIMEOUT, retry=DEFAULT_RETRY_IF_ETAG_IN_JSON): + """Save writable properties to Cloud Storage. + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + + :raises :class:`~google.api_core.exceptions.NotFound`: + if the key does not exist on the back-end. + """ + qs_params = {} + if self.user_project is not None: + qs_params["userProject"] = self.user_project + + payload = {"state": self.state} + self._properties = self._client._put_resource( + self.path, + payload, + query_params=qs_params, + timeout=timeout, + retry=retry, + ) + + def delete(self, timeout=_DEFAULT_TIMEOUT, retry=DEFAULT_RETRY): + """Delete the key from Cloud Storage. + + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + + :raises :class:`~google.api_core.exceptions.NotFound`: + if the key does not exist on the back-end. + """ + qs_params = {} + if self.user_project is not None: + qs_params["userProject"] = self.user_project + + self._client._delete_resource( + self.path, + query_params=qs_params, + timeout=timeout, + retry=retry, + ) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/iam.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/iam.py new file mode 100644 index 000000000000..36c7412b842a --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/iam.py @@ -0,0 +1,86 @@ +# Copyright 2017 Google LLC +# +# 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. +"""Storage API IAM policy definitions + +For allowed roles / permissions, see: +https://cloud.google.com/storage/docs/access-control/iam +""" + +# Storage-specific IAM roles + +STORAGE_OBJECT_CREATOR_ROLE = "roles/storage.objectCreator" +"""Role implying rights to create objects, but not delete or overwrite them.""" + +STORAGE_OBJECT_VIEWER_ROLE = "roles/storage.objectViewer" +"""Role implying rights to view object properties, excluding ACLs.""" + +STORAGE_OBJECT_ADMIN_ROLE = "roles/storage.objectAdmin" +"""Role implying full control of objects.""" + +STORAGE_ADMIN_ROLE = "roles/storage.admin" +"""Role implying full control of objects and buckets.""" + +STORAGE_VIEWER_ROLE = "Viewer" +"""Can list buckets.""" + +STORAGE_EDITOR_ROLE = "Editor" +"""Can create, list, and delete buckets.""" + +STORAGE_OWNER_ROLE = "Owners" +"""Can create, list, and delete buckets.""" + + +# Storage-specific permissions + +STORAGE_BUCKETS_CREATE = "storage.buckets.create" +"""Permission: create buckets.""" + +STORAGE_BUCKETS_DELETE = "storage.buckets.delete" +"""Permission: delete buckets.""" + +STORAGE_BUCKETS_GET = "storage.buckets.get" +"""Permission: read bucket metadata, excluding ACLs.""" + +STORAGE_BUCKETS_GET_IAM_POLICY = "storage.buckets.getIamPolicy" +"""Permission: read bucket ACLs.""" + +STORAGE_BUCKETS_LIST = "storage.buckets.list" +"""Permission: list buckets.""" + +STORAGE_BUCKETS_SET_IAM_POLICY = "storage.buckets.setIamPolicy" +"""Permission: update bucket ACLs.""" + +STORAGE_BUCKETS_UPDATE = "storage.buckets.list" +"""Permission: update buckets, excluding ACLS.""" + +STORAGE_OBJECTS_CREATE = "storage.objects.create" +"""Permission: add new objects to a bucket.""" + +STORAGE_OBJECTS_DELETE = "storage.objects.delete" +"""Permission: delete objects.""" + +STORAGE_OBJECTS_GET = "storage.objects.get" +"""Permission: read object data / metadata, excluding ACLs.""" + +STORAGE_OBJECTS_GET_IAM_POLICY = "storage.objects.getIamPolicy" +"""Permission: read object ACLs.""" + +STORAGE_OBJECTS_LIST = "storage.objects.list" +"""Permission: list objects in a bucket.""" + +STORAGE_OBJECTS_SET_IAM_POLICY = "storage.objects.setIamPolicy" +"""Permission: update object ACLs.""" + +STORAGE_OBJECTS_UPDATE = "storage.objects.update" +"""Permission: update object metadat, excluding ACLs.""" diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/notification.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/notification.py new file mode 100644 index 000000000000..4eb807fa94cf --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/notification.py @@ -0,0 +1,446 @@ +# Copyright 2017 Google LLC +# +# 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. + +"""Configure bucket notification resources to interact with Google Cloud Pub/Sub. + +See [Cloud Pub/Sub Notifications for Google Cloud Storage](https://cloud.google.com/storage/docs/pubsub-notifications) +""" + +import re + +from google.api_core.exceptions import NotFound + +from google.cloud.storage.constants import _DEFAULT_TIMEOUT +from google.cloud.storage.retry import DEFAULT_RETRY + + +OBJECT_FINALIZE_EVENT_TYPE = "OBJECT_FINALIZE" +OBJECT_METADATA_UPDATE_EVENT_TYPE = "OBJECT_METADATA_UPDATE" +OBJECT_DELETE_EVENT_TYPE = "OBJECT_DELETE" +OBJECT_ARCHIVE_EVENT_TYPE = "OBJECT_ARCHIVE" + +JSON_API_V1_PAYLOAD_FORMAT = "JSON_API_V1" +NONE_PAYLOAD_FORMAT = "NONE" + +_TOPIC_REF_FMT = "//pubsub.googleapis.com/projects/{}/topics/{}" +_PROJECT_PATTERN = r"(?P[a-z][a-z0-9-]{4,28}[a-z0-9])" +_TOPIC_NAME_PATTERN = r"(?P[A-Za-z](\w|[-_.~+%])+)" +_TOPIC_REF_PATTERN = _TOPIC_REF_FMT.format(_PROJECT_PATTERN, _TOPIC_NAME_PATTERN) +_TOPIC_REF_RE = re.compile(_TOPIC_REF_PATTERN) +_BAD_TOPIC = ( + "Resource has invalid topic: {}; see " + "https://cloud.google.com/storage/docs/json_api/v1/" + "notifications/insert#topic" +) + + +class BucketNotification(object): + """Represent a single notification resource for a bucket. + + See: https://cloud.google.com/storage/docs/json_api/v1/notifications + + :type bucket: :class:`google.cloud.storage.bucket.Bucket` + :param bucket: Bucket to which the notification is bound. + + :type topic_name: str + :param topic_name: + (Optional) Topic name to which notifications are published. + + :type topic_project: str + :param topic_project: + (Optional) Project ID of topic to which notifications are published. + If not passed, uses the project ID of the bucket's client. + + :type custom_attributes: dict + :param custom_attributes: + (Optional) Additional attributes passed with notification events. + + :type event_types: list(str) + :param event_types: + (Optional) Event types for which notification events are published. + + :type blob_name_prefix: str + :param blob_name_prefix: + (Optional) Prefix of blob names for which notification events are + published. + + :type payload_format: str + :param payload_format: + (Optional) Format of payload for notification events. + + :type notification_id: str + :param notification_id: + (Optional) The ID of the notification. + """ + + def __init__( + self, + bucket, + topic_name=None, + topic_project=None, + custom_attributes=None, + event_types=None, + blob_name_prefix=None, + payload_format=NONE_PAYLOAD_FORMAT, + notification_id=None, + ): + self._bucket = bucket + self._topic_name = topic_name + + if topic_project is None: + topic_project = bucket.client.project + + if topic_project is None: + raise ValueError("Client project not set: pass an explicit topic_project.") + + self._topic_project = topic_project + + self._properties = {} + + if custom_attributes is not None: + self._properties["custom_attributes"] = custom_attributes + + if event_types is not None: + self._properties["event_types"] = event_types + + if blob_name_prefix is not None: + self._properties["object_name_prefix"] = blob_name_prefix + + if notification_id is not None: + self._properties["id"] = notification_id + + self._properties["payload_format"] = payload_format + + @classmethod + def from_api_repr(cls, resource, bucket): + """Construct an instance from the JSON repr returned by the server. + + See: https://cloud.google.com/storage/docs/json_api/v1/notifications + + :type resource: dict + :param resource: JSON repr of the notification + + :type bucket: :class:`google.cloud.storage.bucket.Bucket` + :param bucket: Bucket to which the notification is bound. + + :rtype: :class:`BucketNotification` + :returns: the new notification instance + """ + topic_path = resource.get("topic") + if topic_path is None: + raise ValueError("Resource has no topic") + + name, project = _parse_topic_path(topic_path) + instance = cls(bucket, name, topic_project=project) + instance._properties = resource + + return instance + + @property + def bucket(self): + """Bucket to which the notification is bound.""" + return self._bucket + + @property + def topic_name(self): + """Topic name to which notifications are published.""" + return self._topic_name + + @property + def topic_project(self): + """Project ID of topic to which notifications are published.""" + return self._topic_project + + @property + def custom_attributes(self): + """Custom attributes passed with notification events.""" + return self._properties.get("custom_attributes") + + @property + def event_types(self): + """Event types for which notification events are published.""" + return self._properties.get("event_types") + + @property + def blob_name_prefix(self): + """Prefix of blob names for which notification events are published.""" + return self._properties.get("object_name_prefix") + + @property + def payload_format(self): + """Format of payload of notification events.""" + return self._properties.get("payload_format") + + @property + def notification_id(self): + """Server-set ID of notification resource.""" + return self._properties.get("id") + + @property + def etag(self): + """Server-set ETag of notification resource.""" + return self._properties.get("etag") + + @property + def self_link(self): + """Server-set ETag of notification resource.""" + return self._properties.get("selfLink") + + @property + def client(self): + """The client bound to this notfication.""" + return self.bucket.client + + @property + def path(self): + """The URL path for this notification.""" + return f"/b/{self.bucket.name}/notificationConfigs/{self.notification_id}" + + def _require_client(self, client): + """Check client or verify over-ride. + + :type client: :class:`~google.cloud.storage.client.Client` or + ``NoneType`` + :param client: the client to use. + + :rtype: :class:`google.cloud.storage.client.Client` + :returns: The client passed in or the bucket's client. + """ + if client is None: + client = self.client + return client + + def _set_properties(self, response): + """Helper for :meth:`reload`. + + :type response: dict + :param response: resource mapping from server + """ + self._properties.clear() + self._properties.update(response) + + def create(self, client=None, timeout=_DEFAULT_TIMEOUT, retry=None): + """API wrapper: create the notification. + + See: + https://cloud.google.com/storage/docs/json_api/v1/notifications/insert + + If :attr:`user_project` is set on the bucket, bills the API request + to that project. + + :type client: :class:`~google.cloud.storage.client.Client` + :param client: (Optional) The client to use. If not passed, falls back + to the ``client`` stored on the notification's bucket. + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + + :raises ValueError: if the notification already exists. + """ + if self.notification_id is not None: + raise ValueError( + f"Notification already exists w/ id: {self.notification_id}" + ) + + client = self._require_client(client) + + query_params = {} + if self.bucket.user_project is not None: + query_params["userProject"] = self.bucket.user_project + + path = f"/b/{self.bucket.name}/notificationConfigs" + properties = self._properties.copy() + + if self.topic_name is None: + properties["topic"] = _TOPIC_REF_FMT.format(self.topic_project, "") + else: + properties["topic"] = _TOPIC_REF_FMT.format( + self.topic_project, self.topic_name + ) + + self._properties = client._post_resource( + path, + properties, + query_params=query_params, + timeout=timeout, + retry=retry, + ) + + def exists(self, client=None, timeout=_DEFAULT_TIMEOUT, retry=DEFAULT_RETRY): + """Test whether this notification exists. + + See: + https://cloud.google.com/storage/docs/json_api/v1/notifications/get + + If :attr:`user_project` is set on the bucket, bills the API request + to that project. + + :type client: :class:`~google.cloud.storage.client.Client` or + ``NoneType`` + :param client: (Optional) The client to use. If not passed, falls back + to the ``client`` stored on the current bucket. + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + + :rtype: bool + :returns: True, if the notification exists, else False. + :raises ValueError: if the notification has no ID. + """ + if self.notification_id is None: + raise ValueError("Notification ID not set: set an explicit notification_id") + + client = self._require_client(client) + + query_params = {} + if self.bucket.user_project is not None: + query_params["userProject"] = self.bucket.user_project + + try: + client._get_resource( + self.path, + query_params=query_params, + timeout=timeout, + retry=retry, + ) + except NotFound: + return False + else: + return True + + def reload(self, client=None, timeout=_DEFAULT_TIMEOUT, retry=DEFAULT_RETRY): + """Update this notification from the server configuration. + + See: + https://cloud.google.com/storage/docs/json_api/v1/notifications/get + + If :attr:`user_project` is set on the bucket, bills the API request + to that project. + + :type client: :class:`~google.cloud.storage.client.Client` or + ``NoneType`` + :param client: (Optional) The client to use. If not passed, falls back + to the ``client`` stored on the current bucket. + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + + + :raises ValueError: if the notification has no ID. + """ + if self.notification_id is None: + raise ValueError("Notification ID not set: set an explicit notification_id") + + client = self._require_client(client) + + query_params = {} + if self.bucket.user_project is not None: + query_params["userProject"] = self.bucket.user_project + + response = client._get_resource( + self.path, + query_params=query_params, + timeout=timeout, + retry=retry, + ) + self._set_properties(response) + + def delete(self, client=None, timeout=_DEFAULT_TIMEOUT, retry=DEFAULT_RETRY): + """Delete this notification. + + See: + https://cloud.google.com/storage/docs/json_api/v1/notifications/delete + + If :attr:`user_project` is set on the bucket, bills the API request + to that project. + + :type client: :class:`~google.cloud.storage.client.Client` or + ``NoneType`` + :param client: (Optional) The client to use. If not passed, falls back + to the ``client`` stored on the current bucket. + :type timeout: float or tuple + :param timeout: + (Optional) The amount of time, in seconds, to wait + for the server response. See: :ref:`configuring_timeouts` + + :type retry: google.api_core.retry.Retry or google.cloud.storage.retry.ConditionalRetryPolicy + :param retry: + (Optional) How to retry the RPC. See: :ref:`configuring_retries` + + :raises: :class:`google.api_core.exceptions.NotFound`: + if the notification does not exist. + :raises ValueError: if the notification has no ID. + """ + if self.notification_id is None: + raise ValueError("Notification ID not set: set an explicit notification_id") + + client = self._require_client(client) + + query_params = {} + if self.bucket.user_project is not None: + query_params["userProject"] = self.bucket.user_project + + client._delete_resource( + self.path, + query_params=query_params, + timeout=timeout, + retry=retry, + ) + + +def _parse_topic_path(topic_path): + """Verify that a topic path is in the correct format. + + Expected to be of the form: + + //pubsub.googleapis.com/projects/{project}/topics/{topic} + + where the ``project`` value must be "6 to 30 lowercase letters, digits, + or hyphens. It must start with a letter. Trailing hyphens are prohibited." + (see [`resource manager docs`](https://cloud.google.com/resource-manager/reference/rest/v1beta1/projects#Project.FIELDS.project_id)) + and ``topic`` must have length at least two, + must start with a letter and may only contain alphanumeric characters or + ``-``, ``_``, ``.``, ``~``, ``+`` or ``%`` (i.e characters used for URL + encoding, see [`topic spec`](https://cloud.google.com/storage/docs/json_api/v1/notifications/insert#topic)). + + Args: + topic_path (str): The topic path to be verified. + + Returns: + Tuple[str, str]: The ``project`` and ``topic`` parsed from the + ``topic_path``. + + Raises: + ValueError: If the topic path is invalid. + """ + match = _TOPIC_REF_RE.match(topic_path) + if match is None: + raise ValueError(_BAD_TOPIC.format(topic_path)) + + return match.group("name"), match.group("project") diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/retry.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/retry.py new file mode 100644 index 000000000000..3ea3ae4a0835 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/retry.py @@ -0,0 +1,169 @@ +# Copyright 2020 Google LLC +# +# 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. + +"""Helpers for configuring retries with exponential back-off. + +See [Retry Strategy for Google Cloud Storage](https://cloud.google.com/storage/docs/retry-strategy#client-libraries) +""" + +import requests +import requests.exceptions as requests_exceptions + +from google.api_core import exceptions as api_exceptions +from google.api_core import retry +from google.auth import exceptions as auth_exceptions + + +_RETRYABLE_TYPES = ( + api_exceptions.TooManyRequests, # 429 + api_exceptions.InternalServerError, # 500 + api_exceptions.BadGateway, # 502 + api_exceptions.ServiceUnavailable, # 503 + api_exceptions.GatewayTimeout, # 504 + ConnectionError, + requests.ConnectionError, + requests_exceptions.ChunkedEncodingError, + requests_exceptions.Timeout, +) + + +# Some retriable errors don't have their own custom exception in api_core. +_ADDITIONAL_RETRYABLE_STATUS_CODES = (408,) + + +def _should_retry(exc): + """Predicate for determining when to retry.""" + if isinstance(exc, _RETRYABLE_TYPES): + return True + elif isinstance(exc, api_exceptions.GoogleAPICallError): + return exc.code in _ADDITIONAL_RETRYABLE_STATUS_CODES + elif isinstance(exc, auth_exceptions.TransportError): + return _should_retry(exc.args[0]) + else: + return False + + +DEFAULT_RETRY = retry.Retry(predicate=_should_retry) +"""The default retry object. + +This retry setting will retry all _RETRYABLE_TYPES and any status codes from +_ADDITIONAL_RETRYABLE_STATUS_CODES. + +To modify the default retry behavior, create a new retry object modeled after +this one by calling it a ``with_XXX`` method. For example, to create a copy of +DEFAULT_RETRY with a deadline of 30 seconds, pass +``retry=DEFAULT_RETRY.with_deadline(30)``. See google-api-core reference +(https://googleapis.dev/python/google-api-core/latest/retry.html) for details. +""" + + +class ConditionalRetryPolicy(object): + """A class for use when an API call is only conditionally safe to retry. + + This class is intended for use in inspecting the API call parameters of an + API call to verify that any flags necessary to make the API call idempotent + (such as specifying an ``if_generation_match`` or related flag) are present. + + It can be used in place of a ``retry.Retry`` object, in which case + ``_http.Connection.api_request`` will pass the requested api call keyword + arguments into the ``conditional_predicate`` and return the ``retry_policy`` + if the conditions are met. + + :type retry_policy: class:`google.api_core.retry.Retry` + :param retry_policy: A retry object defining timeouts, persistence and which + exceptions to retry. + + :type conditional_predicate: callable + :param conditional_predicate: A callable that accepts exactly the number of + arguments in ``required_kwargs``, in order, and returns True if the + arguments have sufficient data to determine that the call is safe to + retry (idempotent). + + :type required_kwargs: list(str) + :param required_kwargs: + A list of keyword argument keys that will be extracted from the API call + and passed into the ``conditional predicate`` in order. For example, + ``["query_params"]`` is commmonly used for preconditions in query_params. + """ + + def __init__(self, retry_policy, conditional_predicate, required_kwargs): + self.retry_policy = retry_policy + self.conditional_predicate = conditional_predicate + self.required_kwargs = required_kwargs + + def get_retry_policy_if_conditions_met(self, **kwargs): + if self.conditional_predicate(*[kwargs[key] for key in self.required_kwargs]): + return self.retry_policy + return None + + +def is_generation_specified(query_params): + """Return True if generation or if_generation_match is specified.""" + generation = query_params.get("generation") is not None + if_generation_match = query_params.get("ifGenerationMatch") is not None + return generation or if_generation_match + + +def is_metageneration_specified(query_params): + """Return True if if_metageneration_match is specified.""" + if_metageneration_match = query_params.get("ifMetagenerationMatch") is not None + return if_metageneration_match + + +def is_etag_in_data(data): + """Return True if an etag is contained in the request body. + + :type data: dict or None + :param data: A dict representing the request JSON body. If not passed, returns False. + """ + return data is not None and "etag" in data + + +def is_etag_in_json(data): + """ + ``is_etag_in_json`` is supported for backwards-compatibility reasons only; + please use ``is_etag_in_data`` instead. + """ + return is_etag_in_data(data) + + +DEFAULT_RETRY_IF_GENERATION_SPECIFIED = ConditionalRetryPolicy( + DEFAULT_RETRY, is_generation_specified, ["query_params"] +) +"""Conditional wrapper for the default retry object. + +This retry setting will retry all _RETRYABLE_TYPES and any status codes from +_ADDITIONAL_RETRYABLE_STATUS_CODES, but only if the request included an +``ifGenerationMatch`` header. +""" + +DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED = ConditionalRetryPolicy( + DEFAULT_RETRY, is_metageneration_specified, ["query_params"] +) +"""Conditional wrapper for the default retry object. + +This retry setting will retry all _RETRYABLE_TYPES and any status codes from +_ADDITIONAL_RETRYABLE_STATUS_CODES, but only if the request included an +``ifMetagenerationMatch`` header. +""" + +DEFAULT_RETRY_IF_ETAG_IN_JSON = ConditionalRetryPolicy( + DEFAULT_RETRY, is_etag_in_json, ["data"] +) +"""Conditional wrapper for the default retry object. + +This retry setting will retry all _RETRYABLE_TYPES and any status codes from +_ADDITIONAL_RETRYABLE_STATUS_CODES, but only if the request included an +``ETAG`` entry in its payload. +""" diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/transfer_manager.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/transfer_manager.py new file mode 100644 index 000000000000..162e6465dec9 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/transfer_manager.py @@ -0,0 +1,557 @@ +# Copyright 2022 Google LLC +# +# 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. + +"""Concurrent media operations. This is a PREVIEW FEATURE: API may change.""" + +import concurrent.futures + +import tempfile + +from google.api_core import exceptions + + +DEFAULT_CHUNK_SIZE = 200 * 1024 * 1024 + + +def upload_many( + file_blob_pairs, + skip_if_exists=False, + upload_kwargs=None, + max_workers=None, + deadline=None, + raise_exception=False, +): + """Upload many files concurrently via a worker pool. + + This function is a PREVIEW FEATURE: the API may change in a future version. + + :type file_blob_pairs: List(Tuple(IOBase or str, 'google.cloud.storage.blob.Blob')) + :param file_blob_pairs: + A list of tuples of a file or filename and a blob. Each file will be + uploaded to the corresponding blob by using blob.upload_from_file() or + blob.upload_from_filename() as appropriate. + + :type skip_if_exists: bool + :param skip_if_exists: + If True, blobs that already have a live version will not be overwritten. + This is accomplished by setting "if_generation_match = 0" on uploads. + Uploads so skipped will result in a 412 Precondition Failed response + code, which will be included in the return value but not raised + as an exception regardless of the value of raise_exception. + + :type upload_kwargs: dict + :param upload_kwargs: + A dictionary of keyword arguments to pass to the upload method. Refer + to the documentation for blob.upload_from_file() or + blob.upload_from_filename() for more information. The dict is directly + passed into the upload methods and is not validated by this function. + + :type max_workers: int + :param max_workers: + The number of workers (effectively, the number of threads) to use in + the worker pool. Refer to concurrent.futures.ThreadPoolExecutor + documentation for details. + + :type deadline: int + :param deadline: + The number of seconds to wait for all threads to resolve. If the + deadline is reached, all threads will be terminated regardless of their + progress and concurrent.futures.TimeoutError will be raised. This can be + left as the default of None (no deadline) for most use cases. + + :type raise_exception: bool + :param raise_exception: + If True, instead of adding exceptions to the list of return values, + instead they will be raised. Note that encountering an exception on one + operation will not prevent other operations from starting. Exceptions + are only processed and potentially raised after all operations are + complete in success or failure. + + If skip_if_exists is True, 412 Precondition Failed responses are + considered part of normal operation and are not raised as an exception. + + :raises: :exc:`concurrent.futures.TimeoutError` if deadline is exceeded. + + :rtype: list + :returns: A list of results corresponding to, in order, each item in the + input list. If an exception was received, it will be the result + for that operation. Otherwise, the return value from the successful + upload method is used (typically, None). + """ + if upload_kwargs is None: + upload_kwargs = {} + if skip_if_exists: + upload_kwargs["if_generation_match"] = 0 + + with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor: + futures = [] + for path_or_file, blob in file_blob_pairs: + method = ( + blob.upload_from_filename + if isinstance(path_or_file, str) + else blob.upload_from_file + ) + futures.append(executor.submit(method, path_or_file, **upload_kwargs)) + results = [] + concurrent.futures.wait( + futures, timeout=deadline, return_when=concurrent.futures.ALL_COMPLETED + ) + for future in futures: + exp = future.exception() + + # If raise_exception is False, don't call future.result() + if exp and not raise_exception: + results.append(exp) + # If skip_if_exists and the exception is PreconditionFailed, do same. + elif exp and skip_if_exists and isinstance(exp, exceptions.PreconditionFailed): + results.append(exp) + # Get the real result. If there was an exception not handled above, + # this will raise it. + else: + results.append(future.result()) + return results + + +def download_many( + blob_file_pairs, + download_kwargs=None, + max_workers=None, + deadline=None, + raise_exception=False, +): + """Download many blobs concurrently via a worker pool. + + This function is a PREVIEW FEATURE: the API may change in a future version. + + :type blob_file_pairs: List(Tuple('google.cloud.storage.blob.Blob', IOBase or str)) + :param blob_file_pairs: + A list of tuples of blob and a file or filename. Each blob will be + downloaded to the corresponding blob by using blob.download_to_file() or + blob.download_to_filename() as appropriate. + + Note that blob.download_to_filename() does not delete the destination + file if the download fails. + + :type download_kwargs: dict + :param download_kwargs: + A dictionary of keyword arguments to pass to the download method. Refer + to the documentation for blob.download_to_file() or + blob.download_to_filename() for more information. The dict is directly + passed into the download methods and is not validated by this function. + + :type max_workers: int + :param max_workers: + The number of workers (effectively, the number of threads) to use in + the worker pool. Refer to concurrent.futures.ThreadPoolExecutor + documentation for details. + + :type deadline: int + :param deadline: + The number of seconds to wait for all threads to resolve. If the + deadline is reached, all threads will be terminated regardless of their + progress and concurrent.futures.TimeoutError will be raised. This can be + left as the default of None (no deadline) for most use cases. + + :type raise_exception: bool + :param raise_exception: + If True, instead of adding exceptions to the list of return values, + instead they will be raised. Note that encountering an exception on one + operation will not prevent other operations from starting. Exceptions + are only processed and potentially raised after all operations are + complete in success or failure. + + :raises: :exc:`concurrent.futures.TimeoutError` if deadline is exceeded. + + :rtype: list + :returns: A list of results corresponding to, in order, each item in the + input list. If an exception was received, it will be the result + for that operation. Otherwise, the return value from the successful + download method is used (typically, None). + """ + + if download_kwargs is None: + download_kwargs = {} + with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor: + futures = [] + for blob, path_or_file in blob_file_pairs: + method = ( + blob.download_to_filename + if isinstance(path_or_file, str) + else blob.download_to_file + ) + futures.append(executor.submit(method, path_or_file, **download_kwargs)) + results = [] + concurrent.futures.wait( + futures, timeout=deadline, return_when=concurrent.futures.ALL_COMPLETED + ) + for future in futures: + if not raise_exception: + exp = future.exception() + if exp: + results.append(exp) + continue + results.append(future.result()) + return results + + +def download_chunks_concurrently_to_file( + blob, + file_obj, + chunk_size=DEFAULT_CHUNK_SIZE, + download_kwargs=None, + max_workers=None, + deadline=None, +): + """Download a single blob in chunks, concurrently. + + This function is a PREVIEW FEATURE: the API may change in a future version. + + Use of this function, in cases where single threads are unable to fully + saturate available network bandwidth, may improve download performance for + large objects. + + The size of the blob must be known in order to calculate the number of + chunks. If the size is not already set, blob.reload() will be called + automatically to set it. + + :type blob: 'google.cloud.storage.blob.Blob' + :param blob: + The blob to download. + + :type file_obj: IOBase + :param file_obj: The file object to which the downloaded chunks will be + written. Chunks are written in order. While the current implementation + of this function does not use seek(), a future version may use seek() to + write chunks out of order to improve write performance. + + :type chunk_size: int + :param chunk_size: The size of each chunk. An excessively small size may + have a negative performance impact, as each chunk will be uploaded in a + separate HTTP request. + + :type download_kwargs: dict + :param download_kwargs: + A dictionary of keyword arguments to pass to the download method. Refer + to the documentation for blob.download_to_file() or + blob.download_to_filename() for more information. The dict is directly + passed into the download methods and is not validated by this function. + + :type max_workers: int + :param max_workers: + The number of workers (effectively, the number of threads) to use in + the worker pool. Refer to concurrent.futures.ThreadPoolExecutor + documentation for details. + + :type deadline: int + :param deadline: + The number of seconds to wait for all threads to resolve. If the + deadline is reached, all threads will be terminated regardless of their + progress and concurrent.futures.TimeoutError will be raised. This can be + left as the default of None (no deadline) for most use cases. + + :raises: :exc:`concurrent.futures.TimeoutError` if deadline is exceeded. + """ + + if download_kwargs is None: + download_kwargs = {} + # We must know the size of the object, and the generation. + if not blob.size or not blob.generation: + blob.reload() + + def download_range_via_tempfile(blob, start, end, download_kwargs): + tmp = tempfile.TemporaryFile() + blob.download_to_file(tmp, start=start, end=end, **download_kwargs) + return tmp + + futures = [] + + with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor: + cursor = 0 + while cursor < blob.size: + start = cursor + cursor = min(cursor + chunk_size, blob.size) + futures.append( + executor.submit( + download_range_via_tempfile, + blob, + start=start, + end=cursor - 1, + download_kwargs=download_kwargs, + ) + ) + + # Wait until all futures are done and process them in order. + concurrent.futures.wait( + futures, timeout=deadline, return_when=concurrent.futures.ALL_COMPLETED + ) + for future in futures: + tmp = future.result() + tmp.seek(0) + file_obj.write(tmp.read()) + tmp.close() + + +def upload_many_from_filenames( + bucket, + filenames, + root="", + blob_name_prefix="", + skip_if_exists=False, + blob_constructor_kwargs=None, + upload_kwargs=None, + max_workers=None, + deadline=None, + raise_exception=False, +): + """Upload many files concurrently by their filenames. + + This function is a PREVIEW FEATURE: the API may change in a future version. + + The destination blobs are automatically created, with blob names based on + the source filenames and the blob_name_prefix. + + For example, if the `filenames` include "images/icon.jpg", `root` is + "/home/myuser/", and `blob_name_prefix` is "myfiles/", then the file at + "/home/myuser/images/icon.jpg" will be uploaded to a blob named + "myfiles/images/icon.jpg". + + :type bucket: 'google.cloud.storage.bucket.Bucket' + :param bucket: + The bucket which will contain the uploaded blobs. + + :type filenames: list(str) + :param filenames: + A list of filenames to be uploaded. This may include part of the path. + The full path to the file must be root + filename. The filename is + separate from the root because the filename will also determine the + name of the destination blob. + + :type root: str + :param root: + A string that will be prepended to each filename in the input list, in + order to find the source file for each blob. Unlike the filename itself, + the root string does not affect the name of the uploaded blob itself. + The root string will usually end in "/" (or "\\" depending on platform) + but is not required to do so. + + For instance, if the root string is "/tmp/img-" and a filename is + "0001.jpg", with an empty blob_name_prefix, then the file uploaded will + be "/tmp/img-0001.jpg" and the destination blob will be "0001.jpg". + + This parameter can be an empty string. + + :type blob_name_prefix: str + :param blob_name_prefix: + A string that will be prepended to each filename in the input list, in + order to determine the name of the destination blob. Unlike the filename + itself, the prefix string does not affect the location the library will + look for the source data on the local filesystem. + + For instance, if the root is "/tmp/img-", the blob_name_prefix is + "myuser/mystuff-" and a filename is "0001.jpg" then the file uploaded + will be "/tmp/img-0001.jpg" and the destination blob will be + "myuser/mystuff-0001.jpg". + + The blob_name_prefix can be blank (an empty string). + + :type skip_if_exists: bool + :param skip_if_exists: + If True, blobs that already have a live version will not be overwritten. + This is accomplished by setting "if_generation_match = 0" on uploads. + Uploads so skipped will result in a 412 Precondition Failed response + code, which will be included in the return value but not raised + as an exception regardless of the value of raise_exception. + + :type blob_constructor_kwargs: dict + :param blob_constructor_kwargs: + A dictionary of keyword arguments to pass to the blob constructor. Refer + to the documentation for blob.Blob() for more information. The dict is + directly passed into the constructor and is not validated by this + function. `name` and `bucket` keyword arguments are reserved by this + function and will result in an error if passed in here. + + :type upload_kwargs: dict + :param upload_kwargs: + A dictionary of keyword arguments to pass to the upload method. Refer + to the documentation for blob.upload_from_file() or + blob.upload_from_filename() for more information. The dict is directly + passed into the upload methods and is not validated by this function. + + :type max_workers: int + :param max_workers: + The number of workers (effectively, the number of threads) to use in + the worker pool. Refer to concurrent.futures.ThreadPoolExecutor + documentation for details. + + :type deadline: int + :param deadline: + The number of seconds to wait for all threads to resolve. If the + deadline is reached, all threads will be terminated regardless of their + progress and concurrent.futures.TimeoutError will be raised. This can be + left as the default of None (no deadline) for most use cases. + + :type raise_exception: bool + :param raise_exception: + If True, instead of adding exceptions to the list of return values, + instead they will be raised. Note that encountering an exception on one + operation will not prevent other operations from starting. Exceptions + are only processed and potentially raised after all operations are + complete in success or failure. + + If skip_if_exists is True, 412 Precondition Failed responses are + considered part of normal operation and are not raised as an exception. + + :raises: :exc:`concurrent.futures.TimeoutError` if deadline is exceeded. + + :rtype: list + :returns: A list of results corresponding to, in order, each item in the + input list. If an exception was received, it will be the result + for that operation. Otherwise, the return value from the successful + upload method is used (typically, None). + """ + if blob_constructor_kwargs is None: + blob_constructor_kwargs = {} + + file_blob_pairs = [] + + for filename in filenames: + path = root + filename + blob_name = blob_name_prefix + filename + blob = bucket.blob(blob_name, **blob_constructor_kwargs) + file_blob_pairs.append((path, blob)) + + return upload_many( + file_blob_pairs, + skip_if_exists=skip_if_exists, + upload_kwargs=upload_kwargs, + max_workers=max_workers, + deadline=deadline, + raise_exception=raise_exception, + ) + + +def download_many_to_path( + bucket, + blob_names, + path_root="", + blob_name_prefix="", + download_kwargs=None, + max_workers=None, + deadline=None, + raise_exception=False, +): + """Download many files concurrently by their blob names. + + This function is a PREVIEW FEATURE: the API may change in a future version. + + The destination files are automatically created, with filenames based on + the source blob_names and the path_root. + + The destination files are not automatically deleted if their downloads fail, + so please check the return value of this function for any exceptions, or + enable `raise_exception=True`, and process the files accordingly. + + For example, if the `blob_names` include "icon.jpg", `path_root` is + "/home/myuser/", and `blob_name_prefix` is "images/", then the blob named + "images/icon.jpg" will be downloaded to a file named + "/home/myuser/icon.jpg". + + :type bucket: 'google.cloud.storage.bucket.Bucket' + :param bucket: + The bucket which contains the blobs to be downloaded + + :type blob_names: list(str) + :param blob_names: + A list of blobs to be downloaded. The blob name in this string will be + used to determine the destination file path as well. + + The full name to the blob must be blob_name_prefix + blob_name. The + blob_name is separate from the blob_name_prefix because the blob_name + will also determine the name of the destination blob. Any shared part of + the blob names that need not be part of the destination path should be + included in the blob_name_prefix. + + :type path_root: str + :param path_root: + A string that will be prepended to each blob_name in the input list, + in order to determine the destination path for that blob. The path_root + string will usually end in "/" (or "\\" depending on platform) but is + not required to do so. For instance, if the path_root string is + "/tmp/img-" and a blob_name is "0001.jpg", with an empty + blob_name_prefix, then the source blob "0001.jpg" will be downloaded to + destination "/tmp/img-0001.jpg" . This parameter can be an empty string. + + :type blob_name_prefix: str + :param blob_name_prefix: + A string that will be prepended to each blob_name in the input list, in + order to determine the name of the source blob. Unlike the blob_name + itself, the prefix string does not affect the destination path on the + local filesystem. For instance, if the path_root is "/tmp/img-", the + blob_name_prefix is "myuser/mystuff-" and a blob_name is "0001.jpg" then + the source blob "myuser/mystuff-0001.jpg" will be downloaded to + "/tmp/img-0001.jpg". The blob_name_prefix can be blank (an empty + string). + + :type download_kwargs: dict + :param download_kwargs: + A dictionary of keyword arguments to pass to the download method. Refer + to the documentation for blob.download_to_file() or + blob.download_to_filename() for more information. The dict is directly + passed into the download methods and is not validated by this function. + + :type max_workers: int + :param max_workers: + The number of workers (effectively, the number of threads) to use in + the worker pool. Refer to concurrent.futures.ThreadPoolExecutor + documentation for details. + + :type deadline: int + :param deadline: + The number of seconds to wait for all threads to resolve. If the + deadline is reached, all threads will be terminated regardless of their + progress and concurrent.futures.TimeoutError will be raised. This can be + left as the default of None (no deadline) for most use cases. + + :type raise_exception: bool + :param raise_exception: + If True, instead of adding exceptions to the list of return values, + instead they will be raised. Note that encountering an exception on one + operation will not prevent other operations from starting. Exceptions + are only processed and potentially raised after all operations are + complete in success or failure. If skip_if_exists is True, 412 + Precondition Failed responses are considered part of normal operation + and are not raised as an exception. + + :raises: :exc:`concurrent.futures.TimeoutError` if deadline is exceeded. + + :rtype: list + :returns: A list of results corresponding to, in order, each item in the + input list. If an exception was received, it will be the result + for that operation. Otherwise, the return value from the successful + download method is used (typically, None). + """ + blob_file_pairs = [] + + for blob_name in blob_names: + full_blob_name = blob_name_prefix + blob_name + path = path_root + blob_name + blob_file_pairs.append((bucket.blob(full_blob_name), path)) + + return download_many( + blob_file_pairs, + download_kwargs=download_kwargs, + max_workers=max_workers, + deadline=deadline, + raise_exception=raise_exception, + ) diff --git a/packages/gcp-sphinx-docfx-yaml/tests/__init__.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/version.py similarity index 83% rename from packages/gcp-sphinx-docfx-yaml/tests/__init__.py rename to packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/version.py index 690df65fb6bc..5836d8051156 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/__init__.py +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/google/cloud/storage/version.py @@ -1,10 +1,10 @@ -# Copyright 2021 Google LLC +# Copyright 2020 Google LLC # # 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 +# 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, @@ -12,3 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. +__version__ = "2.5.0" diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/setup.cfg b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/setup.cfg new file mode 100644 index 000000000000..c3a2b39f6528 --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/setup.cfg @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2020 Google LLC +# +# 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 +# +# https://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 by synthtool. DO NOT EDIT! +[bdist_wheel] +universal = 1 diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/setup.py b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/setup.py new file mode 100644 index 000000000000..8686745f71cd --- /dev/null +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/handwritten/setup.py @@ -0,0 +1,95 @@ +# Copyright 2018 Google LLC +# +# 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. + +import io +import os + +import setuptools + + +# Package metadata. + +name = "google-cloud-storage" +description = "Google Cloud Storage API client library" +# Should be one of: +# 'Development Status :: 3 - Alpha' +# 'Development Status :: 4 - Beta' +# 'Development Status :: 5 - Production/Stable' +release_status = "Development Status :: 5 - Production/Stable" +dependencies = [ + "google-auth >= 1.25.0, < 3.0dev", + "google-api-core >= 1.31.5, <3.0.0dev,!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.0", + "google-cloud-core >= 2.3.0, < 3.0dev", + "google-resumable-media >= 2.3.2", + "requests >= 2.18.0, < 3.0.0dev", +] +extras = {"protobuf": ["protobuf<5.0.0dev"]} + + +# Setup boilerplate below this line. + +package_root = os.path.abspath(os.path.dirname(__file__)) + +version = {} +with open(os.path.join(package_root, "google/cloud/storage/version.py")) as fp: + exec(fp.read(), version) +version = version["__version__"] + +readme_filename = os.path.join(package_root, "README.rst") +with io.open(readme_filename, encoding="utf-8") as readme_file: + readme = readme_file.read() + +# Only include packages under the 'google' namespace. Do not include tests, +# benchmarks, etc. +packages = [ + package for package in setuptools.find_packages() if package.startswith("google") +] + +# Determine which namespaces are needed. +namespaces = ["google"] +if "google.cloud" in packages: + namespaces.append("google.cloud") + + +setuptools.setup( + name=name, + version=version, + description=description, + long_description=readme, + author="Google LLC", + author_email="googleapis-packages@google.com", + license="Apache 2.0", + url="https://github.com/googleapis/python-storage", + classifiers=[ + release_status, + "Intended Audience :: Developers", + "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Operating System :: OS Independent", + "Topic :: Internet", + ], + platforms="Posix; MacOS X; Windows", + packages=packages, + namespace_packages=namespaces, + install_requires=dependencies, + extras_require=extras, + python_requires=">=3.7", + include_package_data=True, + zip_safe=False, +) diff --git a/packages/gcp-sphinx-docfx-yaml/tox.ini b/packages/gcp-sphinx-docfx-yaml/tox.ini index 04bfa7aaefbe..ca14c8c0aa02 100644 --- a/packages/gcp-sphinx-docfx-yaml/tox.ini +++ b/packages/gcp-sphinx-docfx-yaml/tox.ini @@ -1,44 +1,21 @@ [tox] -envlist = py37,py38,py39,lint,docs +envlist = tests [testenv] setenv = LANG=C deps = -r{toxinidir}/requirements.txt - pytest - mock commands = py.test {posargs} -[testenv:docs] +[testenv:tests] deps = - sphinx_rtd_theme {[testenv]deps} -changedir = {toxinidir}/docs commands = - sphinx-build -D extensions=sphinx.ext.autodoc,sphinx.ext.autosummary,docfx_yaml.extension,sphinx.ext.intersphinx,sphinx.ext.coverage,sphinx.ext.napoleon,sphinx.ext.todo,sphinx.ext.viewcode -b html -d {envtmpdir}/doctrees . {envtmpdir}/html + python3 -m pytest tests -[testenv:unittest] +[testenv:update_goldens] deps = {[testenv]deps} commands = - python3 -m unittest tests/test_unit.py tests/test_helpers.py tests/test_markdown.py - -[testenv:librarytest] -deps = - sphinx_rtd_theme - {[testenv]deps} -changedir = {toxinidir}/docs -commands = - sphinx-build -D extensions=sphinx.ext.autodoc,sphinx.ext.autosummary,docfx_yaml.extension,sphinx.ext.intersphinx,sphinx.ext.coverage,sphinx.ext.napoleon,sphinx.ext.todo,sphinx.ext.viewcode -b html -d {envtmpdir}/doctrees . {envtmpdir}/html - -[testenv:lint] -deps = - {[testenv]deps} - prospector - pylint<1.7.0 -commands = - prospector \ - --profile-path={toxinidir} \ - --profile=prospector \ - --die-on-tool-error + python3 -m pytest --update-goldens True tests/test_goldens.py From 29d464bbf2b45fd0de1de3e9e40fa2e43a235ed4 Mon Sep 17 00:00:00 2001 From: Dan Lee <71398022+dandhlee@users.noreply.github.com> Date: Wed, 2 Nov 2022 12:02:46 -0400 Subject: [PATCH 167/279] fix: remove unused YAML fields to fix presubmit (#265) * fix: remove unused YAML fields for repo * test: remove patch on goldens test for repo * test: update goldens --- .../docfx_yaml/extension.py | 10 - .../tests/test_goldens.py | 13 - ...text_to_speech.TextToSpeechAsyncClient.yml | 88 ------ ...ices.text_to_speech.TextToSpeechClient.yml | 88 ------ ...exttospeech_v1.services.text_to_speech.yml | 4 - ...loud.texttospeech_v1.types.AudioConfig.yml | 4 - ...ud.texttospeech_v1.types.AudioEncoding.yml | 4 - ....types.CustomVoiceParams.ReportedUsage.yml | 4 - ...exttospeech_v1.types.CustomVoiceParams.yml | 4 - ...exttospeech_v1.types.ListVoicesRequest.yml | 4 - ...xttospeech_v1.types.ListVoicesResponse.yml | 4 - ....texttospeech_v1.types.SsmlVoiceGender.yml | 4 - ...d.texttospeech_v1.types.SynthesisInput.yml | 4 - ...peech_v1.types.SynthesizeSpeechRequest.yml | 4 - ...eech_v1.types.SynthesizeSpeechResponse.yml | 4 - ...ogle.cloud.texttospeech_v1.types.Voice.yml | 4 - ...tospeech_v1.types.VoiceSelectionParams.yml | 4 - .../google.cloud.texttospeech_v1.types.yml | 4 - ...text_to_speech.TextToSpeechAsyncClient.yml | 88 ------ ...ices.text_to_speech.TextToSpeechClient.yml | 88 ------ ...speech_v1beta1.services.text_to_speech.yml | 4 - ...texttospeech_v1beta1.types.AudioConfig.yml | 4 - ...xttospeech_v1beta1.types.AudioEncoding.yml | 4 - ....types.CustomVoiceParams.ReportedUsage.yml | 4 - ...speech_v1beta1.types.CustomVoiceParams.yml | 4 - ...speech_v1beta1.types.ListVoicesRequest.yml | 4 - ...peech_v1beta1.types.ListVoicesResponse.yml | 4 - ...tospeech_v1beta1.types.SsmlVoiceGender.yml | 4 - ...ttospeech_v1beta1.types.SynthesisInput.yml | 4 - ....SynthesizeSpeechRequest.TimepointType.yml | 4 - ..._v1beta1.types.SynthesizeSpeechRequest.yml | 4 - ...v1beta1.types.SynthesizeSpeechResponse.yml | 4 - ...d.texttospeech_v1beta1.types.Timepoint.yml | 4 - ...cloud.texttospeech_v1beta1.types.Voice.yml | 4 - ...ech_v1beta1.types.VoiceSelectionParams.yml | 4 - ...oogle.cloud.texttospeech_v1beta1.types.yml | 4 - ...loud.pubsub_v1.publisher.client.Client.yml | 164 ----------- ...oogle.cloud.pubsub_v1.publisher.client.yml | 4 - ...oud.pubsub_v1.publisher.futures.Future.yml | 48 ---- ...ogle.cloud.pubsub_v1.publisher.futures.yml | 4 - ...oud.pubsub_v1.subscriber.client.Client.yml | 188 ------------- ...ogle.cloud.pubsub_v1.subscriber.client.yml | 4 - ...ud.pubsub_v1.subscriber.futures.Future.yml | 48 ---- ...subscriber.futures.StreamingPullFuture.yml | 48 ---- ...gle.cloud.pubsub_v1.subscriber.futures.yml | 4 - ...d.pubsub_v1.subscriber.message.Message.yml | 64 ----- ...bsub_v1.subscriber.scheduler.Scheduler.yml | 16 -- ...1.subscriber.scheduler.ThreadScheduler.yml | 16 -- ...e.cloud.pubsub_v1.subscriber.scheduler.yml | 4 - ...oud.pubsub_v1.types.AcknowledgeRequest.yml | 4 - ...ogle.cloud.pubsub_v1.types.AuditConfig.yml | 4 - ...cloud.pubsub_v1.types.AuditConfigDelta.yml | 4 - ...google.cloud.pubsub_v1.types.AuditData.yml | 4 - ...e.cloud.pubsub_v1.types.AuditLogConfig.yml | 4 - ...le.cloud.pubsub_v1.types.BatchSettings.yml | 20 -- ...d.pubsub_v1.types.BigQueryConfig.State.yml | 4 - ...e.cloud.pubsub_v1.types.BigQueryConfig.yml | 4 - .../google.cloud.pubsub_v1.types.Binding.yml | 4 - ...gle.cloud.pubsub_v1.types.BindingDelta.yml | 4 - ...ypes.CreateSnapshotRequest.LabelsEntry.yml | 4 - ....pubsub_v1.types.CreateSnapshotRequest.yml | 4 - ...loud.pubsub_v1.types.CustomHttpPattern.yml | 4 - ...cloud.pubsub_v1.types.DeadLetterPolicy.yml | 4 - ....pubsub_v1.types.DeleteSnapshotRequest.yml | 4 - ...sub_v1.types.DeleteSubscriptionRequest.yml | 4 - ...oud.pubsub_v1.types.DeleteTopicRequest.yml | 4 - ...1.types.DescriptorProto.ExtensionRange.yml | 4 - ...v1.types.DescriptorProto.ReservedRange.yml | 4 - ....cloud.pubsub_v1.types.DescriptorProto.yml | 4 - ...sub_v1.types.DetachSubscriptionRequest.yml | 4 - ...ub_v1.types.DetachSubscriptionResponse.yml | 4 - .../google.cloud.pubsub_v1.types.Duration.yml | 4 - .../google.cloud.pubsub_v1.types.Empty.yml | 4 - ....EnumDescriptorProto.EnumReservedRange.yml | 4 - ...ud.pubsub_v1.types.EnumDescriptorProto.yml | 4 - ...ogle.cloud.pubsub_v1.types.EnumOptions.yml | 4 - ...bsub_v1.types.EnumValueDescriptorProto.yml | 4 - ...cloud.pubsub_v1.types.EnumValueOptions.yml | 4 - ...cloud.pubsub_v1.types.ExpirationPolicy.yml | 4 - ....pubsub_v1.types.ExtensionRangeOptions.yml | 4 - ...d.pubsub_v1.types.FieldDescriptorProto.yml | 4 - ...google.cloud.pubsub_v1.types.FieldMask.yml | 4 - ...gle.cloud.pubsub_v1.types.FieldOptions.yml | 4 - ...ud.pubsub_v1.types.FileDescriptorProto.yml | 4 - ...loud.pubsub_v1.types.FileDescriptorSet.yml | 4 - ...ogle.cloud.pubsub_v1.types.FileOptions.yml | 4 - ...ogle.cloud.pubsub_v1.types.FlowControl.yml | 28 -- ..._v1.types.GeneratedCodeInfo.Annotation.yml | 4 - ...loud.pubsub_v1.types.GeneratedCodeInfo.yml | 4 - ...ud.pubsub_v1.types.GetIamPolicyRequest.yml | 4 - ...oud.pubsub_v1.types.GetSnapshotRequest.yml | 4 - ...pubsub_v1.types.GetSubscriptionRequest.yml | 4 - ....cloud.pubsub_v1.types.GetTopicRequest.yml | 4 - .../google.cloud.pubsub_v1.types.Http.yml | 4 - .../google.cloud.pubsub_v1.types.HttpRule.yml | 4 - ....pubsub_v1.types.LimitExceededBehavior.yml | 4 - ...d.pubsub_v1.types.ListSnapshotsRequest.yml | 4 - ....pubsub_v1.types.ListSnapshotsResponse.yml | 4 - ...bsub_v1.types.ListSubscriptionsRequest.yml | 4 - ...sub_v1.types.ListSubscriptionsResponse.yml | 4 - ...sub_v1.types.ListTopicSnapshotsRequest.yml | 4 - ...ub_v1.types.ListTopicSnapshotsResponse.yml | 4 - ...v1.types.ListTopicSubscriptionsRequest.yml | 4 - ...1.types.ListTopicSubscriptionsResponse.yml | 4 - ...loud.pubsub_v1.types.ListTopicsRequest.yml | 4 - ...oud.pubsub_v1.types.ListTopicsResponse.yml | 4 - ...e.cloud.pubsub_v1.types.MessageOptions.yml | 4 - ...d.pubsub_v1.types.MessageStoragePolicy.yml | 4 - ....pubsub_v1.types.MethodDescriptorProto.yml | 4 - ...le.cloud.pubsub_v1.types.MethodOptions.yml | 4 - ...bsub_v1.types.ModifyAckDeadlineRequest.yml | 4 - ...ubsub_v1.types.ModifyPushConfigRequest.yml | 4 - ...d.pubsub_v1.types.OneofDescriptorProto.yml | 4 - ...gle.cloud.pubsub_v1.types.OneofOptions.yml | 4 - .../google.cloud.pubsub_v1.types.Policy.yml | 4 - ...ogle.cloud.pubsub_v1.types.PolicyDelta.yml | 4 - ...oud.pubsub_v1.types.PublishFlowControl.yml | 20 -- ...e.cloud.pubsub_v1.types.PublishRequest.yml | 4 - ....cloud.pubsub_v1.types.PublishResponse.yml | 4 - ...cloud.pubsub_v1.types.PublisherOptions.yml | 24 -- ...v1.types.PubsubMessage.AttributesEntry.yml | 4 - ...le.cloud.pubsub_v1.types.PubsubMessage.yml | 4 - ...ogle.cloud.pubsub_v1.types.PullRequest.yml | 4 - ...gle.cloud.pubsub_v1.types.PullResponse.yml | 4 - ...ub_v1.types.PushConfig.AttributesEntry.yml | 4 - ...d.pubsub_v1.types.PushConfig.OidcToken.yml | 4 - ...oogle.cloud.pubsub_v1.types.PushConfig.yml | 4 - ....cloud.pubsub_v1.types.ReceivedMessage.yml | 4 - ...ogle.cloud.pubsub_v1.types.RetryPolicy.yml | 4 - ...e.cloud.pubsub_v1.types.SchemaSettings.yml | 4 - ...ogle.cloud.pubsub_v1.types.SeekRequest.yml | 4 - ...gle.cloud.pubsub_v1.types.SeekResponse.yml | 4 - ...pubsub_v1.types.ServiceDescriptorProto.yml | 4 - ...e.cloud.pubsub_v1.types.ServiceOptions.yml | 4 - ...ud.pubsub_v1.types.SetIamPolicyRequest.yml | 4 - ...d.pubsub_v1.types.Snapshot.LabelsEntry.yml | 4 - .../google.cloud.pubsub_v1.types.Snapshot.yml | 4 - ...ubsub_v1.types.SourceCodeInfo.Location.yml | 4 - ...e.cloud.pubsub_v1.types.SourceCodeInfo.yml | 4 - ...d.pubsub_v1.types.StreamingPullRequest.yml | 4 - ...ngPullResponse.AcknowledgeConfirmation.yml | 4 - ...Response.ModifyAckDeadlineConfirmation.yml | 4 - ...ingPullResponse.SubscriptionProperties.yml | 4 - ....pubsub_v1.types.StreamingPullResponse.yml | 4 - ...bsub_v1.types.Subscription.LabelsEntry.yml | 4 - ...oud.pubsub_v1.types.Subscription.State.yml | 4 - ...gle.cloud.pubsub_v1.types.Subscription.yml | 4 - ...sub_v1.types.TestIamPermissionsRequest.yml | 4 - ...ub_v1.types.TestIamPermissionsResponse.yml | 4 - ...google.cloud.pubsub_v1.types.Timestamp.yml | 4 - ...loud.pubsub_v1.types.Topic.LabelsEntry.yml | 4 - .../google.cloud.pubsub_v1.types.Topic.yml | 4 - ..._v1.types.UninterpretedOption.NamePart.yml | 4 - ...ud.pubsub_v1.types.UninterpretedOption.yml | 4 - ....pubsub_v1.types.UpdateSnapshotRequest.yml | 4 - ...sub_v1.types.UpdateSubscriptionRequest.yml | 4 - ...oud.pubsub_v1.types.UpdateTopicRequest.yml | 4 - .../google.cloud.pubsub_v1.types.yml | 4 - ...er.pagers.ListTopicSnapshotsAsyncPager.yml | 8 - ...blisher.pagers.ListTopicSnapshotsPager.yml | 8 - ...agers.ListTopicSubscriptionsAsyncPager.yml | 8 - ...her.pagers.ListTopicSubscriptionsPager.yml | 8 - ....publisher.pagers.ListTopicsAsyncPager.yml | 8 - ...vices.publisher.pagers.ListTopicsPager.yml | 8 - ...le.pubsub_v1.services.publisher.pagers.yml | 4 - ...scriber.pagers.ListSnapshotsAsyncPager.yml | 8 - ...s.subscriber.pagers.ListSnapshotsPager.yml | 8 - ...ber.pagers.ListSubscriptionsAsyncPager.yml | 8 - ...bscriber.pagers.ListSubscriptionsPager.yml | 8 - ...e.pubsub_v1.services.subscriber.pagers.yml | 4 - .../google.cloud.storage.acl.ACL.yml | 80 ------ .../google.cloud.storage.acl.BucketACL.yml | 20 -- ...gle.cloud.storage.acl.DefaultObjectACL.yml | 4 - .../google.cloud.storage.acl.ObjectACL.yml | 20 -- .../handwritten/google.cloud.storage.acl.yml | 4 - .../google.cloud.storage.batch.Batch.yml | 12 - ...loud.storage.batch.MIMEApplicationHTTP.yml | 8 - .../google.cloud.storage.batch.yml | 4 - .../google.cloud.storage.blob.Blob.yml | 252 ----------------- .../handwritten/google.cloud.storage.blob.yml | 4 - .../google.cloud.storage.bucket.Bucket.yml | 264 ------------------ ....cloud.storage.bucket.IAMConfiguration.yml | 76 ----- ...ycleRuleAbortIncompleteMultipartUpload.yml | 52 ---- ...storage.bucket.LifecycleRuleConditions.yml | 96 ------- ...oud.storage.bucket.LifecycleRuleDelete.yml | 52 ---- ...ge.bucket.LifecycleRuleSetStorageClass.yml | 52 ---- .../google.cloud.storage.bucket.yml | 4 - .../google.cloud.storage.client.Client.yml | 68 ----- .../google.cloud.storage.client.yml | 4 - .../google.cloud.storage.constants.yml | 4 - ...google.cloud.storage.fileio.BlobReader.yml | 32 --- ...google.cloud.storage.fileio.BlobWriter.yml | 32 --- ...gle.cloud.storage.fileio.SlidingBuffer.yml | 28 -- .../google.cloud.storage.fileio.yml | 4 - ...cloud.storage.hmac_key.HMACKeyMetadata.yml | 72 ----- .../google.cloud.storage.hmac_key.yml | 4 - ...torage.notification.BucketNotification.yml | 72 ----- .../google.cloud.storage.notification.yml | 4 - ...d.storage.retry.ConditionalRetryPolicy.yml | 4 - .../google.cloud.storage.retry.yml | 20 -- 200 files changed, 3059 deletions(-) diff --git a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py index 61c56830e2c0..5eb32fac1379 100644 --- a/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py +++ b/packages/gcp-sphinx-docfx-yaml/docfx_yaml/extension.py @@ -935,11 +935,6 @@ def _update_friendly_package_name(path): 'name': short_name, 'fullName': name, 'source': { - 'remote': { - 'path': path, - 'branch': app.env.docfx_branch, - 'repo': app.env.docfx_remote, - }, 'id': short_name, 'path': path, 'startLine': start_line, @@ -1735,11 +1730,6 @@ def convert_module_to_package_if_needed(obj): except NameError: pass - if 'source' in obj and (not obj['source']['remote']['repo'] or \ - obj['source']['remote']['repo'] == 'https://apidrop.visualstudio.com/Content%20CI/_git/ReferenceAutomation'): - del(obj['source']) - - # Extract any missing cross references where applicable. # Potential targets are instances of full uid shown, or # if we find a short form of the uid of one of current diff --git a/packages/gcp-sphinx-docfx-yaml/tests/test_goldens.py b/packages/gcp-sphinx-docfx-yaml/tests/test_goldens.py index 637862a00714..9067c6002fea 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/test_goldens.py +++ b/packages/gcp-sphinx-docfx-yaml/tests/test_goldens.py @@ -97,19 +97,6 @@ def test_goldens(update_goldens, test_dir): if update_goldens: shutil.rmtree(golden_dir, ignore_errors=True) - files_to_move = out_dir.rglob("*") - - # Overwrite incorrect repo data used compared to GH Action. - incorrect_repo = "git@github.com:googleapis/sphinx-docfx-yaml.git" - correct_repo = "https://github.com/googleapis/sphinx-docfx-yaml" - - for yaml_file in files_to_move: - with open(yaml_file) as file: - lines = file.read() - lines = lines.replace(incorrect_repo, correct_repo) - with open(yaml_file, 'w') as file: - file.write(lines) - shutil.copytree(out_dir, golden_dir, dirs_exist_ok=True) pytest.skip( "Updated goldens! Re-run the test without the --update-goldens flag." diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.yml index f88b9e128547..d943d856e729 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.yml +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechAsyncClient.yml @@ -35,10 +35,6 @@ items: source: id: TextToSpeechAsyncClient path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/async_client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/async_client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 41 summary: 'Service that implements Google Cloud Text-to-Speech API. @@ -65,10 +61,6 @@ items: source: id: TextToSpeechAsyncClient path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/async_client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/async_client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 41 summary: 'Instantiates the text to speech client. @@ -117,10 +109,6 @@ items: source: id: common_billing_account_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 185 summary: 'Returns a fully-qualified billing_account string. @@ -141,10 +129,6 @@ items: source: id: common_folder_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 200 summary: 'Returns a fully-qualified folder string. @@ -165,10 +149,6 @@ items: source: id: common_location_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 245 summary: 'Returns a fully-qualified location string. @@ -189,10 +169,6 @@ items: source: id: common_organization_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 215 summary: 'Returns a fully-qualified organization string. @@ -213,10 +189,6 @@ items: source: id: common_project_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 230 summary: 'Returns a fully-qualified project string. @@ -237,10 +209,6 @@ items: source: id: from_service_account_file path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/async_client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/async_client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 87 summary: "Creates an instance of this client using the provided credentials\n \ \ file.\n" @@ -265,10 +233,6 @@ items: source: id: from_service_account_info path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/async_client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/async_client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 72 summary: "Creates an instance of this client using the provided credentials\n \ \ info.\n" @@ -293,10 +257,6 @@ items: source: id: from_service_account_json path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/async_client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/async_client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 87 summary: "Creates an instance of this client using the provided credentials\n \ \ file.\n" @@ -321,10 +281,6 @@ items: source: id: get_mtls_endpoint_and_cert_source path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/async_client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/async_client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 105 summary: 'Return the API endpoint and client cert source for mutual TLS. @@ -390,10 +346,6 @@ items: source: id: get_transport_class path: null - remote: - branch: add_goldens - path: null - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: null summary: 'Returns an appropriate transport class. @@ -413,10 +365,6 @@ items: source: id: list_voices path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/async_client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/async_client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 201 summary: "Returns a list of Voice supported for synthesis.\n\n```python\n# This\ \ snippet has been automatically generated and should be regarded as a\n# code\ @@ -477,10 +425,6 @@ items: source: id: model_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 163 summary: 'Returns a fully-qualified model string. @@ -501,10 +445,6 @@ items: source: id: parse_common_billing_account_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 194 summary: 'Parse a billing_account path into its component segments. @@ -525,10 +465,6 @@ items: source: id: parse_common_folder_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 209 summary: 'Parse a folder path into its component segments. @@ -549,10 +485,6 @@ items: source: id: parse_common_location_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 256 summary: 'Parse a location path into its component segments. @@ -573,10 +505,6 @@ items: source: id: parse_common_organization_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 224 summary: 'Parse a organization path into its component segments. @@ -597,10 +525,6 @@ items: source: id: parse_common_project_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 239 summary: 'Parse a project path into its component segments. @@ -621,10 +545,6 @@ items: source: id: parse_model_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 176 summary: 'Parses a model path into its component segments. @@ -645,10 +565,6 @@ items: source: id: synthesize_speech path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/async_client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/async_client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 303 summary: "Synthesizes speech synchronously: receive results\nafter all text input\ \ has been processed.\n\n```python\n# This snippet has been automatically generated\ @@ -723,10 +639,6 @@ items: source: id: transport path: null - remote: - branch: add_goldens - path: null - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: null summary: 'Returns the transport used by the client instance. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.yml index bafb3765cfbf..cb01258bfe2e 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.yml +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.services.text_to_speech.TextToSpeechClient.yml @@ -35,10 +35,6 @@ items: source: id: TextToSpeechClient path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 78 summary: 'Service that implements Google Cloud Text-to-Speech API. @@ -65,10 +61,6 @@ items: source: id: TextToSpeechClient path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 78 summary: 'Instantiates the text to speech client. @@ -122,10 +114,6 @@ items: source: id: __exit__ path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 661 summary: 'Releases underlying transport''s resources. @@ -156,10 +144,6 @@ items: source: id: common_billing_account_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 185 summary: 'Returns a fully-qualified billing_account string. @@ -180,10 +164,6 @@ items: source: id: common_folder_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 200 summary: 'Returns a fully-qualified folder string. @@ -204,10 +184,6 @@ items: source: id: common_location_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 245 summary: 'Returns a fully-qualified location string. @@ -228,10 +204,6 @@ items: source: id: common_organization_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 215 summary: 'Returns a fully-qualified organization string. @@ -252,10 +224,6 @@ items: source: id: common_project_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 230 summary: 'Returns a fully-qualified project string. @@ -276,10 +244,6 @@ items: source: id: from_service_account_file path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 133 summary: "Creates an instance of this client using the provided credentials\n \ \ file.\n" @@ -304,10 +268,6 @@ items: source: id: from_service_account_info path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 116 summary: "Creates an instance of this client using the provided credentials\n \ \ info.\n" @@ -332,10 +292,6 @@ items: source: id: from_service_account_json path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 133 summary: "Creates an instance of this client using the provided credentials\n \ \ file.\n" @@ -360,10 +316,6 @@ items: source: id: get_mtls_endpoint_and_cert_source path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 262 summary: 'Return the API endpoint and client cert source for mutual TLS. @@ -429,10 +381,6 @@ items: source: id: list_voices path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 428 summary: "Returns a list of Voice supported for synthesis.\n\n```python\n# This\ \ snippet has been automatically generated and should be regarded as a\n# code\ @@ -493,10 +441,6 @@ items: source: id: model_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 163 summary: 'Returns a fully-qualified model string. @@ -517,10 +461,6 @@ items: source: id: parse_common_billing_account_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 194 summary: 'Parse a billing_account path into its component segments. @@ -541,10 +481,6 @@ items: source: id: parse_common_folder_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 209 summary: 'Parse a folder path into its component segments. @@ -565,10 +501,6 @@ items: source: id: parse_common_location_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 256 summary: 'Parse a location path into its component segments. @@ -589,10 +521,6 @@ items: source: id: parse_common_organization_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 224 summary: 'Parse a organization path into its component segments. @@ -613,10 +541,6 @@ items: source: id: parse_common_project_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 239 summary: 'Parse a project path into its component segments. @@ -637,10 +561,6 @@ items: source: id: parse_model_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 176 summary: 'Parses a model path into its component segments. @@ -661,10 +581,6 @@ items: source: id: synthesize_speech path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 530 summary: "Synthesizes speech synchronously: receive results\nafter all text input\ \ has been processed.\n\n```python\n# This snippet has been automatically generated\ @@ -739,10 +655,6 @@ items: source: id: transport path: null - remote: - branch: add_goldens - path: null - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: null summary: 'Returns the transport used by the client instance. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.services.text_to_speech.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.services.text_to_speech.yml index 9a054deabc2a..326e773c2625 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.services.text_to_speech.yml +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.services.text_to_speech.yml @@ -12,10 +12,6 @@ items: source: id: text_to_speech path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/__init__.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/services/text_to_speech/__init__.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 0 summary: API documentation for `texttospeech_v1.services.text_to_speech` package. syntax: {} diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.AudioConfig.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.AudioConfig.yml index 68fd0289c8e5..68b91b99f501 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.AudioConfig.yml +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.AudioConfig.yml @@ -57,10 +57,6 @@ items: source: id: AudioConfig path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 262 summary: 'Description of audio data to be synthesized. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.AudioEncoding.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.AudioEncoding.yml index 8a5907cca536..1b25991b6a18 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.AudioEncoding.yml +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.AudioEncoding.yml @@ -23,10 +23,6 @@ items: source: id: AudioEncoding path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 46 summary: 'Configuration to set up audio encoder. The encoding diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.CustomVoiceParams.ReportedUsage.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.CustomVoiceParams.ReportedUsage.yml index 066f9cea470d..d488ec73198f 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.CustomVoiceParams.ReportedUsage.yml +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.CustomVoiceParams.ReportedUsage.yml @@ -23,10 +23,6 @@ items: source: id: ReportedUsage path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 348 summary: 'The usage of the synthesized audio. You must report your diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.CustomVoiceParams.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.CustomVoiceParams.yml index 76ed7b4ddbb1..4d62996ffcf2 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.CustomVoiceParams.yml +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.CustomVoiceParams.yml @@ -24,10 +24,6 @@ items: source: id: CustomVoiceParams path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 336 summary: 'Description of the custom voice to be synthesized. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.ListVoicesRequest.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.ListVoicesRequest.yml index 3beda141801f..88894370623c 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.ListVoicesRequest.yml +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.ListVoicesRequest.yml @@ -25,10 +25,6 @@ items: source: id: ListVoicesRequest path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 58 summary: 'The top-level message sent by the client for the `ListVoices` diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.ListVoicesResponse.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.ListVoicesResponse.yml index 33beba4488f0..0c98c54a49b7 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.ListVoicesResponse.yml +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.ListVoicesResponse.yml @@ -19,10 +19,6 @@ items: source: id: ListVoicesResponse path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 81 summary: 'The message returned to the client by the `ListVoices` method. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.SsmlVoiceGender.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.SsmlVoiceGender.yml index d3f57ad70391..5b260459d6aa 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.SsmlVoiceGender.yml +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.SsmlVoiceGender.yml @@ -23,10 +23,6 @@ items: source: id: SsmlVoiceGender path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 36 summary: 'Gender of the voice as described in `SSML voice diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.SynthesisInput.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.SynthesisInput.yml index 0c4255ce6485..3aae020352e4 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.SynthesisInput.yml +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.SynthesisInput.yml @@ -26,10 +26,6 @@ items: source: id: SynthesisInput path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 166 summary: 'Contains text input to be synthesized. Either `text` or `ssml` diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.SynthesizeSpeechRequest.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.SynthesizeSpeechRequest.yml index 10c55f04a6e8..0d512f13840b 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.SynthesizeSpeechRequest.yml +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.SynthesizeSpeechRequest.yml @@ -26,10 +26,6 @@ items: source: id: SynthesizeSpeechRequest path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 133 summary: 'The top-level message sent by the client for the diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.SynthesizeSpeechResponse.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.SynthesizeSpeechResponse.yml index 5617e3e8dd23..e4c4e76242cc 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.SynthesizeSpeechResponse.yml +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.SynthesizeSpeechResponse.yml @@ -23,10 +23,6 @@ items: source: id: SynthesizeSpeechResponse path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 368 summary: 'The message returned to the client by the `SynthesizeSpeech` diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.Voice.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.Voice.yml index b359bef43a12..f3b46abd9f28 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.Voice.yml +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.Voice.yml @@ -30,10 +30,6 @@ items: source: id: Voice path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 96 summary: 'Description of a voice supported by the TTS service. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.VoiceSelectionParams.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.VoiceSelectionParams.yml index b31c083ea718..ba0785e99c3e 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.VoiceSelectionParams.yml +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.VoiceSelectionParams.yml @@ -45,10 +45,6 @@ items: source: id: VoiceSelectionParams path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/cloud_tts.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 206 summary: 'Description of which voice to use for a synthesis request. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.yml index 62e40a3ea2cf..6ad4b9384b79 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.yml +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1.types.yml @@ -21,10 +21,6 @@ items: source: id: types path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/__init__.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1/types/__init__.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 0 summary: API documentation for `texttospeech_v1.types` package. syntax: {} diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.yml index 9ba4d5d190e0..9233143da7c8 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.yml +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechAsyncClient.yml @@ -35,10 +35,6 @@ items: source: id: TextToSpeechAsyncClient path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/async_client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/async_client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 41 summary: 'Service that implements Google Cloud Text-to-Speech API. @@ -65,10 +61,6 @@ items: source: id: TextToSpeechAsyncClient path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/async_client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/async_client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 41 summary: 'Instantiates the text to speech client. @@ -117,10 +109,6 @@ items: source: id: common_billing_account_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 185 summary: 'Returns a fully-qualified billing_account string. @@ -141,10 +129,6 @@ items: source: id: common_folder_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 200 summary: 'Returns a fully-qualified folder string. @@ -165,10 +149,6 @@ items: source: id: common_location_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 245 summary: 'Returns a fully-qualified location string. @@ -189,10 +169,6 @@ items: source: id: common_organization_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 215 summary: 'Returns a fully-qualified organization string. @@ -213,10 +189,6 @@ items: source: id: common_project_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 230 summary: 'Returns a fully-qualified project string. @@ -237,10 +209,6 @@ items: source: id: from_service_account_file path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/async_client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/async_client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 87 summary: "Creates an instance of this client using the provided credentials\n \ \ file.\n" @@ -265,10 +233,6 @@ items: source: id: from_service_account_info path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/async_client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/async_client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 72 summary: "Creates an instance of this client using the provided credentials\n \ \ info.\n" @@ -293,10 +257,6 @@ items: source: id: from_service_account_json path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/async_client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/async_client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 87 summary: "Creates an instance of this client using the provided credentials\n \ \ file.\n" @@ -321,10 +281,6 @@ items: source: id: get_mtls_endpoint_and_cert_source path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/async_client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/async_client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 105 summary: 'Return the API endpoint and client cert source for mutual TLS. @@ -390,10 +346,6 @@ items: source: id: get_transport_class path: null - remote: - branch: add_goldens - path: null - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: null summary: 'Returns an appropriate transport class. @@ -413,10 +365,6 @@ items: source: id: list_voices path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/async_client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/async_client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 201 summary: "Returns a list of Voice supported for synthesis.\n\n```python\n# This\ \ snippet has been automatically generated and should be regarded as a\n# code\ @@ -477,10 +425,6 @@ items: source: id: model_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 163 summary: 'Returns a fully-qualified model string. @@ -501,10 +445,6 @@ items: source: id: parse_common_billing_account_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 194 summary: 'Parse a billing_account path into its component segments. @@ -525,10 +465,6 @@ items: source: id: parse_common_folder_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 209 summary: 'Parse a folder path into its component segments. @@ -549,10 +485,6 @@ items: source: id: parse_common_location_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 256 summary: 'Parse a location path into its component segments. @@ -573,10 +505,6 @@ items: source: id: parse_common_organization_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 224 summary: 'Parse a organization path into its component segments. @@ -597,10 +525,6 @@ items: source: id: parse_common_project_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 239 summary: 'Parse a project path into its component segments. @@ -621,10 +545,6 @@ items: source: id: parse_model_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 176 summary: 'Parses a model path into its component segments. @@ -645,10 +565,6 @@ items: source: id: synthesize_speech path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/async_client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/async_client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 303 summary: "Synthesizes speech synchronously: receive results\nafter all text input\ \ has been processed.\n\n```python\n# This snippet has been automatically generated\ @@ -723,10 +639,6 @@ items: source: id: transport path: null - remote: - branch: add_goldens - path: null - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: null summary: 'Returns the transport used by the client instance. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.yml index 9b83f59cd439..1675ddc33ca2 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.yml +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.services.text_to_speech.TextToSpeechClient.yml @@ -35,10 +35,6 @@ items: source: id: TextToSpeechClient path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 78 summary: 'Service that implements Google Cloud Text-to-Speech API. @@ -65,10 +61,6 @@ items: source: id: TextToSpeechClient path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 78 summary: 'Instantiates the text to speech client. @@ -122,10 +114,6 @@ items: source: id: __exit__ path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 661 summary: 'Releases underlying transport''s resources. @@ -156,10 +144,6 @@ items: source: id: common_billing_account_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 185 summary: 'Returns a fully-qualified billing_account string. @@ -180,10 +164,6 @@ items: source: id: common_folder_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 200 summary: 'Returns a fully-qualified folder string. @@ -204,10 +184,6 @@ items: source: id: common_location_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 245 summary: 'Returns a fully-qualified location string. @@ -228,10 +204,6 @@ items: source: id: common_organization_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 215 summary: 'Returns a fully-qualified organization string. @@ -252,10 +224,6 @@ items: source: id: common_project_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 230 summary: 'Returns a fully-qualified project string. @@ -276,10 +244,6 @@ items: source: id: from_service_account_file path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 133 summary: "Creates an instance of this client using the provided credentials\n \ \ file.\n" @@ -304,10 +268,6 @@ items: source: id: from_service_account_info path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 116 summary: "Creates an instance of this client using the provided credentials\n \ \ info.\n" @@ -332,10 +292,6 @@ items: source: id: from_service_account_json path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 133 summary: "Creates an instance of this client using the provided credentials\n \ \ file.\n" @@ -360,10 +316,6 @@ items: source: id: get_mtls_endpoint_and_cert_source path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 262 summary: 'Return the API endpoint and client cert source for mutual TLS. @@ -429,10 +381,6 @@ items: source: id: list_voices path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 428 summary: "Returns a list of Voice supported for synthesis.\n\n```python\n# This\ \ snippet has been automatically generated and should be regarded as a\n# code\ @@ -493,10 +441,6 @@ items: source: id: model_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 163 summary: 'Returns a fully-qualified model string. @@ -517,10 +461,6 @@ items: source: id: parse_common_billing_account_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 194 summary: 'Parse a billing_account path into its component segments. @@ -541,10 +481,6 @@ items: source: id: parse_common_folder_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 209 summary: 'Parse a folder path into its component segments. @@ -565,10 +501,6 @@ items: source: id: parse_common_location_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 256 summary: 'Parse a location path into its component segments. @@ -589,10 +521,6 @@ items: source: id: parse_common_organization_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 224 summary: 'Parse a organization path into its component segments. @@ -613,10 +541,6 @@ items: source: id: parse_common_project_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 239 summary: 'Parse a project path into its component segments. @@ -637,10 +561,6 @@ items: source: id: parse_model_path path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 176 summary: 'Parses a model path into its component segments. @@ -661,10 +581,6 @@ items: source: id: synthesize_speech path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 530 summary: "Synthesizes speech synchronously: receive results\nafter all text input\ \ has been processed.\n\n```python\n# This snippet has been automatically generated\ @@ -739,10 +655,6 @@ items: source: id: transport path: null - remote: - branch: add_goldens - path: null - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: null summary: 'Returns the transport used by the client instance. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.services.text_to_speech.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.services.text_to_speech.yml index c58a644d368e..cec2caa30c81 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.services.text_to_speech.yml +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.services.text_to_speech.yml @@ -12,10 +12,6 @@ items: source: id: text_to_speech path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/__init__.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/services/text_to_speech/__init__.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 0 summary: API documentation for `texttospeech_v1beta1.services.text_to_speech` package. syntax: {} diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.AudioConfig.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.AudioConfig.yml index c79100bc5255..60905825a885 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.AudioConfig.yml +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.AudioConfig.yml @@ -57,10 +57,6 @@ items: source: id: AudioConfig path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 279 summary: 'Description of audio data to be synthesized. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.AudioEncoding.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.AudioEncoding.yml index 1c76899c2414..8b6d3d79ca8a 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.AudioEncoding.yml +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.AudioEncoding.yml @@ -23,10 +23,6 @@ items: source: id: AudioEncoding path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 47 summary: 'Configuration to set up audio encoder. The encoding diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.CustomVoiceParams.ReportedUsage.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.CustomVoiceParams.ReportedUsage.yml index 14f55e157e32..9d240617d206 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.CustomVoiceParams.ReportedUsage.yml +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.CustomVoiceParams.ReportedUsage.yml @@ -23,10 +23,6 @@ items: source: id: ReportedUsage path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 365 summary: 'The usage of the synthesized audio. You must report your diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.CustomVoiceParams.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.CustomVoiceParams.yml index d074295a40fe..44fc9f93801a 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.CustomVoiceParams.yml +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.CustomVoiceParams.yml @@ -24,10 +24,6 @@ items: source: id: CustomVoiceParams path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 353 summary: 'Description of the custom voice to be synthesized. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.ListVoicesRequest.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.ListVoicesRequest.yml index 14522408407b..047f02702c03 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.ListVoicesRequest.yml +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.ListVoicesRequest.yml @@ -25,10 +25,6 @@ items: source: id: ListVoicesRequest path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 60 summary: 'The top-level message sent by the client for the `ListVoices` diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.ListVoicesResponse.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.ListVoicesResponse.yml index f704a78c7746..96ed0d6251ee 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.ListVoicesResponse.yml +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.ListVoicesResponse.yml @@ -19,10 +19,6 @@ items: source: id: ListVoicesResponse path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 83 summary: 'The message returned to the client by the `ListVoices` method. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.SsmlVoiceGender.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.SsmlVoiceGender.yml index 20fb94711037..1d9127c47d6d 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.SsmlVoiceGender.yml +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.SsmlVoiceGender.yml @@ -23,10 +23,6 @@ items: source: id: SsmlVoiceGender path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 37 summary: 'Gender of the voice as described in `SSML voice diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.SynthesisInput.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.SynthesisInput.yml index 8ad16edaf9f0..77963f12e2c2 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.SynthesisInput.yml +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.SynthesisInput.yml @@ -26,10 +26,6 @@ items: source: id: SynthesisInput path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 183 summary: 'Contains text input to be synthesized. Either `text` or `ssml` diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechRequest.TimepointType.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechRequest.TimepointType.yml index 22781ee34713..eebf047d639d 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechRequest.TimepointType.yml +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechRequest.TimepointType.yml @@ -23,10 +23,6 @@ items: source: id: TimepointType path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 154 summary: 'The type of timepoint information that is returned in the diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechRequest.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechRequest.yml index 73438340ac3a..cb4e1221b141 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechRequest.yml +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechRequest.yml @@ -30,10 +30,6 @@ items: source: id: SynthesizeSpeechRequest path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 135 summary: 'The top-level message sent by the client for the diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechResponse.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechResponse.yml index 43d141da1ef8..a1cde52d7403 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechResponse.yml +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.SynthesizeSpeechResponse.yml @@ -31,10 +31,6 @@ items: source: id: SynthesizeSpeechResponse path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 385 summary: 'The message returned to the client by the `SynthesizeSpeech` diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.Timepoint.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.Timepoint.yml index 738d0ed8d745..024ee84043e3 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.Timepoint.yml +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.Timepoint.yml @@ -23,10 +23,6 @@ items: source: id: Timepoint path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 421 summary: 'This contains a mapping between a certain point in the input diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.Voice.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.Voice.yml index c78224c9a8ec..076a07fd3f3d 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.Voice.yml +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.Voice.yml @@ -30,10 +30,6 @@ items: source: id: Voice path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 98 summary: 'Description of a voice supported by the TTS service. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.VoiceSelectionParams.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.VoiceSelectionParams.yml index d9490ca0b491..ad2f128f100b 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.VoiceSelectionParams.yml +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.VoiceSelectionParams.yml @@ -45,10 +45,6 @@ items: source: id: VoiceSelectionParams path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/cloud_tts.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 223 summary: 'Description of which voice to use for a synthesis request. diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.yml index 707b6cdc6d3e..cf050947f434 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.yml +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-auto/google.cloud.texttospeech_v1beta1.types.yml @@ -22,10 +22,6 @@ items: source: id: types path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/__init__.py - remote: - branch: add_goldens - path: tests/testdata/gapic-auto/google/cloud/texttospeech_v1beta1/types/__init__.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 0 summary: API documentation for `texttospeech_v1beta1.types` package. syntax: {} diff --git a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.publisher.client.Client.yml b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.publisher.client.Client.yml index e564b88b1af0..8745b0f769d0 100644 --- a/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.publisher.client.Client.yml +++ b/packages/gcp-sphinx-docfx-yaml/tests/testdata/goldens/gapic-combo/google.cloud.pubsub_v1.publisher.client.Client.yml @@ -56,10 +56,6 @@ items: source: id: Client path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 65 summary: 'A publisher client for Google Cloud Pub/Sub. @@ -93,10 +89,6 @@ items: source: id: Client path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 65 summary: 'Instantiates the publisher client. @@ -149,10 +141,6 @@ items: source: id: __exit__ path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 1430 summary: 'Releases underlying transport''s resources. @@ -184,10 +172,6 @@ items: source: id: api path: null - remote: - branch: add_goldens - path: null - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: null summary: "The underlying gapic API client.\n\n.. versionchanged:: 2.10.0\n Instead\ \ of a GAPIC `PublisherClient` client instance, this property is a\n proxy\ @@ -208,10 +192,6 @@ items: source: id: common_billing_account_path path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 236 summary: 'Returns a fully-qualified billing_account string. @@ -232,10 +212,6 @@ items: source: id: common_folder_path path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 251 summary: 'Returns a fully-qualified folder string. @@ -256,10 +232,6 @@ items: source: id: common_location_path path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 296 summary: 'Returns a fully-qualified location string. @@ -280,10 +252,6 @@ items: source: id: common_organization_path path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 266 summary: 'Returns a fully-qualified organization string. @@ -304,10 +272,6 @@ items: source: id: common_project_path path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 281 summary: 'Returns a fully-qualified project string. @@ -328,10 +292,6 @@ items: source: id: create_topic path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 488 summary: "Creates the given topic with the given name. See the [resource\nname rules]\n\ (https://cloud.google.com/pubsub/docs/admin#resource_names).\n\n```python\n# This\ @@ -391,10 +351,6 @@ items: source: id: delete_topic path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 1243 summary: "Deletes the topic with the given name. Returns `NOT_FOUND` if\nthe topic\ \ does not exist. After a topic is deleted, a new topic\nmay be created with the\ @@ -448,10 +404,6 @@ items: source: id: detach_subscription path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 1339 summary: "Detaches a subscription from this topic. All messages retained\nin the\ \ subscription are dropped. Subsequent `Pull` and\n`StreamingPull` requests will\ @@ -503,10 +455,6 @@ items: source: id: ensure_cleanup_and_commit_timer_runs path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 421 summary: 'Ensure a cleanup/commit timer thread is running. @@ -530,10 +478,6 @@ items: source: id: from_service_account_file path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 161 summary: 'Creates an instance of this client using the provided credentials @@ -557,10 +501,6 @@ items: source: id: from_service_account_info path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 136 summary: "Creates an instance of this client using the provided credentials\n \ \ info.\n" @@ -585,10 +525,6 @@ items: source: id: from_service_account_json path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 161 summary: 'Creates an instance of this client using the provided credentials @@ -612,10 +548,6 @@ items: source: id: get_iam_policy path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 1561 summary: 'Gets the IAM access control policy for a function. @@ -683,10 +615,6 @@ items: source: id: get_mtls_endpoint_and_cert_source path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 313 summary: 'Return the API endpoint and client cert source for mutual TLS. @@ -752,10 +680,6 @@ items: source: id: get_topic path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 791 summary: "Gets the configuration of a topic.\n\n```python\n# This snippet has been\ \ automatically generated and should be regarded as a\n# code template only.\n\ @@ -809,10 +733,6 @@ items: source: id: list_topic_snapshots path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 1122 summary: "Lists the names of the snapshots on this topic. Snapshots are\nused in\n\ `Seek `__\noperations, which\ @@ -874,10 +794,6 @@ items: source: id: list_topic_subscriptions path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 1005 summary: "Lists the names of the attached subscriptions on this\ntopic.\n\n```python\n\ # This snippet has been automatically generated and should be regarded as a\n\ @@ -935,10 +851,6 @@ items: source: id: list_topics path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 891 summary: "Lists matching topics.\n\n```python\n# This snippet has been automatically\ \ generated and should be regarded as a\n# code template only.\n# It will require\ @@ -995,10 +907,6 @@ items: source: id: parse_common_billing_account_path path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 245 summary: 'Parse a billing_account path into its component segments. @@ -1019,10 +927,6 @@ items: source: id: parse_common_folder_path path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 260 summary: 'Parse a folder path into its component segments. @@ -1043,10 +947,6 @@ items: source: id: parse_common_location_path path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 307 summary: 'Parse a location path into its component segments. @@ -1067,10 +967,6 @@ items: source: id: parse_common_organization_path path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 275 summary: 'Parse a organization path into its component segments. @@ -1091,10 +987,6 @@ items: source: id: parse_common_project_path path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 290 summary: 'Parse a project path into its component segments. @@ -1115,10 +1007,6 @@ items: source: id: parse_schema_path path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 194 summary: 'Parses a schema path into its component segments. @@ -1139,10 +1027,6 @@ items: source: id: parse_subscription_path path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 211 summary: 'Parses a subscription path into its component segments. @@ -1163,10 +1047,6 @@ items: source: id: parse_topic_path path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-combo/google/pubsub_v1/services/publisher/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 230 summary: 'Parses a topic path into its component segments. @@ -1187,10 +1067,6 @@ items: source: id: publish path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/client.py - remote: - branch: add_goldens - path: tests/testdata/gapic-combo/google/cloud/pubsub_v1/publisher/client.py - repo: https://github.com/googleapis/sphinx-docfx-yaml startLine: 274 summary: "Publish a single message.\n\n