aboutsummaryrefslogtreecommitdiff
path: root/.venv/lib/python3.12/site-packages/botocore/docs/bcdoc/docstringparser.py
diff options
context:
space:
mode:
authorS. Solomon Darnell2025-03-28 21:52:21 -0500
committerS. Solomon Darnell2025-03-28 21:52:21 -0500
commit4a52a71956a8d46fcb7294ac71734504bb09bcc2 (patch)
treeee3dc5af3b6313e921cd920906356f5d4febc4ed /.venv/lib/python3.12/site-packages/botocore/docs/bcdoc/docstringparser.py
parentcc961e04ba734dd72309fb548a2f97d67d578813 (diff)
downloadgn-ai-master.tar.gz
two version of R2R are hereHEADmaster
Diffstat (limited to '.venv/lib/python3.12/site-packages/botocore/docs/bcdoc/docstringparser.py')
-rw-r--r--.venv/lib/python3.12/site-packages/botocore/docs/bcdoc/docstringparser.py315
1 files changed, 315 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/botocore/docs/bcdoc/docstringparser.py b/.venv/lib/python3.12/site-packages/botocore/docs/bcdoc/docstringparser.py
new file mode 100644
index 00000000..ebe16ba5
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/botocore/docs/bcdoc/docstringparser.py
@@ -0,0 +1,315 @@
+# Copyright 2012-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"). You
+# may not use this file except in compliance with the License. A copy of
+# the License is located at
+#
+# http://aws.amazon.com/apache2.0/
+#
+# or in the "license" file accompanying this file. This file 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 html.parser import HTMLParser
+from itertools import zip_longest
+
+PRIORITY_PARENT_TAGS = ('code', 'a')
+OMIT_NESTED_TAGS = ('span', 'i', 'code', 'a')
+OMIT_SELF_TAGS = ('i', 'b')
+HTML_BLOCK_DISPLAY_TAGS = ('p', 'note', 'ul', 'li')
+
+
+class DocStringParser(HTMLParser):
+ """
+ A simple HTML parser. Focused on converting the subset of HTML
+ that appears in the documentation strings of the JSON models into
+ simple ReST format.
+ """
+
+ def __init__(self, doc):
+ self.tree = None
+ self.doc = doc
+ super().__init__()
+
+ def reset(self):
+ HTMLParser.reset(self)
+ self.tree = HTMLTree(self.doc)
+
+ def feed(self, data):
+ super().feed(data)
+ self.tree.write()
+ self.tree = HTMLTree(self.doc)
+
+ def close(self):
+ super().close()
+ # Write if there is anything remaining.
+ self.tree.write()
+ self.tree = HTMLTree(self.doc)
+
+ def handle_starttag(self, tag, attrs):
+ self.tree.add_tag(tag, attrs=attrs)
+
+ def handle_endtag(self, tag):
+ self.tree.add_tag(tag, is_start=False)
+
+ def handle_data(self, data):
+ self.tree.add_data(data)
+
+
+class HTMLTree:
+ """
+ A tree which handles HTML nodes. Designed to work with a python HTML parser,
+ meaning that the current_node will be the most recently opened tag. When
+ a tag is closed, the current_node moves up to the parent node.
+ """
+
+ def __init__(self, doc):
+ self.doc = doc
+ self.head = StemNode()
+ self.current_node = self.head
+ self.unhandled_tags = []
+
+ def add_tag(self, tag, attrs=None, is_start=True):
+ if not self._doc_has_handler(tag, is_start):
+ self.unhandled_tags.append(tag)
+ return
+
+ if is_start:
+ node = TagNode(tag, attrs)
+ self.current_node.add_child(node)
+ self.current_node = node
+ else:
+ self.current_node = self.current_node.parent
+
+ def _doc_has_handler(self, tag, is_start):
+ if is_start:
+ handler_name = f'start_{tag}'
+ else:
+ handler_name = f'end_{tag}'
+
+ return hasattr(self.doc.style, handler_name)
+
+ def add_data(self, data):
+ self.current_node.add_child(DataNode(data))
+
+ def write(self):
+ self.head.write(self.doc)
+
+
+class Node:
+ def __init__(self, parent=None):
+ self.parent = parent
+
+ def write(self, doc):
+ raise NotImplementedError
+
+
+class StemNode(Node):
+ def __init__(self, parent=None):
+ super().__init__(parent)
+ self.children = []
+
+ def add_child(self, child):
+ child.parent = self
+ self.children.append(child)
+
+ def write(self, doc):
+ self.collapse_whitespace()
+ self._write_children(doc)
+
+ def _write_children(self, doc):
+ for child, next_child in zip_longest(self.children, self.children[1:]):
+ if isinstance(child, TagNode) and next_child is not None:
+ child.write(doc, next_child)
+ else:
+ child.write(doc)
+
+ def is_whitespace(self):
+ return all(child.is_whitespace() for child in self.children)
+
+ def startswith_whitespace(self):
+ return self.children and self.children[0].startswith_whitespace()
+
+ def endswith_whitespace(self):
+ return self.children and self.children[-1].endswith_whitespace()
+
+ def lstrip(self):
+ while self.children and self.children[0].is_whitespace():
+ self.children = self.children[1:]
+ if self.children:
+ self.children[0].lstrip()
+
+ def rstrip(self):
+ while self.children and self.children[-1].is_whitespace():
+ self.children = self.children[:-1]
+ if self.children:
+ self.children[-1].rstrip()
+
+ def collapse_whitespace(self):
+ """Remove collapsible white-space from HTML.
+
+ HTML in docstrings often contains extraneous white-space around tags,
+ for readability. Browsers would collapse this white-space before
+ rendering. If not removed before conversion to RST where white-space is
+ part of the syntax, for example for indentation, it can result in
+ incorrect output.
+ """
+ self.lstrip()
+ self.rstrip()
+ for child in self.children:
+ child.collapse_whitespace()
+
+
+class TagNode(StemNode):
+ """
+ A generic Tag node. It will verify that handlers exist before writing.
+ """
+
+ def __init__(self, tag, attrs=None, parent=None):
+ super().__init__(parent)
+ self.attrs = attrs
+ self.tag = tag
+
+ def _has_nested_tags(self):
+ # Returns True if any children are TagNodes and False otherwise.
+ return any(isinstance(child, TagNode) for child in self.children)
+
+ def write(self, doc, next_child=None):
+ prioritize_nested_tags = (
+ self.tag in OMIT_SELF_TAGS and self._has_nested_tags()
+ )
+ prioritize_parent_tag = (
+ isinstance(self.parent, TagNode)
+ and self.parent.tag in PRIORITY_PARENT_TAGS
+ and self.tag in OMIT_NESTED_TAGS
+ )
+ if prioritize_nested_tags or prioritize_parent_tag:
+ self._write_children(doc)
+ return
+
+ self._write_start(doc)
+ self._write_children(doc)
+ self._write_end(doc, next_child)
+
+ def collapse_whitespace(self):
+ """Remove collapsible white-space.
+
+ All tags collapse internal whitespace. Block-display HTML tags also
+ strip all leading and trailing whitespace.
+
+ Approximately follows the specification used in browsers:
+ https://www.w3.org/TR/css-text-3/#white-space-rules
+ https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Whitespace
+ """
+ if self.tag in HTML_BLOCK_DISPLAY_TAGS:
+ self.lstrip()
+ self.rstrip()
+ # Collapse whitespace in situations like ``</b> <i> foo</i>`` into
+ # ``</b><i> foo</i>``.
+ for prev, cur in zip(self.children[:-1], self.children[1:]):
+ if (
+ isinstance(prev, DataNode)
+ and prev.endswith_whitespace()
+ and cur.startswith_whitespace()
+ ):
+ cur.lstrip()
+ # Same logic, but for situations like ``<b>bar </b> <i>``:
+ for cur, nxt in zip(self.children[:-1], self.children[1:]):
+ if (
+ isinstance(nxt, DataNode)
+ and cur.endswith_whitespace()
+ and nxt.startswith_whitespace()
+ ):
+ cur.rstrip()
+ # Recurse into children
+ for child in self.children:
+ child.collapse_whitespace()
+
+ def _write_start(self, doc):
+ handler_name = f'start_{self.tag}'
+ if hasattr(doc.style, handler_name):
+ getattr(doc.style, handler_name)(self.attrs)
+
+ def _write_end(self, doc, next_child):
+ handler_name = f'end_{self.tag}'
+ if hasattr(doc.style, handler_name):
+ if handler_name == 'end_a':
+ # We use lookahead to determine if a space is needed after a link node
+ getattr(doc.style, handler_name)(next_child)
+ else:
+ getattr(doc.style, handler_name)()
+
+
+class DataNode(Node):
+ """
+ A Node that contains only string data.
+ """
+
+ def __init__(self, data, parent=None):
+ super().__init__(parent)
+ if not isinstance(data, str):
+ raise ValueError(f"Expecting string type, {type(data)} given.")
+ self._leading_whitespace = ''
+ self._trailing_whitespace = ''
+ self._stripped_data = ''
+ if data == '':
+ return
+ if data.isspace():
+ self._trailing_whitespace = data
+ return
+ first_non_space = next(
+ idx for idx, ch in enumerate(data) if not ch.isspace()
+ )
+ last_non_space = len(data) - next(
+ idx for idx, ch in enumerate(reversed(data)) if not ch.isspace()
+ )
+ self._leading_whitespace = data[:first_non_space]
+ self._trailing_whitespace = data[last_non_space:]
+ self._stripped_data = data[first_non_space:last_non_space]
+
+ @property
+ def data(self):
+ return (
+ f'{self._leading_whitespace}{self._stripped_data}'
+ f'{self._trailing_whitespace}'
+ )
+
+ def is_whitespace(self):
+ return self._stripped_data == '' and (
+ self._leading_whitespace != '' or self._trailing_whitespace != ''
+ )
+
+ def startswith_whitespace(self):
+ return self._leading_whitespace != '' or (
+ self._stripped_data == '' and self._trailing_whitespace != ''
+ )
+
+ def endswith_whitespace(self):
+ return self._trailing_whitespace != '' or (
+ self._stripped_data == '' and self._leading_whitespace != ''
+ )
+
+ def lstrip(self):
+ if self._leading_whitespace != '':
+ self._leading_whitespace = ''
+ elif self._stripped_data == '':
+ self.rstrip()
+
+ def rstrip(self):
+ if self._trailing_whitespace != '':
+ self._trailing_whitespace = ''
+ elif self._stripped_data == '':
+ self.lstrip()
+
+ def collapse_whitespace(self):
+ """Noop, ``DataNode.write`` always collapses whitespace"""
+ return
+
+ def write(self, doc):
+ words = doc.translate_words(self._stripped_data.split())
+ str_data = (
+ f'{self._leading_whitespace}{" ".join(words)}'
+ f'{self._trailing_whitespace}'
+ )
+ if str_data != '':
+ doc.handle_data(str_data)