Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented Nested Docs. #3597

Merged
merged 10 commits into from
Feb 28, 2023
4 changes: 3 additions & 1 deletion boto3/docs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ def generate_docs(root_dir, session):
os.makedirs(services_doc_path)

for service_name in session.get_available_services():
docs = ServiceDocumenter(service_name, session).document_service()
docs = ServiceDocumenter(
service_name, session, services_doc_path
).document_service()
service_doc_path = os.path.join(
services_doc_path, service_name + '.rst'
)
Expand Down
20 changes: 17 additions & 3 deletions boto3/docs/action.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,18 @@
# 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

from botocore import xform_name
from botocore.docs.bcdoc.restdoc import DocumentStructure
from botocore.docs.method import (
document_custom_method,
document_model_driven_method,
)
from botocore.model import OperationModel
from botocore.utils import get_service_module_name

from boto3.docs.base import BaseDocumenter
from boto3.docs.base import NestedDocumenter
from boto3.docs.method import document_model_driven_resource_method
from boto3.docs.utils import (
add_resource_type_overview,
Expand All @@ -27,7 +30,7 @@
)


class ActionDocumenter(BaseDocumenter):
class ActionDocumenter(NestedDocumenter):
def document_actions(self, section):
modeled_actions_list = self._resource_model.actions
modeled_actions = {}
Expand All @@ -49,7 +52,10 @@ def document_actions(self, section):
)

for action_name in sorted(resource_actions):
action_section = section.add_new_section(action_name)
# Create a new DocumentStructure for each action and add contents.
action_doc = DocumentStructure(action_name, target='html')
action_doc.add_title_section(action_name)
action_section = action_doc.add_new_section(action_name)
if action_name in ['load', 'reload'] and self._resource_model.load:
document_load_reload_action(
section=action_section,
Expand All @@ -71,6 +77,14 @@ def document_actions(self, section):
document_custom_method(
action_section, action_name, resource_actions[action_name]
)
# Write actions in individual/nested files.
# Path: <root>/reference/services/<service>/<resource_name>/<action_name>.rst
actions_dir_path = os.path.join(
self._root_docs_path,
f'{self._service_name}',
f'{self._resource_sub_path}',
)
action_doc.write_to_file(actions_dir_path, action_name)


def document_action(
Expand Down
9 changes: 9 additions & 0 deletions boto3/docs/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,12 @@ def __init__(self, resource):
@property
def class_name(self):
return f'{self._service_docs_name}.{self._resource_name}'


class NestedDocumenter(BaseDocumenter):
def __init__(self, resource, root_docs_path):
super().__init__(resource)
self._root_docs_path = root_docs_path
self._resource_sub_path = self._resource_name.lower()
if self._resource_name == self._service_name:
self._resource_sub_path = 'service-resource'
23 changes: 20 additions & 3 deletions boto3/docs/collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,22 @@
# 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

from botocore import xform_name
from botocore.docs.bcdoc.restdoc import DocumentStructure
from botocore.docs.method import get_instance_public_methods
from botocore.docs.utils import DocumentedShape

from boto3.docs.base import BaseDocumenter
from boto3.docs.base import NestedDocumenter
from boto3.docs.method import document_model_driven_resource_method
from boto3.docs.utils import (
add_resource_type_overview,
get_resource_ignore_params,
)


class CollectionDocumenter(BaseDocumenter):
class CollectionDocumenter(NestedDocumenter):
def document_collections(self, section):
collections = self._resource.meta.resource_model.collections
collections_list = []
Expand All @@ -37,10 +40,24 @@ def document_collections(self, section):
)
self.member_map['collections'] = collections_list
for collection in collections:
collection_section = section.add_new_section(collection.name)
collections_list.append(collection.name)
# Create a new DocumentStructure for each collection and add contents.
collection_doc = DocumentStructure(collection.name, target='html')
collection_doc.add_title_section(collection.name)
collection_section = collection_doc.add_new_section(
collection.name
)
self._document_collection(collection_section, collection)

# Write collections in individual/nested files.
# Path: <root>/reference/services/<service>/<resource_name>/<collection_name>.rst
collections_dir_path = os.path.join(
self._root_docs_path,
f'{self._service_name}',
f'{self._resource_sub_path}',
)
collection_doc.write_to_file(collections_dir_path, collection.name)

def _document_collection(self, section, collection):
methods = get_instance_public_methods(
getattr(self._resource, collection.name)
Expand Down
125 changes: 94 additions & 31 deletions boto3/docs/resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@
# 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

from botocore import xform_name
from botocore.docs.bcdoc.restdoc import DocumentStructure
from botocore.docs.utils import get_official_service_name

from boto3.docs.action import ActionDocumenter
Expand All @@ -32,22 +35,25 @@


class ResourceDocumenter(BaseDocumenter):
def __init__(self, resource, botocore_session):
def __init__(self, resource, botocore_session, root_docs_path):
super().__init__(resource)
self._botocore_session = botocore_session
self._root_docs_path = root_docs_path
self._resource_sub_path = self._resource_name.lower()
if self._resource_name == self._service_name:
self._resource_sub_path = 'service-resource'

def document_resource(self, section):
self._add_title(section)
self._add_resource_note(section)
self._add_intro(section)
overview_section = section.add_new_section('member-overview')
self._add_identifiers(section)
self._add_attributes(section)
self._add_references(section)
self._add_actions(section)
self._add_sub_resources(section)
self._add_collections(section)
self._add_waiters(section)
self._add_overview_of_members(overview_section)

def _add_title(self, section):
section.style.h2(self._resource_name)
Expand All @@ -60,23 +66,27 @@ def _add_intro(self, section):

# Write out the class signature.
class_args = get_identifier_args_for_signature(identifier_names)
section.style.start_sphinx_py_class(
start_class = section.add_new_section('start_class')
start_class.style.start_sphinx_py_class(
class_name=f'{self.class_name}({class_args})'
)

# Add as short description about the resource
description_section = section.add_new_section('description')
description_section = start_class.add_new_section('description')
self._add_description(description_section)

# Add an example of how to instantiate the resource
example_section = section.add_new_section('example')
example_section = start_class.add_new_section('example')
self._add_example(example_section, identifier_names)

# Add the description for the parameters to instantiate the
# resource.
param_section = section.add_new_section('params')
param_section = start_class.add_new_section('params')
self._add_params_description(param_section, identifier_names)

end_class = section.add_new_section('end_class')
end_class.style.end_sphinx_py_class()

def _add_description(self, section):
official_service_name = get_official_service_name(self._service_model)
section.write(
Expand Down Expand Up @@ -118,23 +128,15 @@ def _add_params_description(self, section, identifier_names):
section.write(f':param {identifier_name}: {description}')
section.style.new_line()

def _add_overview_of_members(self, section):
for resource_member_type in self.member_map:
section.style.new_line()
section.write(
f'These are the resource\'s available {resource_member_type}:'
)
section.style.new_line()
for member in self.member_map[resource_member_type]:
if resource_member_type in (
'attributes',
'collections',
'identifiers',
'references',
):
section.style.li(f':py:attr:`{member}`')
else:
section.style.li(f':py:meth:`{member}()`')
def _add_overview_of_member_type(self, section, resource_member_type):
section.style.new_line()
section.write(
f'These are the resource\'s available {resource_member_type}:'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit; we can fix this in a follow up, but I think this is supposed to be "resources" plural rather than possessive?

)
section.style.new_line()
section.style.toctree()
for member in self.member_map[resource_member_type]:
section.style.tocitem(f'{member}')

def _add_identifiers(self, section):
identifiers = self._resource.meta.resource_model.identifiers
Expand All @@ -152,13 +154,29 @@ def _add_identifiers(self, section):
intro_link='identifiers_attributes_intro',
)
for identifier in identifiers:
identifier_section = section.add_new_section(identifier.name)
member_list.append(identifier.name)
# Create a new DocumentStructure for each identifier and add contents.
identifier_doc = DocumentStructure(identifier.name, target='html')
identifier_doc.add_title_section(identifier.name)
identifier_section = identifier_doc.add_new_section(
identifier.name
)
document_identifier(
section=identifier_section,
resource_name=self._resource_name,
identifier_model=identifier,
)
# Write identifiers in individual/nested files.
# Path: <root>/reference/services/<service>/<resource_name>/<identifier_name>.rst
identifiers_dir_path = os.path.join(
self._root_docs_path,
f'{self._service_name}',
f'{self._resource_sub_path}',
)
identifier_doc.write_to_file(identifiers_dir_path, identifier.name)

if identifiers:
self._add_overview_of_member_type(section, 'identifiers')

def _add_attributes(self, section):
service_model = self._resource.meta.client.meta.service_model
Expand Down Expand Up @@ -187,8 +205,11 @@ def _add_attributes(self, section):
self.member_map['attributes'] = attribute_list
for attr_name in sorted(attributes):
_, attr_shape = attributes[attr_name]
attribute_section = section.add_new_section(attr_name)
attribute_list.append(attr_name)
# Create a new DocumentStructure for each attribute and add contents.
attribute_doc = DocumentStructure(attr_name, target='html')
attribute_doc.add_title_section(attr_name)
attribute_section = attribute_doc.add_new_section(attr_name)
document_attribute(
section=attribute_section,
service_name=self._service_name,
Expand All @@ -197,6 +218,16 @@ def _add_attributes(self, section):
event_emitter=self._resource.meta.client.meta.events,
attr_model=attr_shape,
)
# Write attributes in individual/nested files.
# Path: <root>/reference/services/<service>/<resource_name>/<attribute_name>.rst
attributes_dir_path = os.path.join(
self._root_docs_path,
f'{self._service_name}',
f'{self._resource_sub_path}',
)
attribute_doc.write_to_file(attributes_dir_path, attr_name)
if attributes:
self._add_overview_of_member_type(section, 'attributes')

def _add_references(self, section):
section = section.add_new_section('references')
Expand All @@ -213,36 +244,57 @@ def _add_references(self, section):
intro_link='references_intro',
)
self.member_map['references'] = reference_list
self._add_overview_of_member_type(section, 'references')
for reference in references:
reference_section = section.add_new_section(reference.name)
reference_list.append(reference.name)
# Create a new DocumentStructure for each reference and add contents.
reference_doc = DocumentStructure(reference.name, target='html')
reference_doc.add_title_section(reference.name)
reference_section = reference_doc.add_new_section(reference.name)
document_reference(
section=reference_section, reference_model=reference
)
# Write references in individual/nested files.
# Path: <root>/reference/services/<service>/<resource_name>/<reference_name>.rst
references_dir_path = os.path.join(
self._root_docs_path,
f'{self._service_name}',
f'{self._resource_sub_path}',
)
reference_doc.write_to_file(references_dir_path, reference.name)
if references:
self._add_overview_of_member_type(section, 'references')

def _add_actions(self, section):
section = section.add_new_section('actions')
actions = self._resource.meta.resource_model.actions
if actions:
documenter = ActionDocumenter(self._resource)
documenter = ActionDocumenter(self._resource, self._root_docs_path)
documenter.member_map = self.member_map
documenter.document_actions(section)
self._add_overview_of_member_type(section, 'actions')

def _add_sub_resources(self, section):
section = section.add_new_section('sub-resources')
sub_resources = self._resource.meta.resource_model.subresources
if sub_resources:
documenter = SubResourceDocumenter(self._resource)
documenter = SubResourceDocumenter(
self._resource, self._root_docs_path
)
documenter.member_map = self.member_map
documenter.document_sub_resources(section)
self._add_overview_of_member_type(section, 'sub-resources')

def _add_collections(self, section):
section = section.add_new_section('collections')
collections = self._resource.meta.resource_model.collections
if collections:
documenter = CollectionDocumenter(self._resource)
documenter = CollectionDocumenter(
self._resource, self._root_docs_path
)
documenter.member_map = self.member_map
documenter.document_collections(section)
self._add_overview_of_member_type(section, 'collections')

def _add_waiters(self, section):
section = section.add_new_section('waiters')
Expand All @@ -252,10 +304,21 @@ def _add_waiters(self, section):
self._service_name
)
documenter = WaiterResourceDocumenter(
self._resource, service_waiter_model
self._resource, service_waiter_model, self._root_docs_path
)
documenter.member_map = self.member_map
documenter.document_resource_waiters(section)
self._add_overview_of_member_type(section, 'waiters')

def _add_resource_note(self, section):
section = section.add_new_section('feature-freeze')
section.style.start_note()
section.write(
"Before using anything on this page, please refer to the resources "
":doc:`user guide <../../../../guide/resources>` for the most recent "
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit; can we do this as an absolute path relative than relative to the resource page?

"guidance on using resources."
)
section.style.end_note()


class ServiceResourceDocumenter(ResourceDocumenter):
Expand Down
Loading