././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1732045156.0020812 os-api-ref-3.0.1/0000775000175000017500000000000000000000000013500 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045126.0 os-api-ref-3.0.1/.coveragerc0000664000175000017500000000014500000000000015621 0ustar00zuulzuul00000000000000[run] branch = True source = os_api_ref omit = os_api_ref/openstack/* [report] ignore_errors = True ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045126.0 os-api-ref-3.0.1/.mailmap0000664000175000017500000000013100000000000015114 0ustar00zuulzuul00000000000000# Format is: # # ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045126.0 os-api-ref-3.0.1/.pre-commit-config.yaml0000664000175000017500000000252300000000000017763 0ustar00zuulzuul00000000000000# We from the Oslo project decided to pin repos based on the # commit hash instead of the version tag to prevend arbitrary # code from running in developer's machines. To update to a # newer version, run `pre-commit autoupdate` and then replace # the newer versions with their commit hash. default_language_version: python: python3 repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: 9136088a246768144165fcc3ecc3d31bb686920a # v3.3.0 hooks: - id: trailing-whitespace # Replaces or checks mixed line ending - id: mixed-line-ending args: ['--fix', 'lf'] exclude: '.*\.(svg)$' # Forbid files which have a UTF-8 byte-order marker - id: check-byte-order-marker # Checks that non-binary executables have a proper shebang - id: check-executables-have-shebangs # Check for files that contain merge conflict strings. - id: check-merge-conflict # Check for debugger imports and py37+ breakpoint() # calls in python source - id: debug-statements - id: check-yaml files: .*\.(yaml|yml)$ - repo: local hooks: - id: flake8 name: flake8 additional_dependencies: - hacking>=3.0.1,<3.1.0 language: python entry: flake8 files: '^.*\.py$' exclude: '^(doc|releasenotes|tools)/.*$' ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045126.0 os-api-ref-3.0.1/.stestr.conf0000664000175000017500000000010200000000000015742 0ustar00zuulzuul00000000000000[DEFAULT] test_path=${OS_TEST_PATH:-./os_api_ref/tests} top_dir=./././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045126.0 os-api-ref-3.0.1/.zuul.yaml0000664000175000017500000000101600000000000015437 0ustar00zuulzuul00000000000000- job: name: os-api-ref-nova-src parent: build-openstack-api-ref description: | Run the api-ref job against nova with proposed os-api-ref change. vars: zuul_work_dir: src/opendev.org/openstack/nova required-projects: - openstack/nova - openstack/os-api-ref - project: templates: - openstack-python3-jobs - check-requirements - publish-openstack-docs-pti check: jobs: - os-api-ref-nova-src gate: jobs: - os-api-ref-nova-src ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045155.0 os-api-ref-3.0.1/AUTHORS0000664000175000017500000000341300000000000014551 0ustar00zuulzuul00000000000000Akihiro Motoki Alexander Fadeev Andreas Jaeger Anne Gentle Cao Xuan Hoang Corey Bryant Daniel Bengtsson Daniel Garcia Moreno Daniel Gonzalez Dirk Mueller Dmitry Shachnev Doug Hellmann Flavio Percoco Gergely Csatari Graham Hayes Graham Hayes Hervé Beraud Karen Bradshaw Luigi Toscano Masayuki Igawa Monty Taylor Nam Nguyen Hoai Ondřej Nový Rafael Weingärtner Sean Dague Sean McGinnis Stephen Finucane Takashi Kajinami Telles Nobrega Thomas Bechtold Tony Breeds Tony Xu Tristan Cacqueray Yuval Brik ZhijunWei gengchc2 ghanshyam jacky06 maaoyu melissaml niuke ricolin shangxiaobj shashi.kant tengqm tushargite96 yanghuichan yangyawei zhoulinhui zhulingjie ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045126.0 os-api-ref-3.0.1/CONTRIBUTING.rst0000664000175000017500000000123100000000000016136 0ustar00zuulzuul00000000000000If you would like to contribute to the development of OpenStack, you must follow the steps in this page: https://docs.openstack.org/infra/manual/developers.html If you already have a good understanding of how the system works and your OpenStack accounts are set up, you can skip to the development workflow section of this documentation to learn how changes to OpenStack should be submitted for review via the Gerrit tool: https://docs.openstack.org/infra/manual/developers.html#development-workflow Pull requests submitted through GitHub will be ignored. Bugs should be filed on Launchpad, not GitHub: https://bugs.launchpad.net/openstack-doc-tools ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045155.0 os-api-ref-3.0.1/ChangeLog0000664000175000017500000001252600000000000015260 0ustar00zuulzuul00000000000000CHANGES ======= 3.0.1 ----- * Mark sphinx extensions thread safe * Series of job fixes 3.0.0 ----- * remove unicode prefix from code * Fix the 'No such file or directory' error * Remove deprecated sphinx-testing dependency * Drop python3.6/3.7 support in testing runtime * Update CI to use unversioned jobs template * Add Python3 yoga unit tests 2.3.0 ----- * Fix exception logging * tox: Don't use distutils entrypoint for coverage * Remove six * Drop support for Sphinx < 4.x 2.2.0 ----- * setup.cfg: Replace dashes with underscores * Switch testing to Xena testing runtime * Move flake8 as a pre-commit local target * Replace 'add\_stylesheet', 'add\_javascript' * Use TOX\_CONSTRAINTS\_FILE * Use py3 as the default runtime for tox * Bump py37 to py38 in tox.ini * bump py37 to py38 in tox.ini * Fix hacking min version to 3.0.1 * Stop install unnecessary packages when run tox -edocs * Remove install unnecessary packages * Adding pre-commit 2.1.0 ----- * Switch to newer openstackdocstheme version * Remove .testr.conf * Remove unused translation content 2.0.1 ----- * Update hacking for Python3 * Update sphinx-testing requirements to >=1.0.1 2.0.0 ----- * [ussuri][goal] Drop python 2.7 support and testing * Use Ussuri jobs 1.6.2 ----- * Add Python 3 Train unit tests * Add support for Sphinx v2.1 * Update Testing for Train * Replace git.openstack.org URLs with opendev.org URLs * Add support for Sphinx 2.0 * OpenDev Migration Patch * trivial: Remove unused attribute 1.6.1 ----- * Generate stable targets rather than random * Fix microversion test: handle different HTML renderings * Update hacking version * Remove support for py34 1.6.0 ----- * Fixing duplicate label issue * readthedocs.io support * Update the remained discuss email * Change openstack-dev to openstack-discuss * Update sphinx extension logging * tests: Support Sphinx 1.8+ * docs: Remove broken link * switch documentation job to new PTI * Fix sphinx-build invocation * import zuul job settings from project-config * Use 'sphinx.util.logging' * General overhaul of testing setup * Raise warning if top-level value is not a dict * Updated from global requirements * Updated from global requirements * Updated from global requirements * Use openstackdocstheme * Remove name from project stanza 1.5.0 ----- * Updated from global requirements * Fix wrong links * Update and replace http with https for doc links * Add 'uuid' type * Fix Zuul jobs * Updated from global requirements * Fix UnicodeDecodeError * Updated from global requirements * doc: Remove deprecated call to sphinx.util.compat * Remove unconstraint package installation * Clear description for max\_version field 1.4.0 ----- * Fix for sphinx 1.6.2 * Updated from global requirements * Updated from global requirements * Replaces yaml.load() with yaml.safe\_load() * Update tests for more recent sphinx * Enable warnings as errors * Updated from global requirements * [Fix gate]Update test requirement * Update hacking 1.3.0 ----- * Updated from global requirements * Delete support py33 * add file on releasing the software 1.2.0 ----- * Fix anchor link setting url bar * detail/close button, bug #1618955 * Removes unnecessary utf-8 encoding * Show team and repo badges on README * Updated from global requirements * Removes unnecessary utf-8 encoding * Add compatibility with docutils 0.13 * Add Constraints support * Import httplib from six to support Python 3 * Updated from global requirements * Add test for missing path params * microversion selector - dropdown 1.1.0 ----- * Sync with global-requirements * Update homepage with developer documentation page * Adds an example http-status.yaml file and updates doc * Use beautifulsoup4 instead of bs4 in test-requirements.txt * remove padding-top for endpoint-container * Adds more info to the README to instruct authors * Expand width of API Site 1.0.0 ----- * Update docs for openstackdocstheme * openstackdocstheme integration * Add color for COPY label * Change Layout of Path + Sub Title 0.4.0 ----- * Added docutils to requirements * Moved sphinx from test requirements to requirements * Tests for invalid parameter files * HTTP Response Code Table 0.3.0 ----- * add experimental microversion selector * track the expanded elements in the url * remove unused javascript code * Add warning for invalid parameters * Added more details to usage.rst * Highlight parameters in path * fix microversion parsing in parameters.yaml * add min/max version to rest method * simplify conf.py in tests * add a list of tests we should have * make testing be non parallel * tests for parameter out of order behavior * More unit tests * add first basic unit test * Trivial: fix typos in README.rst * Colour Code HTTP Methods * Validate in value before sorting validation * fix docs to link the new bug tracker 0.1.1 ----- * Make the version returned by the extension be the pbr version * Update css for version-added * Add parsing and output of max\_version * Remove errant ";" from the "expand\_all" detection 0.1.0 ----- * make unsorted parameters lists warnings * add section on warnings * document parameters.yaml and rest\_expand\_all * partial documentation on rest\_parameters * update usage for rest\_method * further enhance documentation * Update README * trim test-requirements.txt * Import the sphinx extension from nova * remove constraints, we're not going to use that * Initial Cookiecutter Commit * Added .gitreview ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045126.0 os-api-ref-3.0.1/HACKING.rst0000664000175000017500000000024000000000000015272 0ustar00zuulzuul00000000000000os-api-ref Style Commandments =============================================== Read the OpenStack Style Commandments https://docs.openstack.org/hacking/latest/ ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045126.0 os-api-ref-3.0.1/LICENSE0000664000175000017500000002363700000000000014520 0ustar00zuulzuul00000000000000 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. ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1732045156.0060813 os-api-ref-3.0.1/PKG-INFO0000664000175000017500000001335600000000000014605 0ustar00zuulzuul00000000000000Metadata-Version: 1.2 Name: os-api-ref Version: 3.0.1 Summary: Sphinx Extensions to support API reference sites in OpenStack Home-page: https://docs.openstack.org/os-api-ref/latest/ Author: OpenStack Author-email: openstack-discuss@lists.openstack.org License: UNKNOWN Description: ======================== Team and repository tags ======================== .. image:: https://governance.openstack.org/tc/badges/os-api-ref.svg :target: https://governance.openstack.org/tc/reference/tags/index.html .. Change things from this point on os-api-ref ========== Sphinx Extensions to support API reference sites in OpenStack This project is a collection of sphinx stanzas that assist in building an API Reference site for an OpenStack project in RST. RST is great for unstructured English, but displaying semi structured (and repetitive) data in tables is not its strength. This provides tooling to insert semi-structured data describing request and response parameters and status or error messages, and turn those into nice tables. The project also includes a set of styling (and javascript) that is expected to layer on top of a Sphinx theme base. This addition provides a nice set of collapsing sections for REST methods and javascript controls to expand / collapse all sections. Features -------- * Sphinx stanza ``rest_method`` describing the method and resource for a REST API call. Lets authors write simply and also gives readers a clean way to scan all methods then click a button to get more information about a method. * Sphinx stanza ``rest_parameters`` used to insert semi-structured data into the RST files describing the parameters users can send with the request. The stanza points to a structured YAML file, ``parameters.yaml``. * Sphinx stanza ``rest_status_code`` used to insert pointers to error or status codes returned by the service. Points to a structured YAML file, ``http_codes.yaml``. TODO ---- A list, in no particular order, of things we should do in this project. If you would like to contribute to any of these please show up in ``#openstack-dev`` on IRC and ask for ``sdague`` or ``mugsie`` to discuss or send an email to the openstack-discuss@lists.openstack.org list with [api] in the subject line. * Enhance documentation with more examples and best practices * Testing for the code * ``max_microversion`` parameter support - so that we automatically tag parameters that have been removed * Make a microversion selector, so that you can get a version of the api-ref that hides all microversion elements beyond your selected version (this one is going to be a bit of complex javascript), in progress. Potential ideas ~~~~~~~~~~~~~~~ These aren't even quite todos, but just ideas about things that might be useful. * ``.. literalinclude`` is good for API samples files to be included, but should we have more markup that includes the full ``REST /URL`` as well. Sphinx stanzas -------------- **rest_method**: Enter the REST method, such as GET, PUT, POST, DELETE, followed by the resource (not including an endpoint) for the call. For example:: .. rest_method:: PUT /v2/images/{image_id}/file **rest_parameters**: Enter a reference to a ``parameters.yaml`` file and indicate which parameter you want to document. For example:: .. rest_parameters:: images-parameters.yaml - Content-type: Content-Type-data - image_id: image_id-in-path Where the ``images-parameters.yaml`` file contains pointers named ``Content-type`` and ``image_id`` and descriptions for each. **rest_status_code**: Enter a reference to a ``http-status.yaml`` file and indicate which errors or status codes you want to document. You can also add a pointer to more precise descriptions for each code. For example:: .. rest_status_code:: success http-codes.yaml - 204 .. rest_status_code:: error http-codes.yaml - 400: informal - 401 - 403 - 404 - 409 - 410: image-data-410 - 413: image-data-413 - 415: image-data-415 - 500: informal - 503: image-data-503 * Free software: Apache license * Documentation: https://docs.openstack.org/os-api-ref/latest/ * Source: https://opendev.org/openstack/os-api-ref Platform: UNKNOWN Classifier: Environment :: OpenStack Classifier: Intended Audience :: Information Technology Classifier: Intended Audience :: System Administrators Classifier: License :: OSI Approved :: Apache Software License Classifier: Operating System :: POSIX :: Linux Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3.12 Classifier: Programming Language :: Python :: 3 :: Only Classifier: Programming Language :: Python :: Implementation :: CPython Requires-Python: >=3.9 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045126.0 os-api-ref-3.0.1/README.rst0000664000175000017500000000757100000000000015201 0ustar00zuulzuul00000000000000======================== Team and repository tags ======================== .. image:: https://governance.openstack.org/tc/badges/os-api-ref.svg :target: https://governance.openstack.org/tc/reference/tags/index.html .. Change things from this point on os-api-ref ========== Sphinx Extensions to support API reference sites in OpenStack This project is a collection of sphinx stanzas that assist in building an API Reference site for an OpenStack project in RST. RST is great for unstructured English, but displaying semi structured (and repetitive) data in tables is not its strength. This provides tooling to insert semi-structured data describing request and response parameters and status or error messages, and turn those into nice tables. The project also includes a set of styling (and javascript) that is expected to layer on top of a Sphinx theme base. This addition provides a nice set of collapsing sections for REST methods and javascript controls to expand / collapse all sections. Features -------- * Sphinx stanza ``rest_method`` describing the method and resource for a REST API call. Lets authors write simply and also gives readers a clean way to scan all methods then click a button to get more information about a method. * Sphinx stanza ``rest_parameters`` used to insert semi-structured data into the RST files describing the parameters users can send with the request. The stanza points to a structured YAML file, ``parameters.yaml``. * Sphinx stanza ``rest_status_code`` used to insert pointers to error or status codes returned by the service. Points to a structured YAML file, ``http_codes.yaml``. TODO ---- A list, in no particular order, of things we should do in this project. If you would like to contribute to any of these please show up in ``#openstack-dev`` on IRC and ask for ``sdague`` or ``mugsie`` to discuss or send an email to the openstack-discuss@lists.openstack.org list with [api] in the subject line. * Enhance documentation with more examples and best practices * Testing for the code * ``max_microversion`` parameter support - so that we automatically tag parameters that have been removed * Make a microversion selector, so that you can get a version of the api-ref that hides all microversion elements beyond your selected version (this one is going to be a bit of complex javascript), in progress. Potential ideas ~~~~~~~~~~~~~~~ These aren't even quite todos, but just ideas about things that might be useful. * ``.. literalinclude`` is good for API samples files to be included, but should we have more markup that includes the full ``REST /URL`` as well. Sphinx stanzas -------------- **rest_method**: Enter the REST method, such as GET, PUT, POST, DELETE, followed by the resource (not including an endpoint) for the call. For example:: .. rest_method:: PUT /v2/images/{image_id}/file **rest_parameters**: Enter a reference to a ``parameters.yaml`` file and indicate which parameter you want to document. For example:: .. rest_parameters:: images-parameters.yaml - Content-type: Content-Type-data - image_id: image_id-in-path Where the ``images-parameters.yaml`` file contains pointers named ``Content-type`` and ``image_id`` and descriptions for each. **rest_status_code**: Enter a reference to a ``http-status.yaml`` file and indicate which errors or status codes you want to document. You can also add a pointer to more precise descriptions for each code. For example:: .. rest_status_code:: success http-codes.yaml - 204 .. rest_status_code:: error http-codes.yaml - 400: informal - 401 - 403 - 404 - 409 - 410: image-data-410 - 413: image-data-413 - 415: image-data-415 - 500: informal - 503: image-data-503 * Free software: Apache license * Documentation: https://docs.openstack.org/os-api-ref/latest/ * Source: https://opendev.org/openstack/os-api-ref ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045126.0 os-api-ref-3.0.1/RELEASING.rst0000664000175000017500000000227000000000000015544 0ustar00zuulzuul00000000000000=========== Releasing =========== This documents the how and when to release ``os-api-ref``. When to release =============== Any time there are fixes or additions ready to go, they should be released. Releases are cheap. If it's been more than a month and there are changes in master, consider releasing them. If the changes are entirely on the CSS / JS cosmetic side, things are usually pretty safe to release as long as they have been spot checked against a couple of projects. (The gate does the nova tree automatically). If new warnings are added ------------------------- If **new** warnings have been added since the last release, care should be taken to: * Alert the mailing list 2 days before the release about the new warning coming in (that should give them time to go non enforcing or fix the issue). * Ensure that you bump at least the Y in the version number (X.Y.Z). New warnings are not a Z level release. How to release ============== Check out ``openstack/releases`` Edit ``deliverables/_independent/os-api-ref.yaml`` Add a line with the version number desired, the git has of the commit that should be that release. If you have questions ask in ``#openstack-release`` ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045126.0 os-api-ref-3.0.1/TESTS.rst0000664000175000017500000000052200000000000015133 0ustar00zuulzuul00000000000000============================== Tests that should be written ============================== Negative * test warning when groups are out of order * test when parameter keys are missing * test when description RST is invalid * test when parameter file is missing Microversion * test attributes are set when microversions are annotated. ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1732045155.9940813 os-api-ref-3.0.1/doc/0000775000175000017500000000000000000000000014245 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045126.0 os-api-ref-3.0.1/doc/requirements.txt0000664000175000017500000000041500000000000017531 0ustar00zuulzuul00000000000000# The order of packages is significant, because pip processes them in the order # of appearance. Changing the order has an impact on the overall integration # process, which may cause wedges in the gate later. sphinx>=4.0.0 # BSD openstackdocstheme>=2.2.1 # Apache-2.0 ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1732045155.9940813 os-api-ref-3.0.1/doc/source/0000775000175000017500000000000000000000000015545 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045126.0 os-api-ref-3.0.1/doc/source/conf.py0000664000175000017500000000474300000000000017054 0ustar00zuulzuul00000000000000# Copyright (C) 2020 Red Hat, 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. import os import sys sys.path.insert(0, os.path.abspath('../..')) # -- General configuration ---------------------------------------------------- # 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', 'openstackdocstheme' ] # openstackdocstheme options openstackdocs_repo_name = 'openstack/os-api-ref' openstackdocs_auto_name = False openstackdocs_bug_project = 'openstack-doc-tools' openstackdocs_bug_tag = 'os-api-ref' # autodoc generation is a bit aggressive and a nuisance when doing heavy # text edit cycles. # execute "export SPHINX_DEBUG=1" in your terminal to disable # The suffix of source filenames. source_suffix = '.rst' # The master toctree document. master_doc = 'index' # General information about the project. project = 'os-api-ref' copyright = '2018, The contributors' # 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 # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'native' # -- Options for HTML output -------------------------------------------------- # The theme to use for HTML and HTML Help pages. Major themes that come with # Sphinx are currently 'default' and 'sphinxdoc'. # html_theme_path = ["."] # html_theme = '_theme' # html_static_path = ['static'] html_theme = 'openstackdocs' # Output file base name for HTML help builder. htmlhelp_basename = '%sdoc' % project # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass # [howto/manual]). latex_documents = [ ('index', '%s.tex' % project, '%s Documentation' % project, 'OpenStack Foundation', 'manual'), ] ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045126.0 os-api-ref-3.0.1/doc/source/contributing.rst0000664000175000017500000000007700000000000021012 0ustar00zuulzuul00000000000000 Contributing ============ .. include:: ../../CONTRIBUTING.rst ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045126.0 os-api-ref-3.0.1/doc/source/http-status.yaml0000664000175000017500000000371700000000000020741 0ustar00zuulzuul00000000000000 200: default: | Request was successful. image-data-200: | The service lists the image data in the response body. 201: default: | Request has been fulfilled and new resource created. 202: default: | Request is accepted, but processing may take some time. 203: default: | Returned information is not full set, but a subset. 204: default: | Request fulfilled but service does not return anything. 300: default: | The resource corresponds to more than one representation. 400: default: | Some content in the request was invalid. 401: default: | User must authenticate before making a request. 403: default: | Policy does not allow current user to do this operation. 404: default: | The requested resource could not be found. 405: default: | Method is not valid for this endpoint and resource. 409: default: | This resource has an action in progress that would conflict with this request. 413: default: | This operation cannot be completed. image-data-413: | The payload cannot be accepted. Possible causes include: * The backend storage is full. * This request added to your existing image data exceeds your total storage quota for images. * The image payload submitted with this request exceeds the maximum allowable image size. 415: default: | The entity of the request is in a format not supported by the requested resource for the method. 500: default: | Something went wrong with the service which prevents it from fulfilling the request. 501: default: | The service does not have the functionality required to fulfill this request. 503: default: | The service cannot handle the request right now. ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045126.0 os-api-ref-3.0.1/doc/source/index.rst0000664000175000017500000000044000000000000017404 0ustar00zuulzuul00000000000000============================================== Welcome to os-api-ref developer documentation! ============================================== .. toctree:: :maxdepth: 1 installation usage contributing Indices and tables ================== * :ref:`genindex` * :ref:`search` ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045126.0 os-api-ref-3.0.1/doc/source/installation.rst0000664000175000017500000000027200000000000021001 0ustar00zuulzuul00000000000000Installation ============ At the command line:: $ pip install os-api-ref Or, if you have virtualenvwrapper installed:: $ mkvirtualenv os-api-ref $ pip install os-api-ref ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045126.0 os-api-ref-3.0.1/doc/source/usage.rst0000664000175000017500000002434400000000000017412 0ustar00zuulzuul00000000000000Usage ===== ``os-api-ref`` is designed to be used inside of a sphinx tree that is devoted solely to the documentation of the API. Modify your ``source/conf.py`` file to include ``os_api_ref`` in the list of sphinx extensions. This extension assumes you are also using ``openstackdocstheme`` for some of the styling, and may not fully work if you are not. .. code-block:: python # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = [ 'os_api_ref', ] Stanzas ======= rest_method ----------- The ``rest_method`` stanza is a way to declare that a section is about a particular REST method. It takes the form of: .. code-block:: rst .. rest_method:: ``METHODNAME`` should be one of the commonly used REST methods or HTTP verbs. This stanza should be the first element in a ``section`` that has some descriptive title about the method. An example from the Nova documentation is: .. code-block:: rst List Servers ============ .. rest_method:: GET /v2.1/{tenant_id}/servers Lists IDs, names, and links for all servers. Servers contain a status attribute that indicates the current server state. You can filter on the server status when you complete a list servers request. The server status is returned in the response body. The possible server status values are: ... This is going to do a slightly unexpected transform where the ``rest_method`` is pivoted up and into the section title to produce an HTML line of the form: . The entire contents of the ``List Servers`` section will then be hidden by default, with a button to open it on demand. rest_parameters --------------- The ``rest_parameters`` stanza is a solution to the problem of tables in ``rst``. A REST API that uses JSON has a large number of structured parameters that include type, location (i.e. is this in the query, the header, the path, the body), whether or not this parameter is required, as well as the desire to provide a long description about each parameter. And, assuming some consistent modeling, that parameter will show up in multiple calls. A ``server_id`` used in the path is always going to have the same meaning. It is natural to want to display this data in a tabular way to show all these dimensions. However, tables in ``rst`` are quite cumbersome, and repeating the same data over and over again is error prone. The ``rest_parameters`` stanza solves this by having the inline markup be a yaml list of ``name: value`` pairs. ``name`` is the name of the parameter. ``value`` is the key to lookup the rest of the details for this parameter in a parameters file. In each method, there should be one ``rest_parameters`` stanza for the request, and another ``rest_parameters`` stanza for the response. .. code-block:: rst .. rest_parameters:: parameters.yaml - tenant_id: tenant_id - changes-since: changes-since - image: image_query - flavor: flavor_query - name: server_name_query - status: server_status_query - host: host_query - limit: limit - marker: marker And corresponding entries in ``parameters.yaml``: .. code-block:: yaml tenant_id: description: | The UUID of the tenant in a multi-tenancy cloud. in: path required: true type: string ... changes-since: description: | Filters the response by a date and time when the image last changed status. Use this query parameter to check for changes since a previous request rather than re-downloading and re-parsing the full status at each polling interval. If data has changed, the call returns only the items changed since the ``changes-since`` time. If data has not changed since the ``changes-since`` time, the call returns an empty list.\nTo enable you to keep track of changes, this filter also displays images that were deleted if the ``changes-since`` value specifies a date in the last 30 days. Items deleted more than 30 days ago might be returned, but it is not guaranteed. The date and time stamp format is `ISO 8601 `_: :: CCYY-MM-DDThh:mm:ss±hh:mm The ``±hh:mm`` value, if included, returns the time zone as an offset from UTC. For example, ``2015-08-27T09:49:58-05:00``. If you omit the time zone, the UTC time zone is assumed. in: query required: false type: string server_status_query: description: | Filters the response by a server status, as a string. For example, ``ACTIVE``. in: query required: false type: string Every ``rest_parameters`` stanza specifies the lookup file it will use. This gives you the freedom to decide how you would like to split up your parameters, ranging from a single global file, to a dedicated file for every stanza, or anywhere in between. parameters file format ---------------------- The parameters file is inspired by the OpenAPI (aka: Swagger) specification. The OpenAPI specification provides a property object which categorizes the parameters by type and describes how the parameter is used. The following fields exist for every entry: in where this parameter exists. One of ``header``, ``path``, ``query``, ``body``. description a free form description of the parameter. This can be multiline (if using the | or > tags in yaml), and supports ``rst`` format syntax. required whether this parameter is required or not. If ``required: false`` the parameter name will be rendered with an (Optional) keyword next to it type the javascript/json type of the field. one of ``boolean``, ``int``, ``float``, ``string``, ``uuid``, ``array``, ``object``. min_version the microversion that this parameter was introduced at. Will render a *new in $version* stanza in the html output. max_version the last version that includes this parameter. Will render a *Available until $version* stanza in the html output. rest_status_code ---------------- The ``rest_status_code`` stanza is how you can show what HTTP status codes your API uses and what they indicate. .. code-block:: rst .. rest_status_code:: This stanza should be the first element after the narrative section of the method description. An example from the Designate documentation is: .. code-block:: rst :emphasize-lines: 11-25 Create Zone =========== .. rest_method:: POST /v2/zones Create a zone Response codes -------------- .. rest_status_code:: success status.yaml - 200 - 100 - 201 .. rest_status_code:: error status.yaml - 405 - 403 - 401 - 400 - 500 - 409: duplicate_zone And corresponding entries in ``http-status.yaml``: .. code-block:: yaml 100: default: | An unusual code for an API 200: default: | Request was successful. 201: default: > Request has been fulfilled and new resource created. The ``Location`` header has the URL to the new item. 400: default: | Some content in the request was invalid zone_data_error: | Some of the data for the zone in the request is unavailable to the service. 401: default: | User must authenticate before making a request. 403: default: | Policy does not allow current user to do this operation. 405: default: | Method is not valid for this endpoint and resource. 409: default: | This resource has an action in progress that would conflict with this request. duplicate_zone: | There is already a zone with this name. 500: default: | Something went wrong with the service which prevents it from fulfilling the request. This RST example creates two HTML tables of response codes, one for success and one for errors. status file format ------------------ This is a simple yaml file, with a single object of status codes and the reasons that each would be used. Each status code **must** have a default entry in the status yaml file. The default entry is used in the ``rest_status_code`` stanza when a code is listed with no value or lookup key. There may be situations where the reason for a code may be different across endpoints, or a different message may be appropriate. In this case, adding a entry at the same level as the ``default`` and referencing that in the stanza like so: .. code-block:: yaml - 409: duplicate_zone This will override the default message with the newly defined one. You can get a copy of a starter status file from the os-api-ref repository, by downloading :download:`http-status.yaml `. rest_expand_all --------------- The ``rest_expand_all`` stanza is used to place a control in the document that will be a global Show / Hide for all sections. There are times when this is extremely nice to have. Including Sample Files ====================== To refer to a sample file in a ``rst`` file, use the ``rst`` directive, ``literalinclude``. Typically, the content sent or received is of type JSON, so the language role is set to javascript. The example immediately follows the parameter listing in the ``rst`` file. An example of an included Nova response sample file: .. code-block:: rst .. literalinclude:: ../../doc/api_samples/os-evacuate/server-evacuate-resp.json :language: javascript Runtime Warnings ================ The extension tries to help when it can by pointing out that something isn't matching up correctly. The following warnings are generated when issues are found: * parameters file is not found * parameters file is not valid yaml, i.e. missing colon after the name * a lookup value in the ``rst`` file is not found in the parameters file * the parameters file is not sorted as outlined in the rules below The sorting rules for parameters file is that first elements should be sorted by ``in``, going from earliest to latest processed. #. header #. path #. query #. body After that, the parameters should be sorted by name, lower case alpha numerically. The sort enforcement is because in large parameters files it helps prevent unintended duplicates. ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1732045155.9980812 os-api-ref-3.0.1/os_api_ref/0000775000175000017500000000000000000000000015606 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045126.0 os-api-ref-3.0.1/os_api_ref/__init__.py0000664000175000017500000006116100000000000017724 0ustar00zuulzuul00000000000000# 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 hashlib import os import re from docutils import nodes from docutils.parsers import rst from docutils.parsers.rst.directives.tables import Table from docutils.statemachine import ViewList import pbr.version from sphinx.util import logging from sphinx.util.osutil import copyfile import yaml from os_api_ref.http_codes import http_code from os_api_ref.http_codes import http_code_html from os_api_ref.http_codes import HTTPResponseCodeDirective __version__ = pbr.version.VersionInfo( 'os_api_ref').version_string() LOG = logging.getLogger(__name__) """This provides a sphinx extension able to create the HTML needed for the api-ref website. It contains 2 new stanzas. .. rest_method:: GET /foo/bar Which is designed to be used as the first stanza in a new section to state that section is about that REST method. During processing the rest stanza will be reparented to be before the section in question, and used as a show/hide selector for it's details. .. rest_parameters:: file.yaml - name1: name_in_file1 - name2: name_in_file2 - name3: name_in_file3 Which is designed to build structured tables for either response or request parameters. The stanza takes a value which is a file to lookup details about the parameters in question. The contents of the stanza are a yaml list of key / value pairs. The key is the name of the parameter to be shown in the table. The value is the key in the file.yaml where all other metadata about the parameter will be extracted. This allows for reusing parameter definitions widely in API definitions, but still providing for control in both naming and ordering of parameters at every declaration. """ def ordered_load( stream, Loader=yaml.SafeLoader, object_pairs_hook=OrderedDict): """Load yaml as an ordered dict This allows us to inspect the order of the file on disk to make sure it was correct by our rules. """ class OrderedLoader(Loader): pass def construct_mapping(loader, node): loader.flatten_mapping(node) return object_pairs_hook(loader.construct_pairs(node)) OrderedLoader.add_constructor( yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG, construct_mapping) # for parameters.yaml we treat numbers (especially version # numbers) as strings. So that microversion specification of 2.20 # and 2.2 don't get confused. OrderedLoader.add_constructor( u'tag:yaml.org,2002:float', yaml.constructor.SafeConstructor.construct_yaml_str) return yaml.load(stream, OrderedLoader) class rest_method(nodes.Part, nodes.Element): """Node for rest_method stanza Because we need to insert very specific HTML at the final stage of processing, the rest_method stanza needs a custom node type. This lets us accumulate the relevant data into this node, during parsing, but not turn it into known sphinx types (lists, tables, sections). Then, during the final build phase we transform directly to the html that we want. NOTE: this means we error trying to build latex or man pages for these stanza types right now. This is all fixable if we add an output formatter for this node type, but it's not yet a priority. Contributions welcomed. """ pass class rest_expand_all(nodes.Part, nodes.Element): """A node placeholder for the expand all button. This is a node that we can insert into the doctree which on final render can be converted to the custom HTML we need for the expand all button. It is automatically inserted at the top of the page for API ref documents. """ pass class RestExpandAllDirective(rst.Directive): # This tells sphinx that the directive will need to generate # content during the final build phase. has_content = True def run(self): app = self.state.document.settings.env.app node = rest_expand_all() max_ver = app.config.os_api_ref_max_microversion min_ver = app.config.os_api_ref_min_microversion releases = app.config.os_api_ref_release_microversions node['major'] = None try: if max_ver.split('.')[0] == min_ver.split('.')[0]: node['max_ver'] = int(max_ver.split('.')[1]) node['min_ver'] = int(min_ver.split('.')[1]) node['major'] = int(max_ver.split('.')[0]) node['releases'] = releases except ValueError: # TODO(sdague): warn that we're ignoring this all pass except IndexError: pass return [node] class RestMethodDirective(rst.Directive): # this enables content in the directive has_content = True @staticmethod def find_param(content, name): for line in content: if ("%s: " % name) in line: _, value = line.split(': ') return value.rstrip().lstrip() return None def run(self): lineno = self.state_machine.abs_line_number() target = nodes.target() section = nodes.section(classes=["detail-control"]) node = rest_method() # TODO(sdague): this is a super simplistic parser, should be # more robust. method, sep, url = self.content[0].partition(' ') node['min_version'] = self.find_param(self.content, 'min_version') node['max_version'] = self.find_param(self.content, 'max_version') node['method'] = method node['url'] = url # Extract the path parameters from the url env = self.state.document.settings.env env.path_params = [] env.path_params = re.findall("{[a-zA-Z][a-zA-Z_0-9]*}", url) node['target'] = self.state.parent.attributes['ids'][0] node['css_classes'] = "" if node['min_version']: node['css_classes'] += "rp_min_ver_%s " % ( str(node['min_version']).replace('.', '_')) if node['max_version']: node['css_classes'] += "rp_max_ver_%s " % ( str(node['max_version']).replace('.', '_')) # We need to build a temporary target that we can replace # later in the processing to get the TOC to resolve correctly. # SHA-1 is used even if collisions are possible, because # they are still unlikely to occurr and it is way shorter # than stronger SHAs. node_hash = hashlib.sha1(str(node).encode('utf-8')).hexdigest() temp_target = "%s-%s-selector" % (node['target'], node_hash) target = nodes.target(ids=[temp_target]) self.state.add_target(temp_target, '', target, lineno) section += node return [target, section] # cache for file -> yaml so we only do the load and check of a yaml # file once during a sphinx processing run. YAML_CACHE = {} class RestParametersDirective(Table): headers = ["Name", "In", "Type", "Description"] def _load_param_file(self, fpath): global YAML_CACHE if fpath in YAML_CACHE: return YAML_CACHE[fpath] lookup = {} try: with open(fpath, 'r') as stream: lookup = ordered_load(stream) except IOError: LOG.warning("Parameters file not found, %s", fpath, location=(self.env.docname, None)) return except yaml.YAMLError as exc: LOG.exception(exc_info=exc, msg="Error while parsing file [%s]." % fpath) raise if lookup: self._check_yaml_sorting(fpath, lookup) else: LOG.warning("Parameters file is empty, %s", fpath, location=(self.env.docname, None)) return YAML_CACHE[fpath] = lookup return lookup def _check_yaml_sorting(self, fpath, yaml_data): """check yaml sorting Assuming we got an ordered dict, we iterate through it basically doing a gnome sort test (https://en.wikipedia.org/wiki/Gnome_sort) and ensure the item we are looking at is > the last item we saw. This is done at the section level first, so we're grouped, then alphabetically by lower case name within a section. Every time there is a mismatch we raise an warn message. """ sections = {"header": 1, "path": 2, "query": 3, "body": 4} last = None for key, value in yaml_data.items(): if not isinstance(value, dict): raise Exception('Expected a dict for {0}; got {0}={1}).\n' 'You probably have indentation typo in your' 'YAML source'.format(key, value)) # use of an invalid 'in' value if value['in'] not in sections: LOG.warning("``%s`` is not a valid value for 'in' (must be " "one of: %s). (see ``%s``)", value['in'], ", ".join(sorted(sections.keys())), key) continue if last is None: last = (key, value) continue # ensure that sections only go up current_section = value['in'] last_section = last[1]['in'] if sections[current_section] < sections[last_section]: LOG.warning("Section out of order. All parameters in section " "``%s`` should be after section ``%s``. (see " "``%s``)", last_section, current_section, last[0]) if (sections[value['in']] == sections[last[1]['in']] and key.lower() < last[0].lower()): LOG.warning("Parameters out of order ``%s`` should be after " "``%s``", last[0], key) last = (key, value) def yaml_from_file(self, fpath): """Collect Parameter stanzas from inline + file. This allows use to reference an external file for the actual parameter definitions. """ lookup = self._load_param_file(fpath) if not lookup: return content = "\n".join(self.content) parsed = yaml.safe_load(content) new_content = list() for paramlist in parsed: if not isinstance(paramlist, dict): location = (self.state_machine.node.source, self.state_machine.node.line) LOG.warning("Invalid parameter definition ``%s``. Expected " "format: ``name: reference``. Skipping.", paramlist, location=location) continue for name, ref in paramlist.items(): if ref in lookup: new_content.append((name, lookup[ref])) else: # TODO(sdague): this provides a kind of confusing # error message because app.warn isn't meant to be # used this way, however it does provide a way to # track down where the parameters list is that is # wrong. So it's good enough for now. location = (self.state_machine.node.source, self.state_machine.node.line) LOG.warning("No field definition for ``%s`` found in " "``%s``. Skipping.", ref, fpath) # Check for path params in stanza for i, param in enumerate(self.env.path_params): if (param.rstrip('}').lstrip('{')) == name: del self.env.path_params[i] break else: continue if len(self.env.path_params) != 0: # Warn that path parameters are not set in rest_parameter # stanza and will not appear in the generated table. for param in self.env.path_params: location = (self.state_machine.node.source, self.state_machine.node.line) LOG.warning("No path parameter ``%s`` found in rest_parameter" " stanza.\n", param.rstrip('}').lstrip('{')) self.yaml = new_content def run(self): self.env = self.state.document.settings.env # Make sure we have some content, which should be yaml that # defines some parameters. if not self.content: error = self.state_machine.reporter.error( 'No parameters defined', nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [error] if not len(self.arguments) >= 1: error = self.state_machine.reporter.error( 'No reference file defined', nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [error] # NOTE(sdague): it's important that we pop the arg otherwise # we end up putting the filename as the table caption. rel_fpath, fpath = self.env.relfn2path(self.arguments.pop()) self.yaml_file = fpath self.yaml_from_file(self.yaml_file) self.max_cols = len(self.headers) # TODO(sdague): it would be good to dynamically set column # widths (or basically make the colwidth thing go away # entirely) self.options['widths'] = [20, 10, 10, 60] self.col_widths = self.get_column_widths(self.max_cols) if isinstance(self.col_widths, tuple): # In docutils 0.13.1, get_column_widths returns a (widths, # colwidths) tuple, where widths is a string (i.e. 'auto'). # See https://sourceforge.net/p/docutils/patches/120/. self.col_widths = self.col_widths[1] # Actually convert the yaml title, messages = self.make_title() table_node = self.build_table() self.add_name(table_node) if title: table_node.insert(0, title) return [table_node] + messages def get_rows(self, table_data): rows = [] groups = [] trow = nodes.row() entry = nodes.entry() para = nodes.paragraph(text=str(table_data)) entry += para trow += entry rows.append(trow) return rows, groups # Add a column for a field. In order to have the RST inside # these fields get rendered, we need to use the # ViewList. Note, ViewList expects a list of lines, so chunk # up our content as a list to make it happy. def add_col(self, value): entry = nodes.entry() result = ViewList(value.split('\n')) self.state.nested_parse(result, 0, entry) return entry def show_no_yaml_error(self): trow = nodes.row(classes=["no_yaml"]) trow += self.add_col("No yaml found %s" % self.yaml_file) trow += self.add_col("") trow += self.add_col("") trow += self.add_col("") return trow def collect_rows(self): rows = [] groups = [] try: for key, values in self.yaml: min_version = values.get('min_version', '') max_version = values.get('max_version', '') desc = values.get('description', '') classes = [] if min_version: desc += ("\n\n**New in version %s**\n" % min_version) min_ver_css_name = ("rp_min_ver_" + str(min_version).replace('.', '_')) classes.append(min_ver_css_name) if max_version: desc += ("\n\n**Available until version %s**\n" % max_version) max_ver_css_name = ("rp_max_ver_" + str(max_version).replace('.', '_')) classes.append(max_ver_css_name) trow = nodes.row(classes=classes) name = key if values.get('required', False) is False: name += " (Optional)" trow += self.add_col(name) trow += self.add_col(values.get('in')) trow += self.add_col(values.get('type')) trow += self.add_col(desc) rows.append(trow) except AttributeError as exc: if 'key' in locals(): LOG.warning("Failure on key: %s, values: %s. %s", key, values, exc) else: rows.append(self.show_no_yaml_error()) return rows, groups def build_table(self): table = nodes.table() tgroup = nodes.tgroup(cols=len(self.headers)) table += tgroup # TODO(sdague): it would be really nice to figure out how not # to have this stanza, it kind of messes up all of the table # formatting because it doesn't let tables just be the right # size. tgroup.extend( nodes.colspec(colwidth=col_width, colname='c' + str(idx)) for idx, col_width in enumerate(self.col_widths) ) thead = nodes.thead() tgroup += thead row_node = nodes.row() thead += row_node row_node.extend(nodes.entry(h, nodes.paragraph(text=h)) for h in self.headers) tbody = nodes.tbody() tgroup += tbody rows, groups = self.collect_rows() tbody.extend(rows) table.extend(groups) return table def rest_method_html(self, node): tmpl = """
%(method)s
%(url)s

%(desc)s

""" node['url'] = node['url'].replace( '{', '{') node['url'] = node['url'].replace( '}', '}') self.body.append(tmpl % node) raise nodes.SkipNode def rest_expand_all_html(self, node): tmpl = """
%(extra_js)s
%(selector)s
""" node.setdefault('selector', "") node.setdefault('extra_js', "") if node['major']: node['selector'], node['extra_js'] = create_mv_selector(node) self.body.append(tmpl % node) raise nodes.SkipNode def create_mv_selector(node): mv_list = '' for x in range(node['min_ver'], node['max_ver'] + 1): mv_list += build_mv_item(node['major'], x, node['releases']) selector_tmpl = """
""" js_tmpl = """ """ selector_content = { 'mv_list': mv_list } js_content = { 'min': node['min_ver'], 'max': node['max_ver'] } return selector_tmpl % selector_content, js_tmpl % js_content def build_mv_item(major, micro, releases): version = "%d.%d" % (major, micro) if version in releases: return '' % ( version, version, releases[version].capitalize()) else: return '' % (version, version) def resolve_rest_references(app, doctree): for node in doctree.traverse(): if isinstance(node, rest_method): rest_node = node rest_method_section = node.parent rest_section = rest_method_section.parent gp = rest_section.parent # Added required classes to the top section rest_section.attributes['classes'].append('api-detail') rest_section.attributes['classes'].append('collapse') # Pop the title off the collapsed section title = rest_section.children.pop(0) rest_node['desc'] = title.children[0] # In order to get the links in the sidebar to be right, we # have to do some id flipping here late in the game. The # rest_method_section has basically had a dummy id up # until this point just to keep it from colliding with # it's parent. rest_section.attributes['ids'][0] = ( "%s-detail" % rest_section.attributes['ids'][0]) rest_method_section.attributes['ids'][0] = rest_node['target'] # Pop the overall section into it's grand parent, # right before where the current parent lives idx = gp.children.index(rest_section) rest_section.remove(rest_method_section) gp.insert(idx, rest_method_section) def copy_assets(app, exception): assets = ('api-site.css', 'api-site.js', 'combobox.js') fonts = ( 'glyphicons-halflings-regular.ttf', 'glyphicons-halflings-regular.woff' ) builders = ('html', 'readthedocs', 'readthedocssinglehtmllocalmedia') if app.builder.name not in builders or exception: return dirtree = os.path.join(app.builder.outdir, '_static/fonts') if not os.path.exists(dirtree): os.makedirs(dirtree) LOG.info('Copying assets: %s', ', '.join(assets)) LOG.info('Copying fonts: %s', ', '.join(fonts)) for asset in assets: dest = os.path.join(app.builder.outdir, '_static', asset) source = os.path.abspath(os.path.dirname(__file__)) copyfile(os.path.join(source, 'assets', asset), dest) for font in fonts: dest = os.path.join(app.builder.outdir, '_static/fonts', font) source = os.path.abspath(os.path.dirname(__file__)) copyfile(os.path.join(source, 'assets', font), dest) def add_assets(app): app.add_css_file('api-site.css') app.add_js_file('api-site.js') app.add_js_file('combobox.js') def setup(app): # Add some config options around microversions app.add_config_value('os_api_ref_max_microversion', '', 'env') app.add_config_value('os_api_ref_min_microversion', '', 'env') app.add_config_value('os_api_ref_release_microversions', '', 'env') # TODO(sdague): if someone wants to support latex/pdf, or man page # generation using these stanzas, here is where you'd need to # specify content specific renderers. app.add_node(rest_method, html=(rest_method_html, None)) app.add_node(rest_expand_all, html=(rest_expand_all_html, None)) app.add_node(http_code, html=(http_code_html, None)) # This specifies all our directives that we're adding app.add_directive('rest_parameters', RestParametersDirective) app.add_directive('rest_method', RestMethodDirective) app.add_directive('rest_expand_all', RestExpandAllDirective) app.add_directive('rest_status_code', HTTPResponseCodeDirective) # The doctree-read hook is used do the slightly crazy doc # transformation that we do to get the rest_method document # structure. app.connect('doctree-read', resolve_rest_references) # Add all the static assets to our build during the early stage of building app.connect('builder-inited', add_assets) # This copies all the assets (css, js, fonts) over to the build # _static directory during final build. app.connect('build-finished', copy_assets) return { 'parallel_read_safe': True, 'parallel_write_safe': True, 'version': __version__, } ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1732045155.9980812 os-api-ref-3.0.1/os_api_ref/assets/0000775000175000017500000000000000000000000017110 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045126.0 os-api-ref-3.0.1/os_api_ref/assets/api-site.css0000664000175000017500000000772600000000000021351 0ustar00zuulzuul00000000000000tt.literal { padding: 2px 4px; font-size: 90%; color: #c7254e; white-space: nowrap; background-color: #f9f2f4; border-radius: 4px; } /* bootstrap users blockquote for pull quotes, so they are much larger, we need them smaller */ blockquote { font-size: 1em; } .docs-book-wrapper { width: 90% !important } tbody>tr:nth-child(odd)>td, tbody>tr:nth-child(odd)>th { background-color: #f9f9f9; } td>p { margin: 0 0 0.5em; } .operation-grp { padding-top: 0.5em; padding-bottom: 1em; } /* Ensure the method buttons and their links don't split lines when the page is narrower */ .operation { /* this moves the link icon into the gutter */ margin-left: -1.25em; margin-right: 1.25em; white-space: nowrap; } /* These make the links only show up on hover */ a.operation-anchor { visibility: hidden; } .operation-grp:hover a.operation-anchor { visibility: visible; } /* All parameter tables should be full width */ .api-detail table.docutils { width: 100%; } .versionmodified { font-weight: bold; } .label-POST { background-color: #5cb85c; } .label-POST[href]:hover, .label-POST[href]:focus { background-color: #449d44; } .label-GET, .label-HEAD { background-color: #5bc0de; } .label-GET[href]:hover, .label-GET[href]:focus, .label-HEAD[href]:hover, .label-HEAD[href]:focus { background-color: #31b0d5; } .label-PUT, .label-PATCH { background-color: #f0ad4e; } .label-PUT[href]:hover, .label-PUT[href]:focus, .label-PATCH[href]:hover, .label-PATCH[href]:focus { background-color: #ec971f; } .label-COPY { background-color: #6666ff; } .label-COPY[href]:hover, .label-COPY[href]:focus { background-color: #6699ff; } .label-DELETE { background-color: #d9534f; } .label-DELETE[href]:hover, .label-DELETE[href]:focus { background-color: #c9302c; } .btn-detail:hover, .btn-detail:focus, .btn-expand-all:hover, .btn-expand-all:focus { color: #fff; background-color: #3b6c91; border-color: #269abc; } .btn-detail, .btn-expand-all { color: #fff; background-color: #2A4E68; } span.path_parameter { font-family: monospace; padding: 2px 4px; font-size: 90%; color: #c7254e; white-space: nowrap; background-color: #f9f2f4; border-radius: 4px; } /* for microversion selector */ .mv_selector { font-size: 0.8em; padding: 0.3em; } .mv_selector.active { color: #fff; background-color: #31b0d5; border-color: #269abc; } p.url-subtitle { color: #555; font-weight: bold; } .docs-body .section h1 { display: block; } div.docs-sidebar-toc > div > ul > li { list-style-type: none; font-size: 0.8em; font-weight: bold; } div.docs-sidebar-toc > div > ul { padding-left: 20px } div.docs-sidebar-toc > div > ul > li > ul > li { list-style-type: disc; font-weight: normal; } div.docs-top-contents { display: none; } div.endpoint-container{ padding-left: 15px; } #expand-all { margin-top: 23px; } ### Combobox Experiment @media (min-width: 768px) { .form-search .combobox-container, .form-inline .combobox-container { display: inline-block; margin-bottom: 0; vertical-align: top; } .form-search .combobox-container .input-group-addon, .form-inline .combobox-container .input-group-addon { width: auto; } } .combobox-selected .caret { display: none; } /* :not doesn't work in IE8 */ .combobox-container:not(.combobox-selected) .glyphicon-remove { display: none; } .typeahead-long { max-height: 300px; overflow-y: auto; } .control-group.error .combobox-container .add-on { color: #B94A48; border-color: #B94A48; } .control-group.error .combobox-container .caret { border-top-color: #B94A48; } .control-group.warning .combobox-container .add-on { color: #C09853; border-color: #C09853; } .control-group.warning .combobox-container .caret { border-top-color: #C09853; } .control-group.success .combobox-container .add-on { color: #468847; border-color: #468847; } .control-group.success .combobox-container .caret { border-top-color: #468847; } ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045126.0 os-api-ref-3.0.1/os_api_ref/assets/api-site.js0000664000175000017500000001502300000000000021162 0ustar00zuulzuul00000000000000(function() { // the list of expanded element ids var expanded = []; // whether we should sync expand changes with the location // url. We need to make this false during large scale // operations because we're using the history API, which is // expensive. So a bulk expand turns this off, expands // everything, turns it back on, then does a history sync. var should_sync = true; $(document).ready(function() { // Change the text on the expando buttons when // appropriate. This also add or removes them to the list of // expanded sections, and then syncs that list to the history // after such a change. $('.api-detail') .on('hide.bs.collapse', function(e) { processButton(this, 'detail'); var index = expanded.indexOf(this.id); if (index > -1) { expanded.splice(index, 1); } sync_expanded(); }) .on('show.bs.collapse', function(e) { processButton(this, 'close'); expanded.push(this.id); sync_expanded(); }); // Expand the world. Wires up the expand all button, it turns // off the sync while it is running to save the costs with the // history API. var expandAllActive = true; $('#expand-all').click(function () { should_sync = false; if (expandAllActive) { expandAllActive = false; $('.api-detail').collapse('show'); $('#expand-all').attr('data-toggle', ''); $(this).text('Hide All'); } else { expandAllActive = true; $('.api-detail').collapse('hide'); $('#expand-all').attr('data-toggle', 'collapse'); $(this).text('Show All'); } should_sync = true; sync_expanded(); }); // if there is an expanded parameter passed in a url, we run // through and expand all the appropriate things. if (window.location.search.substring(1).indexOf("expanded") > -1) { should_sync = false; var parts = window.location.search.substring(1).split('&'); for (var i = 0; i < parts.length; i++) { var keyval = parts[i].split('='); if (keyval[0] == "expanded" && keyval[1]) { var expanded_ids = keyval[1].split(','); for (var j = 0; j < expanded_ids.length; j++) { $('#' + expanded_ids[j]).collapse('show'); } } } should_sync = true; // This is needed because the hash *might* be inside a // collapsed section. // // NOTE(sdague): this doesn't quite seem to work while // we're changing the rest of the document. $(document.body).scrollTop($(window.location.hash).offset().top); } // Wire up microversion selector $('.mv_selector').on('click', function(e) { var version = e.currentTarget.innerHTML; // flip what is active $(this).addClass('active').siblings().removeClass('active'); if (version == "All") { reset_microversion(); } else { set_microversion(version); } }); }); /** * Helper function for setting the text, styles for expandos */ function processButton(button, text) { $('#' + $(button).attr('id') + '-btn').text(text) .toggleClass('btn-info') .toggleClass('btn-default'); } // Take the expanded array and push it into history. Because // sphinx is building css appropriate ids, they should not have // any special characters we need to encode. So we can simply join // them into a comma separated list. function sync_expanded() { if (should_sync) { var url = UpdateQueryString('expanded', expanded.join(',')); history.pushState('', 'new expand', url); } } // Generically update the query string for a url. Credit to // http://stackoverflow.com/questions/5999118/add-or-update-query-string-parameter // for making this properly generic. function UpdateQueryString(key, value, url) { if (!url) url = window.location.href; var re = new RegExp("([?&])" + key + "=.*?(&|#|$)(.*)", "gi"), hash; if (re.test(url)) { if (typeof value !== 'undefined' && value !== null) return url.replace(re, '$1' + key + "=" + value + '$2$3'); else { hash = url.split('#'); url = hash[0].replace(re, '$1$3').replace(/(&|\?)$/, ''); if (typeof hash[1] !== 'undefined' && hash[1] !== null) url += '#' + hash[1]; return url; } } else { if (typeof value !== 'undefined' && value !== null) { var separator = url.indexOf('?') !== -1 ? '&' : '?'; hash = url.split('#'); url = hash[0] + separator + key + '=' + value; if (typeof hash[1] !== 'undefined' && hash[1] !== null) url += '#' + hash[1]; return url; } else return url; } } // Set the Y value of the microversion to turn on / off visibility // of components. function set_microversion(number) { var major = number.split(".")[0]; var micro = number.split(".")[1]; for (var i = os_min_mv; i <= os_max_mv; i++) { var max_class = ".rp_max_ver_" + major + "_" + i; var min_class = ".rp_min_ver_" + major + "_" + i; if (i < micro) { $(max_class).hide(400); $(min_class).show(400); } else if (i >= micro) { $(min_class).hide(400); $(max_class).show(400); } } } function reset_microversion() { $('[class^=rp_min_ver]').show(400); $('[class^=rp_max_ver]').show(400); } $(document).ready(function(){ $('#mv_select').combobox({appendId: '-visable'}); $('#mv_select').on('change', function() { var version = this.value; if (version == "") { reset_microversion(); } else { set_microversion(version); } }); }); })(); ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045126.0 os-api-ref-3.0.1/os_api_ref/assets/combobox.js0000664000175000017500000003201600000000000021260 0ustar00zuulzuul00000000000000/* ============================================================= * bootstrap-combobox.js v1.1.7 * ============================================================= * Copyright 2012 Daniel Farrell * * 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. * ============================================================ */ !function( $ ) { "use strict"; /* COMBOBOX PUBLIC CLASS DEFINITION * ================================ */ var Combobox = function ( element, options ) { this.options = $.extend({}, $.fn.combobox.defaults, options); this.template = this.options.template || this.template this.$source = $(element); this.$container = this.setup(); this.$element = this.$container.find('input[type=text]'); this.$target = this.$container.find('input[type=hidden]'); this.$button = this.$container.find('.dropdown-toggle'); this.$menu = $(this.options.menu).appendTo('body'); this.matcher = this.options.matcher || this.matcher; this.sorter = this.options.sorter || this.sorter; this.highlighter = this.options.highlighter || this.highlighter; this.shown = false; this.selected = false; this.refresh(); this.transferAttributes(); this.listen(); }; Combobox.prototype = { constructor: Combobox , setup: function () { var combobox = $(this.template()); this.$source.before(combobox); this.$source.hide(); return combobox; } , disable: function() { this.$element.prop('disabled', true); this.$button.attr('disabled', true); this.disabled = true; this.$container.addClass('combobox-disabled'); } , enable: function() { this.$element.prop('disabled', false); this.$button.attr('disabled', false); this.disabled = false; this.$container.removeClass('combobox-disabled'); } , parse: function () { var that = this , map = {} , source = [] , selected = false , selectedValue = ''; this.$source.find('option').each(function() { var option = $(this); if (option.val() === '') { that.options.placeholder = option.text(); return; } map[option.text()] = option.val(); source.push(option.text()); if (option.prop('selected')) { selected = option.text(); selectedValue = option.val(); } }) this.map = map; if (selected) { this.$element.val(selected); this.$target.val(selectedValue); this.$container.addClass('combobox-selected'); this.selected = true; } return source; } , transferAttributes: function() { this.options.placeholder = this.$source.attr('data-placeholder') || this.options.placeholder if(this.options.appendId !== "undefined") { this.$element.attr('id', this.$source.attr('id') + this.options.appendId); } this.$element.attr('placeholder', this.options.placeholder) this.$target.prop('name', this.$source.prop('name')) this.$target.val(this.$source.val()) this.$source.removeAttr('name') // Remove from source otherwise form will pass parameter twice. this.$element.attr('required', this.$source.attr('required')) this.$element.attr('rel', this.$source.attr('rel')) this.$element.attr('title', this.$source.attr('title')) this.$element.attr('class', this.$source.attr('class')) this.$element.attr('tabindex', this.$source.attr('tabindex')) this.$source.removeAttr('tabindex') if (this.$source.attr('disabled')!==undefined) this.disable(); } , select: function () { var val = this.$menu.find('.active').attr('data-value'); this.$element.val(this.updater(val)).trigger('change'); this.$target.val(this.map[val]).trigger('change'); this.$source.val(this.map[val]).trigger('change'); this.$container.addClass('combobox-selected'); this.selected = true; return this.hide(); } , updater: function (item) { return item; } , show: function () { var pos = $.extend({}, this.$element.position(), { height: this.$element[0].offsetHeight }); this.$menu .insertAfter(this.$element) .css({ top: pos.top + pos.height , left: pos.left }) .show(); $('.dropdown-menu').on('mousedown', $.proxy(this.scrollSafety, this)); this.shown = true; return this; } , hide: function () { this.$menu.hide(); $('.dropdown-menu').off('mousedown', $.proxy(this.scrollSafety, this)); this.$element.on('blur', $.proxy(this.blur, this)); this.shown = false; return this; } , lookup: function (event) { this.query = this.$element.val(); return this.process(this.source); } , process: function (items) { var that = this; items = $.grep(items, function (item) { return that.matcher(item); }) items = this.sorter(items); if (!items.length) { return this.shown ? this.hide() : this; } return this.render(items.slice(0, this.options.items)).show(); } , template: function() { if (this.options.bsVersion == '2') { return '
' } else { return '
' } } , matcher: function (item) { return ~item.toLowerCase().indexOf(this.query.toLowerCase()); } , sorter: function (items) { var beginswith = [] , caseSensitive = [] , caseInsensitive = [] , item; while (item = items.shift()) { if (!item.toLowerCase().indexOf(this.query.toLowerCase())) {beginswith.push(item);} else if (~item.indexOf(this.query)) {caseSensitive.push(item);} else {caseInsensitive.push(item);} } return beginswith.concat(caseSensitive, caseInsensitive); } , highlighter: function (item) { var query = this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&'); return item.replace(new RegExp('(' + query + ')', 'ig'), function ($1, match) { return '' + match + ''; }) } , render: function (items) { var that = this; items = $(items).map(function (i, item) { i = $(that.options.item).attr('data-value', item); i.find('a').html(that.highlighter(item)); return i[0]; }) items.first().addClass('active'); this.$menu.html(items); return this; } , next: function (event) { var active = this.$menu.find('.active').removeClass('active') , next = active.next(); if (!next.length) { next = $(this.$menu.find('li')[0]); } next.addClass('active'); } , prev: function (event) { var active = this.$menu.find('.active').removeClass('active') , prev = active.prev(); if (!prev.length) { prev = this.$menu.find('li').last(); } prev.addClass('active'); } , toggle: function () { if (!this.disabled) { if (this.$container.hasClass('combobox-selected')) { this.clearTarget(); this.triggerChange(); this.clearElement(); } else { if (this.shown) { this.hide(); } else { this.clearElement(); this.lookup(); } } } } , scrollSafety: function(e) { if (e.target.tagName == 'UL') { this.$element.off('blur'); } } , clearElement: function () { this.$element.val('').focus(); } , clearTarget: function () { this.$source.val(''); this.$target.val(''); this.$container.removeClass('combobox-selected'); this.selected = false; } , triggerChange: function () { this.$source.trigger('change'); } , refresh: function () { this.source = this.parse(); this.options.items = this.source.length; } , listen: function () { this.$element .on('focus', $.proxy(this.focus, this)) .on('blur', $.proxy(this.blur, this)) .on('keypress', $.proxy(this.keypress, this)) .on('keyup', $.proxy(this.keyup, this)); if (this.eventSupported('keydown')) { this.$element.on('keydown', $.proxy(this.keydown, this)); } this.$menu .on('click', $.proxy(this.click, this)) .on('mouseenter', 'li', $.proxy(this.mouseenter, this)) .on('mouseleave', 'li', $.proxy(this.mouseleave, this)); this.$button .on('click', $.proxy(this.toggle, this)); } , eventSupported: function(eventName) { var isSupported = eventName in this.$element; if (!isSupported) { this.$element.setAttribute(eventName, 'return;'); isSupported = typeof this.$element[eventName] === 'function'; } return isSupported; } , move: function (e) { if (!this.shown) {return;} switch(e.keyCode) { case 9: // tab case 13: // enter case 27: // escape e.preventDefault(); break; case 38: // up arrow e.preventDefault(); this.prev(); this.fixMenuScroll(); break; case 40: // down arrow e.preventDefault(); this.next(); this.fixMenuScroll(); break; } e.stopPropagation(); } , fixMenuScroll: function(){ var active = this.$menu.find('.active'); if(active.length){ var top = active.position().top; var bottom = top + active.height(); var scrollTop = this.$menu.scrollTop(); var menuHeight = this.$menu.height(); if(bottom > menuHeight){ this.$menu.scrollTop(scrollTop + bottom - menuHeight); } else if(top < 0){ this.$menu.scrollTop(scrollTop + top); } } } , keydown: function (e) { this.suppressKeyPressRepeat = ~$.inArray(e.keyCode, [40,38,9,13,27]); this.move(e); } , keypress: function (e) { if (this.suppressKeyPressRepeat) {return;} this.move(e); } , keyup: function (e) { switch(e.keyCode) { case 40: // down arrow if (!this.shown){ this.toggle(); } break; case 39: // right arrow case 38: // up arrow case 37: // left arrow case 36: // home case 35: // end case 16: // shift case 17: // ctrl case 18: // alt break; case 9: // tab case 13: // enter if (!this.shown) {return;} this.select(); break; case 27: // escape if (!this.shown) {return;} this.hide(); break; default: this.clearTarget(); this.lookup(); } e.stopPropagation(); e.preventDefault(); } , focus: function (e) { this.focused = true; } , blur: function (e) { var that = this; this.focused = false; var val = this.$element.val(); if (!this.selected && val !== '' ) { this.$element.val(''); this.$source.val('').trigger('change'); this.$target.val('').trigger('change'); } if (!this.mousedover && this.shown) {setTimeout(function () { that.hide(); }, 200);} } , click: function (e) { e.stopPropagation(); e.preventDefault(); this.select(); this.$element.focus(); } , mouseenter: function (e) { this.mousedover = true; this.$menu.find('.active').removeClass('active'); $(e.currentTarget).addClass('active'); } , mouseleave: function (e) { this.mousedover = false; } }; /* COMBOBOX PLUGIN DEFINITION * =========================== */ $.fn.combobox = function ( option ) { return this.each(function () { var $this = $(this) , data = $this.data('combobox') , options = typeof option == 'object' && option; if(!data) {$this.data('combobox', (data = new Combobox(this, options)));} if (typeof option == 'string') {data[option]();} }); }; $.fn.combobox.defaults = { bsVersion: '3' , menu: '' , item: '
  • ' }; $.fn.combobox.Constructor = Combobox; }( window.jQuery ); ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045126.0 os-api-ref-3.0.1/os_api_ref/http_codes.py0000664000175000017500000001744000000000000020322 0ustar00zuulzuul00000000000000# 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 http.client import responses from docutils import nodes from docutils.parsers.rst.directives.tables import Table from docutils.statemachine import ViewList from sphinx.util import logging import yaml LOG = logging.getLogger(__name__) # cache for file -> yaml so we only do the load and check of a yaml # file once during a sphinx processing run. HTTP_YAML_CACHE = {} class HTTPResponseCodeDirective(Table): headers = ["Code", "Reason"] status_types = ("success", "error") # This is for HTTP response codes that OpenStack may use that are not part # the httplib response dict. CODES = { 429: "Too Many Requests", } required_arguments = 2 def __init__(self, *args, **kwargs): self.CODES.update(responses) super(HTTPResponseCodeDirective, self).__init__(*args, **kwargs) def _load_status_file(self, fpath): global HTTP_YAML_CACHE if fpath in HTTP_YAML_CACHE: return HTTP_YAML_CACHE[fpath] # LOG.info("Fpath: %s" % fpath) try: with open(fpath, 'r') as stream: lookup = yaml.safe_load(stream) except IOError: LOG.warning( "Parameters file %s not found" % fpath, (self.env.docname, None)) return except yaml.YAMLError as exc: LOG.warning(exc) raise HTTP_YAML_CACHE[fpath] = lookup return lookup def run(self): self.env = self.state.document.settings.env # Make sure we have some content, which should be yaml that # defines some parameters. if not self.content: error = self.state_machine.reporter.error( 'No parameters defined', nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [error] if not len(self.arguments) >= 2: error = self.state_machine.reporter.error( '%s' % self.arguments, nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [error] _, status_defs_file = self.env.relfn2path(self.arguments.pop()) status_type = self.arguments.pop() self.status_defs = self._load_status_file(status_defs_file) # LOG.info("%s" % str(self.status_defs)) if status_type not in self.status_types: error = self.state_machine.reporter.error( 'Type %s is not one of %s' % (status_type, self.status_types), nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [error] self.yaml = self._load_codes() self.max_cols = len(self.headers) # TODO(sdague): it would be good to dynamically set column # widths (or basically make the colwidth thing go away # entirely) self.options['widths'] = [30, 70] self.col_widths = self.get_column_widths(self.max_cols) if isinstance(self.col_widths, tuple): # In docutils 0.13.1, get_column_widths returns a (widths, # colwidths) tuple, where widths is a string (i.e. 'auto'). # See https://sourceforge.net/p/docutils/patches/120/. self.col_widths = self.col_widths[1] # Actually convert the yaml title, messages = self.make_title() # LOG.info("Title %s, messages %s" % (title, messages)) table_node = self.build_table() self.add_name(table_node) title_block = nodes.title( text=status_type.capitalize()) section = nodes.section(ids=title_block) section += title_block section += table_node return [section] + messages def _load_codes(self): content = "\n".join(self.content) parsed = yaml.safe_load(content) new_content = list() for item in parsed: if isinstance(item, int): new_content.append((item, self.status_defs[item]['default'])) else: try: for code, reason in item.items(): new_content.append( (code, self.status_defs[code][reason]) ) except KeyError: LOG.warning( "Could not find %s for code %s" % (reason, code)) new_content.append( (code, self.status_defs[code]['default'])) return new_content def build_table(self): table = nodes.table() tgroup = nodes.tgroup(cols=len(self.headers)) table += tgroup # TODO(sdague): it would be really nice to figure out how not # to have this stanza, it kind of messes up all of the table # formatting because it doesn't let tables just be the right # size. tgroup.extend( nodes.colspec(colwidth=col_width, colname='c' + str(idx)) for idx, col_width in enumerate(self.col_widths) ) thead = nodes.thead() tgroup += thead row_node = nodes.row() thead += row_node row_node.extend(nodes.entry(h, nodes.paragraph(text=h)) for h in self.headers) tbody = nodes.tbody() tgroup += tbody rows, groups = self.collect_rows() tbody.extend(rows) table.extend(groups) return table def add_col(self, node): entry = nodes.entry() entry.append(node) return entry def add_desc_col(self, value): entry = nodes.entry() result = ViewList(value.split('\n')) self.state.nested_parse(result, 0, entry) return entry def collect_rows(self): rows = [] groups = [] try: # LOG.info("Parsed content is: %s" % self.yaml) for code, desc in self.yaml: h_code = http_code() h_code['code'] = code h_code['title'] = self.CODES.get(code, 'Unknown') trow = nodes.row() trow += self.add_col(h_code) trow += self.add_desc_col(desc) rows.append(trow) except AttributeError as exc: # if 'key' in locals(): LOG.warning("Failure on key: %s, values: %s. %s" % (code, desc, exc)) # else: # rows.append(self.show_no_yaml_error()) return rows, groups def http_code_html(self, node): tmpl = "%(code)s - %(title)s" self.body.append(tmpl % node) raise nodes.SkipNode class http_code(nodes.Part, nodes.Element): """Node for http_code stanza Because we need to insert very specific HTML at the final stage of processing, the http_code stanza needs a custom node type. This lets us accumulate the relevant data into this node, during parsing, but not turn it into known sphinx types (lists, tables, sections). Then, during the final build phase we transform directly to the html that we want. NOTE: this means we error trying to build latex or man pages for these stanza types right now. This is all fixable if we add an output formatter for this node type, but it's not yet a priority. Contributions welcomed. """ pass ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1732045156.0020812 os-api-ref-3.0.1/os_api_ref/tests/0000775000175000017500000000000000000000000016750 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045126.0 os-api-ref-3.0.1/os_api_ref/tests/__init__.py0000664000175000017500000000000000000000000021047 0ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045126.0 os-api-ref-3.0.1/os_api_ref/tests/base.py0000664000175000017500000000767600000000000020254 0ustar00zuulzuul00000000000000# Copyright 2010-2011 OpenStack Foundation # Copyright (c) 2013 Hewlett-Packard Development Company, L.P. # # 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 pathlib import shutil import fixtures import tempfile import testtools from sphinx.testing.util import SphinxTestApp def example_dir(name=""): return os.path.join(os.path.dirname(__file__), 'examples', name) _TRUE_VALUES = ('True', 'true', '1', 'yes') class with_app: def __init__(self, **kwargs): self.srcdir = pathlib.Path(kwargs['srcdir']) self.sphinx_app_args = kwargs def __call__(self, f): def newf(*args, **kwargs): with tempfile.TemporaryDirectory() as tmpdirname: tmpdir = pathlib.Path(tmpdirname) tmproot = tmpdir.joinpath(self.srcdir.name) shutil.copytree(self.srcdir, tmproot) self.sphinx_app_args['srcdir'] = tmproot self.builddir = tmproot.joinpath('_build') app = SphinxTestApp(freshenv=True, **self.sphinx_app_args) f(*args, app, app._status, app._warning, **kwargs) app.cleanup() return newf class OutputStreamCapture(fixtures.Fixture): """Capture output streams during tests. This fixture captures errant printing to stderr / stdout during the tests and lets us see those streams at the end of the test runs instead. Useful to see what was happening during failed tests. """ def setUp(self): super(OutputStreamCapture, self).setUp() if os.environ.get('OS_STDOUT_CAPTURE') in _TRUE_VALUES: self.out = self.useFixture(fixtures.StringStream('stdout')) self.useFixture( fixtures.MonkeyPatch('sys.stdout', self.out.stream)) if os.environ.get('OS_STDERR_CAPTURE') in _TRUE_VALUES: self.err = self.useFixture(fixtures.StringStream('stderr')) self.useFixture( fixtures.MonkeyPatch('sys.stderr', self.err.stream)) @property def stderr(self): return self.err._details["stderr"].as_text() @property def stdout(self): return self.out._details["stdout"].as_text() class Timeout(fixtures.Fixture): """Setup per test timeouts. In order to avoid test deadlocks we support setting up a test timeout parameter read from the environment. In almost all cases where the timeout is reached this means a deadlock. A class level TIMEOUT_SCALING_FACTOR also exists, which allows extremely long tests to specify they need more time. """ def __init__(self, timeout, scaling=1): super(Timeout, self).__init__() try: self.test_timeout = int(timeout) except ValueError: # If timeout value is invalid do not set a timeout. self.test_timeout = 0 if scaling >= 1: self.test_timeout *= scaling else: raise ValueError('scaling value must be >= 1') def setUp(self): super(Timeout, self).setUp() if self.test_timeout > 0: self.useFixture(fixtures.Timeout(self.test_timeout, gentle=True)) class TestCase(testtools.TestCase): """Test case base class for all unit tests.""" def setUp(self): """Run before each test method to initialize test environment.""" super(TestCase, self).setUp() self.useFixture(Timeout( os.environ.get('OS_TEST_TIMEOUT', 0))) self.useFixture(OutputStreamCapture()) ././@PaxHeader0000000000000000000000000000003300000000000011451 xustar000000000000000027 mtime=1732045155.990081 os-api-ref-3.0.1/os_api_ref/tests/examples/0000775000175000017500000000000000000000000020566 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1732045156.0020812 os-api-ref-3.0.1/os_api_ref/tests/examples/basic/0000775000175000017500000000000000000000000021647 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045126.0 os-api-ref-3.0.1/os_api_ref/tests/examples/basic/conf.py0000664000175000017500000000210200000000000023141 0ustar00zuulzuul00000000000000# # 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. # -- General configuration ---------------------------------------------------- # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. import openstackdocstheme html_theme = 'openstackdocs' html_theme_path = [openstackdocstheme.get_html_theme_path()] html_theme_options = { "sidebar_mode": "toc", } extensions = [ 'os_api_ref', ] # The suffix of source filenames. source_suffix = '.rst' # The master toctree document. master_doc = 'index' ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045126.0 os-api-ref-3.0.1/os_api_ref/tests/examples/basic/index.rst0000664000175000017500000000061000000000000023505 0ustar00zuulzuul00000000000000.. rest_expand_all:: I am text, hear me roar! ============== List Servers ============== .. rest_method:: GET /servers .. rest_parameters:: parameters.yaml - name: name Response codes -------------- .. rest_status_code:: success status.yaml - 200 - 100 - 201 .. rest_status_code:: error status.yaml - 405 - 403 - 401 - 400 - 500 - 409: duplcate_zone ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045126.0 os-api-ref-3.0.1/os_api_ref/tests/examples/basic/parameters.yaml0000664000175000017500000000013100000000000024671 0ustar00zuulzuul00000000000000name: in: body required: true type: string description: | The name of things ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045126.0 os-api-ref-3.0.1/os_api_ref/tests/examples/basic/status.yaml0000664000175000017500000000144300000000000024060 0ustar00zuulzuul00000000000000################# # Success Codes # ################# 100: default: | An unusual code for an API 200: default: | Request was successful. 201: default: | Resource was created and is ready to use. ################# # Error Codes # ################# 400: default: | Some content in the request was invalid zone_data_error: | Some of the data for the 401: default: | User must authenticate before making a request 403: default: | Policy does not allow current user to do this operation. 405: default: | Method is not valid for this endpoint. 409: default: | This operation conflicted with another operation on this resource duplcate_zone: | There is already a zone with this name. 500: default: | Something went wrong inside the service. ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1732045156.0020812 os-api-ref-3.0.1/os_api_ref/tests/examples/microversions/0000775000175000017500000000000000000000000023470 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045126.0 os-api-ref-3.0.1/os_api_ref/tests/examples/microversions/conf.py0000664000175000017500000000221400000000000024766 0ustar00zuulzuul00000000000000# # 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. # -- General configuration ---------------------------------------------------- # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. import openstackdocstheme html_theme = 'openstackdocs' html_theme_path = [openstackdocstheme.get_html_theme_path()] html_theme_options = { "sidebar_mode": "toc", } extensions = [ 'os_api_ref', ] # The suffix of source filenames. source_suffix = '.rst' # The master toctree document. master_doc = 'index' os_api_ref_min_microversion = '2.1' os_api_ref_max_microversion = '2.30' ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045126.0 os-api-ref-3.0.1/os_api_ref/tests/examples/microversions/index.rst0000664000175000017500000000050000000000000025324 0ustar00zuulzuul00000000000000.. rest_expand_all:: I am text, hear me roar! ============== List Servers ============== .. rest_method:: GET /servers .. rest_parameters:: parameters.yaml - name: name - name2: name2 - name3: name3 =========== List Tags =========== .. rest_method:: GET /tags min_version: 2.17 max_version: 2.19 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045126.0 os-api-ref-3.0.1/os_api_ref/tests/examples/microversions/parameters.yaml0000664000175000017500000000046400000000000026523 0ustar00zuulzuul00000000000000name: in: body required: true type: string description: | The name of things name2: in: body required: true type: string description: | The name of things min_version: 2.11 name3: in: body required: true type: string description: | The name of things max_version: 2.20././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1732045156.0020812 os-api-ref-3.0.1/os_api_ref/tests/examples/warnings/0000775000175000017500000000000000000000000022416 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045126.0 os-api-ref-3.0.1/os_api_ref/tests/examples/warnings/conf.py0000664000175000017500000000210200000000000023710 0ustar00zuulzuul00000000000000# # 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. # -- General configuration ---------------------------------------------------- # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. import openstackdocstheme html_theme = 'openstackdocs' html_theme_path = [openstackdocstheme.get_html_theme_path()] html_theme_options = { "sidebar_mode": "toc", } extensions = [ 'os_api_ref', ] # The suffix of source filenames. source_suffix = '.rst' # The master toctree document. master_doc = 'index' ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045126.0 os-api-ref-3.0.1/os_api_ref/tests/examples/warnings/empty_parameters_file.yaml0000664000175000017500000000002700000000000027661 0ustar00zuulzuul00000000000000# Empty parameter file ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045126.0 os-api-ref-3.0.1/os_api_ref/tests/examples/warnings/index.rst0000664000175000017500000000174100000000000024262 0ustar00zuulzuul00000000000000.. rest_expand_all:: I am text, hear me roar! ============== List Servers ============== .. rest_method:: GET /servers .. rest_parameters:: parameters.yaml - name: name - name: lookup_key_name - name: name_1 - invalid_name No Parameters Specified ----------------------- .. rest_parameters:: parameters.yaml Empty File and Parameters Specified ----------------------------------- .. rest_parameters:: empty_parameters_file.yaml - name: name Nonexistent Parameter File -------------------------- .. rest_parameters:: no_parameters.yaml Check missing path parameters in stanza --------------------------------------- .. rest_method:: GET /server/{server_id}/{new_id}/{new_id2} .. rest_parameters:: parameters.yaml - server_id: server_id Check another missing path parameters in stanza ----------------------------------------------- .. rest_method:: GET /server/{b_id}/{c_id2}/{server_id} .. rest_parameters:: parameters.yaml - server_id: server_id ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045126.0 os-api-ref-3.0.1/os_api_ref/tests/examples/warnings/parameters.yaml0000664000175000017500000000064100000000000025446 0ustar00zuulzuul00000000000000# valid path parameter server_id: description: | ID for server. in: path required: true type: string # These are out of order, this should be a warning. name2: in: body required: false type: string description: | foo name: in: body required: true type: string description: | The name of things name_1: description: | name_1 is missing type field. in: body required: true ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045126.0 os-api-ref-3.0.1/os_api_ref/tests/test_basic_example.py0000664000175000017500000001123300000000000023155 0ustar00zuulzuul00000000000000# 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. """ test_os_api_ref ---------------------------------- Tests for `os_api_ref` module. """ from bs4 import BeautifulSoup from os_api_ref.tests import base class TestBasicExample(base.TestCase): """Test basic rendering. This can be used to test that basic rendering works for these examples, so if someone breaks something we know. """ @base.with_app(buildername='html', srcdir=base.example_dir('basic')) def setUp(self, app, status, warning): super(TestBasicExample, self).setUp() self.app = app self.status = status self.warning = warning self.app.build() self.html = (app.outdir / 'index.html').read_text(encoding='utf-8') self.soup = BeautifulSoup(self.html, 'html.parser') self.content = str(self.soup) def test_expand_all(self): """Do we get an expand all button like we expect.""" content = str(self.soup.find(id='expand-all')) example_button = ('') self.assertEqual( example_button, content) def test_rest_method(self): """Do we get a REST method call block""" # TODO(sdague): it probably would make sense to do this as a # whole template instead of parts. content = str(self.soup.find_all(class_='operation-grp')) self.assertIn( '', str(content)) self.assertIn( 'GET', str(content)) self.assertIn( '
    /servers
    ', str(content)) self.assertIn( (''), str(content)) def test_parameters(self): """Do we get some parameters table""" table = """

    Name

    In

    Type

    Description

    name

    body

    string

    The name of things

    """ self.assertIn(table, self.content) def test_rest_response(self): success_table = """

    Code

    Reason

    200 - OK

    Request was successful.

    100 - Continue

    An unusual code for an API

    201 - Created

    Resource was created and is ready to use.

    """ error_table = """

    Code

    Reason

    405 - Method Not Allowed

    Method is not valid for this endpoint.

    403 - Forbidden

    Policy does not allow current user to do this operation.

    401 - Unauthorized

    User must authenticate before making a request

    400 - Bad Request

    Some content in the request was invalid

    500 - Internal Server Error

    Something went wrong inside the service.

    409 - Conflict

    There is already a zone with this name.

    """ self.assertIn(success_table, self.content) self.assertIn(error_table, self.content) ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045126.0 os-api-ref-3.0.1/os_api_ref/tests/test_microversions.py0000664000175000017500000001006500000000000023265 0ustar00zuulzuul00000000000000# 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. """ test_os_api_ref ---------------------------------- Tests for `os_api_ref` module. """ from bs4 import BeautifulSoup from os_api_ref.tests import base class TestMicroversions(base.TestCase): """Test basic rendering. This can be used to test that basic rendering works for these examples, so if someone breaks something we know. """ @base.with_app(buildername='html', srcdir=base.example_dir('microversions')) def setUp(self, app, status, warning): super(TestMicroversions, self).setUp() self.app = app self.app.build() self.status = status.getvalue() self.warning = warning.getvalue() self.html = (app.outdir / 'index.html').read_text(encoding='utf-8') self.soup = BeautifulSoup(self.html, 'html.parser') self.content = str(self.soup) def test_rest_method(self): """Test that min / max mv css class attributes are set""" content = self.soup.find_all(class_='rp_min_ver_2_17') self.assertRegex( str(content[0]), '^

    Name

    In

    Type

    Description

    name

    body

    string

    The name of things

    name2

    body

    string

    The name of things

    New in version 2.11

    name3

    body

    string

    The name of things

    Available until version 2.20

    """ self.assertIn(table, self.content) def test_mv_selector(self): button_selectors = '' # noqa self.assertIn(button_selectors, self.content) def test_js_declares(self): self.assertIn("os_max_mv = 30;", self.content) self.assertIn("os_min_mv = 1;", self.content) ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045126.0 os-api-ref-3.0.1/os_api_ref/tests/test_os_api_ref.py0000664000175000017500000000136300000000000022472 0ustar00zuulzuul00000000000000# 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. """ test_os_api_ref ---------------------------------- Tests for `os_api_ref` module. """ from os_api_ref.tests import base class TestOs_api_ref(base.TestCase): def test_something(self): pass ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045126.0 os-api-ref-3.0.1/os_api_ref/tests/test_warnings.py0000664000175000017500000000724300000000000022217 0ustar00zuulzuul00000000000000# 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. """ test_os_api_ref ---------------------------------- Tests for `os_api_ref` module. """ from collections import OrderedDict from bs4 import BeautifulSoup from os_api_ref.tests import base class TestWarnings(base.TestCase): """Test basic rendering. This can be used to test that basic rendering works for these examples, so if someone breaks something we know. """ @base.with_app(buildername='html', srcdir=base.example_dir('warnings')) def setUp(self, app, status, warning): super(TestWarnings, self).setUp() self.app = app self.app.build() self.status = status.getvalue() self.warning = warning.getvalue() self.html = (app.outdir / 'index.html').read_text(encoding='utf-8') self.soup = BeautifulSoup(self.html, 'html.parser') self.content = str(self.soup) def test_out_of_order(self): """Do we get an out of order naming warning.""" self.assertIn( ("WARNING: Parameters out of order ``name2`` " "should be after ``name``"), self.warning) def test_missing_lookup_name(self): """Warning when missing a lookup key in parameter file.""" self.assertIn( ("WARNING: No field definition for ``lookup_key_name`` found in "), self.warning) def test_missing_field(self): """Warning when missing type field in parameter file.""" # py312 changes string interpretation of OrderedDict. # Prevent such failures by using OrderedDict directly cmp_data = OrderedDict({ "description": "name_1 is missing type field.\n", "in": "body", "required": True }) self.assertIn( ("WARNING: Failure on key: name, values: " + f"{cmp_data}. " + "'NoneType' object has no attribute 'split'"), self.warning) def test_invalid_parameter_definition(self): """Warning when parameter definition is invalid.""" self.assertIn( ("WARNING: Invalid parameter definition ``invalid_name``. " + "Expected format: ``name: reference``. "), self.warning) def test_empty_parameter_file(self): """Warning when parameter file exists but is empty.""" self.assertIn( ("WARNING: Parameters file is empty"), self.warning) def test_no_parameters_set(self): """Error when parameters are not set in rest_parameters stanza.""" self.assertIn( ("No parameters defined\n\n.." + " rest_parameters:: parameters.yaml"), self.warning) def test_parameter_file_not_exist(self): """Error when parameter file does not exist""" self.assertIn( ("No parameters defined\n\n.." + " rest_parameters:: no_parameters.yaml"), self.warning) def test_missing_path_parameter_in_stanza(self): """Warning when path param not found in rest_parameter stanza.""" self.assertIn( ("WARNING: No path parameter ``b_id`` found in" + " rest_parameter stanza.\n"), self.warning) ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1732045155.9980812 os-api-ref-3.0.1/os_api_ref.egg-info/0000775000175000017500000000000000000000000017300 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045155.0 os-api-ref-3.0.1/os_api_ref.egg-info/PKG-INFO0000664000175000017500000001335600000000000020405 0ustar00zuulzuul00000000000000Metadata-Version: 1.2 Name: os-api-ref Version: 3.0.1 Summary: Sphinx Extensions to support API reference sites in OpenStack Home-page: https://docs.openstack.org/os-api-ref/latest/ Author: OpenStack Author-email: openstack-discuss@lists.openstack.org License: UNKNOWN Description: ======================== Team and repository tags ======================== .. image:: https://governance.openstack.org/tc/badges/os-api-ref.svg :target: https://governance.openstack.org/tc/reference/tags/index.html .. Change things from this point on os-api-ref ========== Sphinx Extensions to support API reference sites in OpenStack This project is a collection of sphinx stanzas that assist in building an API Reference site for an OpenStack project in RST. RST is great for unstructured English, but displaying semi structured (and repetitive) data in tables is not its strength. This provides tooling to insert semi-structured data describing request and response parameters and status or error messages, and turn those into nice tables. The project also includes a set of styling (and javascript) that is expected to layer on top of a Sphinx theme base. This addition provides a nice set of collapsing sections for REST methods and javascript controls to expand / collapse all sections. Features -------- * Sphinx stanza ``rest_method`` describing the method and resource for a REST API call. Lets authors write simply and also gives readers a clean way to scan all methods then click a button to get more information about a method. * Sphinx stanza ``rest_parameters`` used to insert semi-structured data into the RST files describing the parameters users can send with the request. The stanza points to a structured YAML file, ``parameters.yaml``. * Sphinx stanza ``rest_status_code`` used to insert pointers to error or status codes returned by the service. Points to a structured YAML file, ``http_codes.yaml``. TODO ---- A list, in no particular order, of things we should do in this project. If you would like to contribute to any of these please show up in ``#openstack-dev`` on IRC and ask for ``sdague`` or ``mugsie`` to discuss or send an email to the openstack-discuss@lists.openstack.org list with [api] in the subject line. * Enhance documentation with more examples and best practices * Testing for the code * ``max_microversion`` parameter support - so that we automatically tag parameters that have been removed * Make a microversion selector, so that you can get a version of the api-ref that hides all microversion elements beyond your selected version (this one is going to be a bit of complex javascript), in progress. Potential ideas ~~~~~~~~~~~~~~~ These aren't even quite todos, but just ideas about things that might be useful. * ``.. literalinclude`` is good for API samples files to be included, but should we have more markup that includes the full ``REST /URL`` as well. Sphinx stanzas -------------- **rest_method**: Enter the REST method, such as GET, PUT, POST, DELETE, followed by the resource (not including an endpoint) for the call. For example:: .. rest_method:: PUT /v2/images/{image_id}/file **rest_parameters**: Enter a reference to a ``parameters.yaml`` file and indicate which parameter you want to document. For example:: .. rest_parameters:: images-parameters.yaml - Content-type: Content-Type-data - image_id: image_id-in-path Where the ``images-parameters.yaml`` file contains pointers named ``Content-type`` and ``image_id`` and descriptions for each. **rest_status_code**: Enter a reference to a ``http-status.yaml`` file and indicate which errors or status codes you want to document. You can also add a pointer to more precise descriptions for each code. For example:: .. rest_status_code:: success http-codes.yaml - 204 .. rest_status_code:: error http-codes.yaml - 400: informal - 401 - 403 - 404 - 409 - 410: image-data-410 - 413: image-data-413 - 415: image-data-415 - 500: informal - 503: image-data-503 * Free software: Apache license * Documentation: https://docs.openstack.org/os-api-ref/latest/ * Source: https://opendev.org/openstack/os-api-ref Platform: UNKNOWN Classifier: Environment :: OpenStack Classifier: Intended Audience :: Information Technology Classifier: Intended Audience :: System Administrators Classifier: License :: OSI Approved :: Apache Software License Classifier: Operating System :: POSIX :: Linux Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3.12 Classifier: Programming Language :: Python :: 3 :: Only Classifier: Programming Language :: Python :: Implementation :: CPython Requires-Python: >=3.9 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045155.0 os-api-ref-3.0.1/os_api_ref.egg-info/SOURCES.txt0000664000175000017500000000307200000000000021166 0ustar00zuulzuul00000000000000.coveragerc .mailmap .pre-commit-config.yaml .stestr.conf .zuul.yaml AUTHORS CONTRIBUTING.rst ChangeLog HACKING.rst LICENSE README.rst RELEASING.rst TESTS.rst requirements.txt setup.cfg setup.py test-requirements.txt tox.ini doc/requirements.txt doc/source/conf.py doc/source/contributing.rst doc/source/http-status.yaml doc/source/index.rst doc/source/installation.rst doc/source/usage.rst os_api_ref/__init__.py os_api_ref/http_codes.py os_api_ref.egg-info/PKG-INFO os_api_ref.egg-info/SOURCES.txt os_api_ref.egg-info/dependency_links.txt os_api_ref.egg-info/not-zip-safe os_api_ref.egg-info/pbr.json os_api_ref.egg-info/requires.txt os_api_ref.egg-info/top_level.txt os_api_ref/assets/api-site.css os_api_ref/assets/api-site.js os_api_ref/assets/combobox.js os_api_ref/assets/glyphicons-halflings-regular.ttf os_api_ref/assets/glyphicons-halflings-regular.woff os_api_ref/tests/__init__.py os_api_ref/tests/base.py os_api_ref/tests/test_basic_example.py os_api_ref/tests/test_microversions.py os_api_ref/tests/test_os_api_ref.py os_api_ref/tests/test_warnings.py os_api_ref/tests/examples/basic/conf.py os_api_ref/tests/examples/basic/index.rst os_api_ref/tests/examples/basic/parameters.yaml os_api_ref/tests/examples/basic/status.yaml os_api_ref/tests/examples/microversions/conf.py os_api_ref/tests/examples/microversions/index.rst os_api_ref/tests/examples/microversions/parameters.yaml os_api_ref/tests/examples/warnings/conf.py os_api_ref/tests/examples/warnings/empty_parameters_file.yaml os_api_ref/tests/examples/warnings/index.rst os_api_ref/tests/examples/warnings/parameters.yaml././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045155.0 os-api-ref-3.0.1/os_api_ref.egg-info/dependency_links.txt0000664000175000017500000000000100000000000023346 0ustar00zuulzuul00000000000000 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045155.0 os-api-ref-3.0.1/os_api_ref.egg-info/not-zip-safe0000664000175000017500000000000100000000000021526 0ustar00zuulzuul00000000000000 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045155.0 os-api-ref-3.0.1/os_api_ref.egg-info/pbr.json0000664000175000017500000000005600000000000020757 0ustar00zuulzuul00000000000000{"git_version": "62c2aba", "is_release": true}././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045155.0 os-api-ref-3.0.1/os_api_ref.egg-info/requires.txt0000664000175000017500000000011000000000000021670 0ustar00zuulzuul00000000000000PyYAML>=3.12 openstackdocstheme>=2.2.1 pbr!=2.1.0,>=2.0.0 sphinx>=4.0.0 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045155.0 os-api-ref-3.0.1/os_api_ref.egg-info/top_level.txt0000664000175000017500000000001300000000000022024 0ustar00zuulzuul00000000000000os_api_ref ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045126.0 os-api-ref-3.0.1/requirements.txt0000664000175000017500000000050100000000000016760 0ustar00zuulzuul00000000000000# The order of packages is significant, because pip processes them in the order # of appearance. Changing the order has an impact on the overall integration # process, which may cause wedges in the gate later. pbr!=2.1.0,>=2.0.0 # Apache-2.0 PyYAML>=3.12 # MIT sphinx>=4.0.0 # BSD openstackdocstheme>=2.2.1 # Apache-2.0 ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1732045156.0060813 os-api-ref-3.0.1/setup.cfg0000664000175000017500000000161600000000000015325 0ustar00zuulzuul00000000000000[metadata] name = os-api-ref summary = Sphinx Extensions to support API reference sites in OpenStack description_file = README.rst author = OpenStack author_email = openstack-discuss@lists.openstack.org home_page = https://docs.openstack.org/os-api-ref/latest/ python_requires = >=3.9 classifier = Environment :: OpenStack Intended Audience :: Information Technology Intended Audience :: System Administrators License :: OSI Approved :: Apache Software License Operating System :: POSIX :: Linux Programming Language :: Python Programming Language :: Python :: 3 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 Programming Language :: Python :: 3.11 Programming Language :: Python :: 3.12 Programming Language :: Python :: 3 :: Only Programming Language :: Python :: Implementation :: CPython [files] packages = os_api_ref [egg_info] tag_build = tag_date = 0 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045126.0 os-api-ref-3.0.1/setup.py0000664000175000017500000000200600000000000015210 0ustar00zuulzuul00000000000000# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. # # 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 FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT import setuptools # In python < 2.7.4, a lazy loading of package `pbr` will break # setuptools if some other modules registered functions in `atexit`. # solution from: http://bugs.python.org/issue15881#msg170215 try: import multiprocessing # noqa except ImportError: pass setuptools.setup( setup_requires=['pbr>=2.0.0'], pbr=True) ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045126.0 os-api-ref-3.0.1/test-requirements.txt0000664000175000017500000000103700000000000017742 0ustar00zuulzuul00000000000000# The order of packages is significant, because pip processes them in the order # of appearance. Changing the order has an impact on the overall integration # process, which may cause wedges in the gate later. hacking>=3.0.1,<3.1.0 # Apache-2.0 coverage!=4.4,>=4.0 # Apache-2.0 python-subunit>=1.0.0 # Apache-2.0/BSD testrepository>=0.0.18 # Apache-2.0/BSD testtools>=2.2.0 # MIT beautifulsoup4>=4.6.0 # MIT stestr>=2.0.0 # Apache-2.0 pre-commit>=2.6.0 # MIT # The minimum version requirement is specific to unit tests. sphinx>=7.2.0 # BSD ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1732045126.0 os-api-ref-3.0.1/tox.ini0000664000175000017500000000215700000000000015020 0ustar00zuulzuul00000000000000[tox] minversion = 3.1.1 envlist = py3,pep8,docs ignore_basepython_conflict = true skipsdist = true [testenv] basepython = python3 setenv = VIRTUAL_ENV={envdir} deps = -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master} -r{toxinidir}/requirements.txt -r{toxinidir}/test-requirements.txt commands = stestr run {posargs} [testenv:pep8] commands = pre-commit run -a [testenv:venv] commands = {posargs} [testenv:cover] setenv = {[testenv]setenv} PYTHON=coverage run --source nova --parallel-mode commands = coverage erase stestr run {posargs} coverage combine coverage html -d cover coverage report [testenv:docs] deps = -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master} -r{toxinidir}/doc/requirements.txt commands = sphinx-build -W -b html -d doc/build/doctrees doc/source doc/build/html [testenv:debug] commands = oslo_debug_helper {posargs} [flake8] # E123, E125 skipped as they are invalid PEP-8. show-source = true ignore = E123,E125,E129,W504 builtins = _ exclude=.venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,build