This is an automated email from the ASF dual-hosted git repository.

rawlin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficcontrol.git


The following commit(s) were added to refs/heads/master by this push:
     new dd28e74  Added an implementation of the to-access functions to Python 
client package (#3266)
dd28e74 is described below

commit dd28e749f8c2ec53152433f38dbf0dc6728dd43c
Author: ocket8888 <[email protected]>
AuthorDate: Thu Apr 4 12:59:39 2019 -0600

    Added an implementation of the to-access functions to Python client package 
(#3266)
    
    * Added an implementation of the to-access functions to Python client 
package
    
    * proper exit codes
    
    * function argument formatting is now like <arg>: <type> = <default>
    
    * Documented exit codes and switched to snake_case for exposed objects
    
    * removed unused and/or commented-out code
    
    * Reduced all scripts to stubs that call common functionality
    
    * Command line flags `_` -> `-`, fixed missing imports, and `TO_URL` now 
parsed via urllib
    
    * Fixed urlparse netloc hack for determining hostname
---
 docs/source/tools/index.rst                        |   1 +
 docs/source/tools/{index.rst => toaccess.rst}      |  19 +-
 traffic_control/clients/python/setup.py            |  11 +
 .../clients/python/to_access/__init__.py           | 454 +++++++++++++++++++++
 .../clients/python/trafficops/restapi.py           |  88 +++-
 5 files changed, 557 insertions(+), 16 deletions(-)

diff --git a/docs/source/tools/index.rst b/docs/source/tools/index.rst
index c834ab7..f747d1b 100644
--- a/docs/source/tools/index.rst
+++ b/docs/source/tools/index.rst
@@ -26,3 +26,4 @@ This is a living list of tools used to interact with, test, 
and develop for the
        compare
        python_client
        traffic_vault_util
+       toaccess
diff --git a/docs/source/tools/index.rst b/docs/source/tools/toaccess.rst
similarity index 73%
copy from docs/source/tools/index.rst
copy to docs/source/tools/toaccess.rst
index c834ab7..ca42807 100644
--- a/docs/source/tools/index.rst
+++ b/docs/source/tools/toaccess.rst
@@ -13,16 +13,13 @@
 .. limitations under the License.
 ..
 
-.. _tools:
+.. _toaccess-module:
 
-*****
-Tools
-*****
-This is a living list of tools used to interact with, test, and develop for 
the Traffic Control CDN.
+********
+toaccess
+********
 
-.. toctree::
-       :maxdepth: 2
-
-       compare
-       python_client
-       traffic_vault_util
+.. automodule:: to_access
+       :members:
+       :undoc-members:
+       :show-inheritance:
diff --git a/traffic_control/clients/python/setup.py 
b/traffic_control/clients/python/setup.py
index f32219c..e897aa2 100755
--- a/traffic_control/clients/python/setup.py
+++ b/traffic_control/clients/python/setup.py
@@ -64,6 +64,17 @@ with open(os.path.join(HERE, "README.rst")) as fd:
                   "requests>=2.13.0",
                   "munch>=2.1.1",
               ],
+              entry_points={
+                  'console_scripts': [
+                   'toget=to_access:get',
+                   'toput=to_access:put',
+                   'topost=to_access:post',
+                   'todelete=to_access:delete',
+                   'tooptions=to_access:options',
+                   'tohead=to_access:head',
+                   'topatch=to_access:patch'
+                   ],
+              },
               extras_require={
                   "dev": [
                       "pylint>=2.0,<3.0"
diff --git a/traffic_control/clients/python/to_access/__init__.py 
b/traffic_control/clients/python/to_access/__init__.py
new file mode 100644
index 0000000..38a47de
--- /dev/null
+++ b/traffic_control/clients/python/to_access/__init__.py
@@ -0,0 +1,454 @@
+#
+# 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.
+#
+
+"""
+.. _toaccess:
+
+.. program:: toaccess
+
+``toaccess``
+============
+This module provides a set of functions meant to provide ease-of-use 
functionality for interacting
+with the Traffic Ops API. It provides scripts named :file:`to{method}` where 
`method` is the name of
+an HTTP method (in lowercase). Collectively they are referred to as 
:program:`toaccess` Implemented
+methods thus far are:
+
+- delete
+- head
+- get
+- options
+- patch
+- post
+- put
+
+Arguments and Flags
+-------------------
+.. option:: PATH
+
+       This is the request path. By default, whatever is passed is considered 
to be relative to
+       :file:`/api/{api-version}/` where ``api-version`` is 
:option:`--api-version`. This behavior can
+       be disabled by using :option:`--raw-path`.
+
+.. option:: DATA
+
+       An optional positional argument that is a data payload to pass to the 
Traffic Ops server in the
+       request body. If this is the absolute or relative path to a file, the 
contents of the file will
+       instead be read and used as the request payload.
+
+.. option:: -h, --help
+
+       Print usage information and exit
+
+.. option:: -a API_VERSION, --api-version API_VERSION
+
+       Specifies the version of the Traffic Ops API that will be used for the 
request. Has no effect if
+       :option:`--raw-path` is used. (Default: 1.3)
+
+.. option:: -f, --full
+
+       Output the full HTTP exchange including request method line, request 
headers, request body (if
+       any), response status line, and response headers (as well as the 
response body, if any). This is
+       equivalent to using :option:`--request-headers`, 
:option:`--request-payload`, and
+       :option:`--response-headers` at the same time, and those options will 
have no effect if given.
+       (Default: false)
+
+.. option:: -k, --insecure
+
+       Do not verify SSL certificates - typically useful for making requests 
to development or testing
+       servers as they frequently have self-signed certificates. (Default: 
false)
+
+.. option:: -p, --pretty
+
+       Pretty-print any payloads that are output as formatted JSON. Has no 
effect on plaintext payloads.
+       Uses tab characters for indentation. (Default: false)
+
+.. option:: -r, --raw-path
+
+       Request exactly :option:`PATH`; do not preface the request path with 
:file:`/api/{api_version}`.
+       This effectively means that :option:`--api-version` will have no 
effect. (Default: false)
+
+.. option:: --request-headers
+
+       Output the request method line and any and all request headers. 
(Default: false)
+
+.. option:: --request-payload
+
+       Output the request body if any was sent. Will attempt to pretty-print 
the body as JSON if
+       :option:`--pretty` is used. (Default: false)
+
+.. option:: --response-headers
+
+       Output the response status line and any and all response headers. 
(Default: false)
+
+.. option:: --to-url URL
+
+       The :abbr:`FQDN (Fully Qualified Domain Name)` and optionally the port 
and scheme of the Traffic
+       Ops server. This will override :envvar:`TO_URL`. The format is the same 
as for :envvar:`TO_URL`.
+       (Default: uses the value of :envvar:`TO_URL`)
+
+.. option:: --to-password PASSWORD
+
+       The password to use when authenticating to Traffic Ops. Overrides 
:envvar:`TO_PASSWORD`.
+       (Default: uses the value of :envvar:`TO_PASSWORD`)
+
+.. option:: --to-user USERNAME
+
+       The username to use when connecting to Traffic Ops. Overrides 
:envvar:`TO_USER`. (Default: uses
+       the value of :envvar:`TO_USER`)
+
+Environment Variables
+---------------------
+If defined, :program:`toaccess` scripts will use these environment variables 
to define their
+connection to and authentication with the Traffic Ops server. Typically, 
setting these is easier
+than using the long options :option:`--to-url`, :option:`--to-user`, and 
:option:`--to-password` on
+every invocation.
+
+.. envvar:: TO_PASSWORD
+
+       Will be used to authenticate the user defined by either 
:option:`--to-user` or :envvar:`TO_USER`.
+
+.. envvar:: TO_URL
+
+       The :abbr:`FQDN (Fully Qualified Domain Name)` of the Traffic Ops 
server to which the script
+       will connect. The format of this should be :file:`[{http or 
https}://]{hostname}[:{port}]`. Note
+       that this may optionally start with ``http://`` or ``https://`` (case 
insensitive), but
+       typically this is unnecessary. Also notice that the port number may be 
specified, though again
+       this isn't usually required. All :program:`toaccess` scripts will 
assume that port 443 should be
+       used unless otherwise specified. They will further assume that the 
protocol is HTTPS unless
+       :envvar:`TO_URL` (or :option:`--to-url`) starts with ``http://``, in 
which case the default port
+       will also be set to 80 unless otherwise specified in the URL.
+
+.. envvar:: TO_USER
+
+       The name of the user as whom to connect to the Traffic Ops server. 
Overriden by
+       :option:`--to-user`.
+
+Exit Codes
+----------
+The exit code of a :program:`toaccess` script can sometimes be used by the 
caller to determine what
+the result of calling the script was without needing to parse the output. The 
exit codes used are:
+
+0
+       The command executed successfully, and the result is on STDOUT.
+1
+       Typically this exit code means that an error was encountered when 
parsing positional command
+       line arguments. However, this is also the exit code used by most Python 
interpreters to signal
+       an unhandled exception.
+2
+       Signifies a runtime error that caused the request to fail - this is 
**not** generally indicative
+       of an HTTP client or server error, but rather an underlying issue 
connecting to or
+       authenticating with Traffic Ops. This is distinct from an exit code of 
``32`` in that the
+       *format* of the arguments was correct, but there was some problem with 
the *value*. For example,
+       passing ``https://test:`` to :option:`--to-url` will cause an exit code 
of ``2``, not ``32``.
+4
+       An HTTP client error occurred. The HTTP stack will be printed to stdout 
as indicated by other
+       options - meaning by default it will only print the response payload if 
one was given, but will
+       respect options like e.g. :option:`--request-payload` as well as
+       :option:`-p`/:option:`--pretty`.
+5
+       An HTTP server error occurred. The HTTP stack will be printed to stdout 
as indicated by other
+       options - meaning by default it will only print the response payload if 
one was given, but will
+       respect options like e.g. :option:`--request-payload` as well as
+       :option:`-p`/:option:`--pretty`.
+32
+       This is the error code emitted by Python's :mod:`argparse` module when 
the passed arguments
+       could not be parsed successfully.
+
+.. note:: The way exit codes ``4`` and ``5`` are implemented is by returning 
the status code of the
+       HTTP request divided by 100 whenever it is at least 400. This means 
that if the Traffic Ops
+       server ever started returning e.g. 700 status codes, the exit code of 
the script would be 7.
+
+
+Module Reference
+================
+
+"""
+from __future__ import print_function
+
+import json
+import logging
+import os
+import sys
+from urllib.parse import urlparse
+
+from future.utils import raise_from
+
+from trafficops.restapi import LoginError, OperationError, InvalidJSONError
+from trafficops.tosession import TOSession
+
+from requests.exceptions import RequestException
+
+l = logging.getLogger()
+l.disabled = True
+logging.basicConfig(level=logging.CRITICAL+1)
+
+def output(r, pretty, request_header, response_header, request_payload, indent 
= '\t'):
+       """
+       Prints the passed response object in a format consistent with the other 
parameters.
+
+       :param r: The :mod:`requests` response object being printed
+       :param pretty: If :const:`True`, attempt to pretty-print payloads as 
JSON
+       :param request_header: If :const:`True`, print request line and request 
headers
+       :param response_header: If :const:`True`, print response line and 
response headers
+       :param request_payload: If :const:`True`, print the request payload
+       :param indent: An optional number of spaces for pretty-printing 
indentation (default is the tab character)
+       """
+       if request_header:
+               print(r.request.method, r.request.path_url, "HTTP/1.1")
+               for h,v in r.request.headers.items():
+                       print("%s:" % h, v)
+               print()
+
+       if request_payload and r.request.body:
+               try:
+                       result = r.request.body if not pretty else 
json.dumps(json.loads(r.request.body))
+               except ValueError:
+                       result = r.request.body
+               print(result, end="\n\n")
+
+       if response_header:
+               print("HTTP/1.1", r.status_code, end="")
+               print(" "+r.reason if r.reason else "")
+               for h,v in r.headers.items():
+                       print("%s:" % h, v)
+               print()
+
+       try:
+               result = r.text if not pretty else json.dumps(r.json(), 
indent=indent)
+       except ValueError:
+               result = r.text
+       print(result)
+
+def parse_arguments(program):
+       """
+       A common-use function that parses the command line arguments.
+
+       :param program: The name of the program being run - used for usage 
informational output
+       :returns: The Traffic Ops HTTP session object, the requested path, any 
data to be sent, an output
+                 format specification, whether or not the path is raw, and 
whether or not output should
+                 be prettified
+       """
+       from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter
+       parser = ArgumentParser(prog=program,
+                               formatter_class=ArgumentDefaultsHelpFormatter,
+                               description="A helper program for interfacing 
with the Traffic Ops API",
+                               epilog=("Typically, one will want to connect 
and authenticate by defining "
+                                      "the 'TO_URL', 'TO_USER' and 
'TO_PASSWORD' environment variables "
+                                      "rather than (respectively) the 
'--to-url', '--to-user' and "
+                                      "'--to-password' command-line flags. 
Those flags are only "
+                                      "required when said environment 
variables are not defined.\n"
+                                      "%(prog)s will exit with a success 
provided a response was "
+                                      "received and the status code of said 
response was less than 400. "
+                                      "The exit code will be 1 if command line 
arguments cannot be "
+                                      "parsed or authentication with the 
Traffic Ops server fails. "
+                                      "In the event of some unknown error 
occurring when waiting for a "
+                                      "response, the exit code will be 2. If 
the server responds with "
+                                      "a status code indicating a client or 
server error, that status "
+                                      "code will be used as the exit code."))
+
+       parser.add_argument("--to-url",
+                           type=str,
+                           help=("The fully qualified domain name of the 
Traffic Ops server. Overrides "
+                                "'$TO_URL'. The format for both the 
environment variable and the flag "
+                                "is '[scheme]hostname[:port]'. That is, ports 
should be specified here, "
+                                "and they need not start with 'http://' or 
'https://'. HTTPS is the "
+                                "assumed protocol unless the scheme _is_ 
provided and is 'http://'."))
+       parser.add_argument("--to-user",
+                           type=str,
+                           help="The username to use when connecting to 
Traffic Ops. Overrides '$TO_USER")
+       parser.add_argument("--to-password",
+                           type=str,
+                           help="The password to use when authenticating to 
Traffic Ops. Overrides '$TO_PASSWORD'")
+       parser.add_argument("-k", "--insecure", action="store_true", help="Do 
not verify SSL certificates")
+       parser.add_argument("-f", "--full",
+                           action="store_true",
+                           help=("Also output HTTP request/response lines and 
headers, and request payload. "
+                                "This is equivalent to using 
'--request-headers', '--response-headers' "
+                                "and '--request-payload' at the same time."))
+       parser.add_argument("--request-headers",
+                           action="store_true",
+                           help="Output request method line and headers")
+       parser.add_argument("--response-headers",
+                           action="store_true",
+                           help="Output response status line and headers")
+       parser.add_argument("--request-payload",
+                           action="store_true",
+                           help="Output request payload (will try to 
pretty-print if '--pretty' is given)")
+       parser.add_argument("-r", "--raw-path",
+                           action="store_true",
+                           help="Request exactly PATH; it won't be prefaced 
with '/api/{{api-version}}/")
+       parser.add_argument("-a", "--api-version",
+                           type=float,
+                           default=1.3,
+                           help="Specify the API version to request against")
+       parser.add_argument("-p", "--pretty",
+                           action="store_true",
+                           help=("Pretty-print payloads as JSON. "
+                                "Note that this will make Content-Type headers 
\"wrong\", in general"))
+       parser.add_argument("PATH", help="The path to the resource being 
requested - omit '/api/1.x'")
+       parser.add_argument("DATA",
+                           help=("An optional data string to pass with the 
request. If this is a "
+                                "filename, the contents of the file will be 
sent instead."),
+                           nargs='?')
+
+
+       args = parser.parse_args()
+
+       try:
+               to_host = args.to_url if args.to_url else os.environ["TO_URL"]
+       except KeyError as e:
+               raise KeyError("Traffic Ops hostname not set! Set the TO_URL 
environment variable or use "\
+                              "'--to-url'.") from e
+
+       original_to_host = to_host
+       to_host = urlparse(to_host, scheme="https")
+       useSSL = to_host.scheme.lower() == "https"
+       to_port = to_host.port
+       if to_port is None:
+               if useSSL:
+                       to_port = 443
+               else:
+                       to_port = 80
+
+       to_host = to_host.hostname
+       if not to_host:
+               raise KeyError("Invalid URL/host for Traffic Ops: '%s'" % 
original_to_host)
+
+       s = TOSession(to_host,
+                     host_port=to_port,
+                     ssl=useSSL,
+                     api_version=str(args.api_version),
+                     verify_cert=not args.insecure)
+
+       data = args.DATA
+       if data and os.path.isfile(data):
+               with open(data) as f:
+                       data = f.read()
+
+       if isinstance(data, str):
+               data = data.encode()
+
+       try:
+               to_user = args.to_user if args.to_user else 
os.environ["TO_USER"]
+       except KeyError as e:
+               raise KeyError("Traffic Ops user not set! Set the TO_USER 
environment variable or use "\
+                              "'--to-user'.") from e
+
+       try:
+               to_passwd = args.to_password if args.to_password else 
os.environ["TO_PASSWORD"]
+       except KeyError as e:
+               raise KeyError("Traffic Ops password not set! Set the 
TO_PASSWORD environment variable or "\
+                              "use '--to-password'") from e
+
+       try:
+               s.login(to_user, to_passwd)
+       except (OperationError, InvalidJSONError, LoginError) as e:
+               raise PermissionError from e
+
+       return (s,
+              args.PATH,
+              data,
+              (
+                args.request_headers or args.full,
+                args.response_headers or args.full,
+                args.request_payload or args.full
+              ),
+              args.raw_path,
+              args.pretty)
+
+def request(method):
+       """
+       All of the scripts wind up calling this function to handle their common 
functionality.
+
+       :param method: The name of the request method to use (case-insensitive)
+       :returns: The program's exit code
+       """
+       try:
+               s, path, data, full, raw, pretty = parse_arguments("to%s" % 
method)
+       except (PermissionError, KeyError) as e:
+               print(e, file=sys.stderr)
+               return 1
+
+       if raw:
+               path = '/'.join((s.to_url.rstrip('/'), path.lstrip('/')))
+       else:
+               path = '/'.join((s.base_url.rstrip('/'), path.lstrip('/')))
+
+       try:
+               if data is not None:
+                       r = s._session.request(method, path, data=data)
+               else:
+                       r = s._session.request(method, path)
+       except (RequestException, ValueError) as e:
+               print("Error occurred: ", e, file=sys.stderr)
+               return 2
+
+       output(r, pretty, *full)
+       return 0 if r.status_code < 400 else r.status_code // 100
+
+def get():
+       """
+       Entry point for :program:`toget`
+
+       :returns: The program's exit code
+       """
+       return request("get")
+
+def put():
+       """
+       Entry point for :program:`toput`
+
+       :returns: The program's exit code
+       """
+       return request("put")
+
+def post():
+       """
+       Entry point for :program:`topost`
+
+       :returns: The program's exit code
+       """
+       return request("post")
+
+def delete():
+       """
+       Entry point for :program:`todelete`
+
+       :returns: The program's exit code
+       """
+       return request("delete")
+
+def options():
+       """
+       Entry point for :program:`tooptions`
+
+       :returns: The program's exit code
+       """
+       return request("options")
+
+def head():
+       """
+       Entry point for :program:`tohead`
+
+       :returns: The program's exit code
+       """
+       return request("head")
+
+def patch():
+       """
+       Entry point for :program:`topatch`
+
+       :returns: The program's exit code
+       """
+       return request("patch")
diff --git a/traffic_control/clients/python/trafficops/restapi.py 
b/traffic_control/clients/python/trafficops/restapi.py
index cacfe83..4189af4 100644
--- a/traffic_control/clients/python/trafficops/restapi.py
+++ b/traffic_control/clients/python/trafficops/restapi.py
@@ -61,16 +61,22 @@ class OperationError(IOError):
        This class represents a generic error, indicating something went wrong 
with the request or on
        the server.
        """
-       def __init__(self, *args):
+       #: Contains the response object that generated the error
+       resp = None
+       def __init__(self, *args, resp=None):
                IOError.__init__(self, *args)
+               self.resp = resp
 
 
 class InvalidJSONError(ValueError):
        """
        An error that occurs when an invalid JSON payload is passed to an 
endpoint.
        """
-       def __init__(self, *args):
+       #: Contains the response object that generated the error
+       resp = None
+       def __init__(self, *args, resp=None):
                ValueError.__init__(self, *args)
+               self.resp = resp
 
 # Miscellaneous Constants and/or Variables
 DEFAULT_HEADERS = {u'Content-Type': u'application/json; charset=UTF-8'}
@@ -410,13 +416,13 @@ class RestApiSession(object):
                                msg = msg.format(response.status_code, 
endpoint, e)
                                if debug_response:
                                        log_with_debug_info(logging.ERROR, msg 
+ u' Data: [' + str(response.text) + u']')
-                               raise InvalidJSONError(msg)
+                               raise InvalidJSONError(msg, resp=response)
                        msg = u'{0} request to RESTful API at [{1}] expected 
status(s) {2}; failed: {3} {4};'\
                              u' Response: {5}'
                        msg = msg.format(operation.upper(), endpoint, 
expected_status_codes,
                                         response.status_code, response.reason, 
retdata)
                        log_with_debug_info(logging.ERROR, msg)
-                       raise OperationError(msg)
+                       raise OperationError(msg, resp=response)
 
                try:
                        if response.status_code in ('204',):
@@ -432,7 +438,7 @@ class RestApiSession(object):
                        msg = msg.format(response.status_code, endpoint, e)
                        if debug_response:
                                log_with_debug_info(logging.ERROR, msg + u' 
Data: [' + str(response.text) + u']')
-                       raise InvalidJSONError(msg)
+                       raise InvalidJSONError(msg, resp=response)
                retdata = munch.munchify(retdata) if munchify else retdata
                return (retdata[u'response'] if u'response' in retdata else 
retdata), response
 
@@ -495,3 +501,75 @@ class RestApiSession(object):
                """
 
                return self._do_operation(u'delete', api_path, *args, **kwargs)
+
+       def head(self, api_path, *args, **kwargs):
+               """
+               Perform HTTP HEAD requests
+               :param api_path: The path to the API end-point that you want to 
call which does not include
+                       the base URL e.g. ``user/login``, ``servers``, etc. 
This string can contain substitution
+                       parameters as denoted by a valid field_name replacement 
field specification as per
+                       :meth:`str.format` e.g. ``cachegroups/{id}`` or 
``cachegroups/{id:d}``
+
+               :type api_path: str
+               :param kwargs: Passed Keyword Parameters. If you need to send 
JSON data to the endpoint pass
+                       the keyword parameter ``data`` with the Python data 
structure. This method will convert
+                       it to JSON before sending it to the API endpoint. Use 
``query_params`` to pass a
+                       dictionary of query parameters
+
+               :type kwargs: Dict[str, Any]
+               :return: Python data structure distilled from JSON from the API 
request.
+               :rtype: Tuple[Union[Dict[str, Any], List[Dict[str, Any]], 
munch.Munch, List[munch.Munch]],
+                       requests.Response]
+
+               :raises: Union[LoginError, OperationError]
+               """
+
+               return self._do_operation(u'head', api_path, *args, **kwargs)
+
+       def options(self, api_path, *args, **kwargs):
+               """
+               Perform HTTP OPTIONS requests
+               :param api_path: The path to the API end-point that you want to 
call which does not include
+                       the base URL e.g. ``user/login``, ``servers``, etc. 
This string can contain substitution
+                       parameters as denoted by a valid field_name replacement 
field specification as per
+                       :meth:`str.format` e.g. ``cachegroups/{id}`` or 
``cachegroups/{id:d}``
+
+               :type api_path: str
+               :param kwargs: Passed Keyword Parameters. If you need to send 
JSON data to the endpoint pass
+                       the keyword parameter ``data`` with the Python data 
structure. This method will convert
+                       it to JSON before sending it to the API endpoint. Use 
``query_params`` to pass a
+                       dictionary of query parameters
+
+               :type kwargs: Dict[str, Any]
+               :return: Python data structure distilled from JSON from the API 
request.
+               :rtype: Tuple[Union[Dict[str, Any], List[Dict[str, Any]], 
munch.Munch, List[munch.Munch]],
+                       requests.Response]
+
+               :raises: Union[LoginError, OperationError]
+               """
+
+               return self._do_operation(u'options', api_path, *args, **kwargs)
+
+       def patch(self, api_path, *args, **kwargs):
+               """
+               Perform HTTP PATCH requests
+               :param api_path: The path to the API end-point that you want to 
call which does not include
+                       the base URL e.g. ``user/login``, ``servers``, etc. 
This string can contain substitution
+                       parameters as denoted by a valid field_name replacement 
field specification as per
+                       :meth:`str.format` e.g. ``cachegroups/{id}`` or 
``cachegroups/{id:d}``
+
+               :type api_path: str
+               :param kwargs: Passed Keyword Parameters. If you need to send 
JSON data to the endpoint pass
+                       the keyword parameter ``data`` with the Python data 
structure. This method will convert
+                       it to JSON before sending it to the API endpoint. Use 
``query_params`` to pass a
+                       dictionary of query parameters
+
+               :type kwargs: Dict[str, Any]
+               :return: Python data structure distilled from JSON from the API 
request.
+               :rtype: Tuple[Union[Dict[str, Any], List[Dict[str, Any]], 
munch.Munch, List[munch.Munch]],
+                       requests.Response]
+
+               :raises: Union[LoginError, OperationError]
+               """
+
+               return self._do_operation(u'patch', api_path, *args, **kwargs)

Reply via email to