[arvados] created: 2.7.0-5360-g44f7408d23

git repository hosting git at public.arvados.org
Sat Nov 18 21:45:29 UTC 2023


        at  44f7408d23ccfbb51dbc06522302af5e4aa53da7 (commit)


commit 44f7408d23ccfbb51dbc06522302af5e4aa53da7
Author: Brett Smith <brett.smith at curii.com>
Date:   Sat Nov 18 16:41:04 2023 -0500

    21132: Annotate API methods as returning a request object
    
    This is a factual correction. Before this, it looked like the API
    methods communicated with the API server and returned a response
    directly, which is not true.
    
    Unfortunately pdoc doesn't render the documentation for the
    ArvadosAPIRequest.execute override. That's frustrating. I looked for
    ways to coerce this but didn't find any. Hopefully the class docstring
    gives users enough information about what they need to do. pydoc renders
    it as expected, so I still think it's worth keeping.
    
    Arvados-DCO-1.1-Signed-off-by: Brett Smith <brett.smith at curii.com>

diff --git a/sdk/python/discovery2pydoc.py b/sdk/python/discovery2pydoc.py
index e37784e06d..4fe050baf0 100755
--- a/sdk/python/discovery2pydoc.py
+++ b/sdk/python/discovery2pydoc.py
@@ -96,15 +96,51 @@ to list the specific keys you need. Refer to the API documentation for details.
 
 _MODULE_PRELUDE = '''
 import googleapiclient.discovery
+import googleapiclient.http
+import httplib2
 import sys
-from typing import Any, Dict, List
+from typing import Any, Dict, Generic, List, Optional, TypeVar
 if sys.version_info < (3, 8):
     from typing_extensions import TypedDict
 else:
     from typing import TypedDict
+
+# ST represents an API response type
+ST = TypeVar('ST', bound=TypedDict)
+'''
+_REQUEST_CLASS = '''
+class ArvadosAPIRequest(googleapiclient.http.HttpRequest, Generic[ST]):
+    """Generic API request object
+
+    When you call an API method in the Arvados Python SDK, it returns a
+    request object. You usually call `execute()` on this object to submit the
+    request to your Arvados API server and retrieve the response. `execute()`
+    will return the type of object annotated in the subscript of
+    `ArvadosAPIRequest`.
+    """
+
+    def execute(self, http: Optional[httplib2.Http]=None, num_retries: int=0) -> ST:
+        """Execute this request and return the response
+
+        Arguments:
+
+        * http: httplib2.Http | None --- The HTTP client object to use to
+          execute the request. If not specified, uses the HTTP client object
+          created with the API client object.
+
+        * num_retries: int --- The maximum number of times to retry this
+          request if the server returns a retryable failure. The API client
+          object also has a maximum number of retries specified when it is
+          instantiated (see `arvados.api.api_client`). This request is run
+          with the larger of that number and this argument. Default 0.
+        """
+
 '''
 
-_TYPE_MAP = {
+# Annotation represents a valid Python type annotation. Future development
+# could expand this to include other valid types like `type`.
+Annotation = str
+_TYPE_MAP: Mapping[str, Annotation] = {
     # Map the API's JavaScript-based type names to Python annotations.
     # Some of these may disappear after Arvados issue #19795 is fixed.
     'Array': 'List',
@@ -198,9 +234,15 @@ class Parameter(inspect.Parameter):
 
 
 class Method:
-    def __init__(self, name: str, spec: Mapping[str, Any]) -> None:
+    def __init__(
+            self,
+            name: str,
+            spec: Mapping[str, Any],
+            annotate: Callable[[Annotation], Annotation]=str,
+    ) -> None:
         self.name = name
         self._spec = spec
+        self._annotate = annotate
         self._required_params = []
         self._optional_params = []
         for param_name, param_spec in spec['parameters'].items():
@@ -223,6 +265,7 @@ class Method:
             returns = get_type_annotation(self._spec['response']['$ref'])
         except KeyError:
             returns = 'Dict[str, Any]'
+        returns = self._annotate(returns)
         return inspect.Signature(parameters, return_annotation=returns)
 
     def doc(self, doc_slice: slice=slice(None)) -> str:
@@ -286,7 +329,7 @@ def document_resource(name: str, spec: Mapping[str, Any]) -> str:
     if class_name in _DEPRECATED_RESOURCES:
         docstring += _DEPRECATED_NOTICE
     methods = [
-        Method(key, meth_spec)
+        Method(key, meth_spec, 'ArvadosAPIRequest[{}]'.format)
         for key, meth_spec in spec['methods'].items()
         if key not in _ALIASED_METHODS
     ]
@@ -355,7 +398,11 @@ def main(arglist: Optional[Sequence[str]]=None) -> int:
     for name, resource_spec in resources:
         print(document_resource(name, resource_spec), file=args.out_file)
 
-    print('''class ArvadosAPIClient(googleapiclient.discovery.Resource):''', file=args.out_file)
+    print(
+        _REQUEST_CLASS,
+        '''class ArvadosAPIClient(googleapiclient.discovery.Resource):''',
+        sep='\n', file=args.out_file,
+    )
     for name, _ in resources:
         class_name = classify_name(name)
         docstring = f"Return an instance of `{class_name}` to call methods via this client"

commit 4571ee1ebc16366997b28561e85e07717da62be9
Author: Brett Smith <brett.smith at curii.com>
Date:   Sat Nov 18 12:22:54 2023 -0500

    21132: Note ArvadosAPIClient is a Resource
    
    The real impact of this change is marginal, but it establishes a pattern
    for documenting request objects, which will be more substantial.
    
    Arvados-DCO-1.1-Signed-off-by: Brett Smith <brett.smith at curii.com>

diff --git a/sdk/python/discovery2pydoc.py b/sdk/python/discovery2pydoc.py
index d2f206c80f..e37784e06d 100755
--- a/sdk/python/discovery2pydoc.py
+++ b/sdk/python/discovery2pydoc.py
@@ -95,6 +95,7 @@ to list the specific keys you need. Refer to the API documentation for details.
 '''
 
 _MODULE_PRELUDE = '''
+import googleapiclient.discovery
 import sys
 from typing import Any, Dict, List
 if sys.version_info < (3, 8):
@@ -354,7 +355,7 @@ def main(arglist: Optional[Sequence[str]]=None) -> int:
     for name, resource_spec in resources:
         print(document_resource(name, resource_spec), file=args.out_file)
 
-    print('''class ArvadosAPIClient:''', file=args.out_file)
+    print('''class ArvadosAPIClient(googleapiclient.discovery.Resource):''', file=args.out_file)
     for name, _ in resources:
         class_name = classify_name(name)
         docstring = f"Return an instance of `{class_name}` to call methods via this client"

commit 6f481c9e2379cc470d2fb392b6fd495fc7cc8f21
Author: Brett Smith <brett.smith at curii.com>
Date:   Sat Nov 18 10:18:22 2023 -0500

    21136: Use typing generics for builtins in api_resources
    
    The immediate problem this solves is that using `list` unqualified as an
    annotation causes pdoc to resolve it as the current class' `list`
    method, which is not correct.
    
    We could also specify `builtins.list`, but since it doesn't support
    subscripting in Python 3.8, that generates a lot of noisy warnings right
    now. So this solution is better for now, and we'll probably migrate to
    `builtins.list` in the future.
    
    Arvados-DCO-1.1-Signed-off-by: Brett Smith <brett.smith at curii.com>

diff --git a/sdk/python/discovery2pydoc.py b/sdk/python/discovery2pydoc.py
index 6ca3aafeb6..d2f206c80f 100755
--- a/sdk/python/discovery2pydoc.py
+++ b/sdk/python/discovery2pydoc.py
@@ -96,24 +96,24 @@ to list the specific keys you need. Refer to the API documentation for details.
 
 _MODULE_PRELUDE = '''
 import sys
+from typing import Any, Dict, List
 if sys.version_info < (3, 8):
-    from typing import Any
     from typing_extensions import TypedDict
 else:
-    from typing import Any, TypedDict
+    from typing import TypedDict
 '''
 
 _TYPE_MAP = {
     # Map the API's JavaScript-based type names to Python annotations.
     # Some of these may disappear after Arvados issue #19795 is fixed.
-    'Array': 'list',
-    'array': 'list',
+    'Array': 'List',
+    'array': 'List',
     'boolean': 'bool',
     # datetime fields are strings in ISO 8601 format.
     'datetime': 'str',
-    'Hash': 'dict[str, Any]',
+    'Hash': 'Dict[str, Any]',
     'integer': 'int',
-    'object': 'dict[str, Any]',
+    'object': 'Dict[str, Any]',
     'string': 'str',
     'text': 'str',
 }
@@ -221,7 +221,7 @@ class Method:
         try:
             returns = get_type_annotation(self._spec['response']['$ref'])
         except KeyError:
-            returns = 'dict[str, Any]'
+            returns = 'Dict[str, Any]'
         return inspect.Signature(parameters, return_annotation=returns)
 
     def doc(self, doc_slice: slice=slice(None)) -> str:

-----------------------------------------------------------------------


hooks/post-receive
-- 




More information about the arvados-commits mailing list