1# Copyright 2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License"). You
4# may not use this file except in compliance with the License. A copy of
5# the License is located at
6#
7# http://aws.amazon.com/apache2.0/
8#
9# or in the "license" file accompanying this file. This file is
10# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11# ANY KIND, either express or implied. See the License for the specific
12# language governing permissions and limitations under the License.
13from botocore.docs.method import document_model_driven_method
14from botocore.docs.waiter import document_wait_method
15from botocore.docs.paginator import document_paginate_method
16from botocore.docs.bcdoc.restdoc import DocumentStructure
17
18
19class LazyLoadedDocstring(str):
20    """Used for lazily loading docstrings
21
22    You can instantiate this class and assign it to a __doc__ value.
23    The docstring will not be generated till accessed via __doc__ or
24    help(). Note that all docstring classes **must** subclass from
25    this class. It cannot be used directly as a docstring.
26    """
27    def __init__(self, *args, **kwargs):
28        """
29        The args and kwargs are the same as the underlying document
30        generation function. These just get proxied to the underlying
31        function.
32        """
33        super(LazyLoadedDocstring, self).__init__()
34        self._gen_args = args
35        self._gen_kwargs = kwargs
36        self._docstring = None
37
38    def __new__(cls, *args, **kwargs):
39        # Needed in order to sub class from str with args and kwargs
40        return super(LazyLoadedDocstring, cls).__new__(cls)
41
42    def _write_docstring(self, *args, **kwargs):
43        raise NotImplementedError(
44            '_write_docstring is not implemented. Please subclass from '
45            'this class and provide your own _write_docstring method'
46        )
47
48    def expandtabs(self, tabsize=8):
49        """Expands tabs to spaces
50
51        So this is a big hack in order to get lazy loaded docstring work
52        for the ``help()``. In the ``help()`` function, ``pydoc`` and
53        ``inspect`` are used. At some point the ``inspect.cleandoc``
54        method is called. To clean the docs ``expandtabs`` is called
55        and that is where we override the method to generate and return the
56        docstrings.
57        """
58        if self._docstring is None:
59            self._generate()
60        return self._docstring.expandtabs(tabsize)
61
62    def __str__(self):
63        return self._generate()
64
65    # __doc__ of target will use either __repr__ or __str__ of this class.
66    __repr__ = __str__
67
68    def _generate(self):
69        # Generate the docstring if it is not already cached.
70        if self._docstring is None:
71            self._docstring = self._create_docstring()
72        return self._docstring
73
74    def _create_docstring(self):
75        docstring_structure = DocumentStructure('docstring', target='html')
76        # Call the document method function with the args and kwargs
77        # passed to the class.
78        self._write_docstring(
79            docstring_structure, *self._gen_args,
80            **self._gen_kwargs)
81        return docstring_structure.flush_structure().decode('utf-8')
82
83
84class ClientMethodDocstring(LazyLoadedDocstring):
85    def _write_docstring(self, *args, **kwargs):
86        document_model_driven_method(*args, **kwargs)
87
88
89class WaiterDocstring(LazyLoadedDocstring):
90    def _write_docstring(self, *args, **kwargs):
91        document_wait_method(*args, **kwargs)
92
93
94class PaginatorDocstring(LazyLoadedDocstring):
95    def _write_docstring(self, *args, **kwargs):
96        document_paginate_method(*args, **kwargs)
97